diff --git a/DEPS b/DEPS
index 3f5f3f8..48f4de84 100644
--- a/DEPS
+++ b/DEPS
@@ -42,12 +42,12 @@
   'boringssl_git': 'https://boringssl.googlesource.com',
   'libvpx_revision': '5cdd30205301c293be6160f778bce981300b5a28',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': 'fef4c32bdf02f1bf3cde722cd48c4ac4cd137ab6',
+  'skia_revision': 'f16201250315bd807e06547f1c412fcdc5c8805a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
   'v8_branch': 'trunk',
-  'v8_revision': 'c9709b92ec2a695cf85a688f63eff3ef97939a78',
+  'v8_revision': 'e8694f69297c3bee240490aecd29fab6c40ec3f0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling WebRTC
   # and V8 without interference from each other.
@@ -58,7 +58,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'bc393df9cd8ae893da686533644da29a8c4911ae',
+  'angle_revision': '592ab9dd91e653f5c2d4f7395267046d229e20c1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -66,7 +66,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'b3a788e5e37955620b26be5b6e3048d37b605e00',
+  'pdfium_revision': '615082de70c7fc18d46d0d1a03b62d0d76b1daa9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -74,7 +74,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'be629e0e920ae32cca691f5e45410ff00db1a849',
+  'boringssl_revision': '8f5e2ebcee628ef02add9b21955402b0c6256624',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
@@ -94,7 +94,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '7c13b1d2cb6133e2edcf21df769e708c350b5fb0',
+  'nacl_revision': 'e8fbd4b6737a83a082f3de3b713a6f48cadd3e37',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -441,7 +441,7 @@
      Var('chromium_git') + '/external/android_protobuf.git' + '@' + '94f522f907e3f34f70d9e7816b947e62fddbb267',
 
     'src/third_party/android_tools':
-     Var('chromium_git') + '/android_tools.git' + '@' + 'aaeda3d69df4b4352e3cac7c16bea7f16bd1ec12',
+     Var('chromium_git') + '/android_tools.git' + '@' + 'f6e2370dff438125897bb3b3800de1ad7aa62c27',
 
     'src/third_party/apache-mime4j':
      Var('chromium_git') + '/chromium/deps/apache-mime4j.git' + '@' + '28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 3326d8c..8e4880b2 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -359,6 +359,69 @@
       '\n'.join(problems))]
 
 
+def _FindHistogramNameInLine(histogram_name, line):
+  """Tries to find a histogram name or prefix in a line."""
+  if not "affected-histogram" in line:
+    return histogram_name in line
+  # A histogram_suffixes tag type has an affected-histogram name as a prefix of
+  # the histogram_name.
+  if not '"' in line:
+    return False
+  histogram_prefix = line.split('\"')[1]
+  return histogram_prefix in histogram_name
+
+
+def _CheckUmaHistogramChanges(input_api, output_api):
+  """Check that UMA histogram names in touched lines can still be found in other
+  lines of the patch or in histograms.xml. Note that this check would not catch
+  the reverse: changes in histograms.xml not matched in the code itself."""
+  touched_histograms = []
+  histograms_xml_modifications = []
+  pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"')
+  for f in input_api.AffectedFiles():
+    # If histograms.xml itself is modified, keep the modified lines for later.
+    if f.LocalPath().endswith(('histograms.xml')):
+      histograms_xml_modifications = f.ChangedContents()
+      continue
+    if not f.LocalPath().endswith(('cc', 'mm', 'cpp')):
+      continue
+    for line_num, line in f.ChangedContents():
+      found = pattern.search(line)
+      if found:
+        touched_histograms.append([found.group(1), f, line_num])
+
+  # Search for the touched histogram names in the local modifications to
+  # histograms.xml, and, if not found, on the base histograms.xml file.
+  unmatched_histograms = []
+  for histogram_info in touched_histograms:
+    histogram_name_found = False
+    for line_num, line in histograms_xml_modifications:
+      histogram_name_found = _FindHistogramNameInLine(histogram_info[0], line)
+      if histogram_name_found:
+        break
+    if not histogram_name_found:
+      unmatched_histograms.append(histogram_info)
+
+  problems = []
+  if unmatched_histograms:
+    with open('tools/metrics/histograms/histograms.xml') as histograms_xml:
+      for histogram_name, f, line_num in unmatched_histograms:
+        histogram_name_found = False
+        for line in histograms_xml:
+          histogram_name_found = _FindHistogramNameInLine(histogram_name, line)
+          if histogram_name_found:
+            break
+        if not histogram_name_found:
+          problems.append(' [%s:%d] %s' %
+                          (f.LocalPath(), line_num, histogram_name))
+
+  if not problems:
+    return []
+  return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have '
+    'been modified and the associated histogram name has no match in either '
+    'metrics/histograms.xml or the modifications of it:',  problems)]
+
+
 def _CheckNoNewWStrings(input_api, output_api):
   """Checks to make sure we don't introduce use of wstrings."""
   problems = []
@@ -1585,6 +1648,7 @@
   results.extend(_CheckJavaStyle(input_api, output_api))
   results.extend(
       input_api.canned_checks.CheckGNFormatted(input_api, output_api))
+  results.extend(_CheckUmaHistogramChanges(input_api, output_api))
   return results
 
 
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index 58ca402..00997b43 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -270,6 +270,73 @@
     self.assertTrue('3' in errors[1])
     self.assertTrue('5' in errors[2])
 
+class UmaHistogramChangeMatchedOrNotTest(unittest.TestCase):
+  def testTypicalCorrectlyMatchedChange(self):
+    diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
+    diff_xml = ['<histogram name="Bla.Foo.Dummy"> </histogram>']
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+      MockFile('some/path/foo.cc', diff_cc),
+      MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
+    ]
+    warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
+                                                   MockOutputApi())
+    self.assertEqual(0, len(warnings))
+
+  def testTypicalNotMatchedChange(self):
+    diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [MockFile('some/path/foo.cc', diff_cc)]
+    warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
+                                                   MockOutputApi())
+    self.assertEqual(1, len(warnings))
+    self.assertEqual('warning', warnings[0].type)
+
+  def testTypicalNotMatchedChangeViaSuffixes(self):
+    diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
+    diff_xml = ['<histogram_suffixes name="SuperHistogram">',
+                '  <suffix name="Dummy"/>',
+                '  <affected-histogram name="Snafu.Dummy"/>',
+                '</histogram>']
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+      MockFile('some/path/foo.cc', diff_cc),
+      MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
+    ]
+    warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
+                                                   MockOutputApi())
+    self.assertEqual(1, len(warnings))
+    self.assertEqual('warning', warnings[0].type)
+
+  def testTypicalCorrectlyMatchedChangeViaSuffixes(self):
+    diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
+    diff_xml = ['<histogram_suffixes name="SuperHistogram">',
+                '  <suffix name="Dummy"/>',
+                '  <affected-histogram name="Bla.Foo"/>',
+                '</histogram>']
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+      MockFile('some/path/foo.cc', diff_cc),
+      MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
+    ]
+    warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
+                                                   MockOutputApi())
+    self.assertEqual(0, len(warnings))
+
+  def testTypicalCorrectlyMatchedChangeViaSuffixesWithSeparator(self):
+    diff_cc = ['UMA_HISTOGRAM_BOOL("Snafu_Dummy", true)']
+    diff_xml = ['<histogram_suffixes name="SuperHistogram" separator="_">',
+                '  <suffix name="Dummy"/>',
+                '  <affected-histogram name="Snafu"/>',
+                '</histogram>']
+    mock_input_api = MockInputApi()
+    mock_input_api.files = [
+      MockFile('some/path/foo.cc', diff_cc),
+      MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
+    ]
+    warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
+                                                   MockOutputApi())
+    self.assertEqual(0, len(warnings))
 
 class BadExtensionsTest(unittest.TestCase):
   def testBadRejFile(self):
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index b9e1d66a..755a838 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -56,7 +56,7 @@
 
   AwBrowserContext(const base::FilePath path,
                    JniDependencyFactory* native_factory);
-  virtual ~AwBrowserContext();
+  ~AwBrowserContext() override;
 
   // Currently only one instance per process is supported.
   static AwBrowserContext* GetDefault();
@@ -106,28 +106,26 @@
   // content::BrowserContext implementation.
   scoped_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath& partition_path) override;
-  virtual base::FilePath GetPath() const override;
-  virtual bool IsOffTheRecord() const override;
-  virtual net::URLRequestContextGetter* GetRequestContext() override;
-  virtual net::URLRequestContextGetter* GetRequestContextForRenderProcess(
+  base::FilePath GetPath() const override;
+  bool IsOffTheRecord() const override;
+  net::URLRequestContextGetter* GetRequestContext() override;
+  net::URLRequestContextGetter* GetRequestContextForRenderProcess(
       int renderer_child_id) override;
-  virtual net::URLRequestContextGetter* GetMediaRequestContext() override;
-  virtual net::URLRequestContextGetter* GetMediaRequestContextForRenderProcess(
+  net::URLRequestContextGetter* GetMediaRequestContext() override;
+  net::URLRequestContextGetter* GetMediaRequestContextForRenderProcess(
       int renderer_child_id) override;
-  virtual net::URLRequestContextGetter*
-      GetMediaRequestContextForStoragePartition(
-          const base::FilePath& partition_path, bool in_memory) override;
-  virtual content::ResourceContext* GetResourceContext() override;
-  virtual content::DownloadManagerDelegate*
-      GetDownloadManagerDelegate() override;
-  virtual content::BrowserPluginGuestManager* GetGuestManager() override;
-  virtual storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
-  virtual content::PushMessagingService* GetPushMessagingService() override;
-  virtual content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
+  net::URLRequestContextGetter* GetMediaRequestContextForStoragePartition(
+      const base::FilePath& partition_path,
+      bool in_memory) override;
+  content::ResourceContext* GetResourceContext() override;
+  content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
+  content::BrowserPluginGuestManager* GetGuestManager() override;
+  storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
+  content::PushMessagingService* GetPushMessagingService() override;
+  content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
 
   // visitedlink::VisitedLinkDelegate implementation.
-  virtual void RebuildTable(
-      const scoped_refptr<URLEnumerator>& enumerator) override;
+  void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override;
 
  private:
   void CreateDataReductionProxyStatisticsIfNecessary();
diff --git a/android_webview/browser/aw_browser_main_parts.h b/android_webview/browser/aw_browser_main_parts.h
index 62a3505..2f417c0 100644
--- a/android_webview/browser/aw_browser_main_parts.h
+++ b/android_webview/browser/aw_browser_main_parts.h
@@ -20,13 +20,13 @@
 class AwBrowserMainParts : public content::BrowserMainParts {
  public:
   explicit AwBrowserMainParts(AwBrowserContext* browser_context);
-  virtual ~AwBrowserMainParts();
+  ~AwBrowserMainParts() override;
 
   // Overriding methods from content::BrowserMainParts.
-  virtual void PreEarlyInitialization() override;
-  virtual int PreCreateThreads() override;
-  virtual void PreMainMessageLoopRun() override;
-  virtual bool MainMessageLoopRun(int* result_code) override;
+  void PreEarlyInitialization() override;
+  int PreCreateThreads() override;
+  void PreMainMessageLoopRun() override;
+  bool MainMessageLoopRun(int* result_code) override;
 
  private:
   // Android specific UI MessageLoop.
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index c38ce6a..f56dc6c 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -54,11 +54,9 @@
   explicit AwContentsMessageFilter(int process_id);
 
   // BrowserMessageFilter methods.
-  virtual void OverrideThreadForMessage(
-      const IPC::Message& message,
-      BrowserThread::ID* thread) override;
-  virtual bool OnMessageReceived(
-      const IPC::Message& message) override;
+  void OverrideThreadForMessage(const IPC::Message& message,
+                                BrowserThread::ID* thread) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
 
   void OnShouldOverrideUrlLoading(int routing_id,
                                   const base::string16& url,
@@ -66,7 +64,7 @@
   void OnSubFrameCreated(int parent_render_frame_id, int child_render_frame_id);
 
 private:
-  virtual ~AwContentsMessageFilter();
+ ~AwContentsMessageFilter() override;
 
   int process_id_;
 
@@ -126,18 +124,17 @@
   AwAccessTokenStore() { }
 
   // content::AccessTokenStore implementation
-  virtual void LoadAccessTokens(
-      const LoadAccessTokensCallbackType& request) override {
+  void LoadAccessTokens(const LoadAccessTokensCallbackType& request) override {
     AccessTokenStore::AccessTokenSet access_token_set;
     // AccessTokenSet and net::URLRequestContextGetter not used on Android,
     // but Run needs to be called to finish the geolocation setup.
     request.Run(access_token_set, NULL);
   }
-  virtual void SaveAccessToken(const GURL& server_url,
-                               const base::string16& access_token) override { }
+  void SaveAccessToken(const GURL& server_url,
+                       const base::string16& access_token) override {}
 
  private:
-  virtual ~AwAccessTokenStore() { }
+  ~AwAccessTokenStore() override {}
 
   DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore);
 };
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index f9507a67..93080a9 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -25,73 +25,71 @@
   static AwBrowserContext* GetAwBrowserContext();
 
   AwContentBrowserClient(JniDependencyFactory* native_factory);
-  virtual ~AwContentBrowserClient();
+  ~AwContentBrowserClient() override;
 
   // Overriden methods from ContentBrowserClient.
-  virtual void AddCertificate(net::CertificateMimeType cert_type,
-                              const void* cert_data,
-                              size_t cert_size,
-                              int render_process_id,
-                              int render_frame_id) override;
-  virtual content::BrowserMainParts* CreateBrowserMainParts(
+  void AddCertificate(net::CertificateMimeType cert_type,
+                      const void* cert_data,
+                      size_t cert_size,
+                      int render_process_id,
+                      int render_frame_id) override;
+  content::BrowserMainParts* CreateBrowserMainParts(
       const content::MainFunctionParams& parameters) override;
-  virtual content::WebContentsViewDelegate* GetWebContentsViewDelegate(
+  content::WebContentsViewDelegate* GetWebContentsViewDelegate(
       content::WebContents* web_contents) override;
-  virtual void RenderProcessWillLaunch(
-      content::RenderProcessHost* host) override;
-  virtual net::URLRequestContextGetter* CreateRequestContext(
+  void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
+  net::URLRequestContextGetter* CreateRequestContext(
       content::BrowserContext* browser_context,
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector request_interceptors) override;
-  virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
+  net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
       content::BrowserContext* browser_context,
       const base::FilePath& partition_path,
       bool in_memory,
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector request_interceptors) override;
-  virtual std::string GetCanonicalEncodingNameByAliasName(
+  std::string GetCanonicalEncodingNameByAliasName(
       const std::string& alias_name) override;
-  virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
-                                              int child_process_id) override;
-  virtual std::string GetApplicationLocale() override;
-  virtual std::string GetAcceptLangs(content::BrowserContext* context) override;
-  virtual const gfx::ImageSkia* GetDefaultFavicon() override;
-  virtual bool AllowAppCache(const GURL& manifest_url,
-                             const GURL& first_party,
-                             content::ResourceContext* context) override;
-  virtual bool AllowGetCookie(const GURL& url,
-                              const GURL& first_party,
-                              const net::CookieList& cookie_list,
-                              content::ResourceContext* context,
-                              int render_process_id,
-                              int render_frame_id) override;
-  virtual bool AllowSetCookie(const GURL& url,
-                              const GURL& first_party,
-                              const std::string& cookie_line,
-                              content::ResourceContext* context,
-                              int render_process_id,
-                              int render_frame_id,
-                              net::CookieOptions* options) override;
-  virtual bool AllowWorkerDatabase(
+  void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
+                                      int child_process_id) override;
+  std::string GetApplicationLocale() override;
+  std::string GetAcceptLangs(content::BrowserContext* context) override;
+  const gfx::ImageSkia* GetDefaultFavicon() override;
+  bool AllowAppCache(const GURL& manifest_url,
+                     const GURL& first_party,
+                     content::ResourceContext* context) override;
+  bool AllowGetCookie(const GURL& url,
+                      const GURL& first_party,
+                      const net::CookieList& cookie_list,
+                      content::ResourceContext* context,
+                      int render_process_id,
+                      int render_frame_id) override;
+  bool AllowSetCookie(const GURL& url,
+                      const GURL& first_party,
+                      const std::string& cookie_line,
+                      content::ResourceContext* context,
+                      int render_process_id,
+                      int render_frame_id,
+                      net::CookieOptions* options) override;
+  bool AllowWorkerDatabase(
       const GURL& url,
       const base::string16& name,
       const base::string16& display_name,
       unsigned long estimated_size,
       content::ResourceContext* context,
-      const std::vector<std::pair<int, int> >& render_frames) override;
-  virtual void AllowWorkerFileSystem(
+      const std::vector<std::pair<int, int>>& render_frames) override;
+  void AllowWorkerFileSystem(
       const GURL& url,
       content::ResourceContext* context,
-      const std::vector<std::pair<int, int> >& render_frames,
+      const std::vector<std::pair<int, int>>& render_frames,
       base::Callback<void(bool)> callback) override;
-  virtual bool AllowWorkerIndexedDB(
+  bool AllowWorkerIndexedDB(
       const GURL& url,
       const base::string16& name,
       content::ResourceContext* context,
-      const std::vector<std::pair<int, int> >& render_frames) override;
-  virtual content::QuotaPermissionContext*
-      CreateQuotaPermissionContext() override;
-  virtual void AllowCertificateError(
+      const std::vector<std::pair<int, int>>& render_frames) override;
+  content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
+  void AllowCertificateError(
       int render_process_id,
       int render_frame_id,
       int cert_error,
@@ -103,61 +101,59 @@
       bool expired_previous_decision,
       const base::Callback<void(bool)>& callback,
       content::CertificateRequestResultType* result) override;
-  virtual void SelectClientCertificate(
+  void SelectClientCertificate(
       int render_process_id,
       int render_frame_id,
       net::SSLCertRequestInfo* cert_request_info,
       const base::Callback<void(net::X509Certificate*)>& callback) override;
-  virtual void RequestPermission(
+  void RequestPermission(
       content::PermissionType permission,
       content::WebContents* web_contents,
       int bridge_id,
       const GURL& requesting_frame,
       bool user_gesture,
       const base::Callback<void(bool)>& result_callback) override;
-  virtual void CancelPermissionRequest(content::PermissionType permission,
-                                       content::WebContents* web_contents,
-                                       int bridge_id,
-                                       const GURL& origin) override;
-  virtual bool CanCreateWindow(const GURL& opener_url,
-                               const GURL& opener_top_level_frame_url,
-                               const GURL& source_origin,
-                               WindowContainerType container_type,
-                               const GURL& target_url,
-                               const content::Referrer& referrer,
-                               WindowOpenDisposition disposition,
-                               const blink::WebWindowFeatures& features,
-                               bool user_gesture,
-                               bool opener_suppressed,
-                               content::ResourceContext* context,
-                               int render_process_id,
-                               int opener_id,
-                               bool* no_javascript_access) override;
-  virtual void ResourceDispatcherHostCreated() override;
-  virtual net::NetLog* GetNetLog() override;
-  virtual content::AccessTokenStore* CreateAccessTokenStore() override;
-  virtual bool IsFastShutdownPossible() override;
-  virtual void ClearCache(content::RenderViewHost* rvh) override;
-  virtual void ClearCookies(content::RenderViewHost* rvh) override;
-  virtual base::FilePath GetDefaultDownloadDirectory() override;
-  virtual std::string GetDefaultDownloadName() override;
-  virtual void DidCreatePpapiPlugin(
-      content::BrowserPpapiHost* browser_host) override;
-  virtual bool AllowPepperSocketAPI(
+  void CancelPermissionRequest(content::PermissionType permission,
+                               content::WebContents* web_contents,
+                               int bridge_id,
+                               const GURL& origin) override;
+  bool CanCreateWindow(const GURL& opener_url,
+                       const GURL& opener_top_level_frame_url,
+                       const GURL& source_origin,
+                       WindowContainerType container_type,
+                       const GURL& target_url,
+                       const content::Referrer& referrer,
+                       WindowOpenDisposition disposition,
+                       const blink::WebWindowFeatures& features,
+                       bool user_gesture,
+                       bool opener_suppressed,
+                       content::ResourceContext* context,
+                       int render_process_id,
+                       int opener_id,
+                       bool* no_javascript_access) override;
+  void ResourceDispatcherHostCreated() override;
+  net::NetLog* GetNetLog() override;
+  content::AccessTokenStore* CreateAccessTokenStore() override;
+  bool IsFastShutdownPossible() override;
+  void ClearCache(content::RenderViewHost* rvh) override;
+  void ClearCookies(content::RenderViewHost* rvh) override;
+  base::FilePath GetDefaultDownloadDirectory() override;
+  std::string GetDefaultDownloadName() override;
+  void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
+  bool AllowPepperSocketAPI(
       content::BrowserContext* browser_context,
       const GURL& url,
       bool private_api,
       const content::SocketPermissionRequest* params) override;
-  virtual void OverrideWebkitPrefs(content::RenderViewHost* rvh,
-                                   const GURL& url,
-                                   content::WebPreferences* web_prefs) override;
+  void OverrideWebkitPrefs(content::RenderViewHost* rvh,
+                           const GURL& url,
+                           content::WebPreferences* web_prefs) override;
 #if defined(VIDEO_HOLE)
-  virtual content::ExternalVideoSurfaceContainer*
-      OverrideCreateExternalVideoSurfaceContainer(
-          content::WebContents* web_contents) override;
+  content::ExternalVideoSurfaceContainer*
+  OverrideCreateExternalVideoSurfaceContainer(
+      content::WebContents* web_contents) override;
 #endif
-  virtual content::DevToolsManagerDelegate*
-      GetDevToolsManagerDelegate() override;
+  content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
 
  private:
   // Android WebView currently has a single global (non-off-the-record) browser
diff --git a/android_webview/browser/aw_dev_tools_manager_delegate.cc b/android_webview/browser/aw_dev_tools_manager_delegate.cc
index 8cc3ce8..c1f2e3f 100644
--- a/android_webview/browser/aw_dev_tools_manager_delegate.cc
+++ b/android_webview/browser/aw_dev_tools_manager_delegate.cc
@@ -30,9 +30,9 @@
  public:
   explicit Target(scoped_refptr<DevToolsAgentHost> agent_host);
 
-  virtual std::string GetId() const override { return agent_host_->GetId(); }
-  virtual std::string GetParentId() const override { return std::string(); }
-  virtual std::string GetType() const override {
+  std::string GetId() const override { return agent_host_->GetId(); }
+  std::string GetParentId() const override { return std::string(); }
+  std::string GetType() const override {
     switch (agent_host_->GetType()) {
       case DevToolsAgentHost::TYPE_WEB_CONTENTS:
         return kTargetTypePage;
@@ -43,23 +43,19 @@
     }
     return kTargetTypeOther;
   }
-  virtual std::string GetTitle() const override {
-    return agent_host_->GetTitle();
-  }
-  virtual std::string GetDescription() const override { return description_; }
-  virtual GURL GetURL() const override { return agent_host_->GetURL(); }
-  virtual GURL GetFaviconURL() const override { return GURL(); }
-  virtual base::TimeTicks GetLastActivityTime() const override {
+  std::string GetTitle() const override { return agent_host_->GetTitle(); }
+  std::string GetDescription() const override { return description_; }
+  GURL GetURL() const override { return agent_host_->GetURL(); }
+  GURL GetFaviconURL() const override { return GURL(); }
+  base::TimeTicks GetLastActivityTime() const override {
     return last_activity_time_;
   }
-  virtual bool IsAttached() const override {
-    return agent_host_->IsAttached();
-  }
-  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const override {
+  bool IsAttached() const override { return agent_host_->IsAttached(); }
+  scoped_refptr<DevToolsAgentHost> GetAgentHost() const override {
     return agent_host_;
   }
-  virtual bool Activate() const override { return agent_host_->Activate(); }
-  virtual bool Close() const override { return agent_host_->Close(); }
+  bool Activate() const override { return agent_host_->Activate(); }
+  bool Close() const override { return agent_host_->Close(); }
 
  private:
   scoped_refptr<DevToolsAgentHost> agent_host_;
diff --git a/android_webview/browser/aw_dev_tools_manager_delegate.h b/android_webview/browser/aw_dev_tools_manager_delegate.h
index ea72c6f..68f22851 100644
--- a/android_webview/browser/aw_dev_tools_manager_delegate.h
+++ b/android_webview/browser/aw_dev_tools_manager_delegate.h
@@ -13,22 +13,19 @@
 class AwDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
  public:
   AwDevToolsManagerDelegate();
-  virtual ~AwDevToolsManagerDelegate();
+  ~AwDevToolsManagerDelegate() override;
 
   // content::DevToolsManagerDelegate implementation.
-  virtual void Inspect(
-      content::BrowserContext* browser_context,
-      content::DevToolsAgentHost* agent_host) override {}
-  virtual void DevToolsAgentStateChanged(
-      content::DevToolsAgentHost* agent_host,
-      bool attached) override {}
-  virtual base::DictionaryValue* HandleCommand(
+  void Inspect(content::BrowserContext* browser_context,
+               content::DevToolsAgentHost* agent_host) override {}
+  void DevToolsAgentStateChanged(content::DevToolsAgentHost* agent_host,
+                                 bool attached) override {}
+  base::DictionaryValue* HandleCommand(
       content::DevToolsAgentHost* agent_host,
       base::DictionaryValue* command_dict) override;
-  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget(
-      const GURL& url) override;
-  virtual void EnumerateTargets(TargetCallback callback) override;
-  virtual std::string GetPageThumbnailData(const GURL& url) override;
+  scoped_ptr<content::DevToolsTarget> CreateNewTarget(const GURL& url) override;
+  void EnumerateTargets(TargetCallback callback) override;
+  std::string GetPageThumbnailData(const GURL& url) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AwDevToolsManagerDelegate);
diff --git a/android_webview/browser/aw_download_manager_delegate.h b/android_webview/browser/aw_download_manager_delegate.h
index 6aed565..36b3d6b 100644
--- a/android_webview/browser/aw_download_manager_delegate.h
+++ b/android_webview/browser/aw_download_manager_delegate.h
@@ -13,19 +13,18 @@
 // unconditionally cancel the download.
 class AwDownloadManagerDelegate : public content::DownloadManagerDelegate {
  public:
-  virtual ~AwDownloadManagerDelegate();
+  ~AwDownloadManagerDelegate() override;
 
   // content::DownloadManagerDelegate implementation.
-  virtual bool DetermineDownloadTarget(
+  bool DetermineDownloadTarget(
       content::DownloadItem* item,
       const content::DownloadTargetCallback& callback) override;
-  virtual bool ShouldCompleteDownload(
-      content::DownloadItem* item,
-      const base::Closure& complete_callback) override;
-  virtual bool ShouldOpenDownload(
+  bool ShouldCompleteDownload(content::DownloadItem* item,
+                              const base::Closure& complete_callback) override;
+  bool ShouldOpenDownload(
       content::DownloadItem* item,
       const content::DownloadOpenDelayedCallback& callback) override;
-  virtual void GetNextId(const content::DownloadIdCallback& callback) override;
+  void GetNextId(const content::DownloadIdCallback& callback) override;
 };
 
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_form_database_service.h b/android_webview/browser/aw_form_database_service.h
index 5a58953..857b23a 100644
--- a/android_webview/browser/aw_form_database_service.h
+++ b/android_webview/browser/aw_form_database_service.h
@@ -25,7 +25,7 @@
  public:
   AwFormDatabaseService(const base::FilePath path);
 
-  virtual ~AwFormDatabaseService();
+  ~AwFormDatabaseService() override;
 
   void Shutdown();
 
@@ -40,9 +40,8 @@
       get_autofill_webdata_service();
 
   // WebDataServiceConsumer implementation.
-  virtual void OnWebDataServiceRequestDone(
-      WebDataServiceBase::Handle h,
-      const WDTypedResult* result) override;
+  void OnWebDataServiceRequestDone(WebDataServiceBase::Handle h,
+                                   const WDTypedResult* result) override;
 
  private:
   struct PendingQuery {
diff --git a/android_webview/browser/aw_form_database_service_unittest.cc b/android_webview/browser/aw_form_database_service_unittest.cc
index 9750fc8..34f4449 100644
--- a/android_webview/browser/aw_form_database_service_unittest.cc
+++ b/android_webview/browser/aw_form_database_service_unittest.cc
@@ -33,7 +33,7 @@
   }
 
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     env_ = AttachCurrentThread();
     ASSERT_TRUE(env_ != NULL);
@@ -42,9 +42,7 @@
     service_.reset(new AwFormDatabaseService(temp_dir_.path()));
   }
 
-  virtual void TearDown() {
-    service_->Shutdown();
-  }
+  void TearDown() override { service_->Shutdown(); }
 
   // The path to the temporary directory used for the test operations.
   base::ScopedTempDir temp_dir_;
diff --git a/android_webview/browser/aw_gl_surface.h b/android_webview/browser/aw_gl_surface.h
index 9e48133c..128b5515 100644
--- a/android_webview/browser/aw_gl_surface.h
+++ b/android_webview/browser/aw_gl_surface.h
@@ -17,19 +17,19 @@
   AwGLSurface();
 
   // Implement GLSurface.
-  virtual void Destroy() override;
-  virtual bool IsOffscreen() override;
-  virtual unsigned int GetBackingFrameBufferObject() override;
-  virtual bool SwapBuffers() override;
-  virtual gfx::Size GetSize() override;
-  virtual void* GetHandle() override;
-  virtual void* GetDisplay() override;
+  void Destroy() override;
+  bool IsOffscreen() override;
+  unsigned int GetBackingFrameBufferObject() override;
+  bool SwapBuffers() override;
+  gfx::Size GetSize() override;
+  void* GetHandle() override;
+  void* GetDisplay() override;
 
   void SetBackingFrameBufferObject(unsigned int fbo);
   void ResetBackingFrameBufferObject();
 
  protected:
-  virtual ~AwGLSurface();
+  ~AwGLSurface() override;
 
  private:
   unsigned int fbo_;
diff --git a/android_webview/browser/aw_javascript_dialog_manager.h b/android_webview/browser/aw_javascript_dialog_manager.h
index edd6d38..8713e3d 100644
--- a/android_webview/browser/aw_javascript_dialog_manager.h
+++ b/android_webview/browser/aw_javascript_dialog_manager.h
@@ -12,27 +12,24 @@
 class AwJavaScriptDialogManager : public content::JavaScriptDialogManager {
  public:
   explicit AwJavaScriptDialogManager();
-  virtual ~AwJavaScriptDialogManager();
+  ~AwJavaScriptDialogManager() override;
 
   // Overridden from content::JavaScriptDialogManager:
-  virtual void RunJavaScriptDialog(
-      content::WebContents* web_contents,
-      const GURL& origin_url,
-      const std::string& accept_lang,
-      content::JavaScriptMessageType message_type,
-      const base::string16& message_text,
-      const base::string16& default_prompt_text,
-      const DialogClosedCallback& callback,
-      bool* did_suppress_message) override;
-  virtual void RunBeforeUnloadDialog(
-      content::WebContents* web_contents,
-      const base::string16& message_text,
-      bool is_reload,
-      const DialogClosedCallback& callback) override;
-  virtual void CancelActiveAndPendingDialogs(
+  void RunJavaScriptDialog(content::WebContents* web_contents,
+                           const GURL& origin_url,
+                           const std::string& accept_lang,
+                           content::JavaScriptMessageType message_type,
+                           const base::string16& message_text,
+                           const base::string16& default_prompt_text,
+                           const DialogClosedCallback& callback,
+                           bool* did_suppress_message) override;
+  void RunBeforeUnloadDialog(content::WebContents* web_contents,
+                             const base::string16& message_text,
+                             bool is_reload,
+                             const DialogClosedCallback& callback) override;
+  void CancelActiveAndPendingDialogs(
       content::WebContents* web_contents) override;
-  virtual void WebContentsDestroyed(
-      content::WebContents* web_contents) override;
+  void WebContentsDestroyed(content::WebContents* web_contents) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AwJavaScriptDialogManager);
diff --git a/android_webview/browser/aw_login_delegate.h b/android_webview/browser/aw_login_delegate.h
index bb0fe44..0331c6b5 100644
--- a/android_webview/browser/aw_login_delegate.h
+++ b/android_webview/browser/aw_login_delegate.h
@@ -29,10 +29,10 @@
   virtual void Cancel();
 
   // from ResourceDispatcherHostLoginDelegate
-  virtual void OnRequestCancelled() override;
+  void OnRequestCancelled() override;
 
  private:
-  virtual ~AwLoginDelegate();
+  ~AwLoginDelegate() override;
   void HandleHttpAuthRequestOnUIThread(bool first_auth_attempt);
   void CancelOnIOThread();
   void ProceedOnIOThread(const base::string16& user,
diff --git a/android_webview/browser/aw_pref_store.h b/android_webview/browser/aw_pref_store.h
index dec25b57..6935c719 100644
--- a/android_webview/browser/aw_pref_store.h
+++ b/android_webview/browser/aw_pref_store.h
@@ -22,29 +22,27 @@
   AwPrefStore();
 
   // Overriden from PrefStore.
-  virtual bool GetValue(const std::string& key,
-                        const base::Value** result) const override;
-  virtual void AddObserver(PrefStore::Observer* observer) override;
-  virtual void RemoveObserver(PrefStore::Observer* observer) override;
-  virtual bool HasObservers() const override;
-  virtual bool IsInitializationComplete() const override;
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+  bool IsInitializationComplete() const override;
 
   // PersistentPrefStore overrides:
-  virtual bool GetMutableValue(const std::string& key,
-                               base::Value** result) override;
-  virtual void ReportValueChanged(const std::string& key) override;
-  virtual void SetValue(const std::string& key, base::Value* value) override;
-  virtual void SetValueSilently(const std::string& key,
-                                base::Value* value) override;
-  virtual void RemoveValue(const std::string& key) override;
-  virtual bool ReadOnly() const override;
-  virtual PrefReadError GetReadError() const override;
-  virtual PersistentPrefStore::PrefReadError ReadPrefs() override;
-  virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
-  virtual void CommitPendingWrite() override {}
+  bool GetMutableValue(const std::string& key, base::Value** result) override;
+  void ReportValueChanged(const std::string& key) override;
+  void SetValue(const std::string& key, base::Value* value) override;
+  void SetValueSilently(const std::string& key, base::Value* value) override;
+  void RemoveValue(const std::string& key) override;
+  bool ReadOnly() const override;
+  PrefReadError GetReadError() const override;
+  PersistentPrefStore::PrefReadError ReadPrefs() override;
+  void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+  void CommitPendingWrite() override {}
 
  protected:
-  virtual ~AwPrefStore();
+  ~AwPrefStore() override;
 
  private:
   // Stores the preference values.
diff --git a/android_webview/browser/aw_quota_permission_context.h b/android_webview/browser/aw_quota_permission_context.h
index a42f00b..035557e 100644
--- a/android_webview/browser/aw_quota_permission_context.h
+++ b/android_webview/browser/aw_quota_permission_context.h
@@ -14,13 +14,12 @@
  public:
   AwQuotaPermissionContext();
 
-  virtual void RequestQuotaPermission(
-      const content::StorageQuotaParams& params,
-      int render_process_id,
-      const PermissionCallback& callback) override;
+  void RequestQuotaPermission(const content::StorageQuotaParams& params,
+                              int render_process_id,
+                              const PermissionCallback& callback) override;
 
  private:
-  virtual ~AwQuotaPermissionContext();
+  ~AwQuotaPermissionContext() override;
 
   DISALLOW_COPY_AND_ASSIGN(AwQuotaPermissionContext);
 };
diff --git a/android_webview/browser/aw_request_interceptor.h b/android_webview/browser/aw_request_interceptor.h
index d66f1b6c..adbb18b 100644
--- a/android_webview/browser/aw_request_interceptor.h
+++ b/android_webview/browser/aw_request_interceptor.h
@@ -27,10 +27,10 @@
 class AwRequestInterceptor : public net::URLRequestInterceptor {
  public:
   AwRequestInterceptor();
-  virtual ~AwRequestInterceptor();
+  ~AwRequestInterceptor() override;
 
   // net::URLRequestInterceptor override --------------------------------------
-  virtual net::URLRequestJob* MaybeInterceptRequest(
+  net::URLRequestJob* MaybeInterceptRequest(
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate) const override;
 
diff --git a/android_webview/browser/aw_resource_context.h b/android_webview/browser/aw_resource_context.h
index 87396df..49922ca 100644
--- a/android_webview/browser/aw_resource_context.h
+++ b/android_webview/browser/aw_resource_context.h
@@ -20,14 +20,14 @@
 class AwResourceContext : public content::ResourceContext {
  public:
   explicit AwResourceContext(net::URLRequestContextGetter* getter);
-  virtual ~AwResourceContext();
+  ~AwResourceContext() override;
 
   void SetExtraHeaders(const GURL& url, const std::string& headers);
   std::string GetExtraHeaders(const GURL& url);
 
   // content::ResourceContext implementation.
-  virtual net::HostResolver* GetHostResolver() override;
-  virtual net::URLRequestContext* GetRequestContext() override;
+  net::HostResolver* GetHostResolver() override;
+  net::URLRequestContext* GetRequestContext() override;
 
  private:
   net::URLRequestContextGetter* getter_;
diff --git a/android_webview/browser/aw_ssl_host_state_delegate.h b/android_webview/browser/aw_ssl_host_state_delegate.h
index 1297af9..bc3e1a8 100644
--- a/android_webview/browser/aw_ssl_host_state_delegate.h
+++ b/android_webview/browser/aw_ssl_host_state_delegate.h
@@ -41,7 +41,7 @@
 class AwSSLHostStateDelegate : public content::SSLHostStateDelegate {
  public:
   AwSSLHostStateDelegate();
-  virtual ~AwSSLHostStateDelegate();
+  ~AwSSLHostStateDelegate() override;
 
   // Records that |cert| is permitted to be used for |host| in the future, for
   // a specified |error| type.
diff --git a/android_webview/browser/aw_web_resource_response.cc b/android_webview/browser/aw_web_resource_response.cc
index 78a30a8..44f2aa8 100644
--- a/android_webview/browser/aw_web_resource_response.cc
+++ b/android_webview/browser/aw_web_resource_response.cc
@@ -22,33 +22,32 @@
     DCHECK(aw_web_resource_response_);
   }
 
-  virtual scoped_ptr<InputStream> OpenInputStream(JNIEnv* env,
-                                                  const GURL& url) override {
+  scoped_ptr<InputStream> OpenInputStream(JNIEnv* env,
+                                          const GURL& url) override {
     return aw_web_resource_response_->GetInputStream(env).Pass();
   }
 
-  virtual void OnInputStreamOpenFailed(net::URLRequest* request,
-                                       bool* restart) override {
+  void OnInputStreamOpenFailed(net::URLRequest* request,
+                               bool* restart) override {
     *restart = false;
   }
 
-  virtual bool GetMimeType(JNIEnv* env,
-                           net::URLRequest* request,
-                           android_webview::InputStream* stream,
-                           std::string* mime_type) override {
+  bool GetMimeType(JNIEnv* env,
+                   net::URLRequest* request,
+                   android_webview::InputStream* stream,
+                   std::string* mime_type) override {
     return aw_web_resource_response_->GetMimeType(env, mime_type);
   }
 
-  virtual bool GetCharset(JNIEnv* env,
-                          net::URLRequest* request,
-                          android_webview::InputStream* stream,
-                          std::string* charset) override {
+  bool GetCharset(JNIEnv* env,
+                  net::URLRequest* request,
+                  android_webview::InputStream* stream,
+                  std::string* charset) override {
     return aw_web_resource_response_->GetCharset(env, charset);
   }
 
-  virtual void AppendResponseHeaders(
-      JNIEnv* env,
-      net::HttpResponseHeaders* headers) override {
+  void AppendResponseHeaders(JNIEnv* env,
+                             net::HttpResponseHeaders* headers) override {
     int status_code;
     std::string reason_phrase;
     if (aw_web_resource_response_->GetStatusInfo(
diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h
index bf2b23d..c016cf1 100644
--- a/android_webview/browser/browser_view_renderer.h
+++ b/android_webview/browser/browser_view_renderer.h
@@ -32,7 +32,7 @@
       BrowserViewRendererClient* client,
       const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
 
-  virtual ~BrowserViewRenderer();
+  ~BrowserViewRenderer() override;
 
   SharedRendererState* GetAwDrawGLViewContext();
   bool RequestDrawGL(bool wait_for_completion);
@@ -80,24 +80,23 @@
   void TrimMemory(const int level, const bool visible);
 
   // SynchronousCompositorClient overrides.
-  virtual void DidInitializeCompositor(
+  void DidInitializeCompositor(
       content::SynchronousCompositor* compositor) override;
-  virtual void DidDestroyCompositor(content::SynchronousCompositor* compositor)
-      override;
-  virtual void SetContinuousInvalidate(bool invalidate) override;
-  virtual void DidUpdateContent() override;
-  virtual gfx::Vector2dF GetTotalRootLayerScrollOffset() override;
-  virtual void UpdateRootLayerState(
-      const gfx::Vector2dF& total_scroll_offset_dip,
-      const gfx::Vector2dF& max_scroll_offset_dip,
-      const gfx::SizeF& scrollable_size_dip,
-      float page_scale_factor,
-      float min_page_scale_factor,
-      float max_page_scale_factor) override;
-  virtual bool IsExternalFlingActive() const override;
-  virtual void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
-                             gfx::Vector2dF latest_overscroll_delta,
-                             gfx::Vector2dF current_fling_velocity) override;
+  void DidDestroyCompositor(
+      content::SynchronousCompositor* compositor) override;
+  void SetContinuousInvalidate(bool invalidate) override;
+  void DidUpdateContent() override;
+  gfx::Vector2dF GetTotalRootLayerScrollOffset() override;
+  void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset_dip,
+                            const gfx::Vector2dF& max_scroll_offset_dip,
+                            const gfx::SizeF& scrollable_size_dip,
+                            float page_scale_factor,
+                            float min_page_scale_factor,
+                            float max_page_scale_factor) override;
+  bool IsExternalFlingActive() const override;
+  void DidOverscroll(gfx::Vector2dF accumulated_overscroll,
+                     gfx::Vector2dF latest_overscroll_delta,
+                     gfx::Vector2dF current_fling_velocity) override;
 
   void UpdateParentDrawConstraints();
   void DidSkipCommitFrame();
diff --git a/android_webview/browser/deferred_gpu_command_service.h b/android_webview/browser/deferred_gpu_command_service.h
index bd361b7..0b092ed 100644
--- a/android_webview/browser/deferred_gpu_command_service.h
+++ b/android_webview/browser/deferred_gpu_command_service.h
@@ -36,11 +36,11 @@
   static void SetInstance();
   static DeferredGpuCommandService* GetInstance();
 
-  virtual void ScheduleTask(const base::Closure& task) override;
-  virtual void ScheduleIdleWork(const base::Closure& task) override;
-  virtual bool UseVirtualizedGLContexts() override;
-  virtual scoped_refptr<gpu::gles2::ShaderTranslatorCache>
-      shader_translator_cache() override;
+  void ScheduleTask(const base::Closure& task) override;
+  void ScheduleIdleWork(const base::Closure& task) override;
+  bool UseVirtualizedGLContexts() override;
+  scoped_refptr<gpu::gles2::ShaderTranslatorCache> shader_translator_cache()
+      override;
 
   void RunTasks();
   // If |is_idle| is false, this will only run older idle tasks.
@@ -50,11 +50,11 @@
   // idle tasks during the idle run.
   void PerformAllIdleWork();
 
-  virtual void AddRef() const override;
-  virtual void Release() const override;
+  void AddRef() const override;
+  void Release() const override;
 
  protected:
-  virtual ~DeferredGpuCommandService();
+  ~DeferredGpuCommandService() override;
   friend class base::RefCountedThreadSafe<DeferredGpuCommandService>;
 
  private:
diff --git a/android_webview/browser/find_helper.h b/android_webview/browser/find_helper.h
index eabf1975..198d947 100644
--- a/android_webview/browser/find_helper.h
+++ b/android_webview/browser/find_helper.h
@@ -25,7 +25,7 @@
   };
 
   explicit FindHelper(content::WebContents* web_contents);
-  virtual ~FindHelper();
+  ~FindHelper() override;
 
   // Sets the listener to receive find result updates.
   // Does not own the listener and must set to NULL when invalid.
diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h
index 671b3ca2..67a9f90 100644
--- a/android_webview/browser/hardware_renderer.h
+++ b/android_webview/browser/hardware_renderer.h
@@ -31,7 +31,7 @@
                          public cc::DelegatedFrameResourceCollectionClient {
  public:
   explicit HardwareRenderer(SharedRendererState* state);
-  virtual ~HardwareRenderer();
+  ~HardwareRenderer() override;
 
   void DrawGL(bool stencil_enabled,
               int framebuffer_binding_ext,
@@ -39,34 +39,33 @@
   void CommitFrame();
 
   // cc::LayerTreeHostClient overrides.
-  virtual void WillBeginMainFrame(int frame_id) override {}
-  virtual void DidBeginMainFrame() override;
-  virtual void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
-  virtual void Layout() override {}
-  virtual void ApplyViewportDeltas(
-      const gfx::Vector2d& inner_delta,
-      const gfx::Vector2d& outer_delta,
-      const gfx::Vector2dF& elastic_overscroll_delta,
-      float page_scale,
-      float top_controls_delta) override {}
-  virtual void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
-                                   float page_scale,
-                                   float top_controls_delta) override {}
-  virtual void RequestNewOutputSurface() override;
-  virtual void DidInitializeOutputSurface() override {}
-  virtual void DidFailToInitializeOutputSurface() override;
-  virtual void WillCommit() override {}
-  virtual void DidCommit() override {}
-  virtual void DidCommitAndDrawFrame() override {}
-  virtual void DidCompleteSwapBuffers() override {}
-  virtual void DidCompletePageScaleAnimation() override {}
+  void WillBeginMainFrame() override {}
+  void DidBeginMainFrame() override;
+  void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
+  void Layout() override {}
+  void ApplyViewportDeltas(const gfx::Vector2d& inner_delta,
+                           const gfx::Vector2d& outer_delta,
+                           const gfx::Vector2dF& elastic_overscroll_delta,
+                           float page_scale,
+                           float top_controls_delta) override {}
+  void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
+                           float page_scale,
+                           float top_controls_delta) override {}
+  void RequestNewOutputSurface() override;
+  void DidInitializeOutputSurface() override {}
+  void DidFailToInitializeOutputSurface() override;
+  void WillCommit() override {}
+  void DidCommit() override {}
+  void DidCommitAndDrawFrame() override {}
+  void DidCompleteSwapBuffers() override {}
+  void DidCompletePageScaleAnimation() override {}
 
   // cc::LayerTreeHostSingleThreadClient overrides.
-  virtual void DidPostSwapBuffers() override {}
-  virtual void DidAbortSwapBuffers() override {}
+  void DidPostSwapBuffers() override {}
+  void DidAbortSwapBuffers() override {}
 
   // cc::DelegatedFrameResourceCollectionClient overrides.
-  virtual void UnusedResourcesAreAvailable() override;
+  void UnusedResourcesAreAvailable() override;
 
  private:
   void SetFrameData();
diff --git a/android_webview/browser/icon_helper.h b/android_webview/browser/icon_helper.h
index 287be27f..dc9a1d63f 100644
--- a/android_webview/browser/icon_helper.h
+++ b/android_webview/browser/icon_helper.h
@@ -37,14 +37,14 @@
   };
 
   explicit IconHelper(content::WebContents* web_contents);
-  virtual ~IconHelper();
+  ~IconHelper() override;
 
   void SetListener(Listener* listener);
 
   // From WebContentsObserver
-  virtual void DidUpdateFaviconURL(
+  void DidUpdateFaviconURL(
       const std::vector<content::FaviconURL>& candidates) override;
-  virtual void DidStartNavigationToPendingEntry(
+  void DidStartNavigationToPendingEntry(
       const GURL& url,
       content::NavigationController::ReloadType reload_type) override;
 
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.h b/android_webview/browser/net/android_stream_reader_url_request_job.h
index f3f230d2..903ba61 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job.h
+++ b/android_webview/browser/net/android_stream_reader_url_request_job.h
@@ -79,20 +79,17 @@
       scoped_ptr<Delegate> delegate);
 
   // URLRequestJob:
-  virtual void Start() override;
-  virtual void Kill() override;
-  virtual bool ReadRawData(net::IOBuffer* buf,
-                           int buf_size,
-                           int* bytes_read) override;
-  virtual void SetExtraRequestHeaders(
-      const net::HttpRequestHeaders& headers) override;
-  virtual bool GetMimeType(std::string* mime_type) const override;
-  virtual bool GetCharset(std::string* charset) override;
-  virtual int GetResponseCode() const override;
-  virtual void GetResponseInfo(net::HttpResponseInfo* info) override;
+  void Start() override;
+  void Kill() override;
+  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override;
+  void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
+  bool GetMimeType(std::string* mime_type) const override;
+  bool GetCharset(std::string* charset) override;
+  int GetResponseCode() const override;
+  void GetResponseInfo(net::HttpResponseInfo* info) override;
 
  protected:
-  virtual ~AndroidStreamReaderURLRequestJob();
+  ~AndroidStreamReaderURLRequestJob() override;
 
   // Gets the TaskRunner for the worker thread.
   // Overridden in unittests.
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc b/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc
index 4b80c41f..b9332c5 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc
+++ b/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc
@@ -51,16 +51,16 @@
 class NotImplInputStream : public InputStream {
  public:
   NotImplInputStream() {}
-  virtual ~NotImplInputStream() {}
-  virtual bool BytesAvailable(int* bytes_available) const override {
+  ~NotImplInputStream() override {}
+  bool BytesAvailable(int* bytes_available) const override {
     NOTIMPLEMENTED();
     return false;
   }
-  virtual bool Skip(int64_t n, int64_t* bytes_skipped) override {
+  bool Skip(int64_t n, int64_t* bytes_skipped) override {
     NOTIMPLEMENTED();
     return false;
   }
-  virtual bool Read(net::IOBuffer* dest, int length, int* bytes_read) override {
+  bool Read(net::IOBuffer* dest, int length, int* bytes_read) override {
     NOTIMPLEMENTED();
     return false;
   }
@@ -72,34 +72,32 @@
  public:
   StreamReaderDelegate() {}
 
-  virtual scoped_ptr<InputStream> OpenInputStream(
-      JNIEnv* env,
-      const GURL& url) override {
+  scoped_ptr<InputStream> OpenInputStream(JNIEnv* env,
+                                          const GURL& url) override {
     return make_scoped_ptr<InputStream>(new NotImplInputStream());
   }
 
-  virtual void OnInputStreamOpenFailed(net::URLRequest* request,
-                                       bool* restart) override {
+  void OnInputStreamOpenFailed(net::URLRequest* request,
+                               bool* restart) override {
     *restart = false;
   }
 
-  virtual bool GetMimeType(JNIEnv* env,
-                           net::URLRequest* request,
-                           android_webview::InputStream* stream,
-                           std::string* mime_type) override {
+  bool GetMimeType(JNIEnv* env,
+                   net::URLRequest* request,
+                   android_webview::InputStream* stream,
+                   std::string* mime_type) override {
     return false;
   }
 
-  virtual bool GetCharset(JNIEnv* env,
-                          net::URLRequest* request,
-                          android_webview::InputStream* stream,
-                          std::string* charset) override {
+  bool GetCharset(JNIEnv* env,
+                  net::URLRequest* request,
+                  android_webview::InputStream* stream,
+                  std::string* charset) override {
     return false;
   }
 
-  virtual void AppendResponseHeaders(
-      JNIEnv* env,
-      net::HttpResponseHeaders* headers) override {
+  void AppendResponseHeaders(JNIEnv* env,
+                             net::HttpResponseHeaders* headers) override {
     // no-op
   }
 };
@@ -108,9 +106,8 @@
  public:
   NullStreamReaderDelegate() {}
 
-  virtual scoped_ptr<InputStream> OpenInputStream(
-      JNIEnv* env,
-      const GURL& url) override {
+  scoped_ptr<InputStream> OpenInputStream(JNIEnv* env,
+                                          const GURL& url) override {
     return make_scoped_ptr<InputStream>(NULL);
   }
 };
@@ -119,9 +116,8 @@
  public:
   HeaderAlteringStreamReaderDelegate() {}
 
-  virtual void AppendResponseHeaders(
-      JNIEnv* env,
-      net::HttpResponseHeaders* headers) override {
+  void AppendResponseHeaders(JNIEnv* env,
+                             net::HttpResponseHeaders* headers) override {
     headers->ReplaceStatusLine(kStatusLine);
     std::string headerLine(kCustomHeaderName);
     headerLine.append(": ");
@@ -167,14 +163,14 @@
     message_loop_proxy_ = base::MessageLoopProxy::current();
   }
 
-  virtual scoped_ptr<InputStreamReader> CreateStreamReader(
+  scoped_ptr<InputStreamReader> CreateStreamReader(
       InputStream* stream) override {
     return stream_reader_.Pass();
   }
  protected:
-  virtual ~TestStreamReaderJob() {}
+  ~TestStreamReaderJob() override {}
 
-  virtual base::TaskRunner* GetWorkerThreadRunner() override {
+  base::TaskRunner* GetWorkerThreadRunner() override {
     return message_loop_proxy_.get();
   }
 
@@ -187,7 +183,7 @@
   AndroidStreamReaderURLRequestJobTest() {}
 
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     context_.set_job_factory(&factory_);
     context_.set_network_delegate(&network_delegate_);
     req_ = context_.CreateRequest(GURL("content://foo"),
diff --git a/android_webview/browser/net/aw_network_delegate.h b/android_webview/browser/net/aw_network_delegate.h
index c925db9..da6723b8 100644
--- a/android_webview/browser/net/aw_network_delegate.h
+++ b/android_webview/browser/net/aw_network_delegate.h
@@ -19,47 +19,44 @@
 class AwNetworkDelegate : public net::NetworkDelegateImpl {
  public:
   AwNetworkDelegate();
-  virtual ~AwNetworkDelegate();
+  ~AwNetworkDelegate() override;
 
  private:
   // NetworkDelegate implementation.
-  virtual int OnBeforeURLRequest(net::URLRequest* request,
-                                 const net::CompletionCallback& callback,
-                                 GURL* new_url) override;
-  virtual int OnBeforeSendHeaders(net::URLRequest* request,
-                                  const net::CompletionCallback& callback,
-                                  net::HttpRequestHeaders* headers) override;
-  virtual void OnSendHeaders(net::URLRequest* request,
-                             const net::HttpRequestHeaders& headers) override;
-  virtual int OnHeadersReceived(
+  int OnBeforeURLRequest(net::URLRequest* request,
+                         const net::CompletionCallback& callback,
+                         GURL* new_url) override;
+  int OnBeforeSendHeaders(net::URLRequest* request,
+                          const net::CompletionCallback& callback,
+                          net::HttpRequestHeaders* headers) override;
+  void OnSendHeaders(net::URLRequest* request,
+                     const net::HttpRequestHeaders& headers) override;
+  int OnHeadersReceived(
       net::URLRequest* request,
       const net::CompletionCallback& callback,
       const net::HttpResponseHeaders* original_response_headers,
       scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
       GURL* allowed_unsafe_redirect_url) override;
-  virtual void OnBeforeRedirect(net::URLRequest* request,
-                                const GURL& new_location) override;
-  virtual void OnResponseStarted(net::URLRequest* request) override;
-  virtual void OnRawBytesRead(const net::URLRequest& request,
-                              int bytes_read) override;
-  virtual void OnCompleted(net::URLRequest* request, bool started) override;
-  virtual void OnURLRequestDestroyed(net::URLRequest* request) override;
-  virtual void OnPACScriptError(int line_number,
-                                const base::string16& error) override;
-  virtual net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(
+  void OnBeforeRedirect(net::URLRequest* request,
+                        const GURL& new_location) override;
+  void OnResponseStarted(net::URLRequest* request) override;
+  void OnRawBytesRead(const net::URLRequest& request, int bytes_read) override;
+  void OnCompleted(net::URLRequest* request, bool started) override;
+  void OnURLRequestDestroyed(net::URLRequest* request) override;
+  void OnPACScriptError(int line_number, const base::string16& error) override;
+  net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(
       net::URLRequest* request,
       const net::AuthChallengeInfo& auth_info,
       const AuthCallback& callback,
       net::AuthCredentials* credentials) override;
-  virtual bool OnCanGetCookies(const net::URLRequest& request,
-                               const net::CookieList& cookie_list) override;
-  virtual bool OnCanSetCookie(const net::URLRequest& request,
-                              const std::string& cookie_line,
-                              net::CookieOptions* options) override;
-  virtual bool OnCanAccessFile(const net::URLRequest& request,
-                               const base::FilePath& path) const override;
-  virtual bool OnCanThrottleRequest(
-      const net::URLRequest& request) const override;
+  bool OnCanGetCookies(const net::URLRequest& request,
+                       const net::CookieList& cookie_list) override;
+  bool OnCanSetCookie(const net::URLRequest& request,
+                      const std::string& cookie_line,
+                      net::CookieOptions* options) override;
+  bool OnCanAccessFile(const net::URLRequest& request,
+                       const base::FilePath& path) const override;
+  bool OnCanThrottleRequest(const net::URLRequest& request) const override;
 
   DISALLOW_COPY_AND_ASSIGN(AwNetworkDelegate);
 };
diff --git a/android_webview/browser/net/aw_url_request_context_getter.h b/android_webview/browser/net/aw_url_request_context_getter.h
index 50736ba..fbaf24a3 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.h
+++ b/android_webview/browser/net/aw_url_request_context_getter.h
@@ -39,9 +39,9 @@
       scoped_ptr<net::ProxyConfigService> config_service);
 
   // net::URLRequestContextGetter implementation.
-  virtual net::URLRequestContext* GetURLRequestContext() override;
-  virtual scoped_refptr<base::SingleThreadTaskRunner>
-      GetNetworkTaskRunner() const override;
+  net::URLRequestContext* GetURLRequestContext() override;
+  scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
+      const override;
 
   data_reduction_proxy::DataReductionProxyAuthRequestHandler*
       GetDataReductionProxyAuthRequestHandler() const;
@@ -56,7 +56,7 @@
 
  private:
   friend class AwBrowserContext;
-  virtual ~AwURLRequestContextGetter();
+  ~AwURLRequestContextGetter() override;
 
   // Prior to GetURLRequestContext() being called, this is called to hand over
   // the objects that GetURLRequestContext() will later install into
diff --git a/android_webview/browser/net/aw_url_request_job_factory.h b/android_webview/browser/net/aw_url_request_job_factory.h
index db1cfae6..458c1b02 100644
--- a/android_webview/browser/net/aw_url_request_job_factory.h
+++ b/android_webview/browser/net/aw_url_request_job_factory.h
@@ -23,7 +23,7 @@
 class AwURLRequestJobFactory : public net::URLRequestJobFactory {
  public:
   AwURLRequestJobFactory();
-  virtual ~AwURLRequestJobFactory();
+  ~AwURLRequestJobFactory() override;
 
   bool SetProtocolHandler(const std::string& scheme,
                           ProtocolHandler* protocol_handler);
@@ -43,9 +43,9 @@
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate) const override;
 
-  virtual bool IsHandledProtocol(const std::string& scheme) const override;
-  virtual bool IsHandledURL(const GURL& url) const override;
-  virtual bool IsSafeRedirectTarget(const GURL& location) const override;
+  bool IsHandledProtocol(const std::string& scheme) const override;
+  bool IsHandledURL(const GURL& url) const override;
+  bool IsSafeRedirectTarget(const GURL& location) const override;
 
  private:
   // By default calls are forwarded to this factory, to avoid having to
diff --git a/android_webview/browser/parent_output_surface.h b/android_webview/browser/parent_output_surface.h
index 03cd5dd6..442501da 100644
--- a/android_webview/browser/parent_output_surface.h
+++ b/android_webview/browser/parent_output_surface.h
@@ -13,11 +13,11 @@
  public:
   explicit ParentOutputSurface(
       scoped_refptr<cc::ContextProvider> context_provider);
-  virtual ~ParentOutputSurface();
+  ~ParentOutputSurface() override;
 
   // OutputSurface overrides.
-  virtual void Reshape(const gfx::Size& size, float scale_factor) override {}
-  virtual void SwapBuffers(cc::CompositorFrame* frame) override;
+  void Reshape(const gfx::Size& size, float scale_factor) override {}
+  void SwapBuffers(cc::CompositorFrame* frame) override;
   using cc::OutputSurface::SetExternalStencilTest;
 
   void SetDrawConstraints(const gfx::Size& surface_size, const gfx::Rect& clip);
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.h b/android_webview/browser/renderer_host/aw_render_view_host_ext.h
index a0d426bd..3abd8d8 100644
--- a/android_webview/browser/renderer_host/aw_render_view_host_ext.h
+++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.h
@@ -45,7 +45,7 @@
   // as it internally handles RenderViewHost instances changing underneath us.
   AwRenderViewHostExt(
       AwRenderViewHostExtClient* client, content::WebContents* contents);
-  virtual ~AwRenderViewHostExt();
+  ~AwRenderViewHostExt() override;
 
   // |result| will be invoked with the outcome of the request.
   typedef base::Callback<void(bool)> DocumentHasImagesResult;
@@ -82,13 +82,12 @@
 
  private:
   // content::WebContentsObserver implementation.
-  virtual void RenderViewCreated(content::RenderViewHost* view_host) override;
-  virtual void RenderProcessGone(base::TerminationStatus status) override;
-  virtual void DidNavigateAnyFrame(
-      content::RenderFrameHost* render_frame_host,
-      const content::LoadCommittedDetails& details,
-      const content::FrameNavigateParams& params) override;
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
+  void RenderViewCreated(content::RenderViewHost* view_host) override;
+  void RenderProcessGone(base::TerminationStatus status) override;
+  void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host,
+                           const content::LoadCommittedDetails& details,
+                           const content::FrameNavigateParams& params) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
 
   void OnDocumentHasImagesResponse(int msg_id, bool has_images);
   void OnUpdateHitTestData(const AwHitTestData& hit_test_data);
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index d5f1864..efe1707 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -63,12 +63,12 @@
   IoThreadClientThrottle(int render_process_id,
                          int render_frame_id,
                          net::URLRequest* request);
-  virtual ~IoThreadClientThrottle();
+  ~IoThreadClientThrottle() override;
 
   // From content::ResourceThrottle
-  virtual void WillStartRequest(bool* defer) override;
-  virtual void WillRedirectRequest(const GURL& new_url, bool* defer) override;
-  virtual const char* GetNameForLogging() const override;
+  void WillStartRequest(bool* defer) override;
+  void WillRedirectRequest(const GURL& new_url, bool* defer) override;
+  const char* GetNameForLogging() const override;
 
   void OnIoThreadClientReady(int new_render_process_id,
                              int new_render_frame_id);
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
index 25ec4ff..dd08235a 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
@@ -29,13 +29,13 @@
   static void ResourceDispatcherHostCreated();
 
   // Overriden methods from ResourceDispatcherHostDelegate.
-  virtual void RequestBeginning(
+  void RequestBeginning(
       net::URLRequest* request,
       content::ResourceContext* resource_context,
       content::AppCacheService* appcache_service,
       content::ResourceType resource_type,
       ScopedVector<content::ResourceThrottle>* throttles) override;
-  virtual void DownloadStarting(
+  void DownloadStarting(
       net::URLRequest* request,
       content::ResourceContext* resource_context,
       int child_id,
@@ -44,23 +44,21 @@
       bool is_content_initiated,
       bool must_download,
       ScopedVector<content::ResourceThrottle>* throttles) override;
-  virtual content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
+  content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
       net::AuthChallengeInfo* auth_info,
       net::URLRequest* request) override;
-  virtual bool HandleExternalProtocol(const GURL& url,
-                                      int child_id,
-                                      int route_id) override;
-  virtual void OnResponseStarted(
-      net::URLRequest* request,
-      content::ResourceContext* resource_context,
-      content::ResourceResponse* response,
-      IPC::Sender* sender) override;
+  bool HandleExternalProtocol(const GURL& url,
+                              int child_id,
+                              int route_id) override;
+  void OnResponseStarted(net::URLRequest* request,
+                         content::ResourceContext* resource_context,
+                         content::ResourceResponse* response,
+                         IPC::Sender* sender) override;
 
-  virtual void OnRequestRedirected(
-      const GURL& redirect_url,
-      net::URLRequest* request,
-      content::ResourceContext* resource_context,
-      content::ResourceResponse* response) override;
+  void OnRequestRedirected(const GURL& redirect_url,
+                           net::URLRequest* request,
+                           content::ResourceContext* resource_context,
+                           content::ResourceResponse* response) override;
 
   void RemovePendingThrottleOnIoThread(IoThreadClientThrottle* throttle);
 
@@ -74,7 +72,7 @@
   friend struct base::DefaultLazyInstanceTraits<
       AwResourceDispatcherHostDelegate>;
   AwResourceDispatcherHostDelegate();
-  virtual ~AwResourceDispatcherHostDelegate();
+  ~AwResourceDispatcherHostDelegate() override;
 
   // These methods must be called on IO thread.
   void OnIoThreadClientReadyInternal(int new_render_process_id,
diff --git a/android_webview/browser/renderer_host/print_manager.h b/android_webview/browser/renderer_host/print_manager.h
index fc869cdd..3cb4495 100644
--- a/android_webview/browser/renderer_host/print_manager.h
+++ b/android_webview/browser/renderer_host/print_manager.h
@@ -47,7 +47,7 @@
       int fd,
       PrintManagerDelegate* delegate);
 
-  virtual ~PrintManager();
+  ~PrintManager() override;
 
   // Prints the current document immediately. Since the rendering is
   // asynchronous, the actual printing will not be completed on the return of
@@ -69,7 +69,7 @@
                 PrintManagerDelegate* delegate);
   friend class content::WebContentsUserData<PrintManager>;
 
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
   void OnDidGetPrintedPagesCount(int cookie, int number_pages);
   void OnDidGetDocumentCookie(int cookie);
   void OnPrintingFailed(int cookie);
diff --git a/android_webview/common/aw_content_client.h b/android_webview/common/aw_content_client.h
index 55a84e0..0a3a343 100644
--- a/android_webview/common/aw_content_client.h
+++ b/android_webview/common/aw_content_client.h
@@ -16,13 +16,13 @@
 class AwContentClient : public content::ContentClient {
  public:
   // ContentClient implementation.
-  virtual std::string GetProduct() const override;
-  virtual std::string GetUserAgent() const override;
-  virtual base::string16 GetLocalizedString(int message_id) const override;
-  virtual base::StringPiece GetDataResource(
+  std::string GetProduct() const override;
+  std::string GetUserAgent() const override;
+  base::string16 GetLocalizedString(int message_id) const override;
+  base::StringPiece GetDataResource(
       int resource_id,
       ui::ScaleFactor scale_factor) const override;
-  virtual bool CanSendWhileSwappedOut(const IPC::Message* message) override;
+  bool CanSendWhileSwappedOut(const IPC::Message* message) override;
 };
 
 }  // namespace android_webview
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index ba765d9..9efefb7 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -94,7 +94,7 @@
     private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
 
     /**
-     * WebKit hit test related data strcutre. These are used to implement
+     * WebKit hit test related data structure. These are used to implement
      * getHitTestResult, requestFocusNodeHref, requestImageRef methods in WebView.
      * All values should be updated together. The native counterpart is
      * AwHitTestData.
@@ -1803,11 +1803,12 @@
     }
 
     /**
-     * Creates a message channel.
+     * Creates a message channel and asynchronously returns the ports that
+     * forms the ports for each end of the channel.
      *
      * @param callback The message channel created.
      */
-    public void createMessageChannel(ValueCallback<MessageChannel> callback) {
+    public void createMessageChannel(ValueCallback<MessagePort[]> callback) {
         if (isDestroyed()) return;
         // Make sure the message port service is created.
         mBrowserContext.createMessagePortServiceIfNecessary();
@@ -2708,5 +2709,5 @@
             String message, String sourceOrigin, String targetOrigin, int[] msgPorts);
 
     private native void nativeCreateMessageChannel(long nativeAwContents,
-            ValueCallback<MessageChannel> callback);
+            ValueCallback<MessagePort[]> callback);
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java b/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java
index c21546a..b4aae2d 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwMessagePortService.java
@@ -142,8 +142,8 @@
 
     @CalledByNative
     private void onMessageChannelCreated(int portId1, int portId2,
-            ValueCallback<MessageChannel> callback) {
-        callback.onReceiveValue(new MessageChannel(addPort(portId1), addPort(portId2)));
+            ValueCallback<MessagePort[]> callback) {
+        callback.onReceiveValue(new MessagePort[]{addPort(portId1), addPort(portId2)});
     }
 
     // Called on IO thread.
diff --git a/android_webview/java/src/org/chromium/android_webview/MessageChannel.java b/android_webview/java/src/org/chromium/android_webview/MessageChannel.java
deleted file mode 100644
index d2957ce..0000000
--- a/android_webview/java/src/org/chromium/android_webview/MessageChannel.java
+++ /dev/null
@@ -1,28 +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.android_webview;
-
-/**
- * Represents the MessageChannel object. Inspired from
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.html#message-channels
- */
-public class MessageChannel {
-    // The message ports of MessageChannel.
-    private MessagePort mPort1;
-    private MessagePort mPort2;
-
-    public MessageChannel(MessagePort port1, MessagePort port2) {
-        mPort1 = port1;
-        mPort2 = port2;
-    }
-
-    public MessagePort port1() {
-        return mPort1;
-    }
-
-    public MessagePort port2() {
-        return mPort2;
-    }
-}
diff --git a/android_webview/java/src/org/chromium/android_webview/MessagePort.java b/android_webview/java/src/org/chromium/android_webview/MessagePort.java
index e040355..4025c45 100644
--- a/android_webview/java/src/org/chromium/android_webview/MessagePort.java
+++ b/android_webview/java/src/org/chromium/android_webview/MessagePort.java
@@ -70,7 +70,11 @@
         if (msgPorts != null) {
             portIds = new int[msgPorts.length];
             for (int i = 0; i < msgPorts.length; i++) {
-                portIds[i] = msgPorts[i].portId();
+                int sentId = msgPorts[i].portId();
+                if (sentId == mPortId) {
+                    throw new IllegalStateException("Source port cannot be transferred");
+                }
+                portIds[i] = sentId;
             }
         }
         mMessagePortService.postMessage(mPortId, message, portIds);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
index 4c3f945..e87ca2c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
@@ -12,7 +12,6 @@
 import static org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
 
 import org.chromium.android_webview.AwContents;
-import org.chromium.android_webview.MessageChannel;
 import org.chromium.android_webview.MessagePort;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.base.test.util.DisabledTest;
@@ -146,23 +145,56 @@
 
     @SmallTest
     @Feature({"AndroidWebView", "Android-PostMessage"})
-    public void testTransferringSamePortTwiceNotAllowed() throws Throwable {
+    public void testTransferringSamePortTwiceViaPostMessageToFrameNotAllowed() throws Throwable {
         loadPage(TEST_PAGE);
         final CountDownLatch latch = new CountDownLatch(1);
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                ValueCallback<MessageChannel> callback = new ValueCallback<MessageChannel>() {
+                ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
                     @Override
-                    public void onReceiveValue(MessageChannel channel) {
+                    public void onReceiveValue(MessagePort[] channel) {
                         mAwContents.postMessageToFrame(null, "1", SOURCE_ORIGIN,
                                 mWebServer.getBaseUrl(),
-                                new MessagePort[]{channel.port2()});
+                                new MessagePort[]{channel[1]});
                         // retransfer the port. This should fail with an exception
                         try {
                             mAwContents.postMessageToFrame(null, "2", SOURCE_ORIGIN,
                                     mWebServer.getBaseUrl(),
-                                    new MessagePort[]{channel.port2()});
+                                    new MessagePort[]{channel[1]});
+                        } catch (IllegalStateException ex) {
+                            latch.countDown();
+                            return;
+                        }
+                        fail();
+                    }
+                };
+                mAwContents.createMessageChannel(callback);
+            }
+        });
+        boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
+    }
+
+    // channel[0] and channel[1] are entangled ports, establishing a channel. Verify
+    // it is not allowed to transfer channel[0] on channel[0].postMessage.
+    // TODO(sgurun) Note that the related case of posting channel[1] via
+    // channel[0].postMessage does not throw a JS exception at present. We do not throw
+    // an exception in this case either since the information of entangled port is not
+    // available at the source port. We need a new mechanism to implement to prevent
+    // this case.
+    @SmallTest
+    @Feature({"AndroidWebView", "Android-PostMessage"})
+    public void testTransferSourcePortViaMessageChannelNotAllowed() throws Throwable {
+        loadPage(TEST_PAGE);
+        final CountDownLatch latch = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
+                    @Override
+                    public void onReceiveValue(MessagePort[] channel) {
+                        try {
+                            channel[0].postMessage("1", new MessagePort[]{channel[0]});
                         } catch (IllegalStateException ex) {
                             latch.countDown();
                             return;
@@ -178,14 +210,14 @@
 
     private static class ChannelContainer {
         private boolean mReady;
-        private MessageChannel mChannel;
+        private MessagePort[] mChannel;
         private Object mLock = new Object();
         private String mMessage;
 
-        public void set(MessageChannel channel) {
+        public void set(MessagePort[] channel) {
             mChannel = channel;
         }
-        public MessageChannel get() {
+        public MessagePort[] get() {
             return mChannel;
         }
 
@@ -225,19 +257,19 @@
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                ValueCallback<MessageChannel> callback = new ValueCallback<MessageChannel>() {
+                ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
                     @Override
-                    public void onReceiveValue(MessageChannel channel) {
+                    public void onReceiveValue(MessagePort[] channel) {
                         // verify communication from JS to Java.
                         channelContainer.set(channel);
-                        channel.port1().setMessageHandler(new MessagePort.MessageHandler() {
+                        channel[0].setMessageHandler(new MessagePort.MessageHandler() {
                             @Override
                             public void onMessage(String message) {
                                 channelContainer.setMessage(message);
                             }
                         });
                         mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
-                                mWebServer.getBaseUrl(), new MessagePort[]{channel.port2()});
+                                mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
                     }
                 };
                 mAwContents.createMessageChannel(callback);
@@ -285,18 +317,18 @@
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                ValueCallback<MessageChannel> callback = new ValueCallback<MessageChannel>() {
+                ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
                     @Override
-                    public void onReceiveValue(MessageChannel channel) {
-                        channel.port1().setMessageHandler(new MessagePort.MessageHandler() {
+                    public void onReceiveValue(MessagePort[] channel) {
+                        channel[0].setMessageHandler(new MessagePort.MessageHandler() {
                             @Override
                             public void onMessage(String message) {
                                 channelContainer.setMessage(message);
                             }
                         });
                         mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
-                                mWebServer.getBaseUrl(), new MessagePort[]{channel.port2()});
-                        channel.port1().postMessage(hello, null);
+                                mWebServer.getBaseUrl(), new MessagePort[]{channel[1]});
+                        channel[0].postMessage(hello, null);
                     }
                 };
                 mAwContents.createMessageChannel(callback);
@@ -348,12 +380,12 @@
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
-                ValueCallback<MessageChannel> callback = new ValueCallback<MessageChannel>() {
+                ValueCallback<MessagePort[]> callback = new ValueCallback<MessagePort[]>() {
                     @Override
-                    public void onReceiveValue(MessageChannel channel) {
+                    public void onReceiveValue(MessagePort[] channel) {
                         mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN,
                                 mWebServer.getBaseUrl(),
-                                new MessagePort[]{channel.port1(), channel.port2()});
+                                new MessagePort[]{channel[0], channel[1]});
                     }
                 };
                 mAwContents.createMessageChannel(callback);
diff --git a/android_webview/lib/aw_browser_dependency_factory_impl.h b/android_webview/lib/aw_browser_dependency_factory_impl.h
index e0cf3b9d..c5ca0b1 100644
--- a/android_webview/lib/aw_browser_dependency_factory_impl.h
+++ b/android_webview/lib/aw_browser_dependency_factory_impl.h
@@ -22,14 +22,14 @@
 class AwBrowserDependencyFactoryImpl : public AwBrowserDependencyFactory {
  public:
   AwBrowserDependencyFactoryImpl();
-  virtual ~AwBrowserDependencyFactoryImpl();
+  ~AwBrowserDependencyFactoryImpl() override;
 
   // Sets this class as the singleton instance.
   static void InstallInstance();
 
   // AwBrowserDependencyFactory
-  virtual content::BrowserContext* GetBrowserContext() override;
-  virtual content::WebContents* CreateWebContents() override;
+  content::BrowserContext* GetBrowserContext() override;
+  content::WebContents* CreateWebContents() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AwBrowserDependencyFactoryImpl);
diff --git a/android_webview/lib/main/aw_main_delegate.h b/android_webview/lib/main/aw_main_delegate.h
index 167d9219..5e6eefc 100644
--- a/android_webview/lib/main/aw_main_delegate.h
+++ b/android_webview/lib/main/aw_main_delegate.h
@@ -26,7 +26,7 @@
                        public JniDependencyFactory {
  public:
   AwMainDelegate();
-  virtual ~AwMainDelegate();
+  ~AwMainDelegate() override;
 
  private:
   // content::ContentMainDelegate implementation:
@@ -48,9 +48,8 @@
   AwWebPreferencesPopulater* CreateWebPreferencesPopulater() override;
   AwMessagePortService* CreateAwMessagePortService() override;
 #if defined(VIDEO_HOLE)
-  virtual content::ExternalVideoSurfaceContainer*
-      CreateExternalVideoSurfaceContainer(
-          content::WebContents* web_contents) override;
+  content::ExternalVideoSurfaceContainer* CreateExternalVideoSurfaceContainer(
+      content::WebContents* web_contents) override;
 #endif
 
   scoped_ptr<content::BrowserMainRunner> browser_runner_;
diff --git a/android_webview/native/android_protocol_handler.cc b/android_webview/native/android_protocol_handler.cc
index 4bdf6ec..c80d9bd 100644
--- a/android_webview/native/android_protocol_handler.cc
+++ b/android_webview/native/android_protocol_handler.cc
@@ -60,33 +60,31 @@
  public:
   AndroidStreamReaderURLRequestJobDelegateImpl();
 
-  virtual scoped_ptr<InputStream> OpenInputStream(
-      JNIEnv* env,
-      const GURL& url) override;
+  scoped_ptr<InputStream> OpenInputStream(JNIEnv* env,
+                                          const GURL& url) override;
 
-  virtual void OnInputStreamOpenFailed(net::URLRequest* request,
-                                       bool* restart) override;
+  void OnInputStreamOpenFailed(net::URLRequest* request,
+                               bool* restart) override;
 
-  virtual bool GetMimeType(JNIEnv* env,
-                           net::URLRequest* request,
-                           InputStream* stream,
-                           std::string* mime_type) override;
+  bool GetMimeType(JNIEnv* env,
+                   net::URLRequest* request,
+                   InputStream* stream,
+                   std::string* mime_type) override;
 
-  virtual bool GetCharset(JNIEnv* env,
-                          net::URLRequest* request,
-                          InputStream* stream,
-                          std::string* charset) override;
+  bool GetCharset(JNIEnv* env,
+                  net::URLRequest* request,
+                  InputStream* stream,
+                  std::string* charset) override;
 
-  virtual void AppendResponseHeaders(
-      JNIEnv* env,
-      net::HttpResponseHeaders* headers) override;
+  void AppendResponseHeaders(JNIEnv* env,
+                             net::HttpResponseHeaders* headers) override;
 
-  virtual ~AndroidStreamReaderURLRequestJobDelegateImpl();
+  ~AndroidStreamReaderURLRequestJobDelegateImpl() override;
 };
 
 class AndroidRequestInterceptorBase : public net::URLRequestInterceptor {
  public:
-  virtual net::URLRequestJob* MaybeInterceptRequest(
+  net::URLRequestJob* MaybeInterceptRequest(
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate) const override;
 
@@ -97,9 +95,8 @@
  public:
   AssetFileRequestInterceptor();
 
-  virtual ~AssetFileRequestInterceptor() override;
-  virtual bool ShouldHandleRequest(
-      const net::URLRequest* request) const override;
+  ~AssetFileRequestInterceptor() override;
+  bool ShouldHandleRequest(const net::URLRequest* request) const override;
 
  private:
   // file:///android_asset/
@@ -112,8 +109,7 @@
 class ContentSchemeRequestInterceptor : public AndroidRequestInterceptorBase {
  public:
   ContentSchemeRequestInterceptor();
-  virtual bool ShouldHandleRequest(
-      const net::URLRequest* request) const override;
+  bool ShouldHandleRequest(const net::URLRequest* request) const override;
 };
 
 static ScopedJavaLocalRef<jobject> GetResourceContext(JNIEnv* env) {
diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h
index dd85587..9881f8d 100644
--- a/android_webview/native/aw_autofill_client.h
+++ b/android_webview/native/aw_autofill_client.h
@@ -50,50 +50,45 @@
 class AwAutofillClient : public autofill::AutofillClient,
                          public content::WebContentsUserData<AwAutofillClient> {
  public:
-  virtual ~AwAutofillClient();
+  ~AwAutofillClient() override;
 
   void SetSaveFormData(bool enabled);
   bool GetSaveFormData();
 
   // AutofillClient:
-  virtual autofill::PersonalDataManager* GetPersonalDataManager() override;
-  virtual scoped_refptr<autofill::AutofillWebDataService> GetDatabase()
-      override;
-  virtual PrefService* GetPrefs() override;
+  autofill::PersonalDataManager* GetPersonalDataManager() override;
+  scoped_refptr<autofill::AutofillWebDataService> GetDatabase() override;
+  PrefService* GetPrefs() override;
   IdentityProvider* GetIdentityProvider() override;
-  virtual void HideRequestAutocompleteDialog() override;
-  virtual void ShowAutofillSettings() override;
-  virtual void ShowUnmaskPrompt(
+  void HideRequestAutocompleteDialog() override;
+  void ShowAutofillSettings() override;
+  void ShowUnmaskPrompt(
       const autofill::CreditCard& card,
       base::WeakPtr<autofill::CardUnmaskDelegate> delegate) override;
-  virtual void OnUnmaskVerificationResult(bool success) override;
-  virtual void ConfirmSaveCreditCard(
-      const base::Closure& save_card_callback) override;
-  virtual bool HasCreditCardScanFeature() override;
-  virtual void ScanCreditCard(const CreditCardScanCallback& callback) override;
-  virtual void ShowRequestAutocompleteDialog(
-      const autofill::FormData& form,
-      content::RenderFrameHost* rfh,
-      const ResultCallback& callback) override;
-  virtual void ShowAutofillPopup(
+  void OnUnmaskVerificationResult(bool success) override;
+  void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
+  bool HasCreditCardScanFeature() override;
+  void ScanCreditCard(const CreditCardScanCallback& callback) override;
+  void ShowRequestAutocompleteDialog(const autofill::FormData& form,
+                                     content::RenderFrameHost* rfh,
+                                     const ResultCallback& callback) override;
+  void ShowAutofillPopup(
       const gfx::RectF& element_bounds,
       base::i18n::TextDirection text_direction,
       const std::vector<autofill::Suggestion>& suggestions,
       base::WeakPtr<autofill::AutofillPopupDelegate> delegate) override;
-  virtual void UpdateAutofillPopupDataListValues(
+  void UpdateAutofillPopupDataListValues(
       const std::vector<base::string16>& values,
       const std::vector<base::string16>& labels) override;
-  virtual void HideAutofillPopup() override;
-  virtual bool IsAutocompleteEnabled() override;
-  virtual void DetectAccountCreationForms(
+  void HideAutofillPopup() override;
+  bool IsAutocompleteEnabled() override;
+  void DetectAccountCreationForms(
       content::RenderFrameHost* rfh,
       const std::vector<autofill::FormStructure*>& forms) override;
-  virtual void DidFillOrPreviewField(
-      const base::string16& autofilled_value,
-      const base::string16& profile_full_name) override;
-  virtual void OnFirstUserGestureObserved() override;
-  virtual void LinkClicked(const GURL& url,
-                           WindowOpenDisposition disposition) override;
+  void DidFillOrPreviewField(const base::string16& autofilled_value,
+                             const base::string16& profile_full_name) override;
+  void OnFirstUserGestureObserved() override;
+  void LinkClicked(const GURL& url, WindowOpenDisposition disposition) override;
 
   void SuggestionSelected(JNIEnv* env, jobject obj, jint position);
 
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 8987dc2..7110ebab 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -69,7 +69,7 @@
   static AwContents* FromID(int render_process_id, int render_view_id);
 
   AwContents(scoped_ptr<content::WebContents> web_contents);
-  virtual ~AwContents();
+  ~AwContents() override;
 
   AwRenderViewHostExt* render_view_host_ext() {
     return render_view_host_ext_.get();
@@ -139,9 +139,8 @@
                                  jstring origin);
 
   // PermissionRequestHandlerClient implementation.
-  virtual void OnPermissionRequest(AwPermissionRequest* request) override;
-  virtual void OnPermissionRequestCanceled(
-      AwPermissionRequest* request) override;
+  void OnPermissionRequest(AwPermissionRequest* request) override;
+  void OnPermissionRequestCanceled(AwPermissionRequest* request) override;
 
   PermissionRequestHandler* GetPermissionRequestHandler() {
     return permission_request_handler_.get();
@@ -153,17 +152,15 @@
                               jlong resources);
 
   // AwBrowserPermissionRequestDelegate implementation.
-  virtual void RequestProtectedMediaIdentifierPermission(
+  void RequestProtectedMediaIdentifierPermission(
       const GURL& origin,
       const base::Callback<void(bool)>& callback) override;
-  virtual void CancelProtectedMediaIdentifierPermissionRequests(
+  void CancelProtectedMediaIdentifierPermissionRequests(
       const GURL& origin) override;
-  virtual void RequestGeolocationPermission(
+  void RequestGeolocationPermission(
       const GURL& origin,
       const base::Callback<void(bool)>& callback) override;
-  virtual void CancelGeolocationPermissionRequests(
-      const GURL& origin) override;
-
+  void CancelGeolocationPermissionRequests(const GURL& origin) override;
 
   // Find-in-page API and related methods.
   void FindAllAsync(JNIEnv* env, jobject obj, jstring search_string);
@@ -175,36 +172,33 @@
   bool AllowThirdPartyCookies();
 
   // FindHelper::Listener implementation.
-  virtual void OnFindResultReceived(int active_ordinal,
-                                    int match_count,
-                                    bool finished) override;
+  void OnFindResultReceived(int active_ordinal,
+                            int match_count,
+                            bool finished) override;
   // IconHelper::Listener implementation.
-  virtual bool ShouldDownloadFavicon(const GURL& icon_url) override;
-  virtual void OnReceivedIcon(const GURL& icon_url,
-                              const SkBitmap& bitmap) override;
-  virtual void OnReceivedTouchIconUrl(const std::string& url,
-                                      const bool precomposed) override;
+  bool ShouldDownloadFavicon(const GURL& icon_url) override;
+  void OnReceivedIcon(const GURL& icon_url, const SkBitmap& bitmap) override;
+  void OnReceivedTouchIconUrl(const std::string& url,
+                              const bool precomposed) override;
 
   // AwRenderViewHostExtClient implementation.
-  virtual void OnWebLayoutPageScaleFactorChanged(
-      float page_scale_factor) override;
-  virtual void OnWebLayoutContentsSizeChanged(
-      const gfx::Size& contents_size) override;
+  void OnWebLayoutPageScaleFactorChanged(float page_scale_factor) override;
+  void OnWebLayoutContentsSizeChanged(const gfx::Size& contents_size) override;
 
   // BrowserViewRendererClient implementation.
-  virtual bool RequestDrawGL(bool wait_for_completion) override;
-  virtual void PostInvalidate() override;
-  virtual void InvalidateOnFunctorDestroy() override;
-  virtual void OnNewPicture() override;
-  virtual gfx::Point GetLocationOnScreen() override;
-  virtual void ScrollContainerViewTo(gfx::Vector2d new_value) override;
-  virtual bool IsFlingActive() const override;
-  virtual void UpdateScrollState(gfx::Vector2d max_scroll_offset,
-                                 gfx::SizeF contents_size_dip,
-                                 float page_scale_factor,
-                                 float min_page_scale_factor,
-                                 float max_page_scale_factor) override;
-  virtual void DidOverscroll(gfx::Vector2d overscroll_delta) override;
+  bool RequestDrawGL(bool wait_for_completion) override;
+  void PostInvalidate() override;
+  void InvalidateOnFunctorDestroy() override;
+  void OnNewPicture() override;
+  gfx::Point GetLocationOnScreen() override;
+  void ScrollContainerViewTo(gfx::Vector2d new_value) override;
+  bool IsFlingActive() const override;
+  void UpdateScrollState(gfx::Vector2d max_scroll_offset,
+                         gfx::SizeF contents_size_dip,
+                         float page_scale_factor,
+                         float min_page_scale_factor,
+                         float max_page_scale_factor) override;
+  void DidOverscroll(gfx::Vector2d overscroll_delta) override;
 
   const BrowserViewRenderer* GetBrowserViewRenderer() const;
 
diff --git a/android_webview/native/aw_contents_client_bridge.h b/android_webview/native/aw_contents_client_bridge.h
index d50fa62..2a5caba 100644
--- a/android_webview/native/aw_contents_client_bridge.h
+++ b/android_webview/native/aw_contents_client_bridge.h
@@ -30,31 +30,31 @@
 class AwContentsClientBridge : public AwContentsClientBridgeBase {
  public:
   AwContentsClientBridge(JNIEnv* env, jobject obj);
-  virtual ~AwContentsClientBridge();
+  ~AwContentsClientBridge() override;
 
   // AwContentsClientBridgeBase implementation
-  virtual void AllowCertificateError(int cert_error,
-                                     net::X509Certificate* cert,
-                                     const GURL& request_url,
-                                     const base::Callback<void(bool)>& callback,
-                                     bool* cancel_request) override;
-  virtual void SelectClientCertificate(
+  void AllowCertificateError(int cert_error,
+                             net::X509Certificate* cert,
+                             const GURL& request_url,
+                             const base::Callback<void(bool)>& callback,
+                             bool* cancel_request) override;
+  void SelectClientCertificate(
       net::SSLCertRequestInfo* cert_request_info,
       const SelectCertificateCallback& callback) override;
 
-  virtual void RunJavaScriptDialog(
+  void RunJavaScriptDialog(
       content::JavaScriptMessageType message_type,
       const GURL& origin_url,
       const base::string16& message_text,
       const base::string16& default_prompt_text,
       const content::JavaScriptDialogManager::DialogClosedCallback& callback)
       override;
-  virtual void RunBeforeUnloadDialog(
+  void RunBeforeUnloadDialog(
       const GURL& origin_url,
       const base::string16& message_text,
       const content::JavaScriptDialogManager::DialogClosedCallback& callback)
       override;
-  virtual bool ShouldOverrideUrlLoading(const base::string16& url) override;
+  bool ShouldOverrideUrlLoading(const base::string16& url) override;
 
   // Methods called from Java.
   void ProceedSslError(JNIEnv* env, jobject obj, jboolean proceed, jint id);
diff --git a/android_webview/native/aw_contents_client_bridge_unittest.cc b/android_webview/native/aw_contents_client_bridge_unittest.cc
index e6714bb7..b301f919 100644
--- a/android_webview/native/aw_contents_client_bridge_unittest.cc
+++ b/android_webview/native/aw_contents_client_bridge_unittest.cc
@@ -41,7 +41,7 @@
   // Callback method called when a cert is selected.
   void CertSelected(X509Certificate* cert);
  protected:
-  virtual void SetUp();
+  void SetUp() override;
   void TestCertType(SSLClientCertType type, const std::string& expected_name);
   // Create the TestBrowserThreads. Just instantiate the member variable.
   content::TestBrowserThreadBundle thread_bundle_;
diff --git a/android_webview/native/aw_contents_io_thread_client_impl.cc b/android_webview/native/aw_contents_io_thread_client_impl.cc
index 4f7ce44..69003ae 100644
--- a/android_webview/native/aw_contents_io_thread_client_impl.cc
+++ b/android_webview/native/aw_contents_io_thread_client_impl.cc
@@ -116,9 +116,9 @@
   ClientMapEntryUpdater(JNIEnv* env, WebContents* web_contents,
                         jobject jdelegate);
 
-  virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
-  virtual void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
-  virtual void WebContentsDestroyed() override;
+  void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
+  void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+  void WebContentsDestroyed() override;
 
  private:
   JavaObjectWeakGlobalRef jdelegate_;
diff --git a/android_webview/native/aw_contents_io_thread_client_impl.h b/android_webview/native/aw_contents_io_thread_client_impl.h
index 4c9d5551..320d35b 100644
--- a/android_webview/native/aw_contents_io_thread_client_impl.h
+++ b/android_webview/native/aw_contents_io_thread_client_impl.h
@@ -42,26 +42,26 @@
   // Java object.
   AwContentsIoThreadClientImpl(bool pending_associate,
                                const base::android::JavaRef<jobject>& jclient);
-  virtual ~AwContentsIoThreadClientImpl() override;
+  ~AwContentsIoThreadClientImpl() override;
 
   // Implementation of AwContentsIoThreadClient.
-  virtual bool PendingAssociation() const override;
-  virtual CacheMode GetCacheMode() const override;
-  virtual scoped_ptr<AwWebResourceResponse> ShouldInterceptRequest(
+  bool PendingAssociation() const override;
+  CacheMode GetCacheMode() const override;
+  scoped_ptr<AwWebResourceResponse> ShouldInterceptRequest(
       const GURL& location,
       const net::URLRequest* request) override;
-  virtual bool ShouldBlockContentUrls() const override;
-  virtual bool ShouldBlockFileUrls() const override;
-  virtual bool ShouldAcceptThirdPartyCookies() const override;
-  virtual bool ShouldBlockNetworkLoads() const override;
-  virtual void NewDownload(const GURL& url,
-                           const std::string& user_agent,
-                           const std::string& content_disposition,
-                           const std::string& mime_type,
-                           int64 content_length) override;
-  virtual void NewLoginRequest(const std::string& realm,
-                               const std::string& account,
-                               const std::string& args) override;
+  bool ShouldBlockContentUrls() const override;
+  bool ShouldBlockFileUrls() const override;
+  bool ShouldAcceptThirdPartyCookies() const override;
+  bool ShouldBlockNetworkLoads() const override;
+  void NewDownload(const GURL& url,
+                   const std::string& user_agent,
+                   const std::string& content_disposition,
+                   const std::string& mime_type,
+                   int64 content_length) override;
+  void NewLoginRequest(const std::string& realm,
+                       const std::string& account,
+                       const std::string& args) override;
 
  private:
   bool pending_association_;
diff --git a/android_webview/native/aw_dev_tools_server.cc b/android_webview/native/aw_dev_tools_server.cc
index 9c96694..52d474ed 100644
--- a/android_webview/native/aw_dev_tools_server.cc
+++ b/android_webview/native/aw_dev_tools_server.cc
@@ -42,7 +42,7 @@
   AwDevToolsServerDelegate() {
   }
 
-  virtual ~AwDevToolsServerDelegate() {}
+  ~AwDevToolsServerDelegate() override {}
 
   // DevToolsHttpProtocolHandler::Delegate overrides.
   std::string GetDiscoveryPageHTML() override;
@@ -81,7 +81,7 @@
 
  private:
   // content::DevToolsHttpHandler::ServerSocketFactory.
-  virtual scoped_ptr<net::ServerSocket> CreateForHttpServer() override {
+  scoped_ptr<net::ServerSocket> CreateForHttpServer() override {
     scoped_ptr<net::ServerSocket> socket(
         new net::UnixDomainServerSocket(
             base::Bind(&content::CanUserConnectToDevTools),
diff --git a/android_webview/native/aw_http_auth_handler.h b/android_webview/native/aw_http_auth_handler.h
index c063702..79b7406e 100644
--- a/android_webview/native/aw_http_auth_handler.h
+++ b/android_webview/native/aw_http_auth_handler.h
@@ -32,10 +32,10 @@
   AwHttpAuthHandler(AwLoginDelegate* login_delegate,
                     net::AuthChallengeInfo* auth_info,
                     bool first_auth_attempt);
-  virtual ~AwHttpAuthHandler();
+  ~AwHttpAuthHandler() override;
 
   // from AwHttpAuthHandler
-  virtual bool HandleOnUIThread(content::WebContents* web_contents) override;
+  bool HandleOnUIThread(content::WebContents* web_contents) override;
 
   void Proceed(JNIEnv* env, jobject obj, jstring username, jstring password);
   void Cancel(JNIEnv* env, jobject obj);
diff --git a/android_webview/native/aw_media_url_interceptor.h b/android_webview/native/aw_media_url_interceptor.h
index a6370a9..332fd37 100644
--- a/android_webview/native/aw_media_url_interceptor.h
+++ b/android_webview/native/aw_media_url_interceptor.h
@@ -15,10 +15,10 @@
 // Interceptor to handle urls for media assets in the apk.
 class AwMediaUrlInterceptor : public media::MediaUrlInterceptor {
  public:
-  virtual bool Intercept(const std::string& url,
-                         int* fd,
-                         int64* offset,
-                         int64* size) const override;
+  bool Intercept(const std::string& url,
+                 int* fd,
+                 int64* offset,
+                 int64* size) const override;
 };
 
 }  // namespace android_webview
diff --git a/android_webview/native/aw_message_port_service_impl.h b/android_webview/native/aw_message_port_service_impl.h
index 757d75d..f72f80e 100644
--- a/android_webview/native/aw_message_port_service_impl.h
+++ b/android_webview/native/aw_message_port_service_impl.h
@@ -26,7 +26,7 @@
   static AwMessagePortServiceImpl* GetInstance();
 
   AwMessagePortServiceImpl();
-  ~AwMessagePortServiceImpl();
+  ~AwMessagePortServiceImpl() override;
   void Init(JNIEnv* env, jobject object);
 
   void CreateMessageChannel(JNIEnv* env, jobject callback,
diff --git a/android_webview/native/aw_pdf_exporter.h b/android_webview/native/aw_pdf_exporter.h
index 9ead85e..1321354 100644
--- a/android_webview/native/aw_pdf_exporter.h
+++ b/android_webview/native/aw_pdf_exporter.h
@@ -30,7 +30,7 @@
                 jobject obj,
                 content::WebContents* web_contents);
 
-  virtual ~AwPdfExporter();
+  ~AwPdfExporter() override;
 
   void ExportToPdf(JNIEnv* env,
                    jobject obj,
@@ -38,8 +38,8 @@
                    jobject cancel_signal);
 
   // Implement PrintManagerDelegate methods
-  virtual void DidExportPdf(bool success) override;
-  virtual bool IsCancelled() override;
+  void DidExportPdf(bool success) override;
+  bool IsCancelled() override;
 
  private:
   void CreatePdfSettings(JNIEnv* env, jobject obj);
diff --git a/android_webview/native/aw_quota_manager_bridge_impl.h b/android_webview/native/aw_quota_manager_bridge_impl.h
index b327df1e..dc7f20f3 100644
--- a/android_webview/native/aw_quota_manager_bridge_impl.h
+++ b/android_webview/native/aw_quota_manager_bridge_impl.h
@@ -56,7 +56,7 @@
 
  private:
   explicit AwQuotaManagerBridgeImpl(AwBrowserContext* browser_context);
-  virtual ~AwQuotaManagerBridgeImpl();
+  ~AwQuotaManagerBridgeImpl() override;
 
   content::StoragePartition* GetStoragePartition() const;
 
diff --git a/android_webview/native/aw_settings.h b/android_webview/native/aw_settings.h
index 141320d..581a6cd 100644
--- a/android_webview/native/aw_settings.h
+++ b/android_webview/native/aw_settings.h
@@ -25,7 +25,7 @@
   static AwSettings* FromWebContents(content::WebContents* web_contents);
 
   AwSettings(JNIEnv* env, jobject obj, content::WebContents* web_contents);
-  virtual ~AwSettings();
+  ~AwSettings() override;
 
   // Called from Java. Methods with "Locked" suffix require that the settings
   // access lock is held during their execution.
@@ -46,9 +46,8 @@
   void UpdateEverything();
 
   // WebContentsObserver overrides:
-  virtual void RenderViewCreated(
-      content::RenderViewHost* render_view_host) override;
-  virtual void WebContentsDestroyed() override;
+  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+  void WebContentsDestroyed() override;
 
   bool renderer_prefs_initialized_;
 
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc
index 2f43de1ae..acece1b 100644
--- a/android_webview/native/aw_web_contents_delegate.cc
+++ b/android_webview/native/aw_web_contents_delegate.cc
@@ -125,7 +125,7 @@
 void AwWebContentsDelegate::AddNewContents(WebContents* source,
                                            WebContents* new_contents,
                                            WindowOpenDisposition disposition,
-                                           const gfx::Rect& initial_pos,
+                                           const gfx::Rect& initial_rect,
                                            bool user_gesture,
                                            bool* was_blocked) {
   JNIEnv* env = AttachCurrentThread();
diff --git a/android_webview/native/aw_web_contents_delegate.h b/android_webview/native/aw_web_contents_delegate.h
index 8a17a3e..96cd32575 100644
--- a/android_webview/native/aw_web_contents_delegate.h
+++ b/android_webview/native/aw_web_contents_delegate.h
@@ -18,46 +18,44 @@
     : public web_contents_delegate_android::WebContentsDelegateAndroid {
  public:
   AwWebContentsDelegate(JNIEnv* env, jobject obj);
-  virtual ~AwWebContentsDelegate();
-  virtual content::JavaScriptDialogManager* GetJavaScriptDialogManager(
+  ~AwWebContentsDelegate() override;
+  content::JavaScriptDialogManager* GetJavaScriptDialogManager(
       content::WebContents* source) override;
-  virtual void FindReply(content::WebContents* web_contents,
-                         int request_id,
-                         int number_of_matches,
-                         const gfx::Rect& selection_rect,
-                         int active_match_ordinal,
-                         bool final_update) override;
-  virtual void CanDownload(content::RenderViewHost* source,
-                           const GURL& url,
-                           const std::string& request_method,
-                           const base::Callback<void(bool)>& callback) override;
-  virtual void RunFileChooser(
-      content::WebContents* web_contents,
-      const content::FileChooserParams& params) override;
-  virtual void AddNewContents(content::WebContents* source,
-                              content::WebContents* new_contents,
-                              WindowOpenDisposition disposition,
-                              const gfx::Rect& initial_pos,
-                              bool user_gesture,
-                              bool* was_blocked) override;
+  void FindReply(content::WebContents* web_contents,
+                 int request_id,
+                 int number_of_matches,
+                 const gfx::Rect& selection_rect,
+                 int active_match_ordinal,
+                 bool final_update) override;
+  void CanDownload(content::RenderViewHost* source,
+                   const GURL& url,
+                   const std::string& request_method,
+                   const base::Callback<void(bool)>& callback) override;
+  void RunFileChooser(content::WebContents* web_contents,
+                      const content::FileChooserParams& params) override;
+  void AddNewContents(content::WebContents* source,
+                      content::WebContents* new_contents,
+                      WindowOpenDisposition disposition,
+                      const gfx::Rect& initial_rect,
+                      bool user_gesture,
+                      bool* was_blocked) override;
 
-  virtual void WebContentsCreated(content::WebContents* source_contents,
-                                  int opener_render_frame_id,
-                                  const base::string16& frame_name,
-                                  const GURL& target_url,
-                                  content::WebContents* new_contents) override;
+  void WebContentsCreated(content::WebContents* source_contents,
+                          int opener_render_frame_id,
+                          const base::string16& frame_name,
+                          const GURL& target_url,
+                          content::WebContents* new_contents) override;
 
-  virtual void CloseContents(content::WebContents* source) override;
-  virtual void ActivateContents(content::WebContents* contents) override;
-  virtual void RequestMediaAccessPermission(
+  void CloseContents(content::WebContents* source) override;
+  void ActivateContents(content::WebContents* contents) override;
+  void RequestMediaAccessPermission(
       content::WebContents* web_contents,
       const content::MediaStreamRequest& request,
       const content::MediaResponseCallback& callback) override;
-  virtual void EnterFullscreenModeForTab(content::WebContents* web_contents,
-                                         const GURL& origin) override;
-  virtual void ExitFullscreenModeForTab(
-      content::WebContents* web_contents) override;
-  virtual bool IsFullscreenForTabOrPending(
+  void EnterFullscreenModeForTab(content::WebContents* web_contents,
+                                 const GURL& origin) override;
+  void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
+  bool IsFullscreenForTabOrPending(
       const content::WebContents* web_contents) const override;
 
  private:
diff --git a/android_webview/native/aw_web_contents_view_delegate.h b/android_webview/native/aw_web_contents_view_delegate.h
index 95fd0d6a..c4b438a 100644
--- a/android_webview/native/aw_web_contents_view_delegate.h
+++ b/android_webview/native/aw_web_contents_view_delegate.h
@@ -22,13 +22,12 @@
   static content::WebContentsViewDelegate* Create(
       content::WebContents* web_contents);
 
-  virtual ~AwWebContentsViewDelegate();
+  ~AwWebContentsViewDelegate() override;
 
   // content::WebContentsViewDelegate implementation.
-  virtual content::WebDragDestDelegate* GetDragDestDelegate() override;
-  virtual void ShowContextMenu(
-      content::RenderFrameHost* render_frame_host,
-      const content::ContextMenuParams& params) override;
+  content::WebDragDestDelegate* GetDragDestDelegate() override;
+  void ShowContextMenu(content::RenderFrameHost* render_frame_host,
+                       const content::ContextMenuParams& params) override;
 
  private:
   AwWebContentsViewDelegate(content::WebContents* web_contents);
diff --git a/android_webview/native/aw_web_preferences_populater_impl.h b/android_webview/native/aw_web_preferences_populater_impl.h
index 9831b04..8b02845 100644
--- a/android_webview/native/aw_web_preferences_populater_impl.h
+++ b/android_webview/native/aw_web_preferences_populater_impl.h
@@ -15,11 +15,11 @@
 class AwWebPreferencesPopulaterImpl : public AwWebPreferencesPopulater {
  public:
   AwWebPreferencesPopulaterImpl();
-  virtual ~AwWebPreferencesPopulaterImpl();
+  ~AwWebPreferencesPopulaterImpl() override;
 
   // AwWebPreferencesPopulater
-  virtual void PopulateFor(content::WebContents* web_contents,
-                           content::WebPreferences* web_prefs) override;
+  void PopulateFor(content::WebContents* web_contents,
+                   content::WebPreferences* web_prefs) override;
 };
 
 }  // namespace android_webview
diff --git a/android_webview/native/aw_web_resource_response_impl.h b/android_webview/native/aw_web_resource_response_impl.h
index a33db6eb..842a2cbd 100644
--- a/android_webview/native/aw_web_resource_response_impl.h
+++ b/android_webview/native/aw_web_resource_response_impl.h
@@ -23,17 +23,16 @@
   // It is expected that |obj| is an instance of the Java-side
   // org.chromium.android_webview.AwWebResourceResponse class.
   AwWebResourceResponseImpl(const base::android::JavaRef<jobject>& obj);
-  virtual ~AwWebResourceResponseImpl();
+  ~AwWebResourceResponseImpl() override;
 
-  virtual scoped_ptr<InputStream> GetInputStream(JNIEnv* env) const override;
-  virtual bool GetMimeType(JNIEnv* env, std::string* mime_type) const override;
-  virtual bool GetCharset(JNIEnv* env, std::string* charset) const override;
-  virtual bool GetStatusInfo(JNIEnv* env,
-                             int* status_code,
-                             std::string* reason_phrase) const override;
-  virtual bool GetResponseHeaders(
-      JNIEnv* env,
-      net::HttpResponseHeaders* headers) const override;
+  scoped_ptr<InputStream> GetInputStream(JNIEnv* env) const override;
+  bool GetMimeType(JNIEnv* env, std::string* mime_type) const override;
+  bool GetCharset(JNIEnv* env, std::string* charset) const override;
+  bool GetStatusInfo(JNIEnv* env,
+                     int* status_code,
+                     std::string* reason_phrase) const override;
+  bool GetResponseHeaders(JNIEnv* env,
+                          net::HttpResponseHeaders* headers) const override;
 
  private:
   base::android::ScopedJavaGlobalRef<jobject> java_object_;
diff --git a/android_webview/native/external_video_surface_container_impl.h b/android_webview/native/external_video_surface_container_impl.h
index ff741d8..29e7889 100644
--- a/android_webview/native/external_video_surface_container_impl.h
+++ b/android_webview/native/external_video_surface_container_impl.h
@@ -23,15 +23,15 @@
   ExternalVideoSurfaceContainerImpl(content::WebContents* contents);
 
   // ExternalVideoSurfaceContainer implementation.
-  virtual void RequestExternalVideoSurface(
+  void RequestExternalVideoSurface(
       int player_id,
       const SurfaceCreatedCB& surface_created_cb,
       const SurfaceDestroyedCB& surface_destroyed_cb) override;
-  virtual int GetCurrentPlayerId() override;
-  virtual void ReleaseExternalVideoSurface(int player_id) override;
-  virtual void OnFrameInfoUpdated() override;
-  virtual void OnExternalVideoSurfacePositionChanged(
-      int player_id, const gfx::RectF& rect) override;
+  int GetCurrentPlayerId() override;
+  void ReleaseExternalVideoSurface(int player_id) override;
+  void OnFrameInfoUpdated() override;
+  void OnExternalVideoSurfacePositionChanged(int player_id,
+                                             const gfx::RectF& rect) override;
 
   // Methods called from Java.
   void SurfaceCreated(
@@ -39,7 +39,7 @@
   void SurfaceDestroyed(JNIEnv* env, jobject obj, jint player_id);
 
  private:
-  virtual ~ExternalVideoSurfaceContainerImpl();
+  ~ExternalVideoSurfaceContainerImpl() override;
 
   base::android::ScopedJavaGlobalRef<jobject> jobject_;
 
diff --git a/android_webview/native/input_stream_impl.h b/android_webview/native/input_stream_impl.h
index 4a950e8..aebd7ac 100644
--- a/android_webview/native/input_stream_impl.h
+++ b/android_webview/native/input_stream_impl.h
@@ -26,15 +26,16 @@
   // |stream| should be an instance of the InputStream Java class.
   // |stream| can't be null.
   InputStreamImpl(const base::android::JavaRef<jobject>& stream);
-  virtual ~InputStreamImpl();
+  ~InputStreamImpl() override;
 
   // Gets the underlying Java object. Guaranteed non-NULL.
   const jobject jobj() const { return jobject_.obj(); }
 
   // InputStream implementation.
-  virtual bool BytesAvailable(int* bytes_available) const override;
-  virtual bool Skip(int64_t n, int64_t* bytes_skipped) override;
-  virtual bool Read(net::IOBuffer* dest, int length, int* bytes_read) override;
+  bool BytesAvailable(int* bytes_available) const override;
+  bool Skip(int64_t n, int64_t* bytes_skipped) override;
+  bool Read(net::IOBuffer* dest, int length, int* bytes_read) override;
+
  protected:
   // Parameterless constructor exposed for testing.
   InputStreamImpl();
diff --git a/android_webview/native/input_stream_unittest.cc b/android_webview/native/input_stream_unittest.cc
index ec4faf6..95d7bf5f 100644
--- a/android_webview/native/input_stream_unittest.cc
+++ b/android_webview/native/input_stream_unittest.cc
@@ -35,7 +35,7 @@
   InputStreamTest() {
   }
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     env_ = AttachCurrentThread();
     ASSERT_THAT(env_, NotNull());
     ASSERT_TRUE(android_webview::RegisterInputStream(env_));
diff --git a/android_webview/native/permission/media_access_permission_request.h b/android_webview/native/permission/media_access_permission_request.h
index 080d7f3..01bc83e4 100644
--- a/android_webview/native/permission/media_access_permission_request.h
+++ b/android_webview/native/permission/media_access_permission_request.h
@@ -17,12 +17,12 @@
  public:
   MediaAccessPermissionRequest(const content::MediaStreamRequest& request,
                                const content::MediaResponseCallback& callback);
-  virtual ~MediaAccessPermissionRequest();
+  ~MediaAccessPermissionRequest() override;
 
   // AwPermissionRequestDelegate implementation.
-  virtual const GURL& GetOrigin() override;
-  virtual int64 GetResources() override;
-  virtual void NotifyRequestResult(bool allowed) override;
+  const GURL& GetOrigin() override;
+  int64 GetResources() override;
+  void NotifyRequestResult(bool allowed) override;
 
  private:
   friend class TestMediaAccessPermissionRequest;
diff --git a/android_webview/native/permission/media_access_permission_request_unittest.cc b/android_webview/native/permission/media_access_permission_request_unittest.cc
index 32a1906..a2ba5aa 100644
--- a/android_webview/native/permission/media_access_permission_request_unittest.cc
+++ b/android_webview/native/permission/media_access_permission_request_unittest.cc
@@ -23,7 +23,7 @@
 
 class MediaAccessPermissionRequestTest : public testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     audio_device_id_ = "audio";
     video_device_id_ = "video";
     first_audio_device_id_ = "audio1";
diff --git a/android_webview/native/permission/permission_request_handler.h b/android_webview/native/permission/permission_request_handler.h
index 2318b57..7b264f7 100644
--- a/android_webview/native/permission/permission_request_handler.h
+++ b/android_webview/native/permission/permission_request_handler.h
@@ -27,7 +27,7 @@
  public:
   PermissionRequestHandler(PermissionRequestHandlerClient* client,
                            content::WebContents* aw_contents);
-  virtual ~PermissionRequestHandler();
+  ~PermissionRequestHandler() override;
 
   // Send the given |request| to PermissionRequestHandlerClient.
   void SendRequest(scoped_ptr<AwPermissionRequestDelegate> request);
@@ -39,7 +39,7 @@
   void PreauthorizePermission(const GURL& origin, int64 resources);
 
   // WebContentsObserver
-  virtual void NavigationEntryCommitted(
+  void NavigationEntryCommitted(
       const content::LoadCommittedDetails& load_details) override;
 
  private:
diff --git a/android_webview/native/permission/permission_request_handler_unittest.cc b/android_webview/native/permission/permission_request_handler_unittest.cc
index 775e5fb..0afad0742 100644
--- a/android_webview/native/permission/permission_request_handler_unittest.cc
+++ b/android_webview/native/permission/permission_request_handler_unittest.cc
@@ -21,19 +21,13 @@
         callback_(callback) {}
 
   // Get the origin which initiated the permission request.
-  virtual const GURL& GetOrigin() override {
-    return origin_;
-  }
+  const GURL& GetOrigin() override { return origin_; }
 
   // Get the resources the origin wanted to access.
-  virtual int64 GetResources() override {
-    return resources_;
-  }
+  int64 GetResources() override { return resources_; }
 
   // Notify the permission request is allowed or not.
-  virtual void NotifyRequestResult(bool allowed) override {
-    callback_.Run(allowed);
-  }
+  void NotifyRequestResult(bool allowed) override { callback_.Run(allowed); }
 
  private:
   GURL origin_;
@@ -57,14 +51,13 @@
   TestPermissionRequestHandlerClient()
       : request_(NULL) {}
 
-  virtual void OnPermissionRequest(AwPermissionRequest* request) override {
+  void OnPermissionRequest(AwPermissionRequest* request) override {
     request_ = request;
     requested_permission_ =
         Permission(request->GetOrigin(), request->GetResources());
   }
 
-  virtual void OnPermissionRequestCanceled(
-      AwPermissionRequest* request) override{
+  void OnPermissionRequestCanceled(AwPermissionRequest* request) override {
     canceled_permission_ =
         Permission(request->GetOrigin(), request->GetResources());
   }
@@ -129,7 +122,7 @@
   }
 
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     testing::Test::SetUp();
     origin_ = GURL("http://www.google.com");
     resources_ =
diff --git a/android_webview/native/permission/simple_permission_request.h b/android_webview/native/permission/simple_permission_request.h
index c232bdf1..ba6b8708 100644
--- a/android_webview/native/permission/simple_permission_request.h
+++ b/android_webview/native/permission/simple_permission_request.h
@@ -17,12 +17,12 @@
   SimplePermissionRequest(const GURL& origin,
                           int64 resources,
                           const base::Callback<void(bool)>& callback);
-  virtual ~SimplePermissionRequest();
+  ~SimplePermissionRequest() override;
 
   // AwPermissionRequestDelegate implementation.
-  virtual const GURL& GetOrigin() override;
-  virtual int64 GetResources() override;
-  virtual void NotifyRequestResult(bool allowed) override;
+  const GURL& GetOrigin() override;
+  int64 GetResources() override;
+  void NotifyRequestResult(bool allowed) override;
 
  private:
   const GURL origin_;
diff --git a/android_webview/renderer/aw_content_renderer_client.h b/android_webview/renderer/aw_content_renderer_client.h
index f6ffcbff..c16b506 100644
--- a/android_webview/renderer/aw_content_renderer_client.h
+++ b/android_webview/renderer/aw_content_renderer_client.h
@@ -19,36 +19,33 @@
 class AwContentRendererClient : public content::ContentRendererClient {
  public:
   AwContentRendererClient();
-  virtual ~AwContentRendererClient();
+  ~AwContentRendererClient() override;
 
   // ContentRendererClient implementation.
-  virtual void RenderThreadStarted() override;
-  virtual void RenderFrameCreated(content::RenderFrame* render_frame) override;
-  virtual void RenderViewCreated(content::RenderView* render_view) override;
-  virtual bool HasErrorPage(int http_status_code,
-                            std::string* error_domain) override;
-  virtual void GetNavigationErrorStrings(
-      content::RenderView* render_view,
-      blink::WebFrame* frame,
-      const blink::WebURLRequest& failed_request,
-      const blink::WebURLError& error,
-      std::string* error_html,
-      base::string16* error_description) override;
-  virtual unsigned long long VisitedLinkHash(const char* canonical_url,
-                                             size_t length) override;
-  virtual bool IsLinkVisited(unsigned long long link_hash) override;
-  virtual void AddKeySystems(
-      std::vector<media::KeySystemInfo>* key_systems) override;
+  void RenderThreadStarted() override;
+  void RenderFrameCreated(content::RenderFrame* render_frame) override;
+  void RenderViewCreated(content::RenderView* render_view) override;
+  bool HasErrorPage(int http_status_code, std::string* error_domain) override;
+  void GetNavigationErrorStrings(content::RenderView* render_view,
+                                 blink::WebFrame* frame,
+                                 const blink::WebURLRequest& failed_request,
+                                 const blink::WebURLError& error,
+                                 std::string* error_html,
+                                 base::string16* error_description) override;
+  unsigned long long VisitedLinkHash(const char* canonical_url,
+                                     size_t length) override;
+  bool IsLinkVisited(unsigned long long link_hash) override;
+  void AddKeySystems(std::vector<media::KeySystemInfo>* key_systems) override;
 
-  virtual bool HandleNavigation(content::RenderFrame* render_frame,
-                                content::DocumentState* document_state,
-                                int opener_id,
-                                blink::WebFrame* frame,
-                                const blink::WebURLRequest& request,
-                                blink::WebNavigationType type,
-                                blink::WebNavigationPolicy default_policy,
-                                bool is_redirect) override;
-  virtual bool ShouldOverridePageVisibilityState(
+  bool HandleNavigation(content::RenderFrame* render_frame,
+                        content::DocumentState* document_state,
+                        int opener_id,
+                        blink::WebFrame* frame,
+                        const blink::WebURLRequest& request,
+                        blink::WebNavigationType type,
+                        blink::WebNavigationPolicy default_policy,
+                        bool is_redirect) override;
+  bool ShouldOverridePageVisibilityState(
       const content::RenderFrame* render_frame,
       blink::WebPageVisibilityState* override_state) override;
 
diff --git a/android_webview/renderer/aw_message_port_client.h b/android_webview/renderer/aw_message_port_client.h
index e83641e..bd21472 100644
--- a/android_webview/renderer/aw_message_port_client.h
+++ b/android_webview/renderer/aw_message_port_client.h
@@ -19,7 +19,7 @@
   explicit AwMessagePortClient(content::RenderFrame* render_frame);
 
  private:
-  virtual ~AwMessagePortClient();
+  ~AwMessagePortClient() override;
 
   // RenderFrameObserver
   bool OnMessageReceived(const IPC::Message& message) override;
diff --git a/android_webview/renderer/aw_permission_client.h b/android_webview/renderer/aw_permission_client.h
index e3a4bfa..e5c036d 100644
--- a/android_webview/renderer/aw_permission_client.h
+++ b/android_webview/renderer/aw_permission_client.h
@@ -16,8 +16,8 @@
  public:
   explicit AwPermissionClient(content::RenderFrame* render_view);
 
- private:  
-  virtual ~AwPermissionClient();
+ private:
+  ~AwPermissionClient() override;
 
   // blink::WebPermissionClient implementation.
   virtual bool allowDisplayingInsecureContent(
diff --git a/android_webview/renderer/aw_render_frame_ext.h b/android_webview/renderer/aw_render_frame_ext.h
index 40141bc7..0643f7f8 100644
--- a/android_webview/renderer/aw_render_frame_ext.h
+++ b/android_webview/renderer/aw_render_frame_ext.h
@@ -17,10 +17,10 @@
   AwRenderFrameExt(content::RenderFrame* render_frame);
 
  private:
-  virtual ~AwRenderFrameExt();
+  ~AwRenderFrameExt() override;
 
   // RenderFrame::Observer:
-  virtual void DidCommitProvisionalLoad(bool is_new_navigation) override;
+  void DidCommitProvisionalLoad(bool is_new_navigation) override;
   DISALLOW_COPY_AND_ASSIGN(AwRenderFrameExt);
 };
 
diff --git a/android_webview/renderer/aw_render_process_observer.h b/android_webview/renderer/aw_render_process_observer.h
index 5c39787b..b2df85d 100644
--- a/android_webview/renderer/aw_render_process_observer.h
+++ b/android_webview/renderer/aw_render_process_observer.h
@@ -16,11 +16,11 @@
 class AwRenderProcessObserver : public content::RenderProcessObserver {
  public:
   AwRenderProcessObserver();
-  virtual ~AwRenderProcessObserver();
+  ~AwRenderProcessObserver() override;
 
   // content::RenderProcessObserver implementation.
-  virtual bool OnControlMessageReceived(const IPC::Message& message) override;
-  virtual void WebKitInitialized() override;
+  bool OnControlMessageReceived(const IPC::Message& message) override;
+  void WebKitInitialized() override;
 
  private:
   void OnClearCache();
diff --git a/android_webview/renderer/aw_render_view_ext.h b/android_webview/renderer/aw_render_view_ext.h
index 29f6442..58db3d8 100644
--- a/android_webview/renderer/aw_render_view_ext.h
+++ b/android_webview/renderer/aw_render_view_ext.h
@@ -32,14 +32,14 @@
 
  private:
   AwRenderViewExt(content::RenderView* render_view);
-  virtual ~AwRenderViewExt();
+  ~AwRenderViewExt() override;
 
   // RenderView::Observer:
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
-  virtual void FocusedNodeChanged(const blink::WebNode& node) override;
-  virtual void DidCommitCompositorFrame() override;
-  virtual void DidUpdateLayout() override;
-  virtual void Navigate(const GURL& url) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
+  void FocusedNodeChanged(const blink::WebNode& node) override;
+  void DidCommitCompositorFrame() override;
+  void DidUpdateLayout() override;
+  void Navigate(const GURL& url) override;
 
   void OnDocumentHasImagesRequest(int id);
 
diff --git a/android_webview/renderer/print_render_frame_observer.h b/android_webview/renderer/print_render_frame_observer.h
index 95248ac8..1b99c384 100644
--- a/android_webview/renderer/print_render_frame_observer.h
+++ b/android_webview/renderer/print_render_frame_observer.h
@@ -14,10 +14,10 @@
   explicit PrintRenderFrameObserver(content::RenderFrame* render_view);
 
  private:
-  virtual ~PrintRenderFrameObserver();
+  ~PrintRenderFrameObserver() override;
 
   // RenderFrameObserver implementation.
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
 
   // IPC handlers
   void OnPrintNodeUnderContextMenu();
diff --git a/apps/custom_launcher_page_contents.cc b/apps/custom_launcher_page_contents.cc
index 150bfcf7..20744b3 100644
--- a/apps/custom_launcher_page_contents.cc
+++ b/apps/custom_launcher_page_contents.cc
@@ -71,13 +71,13 @@
     content::WebContents* source,
     content::WebContents* new_contents,
     WindowOpenDisposition disposition,
-    const gfx::Rect& initial_pos,
+    const gfx::Rect& initial_rect,
     bool user_gesture,
     bool* was_blocked) {
   app_delegate_->AddNewContents(new_contents->GetBrowserContext(),
                                 new_contents,
                                 disposition,
-                                initial_pos,
+                                initial_rect,
                                 user_gesture,
                                 was_blocked);
 }
diff --git a/apps/custom_launcher_page_contents.h b/apps/custom_launcher_page_contents.h
index 95c7c65..919bbe3 100644
--- a/apps/custom_launcher_page_contents.h
+++ b/apps/custom_launcher_page_contents.h
@@ -48,7 +48,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   bool IsPopupOrPanel(const content::WebContents* source) const override;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index fec5025..f1c5eb1 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -32,7 +32,6 @@
     "//net",
     "//skia",
     "//third_party/icu",
-    "//ui/accelerometer",
     "//ui/accessibility",
     "//ui/app_list",
     "//ui/aura",
@@ -40,6 +39,7 @@
     "//ui/compositor",
     "//ui/events",
     "//ui/events:events_base",
+    "//ui/events:gesture_detection",
     "//ui/events/devices",
     "//ui/gfx",
     "//ui/gfx/geometry",
@@ -70,7 +70,6 @@
       "//build/config/linux:xfixes",
     ]
     deps += [
-      "//ui/events:gesture_detection",
       "//ui/events/platform",
       "//ui/gfx/x",
     ]
@@ -84,7 +83,10 @@
   }
 
   if (use_ozone) {
-    deps += [ "//ui/ozone" ]
+    deps += [
+      "//ui/events/ozone:events_ozone",
+      "//ui/ozone",
+    ]
   }
 
   if (is_chromeos) {
@@ -260,7 +262,6 @@
     "//skia",
     "//testing/gtest",
     "//third_party/icu",
-    "//ui/accelerometer",
     "//ui/accessibility",
     "//ui/aura",
     "//ui/aura:test_support",
diff --git a/ash/ash.gyp b/ash/ash.gyp
index cd614a6..8861a16 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -884,7 +884,6 @@
         '../skia/skia.gyp:skia',
         '../third_party/icu/icu.gyp:icui18n',
         '../third_party/icu/icu.gyp:icuuc',
-        '../ui/accelerometer/ui_accelerometer.gyp:ui_accelerometer',
         '../ui/accessibility/accessibility.gyp:accessibility',
         '../ui/app_list/app_list.gyp:app_list',
         '../ui/aura/aura.gyp:aura',
@@ -934,6 +933,7 @@
         }],
         ['use_ozone==1', {
           'dependencies': [
+            '../ui/events/ozone/events_ozone.gyp:events_ozone',
             '../ui/ozone/ozone.gyp:ozone',
           ],
         }],
@@ -1063,7 +1063,6 @@
         '../testing/gtest.gyp:gtest',
         '../third_party/icu/icu.gyp:icui18n',
         '../third_party/icu/icu.gyp:icuuc',
-        '../ui/accelerometer/ui_accelerometer.gyp:ui_accelerometer',
         '../ui/accessibility/accessibility.gyp:accessibility',
         '../ui/app_list/app_list.gyp:app_list',
         '../ui/aura/aura.gyp:aura',
diff --git a/ash/content/display/screen_orientation_controller_chromeos.cc b/ash/content/display/screen_orientation_controller_chromeos.cc
index 34398a2..a80a1b8 100644
--- a/ash/content/display/screen_orientation_controller_chromeos.cc
+++ b/ash/content/display/screen_orientation_controller_chromeos.cc
@@ -12,10 +12,12 @@
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
 #include "content/public/browser/screen_orientation_provider.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
+#include "ui/chromeos/accelerometer/accelerometer_util.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/wm/public/activation_client.h"
@@ -145,16 +147,16 @@
 }
 
 void ScreenOrientationController::OnAccelerometerUpdated(
-    const ui::AccelerometerUpdate& update) {
+    const chromeos::AccelerometerUpdate& update) {
   if (rotation_locked_ && !CanRotateInLockedState())
     return;
-  if (!update.has(ui::ACCELEROMETER_SOURCE_SCREEN))
+  if (!update.has(chromeos::ACCELEROMETER_SOURCE_SCREEN))
     return;
   // Ignore the reading if it appears unstable. The reading is considered
   // unstable if it deviates too much from gravity
-  if (chromeos::AccelerometerReader::IsReadingStable(
-          update, ui::ACCELEROMETER_SOURCE_SCREEN)) {
-    HandleScreenRotation(update.get(ui::ACCELEROMETER_SOURCE_SCREEN));
+  if (ui::IsAccelerometerReadingStable(update,
+                                       chromeos::ACCELEROMETER_SOURCE_SCREEN)) {
+    HandleScreenRotation(update.get(chromeos::ACCELEROMETER_SOURCE_SCREEN));
   }
 }
 
@@ -314,8 +316,8 @@
 }
 
 void ScreenOrientationController::HandleScreenRotation(
-    const gfx::Vector3dF& lid) {
-  gfx::Vector3dF lid_flattened(lid.x(), lid.y(), 0.0f);
+    const chromeos::AccelerometerReading& lid) {
+  gfx::Vector3dF lid_flattened(lid.x, lid.y, 0.0f);
   float lid_flattened_length = lid_flattened.Length();
   // When the lid is close to being flat, don't change rotation as it is too
   // sensitive to slight movements.
diff --git a/ash/content/display/screen_orientation_controller_chromeos.h b/ash/content/display/screen_orientation_controller_chromeos.h
index b8cdd86..43fa886 100644
--- a/ash/content/display/screen_orientation_controller_chromeos.h
+++ b/ash/content/display/screen_orientation_controller_chromeos.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
 #include "content/public/browser/screen_orientation_delegate.h"
 #include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
 #include "ui/aura/window_observer.h"
@@ -80,7 +81,8 @@
   void OnWindowDestroying(aura::Window* window) override;
 
   // chromeos::AccelerometerReader::Observer:
-  void OnAccelerometerUpdated(const ui::AccelerometerUpdate& update) override;
+  void OnAccelerometerUpdated(
+      const chromeos::AccelerometerUpdate& update) override;
 
   // content::ScreenOrientationDelegate:
   bool FullScreenRequired(content::WebContents* web_contents) override;
@@ -126,7 +128,7 @@
 
   // Detect screen rotation from |lid| accelerometer and automatically rotate
   // screen.
-  void HandleScreenRotation(const gfx::Vector3dF& lid);
+  void HandleScreenRotation(const chromeos::AccelerometerReading& lid);
 
   // Checks DisplayManager for registered rotation lock, and rotation,
   // preferences. These are then applied.
diff --git a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
index bd9d64e9..03e4e826 100644
--- a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
+++ b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_context.h"
@@ -71,8 +72,8 @@
 }
 
 void TriggerLidUpdate(const gfx::Vector3dF& lid) {
-  ui::AccelerometerUpdate update;
-  update.Set(ui::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
+  chromeos::AccelerometerUpdate update;
+  update.Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
   Shell::GetInstance()->screen_orientation_controller()->OnAccelerometerUpdated(
       update);
 }
diff --git a/ash/display/display_change_observer_chromeos.cc b/ash/display/display_change_observer_chromeos.cc
index 2a8c8bb..de481949 100644
--- a/ash/display/display_change_observer_chromeos.cc
+++ b/ash/display/display_change_observer_chromeos.cc
@@ -280,4 +280,10 @@
 void DisplayChangeObserver::OnKeyboardDeviceConfigurationChanged() {
 }
 
+void DisplayChangeObserver::OnMouseDeviceConfigurationChanged() {
+}
+
+void DisplayChangeObserver::OnTouchpadDeviceConfigurationChanged() {
+}
+
 }  // namespace ash
diff --git a/ash/display/display_change_observer_chromeos.h b/ash/display/display_change_observer_chromeos.h
index a32afc5..228adb27 100644
--- a/ash/display/display_change_observer_chromeos.h
+++ b/ash/display/display_change_observer_chromeos.h
@@ -50,6 +50,8 @@
   // Overriden from ui::InputDeviceEventObserver:
   void OnTouchscreenDeviceConfigurationChanged() override;
   void OnKeyboardDeviceConfigurationChanged() override;
+  void OnMouseDeviceConfigurationChanged() override;
+  void OnTouchpadDeviceConfigurationChanged() override;
 
   // Overriden from ShellObserver:
   void OnAppTerminating() override;
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index c74103a..5846b63 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -246,7 +246,8 @@
     return false;
 
   alignment_ = alignment;
-  if (state_.is_screen_locked || state_.is_adding_user_screen) {
+  if (Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked() ||
+      state_.is_adding_user_screen) {
     // The shelf will itself move to the bottom while locked. If a request is
     // sent to move while being locked, we postpone the move until the lock
     // screen goes away.
@@ -264,7 +265,8 @@
   // bottom alignment. Note: We cannot use state_.is_screen_locked here since
   // that flag gets set later than the SessionStateDelegate reports a locked
   // screen which leads in
-  if (state_.is_screen_locked || state_.is_adding_user_screen)
+  if (Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked() ||
+      state_.is_adding_user_screen)
     return SHELF_ALIGNMENT_BOTTOM;
   return alignment_;
 }
diff --git a/ash/system/chromeos/session/tray_session_length_limit_unittest.cc b/ash/system/chromeos/session/tray_session_length_limit_unittest.cc
index e1152ce6..da203a54 100644
--- a/ash/system/chromeos/session/tray_session_length_limit_unittest.cc
+++ b/ash/system/chromeos/session/tray_session_length_limit_unittest.cc
@@ -30,7 +30,10 @@
     system_tray->AddTrayItem(tray_session_length_limit_);
   }
 
-  void TearDown() override { AshTestBase::TearDown(); }
+  void TearDown() override {
+    ClearSessionLengthLimit();
+    AshTestBase::TearDown();
+  }
 
  protected:
   void UpdateSessionLengthLimitInMin(int mins) {
@@ -47,7 +50,7 @@
       if ((*iter)->id() == TraySessionLengthLimit::kNotificationId)
         return *iter;
     }
-    return NULL;
+    return nullptr;
   }
 
   void ClearSessionLengthLimit() {
@@ -120,8 +123,6 @@
 }
 
 TEST_F(TraySessionLengthLimitTest, RemoveNotification) {
-  message_center::Notification* notification;
-
   // Limit is 15 min.
   UpdateSessionLengthLimitInMin(15);
   EXPECT_TRUE(GetNotification());
@@ -137,7 +138,7 @@
   // Limit is 3 min. The notification should re-appear and should be re-read
   // because of state change.
   UpdateSessionLengthLimitInMin(3);
-  notification = GetNotification();
+  message_center::Notification* notification = GetNotification();
   EXPECT_TRUE(notification);
   EXPECT_TRUE(notification->rich_notification_data().
               should_make_spoken_feedback_for_popup_updates);
diff --git a/ash/virtual_keyboard_controller.cc b/ash/virtual_keyboard_controller.cc
index 3ecc0bc2..d043dd3 100644
--- a/ash/virtual_keyboard_controller.cc
+++ b/ash/virtual_keyboard_controller.cc
@@ -67,6 +67,12 @@
   UpdateDevices();
 }
 
+void VirtualKeyboardController::OnMouseDeviceConfigurationChanged() {
+}
+
+void VirtualKeyboardController::OnTouchpadDeviceConfigurationChanged() {
+}
+
 void VirtualKeyboardController::ToggleIgnoreExternalKeyboard() {
   ignore_external_keyboard_ = !ignore_external_keyboard_;
   UpdateKeyboardEnabled();
diff --git a/ash/virtual_keyboard_controller.h b/ash/virtual_keyboard_controller.h
index 83b9fce..301eb0b 100644
--- a/ash/virtual_keyboard_controller.h
+++ b/ash/virtual_keyboard_controller.h
@@ -28,6 +28,8 @@
   // ui::InputDeviceObserver:
   void OnTouchscreenDeviceConfigurationChanged() override;
   void OnKeyboardDeviceConfigurationChanged() override;
+  void OnMouseDeviceConfigurationChanged() override;
+  void OnTouchpadDeviceConfigurationChanged() override;
 
   // Toggles whether the presense of an external keyboard should be ignored
   // when determining whether or not to show the on-screen keyboard.
diff --git a/ash/wm/maximize_mode/maximize_mode_controller.cc b/ash/wm/maximize_mode/maximize_mode_controller.cc
index 1463a50..ee503a3 100644
--- a/ash/wm/maximize_mode/maximize_mode_controller.cc
+++ b/ash/wm/maximize_mode/maximize_mode_controller.cc
@@ -30,12 +30,14 @@
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "ui/chromeos/accelerometer/accelerometer_util.h"
 #endif  // OS_CHROMEOS
 
 namespace ash {
 
 namespace {
 
+#if defined(OS_CHROMEOS)
 // The hinge angle at which to enter maximize mode.
 const float kEnterMaximizeModeAngle = 200.0f;
 
@@ -49,6 +51,7 @@
 // vice versa).
 const float kMinStableAngle = 20.0f;
 const float kMaxStableAngle = 340.0f;
+#endif  // OS_CHROMEOS
 
 // The time duration to consider the lid to be recently opened.
 // This is used to prevent entering maximize mode if an erroneous accelerometer
@@ -57,6 +60,7 @@
 const base::TimeDelta kLidRecentlyOpenedDuration =
     base::TimeDelta::FromSeconds(2);
 
+#if defined(OS_CHROMEOS)
 // When the device approaches vertical orientation (i.e. portrait orientation)
 // the accelerometers for the base and lid approach the same values (i.e.
 // gravity pointing in the direction of the hinge). When this happens we cannot
@@ -65,13 +69,25 @@
 // detect hinge angle in m/s^2.
 const float kHingeAngleDetectionThreshold = 2.5f;
 
-#if defined(OS_CHROMEOS)
 // The maximum deviation between the magnitude of the two accelerometers under
-// which to detect hinge angle and screen rotation in m/s^2. These
-// accelerometers are attached to the same physical device and so should be
-// under the same acceleration.
+// which to detect hinge angle in m/s^2. These accelerometers are attached to
+// the same physical device and so should be under the same acceleration.
 const float kNoisyMagnitudeDeviation = 1.0f;
-#endif
+
+// The angle between chromeos::AccelerometerReadings are considered stable if
+// their magnitudes do not differ greatly. This returns false if the deviation
+// between the screen and keyboard accelerometers is too high.
+bool IsAngleBetweenAccelerometerReadingsStable(
+    const chromeos::AccelerometerUpdate& update) {
+  return std::abs(
+             ui::ConvertAccelerometerReadingToVector3dF(
+                 update.get(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD))
+                 .Length() -
+             ui::ConvertAccelerometerReadingToVector3dF(
+                 update.get(chromeos::ACCELEROMETER_SOURCE_SCREEN)).Length()) <=
+         kNoisyMagnitudeDeviation;
+}
+#endif  // OS_CHROMEOS
 
 }  // namespace
 
@@ -131,32 +147,28 @@
 
 #if defined(OS_CHROMEOS)
 void MaximizeModeController::OnAccelerometerUpdated(
-    const ui::AccelerometerUpdate& update) {
+    const chromeos::AccelerometerUpdate& update) {
   bool first_accelerometer_update = !have_seen_accelerometer_data_;
   have_seen_accelerometer_data_ = true;
 
-  if (!update.has(ui::ACCELEROMETER_SOURCE_SCREEN))
+  if (!update.has(chromeos::ACCELEROMETER_SOURCE_SCREEN))
     return;
 
   // Whether or not we enter maximize mode affects whether we handle screen
   // rotation, so determine whether to enter maximize mode first.
-  if (!update.has(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)) {
+  if (!update.has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)) {
     if (first_accelerometer_update)
       EnterMaximizeMode();
-  } else if (chromeos::AccelerometerReader::IsReadingStable(
-                 update, ui::ACCELEROMETER_SOURCE_SCREEN) &&
-             chromeos::AccelerometerReader::IsReadingStable(
-                 update, ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) &&
-             std::abs(update.get(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)
-                          .Length() -
-                      update.get(ui::ACCELEROMETER_SOURCE_SCREEN).Length()) <=
-                 kNoisyMagnitudeDeviation) {
-    // update.has(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)
+  } else if (ui::IsAccelerometerReadingStable(
+                 update, chromeos::ACCELEROMETER_SOURCE_SCREEN) &&
+             ui::IsAccelerometerReadingStable(
+                 update, chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) &&
+             IsAngleBetweenAccelerometerReadingsStable(update)) {
+    // update.has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)
     // Ignore the reading if it appears unstable. The reading is considered
     // unstable if it deviates too much from gravity and/or the magnitude of the
     // reading from the lid differs too much from the reading from the base.
-    HandleHingeRotation(update.get(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD),
-                        update.get(ui::ACCELEROMETER_SOURCE_SCREEN));
+    HandleHingeRotation(update);
   }
 }
 
@@ -176,15 +188,16 @@
     const base::TimeDelta& sleep_duration) {
   last_touchview_transition_time_ = base::Time::Now();
 }
-#endif  // OS_CHROMEOS
 
-void MaximizeModeController::HandleHingeRotation(const gfx::Vector3dF& base,
-                                                 const gfx::Vector3dF& lid) {
+void MaximizeModeController::HandleHingeRotation(
+    const chromeos::AccelerometerUpdate& update) {
   static const gfx::Vector3dF hinge_vector(1.0f, 0.0f, 0.0f);
   // Ignore the component of acceleration parallel to the hinge for the purposes
   // of hinge angle calculation.
-  gfx::Vector3dF base_flattened(base);
-  gfx::Vector3dF lid_flattened(lid);
+  gfx::Vector3dF base_flattened(ui::ConvertAccelerometerReadingToVector3dF(
+      update.get(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)));
+  gfx::Vector3dF lid_flattened(ui::ConvertAccelerometerReadingToVector3dF(
+      update.get(chromeos::ACCELEROMETER_SOURCE_SCREEN)));
   base_flattened.set_x(0.0f);
   lid_flattened.set_x(0.0f);
 
@@ -235,6 +248,7 @@
 #endif
   }
 }
+#endif  // OS_CHROMEOS
 
 void MaximizeModeController::EnterMaximizeMode() {
   if (IsMaximizeModeWindowManagerEnabled())
diff --git a/ash/wm/maximize_mode/maximize_mode_controller.h b/ash/wm/maximize_mode/maximize_mode_controller.h
index 5e0a9e9..f7959661 100644
--- a/ash/wm/maximize_mode/maximize_mode_controller.h
+++ b/ash/wm/maximize_mode/maximize_mode_controller.h
@@ -14,6 +14,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
 #include "chromeos/dbus/power_manager_client.h"
 #endif  // OS_CHROMEOS
 
@@ -81,7 +82,8 @@
 
 #if defined(OS_CHROMEOS)
   // chromeos::AccelerometerReader::Observer:
-  void OnAccelerometerUpdated(const ui::AccelerometerUpdate& update) override;
+  void OnAccelerometerUpdated(
+      const chromeos::AccelerometerUpdate& update) override;
 
   // PowerManagerClient::Observer:
   void LidEventReceived(bool open, const base::TimeTicks& time) override;
@@ -99,10 +101,11 @@
   // artificially and deterministically control the current time.
   void SetTickClockForTest(scoped_ptr<base::TickClock> tick_clock);
 
-  // Detect hinge rotation from |base| and |lid| accelerometers and
-  // automatically start / stop maximize mode.
-  void HandleHingeRotation(const gfx::Vector3dF& base,
-                           const gfx::Vector3dF& lid);
+#if defined(OS_CHROMEOS)
+  // Detect hinge rotation from base and lid accelerometers and automatically
+  // start / stop maximize mode.
+  void HandleHingeRotation(const chromeos::AccelerometerUpdate& update);
+#endif
 
   // Returns true if the lid was recently opened.
   bool WasLidOpenedRecently() const;
diff --git a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc
index bed2585..b3f0434 100644
--- a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc
+++ b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc
@@ -17,7 +17,7 @@
 #include "base/command_line.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "chromeos/accelerometer/accelerometer_reader.h"
-#include "ui/accelerometer/accelerometer_types.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
 #include "ui/events/event_handler.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/geometry/vector3d_f.h"
@@ -77,18 +77,19 @@
   }
 
   void TriggerLidUpdate(const gfx::Vector3dF& lid) {
-    ui::AccelerometerUpdate update;
-    update.Set(ui::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
+    chromeos::AccelerometerUpdate update;
+    update.Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(),
+               lid.z());
     maximize_mode_controller()->OnAccelerometerUpdated(update);
   }
 
   void TriggerBaseAndLidUpdate(const gfx::Vector3dF& base,
                                const gfx::Vector3dF& lid) {
-    ui::AccelerometerUpdate update;
-    update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD,
-        base.x(), base.y(), base.z());
-    update.Set(ui::ACCELEROMETER_SOURCE_SCREEN,
-        lid.x(), lid.y(), lid.z());
+    chromeos::AccelerometerUpdate update;
+    update.Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, base.x(),
+               base.y(), base.z());
+    update.Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(),
+               lid.z());
     maximize_mode_controller()->OnAccelerometerUpdated(update);
   }
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index c1df2ec..43f92f50 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -171,11 +171,6 @@
     "debug/stack_trace_win.cc",
     "debug/task_annotator.cc",
     "debug/task_annotator.h",
-    "debug/trace_event.h",
-    "debug/trace_event_argument.h",
-    "debug/trace_event_impl.h",
-    "debug/trace_event_synthetic_delay.h",
-    "debug/trace_event_win.h",
     "deferred_sequenced_task_runner.cc",
     "deferred_sequenced_task_runner.h",
     "environment.cc",
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 602358b..2168c218 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
@@ -175,18 +175,12 @@
                     String apkFilePath = null;
                     boolean useMapExecSupportFallback = false;
 
-                    // If the Android build version pre-dates KitKat and the device
-                    // manufacturer is Samsung, skip the check for mmap exec support and
-                    // return false. This avoids triggering a warning on these devices.
-                    // The version check is included because these devices do not show
-                    // the warning on later OS builds.
+                    // 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;
-                    final int version = android.os.Build.VERSION.SDK_INT;
                     if (manufacturer != null
-                            && version < android.os.Build.VERSION_CODES.KITKAT
                             && manufacturer.toLowerCase(Locale.ENGLISH).contains("samsung")) {
                         Log.w(TAG, "Suppressed load from APK support check on this device");
                         sProbeMapApkWithExecPermission = false;
diff --git a/base/base.gypi b/base/base.gypi
index d4dd4dc..73c6c3b 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -173,11 +173,6 @@
           'debug/stack_trace_win.cc',
           'debug/task_annotator.cc',
           'debug/task_annotator.h',
-          'debug/trace_event.h',
-          'debug/trace_event_argument.h',
-          'debug/trace_event_impl.h',
-          'debug/trace_event_synthetic_delay.h',
-          'debug/trace_event_win.h',
           'deferred_sequenced_task_runner.cc',
           'deferred_sequenced_task_runner.h',
           'environment.cc',
diff --git a/base/base.isolate b/base/base.isolate
index 021c01c..5220887 100644
--- a/base/base.isolate
+++ b/base/base.isolate
@@ -9,13 +9,20 @@
     '../third_party/icu/icu.isolate',
   ],
   'conditions': [
-    ['OS=="linux" and asan==1 and chromeos==0', {
+    ['use_custom_libcxx==1', {
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/lib/libc++.so',
         ],
       },
     }],
+    ['use_instrumented_libraries==1', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/instrumented_libraries/',
+        ],
+      },
+    }],
     ['OS=="mac" and asan==1', {
       'variables': {
         'files': [
@@ -30,7 +37,7 @@
         ],
       },
     }],
-    ['OS=="linux" and asan==1', {
+    ['OS=="linux" and (asan==1 or lsan==1 or msan==1 or tsan==1)', {
       'variables': {
         'files': [
           # For llvm-symbolizer.
@@ -38,7 +45,7 @@
         ],
       },
     }],
-    ['asan==1', {
+    ['asan==1 or lsan==1 or msan==1 or tsan==1', {
       'variables': {
         'files': [
           '../tools/valgrind/asan/',
@@ -53,23 +60,35 @@
         ],
       },
     }],
+    # 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': [
-          # Copy the VS runtime DLLs into the isolate so that they
-          # don't have to be preinstalled on the target machine.
           '<(PRODUCT_DIR)/msvcp120d.dll',
           '<(PRODUCT_DIR)/msvcr120d.dll',
-          '<(PRODUCT_DIR)/x64/msvcp120d.dll',
-          '<(PRODUCT_DIR)/x64/msvcr120d.dll',
         ],
       },
     }],
     ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Release" or CONFIGURATION_NAME=="Release_x64")', {
       'variables': {
         'files': [
-          # Copy the VS runtime DLLs into the isolate so that they
-          # don't have to be preinstalled on the target machine.
           '<(PRODUCT_DIR)/msvcp120.dll',
           '<(PRODUCT_DIR)/msvcr120.dll',
         ],
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
index f561d20..fca76d5 100644
--- a/base/base_unittests.isolate
+++ b/base/base_unittests.isolate
@@ -20,6 +20,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -51,6 +53,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
index 572f285b..fb271b6d 100644
--- a/base/debug/stack_trace.h
+++ b/base/debug/stack_trace.h
@@ -17,6 +17,7 @@
 
 #if defined(OS_WIN)
 struct _EXCEPTION_POINTERS;
+struct _CONTEXT;
 #endif
 
 namespace base {
@@ -54,6 +55,7 @@
   // Note: this function will throw an import not found (StackWalk64) exception
   // on system without dbghelp 5.1.
   StackTrace(const _EXCEPTION_POINTERS* exception_pointers);
+  StackTrace(const _CONTEXT* context);
 #endif
 
   // Copying and assignment are allowed with the default functions.
@@ -76,6 +78,10 @@
   std::string ToString() const;
 
  private:
+#if defined(OS_WIN)
+  void InitTrace(_CONTEXT* context_record);
+#endif
+
   // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
   // the sum of FramesToSkip and FramesToCapture must be less than 63,
   // so set it to 62. Even if on POSIX it could be a larger value, it usually
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
index 8df6fc6..27661edc 100644
--- a/base/debug/stack_trace_win.cc
+++ b/base/debug/stack_trace_win.cc
@@ -214,24 +214,35 @@
 #endif
 
 StackTrace::StackTrace(const EXCEPTION_POINTERS* exception_pointers) {
-  // When walking an exception stack, we need to use StackWalk64().
-  count_ = 0;
   // StackWalk64() may modify context record passed to it, so we will
   // use a copy.
   CONTEXT context_record = *exception_pointers->ContextRecord;
+  InitTrace(&context_record);
+}
+
+StackTrace::StackTrace(const CONTEXT* context) {
+  // StackWalk64() may modify context record passed to it, so we will
+  // use a copy.
+  CONTEXT context_record = *context;
+  InitTrace(&context_record);
+}
+
+void StackTrace::InitTrace(CONTEXT* context_record) {
+  // When walking an exception stack, we need to use StackWalk64().
+  count_ = 0;
   // Initialize stack walking.
   STACKFRAME64 stack_frame;
   memset(&stack_frame, 0, sizeof(stack_frame));
 #if defined(_WIN64)
   int machine_type = IMAGE_FILE_MACHINE_AMD64;
-  stack_frame.AddrPC.Offset = context_record.Rip;
-  stack_frame.AddrFrame.Offset = context_record.Rbp;
-  stack_frame.AddrStack.Offset = context_record.Rsp;
+  stack_frame.AddrPC.Offset = context_record->Rip;
+  stack_frame.AddrFrame.Offset = context_record->Rbp;
+  stack_frame.AddrStack.Offset = context_record->Rsp;
 #else
   int machine_type = IMAGE_FILE_MACHINE_I386;
-  stack_frame.AddrPC.Offset = context_record.Eip;
-  stack_frame.AddrFrame.Offset = context_record.Ebp;
-  stack_frame.AddrStack.Offset = context_record.Esp;
+  stack_frame.AddrPC.Offset = context_record->Eip;
+  stack_frame.AddrFrame.Offset = context_record->Ebp;
+  stack_frame.AddrStack.Offset = context_record->Esp;
 #endif
   stack_frame.AddrPC.Mode = AddrModeFlat;
   stack_frame.AddrFrame.Mode = AddrModeFlat;
@@ -240,7 +251,7 @@
                      GetCurrentProcess(),
                      GetCurrentThread(),
                      &stack_frame,
-                     &context_record,
+                     context_record,
                      NULL,
                      &SymFunctionTableAccess64,
                      &SymGetModuleBase64,
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
deleted file mode 100644
index 7d97e168..0000000
--- a/base/debug/trace_event.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.
-
-// In the process of moving the trace event files. Right now the headers
-// are being forwarded. In next CLs the change will get completed
-// TODO(ssid): https://code.google.com/p/chromium/issues/detail?id=451032
-
-#ifndef BASE_DEBUG_TRACE_EVENT_H_
-#define BASE_DEBUG_TRACE_EVENT_H_
-
-#include "base/trace_event/trace_event.h"
-
-#endif  // BASE_DEBUG_TRACE_EVENT_H_
diff --git a/base/debug/trace_event_argument.h b/base/debug/trace_event_argument.h
deleted file mode 100644
index 167b46c9..0000000
--- a/base/debug/trace_event_argument.h
+++ /dev/null
@@ -1,14 +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.
-
-// In the process of moving the trace event files. Right now the headers
-// are being forwarded. In next CLs the change will get completed
-// TODO(ssid): https://code.google.com/p/chromium/issues/detail?id=451032
-
-#ifndef BASE_DEBUG_TRACE_EVENT_ARGUMENT_H_
-#define BASE_DEBUG_TRACE_EVENT_ARGUMENT_H_
-
-#include "base/trace_event/trace_event_argument.h"
-
-#endif // BASE_DEBUG_TRACE_EVENT_ARGUMENT_H_
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
deleted file mode 100644
index a619d290..0000000
--- a/base/debug/trace_event_impl.h
+++ /dev/null
@@ -1,14 +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.
-
-// In the process of moving the trace event files. Right now the headers
-// are being forwarded. In next CLs the change will get completed
-// TODO(ssid): https://code.google.com/p/chromium/issues/detail?id=451032
-
-#ifndef BASE_DEBUG_TRACE_EVENT_IMPL_H_
-#define BASE_DEBUG_TRACE_EVENT_IMPL_H_
-
-#include "base/trace_event/trace_event_impl.h"
-
-#endif  // BASE_DEBUG_TRACE_EVENT_IMPL_H_
diff --git a/base/debug/trace_event_synthetic_delay.h b/base/debug/trace_event_synthetic_delay.h
deleted file mode 100644
index 1f1eafb5..0000000
--- a/base/debug/trace_event_synthetic_delay.h
+++ /dev/null
@@ -1,14 +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.
-
-// In the process of moving the trace event files. Right now the headers
-// are being forwarded. In next CLs the change will get completed
-// TODO(ssid): https://code.google.com/p/chromium/issues/detail?id=451032
-
-#ifndef BASE_DEBUG_TRACE_EVENT_SYNTHETIC_DELAY_H_
-#define BASE_DEBUG_TRACE_EVENT_SYNTHETIC_DELAY_H_
-
-#include "base/trace_event/trace_event_synthetic_delay.h"
-
-#endif  // BASE_DEBUG_TRACE_EVENT_SYNTHETIC_DELAY_H_
diff --git a/base/debug/trace_event_win.h b/base/debug/trace_event_win.h
deleted file mode 100644
index 473e174e..0000000
--- a/base/debug/trace_event_win.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.
-
-// In the process of moving the trace event files. Right now the headers
-// are being forwarded. In next CLs the change will get completed
-// TODO(ssid): https://code.google.com/p/chromium/issues/detail?id=451032
-
-#ifndef BASE_DEBUG_TRACE_EVENT_WIN_H_
-#define BASE_DEBUG_TRACE_EVENT_WIN_H_
-
-#include "base/trace_event/trace_event_win.h"
-
-#endif  // BASE_DEBUG_TRACE_EVENT_WIN_H_
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 9e5b013..07de4a15 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -4,6 +4,8 @@
 
 #include "base/message_loop/incoming_task_queue.h"
 
+#include <limits>
+
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
@@ -15,6 +17,12 @@
 
 namespace {
 
+// Delays larger than this many microseconds are often bogus, and a warning
+// should be emitted in debug builds to warn developers.
+// http://crbug.com/450045
+const int kTaskDelayWarningThresholdInMicroseconds =
+    std::numeric_limits<int>::max() / 2;  // A little less than 18 minutes.
+
 // Returns true if MessagePump::ScheduleWork() must be called one
 // time for every task that is added to the MessageLoop incoming queue.
 bool AlwaysNotifyPump(MessageLoop::Type type) {
@@ -43,6 +51,11 @@
     const Closure& task,
     TimeDelta delay,
     bool nestable) {
+  DLOG_IF(WARNING,
+          delay.InMicroseconds() > kTaskDelayWarningThresholdInMicroseconds)
+      << "Requesting super-long task delay period of " << delay.InMicroseconds()
+      << " usec from here: " << from_here.ToString();
+
   AutoLock locked(incoming_queue_lock_);
   PendingTask pending_task(
       from_here, task, CalculateDelayedRuntime(delay), nestable);
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 24db543..86771e43 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -5,7 +5,6 @@
 #include "base/message_loop/message_loop.h"
 
 #include <algorithm>
-#include <limits>
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
@@ -44,12 +43,6 @@
 LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
     LAZY_INSTANCE_INITIALIZER;
 
-// Delays larger than this many microseconds are likely bogus, and a warning
-// should be emitted in debug builds to warn developers.
-// http://crbug.com/450045
-const int kTaskDelayWarningThresholdInMicroseconds =
-    std::numeric_limits<int>::max() / 2;
-
 // 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;
@@ -286,10 +279,6 @@
     const Closure& task,
     TimeDelta delay) {
   DCHECK(!task.is_null()) << from_here.ToString();
-  DLOG_IF(WARNING,
-          delay.InMicroseconds() > kTaskDelayWarningThresholdInMicroseconds)
-      << "Requesting super-long task delay period of " << delay.InMicroseconds()
-      << " usec from " << from_here.ToString();
   incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true);
 }
 
@@ -305,10 +294,6 @@
     const Closure& task,
     TimeDelta delay) {
   DCHECK(!task.is_null()) << from_here.ToString();
-  DLOG_IF(WARNING,
-          delay.InMicroseconds() > kTaskDelayWarningThresholdInMicroseconds)
-      << "Requesting super-long task delay period of " << delay.InMicroseconds()
-      << " usec from " << from_here.ToString();
   incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false);
 }
 
diff --git a/base/test/test_support_ios.mm b/base/test/test_support_ios.mm
index 67fae06f1..3b31da6 100644
--- a/base/test/test_support_ios.mm
+++ b/base/test/test_support_ios.mm
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_pump_default.h"
 #include "base/test/test_suite.h"
+#include "testing/coverage_util_ios.h"
 
 // Springboard will kill any iOS app that fails to check in after launch within
 // a given time. Starting a UIApplication before invoking TestSuite::Run
@@ -165,6 +166,8 @@
   UIApplication* application = [UIApplication sharedApplication];
   [application _terminateWithStatus:exitStatus];
 
+  coverage_util::FlushCoverageDataIfNecessary();
+
   exit(exitStatus);
 }
 
diff --git a/build/PRESUBMIT.py b/build/PRESUBMIT.py
new file mode 100644
index 0000000..3c70193
--- /dev/null
+++ b/build/PRESUBMIT.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.
+
+WHITELIST = [ r'.+_test.py$' ]
+
+
+def _RunTests(input_api, output_api):
+  return (input_api.canned_checks.RunUnitTestsInDirectory(
+          input_api, output_api, '.', whitelist=[r'.+_test.py$']))
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _RunTests(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _RunTests(input_api, output_api)
diff --git a/build/all.gyp b/build/all.gyp
index 90c01205..8556aa7 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -750,7 +750,6 @@
               'dependencies': [
                 '../chrome/chrome_syzygy.gyp:chrome_dll_syzygy',
                 '../content/content_shell_and_tests.gyp:content_shell_syzyasan',
-                '../pdf/pdf.gyp:pdf_syzyasan',
               ],
               'conditions': [
                 ['chrome_multiple_dll==1', {
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 7f3a868..d1daaf2 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -62,6 +62,7 @@
       output_api,
       unit_tests=[
           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'),
diff --git a/build/android/adb_gdb b/build/android/adb_gdb
index 97d37db..c71b816 100755
--- a/build/android/adb_gdb
+++ b/build/android/adb_gdb
@@ -26,6 +26,7 @@
 TMPDIR=
 GDBSERVER_PIDFILE=
 TARGET_GDBSERVER=
+COMMAND_PREFIX=
 
 clean_exit () {
   if [ "$TMPDIR" ]; then
@@ -36,7 +37,7 @@
     fi
     if [ "$TARGET_GDBSERVER" ]; then
       log "Removing target gdbserver binary: $TARGET_GDBSERVER."
-      "$ADB" shell run-as "$PACKAGE_NAME" rm "$TARGET_GDBSERVER" >/dev/null 2>&1
+      "$ADB" shell "$COMMAND_PREFIX" rm "$TARGET_GDBSERVER" >/dev/null 2>&1
     fi
     log "Cleaning up: $TMPDIR"
     rm -rf "$TMPDIR"
@@ -908,7 +909,7 @@
 # Push gdbserver to the device
 log "Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER"
 adb push $GDBSERVER $TMP_TARGET_GDBSERVER &>/dev/null
-adb shell run-as $PACKAGE_NAME cp $TMP_TARGET_GDBSERVER .
+adb shell $COMMAND_PREFIX cp $TMP_TARGET_GDBSERVER $TARGET_GDBSERVER
 adb shell rm $TMP_TARGET_GDBSERVER
 fail_panic "Could not copy gdbserver to the device!"
 
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index 5ec1107d..09c12b2 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -5,4 +5,3 @@
 M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.webContents  In PendingDocumentData.java
 M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.originalIntent  In PendingDocumentData.java
 M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.url  In PendingDocumentData.java
-M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.userGesture  In PendingDocumentData.java
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index 1dbb1d8..7d11671 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -285,7 +285,8 @@
           cmd, 'path does not specify an accessible directory in the device',
           device_serial=self._device_serial)
 
-  def Logcat(self, filter_spec=None, timeout=None):
+  def Logcat(self, clear=False, dump=False, filter_spec=None,
+             logcat_format=None, timeout=None):
     """Get an iterator over the logcat output.
 
     Args:
@@ -296,6 +297,12 @@
       logcat output line by line.
     """
     cmd = ['logcat']
+    if clear:
+      cmd.append('-c')
+    if dump:
+      cmd.append('-d')
+    if logcat_format:
+      cmd.extend(['-v', logcat_format])
     if filter_spec is not None:
       cmd.append(filter_spec)
     return self._IterRunDeviceAdbCmd(cmd, timeout)
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 805df65..a5ce11e6 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -6,7 +6,7 @@
 
 Eventually, this will be based on adb_wrapper.
 """
-# pylint: disable=W0613
+# pylint: disable=unused-argument
 
 import logging
 import multiprocessing
@@ -24,6 +24,7 @@
 from pylib.device import decorators
 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 device_temp_file
@@ -350,11 +351,13 @@
   @decorators.WithTimeoutAndRetriesDefaults(
       REBOOT_DEFAULT_TIMEOUT,
       REBOOT_DEFAULT_RETRIES)
-  def Reboot(self, block=True, timeout=None, retries=None):
+  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
 
@@ -369,7 +372,7 @@
     self._cache = {}
     timeout_retry.WaitFor(device_offline, wait_period=1)
     if block:
-      self.WaitUntilFullyBooted()
+      self.WaitUntilFullyBooted(wifi=wifi)
 
   INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT
   INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES
@@ -1288,6 +1291,19 @@
     """
     return self.old_interface.GetMemoryUsageForPid(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 __str__(self):
     """Returns the device serial."""
     return self.adb.GetDeviceSerial()
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 68c8b716..9d41741 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -457,9 +457,17 @@
         self.call.adb.Reboot(),
         (self.call.device.IsOnline(), True),
         (self.call.device.IsOnline(), False),
-        self.call.device.WaitUntilFullyBooted()):
+        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(DeviceUtilsNewImplTest):
 
diff --git a/build/android/pylib/device/logcat_monitor.py b/build/android/pylib/device/logcat_monitor.py
new file mode 100644
index 0000000..7ede49c5
--- /dev/null
+++ b/build/android/pylib/device/logcat_monitor.py
@@ -0,0 +1,143 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=unused-argument
+
+import collections
+import itertools
+import logging
+import subprocess
+import tempfile
+import time
+import re
+
+from pylib.device import adb_wrapper
+from pylib.device import decorators
+from pylib.device import device_errors
+
+
+class LogcatMonitor(object):
+
+  # Format: <DATE> <TIME> <PID> <TID> <LEVEL> <COMPONENT>: <MESSAGE>
+  _THREADTIME_RE_FORMAT = r'\S* +\S* +(%s) +(%s) +(%s) +(%s): +(%s)$'
+
+  def __init__(self, adb, clear=True):
+    """Create a LogcatMonitor instance.
+
+    Args:
+      adb: An instance of adb_wrapper.AdbWrapper.
+      clear: If True, clear the logcat when monitoring starts.
+    """
+    if isinstance(adb, adb_wrapper.AdbWrapper):
+      self._adb = adb
+    else:
+      raise ValueError('Unsupported type passed for argument "device"')
+    self._clear = clear
+    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():
+      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.
+
+    Returns:
+      An iterable containing objects with five attributes:
+        |proc_id|: the process ID
+        |thread_id|: the thread ID
+        |log_level|: the log level
+        |component|: the component
+        |message|: the logcat message
+    """
+    LogcatLine = collections.namedtuple(
+        'LogcatLine',
+        ['proc_id', 'thread_id', 'log_level', 'component', '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))
+
+    regexed_lines = (
+        re.match(threadtime_re, l)
+        for l in self._adb.Logcat(dump=True, logcat_format='threadtime'))
+    only_matches = (m for m in regexed_lines if m)
+    return (LogcatLine(*m.group(1, 2, 3, 4, 5)) for m in only_matches)
+
+  def Start(self):
+    """Starts the logcat monitor.
+
+    Clears the logcat if |clear| was set in |__init__|.
+    """
+    if self._clear:
+      self._adb.Logcat(clear=True)
+
+  def __enter__(self):
+    """Starts the logcat monitor."""
+    self.Start()
+    return self
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """Stops the logcat monitor."""
+    pass
diff --git a/build/android/pylib/device/logcat_monitor_test.py b/build/android/pylib/device/logcat_monitor_test.py
new file mode 100755
index 0000000..7a6bf56d
--- /dev/null
+++ b/build/android/pylib/device/logcat_monitor_test.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import itertools
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.device import adb_wrapper
+from pylib.device import decorators
+from pylib.device import logcat_monitor
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class LogcatMonitorTest(unittest.TestCase):
+
+  _TEST_THREADTIME_LOGCAT_DATA = [
+        '01-01 01:02:03.456  7890  0987 V LogcatMonitorTest: '
+            'verbose logcat monitor test message 1',
+        '01-01 01:02:03.457  8901  1098 D LogcatMonitorTest: '
+            'debug logcat monitor test message 2',
+        '01-01 01:02:03.458  9012  2109 I LogcatMonitorTest: '
+            'info logcat monitor test message 3',
+        '01-01 01:02:03.459  0123  3210 W LogcatMonitorTest: '
+            'warning logcat monitor test message 4',
+        '01-01 01:02:03.460  1234  4321 E LogcatMonitorTest: '
+            'error logcat monitor test message 5',
+        '01-01 01:02:03.461  2345  5432 F LogcatMonitorTest: '
+            'fatal logcat monitor test message 6',
+        '01-01 01:02:03.462  3456  6543 D LogcatMonitorTest: '
+            'ignore me',]
+
+  def _createTestLog(self, raw_logcat=None):
+    test_adb = adb_wrapper.AdbWrapper('0123456789abcdef')
+    test_adb.Logcat = mock.Mock(return_value=(l for l in raw_logcat))
+    test_log = logcat_monitor.LogcatMonitor(test_adb, clear=False)
+    return test_log
+
+  def assertIterEqual(self, expected_iter, actual_iter):
+    for expected, actual in itertools.izip_longest(expected_iter, actual_iter):
+      self.assertIsNotNone(
+          expected,
+          msg='actual has unexpected elements starting with %s' % str(actual))
+      self.assertIsNotNone(
+          actual,
+          msg='actual is missing elements starting with %s' % str(expected))
+      self.assertEqual(actual.proc_id, expected[0])
+      self.assertEqual(actual.thread_id, expected[1])
+      self.assertEqual(actual.log_level, expected[2])
+      self.assertEqual(actual.component, expected[3])
+      self.assertEqual(actual.message, expected[4])
+
+    with self.assertRaises(StopIteration):
+      next(actual_iter)
+    with self.assertRaises(StopIteration):
+      next(expected_iter)
+
+  def testWaitFor_success(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_match = test_log.WaitFor(r'.*(fatal|error) logcat monitor.*', None)
+    self.assertTrue(actual_match)
+    self.assertEqual(
+        '01-01 01:02:03.460  1234  4321 E LogcatMonitorTest: '
+            'error logcat monitor test message 5',
+        actual_match.group(0))
+    self.assertEqual('error', actual_match.group(1))
+
+  def testWaitFor_failure(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_match = test_log.WaitFor(
+        r'.*My Success Regex.*', r'.*(fatal|error) logcat monitor.*')
+    self.assertIsNone(actual_match)
+
+  def testFindAll_defaults(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    expected_results = [
+        ('7890', '0987', 'V', 'LogcatMonitorTest',
+         'verbose logcat monitor test message 1'),
+        ('8901', '1098', 'D', 'LogcatMonitorTest',
+         'debug logcat monitor test message 2'),
+        ('9012', '2109', 'I', 'LogcatMonitorTest',
+         'info logcat monitor test message 3'),
+        ('0123', '3210', 'W', 'LogcatMonitorTest',
+         'warning logcat monitor test message 4'),
+        ('1234', '4321', 'E', 'LogcatMonitorTest',
+         'error logcat monitor test message 5'),
+        ('2345', '5432', 'F', 'LogcatMonitorTest',
+         'fatal logcat monitor test message 6')]
+    actual_results = test_log.FindAll(r'\S* logcat monitor test message \d')
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_defaults_miss(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    expected_results = []
+    actual_results = test_log.FindAll(r'\S* nothing should match this \d')
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterProcId(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(
+        r'\S* logcat monitor test message \d', proc_id=1234)
+    expected_results = [
+        ('1234', '4321', 'E', 'LogcatMonitorTest',
+         'error logcat monitor test message 5')]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterThreadId(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(
+        r'\S* logcat monitor test message \d', thread_id=2109)
+    expected_results = [
+        ('9012', '2109', 'I', 'LogcatMonitorTest',
+         'info logcat monitor test message 3')]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterLogLevel(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(
+        r'\S* logcat monitor test message \d', log_level=r'[DW]')
+    expected_results = [
+        ('8901', '1098', 'D', 'LogcatMonitorTest',
+         'debug logcat monitor test message 2'),
+        ('0123', '3210', 'W', 'LogcatMonitorTest',
+         'warning logcat monitor test message 4'),]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+  def testFindAll_filterComponent(self):
+    test_log = self._createTestLog(
+        raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
+    actual_results = test_log.FindAll(r'.*', component='LogcatMonitorTest')
+    expected_results = [
+        ('7890', '0987', 'V', 'LogcatMonitorTest',
+         'verbose logcat monitor test message 1'),
+        ('8901', '1098', 'D', 'LogcatMonitorTest',
+         'debug logcat monitor test message 2'),
+        ('9012', '2109', 'I', 'LogcatMonitorTest',
+         'info logcat monitor test message 3'),
+        ('0123', '3210', 'W', 'LogcatMonitorTest',
+         'warning logcat monitor test message 4'),
+        ('1234', '4321', 'E', 'LogcatMonitorTest',
+         'error logcat monitor test message 5'),
+        ('2345', '5432', 'F', 'LogcatMonitorTest',
+         'fatal logcat monitor test message 6'),
+        ('3456', '6543', 'D', 'LogcatMonitorTest',
+         'ignore me'),]
+    self.assertIterEqual(iter(expected_results), actual_results)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
+
diff --git a/build/android/pylib/gtest/filter/unit_tests_disabled b/build/android/pylib/gtest/filter/unit_tests_disabled
index 93defbe..c7851fd 100644
--- a/build/android/pylib/gtest/filter/unit_tests_disabled
+++ b/build/android/pylib/gtest/filter/unit_tests_disabled
@@ -1,10 +1,5 @@
 # List of suppressions
 
-# crbug.com/139429
-BrowserMainTest.WarmConnectionFieldTrial_Invalid
-BrowserMainTest.WarmConnectionFieldTrial_Random
-BrowserMainTest.WarmConnectionFieldTrial_WarmestSocket
-
 # The UDP related tests currently do not work on Android because
 # we lack a UDP forwarder tool.
 NetworkStatsTestUDP.*
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 424dcb3b..fb9557e 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -51,6 +51,7 @@
     super(TestRunner, self).__init__(device, test_options.tool,
                                      test_options.cleanup_test_files)
     self._lighttp_port = constants.LIGHTTPD_RANDOM_PORT_FIRST + shard_index
+    self._logcat_monitor = None
 
     self.coverage_device_file = None
     self.coverage_dir = test_options.coverage_dir
@@ -174,9 +175,10 @@
     """
     if not self._IsPerfTest(test):
       return
-    self.device.old_interface.Adb().SendCommand(
-        'shell rm ' + TestRunner._DEVICE_PERF_OUTPUT_SEARCH_PREFIX)
-    self.device.old_interface.StartMonitoringLogcat()
+    self.device.RunShellCommand(
+        ['rm', TestRunner._DEVICE_PERF_OUTPUT_SEARCH_PREFIX])
+    self._logcat_monitor = self.device.GetLogcatMonitor()
+    self._logcat_monitor.Start()
 
   def TestTeardown(self, test, result):
     """Cleans up the test harness after running a particular test.
@@ -219,9 +221,8 @@
     raw_test_name = test.split('#')[1]
 
     # Wait and grab annotation data so we can figure out which traces to parse
-    regex = self.device.old_interface.WaitForLogMatch(
-        re.compile(r'\*\*PERFANNOTATION\(' + raw_test_name + r'\)\:(.*)'),
-        None)
+    regex = self._logcat_monitor.WaitFor(
+        re.compile(r'\*\*PERFANNOTATION\(' + raw_test_name + r'\)\:(.*)'))
 
     # If the test is set to run on a specific device type only (IE: only
     # tablet or phone) and it is being run on the wrong device, the test
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
index 13f68cb..8ebf803 100644
--- a/build/android/pylib/linker/test_case.py
+++ b/build/android/pylib/linker/test_case.py
@@ -42,6 +42,7 @@
 
 from pylib import constants
 from pylib.base import base_test_result
+from pylib.device import device_errors
 from pylib.device import intent
 
 
@@ -70,10 +71,11 @@
 #_LOGCAT_FILTERS = ['*:v']  ## DEBUG
 
 # Regular expression used to match status lines in logcat.
-re_status_line = re.compile(r'(BROWSER|RENDERER)_LINKER_TEST: (FAIL|SUCCESS)')
+_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(
+_RE_LIBRARY_ADDRESS = re.compile(
     r'(BROWSER|RENDERER)_LIBRARY_ADDRESS: (\S+) ([0-9A-Fa-f]+)')
 
 
@@ -109,46 +111,6 @@
     return configs[0]
 
 
-def _WriteCommandLineFile(device, command_line, command_line_file):
-  """Create a command-line file on the device. This does not use FlagChanger
-     because its implementation assumes the device has 'su', and thus does
-     not work at all with production devices."""
-  device.RunShellCommand(
-      'echo "%s" > %s' % (command_line, command_line_file))
-
-
-def _CheckLinkerTestStatus(logcat):
-  """Parse the content of |logcat| and checks for both a browser and
-     renderer status line.
-
-  Args:
-    logcat: A string to parse. Can include line separators.
-
-  Returns:
-    A tuple, result[0] is True if there is a complete match, then
-    result[1] and result[2] will be True or False to reflect the
-    test status for the browser and renderer processes, respectively.
-  """
-  browser_found = False
-  renderer_found = False
-  for m in re_status_line.finditer(logcat):
-    process_type, status = m.groups()
-    if process_type == 'BROWSER':
-      browser_found = True
-      browser_success = (status == 'SUCCESS')
-    elif process_type == 'RENDERER':
-      renderer_found = True
-      renderer_success = (status == 'SUCCESS')
-    else:
-      assert False, 'Invalid process type ' + process_type
-
-  if browser_found and renderer_found:
-    return (True, browser_success, renderer_success)
-
-  # Didn't find anything.
-  return (False, None, None)
-
-
 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|.
@@ -159,38 +121,30 @@
     A (status, logs) tuple, where status is a ResultType constant, and logs
     if the final logcat output as a string.
   """
-  # 1. Start recording logcat with appropriate filters.
-  device.old_interface.StartRecordingLogcat(
-      clear=True, filters=_LOGCAT_FILTERS)
 
-  try:
+  # 1. Start recording logcat with appropriate filters.
+  with device.GetLogcatMonitor(filters=_LOGCAT_FILTERS) as logmon:
+
     # 2. Force-start activity.
     device.StartActivity(
         intent.Intent(package=_PACKAGE_NAME, activity=_ACTIVITY_NAME),
         force_stop=True)
 
     # 3. Wait up to |timeout| seconds until the test status is in the logcat.
-    num_tries = 0
-    max_tries = timeout
-    found = False
-    while num_tries < max_tries:
-      time.sleep(1)
-      num_tries += 1
-      found, browser_ok, renderer_ok = _CheckLinkerTestStatus(
-          device.old_interface.GetCurrentRecordedLogcat())
-      if found:
-        break
+    result = ResultType.PASS
+    try:
+      browser_match = logmon.WaitFor(_RE_BROWSER_STATUS_LINE, timeout=timeout)
+      logging.debug('Found browser match: %s', browser_match.group(0))
+      renderer_match = logmon.WaitFor(_RE_RENDERER_STATUS_LINE,
+                                      timeout=timeout)
+      logging.debug('Found renderer match: %s', renderer_match.group(0))
+      if (browser_match.group(1) != 'SUCCESS'
+          or renderer_match.group(1) != 'SUCCESS'):
+        result = ResultType.FAIL
+    except device_errors.CommandTimeoutError:
+      result = ResultType.TIMEOUT
 
-  finally:
-    logs = device.old_interface.StopRecordingLogcat()
-
-  if num_tries >= max_tries:
-    return ResultType.TIMEOUT, logs
-
-  if browser_ok and renderer_ok:
-    return ResultType.PASS, logs
-
-  return ResultType.FAIL, logs
+    return result, '\n'.join(device.adb.Logcat(dump=True))
 
 
 class LibraryLoadMap(dict):
@@ -226,7 +180,7 @@
   """
   browser_libs = LibraryLoadMap()
   renderer_libs = LibraryLoadMap()
-  for m in re_library_address.finditer(logs):
+  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':
@@ -323,7 +277,7 @@
     command_line_flags = ''
     if self.is_low_memory:
       command_line_flags = '--low-memory-device'
-    _WriteCommandLineFile(device, command_line_flags, _COMMAND_LINE_FILE)
+    device.WriteFile(_COMMAND_LINE_FILE, command_line_flags)
 
     # Run the test.
     status, logs = self._RunTest(device)
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py
index a701d95..cc39112 100644
--- a/build/android/pylib/remote/device/remote_device_environment.py
+++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -4,6 +4,8 @@
 
 """Environment setup and teardown for remote devices."""
 
+import distutils.version
+import json
 import logging
 import os
 import random
@@ -28,50 +30,138 @@
       error_func: error to show when using bad command line arguments.
     """
     super(RemoteDeviceEnvironment, self).__init__()
-
-    if args.api_key_file:
-      with open(args.api_key_file) as api_key_file:
-        self._api_key = api_key_file.read().strip()
-    elif args.api_key:
-      self._api_key = args.api_key
-    else:
-      error_func('Must set api key with --api-key or --api-key-file')
-
-    if args.api_secret_file:
-      with open(args.api_secret_file) as api_secret_file:
-        self._api_secret = api_secret_file.read().strip()
-    elif args.api_secret:
-      self._api_secret = args.api_secret
-    else:
-      error_func('Must set api secret with --api-secret or --api-secret-file')
-
-    if not args.api_protocol:
-      error_func('Must set api protocol with --api-protocol. Example: http')
-    self._api_protocol = args.api_protocol
-
-    if not args.api_address:
-      error_func('Must set api address with --api-address')
-    self._api_address = args.api_address
-
-    if not args.api_port:
-      error_func('Must set api port with --api-port.')
-    self._api_port = args.api_port
-
-    self._access_token = ''
-    self._results_path = args.results_path
-    self._remote_device = args.remote_device
-    self._remote_device_os = args.remote_device_os
-    self._runner_package = args.runner_package
-    self._runner_type = args.runner_type
-    self._device = ''
-    self._verbose_count = args.verbose_count
+    self._access_token = None
+    self._device = None
     self._device_type = args.device_type
+    self._verbose_count = args.verbose_count
     self._timeouts = {
         'queueing': 60 * 10,
         'installing': 60 * 10,
         'in-progress': 60 * 30,
         'unknown': 60 * 5
     }
+    # Example config file:
+    # {
+    #   "remote_device": ["Galaxy S4", "Galaxy S3"],
+    #   "remote_device_os": ["4.4.2", "4.4.4"],
+    #   "remote_device_minimum_os": "4.4.2",
+    #   "api_address": "www.example.com",
+    #   "api_port": "80",
+    #   "api_protocol": "http",
+    #   "api_secret": "apisecret",
+    #   "api_key": "apikey",
+    #   "timeouts": {
+    #     "queueing": 600,
+    #     "installing": 600,
+    #     "in-progress": 1800,
+    #     "unknown": 300
+    #   }
+    # }
+    if args.remote_device_file:
+      with open(args.remote_device_file) as device_file:
+        device_json = json.load(device_file)
+    else:
+      device_json = {}
+
+    self._api_address = device_json.get('api_address', None)
+    self._api_key = device_json.get('api_key', None)
+    self._api_port = device_json.get('api_port', None)
+    self._api_protocol = device_json.get('api_protocol', None)
+    self._api_secret = device_json.get('api_secret', None)
+    self._device_oem = device_json.get('device_oem', None)
+    self._device_type = device_json.get('device_type', 'Android')
+    self._remote_device = device_json.get('remote_device', None)
+    self._remote_device_minimum_os = device_json.get(
+        'remote_device_minimum_os', None)
+    self._remote_device_os = device_json.get('remote_device_os', None)
+    self._results_path = device_json.get('results_path', None)
+    self._runner_package = device_json.get('runner_package', None)
+    self._runner_type = device_json.get('runner_type', None)
+    if 'timeouts' in device_json:
+      for key in device_json['timeouts']:
+        self._timeouts[key] = device_json['timeouts'][key]
+
+    def command_line_override(
+        file_value, cmd_line_value, desc, print_value=True):
+      if cmd_line_value:
+        if file_value and file_value != cmd_line_value:
+          if print_value:
+            logging.info('Overriding %s from %s to %s',
+                         desc, file_value, cmd_line_value)
+          else:
+            logging.info('overriding %s', desc)
+        return cmd_line_value
+      return file_value
+
+    self._api_address = command_line_override(
+        self._api_address, args.api_address, 'api_address')
+    self._api_port = command_line_override(
+        self._api_port, args.api_port, 'api_port')
+    self._api_protocol = command_line_override(
+        self._api_protocol, args.api_protocol, 'api_protocol')
+    self._device_oem = command_line_override(
+        self._device_oem, args.device_oem, 'device_oem')
+    self._device_type = command_line_override(
+        self._device_type, args.device_type, 'device_type')
+    self._remote_device = command_line_override(
+        self._remote_device, args.remote_device, 'remote_device')
+    self._remote_device_minimum_os = command_line_override(
+        self._remote_device_minimum_os, args.remote_device_minimum_os,
+        'remote_device_minimum_os')
+    self._remote_device_os = command_line_override(
+        self._remote_device_os, args.remote_device_os, 'remote_device_os')
+    self._results_path = command_line_override(
+        self._results_path, args.results_path, 'results_path')
+    self._runner_package = command_line_override(
+        self._runner_package, args.runner_package, 'runner_package')
+    self._runner_type = command_line_override(
+        self._runner_type, args.runner_type, 'runner_type')
+
+    if args.api_key_file:
+      with open(args.api_key_file) as api_key_file:
+        temp_key = api_key_file.read().strip()
+        self._api_key = command_line_override(
+            self._api_key, temp_key, 'api_key', print_value=False)
+    self._api_key = command_line_override(
+        self._api_key, args.api_key, 'api_key', print_value=False)
+
+    if args.api_secret_file:
+      with open(args.api_secret_file) as api_secret_file:
+        temp_secret = api_secret_file.read().strip()
+        self._api_secret = command_line_override(
+            self._api_secret, temp_secret, 'api_secret', print_value=False)
+    self._api_secret = command_line_override(
+        self._api_secret, args.api_secret, 'api_secret', print_value=False)
+
+    if not self._api_address:
+      error_func('Must set api address with --api-address'
+                 ' or in --remote-device-file.')
+    if not self._api_key:
+      error_func('Must set api key with --api-key, --api-key-file'
+                 ' or in --remote-device-file')
+    if not self._api_port:
+      error_func('Must set api port with --api-port'
+                 ' or in --remote-device-file')
+    if not self._api_protocol:
+      error_func('Must set api protocol with --api-protocol'
+                 ' or in --remote-device-file. Example: http')
+    if not self._api_secret:
+      error_func('Must set api secret with --api-secret, --api-secret-file'
+                 ' or in --remote-device-file')
+
+    logging.info('Api address: %s', self._api_address)
+    logging.info('Api port: %s', self._api_port)
+    logging.info('Api protocol: %s', self._api_protocol)
+    logging.info('Remote device: %s', self._remote_device)
+    logging.info('Remote device minimum OS: %s',
+                 self._remote_device_minimum_os)
+    logging.info('Remote device OS: %s', self._remote_device_os)
+    logging.info('Remote device OEM: %s', self._device_oem)
+    logging.info('Remote device type: %s', self._device_type)
+    logging.info('Results Path: %s', self._results_path)
+    logging.info('Runner package: %s', self._runner_package)
+    logging.info('Runner type: %s', self._runner_type)
+    logging.info('Timeouts: %s', self._timeouts)
 
     if not args.trigger and not args.collect:
       self._trigger = True
@@ -150,10 +240,16 @@
     for device in device_list:
       if device['os_name'] != self._device_type:
         continue
-      if self._remote_device and device['name'] != self._remote_device:
+      if self._remote_device and device['name'] not in self._remote_device:
         continue
       if (self._remote_device_os
-          and device['os_version'] != self._remote_device_os):
+          and device['os_version'] not in self._remote_device_os):
+        continue
+      if self._device_oem and device['brand'] not in self._device_oem:
+        continue
+      if (self._remote_device_minimum_os
+          and distutils.version.LooseVersion(device['os_version'])
+          < distutils.version.LooseVersion(self._remote_device_minimum_os)):
         continue
       if ((self._remote_device and self._remote_device_os)
           or device['available_devices_count']):
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 0b2deae..91701b0 100644
--- a/build/android/pylib/remote/device/remote_device_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -49,7 +49,7 @@
     if self._env.trigger:
       self._TriggerSetUp()
     elif self._env.collect:
-      assert isinstance(self._env.trigger, basestring), (
+      assert isinstance(self._env.collect, basestring), (
                         'File for storing test_run_id must be a string.')
       with open(self._env.collect, 'r') as persisted_data_file:
         persisted_data = json.loads(persisted_data_file.read())
diff --git a/build/android/pylib/uirobot/uirobot_test_instance.py b/build/android/pylib/uirobot/uirobot_test_instance.py
index f73c569e6..e3f6eb7 100644
--- a/build/android/pylib/uirobot/uirobot_test_instance.py
+++ b/build/android/pylib/uirobot/uirobot_test_instance.py
@@ -3,6 +3,8 @@
 # found in the LICENSE file.
 
 import os
+import json
+import logging
 
 from pylib import constants
 from pylib.base import test_instance
@@ -20,16 +22,27 @@
     if not args.app_under_test:
       error_func('Must set --app-under-test.')
     self._app_under_test = args.app_under_test
+    self._minutes = args.minutes
 
-    if args.device_type == 'Android':
+    if args.remote_device_file:
+      with open(args.remote_device_file) as remote_device_file:
+        device_json = json.load(remote_device_file)
+    else:
+      device_json = {}
+    device_type = device_json.get('device_type', 'Android')
+    if args.device_type:
+      if device_type and device_type != args.device_type:
+        logging.info('Overriding device_type from %s to %s',
+                     device_type, args.device_type)
+      device_type = args.device_type
+
+    if device_type == 'Android':
       self._suite = 'Android Uirobot'
       self._package_name = apk_helper.GetPackageName(self._app_under_test)
-
-    elif args.device_type == 'iOS':
+    elif device_type == 'iOS':
       self._suite = 'iOS Uirobot'
       self._package_name = self._app_under_test
 
-    self._minutes = args.minutes
 
   #override
   def TestType(self):
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py
index afbee2a..845d093 100644
--- a/build/android/pylib/utils/isolator.py
+++ b/build/android/pylib/utils/isolator.py
@@ -33,8 +33,12 @@
     'fastbuild': '0',
     'icu_use_data_file_flag': '1',
     'lsan': '0',
+    'msan': '0',
     # TODO(maruel): This may not always be true.
     'target_arch': 'arm',
+    'tsan': '0',
+    'use_custom_libcxx': '0',
+    'use_instrumented_libraries': '0',
     'use_openssl': '0',
     'use_ozone': '0',
     'v8_use_external_startup_data': '0',
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index bc0980e..cc7bbee6 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -121,28 +121,40 @@
 def AddRemoteDeviceOptions(parser):
   group = parser.add_argument_group('Remote Device Options')
 
-  group.add_argument('--trigger', default='',
+  group.add_argument('--trigger',
                      help=('Only triggers the test if set. Stores test_run_id '
                            'in given file path. '))
-  group.add_argument('--collect', default='',
+  group.add_argument('--collect',
                      help=('Only collects the test results if set. '
                            'Gets test_run_id from given file path.'))
-  group.add_argument('--remote-device', default='',
+  group.add_argument('--remote-device', action='append',
                      help='Device type to run test on.')
-  group.add_argument('--remote-device-os', default='',
-                     help='OS to have on the device.')
-  group.add_argument('--results-path', default='',
+  group.add_argument('--results-path',
                      help='File path to download results to.')
   group.add_argument('--api-protocol',
                      help='HTTP protocol to use. (http or https)')
-  group.add_argument('--api-address', help='Address to send HTTP requests.')
-  group.add_argument('--api-port', help='Port to send HTTP requests to.')
-  group.add_argument('--runner-type', default='',
+  group.add_argument('--api-address',
+                     help='Address to send HTTP requests.')
+  group.add_argument('--api-port',
+                     help='Port to send HTTP requests to.')
+  group.add_argument('--runner-type',
                      help='Type of test to run as.')
-  group.add_argument('--runner-package', help='Package name of test.')
-  group.add_argument('--device-type', default='Android',
+  group.add_argument('--runner-package',
+                     help='Package name of test.')
+  group.add_argument('--device-type',
                      choices=constants.VALID_DEVICE_TYPES,
                      help=('Type of device to run on. iOS or android'))
+  group.add_argument('--device-oem', action='append',
+                     help='Device OEM to run on.')
+  group.add_argument('--remote-device-file',
+                     help=('File with JSON to select remote device. '
+                           'Overrides all other flags.'))
+
+  device_os_group = group.add_mutually_exclusive_group()
+  device_os_group.add_argument('--remote-device-minimum-os',
+                               help='Minimum OS on device.')
+  device_os_group.add_argument('--remote-device-os', action='append',
+                               help='OS to have on the device.')
 
   api_secret_group = group.add_mutually_exclusive_group()
   api_secret_group.add_argument('--api-secret', default='',
@@ -513,7 +525,8 @@
   """Adds uirobot test options to |option_parser|."""
   group = parser.add_argument_group('Uirobot Test Options')
 
-  group.add_argument('--app-under-test', help='APK to run tests on.')
+  group.add_argument('--app-under-test', required=True,
+                     help='APK to run tests on.')
   group.add_argument(
       '--minutes', default=5, type=int,
       help='Number of minutes to run uirobot test [default: %default].')
diff --git a/build/gyp_chromium b/build/gyp_chromium
index 1112575..3d527aa 100755
--- a/build/gyp_chromium
+++ b/build/gyp_chromium
@@ -7,6 +7,7 @@
 # This script is wrapper for Chromium that adds some support for how GYP
 # is invoked by Chromium beyond what can be done in the gclient hooks.
 
+import argparse
 import glob
 import gyp_environment
 import os
@@ -124,15 +125,10 @@
   env_items = ProcessGypDefinesItems(
       shlex.split(os.environ.get('GYP_DEFINES', '')))
 
-  # GYP defines from the command line. We can't use optparse since we want
-  # to ignore all arguments other than "-D".
-  cmdline_input_items = []
-  for i in range(len(sys.argv))[1:]:
-    if sys.argv[i].startswith('-D'):
-      if sys.argv[i] == '-D' and i + 1 < len(sys.argv):
-        cmdline_input_items += [sys.argv[i + 1]]
-      elif len(sys.argv[i]) > 2:
-        cmdline_input_items += [sys.argv[i][2:]]
+  # 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)
@@ -141,21 +137,21 @@
 
 def GetOutputDirectory():
   """Returns the output directory that GYP will use."""
-  # GYP generator flags from the command line. We can't use optparse since we
-  # want to ignore all arguments other than "-G".
-  needle = '-Goutput_dir='
-  cmdline_input_items = []
-  for item in sys.argv[1:]:
-    if item.startswith(needle):
-      return item[len(needle):]
 
-  env_items = shlex.split(os.environ.get('GYP_GENERATOR_FLAGS', ''))
+  # 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 env_items:
+  for item in genflags:
     if item.startswith(needle):
       return item[len(needle):]
 
-  return "out"
+  return 'out'
 
 
 def additional_include_files(supplemental_files, args=[]):
diff --git a/build/gyp_chromium_test.py b/build/gyp_chromium_test.py
new file mode 100755
index 0000000..0c0e479
--- /dev/null
+++ b/build/gyp_chromium_test.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+import unittest
+
+SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
+SRC_DIR = os.path.dirname(SCRIPT_DIR)
+
+sys.path.append(os.path.join(SRC_DIR, 'third_party', 'pymock'))
+
+import mock
+
+# TODO(sbc): Make gyp_chromium more testable by putting the code in
+# a .py file.
+gyp_chromium = __import__('gyp_chromium')
+
+
+class TestGetOutputDirectory(unittest.TestCase):
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__])
+  def testDefaultValue(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'out')
+
+  @mock.patch('os.environ', {'GYP_GENERATOR_FLAGS': 'output_dir=envfoo'})
+  @mock.patch('sys.argv', [__file__])
+  def testEnvironment(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'envfoo')
+
+  @mock.patch('os.environ', {'GYP_GENERATOR_FLAGS': 'output_dir=envfoo'})
+  @mock.patch('sys.argv', [__file__, '-Goutput_dir=cmdfoo'])
+  def testGFlagOverridesEnv(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'cmdfoo')
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-G', 'output_dir=foo'])
+  def testGFlagWithSpace(self):
+    self.assertEqual(gyp_chromium.GetOutputDirectory(), 'foo')
+
+
+class TestGetGypVars(unittest.TestCase):
+  @mock.patch('os.environ', {})
+  def testDefault(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {})
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-D', 'foo=bar'])
+  def testDFlags(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {'foo': 'bar'})
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-D', 'foo'])
+  def testDFlagsNoValue(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {'foo': '1'})
+
+  @mock.patch('os.environ', {})
+  @mock.patch('sys.argv', [__file__, '-D', 'foo=bar', '-Dbaz'])
+  def testDFlagMulti(self):
+    self.assertEqual(gyp_chromium.GetGypVars([]), {'foo': 'bar', 'baz': '1'})
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/isolate.gypi b/build/isolate.gypi
index e6d2f98..d7070fe 100644
--- a/build/isolate.gypi
+++ b/build/isolate.gypi
@@ -74,24 +74,28 @@
         # the .isolate file but are not considered relative paths.
         '--extra-variable', 'version_full=<(version_full)',
 
-        '--config-variable', 'OS=<(OS)',
         '--config-variable', 'CONFIGURATION_NAME=<(CONFIGURATION_NAME)',
+        '--config-variable', 'OS=<(OS)',
         '--config-variable', 'asan=<(asan)',
         '--config-variable', 'chromeos=<(chromeos)',
         '--config-variable', 'component=<(component)',
+        '--config-variable', 'disable_nacl=<(disable_nacl)',
         '--config-variable', 'fastbuild=<(fastbuild)',
+        '--config-variable', 'icu_use_data_file_flag=<(icu_use_data_file_flag)',
         # TODO(kbr): move this to chrome_tests.gypi:gles2_conform_tests_run
         # once support for user-defined config variables is added.
         '--config-variable',
           'internal_gles2_conform_tests=<(internal_gles2_conform_tests)',
-        '--config-variable', 'icu_use_data_file_flag=<(icu_use_data_file_flag)',
-        '--config-variable', 'v8_use_external_startup_data=<(v8_use_external_startup_data)',
-        '--config-variable', 'lsan=<(lsan)',
         '--config-variable', 'libpeer_target_type=<(libpeer_target_type)',
-        '--config-variable', 'use_openssl=<(use_openssl)',
+        '--config-variable', 'lsan=<(lsan)',
+        '--config-variable', 'msan=<(msan)',
         '--config-variable', 'target_arch=<(target_arch)',
+        '--config-variable', 'tsan=<(tsan)',
+        '--config-variable', 'use_custom_libcxx=<(use_custom_libcxx)',
+        '--config-variable', 'use_instrumented_libraries=<(use_instrumented_libraries)',
+        '--config-variable', 'use_openssl=<(use_openssl)',
         '--config-variable', 'use_ozone=<(use_ozone)',
-        '--config-variable', 'disable_nacl=<(disable_nacl)',
+        '--config-variable', 'v8_use_external_startup_data=<(v8_use_external_startup_data)',
       ],
       'conditions': [
         # Note: When gyp merges lists, it appends them to the old value.
diff --git a/cc/base/synced_property.h b/cc/base/synced_property.h
index 8b554c62..6b02e7a6 100644
--- a/cc/base/synced_property.h
+++ b/cc/base/synced_property.h
@@ -24,7 +24,7 @@
 template <typename T>
 class SyncedProperty : public base::RefCounted<SyncedProperty<T>> {
  public:
-  SyncedProperty() {}
+  SyncedProperty() : clobber_active_value_(false) {}
 
   // Returns the canonical value for the specified tree, including the sum of
   // all deltas.  The pending tree should use this for activation purposes and
@@ -84,6 +84,7 @@
     active_base_ = pending_base_;
     active_delta_ = PendingDelta();
     sent_delta_ = T::Identity();
+    clobber_active_value_ = false;
 
     return true;
   }
@@ -105,7 +106,13 @@
   // The new delta we would use if we decide to activate now.  This delta
   // excludes the amount that we expect the main thread to reflect back at the
   // impl thread during the commit.
-  T PendingDelta() const { return active_delta_.InverseCombine(sent_delta_); }
+  T PendingDelta() const {
+    if (clobber_active_value_)
+      return T::Identity();
+    return active_delta_.InverseCombine(sent_delta_);
+  }
+
+  void set_clobber_active_value() { clobber_active_value_ = true; }
 
  private:
   // Value last committed to the pending tree.
@@ -117,6 +124,9 @@
   // The value sent to the main thread (on the last BeginFrame); this is always
   // identity outside of the BeginFrame-to-activation interval.
   T sent_delta_;
+  // When true the pending delta is always identity so that it does not change
+  // and will clobber the active value on push.
+  bool clobber_active_value_;
 
   friend class base::RefCounted<SyncedProperty<T>>;
   ~SyncedProperty() {}
diff --git a/webkit/common/gpu/context_provider_web_context.h b/cc/blink/context_provider_web_context.h
similarity index 63%
rename from webkit/common/gpu/context_provider_web_context.h
rename to cc/blink/context_provider_web_context.h
index c9c666cd..21d1df3 100644
--- a/webkit/common/gpu/context_provider_web_context.h
+++ b/cc/blink/context_provider_web_context.h
@@ -2,15 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef WEBKIT_COMMON_GPU_CONTEXT_PROVIDER_WEB_CONTEXT_H_
-#define WEBKIT_COMMON_GPU_CONTEXT_PROVIDER_WEB_CONTEXT_H_
+#ifndef CC_BLINK_CONTEXT_PROVIDER_WEB_CONTEXT_H_
+#define CC_BLINK_CONTEXT_PROVIDER_WEB_CONTEXT_H_
 
 #include "cc/output/context_provider.h"
 
 namespace blink { class WebGraphicsContext3D; }
 
-namespace webkit {
-namespace gpu {
+namespace cc_blink {
 
 class ContextProviderWebContext : public cc::ContextProvider {
  public:
@@ -20,7 +19,6 @@
   ~ContextProviderWebContext() override {}
 };
 
-}  // namespace gpu
-}  // namespace webkit
+}  // namespace cc_blink
 
-#endif  // WEBKIT_COMMON_GPU_CONTEXT_PROVIDER_WEB_CONTEXT_H_
+#endif  // CC_BLINK_CONTEXT_PROVIDER_WEB_CONTEXT_H_
diff --git a/cc/cc_unittests.isolate b/cc/cc_unittests.isolate
index 4e5ac92c..5d652d9b0 100644
--- a/cc/cc_unittests.isolate
+++ b/cc/cc_unittests.isolate
@@ -22,6 +22,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -46,6 +48,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '<(PRODUCT_DIR)/ffmpegsumo.so',
@@ -62,6 +66,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '<(PRODUCT_DIR)/ffmpegsumo.dll',
diff --git a/cc/debug/devtools_instrumentation.h b/cc/debug/devtools_instrumentation.h
index cfe3e5a2..73788a52 100644
--- a/cc/debug/devtools_instrumentation.h
+++ b/cc/debug/devtools_instrumentation.h
@@ -6,6 +6,7 @@
 #define CC_DEBUG_DEVTOOLS_INSTRUMENTATION_H_
 
 #include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
 
 namespace cc {
 namespace devtools_instrumentation {
@@ -14,6 +15,7 @@
 const char kCategory[] = TRACE_DISABLED_BY_DEFAULT("devtools.timeline");
 const char kCategoryFrame[] =
     TRACE_DISABLED_BY_DEFAULT("devtools.timeline.frame");
+const char kData[] = "data";
 const char kFrameId[] = "frameId";
 const char kLayerId[] = "layerId";
 const char kLayerTreeId[] = "layerTreeId";
@@ -23,7 +25,9 @@
 const char kBeginFrame[] = "BeginFrame";
 const char kActivateLayerTree[] = "ActivateLayerTree";
 const char kRequestMainThreadFrame[] = "RequestMainThreadFrame";
+const char kBeginMainThreadFrame[] = "BeginMainThreadFrame";
 const char kDrawFrame[] = "DrawFrame";
+const char kCompositeLayers[] = "CompositeLayers";
 }  // namespace internal
 
 const char kPaintSetup[] = "PaintSetup";
@@ -77,6 +81,20 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedLayerTreeTask);
 };
 
+struct ScopedCommitTrace {
+ public:
+  explicit ScopedCommitTrace(int layer_tree_host_id) {
+    TRACE_EVENT_BEGIN1(internal::kCategory, internal::kCompositeLayers,
+                       internal::kLayerTreeId, layer_tree_host_id);
+  }
+  ~ScopedCommitTrace() {
+    TRACE_EVENT_END0(internal::kCategory, internal::kCompositeLayers);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedCommitTrace);
+};
+
 struct ScopedLayerObjectTracker
     : public base::debug::TraceScopedTrackableObject<int> {
   explicit ScopedLayerObjectTracker(int layer_id)
@@ -124,6 +142,21 @@
                        layer_tree_host_id);
 }
 
+inline scoped_refptr<base::debug::ConvertableToTraceFormat>
+BeginMainThreadFrameData(int frame_id) {
+  scoped_refptr<base::debug::TracedValue> value =
+      new base::debug::TracedValue();
+  value->SetInteger("frameId", frame_id);
+  return value;
+}
+
+inline void WillBeginMainThreadFrame(int layer_tree_host_id, int frame_id) {
+  TRACE_EVENT_INSTANT2(
+      internal::kCategoryFrame, internal::kBeginMainThreadFrame,
+      TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, layer_tree_host_id,
+      internal::kData, BeginMainThreadFrameData(frame_id));
+}
+
 }  // namespace devtools_instrumentation
 }  // namespace cc
 
diff --git a/cc/debug/frame_timing_request.h b/cc/debug/frame_timing_request.h
index 7ab97de..0937998 100644
--- a/cc/debug/frame_timing_request.h
+++ b/cc/debug/frame_timing_request.h
@@ -5,6 +5,7 @@
 #ifndef CC_DEBUG_FRAME_TIMING_REQUEST_H_
 #define CC_DEBUG_FRAME_TIMING_REQUEST_H_
 
+#include "cc/base/cc_export.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace cc {
@@ -13,12 +14,15 @@
 // given rect (in layer space) and an associated request id. When this request
 // is propagated to the active LayerImpl, it will cause events to be saved in
 // FrameTimingTracker, which in turn can be consumed by the requester.
-class FrameTimingRequest {
+class CC_EXPORT FrameTimingRequest {
  public:
   FrameTimingRequest();
   FrameTimingRequest(int64_t request_id, const gfx::Rect& rect);
 
+  // Return the ID for the request.
   int64_t id() const { return id_; }
+
+  // Return the layer space rect for this request.
   const gfx::Rect& rect() const { return rect_; }
 
  private:
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index face433..cff75e7 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -978,10 +978,14 @@
     layer->SetClipChildren(nullptr);
   }
 
-  layer->PushScrollOffsetFromMainThread(scroll_offset_);
-  if (layer_animation_controller_->scroll_offset_animation_was_interrupted() &&
-      layer->IsActive())
-    layer->SetScrollDelta(gfx::Vector2dF());
+  // When a scroll offset animation is interrupted the new scroll position on
+  // the pending tree will clobber any impl-side scrolling occuring on the
+  // active tree. To do so, avoid scrolling the pending tree along with it
+  // instead of trying to undo that scrolling later.
+  if (layer_animation_controller_->scroll_offset_animation_was_interrupted())
+    layer->PushScrollOffsetFromMainThreadAndClobberActiveValue(scroll_offset_);
+  else
+    layer->PushScrollOffsetFromMainThread(scroll_offset_);
   layer->SetScrollCompensationAdjustment(ScrollCompensationAdjustment());
 
   // Wrap the copy_requests_ in a PostTask to the main thread.
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 55ffa7f..50501a9 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -1080,6 +1080,12 @@
   PushScrollOffset(&scroll_offset);
 }
 
+void LayerImpl::PushScrollOffsetFromMainThreadAndClobberActiveValue(
+    const gfx::ScrollOffset& scroll_offset) {
+  scroll_offset_->set_clobber_active_value();
+  PushScrollOffset(&scroll_offset);
+}
+
 gfx::ScrollOffset LayerImpl::PullDeltaForMainThread() {
   RefreshFromScrollDelegate();
 
@@ -1140,8 +1146,6 @@
   }
   if (IsActive()) {
     changed |= scroll_offset_->PushPendingToActive();
-    if (layer_animation_controller_->scroll_offset_animation_was_interrupted())
-      SetScrollDelta(gfx::Vector2dF());
   }
 
   if (changed)
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index f46c16e..40e295f 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -399,6 +399,11 @@
 
   void SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset);
   void PushScrollOffsetFromMainThread(const gfx::ScrollOffset& scroll_offset);
+  // This method is similar to PushScrollOffsetFromMainThread but will cause the
+  // scroll offset given to clobber any scroll changes on the active tree in the
+  // time until this value is pushed to the active tree.
+  void PushScrollOffsetFromMainThreadAndClobberActiveValue(
+      const gfx::ScrollOffset& scroll_offset);
   gfx::ScrollOffset PullDeltaForMainThread();
   gfx::ScrollOffset CurrentScrollOffset() const;
   gfx::ScrollOffset BaseScrollOffset() const;
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index 4168253..46c3a7d 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -24,7 +24,7 @@
 gfx::OverlayTransform OverlayCandidate::GetOverlayTransform(
     const gfx::Transform& quad_transform,
     bool flipped) {
-  if (!quad_transform.IsIdentityOrTranslation())
+  if (!quad_transform.IsPositiveScaleOrTranslation())
     return gfx::OVERLAY_TRANSFORM_INVALID;
 
   return flipped ? gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL
@@ -32,9 +32,105 @@
 }
 
 // static
+gfx::OverlayTransform OverlayCandidate::ModifyTransform(
+    gfx::OverlayTransform in,
+    gfx::OverlayTransform delta) {
+  // There are 8 different possible transforms. We can characterize these
+  // by looking at where the origin moves and the direction the horizontal goes.
+  // (TL=top-left, BR=bottom-right, H=horizontal, V=vertical).
+  // NONE: TL, H
+  // FLIP_VERTICAL: BL, H
+  // FLIP_HORIZONTAL: TR, H
+  // ROTATE_90: TR, V
+  // ROTATE_180: BR, H
+  // ROTATE_270: BL, V
+  // Missing transforms: TL, V & BR, V
+  // Basic combinations:
+  // Flip X & Y -> Rotate 180 (TL,H -> TR,H -> BR,H or TL,H -> BL,H -> BR,H)
+  // Flip X or Y + Rotate 180 -> other flip (eg, TL,H -> TR,H -> BL,H)
+  // Rotate + Rotate simply adds values.
+  // Rotate 90/270 + flip is invalid because we can only have verticals with
+  // the origin in TR or BL.
+  if (delta == gfx::OVERLAY_TRANSFORM_NONE)
+    return in;
+  switch (in) {
+    case gfx::OVERLAY_TRANSFORM_NONE:
+      return delta;
+    case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+      switch (delta) {
+        case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+          return gfx::OVERLAY_TRANSFORM_NONE;
+        case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+          return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+        default:
+          return gfx::OVERLAY_TRANSFORM_INVALID;
+      }
+      break;
+    case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+      switch (delta) {
+        case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+          return gfx::OVERLAY_TRANSFORM_NONE;
+        case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+        case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+          return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+        default:
+          return gfx::OVERLAY_TRANSFORM_INVALID;
+      }
+      break;
+    case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+      switch (delta) {
+        case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+          return gfx::OVERLAY_TRANSFORM_NONE;
+        default:
+          return gfx::OVERLAY_TRANSFORM_INVALID;
+      }
+      break;
+    case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+      switch (delta) {
+        case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+          return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+        case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+          return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+          return gfx::OVERLAY_TRANSFORM_NONE;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+        default:
+          return gfx::OVERLAY_TRANSFORM_INVALID;
+      }
+      break;
+    case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+      switch (delta) {
+        case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+          return gfx::OVERLAY_TRANSFORM_NONE;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+        case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+          return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+        default:
+          return gfx::OVERLAY_TRANSFORM_INVALID;
+      }
+      break;
+    default:
+      return gfx::OVERLAY_TRANSFORM_INVALID;
+  }
+}
+
+// static
 gfx::Rect OverlayCandidate::GetOverlayRect(const gfx::Transform& quad_transform,
                                            const gfx::Rect& rect) {
-  DCHECK(quad_transform.IsIdentityOrTranslation());
+  DCHECK(quad_transform.IsPositiveScaleOrTranslation());
 
   gfx::RectF float_rect(rect);
   quad_transform.TransformRect(&float_rect);
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index 9a1e534e..28ae8cb7 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -20,6 +20,10 @@
   static gfx::OverlayTransform GetOverlayTransform(
       const gfx::Transform& quad_transform,
       bool flipped);
+  // Apply transform |delta| to |in| and return the resulting transform,
+  // or OVERLAY_TRANSFORM_INVALID.
+  static gfx::OverlayTransform ModifyTransform(gfx::OverlayTransform in,
+                                               gfx::OverlayTransform delta);
   static gfx::Rect GetOverlayRect(const gfx::Transform& quad_transform,
                                   const gfx::Rect& rect);
 
diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc
index 98d77ad4..9a95206 100644
--- a/cc/output/overlay_strategy_single_on_top.cc
+++ b/cc/output/overlay_strategy_single_on_top.cc
@@ -4,8 +4,13 @@
 
 #include "cc/output/overlay_strategy_single_on_top.h"
 
+#include <limits>
+
 #include "cc/quads/draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/stream_video_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
+#include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/transform.h"
 
@@ -17,6 +22,103 @@
     : capability_checker_(capability_checker),
       resource_provider_(resource_provider) {}
 
+bool OverlayStrategySingleOnTop::IsOverlayQuad(const DrawQuad* draw_quad) {
+  unsigned int resource_id;
+  switch (draw_quad->material) {
+    case DrawQuad::TEXTURE_CONTENT:
+      resource_id = TextureDrawQuad::MaterialCast(draw_quad)->resource_id;
+      break;
+    case DrawQuad::STREAM_VIDEO_CONTENT:
+      resource_id = StreamVideoDrawQuad::MaterialCast(draw_quad)->resource_id;
+      break;
+    default:
+      return false;
+  }
+  return resource_provider_->AllowOverlay(resource_id);
+}
+
+bool OverlayStrategySingleOnTop::GetTextureQuadInfo(
+    const TextureDrawQuad& quad,
+    OverlayCandidate* quad_info) {
+  gfx::OverlayTransform overlay_transform =
+      OverlayCandidate::GetOverlayTransform(quad.quadTransform(), quad.flipped);
+  if (quad.background_color != SK_ColorTRANSPARENT ||
+      quad.premultiplied_alpha ||
+      overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
+    return false;
+  quad_info->resource_id = quad.resource_id;
+  quad_info->transform = overlay_transform;
+  quad_info->uv_rect = BoundingRect(quad.uv_top_left, quad.uv_bottom_right);
+  return true;
+}
+
+bool OverlayStrategySingleOnTop::GetVideoQuadInfo(
+    const StreamVideoDrawQuad& quad,
+    OverlayCandidate* quad_info) {
+  gfx::OverlayTransform overlay_transform =
+      OverlayCandidate::GetOverlayTransform(quad.quadTransform(), false);
+  if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
+    return false;
+  if (!quad.matrix.IsScaleOrTranslation()) {
+    // We cannot handle anything other than scaling & translation for texture
+    // coordinates yet.
+    return false;
+  }
+  quad_info->resource_id = quad.resource_id;
+  quad_info->transform = overlay_transform;
+
+  gfx::Point3F uv0 = gfx::Point3F(0, 0, 0);
+  gfx::Point3F uv1 = gfx::Point3F(1, 1, 0);
+  quad.matrix.TransformPoint(&uv0);
+  quad.matrix.TransformPoint(&uv1);
+  gfx::Vector3dF delta = uv1 - uv0;
+  if (delta.x() < 0) {
+    quad_info->transform = OverlayCandidate::ModifyTransform(
+        quad_info->transform, gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL);
+    float x0 = uv0.x();
+    uv0.set_x(uv1.x());
+    uv1.set_x(x0);
+    delta.set_x(-delta.x());
+  }
+
+  if (delta.y() < 0) {
+    // In this situation, uv0y < uv1y. Since we overlay inverted, a request
+    // to invert the source texture means we can just output the texture
+    // normally and it will be correct.
+    quad_info->uv_rect = gfx::RectF(uv0.x(), uv1.y(), delta.x(), -delta.y());
+  } else {
+    quad_info->transform = OverlayCandidate::ModifyTransform(
+        quad_info->transform, gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL);
+    quad_info->uv_rect = gfx::RectF(uv0.x(), uv0.y(), delta.x(), delta.y());
+  }
+  return true;
+}
+
+bool OverlayStrategySingleOnTop::GetCandidateQuadInfo(
+    const DrawQuad& draw_quad,
+    OverlayCandidate* quad_info) {
+  // All quad checks.
+  if (draw_quad.needs_blending || draw_quad.shared_quad_state->opacity != 1.f ||
+      draw_quad.shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode)
+    return false;
+
+  if (draw_quad.material == DrawQuad::TEXTURE_CONTENT) {
+    const TextureDrawQuad& quad = *TextureDrawQuad::MaterialCast(&draw_quad);
+    if (!GetTextureQuadInfo(quad, quad_info))
+      return false;
+  } else if (draw_quad.material == DrawQuad::STREAM_VIDEO_CONTENT) {
+    const StreamVideoDrawQuad& quad =
+        *StreamVideoDrawQuad::MaterialCast(&draw_quad);
+    if (!GetVideoQuadInfo(quad, quad_info))
+      return false;
+  }
+
+  quad_info->format = RGBA_8888;
+  quad_info->display_rect = OverlayCandidate::GetOverlayRect(
+      draw_quad.quadTransform(), draw_quad.rect);
+  return true;
+}
+
 bool OverlayStrategySingleOnTop::Attempt(
     RenderPassList* render_passes_in_draw_order,
     OverlayCandidateList* candidate_list) {
@@ -27,15 +129,12 @@
   RenderPass* root_render_pass = render_passes_in_draw_order->back();
   DCHECK(root_render_pass);
 
+  OverlayCandidate candidate;
   QuadList& quad_list = root_render_pass->quad_list;
   auto candidate_iterator = quad_list.end();
   for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
     const DrawQuad* draw_quad = *it;
-    if (draw_quad->material == DrawQuad::TEXTURE_CONTENT) {
-      const TextureDrawQuad& quad = *TextureDrawQuad::MaterialCast(draw_quad);
-      if (!resource_provider_->AllowOverlay(quad.resource_id)) {
-        continue;
-      }
+    if (IsOverlayQuad(draw_quad)) {
       // Check that no prior quads overlap it.
       bool intersects = false;
       gfx::RectF rect = draw_quad->rect;
@@ -49,7 +148,7 @@
           break;
         }
       }
-      if (intersects)
+      if (intersects || !GetCandidateQuadInfo(*draw_quad, &candidate))
         continue;
       candidate_iterator = it;
       break;
@@ -57,34 +156,14 @@
   }
   if (candidate_iterator == quad_list.end())
     return false;
-  const TextureDrawQuad& quad =
-      *TextureDrawQuad::MaterialCast(*candidate_iterator);
-
-  // Simple quads only.
-  gfx::OverlayTransform overlay_transform =
-      OverlayCandidate::GetOverlayTransform(quad.quadTransform(), quad.flipped);
-  if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID ||
-      !quad.quadTransform().IsIdentityOrTranslation() || quad.needs_blending ||
-      quad.shared_quad_state->opacity != 1.f ||
-      quad.shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode ||
-      quad.premultiplied_alpha || quad.background_color != SK_ColorTRANSPARENT)
-    return false;
 
   // Add our primary surface.
   OverlayCandidateList candidates;
   OverlayCandidate main_image;
   main_image.display_rect = root_render_pass->output_rect;
-  main_image.format = RGBA_8888;
   candidates.push_back(main_image);
 
   // Add the overlay.
-  OverlayCandidate candidate;
-  candidate.transform = overlay_transform;
-  candidate.display_rect =
-      OverlayCandidate::GetOverlayRect(quad.quadTransform(), quad.rect);
-  candidate.uv_rect = BoundingRect(quad.uv_top_left, quad.uv_bottom_right);
-  candidate.format = RGBA_8888;
-  candidate.resource_id = quad.resource_id;
   candidate.plane_z_order = 1;
   candidates.push_back(candidate);
 
diff --git a/cc/output/overlay_strategy_single_on_top.h b/cc/output/overlay_strategy_single_on_top.h
index e5518cc..f92e104 100644
--- a/cc/output/overlay_strategy_single_on_top.h
+++ b/cc/output/overlay_strategy_single_on_top.h
@@ -14,6 +14,8 @@
 
 namespace cc {
 class OverlayCandidateValidator;
+class StreamVideoDrawQuad;
+class TextureDrawQuad;
 
 class CC_EXPORT OverlayStrategySingleOnTop : public OverlayProcessor::Strategy {
  public:
@@ -23,6 +25,15 @@
                OverlayCandidateList* candidate_list) override;
 
  private:
+  bool IsOverlayQuad(const DrawQuad* draw_quad);
+  bool GetCandidateQuadInfo(const DrawQuad& draw_quad,
+                            OverlayCandidate* quad_info);
+
+  bool GetTextureQuadInfo(const TextureDrawQuad& quad,
+                          OverlayCandidate* quad_info);
+  bool GetVideoQuadInfo(const StreamVideoDrawQuad& quad,
+                        OverlayCandidate* quad_info);
+
   OverlayCandidateValidator* capability_checker_;
   ResourceProvider* resource_provider_;
   DISALLOW_COPY_AND_ASSIGN(OverlayStrategySingleOnTop);
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 8fa35cb..4682679 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -11,6 +11,7 @@
 #include "cc/output/overlay_strategy_single_on_top.h"
 #include "cc/quads/checkerboard_draw_quad.h"
 #include "cc/quads/render_pass.h"
+#include "cc/quads/stream_video_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/resources/resource_provider.h"
 #include "cc/resources/texture_mailbox.h"
@@ -32,6 +33,16 @@
 const gfx::Rect kOverlayBottomRightRect(64, 64, 64, 64);
 const gfx::PointF kUVTopLeft(0.1f, 0.2f);
 const gfx::PointF kUVBottomRight(1.0f, 1.0f);
+const gfx::Transform kNormalTransform =
+    gfx::Transform(0.9f, 0, 0, 0.8f, 0.1f, 0.2f);  // x,y -> x,y.
+const gfx::Transform kXMirrorTransform =
+    gfx::Transform(-0.9f, 0, 0, 0.8f, 1.0f, 0.2f);  // x,y -> 1-x,y.
+const gfx::Transform kYMirrorTransform =
+    gfx::Transform(0.9f, 0, 0, -0.8f, 0.1f, 1.0f);  // x,y -> x,1-y.
+const gfx::Transform kBothMirrorTransform =
+    gfx::Transform(-0.9f, 0, 0, -0.8f, 1.0f, 1.0f);  // x,y -> 1-x,1-y.
+const gfx::Transform kSwapTransform =
+    gfx::Transform(0, 1, 1, 0, 0, 0);  // x,y -> y,x.
 
 void MailboxReleased(unsigned sync_point,
                      bool lost_resource,
@@ -173,6 +184,22 @@
   return overlay_quad;
 }
 
+StreamVideoDrawQuad* CreateCandidateVideoQuadAt(
+    ResourceProvider* resource_provider,
+    const SharedQuadState* shared_quad_state,
+    RenderPass* render_pass,
+    const gfx::Rect& rect,
+    const gfx::Transform& transform) {
+  ResourceProvider::ResourceId resource_id = CreateResource(resource_provider);
+
+  StreamVideoDrawQuad* overlay_quad =
+      render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
+  overlay_quad->SetNew(shared_quad_state, rect, rect, rect, resource_id,
+                       transform);
+
+  return overlay_quad;
+}
+
 TextureDrawQuad* CreateFullscreenCandidateQuad(
     ResourceProvider* resource_provider,
     const SharedQuadState* shared_quad_state,
@@ -181,6 +208,15 @@
       resource_provider, shared_quad_state, render_pass, kOverlayRect);
 }
 
+StreamVideoDrawQuad* CreateFullscreenCandidateVideoQuad(
+    ResourceProvider* resource_provider,
+    const SharedQuadState* shared_quad_state,
+    RenderPass* render_pass,
+    const gfx::Transform& transform) {
+  return CreateCandidateVideoQuadAt(resource_provider, shared_quad_state,
+                                    render_pass, kOverlayRect, transform);
+}
+
 void CreateCheckeredQuadAt(ResourceProvider* resource_provider,
                            const SharedQuadState* shared_quad_state,
                            RenderPass* render_pass,
@@ -484,13 +520,13 @@
   EXPECT_EQ(0U, candidate_list.size());
 }
 
-TEST_F(SingleOverlayOnTopTest, RejectTransform) {
+TEST_F(SingleOverlayOnTopTest, RejectNonScaleTransform) {
   scoped_ptr<RenderPass> pass = CreateRenderPass();
   CreateFullscreenCandidateQuad(resource_provider_.get(),
                                 pass->shared_quad_state_list.back(),
                                 pass.get());
-  pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.f,
-                                                                         2.f);
+  pass->shared_quad_state_list.back()
+      ->content_to_target_transform.RotateAboutXAxis(45.f);
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
@@ -500,6 +536,39 @@
   EXPECT_EQ(0U, candidate_list.size());
 }
 
+TEST_F(SingleOverlayOnTopTest, RejectNegativeScaleTransform) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateFullscreenCandidateQuad(resource_provider_.get(),
+                                pass->shared_quad_state_list.back(),
+                                pass.get());
+  pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.0f,
+                                                                         -1.0f);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  ASSERT_EQ(1U, pass_list.size());
+  EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) {
+  gfx::Rect rect = kOverlayRect;
+  rect.set_width(rect.width() / 2);
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateCandidateQuadAt(resource_provider_.get(),
+                        pass->shared_quad_state_list.back(), pass.get(), rect);
+  pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.0f,
+                                                                         1.0f);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  ASSERT_EQ(1U, pass_list.size());
+  EXPECT_EQ(2U, candidate_list.size());
+}
+
 TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
   scoped_ptr<RenderPass> pass = CreateRenderPass();
   CreateCheckeredQuadAt(resource_provider_.get(),
@@ -523,6 +592,76 @@
   EXPECT_EQ(2U, candidate_list.size());
 }
 
+TEST_F(SingleOverlayOnTopTest, RejectVideoSwapTransform) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+                                     pass->shared_quad_state_list.back(),
+                                     pass.get(), kSwapTransform);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  ASSERT_EQ(1U, pass_list.size());
+  EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoXMirrorTransform) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+                                     pass->shared_quad_state_list.back(),
+                                     pass.get(), kXMirrorTransform);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  ASSERT_EQ(1U, pass_list.size());
+  EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoBothMirrorTransform) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+                                     pass->shared_quad_state_list.back(),
+                                     pass.get(), kBothMirrorTransform);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  ASSERT_EQ(1U, pass_list.size());
+  EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoNormalTransform) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+                                     pass->shared_quad_state_list.back(),
+                                     pass.get(), kNormalTransform);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  ASSERT_EQ(1U, pass_list.size());
+  EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+                                     pass->shared_quad_state_list.back(),
+                                     pass.get(), kYMirrorTransform);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  ASSERT_EQ(1U, pass_list.size());
+  EXPECT_EQ(2U, candidate_list.size());
+}
+
 class OverlayInfoRendererGL : public GLRenderer {
  public:
   OverlayInfoRendererGL(RendererClient* client,
diff --git a/cc/resources/gpu_rasterizer.cc b/cc/resources/gpu_rasterizer.cc
index 3fdc8bb..369f12cf 100644
--- a/cc/resources/gpu_rasterizer.cc
+++ b/cc/resources/gpu_rasterizer.cc
@@ -31,22 +31,22 @@
     ContextProvider* context_provider,
     ResourceProvider* resource_provider,
     bool use_distance_field_text,
-    bool tile_prepare_enabled,
+    bool threaded_gpu_rasterization_enabled,
     int msaa_sample_count) {
   return make_scoped_ptr<GpuRasterizer>(new GpuRasterizer(
       context_provider, resource_provider, use_distance_field_text,
-      tile_prepare_enabled, msaa_sample_count));
+      threaded_gpu_rasterization_enabled, msaa_sample_count));
 }
 
 GpuRasterizer::GpuRasterizer(ContextProvider* context_provider,
                              ResourceProvider* resource_provider,
                              bool use_distance_field_text,
-                             bool tile_prepare_enabled,
+                             bool threaded_gpu_rasterization_enabled,
                              int msaa_sample_count)
     : context_provider_(context_provider),
       resource_provider_(resource_provider),
       use_distance_field_text_(use_distance_field_text),
-      tile_prepare_enabled_(tile_prepare_enabled),
+      threaded_gpu_rasterization_enabled_(threaded_gpu_rasterization_enabled),
       msaa_sample_count_(msaa_sample_count) {
   DCHECK(context_provider_);
 }
@@ -55,8 +55,7 @@
 }
 
 PrepareTilesMode GpuRasterizer::GetPrepareTilesMode() {
-  return tile_prepare_enabled_ ? PrepareTilesMode::PREPARE_PRIORITIZED_TILES
-                               : PrepareTilesMode::PREPARE_NONE;
+  return PrepareTilesMode::PREPARE_NONE;
 }
 
 void GpuRasterizer::RasterizeTiles(
diff --git a/cc/resources/gpu_rasterizer.h b/cc/resources/gpu_rasterizer.h
index 206b051d..79a05969 100644
--- a/cc/resources/gpu_rasterizer.h
+++ b/cc/resources/gpu_rasterizer.h
@@ -22,11 +22,12 @@
  public:
   ~GpuRasterizer() override;
 
-  static scoped_ptr<GpuRasterizer> Create(ContextProvider* context_provider,
-                                          ResourceProvider* resource_provider,
-                                          bool use_distance_field_text,
-                                          bool tile_prepare_enabled,
-                                          int msaa_sample_count);
+  static scoped_ptr<GpuRasterizer> Create(
+      ContextProvider* context_provider,
+      ResourceProvider* resource_provider,
+      bool use_distance_field_text,
+      bool threaded_gpu_rasterization_enabled,
+      int msaa_sample_count);
   PrepareTilesMode GetPrepareTilesMode() override;
   void RasterizeTiles(
       const TileVector& tiles,
@@ -38,7 +39,7 @@
   GpuRasterizer(ContextProvider* context_provider,
                 ResourceProvider* resource_provider,
                 bool use_distance_filed_text,
-                bool tile_prepare_enabled,
+                bool threaded_gpu_rasterization_enabled,
                 int msaa_sample_count);
 
   using ScopedResourceWriteLocks =
@@ -55,7 +56,7 @@
   SkMultiPictureDraw multi_picture_draw_;
 
   bool use_distance_field_text_;
-  bool tile_prepare_enabled_;
+  bool threaded_gpu_rasterization_enabled_;
   int msaa_sample_count_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuRasterizer);
diff --git a/cc/resources/rasterizer.h b/cc/resources/rasterizer.h
index 95b9ce2..43df0b0 100644
--- a/cc/resources/rasterizer.h
+++ b/cc/resources/rasterizer.h
@@ -16,7 +16,6 @@
 
 enum class PrepareTilesMode {
   RASTERIZE_PRIORITIZED_TILES,
-  PREPARE_PRIORITIZED_TILES,
   PREPARE_NONE
 };
 
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index c245bd63..9b200e9 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -414,11 +414,10 @@
   }
 }
 
-void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) {
-  DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetNeedsBeginFrames",
-               "active_source",
-               active_source_,
-               "needs_begin_frames",
+void BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange(
+    bool needs_begin_frames) {
+  DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange",
+               "active_source", active_source_, "needs_begin_frames",
                needs_begin_frames);
   if (active_source_) {
     active_source_->SetNeedsBeginFrames(needs_begin_frames);
diff --git a/cc/scheduler/begin_frame_source.h b/cc/scheduler/begin_frame_source.h
index 299db8e3..1612a286 100644
--- a/cc/scheduler/begin_frame_source.h
+++ b/cc/scheduler/begin_frame_source.h
@@ -138,7 +138,7 @@
 
   // BeginFrameSource
   bool NeedsBeginFrames() const override;
-  void SetNeedsBeginFrames(bool needs_begin_frames) override;
+  void SetNeedsBeginFrames(bool needs_begin_frames) final;
   void DidFinishFrame(size_t remaining_frames) override {}
   void AddObserver(BeginFrameObserver* obs) final;
   void RemoveObserver(BeginFrameObserver* obs) final;
@@ -261,9 +261,11 @@
 
   // BeginFrameSource
   bool NeedsBeginFrames() const override;
-  void SetNeedsBeginFrames(bool needs_begin_frames) override;
   void DidFinishFrame(size_t remaining_frames) override;
 
+  // BeginFrameSourceMixIn
+  void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
+
   // Tracing
   void AsValueInto(base::debug::TracedValue* dict) const override;
 
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index aa153c6..5b7f6b7 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -282,7 +282,6 @@
 
   bool ShouldAnimate() const;
   bool ShouldBeginOutputSurfaceCreation() const;
-  bool ShouldDrawForced() const;
   bool ShouldDraw() const;
   bool ShouldActivatePendingTree() const;
   bool ShouldSendBeginMainFrame() const;
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index 25f3114..065aa38 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -46,7 +46,11 @@
   current_frame_ = frame.Pass();
   factory_->ReceiveFromChild(
       current_frame_->delegated_frame_data->resource_list);
-  ++frame_index_;
+  // Empty frames shouldn't be drawn and shouldn't contribute damage, so don't
+  // increment frame index for them.
+  if (!current_frame_ ||
+      !current_frame_->delegated_frame_data->render_pass_list.empty())
+    ++frame_index_;
 
   if (previous_frame) {
     ReturnedResourceArray previous_resources;
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index ed6763d1..068fe03 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -25,6 +25,9 @@
   capabilities_.delegated_rendering = true;
   capabilities_.max_frames_pending = 1;
   capabilities_.can_force_reclaim_resources = true;
+  // Frame always needs to be swapped because forced resource reclaiming
+  // destroys the Display's copy.
+  capabilities_.draw_and_swap_full_viewport_every_frame = true;
 }
 
 SurfaceDisplayOutputSurface::~SurfaceDisplayOutputSurface() {
diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc
index b5c2a63..b9c6bf5 100644
--- a/cc/surfaces/surface_factory_unittest.cc
+++ b/cc/surfaces/surface_factory_unittest.cc
@@ -360,6 +360,21 @@
   }
 }
 
+TEST_F(SurfaceFactoryTest, BlankNoIndexIncrement) {
+  SurfaceId surface_id(6);
+  factory_.Create(surface_id);
+  Surface* surface = manager_.GetSurfaceForId(surface_id);
+  ASSERT_NE(nullptr, surface);
+  EXPECT_EQ(2, surface->frame_index());
+  scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+  frame->delegated_frame_data.reset(new DelegatedFrameData);
+
+  factory_.SubmitFrame(surface_id, frame.Pass(),
+                       SurfaceFactory::DrawCallback());
+  EXPECT_EQ(2, surface->frame_index());
+  factory_.Destroy(surface_id);
+}
+
 void DrawCallback(uint32* execute_count,
                   SurfaceDrawStatus* result,
                   SurfaceDrawStatus drawn) {
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index 5f7afa5..8fcafdb7 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -30,7 +30,7 @@
   void SetLayerTreeHost(LayerTreeHost* host) { host_ = host; }
 
   // LayerTreeHostClient implementation.
-  void WillBeginMainFrame(int frame_id) override {}
+  void WillBeginMainFrame() override {}
   void DidBeginMainFrame() override {}
   void BeginMainFrame(const BeginFrameArgs& args) override {}
   void Layout() override {}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index d02b5104..5f69c354 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -381,9 +381,7 @@
   }
   ~LayerTreeHostClientForTesting() override {}
 
-  void WillBeginMainFrame(int frame_id) override {
-    test_hooks_->WillBeginMainFrame();
-  }
+  void WillBeginMainFrame() override { test_hooks_->WillBeginMainFrame(); }
 
   void DidBeginMainFrame() override { test_hooks_->DidBeginMainFrame(); }
 
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 0f48cb20..2567122 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -222,6 +222,12 @@
     contents_texture_manager_->ClearAllMemory(resource_provider);
 }
 
+void LayerTreeHost::WillBeginMainFrame() {
+  devtools_instrumentation::WillBeginMainThreadFrame(id(),
+                                                     source_frame_number());
+  client_->WillBeginMainFrame();
+}
+
 void LayerTreeHost::DidBeginMainFrame() {
   client_->DidBeginMainFrame();
 }
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 7db722f6..f41e023 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -110,9 +110,7 @@
   void SetLayerTreeHostClientReady();
 
   // LayerTreeHost interface to Proxy.
-  void WillBeginMainFrame() {
-    client_->WillBeginMainFrame(source_frame_number_);
-  }
+  void WillBeginMainFrame();
   void DidBeginMainFrame();
   void BeginMainFrame(const BeginFrameArgs& args);
   void AnimateLayers(base::TimeTicks monotonic_frame_begin_time);
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index ac025f2..a712534 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -22,7 +22,7 @@
 
 class LayerTreeHostClient {
  public:
-  virtual void WillBeginMainFrame(int frame_id) = 0;
+  virtual void WillBeginMainFrame() = 0;
   // Marks finishing compositing-related tasks on the main thread. In threaded
   // mode, this corresponds to DidCommit().
   virtual void BeginMainFrame(const BeginFrameArgs& args) = 0;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 398ef81..53eb58b 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -229,7 +229,8 @@
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       id_(id),
       requires_high_res_to_draw_(false),
-      is_likely_to_require_a_draw_(false) {
+      is_likely_to_require_a_draw_(false),
+      frame_timing_tracker_(FrameTimingTracker::Create()) {
   DCHECK(proxy_->IsImplThread());
   DidVisibilityChange(this, visible_);
   animation_registrar_->set_supports_scroll_animations(
@@ -674,6 +675,7 @@
   if (root_surface_has_contributing_layers &&
       root_surface_has_no_visible_damage &&
       active_tree_->LayersWithCopyOutputRequest().empty() &&
+      !output_surface_->capabilities().can_force_reclaim_resources &&
       !hud_wants_to_draw_) {
     TRACE_EVENT0("cc",
                  "LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect");
@@ -813,6 +815,18 @@
                             *it,
                             occlusion_tracker,
                             &append_quads_data);
+
+        // For layers that represent themselves, add composite frame timing
+        // requests if the visible rect intersects the requested rect.
+        for (const auto& request : it->frame_timing_requests()) {
+          const gfx::Rect& request_content_rect =
+              it->LayerRectToContentRect(request.rect());
+          if (request_content_rect.Intersects(it->visible_content_rect())) {
+            frame->composite_events.push_back(
+                FrameTimingTracker::FrameAndRectIds(
+                    active_tree_->source_frame_number(), request.id()));
+          }
+        }
       }
 
       ++layers_drawn;
@@ -1438,6 +1452,11 @@
   TRACE_EVENT0("cc", "LayerTreeHostImpl::DrawLayers");
   DCHECK(CanDraw());
 
+  if (!frame->composite_events.empty()) {
+    frame_timing_tracker_->SaveTimeStamps(frame_begin_time,
+                                          frame->composite_events);
+  }
+
   if (frame->has_no_damage) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoDamage", TRACE_EVENT_SCOPE_THREAD);
     DCHECK(!output_surface_->capabilities()
@@ -1959,7 +1978,8 @@
   ContextProvider* context_provider = output_surface_->context_provider();
   if (use_gpu_rasterization_ && context_provider) {
     return GpuRasterizer::Create(context_provider, resource_provider_.get(),
-                                 settings_.use_distance_field_text, false,
+                                 settings_.use_distance_field_text,
+                                 settings_.threaded_gpu_rasterization_enabled,
                                  settings_.gpu_rasterization_msaa_sample_count);
   }
   return SoftwareRasterizer::Create();
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index eb84c54..f9cf55c6 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -18,6 +18,7 @@
 #include "cc/animation/scrollbar_animation_controller.h"
 #include "cc/base/cc_export.h"
 #include "cc/base/synced_property.h"
+#include "cc/debug/frame_timing_tracker.h"
 #include "cc/debug/micro_benchmark_controller_impl.h"
 #include "cc/input/input_handler.h"
 #include "cc/input/layer_scroll_offset_delegate.h"
@@ -185,6 +186,7 @@
 
     std::vector<gfx::Rect> occluding_screen_space_rects;
     std::vector<gfx::Rect> non_occluding_screen_space_rects;
+    std::vector<FrameTimingTracker::FrameAndRectIds> composite_events;
     RenderPassList render_passes;
     RenderPassIdHashMap render_passes_by_id;
     const LayerImplList* render_surface_layer_list;
@@ -514,6 +516,10 @@
 
   bool prepare_tiles_needed() const { return tile_priorities_dirty_; }
 
+  FrameTimingTracker* frame_timing_tracker() {
+    return frame_timing_tracker_.get();
+  }
+
  protected:
   LayerTreeHostImpl(
       const LayerTreeSettings& settings,
@@ -732,6 +738,8 @@
   bool requires_high_res_to_draw_;
   bool is_likely_to_require_a_draw_;
 
+  scoped_ptr<FrameTimingTracker> frame_timing_tracker_;
+
   DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
 };
 
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index a3c37ed..35828e3f 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -2068,7 +2068,7 @@
   }
 
   void AfterTest() override {
-    EXPECT_GE(3, num_will_begin_impl_frame_);
+    EXPECT_GE(num_will_begin_impl_frame_, 3);
     EXPECT_EQ(2, num_send_begin_main_frame_);
   }
 
@@ -6120,6 +6120,73 @@
 
 MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestOneActivatePerPrepareTiles);
 
+class LayerTreeHostTestFrameTimingRequestsSaveTimestamps
+    : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestFrameTimingRequestsSaveTimestamps()
+      : check_results_on_commit_(false) {}
+
+  void SetupTree() override {
+    scoped_refptr<FakePictureLayer> root_layer =
+        FakePictureLayer::Create(&client_);
+    root_layer->SetBounds(gfx::Size(200, 200));
+    root_layer->SetIsDrawable(true);
+
+    scoped_refptr<FakePictureLayer> child_layer =
+        FakePictureLayer::Create(&client_);
+    child_layer->SetBounds(gfx::Size(1500, 1500));
+    child_layer->SetIsDrawable(true);
+
+    std::vector<FrameTimingRequest> requests;
+    requests.push_back(FrameTimingRequest(1, gfx::Rect(0, 0, 100, 100)));
+    requests.push_back(FrameTimingRequest(2, gfx::Rect(300, 0, 100, 100)));
+    child_layer->SetFrameTimingRequests(requests);
+
+    root_layer->AddChild(child_layer);
+    layer_tree_host()->SetRootLayer(root_layer);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
+    if (!check_results_on_commit_)
+      return;
+
+    // Since in reality, the events will be read by LayerTreeHost during commit,
+    // we check the requests here to ensure that they are correct at the next
+    // commit time (as opposed to checking in DrawLayers for instance).
+    // TODO(vmpstr): Change this to read things from the main thread when this
+    // information is propagated to the main thread (not yet implemented).
+    FrameTimingTracker* tracker = host_impl->frame_timing_tracker();
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> timing_set =
+        tracker->GroupCountsByRectId();
+    EXPECT_EQ(1u, timing_set->size());
+    auto rect_1_it = timing_set->find(1);
+    EXPECT_TRUE(rect_1_it != timing_set->end());
+    const auto& timing_events = rect_1_it->second;
+    EXPECT_EQ(1u, timing_events.size());
+    EXPECT_EQ(host_impl->active_tree()->source_frame_number(),
+              timing_events[0].frame_id);
+    EXPECT_GT(timing_events[0].timestamp, base::TimeTicks());
+
+    EndTest();
+  }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    check_results_on_commit_ = true;
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void AfterTest() override {}
+
+ private:
+  FakeContentLayerClient client_;
+  bool check_results_on_commit_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestFrameTimingRequestsSaveTimestamps);
+
 class LayerTreeHostTestActivationCausesPrepareTiles : public LayerTreeHostTest {
  public:
   LayerTreeHostTestActivationCausesPrepareTiles()
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index bbdfe6b..e36f6a0 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -1096,13 +1096,21 @@
     host_impl->BlockNotifyReadyToActivateForTesting(false);
   }
 
+  void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    if (!host_impl->settings().impl_side_painting)
+      return;
+    if (host_impl->pending_tree()->source_frame_number() != 1)
+      return;
+    LayerImpl* scroll_layer_impl =
+        host_impl->pending_tree()->root_layer()->children()[0];
+    EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset());
+  }
+
   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    if (host_impl->active_tree()->source_frame_number() != 1)
+      return;
     LayerImpl* scroll_layer_impl =
         host_impl->active_tree()->root_layer()->children()[0];
-    if (scroll_layer_impl->layer_animation_controller()->GetAnimation(
-            Animation::ScrollOffset))
-      return;
-
     EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset());
     EndTest();
   }
diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
index 75eda92..260bfbe 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -54,7 +54,7 @@
   ~LayerTreeHostNoMessageLoopTest() override {}
 
   // LayerTreeHostClient overrides.
-  void WillBeginMainFrame(int frame_id) override {}
+  void WillBeginMainFrame() override {}
   void BeginMainFrame(const BeginFrameArgs& args) override {}
   void DidBeginMainFrame() override {}
   void Layout() override {}
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index d578daf7..07dfc29d 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -30,6 +30,7 @@
       gpu_rasterization_enabled(false),
       gpu_rasterization_forced(false),
       gpu_rasterization_msaa_sample_count(0),
+      threaded_gpu_rasterization_enabled(false),
       create_low_res_tiling(false),
       scrollbar_animator(NoAnimator),
       scrollbar_fade_delay_ms(0),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 597a2797..5eacdf8 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -36,6 +36,7 @@
   bool gpu_rasterization_enabled;
   bool gpu_rasterization_forced;
   int gpu_rasterization_msaa_sample_count;
+  bool threaded_gpu_rasterization_enabled;
   bool create_low_res_tiling;
 
   enum ScrollbarAnimator {
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index dc58d39a..f913c1f 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -7,6 +7,7 @@
 #include "base/auto_reset.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/debug/benchmark_instrumentation.h"
+#include "cc/debug/devtools_instrumentation.h"
 #include "cc/output/context_provider.h"
 #include "cc/output/output_surface.h"
 #include "cc/quads/draw_quad.h"
@@ -204,6 +205,8 @@
 
   commit_requested_ = false;
   layer_tree_host_->WillCommit();
+  devtools_instrumentation::ScopedCommitTrace commit_task(
+      layer_tree_host_->id());
 
   // Commit immediately.
   {
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 88f1314..5ee43aba 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -796,6 +796,8 @@
   bool updated = layer_tree_host()->UpdateLayers(queue.get());
 
   layer_tree_host()->WillCommit();
+  devtools_instrumentation::ScopedCommitTrace commit_task(
+      layer_tree_host()->id());
 
   // Before calling animate, we set main().animate_requested to false. If it is
   // true now, it means SetNeedAnimate was called again, but during a state when
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 65106a2..6deb300 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -45,6 +45,10 @@
         "app/chrome_crash_reporter_client.h",
         "app/chrome_exe.rc",
         "app/chrome_exe_main_win.cc",
+        "app/chrome_watcher_client_win.cc",
+        "app/chrome_watcher_client_win.h",
+        "app/chrome_watcher_command_line_win.cc",
+        "app/chrome_watcher_command_line_win.h",
         "app/client_util.cc",
         "app/client_util.h",
         "app/chrome_watcher_command_line_win.cc",
@@ -150,10 +154,8 @@
       # TODO(GYP) some stuff from GYP including chrome_multiple_dll.
     }
 
-    if (!is_mac) {
-      # On Mac this is done in chrome_dll.gypi.
-      datadeps += [ "//pdf" ]
-      # TODO(GYP) pdf linux symbols
+    if (enable_plugins) {
+      deps += [ "//pdf" ]
     }
   }
 }  # !is_android
@@ -237,6 +239,10 @@
       #}],
       # TODO(GYP) Lots of other stuff in the OS=="mac" block.
     }
+
+    if (enable_plugins) {
+      deps += [ "//pdf" ]
+    }
   }
 }
 
@@ -268,6 +274,7 @@
   if (!is_ios) {
     deps += [
       "//chrome/browser/devtools",
+      "//chrome/child",
       "//chrome/plugin",
       "//chrome/renderer",
       "//chrome/utility",
@@ -685,6 +692,7 @@
     deps = [
       "//chrome/browser",
       "//chrome/browser/ui",
+      "//chrome/child",
       "//chrome/plugin",
       "//chrome/renderer",
       "//chrome/utility",
diff --git a/chrome/DEPS b/chrome/DEPS
index 9c95992..e014b07f 100644
--- a/chrome/DEPS
+++ b/chrome/DEPS
@@ -2,6 +2,7 @@
   "+crypto",
   "+gpu",
   "+net",
+  "+pdf",
   "+printing",
   "+sql",
   # Browser, renderer, common and tests access V8 for various purposes.
diff --git a/chrome/VERSION b/chrome/VERSION
index 1c3b91a..fdcf034 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=42
 MINOR=0
-BUILD=2294
+BUILD=2296
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f171e3c..2e86b19 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -114,7 +114,6 @@
 }
 
 # GYP: //chrome/chrome_browser.gypi:activity_type_ids_java
-# GYP: //chrome/chrome_browser.gypi:add_web_contents_result_java
 # GYP: //chrome/chrome_browser.gypi:profile_account_management_metrics_java
 # GYP: //chrome/chrome_browser.gypi:profile_sync_service_model_type_selection_java
 # GYP: //chrome/chrome_browser.gypi:tab_load_status_java
@@ -122,7 +121,6 @@
 java_cpp_enum("chrome_android_java_enums_srcjar") {
   sources = [
     "//chrome/browser/android/activity_type_ids.h",
-    "//chrome/browser/android/chrome_web_contents_delegate_android.h",
     "//chrome/browser/android/tab_android.h",
     "//chrome/browser/profiles/profile_metrics.h",
     "//chrome/browser/sync/profile_sync_service_android.cc",
@@ -130,7 +128,6 @@
   ]
   outputs = [
     "org/chromium/chrome/browser/ActivityTypeIds.java",
-    "org/chromium/chrome/browser/AddWebContentsResult.java",
     "org/chromium/chrome/browser/TabLoadStatus.java",
     "org/chromium/chrome/browser/profiles/ProfileAccountManagementMetrics.java",
     "org/chromium/chrome/browser/sync/ModelTypeSelection.java",
diff --git a/chrome/android/java/res/drawable-hdpi/btn_toolbar_stop.png b/chrome/android/java/res/drawable-hdpi/btn_toolbar_stop.png
deleted file mode 100644
index 315727c..0000000
--- a/chrome/android/java/res/drawable-hdpi/btn_toolbar_stop.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/cvc_icon.png b/chrome/android/java/res/drawable-hdpi/cvc_icon.png
new file mode 100644
index 0000000..31c60334
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/cvc_icon.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/cvc_icon_amex.png b/chrome/android/java/res/drawable-hdpi/cvc_icon_amex.png
new file mode 100644
index 0000000..31c60334
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/cvc_icon_amex.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/btn_toolbar_stop.png b/chrome/android/java/res/drawable-mdpi/btn_toolbar_stop.png
deleted file mode 100644
index 6e95c99..0000000
--- a/chrome/android/java/res/drawable-mdpi/btn_toolbar_stop.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/cvc_icon.png b/chrome/android/java/res/drawable-mdpi/cvc_icon.png
new file mode 100644
index 0000000..8a733dd
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/cvc_icon.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/cvc_icon_amex.png b/chrome/android/java/res/drawable-mdpi/cvc_icon_amex.png
new file mode 100644
index 0000000..8a733dd
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/cvc_icon_amex.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/btn_toolbar_stop.png b/chrome/android/java/res/drawable-xhdpi/btn_toolbar_stop.png
deleted file mode 100644
index 4c8d6ea..0000000
--- a/chrome/android/java/res/drawable-xhdpi/btn_toolbar_stop.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/cvc_icon.png b/chrome/android/java/res/drawable-xhdpi/cvc_icon.png
new file mode 100644
index 0000000..49ac310a
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/cvc_icon.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/cvc_icon_amex.png b/chrome/android/java/res/drawable-xhdpi/cvc_icon_amex.png
new file mode 100644
index 0000000..49ac310a
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/cvc_icon_amex.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/btn_toolbar_stop.png b/chrome/android/java/res/drawable-xxhdpi/btn_toolbar_stop.png
deleted file mode 100644
index 958a384..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/btn_toolbar_stop.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/cvc_icon.png b/chrome/android/java/res/drawable-xxhdpi/cvc_icon.png
new file mode 100644
index 0000000..c8cf4f2
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/cvc_icon.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/cvc_icon_amex.png b/chrome/android/java/res/drawable-xxhdpi/cvc_icon_amex.png
new file mode 100644
index 0000000..c8cf4f2
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/cvc_icon_amex.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/btn_toolbar_stop.png b/chrome/android/java/res/drawable-xxxhdpi/btn_toolbar_stop.png
deleted file mode 100644
index d14521b0..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/btn_toolbar_stop.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/cvc_icon.png b/chrome/android/java/res/drawable-xxxhdpi/cvc_icon.png
new file mode 100644
index 0000000..f41859d
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/cvc_icon.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/cvc_icon_amex.png b/chrome/android/java/res/drawable-xxxhdpi/cvc_icon_amex.png
new file mode 100644
index 0000000..f41859d
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/cvc_icon_amex.png
Binary files differ
diff --git a/ui/android/java/res/layout/autofill_card_unmask_prompt.xml b/chrome/android/java/res/layout/autofill_card_unmask_prompt.xml
similarity index 89%
rename from ui/android/java/res/layout/autofill_card_unmask_prompt.xml
rename to chrome/android/java/res/layout/autofill_card_unmask_prompt.xml
index 360e216..2ab4a361 100644
--- a/ui/android/java/res/layout/autofill_card_unmask_prompt.xml
+++ b/chrome/android/java/res/layout/autofill_card_unmask_prompt.xml
@@ -47,10 +47,17 @@
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:layout_marginStart="16dp"
-            android:layout_marginEnd="16dp"
             android:ems="4"
             android:hint="@string/card_unmask_input_hint" />
 
+        <ImageView
+            android:id="@+id/cvc_hint_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="16dp" />
+
         <ProgressBar
             style="@android:style/Widget.ProgressBar.Small"
             android:id="@+id/verification_progress_bar"
diff --git a/chrome/android/java/res/layout/autofill_credit_card_editor.xml b/chrome/android/java/res/layout/autofill_credit_card_editor.xml
index c1153fb..2211041 100644
--- a/chrome/android/java/res/layout/autofill_credit_card_editor.xml
+++ b/chrome/android/java/res/layout/autofill_credit_card_editor.xml
@@ -52,6 +52,7 @@
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:focusable="true"
                 android:paddingTop="10dp"
                 android:textAppearance="@style/PreferenceFloatLabelTextAppearance"
                 android:text="@string/autofill_credit_card_editor_expiration_date" />
@@ -66,16 +67,14 @@
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
-                    android:paddingTop="8dp"
-                    android:contentDescription="@string/accessibility_autofill_cc_month" />
+                    android:paddingTop="8dp" />
 
                 <Spinner
                     android:id="@+id/autofill_credit_card_editor_year_spinner"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
-                    android:paddingTop="8dp"
-                    android:contentDescription="@string/accessibility_autofill_cc_year" />
+                    android:paddingTop="8dp" />
             </LinearLayout>
         </LinearLayout>
 
diff --git a/chrome/android/java/res/layout/autofill_profile_editor.xml b/chrome/android/java/res/layout/autofill_profile_editor.xml
index 75a750c..6f06d18 100644
--- a/chrome/android/java/res/layout/autofill_profile_editor.xml
+++ b/chrome/android/java/res/layout/autofill_profile_editor.xml
@@ -25,13 +25,13 @@
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:focusable="true"
                 android:textAppearance="@style/PreferenceFloatLabelTextAppearance"
                 android:text="@string/autofill_profile_editor_country" />
             <Spinner
                 android:id="@+id/countries"
                 android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:contentDescription="@string/autofill_profile_editor_country" />
+                android:layout_height="wrap_content" />
 
             <LinearLayout
                 android:id="@+id/autofill_profile_widget_root"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java
index 76bf0ea08..cd157eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java
@@ -28,9 +28,9 @@
     }
 
     @CalledByNative
-    public int addNewContents(WebContents sourceWebContents, WebContents webContents,
+    public boolean addNewContents(WebContents sourceWebContents, WebContents webContents,
             int disposition, Rect initialPosition, boolean userGesture) {
-        return AddWebContentsResult.STOP_LOAD_AND_DELETE;
+        return false;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java
index a7b4eb36..9652a85 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java
@@ -9,8 +9,8 @@
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.JNINamespace;
-import org.chromium.ui.autofill.CardUnmaskPrompt;
-import org.chromium.ui.autofill.CardUnmaskPrompt.CardUnmaskPromptDelegate;
+import org.chromium.chrome.browser.ResourceId;
+import org.chromium.chrome.browser.autofill.CardUnmaskPrompt.CardUnmaskPromptDelegate;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -22,7 +22,8 @@
     private final CardUnmaskPrompt mCardUnmaskPrompt;
 
     public CardUnmaskBridge(long nativeCardUnmaskPromptViewAndroid, String title,
-            String instructions, boolean shouldRequestExpirationDate, WindowAndroid windowAndroid) {
+            String instructions, int iconId, boolean shouldRequestExpirationDate,
+            WindowAndroid windowAndroid) {
         mNativeCardUnmaskPromptViewAndroid = nativeCardUnmaskPromptViewAndroid;
         Activity activity = windowAndroid.getActivity().get();
         if (activity == null) {
@@ -36,15 +37,16 @@
                 }
             });
         } else {
-            mCardUnmaskPrompt = new CardUnmaskPrompt(
-                    activity, this, title, instructions, shouldRequestExpirationDate);
+            mCardUnmaskPrompt = new CardUnmaskPrompt(activity, this, title, instructions,
+                    ResourceId.mapToDrawableId(iconId), shouldRequestExpirationDate);
         }
     }
 
     @CalledByNative
     private static CardUnmaskBridge create(long nativeUnmaskPrompt, String title,
-            String instructions, boolean shouldRequestExpirationDate, WindowAndroid windowAndroid) {
-        return new CardUnmaskBridge(nativeUnmaskPrompt, title, instructions,
+            String instructions, int iconId, boolean shouldRequestExpirationDate,
+            WindowAndroid windowAndroid) {
+        return new CardUnmaskBridge(nativeUnmaskPrompt, title, instructions, iconId,
                 shouldRequestExpirationDate, windowAndroid);
     }
 
diff --git a/ui/android/java/src/org/chromium/ui/autofill/CardUnmaskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
similarity index 95%
rename from ui/android/java/src/org/chromium/ui/autofill/CardUnmaskPrompt.java
rename to chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
index e9c0a0d9..76349d6 100644
--- a/ui/android/java/src/org/chromium/ui/autofill/CardUnmaskPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.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.ui.autofill;
+package org.chromium.chrome.browser.autofill;
 
 import android.app.AlertDialog;
 import android.content.Context;
@@ -16,11 +16,12 @@
 import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.EditText;
+import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.Spinner;
 import android.widget.TextView;
 
-import org.chromium.ui.R;
+import org.chromium.chrome.R;
 
 import java.text.NumberFormat;
 import java.util.Calendar;
@@ -62,7 +63,7 @@
     }
 
     public CardUnmaskPrompt(Context context, CardUnmaskPromptDelegate delegate, String title,
-            String instructions, boolean shouldRequestExpirationDate) {
+            String instructions, int drawableId, boolean shouldRequestExpirationDate) {
         mDelegate = delegate;
 
         LayoutInflater inflater = LayoutInflater.from(context);
@@ -74,6 +75,7 @@
         mYearSpinner = (Spinner) v.findViewById(R.id.expiration_year);
         mVerificationProgressBar = (ProgressBar) v.findViewById(R.id.verification_progress_bar);
         mVerificationView = (TextView) v.findViewById(R.id.verification_message);
+        ((ImageView) v.findViewById(R.id.cvc_hint_image)).setImageResource(drawableId);
 
         mDialog = new AlertDialog.Builder(context)
                           .setTitle(title)
@@ -207,7 +209,7 @@
     private boolean areInputsValid() {
         if (mShouldRequestExpirationDate
                 && (mMonthSpinner.getSelectedItemPosition() == 0
-                           || mYearSpinner.getSelectedItemPosition() == 0)) {
+                        || mYearSpinner.getSelectedItemPosition() == 0)) {
             return false;
         }
         return mDelegate.checkUserInputValidity(mCardUnmaskInput.getText().toString());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/PendingDocumentData.java b/chrome/android/java/src/org/chromium/chrome/browser/document/PendingDocumentData.java
index 8fac76b..62711bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/PendingDocumentData.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/PendingDocumentData.java
@@ -29,9 +29,6 @@
     /** HTTP "referer". */
     public Referrer referrer;
 
-    /** The original intent. */
+    /** The original intent */
     public Intent originalIntent;
-
-    /** Whether there was a user gesture during the navigation. */
-    public boolean userGesture;
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java
new file mode 100644
index 0000000..f66455b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java
@@ -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.
+
+package org.chromium.chrome.browser.infobar;
+
+import android.graphics.Bitmap;
+import android.widget.TextView;
+
+/**
+ * Infobar informing the user about an app related to this page.
+ */
+public class AppBannerInfoBar extends ConfirmInfoBar {
+    /** Web app: URL pointing to the web app. */
+    private final String mAppUrl;
+
+    public AppBannerInfoBar(long nativeInfoBar, String appTitle, Bitmap iconBitmap,
+            String installText, String url) {
+        super(nativeInfoBar, null, 0, iconBitmap, appTitle, null, installText, null);
+        mAppUrl = url;
+    }
+
+    @Override
+    public void createContent(InfoBarLayout layout) {
+        TextView url = new TextView(layout.getContext());
+        url.setText(mAppUrl);
+        layout.setCustomContent(url);
+        super.createContent(layout);
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java
new file mode 100644
index 0000000..9573af6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java
@@ -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.
+
+package org.chromium.chrome.browser.infobar;
+
+import android.graphics.Bitmap;
+
+import org.chromium.base.CalledByNative;
+
+/**
+ * Handles creation of AppBannerInfoBars.
+ */
+public class AppBannerInfoBarDelegate {
+    private AppBannerInfoBarDelegate() {
+    }
+
+    @CalledByNative
+    private static AppBannerInfoBarDelegate create() {
+        return new AppBannerInfoBarDelegate();
+    }
+
+    @CalledByNative
+    private InfoBar showInfoBar(
+            long nativeInfoBar, String appTitle, Bitmap iconBitmap, String buttonText, String url) {
+        return new AppBannerInfoBar(nativeInfoBar, appTitle, iconBitmap, buttonText, url);
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java
index 5191847..c6d17f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileBridge.java
@@ -60,6 +60,8 @@
         }
     }
 
+    private String mCurrentBestLanguageCode;
+
     /**
      * @return The CLDR region code for the default locale.
      */
@@ -97,21 +99,30 @@
     }
 
     /**
-     * Returns the UI components for the CLDR countryCode provided.
+     * Returns the UI components for the CLDR countryCode and languageCode provided. If no language
+     * code is provided, the application's default locale is used instead. Also stores the
+     * currentBestLanguageCode, retrievable via getCurrentBestLanguageCode, to be used when saving
+     * an autofill profile.
      *
      * @param countryCode The CLDR code used to retrieve address components.
+     * @param languageCode The language code associated with the saved autofill profile that ui
+     *                     components are being retrieved for; can be null if ui components are
+     *                     being retrieved for a new profile.
      * @return A list containing pairs where the first element in the pair is an Integer
      *         representing the component id (one of the constants in AddressField), and the second
      *         element in the pair is the localized component name (intended for use as labels in
      *         the UI). The ordering in the list of pairs specifies the order these components
      *         should appear in the UI.
      */
-    static List<Pair<Integer, String>> getAddressUiComponents(String countryCode) {
+    List<Pair<Integer, String>> getAddressUiComponents(String countryCode,
+            String languageCode) {
         List<Integer> componentIds = new ArrayList<Integer>();
         List<String> componentNames = new ArrayList<String>();
         List<Pair<Integer, String>> uiComponents = new ArrayList<Pair<Integer, String>>();
 
-        nativeGetAddressUiComponents(countryCode, componentIds, componentNames);
+        mCurrentBestLanguageCode =
+                nativeGetAddressUiComponents(countryCode, languageCode, componentIds,
+                        componentNames);
 
         for (int i = 0; i < componentIds.size(); i++) {
             uiComponents.add(new Pair<Integer, String>(componentIds.get(i), componentNames.get(i)));
@@ -120,6 +131,14 @@
         return uiComponents;
     }
 
+    /**
+     * @return The language code associated with the most recently retrieved address ui components.
+     *         Will return null if getAddressUiComponents() has not been called yet.
+     */
+    String getCurrentBestLanguageCode() {
+        return mCurrentBestLanguageCode;
+    }
+
     @CalledByNative
     private static void stringArrayToList(String[] array, List<String> list) {
         for (String s : array) {
@@ -137,6 +156,6 @@
     private static native String nativeGetDefaultCountryCode();
     private static native void nativeGetSupportedCountries(List<String> countryCodes,
             List<String> countryNames);
-    private static native void nativeGetAddressUiComponents(String countryCode,
-            List<Integer> componentIds, List<String> componentNames);
+    private static native String nativeGetAddressUiComponents(String countryCode,
+            String languageCode, List<Integer> componentIds, List<String> componentNames);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java
index 1e3e9316..aeda56e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditor.java
@@ -51,6 +51,8 @@
     private Spinner mCountriesSpinner;
     private ViewGroup mWidgetRoot;
     private FloatLabelLayout[] mAddressFields;
+    private AutofillProfileBridge mAutofillProfileBridge;
+    private boolean mUseSavedProfileLanguage;
 
     @Override
     public void onCreate(Bundle savedState) {
@@ -86,6 +88,8 @@
         mWidgetRoot = (ViewGroup) v.findViewById(R.id.autofill_profile_widget_root);
         mCountriesSpinner = (Spinner) v.findViewById(R.id.countries);
 
+        mAutofillProfileBridge = new AutofillProfileBridge();
+
         populateCountriesSpinner();
         createAndPopulateEditFields();
         hookupSaveCancelDeleteButtons(v);
@@ -123,6 +127,7 @@
     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
         if (position != mCurrentCountryPos) {
             mCurrentCountryPos = position;
+            mUseSavedProfileLanguage = false;
             // If all fields are empty (e.g. the user just entered the form and the first thing
             // they did was select a country), focus on the first form element. Otherwise, don't.
             resetFormFields(position, allFieldsEmpty());
@@ -161,6 +166,7 @@
             }
 
             mLanguageCodeString = profile.getLanguageCode();
+            mUseSavedProfileLanguage = true;
 
             mCurrentCountryPos = mCountryCodes.indexOf(profile.getCountryCode());
             if (mCurrentCountryPos == -1) {
@@ -213,8 +219,12 @@
         mWidgetRoot.removeAllViews();
 
         // Get address fields for the selected country.
-        List<Pair<Integer, String>> fields = AutofillProfileBridge.getAddressUiComponents(
-                mCountryCodes.get(countryCodeIndex));
+        List<Pair<Integer, String>> fields = mAutofillProfileBridge.getAddressUiComponents(
+                mCountryCodes.get(countryCodeIndex),
+                mLanguageCodeString);
+        if (!mUseSavedProfileLanguage) {
+            mLanguageCodeString = mAutofillProfileBridge.getCurrentBestLanguageCode();
+        }
 
         // Create form fields and focus the first field if autoFocusFirstField is true.
         boolean firstField = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
index efbdb22c..82de70c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
@@ -46,7 +46,7 @@
 import org.chromium.chrome.browser.sync.GoogleServiceAuthError;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.ProfileSyncService.SyncStateChangedListener;
-import org.chromium.sync.notifier.SyncStatusHelper;
+import org.chromium.sync.AndroidSyncSettings;
 import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.sync.signin.ChromeSigninController;
 
@@ -388,7 +388,7 @@
                                 ProfileAccountManagementMetrics.CLICK_PRIMARY_ACCOUNT,
                                 mGaiaServiceType);
 
-                        if (SyncStatusHelper.get(activity).isMasterSyncAutomaticallyEnabled()) {
+                        if (AndroidSyncSettings.get(activity).isMasterSyncEnabled()) {
                             getDelegate().openSyncCustomizationFragment(activity, account);
                         } else {
                             Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
@@ -470,7 +470,7 @@
         ChromeSigninController signinController = ChromeSigninController.get(activity);
         if (!signinController.isSignedIn()) return "";
 
-        SyncStatusHelper syncStatusHelper = SyncStatusHelper.get(activity);
+        AndroidSyncSettings androidSyncSettings = AndroidSyncSettings.get(activity);
         ProfileSyncService profileSyncService = ProfileSyncService.get(activity);
         Resources res = activity.getResources();
 
@@ -478,7 +478,7 @@
             return res.getString(R.string.kids_account);
         }
 
-        if (!syncStatusHelper.isMasterSyncAutomaticallyEnabled()) {
+        if (!androidSyncSettings.isMasterSyncEnabled()) {
             return res.getString(R.string.sync_android_master_sync_disabled);
         }
 
@@ -486,7 +486,7 @@
             return res.getString(profileSyncService.getAuthError().getMessage());
         }
 
-        if (syncStatusHelper.isSyncEnabled()) {
+        if (androidSyncSettings.isSyncEnabled()) {
             if (!profileSyncService.isSyncInitialized()) {
                 return res.getString(R.string.sync_setup_progress);
             }
@@ -504,7 +504,7 @@
             }
         }
 
-        return syncStatusHelper.isSyncEnabled(signinController.getSignedInUser())
+        return androidSyncSettings.isSyncEnabled(signinController.getSignedInUser())
                 ? res.getString(R.string.sync_is_enabled)
                 : res.getString(R.string.sync_is_disabled);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
index 7181960a..472d592 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
@@ -18,7 +18,6 @@
 import org.chromium.chrome.browser.notifications.NotificationConstants;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.sync.AndroidSyncSettings;
-import org.chromium.sync.notifier.SyncStatusHelper;
 
 /**
  * {@link SyncNotificationController} provides functionality for displaying Android notifications
@@ -45,22 +44,6 @@
         mAccountManagementFragment = accountManagementFragment;
     }
 
-    /**
-     * Deprecated for having unnecessary args; use the first constructor.
-     */
-    @Deprecated
-    public SyncNotificationController(Context context,
-            GoogleServicesNotificationController controller, ProfileSyncService profileSyncService,
-            SyncStatusHelper syncStatusHelper, Class<? extends Activity> passphraseRequestActivity,
-            Class<? extends Fragment> accountManagementFragment) {
-        mApplicationContext = context.getApplicationContext();
-        mNotificationController = controller;
-        mProfileSyncService = profileSyncService;
-        mAndroidSyncSettings = AndroidSyncSettings.get(context);
-        mPassphraseRequestActivity = passphraseRequestActivity;
-        mAccountManagementFragment = accountManagementFragment;
-    }
-
     public void displayAndroidMasterSyncDisabledNotification() {
         String masterSyncDisabled =
                 GoogleServicesNotificationController.formatMessageParts(mApplicationContext,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabList.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabList.java
index b4f32e0..106f7e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabList.java
@@ -11,6 +11,7 @@
  * well as a currently selected tab (see {@link #index}).
  */
 public interface TabList {
+    // Keep this in sync with chrome/browser/ui/android/tab_model/tab_model.cc
     public static final int INVALID_TAB_INDEX = -1;
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java
index 33eafd0..f182417c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/FloatLabelLayout.java
@@ -96,6 +96,7 @@
         mLabel.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
         mLabel.setVisibility(INVISIBLE);
         mLabel.setText(mHint);
+        mLabel.setFocusable(true);
         ViewCompat.setPivotX(mLabel, 0f);
         ViewCompat.setPivotY(mLabel, 0f);
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 19f8bf3..117bc2d 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -167,12 +167,6 @@
       <message name="IDS_ACCESSIBILITY_AUTOFILL_CC_NUMBER_TEXTBOX" desc="Content description for text input field containing a credit card number.">
         Card number
       </message>
-      <message name="IDS_ACCESSIBILITY_AUTOFILL_CC_MONTH" desc="Content description for text input field containing a credit card expiration month.">
-        Card expiration month
-      </message>
-      <message name="IDS_ACCESSIBILITY_AUTOFILL_CC_YEAR" desc="Content description for text input field containing a credit card expiration year.">
-        Card expiration year
-      </message>
 
       <!-- Autofill/Wallet integration preferences -->
       <message name="IDS_AUTOFILL_WALLET_TITLE" desc="Title for Autofill Wallet settings, which controls import of Wallet cards.">
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
index de5c5f4..73cf1a5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
@@ -8,6 +8,7 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.shell.ChromeShellTab;
 import org.chromium.chrome.shell.ChromeShellTestBase;
@@ -51,8 +52,12 @@
     }
 
     /** Verifies that confirming the form reload performs the reload. */
+    /*
     @MediumTest
     @Feature({"Navigation"})
+    crbug.com/454834
+    */
+    @DisabledTest
     public void testFormResubmissionContinue() throws Throwable {
         // Load the url posting data for the first time.
         postNavigation();
@@ -78,8 +83,12 @@
      * after the "Cancel" button is clicked to verify that the load was not triggered, which blocks
      * for CallbackHelper's default timeout upon each execution.
      */
+    /*
     @SmallTest
     @Feature({"Navigation"})
+    crbug.com/454834
+    */
+    @DisabledTest
     public void testFormResubmissionCancel() throws Throwable {
         // Load the url posting data for the first time.
         postNavigation();
diff --git a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellToolbar.java b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellToolbar.java
index 6d23697..35b8e4f 100644
--- a/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellToolbar.java
+++ b/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellToolbar.java
@@ -50,7 +50,7 @@
             mProgressDrawable.setLevel(100 * mProgress);
             if (mLoading) {
                 mStopReloadButton.setImageResource(
-                        R.drawable.btn_toolbar_stop);
+                        R.drawable.btn_close);
             } else {
                 mStopReloadButton.setImageResource(R.drawable.btn_toolbar_reload);
                 ApiCompatibilityUtils.postOnAnimationDelayed(ChromeShellToolbar.this,
diff --git a/chrome/android/shell/res/layout/chrome_shell_activity.xml b/chrome/android/shell/res/layout/chrome_shell_activity.xml
index fb0ef50..c6050111 100644
--- a/chrome/android/shell/res/layout/chrome_shell_activity.xml
+++ b/chrome/android/shell/res/layout/chrome_shell_activity.xml
@@ -27,7 +27,7 @@
             android:id="@+id/stop_reload_button"
             android:layout_width="38dp"
             android:layout_height="38dp"
-            android:src="@drawable/btn_toolbar_stop"
+            android:src="@drawable/btn_close"
             android:background="?attr/selectableItemBackground"
             android:scaleType="center"/>
         <EditText android:id="@+id/url"
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 1d397e01..0c93b0d 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -304,6 +304,7 @@
   deps = [
     "//base",
     "//chrome/browser",
+    "//chrome/child",
     "//chrome/common",
     "//chrome/plugin",
     "//chrome/renderer",
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index c137446..08a8ab3 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+breakpad",
   "+chrome/browser",
+  "+chrome/child",
   "+chrome/chrome_watcher",
   "+chrome/installer",
   "+chrome/plugin/chrome_content_plugin_client.h",
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index e62085d..7a84022 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -119,12 +119,14 @@
 #include "remoting/client/plugin/pepper_entrypoints.h"
 #endif
 
-#if !defined(CHROME_MULTIPLE_DLL_CHILD)
-base::LazyInstance<chrome::ChromeContentBrowserClient>
-    g_chrome_content_browser_client = LAZY_INSTANCE_INITIALIZER;
+#if defined(ENABLE_PLUGINS) && (defined(CHROME_MULTIPLE_DLL_CHILD) || \
+    !defined(CHROME_MULTIPLE_DLL_BROWSER))
+#include "pdf/pdf.h"
 #endif
 
 #if !defined(CHROME_MULTIPLE_DLL_BROWSER)
+#include "chrome/child/pdf_child_init.h"
+
 base::LazyInstance<ChromeContentRendererClient>
     g_chrome_content_renderer_client = LAZY_INSTANCE_INITIALIZER;
 base::LazyInstance<ChromeContentUtilityClient>
@@ -133,6 +135,11 @@
     g_chrome_content_plugin_client = LAZY_INSTANCE_INITIALIZER;
 #endif
 
+#if !defined(CHROME_MULTIPLE_DLL_CHILD)
+base::LazyInstance<chrome::ChromeContentBrowserClient>
+    g_chrome_content_browser_client = LAZY_INSTANCE_INITIALIZER;
+#endif
+
 #if defined(OS_POSIX)
 base::LazyInstance<chrome::ChromeCrashReporterClient>::Leaky
     g_chrome_crash_client = LAZY_INSTANCE_INITIALIZER;
@@ -775,6 +782,8 @@
         process_type == switches::kZygoteProcess) {
       ChromeContentUtilityClient::PreSandboxStartup();
     }
+
+    chrome::InitializePDF();
 #endif
   }
 
@@ -822,6 +831,12 @@
       nacl_plugin::PPP_InitializeModule,
       nacl_plugin::PPP_ShutdownModule);
 #endif
+#if defined(ENABLE_PLUGINS)
+  ChromeContentClient::SetPDFEntryFunctions(
+      chrome_pdf::PPP_GetInterface,
+      chrome_pdf::PPP_InitializeModule,
+      chrome_pdf::PPP_ShutdownModule);
+#endif
 #endif
 }
 
diff --git a/chrome/app/chrome_watcher_client_unittest_win.cc b/chrome/app/chrome_watcher_client_unittest_win.cc
new file mode 100644
index 0000000..5b916138
--- /dev/null
+++ b/chrome/app/chrome_watcher_client_unittest_win.cc
@@ -0,0 +1,270 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/app/chrome_watcher_client_win.h"
+
+#include <windows.h>
+#include <string>
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/multiprocess_test.h"
+#include "base/threading/simple_thread.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace {
+
+const char kParentHandle[] = "parent-handle";
+const char kEventHandle[] = "event-handle";
+const char kNamedEventSuffix[] = "named-event-suffix";
+
+const base::char16 kExitEventBaseName[] = L"ChromeWatcherClientTestExitEvent_";
+const base::char16 kInitializeEventBaseName[] =
+    L"ChromeWatcherClientTestInitializeEvent_";
+
+base::win::ScopedHandle InterpretHandleSwitch(base::CommandLine& cmd_line,
+                                              const char* switch_name) {
+  std::string str_handle =
+      cmd_line.GetSwitchValueASCII(switch_name);
+  if (str_handle.empty()) {
+    LOG(ERROR) << "Switch " << switch_name << " unexpectedly absent.";
+    return base::win::ScopedHandle();
+  }
+
+  unsigned int_handle = 0;
+  if (!base::StringToUint(str_handle, &int_handle)) {
+    LOG(ERROR) << "Switch " << switch_name << " has invalid value "
+               << str_handle;
+    return base::win::ScopedHandle();
+  }
+
+  return base::win::ScopedHandle(
+      reinterpret_cast<base::ProcessHandle>(int_handle));
+}
+
+// Simulates a Chrome watcher process. Exits when the global exit event is
+// signaled. Signals the "on initialized" event (passed on the command-line)
+// when the global initialization event is signaled.
+MULTIPROCESS_TEST_MAIN(ChromeWatcherClientTestProcess) {
+  base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+
+  base::string16 named_event_suffix =
+      base::ASCIIToUTF16(cmd_line->GetSwitchValueASCII(kNamedEventSuffix));
+  if (named_event_suffix.empty()) {
+    LOG(ERROR) << "Switch " << kNamedEventSuffix << " unexpectedly absent.";
+    return 1;
+  }
+
+  base::win::ScopedHandle exit_event(::CreateEvent(
+      NULL, FALSE, FALSE, (kExitEventBaseName + named_event_suffix).c_str()));
+  if (!exit_event.IsValid()) {
+    LOG(ERROR) << "Failed to create event named "
+               << kExitEventBaseName + named_event_suffix;
+    return 1;
+  }
+
+  base::win::ScopedHandle initialize_event(
+      ::CreateEvent(NULL, FALSE, FALSE,
+                    (kInitializeEventBaseName + named_event_suffix).c_str()));
+  if (!initialize_event.IsValid()) {
+    LOG(ERROR) << "Failed to create event named "
+               << kInitializeEventBaseName + named_event_suffix;
+    return 1;
+  }
+
+  base::win::ScopedHandle parent_process(
+      InterpretHandleSwitch(*cmd_line, kParentHandle));
+  if (!parent_process.IsValid())
+    return 1;
+
+  base::win::ScopedHandle on_initialized_event(
+      InterpretHandleSwitch(*cmd_line, kEventHandle));
+  if (!on_initialized_event.IsValid())
+    return 1;
+
+  while (true) {
+    // We loop as a convenient way to continue waiting for the exit_event after
+    // the initialize_event is signaled. We expect to get initialize_event zero
+    // or one times before exit_event, never more.
+    HANDLE handles[] = {exit_event.Get(), initialize_event.Get()};
+    DWORD result =
+        ::WaitForMultipleObjects(arraysize(handles), handles, FALSE, INFINITE);
+    switch (result) {
+      case WAIT_OBJECT_0:
+        // exit_event
+        return 0;
+      case WAIT_OBJECT_0 + 1:
+        // initialize_event
+        ::SetEvent(on_initialized_event.Get());
+        break;
+      case WAIT_FAILED:
+        PLOG(ERROR) << "Unexpected failure in WaitForMultipleObjects.";
+        return 1;
+      default:
+        NOTREACHED() << "Unexpected result from WaitForMultipleObjects: "
+                     << result;
+        return 1;
+    }
+  }
+}
+
+// Implements a thread to launch the ChromeWatcherClient and block on
+// EnsureInitialized. Provides various helpers to interact with the
+// ChromeWatcherClient.
+class ChromeWatcherClientThread : public base::SimpleThread {
+ public:
+  ChromeWatcherClientThread()
+      : client_(base::Bind(&ChromeWatcherClientThread::GenerateCommandLine,
+                           base::Unretained(this))),
+        complete_(false, false),
+        result_(false),
+        SimpleThread("ChromeWatcherClientTest thread") {}
+
+  // Waits up to |timeout| for the call to EnsureInitialized to complete. If it
+  // does, sets |result| to the return value of EnsureInitialized and returns
+  // true. Otherwise returns false.
+  bool WaitForResultWithTimeout(base::TimeDelta timeout, bool* result) {
+    if (!complete_.TimedWait(timeout))
+      return false;
+    *result = result_;
+    return true;
+  }
+
+  // Waits indefinitely for the call to WaitForInitialization to complete.
+  // Returns the return value of WaitForInitialization.
+  bool WaitForResult() {
+    complete_.Wait();
+    return result_;
+  }
+
+  ChromeWatcherClient& client() { return client_; }
+
+  base::string16 NamedEventSuffix() {
+    return base::UintToString16(base::GetCurrentProcId());
+  }
+
+  // base::SimpleThread implementation.
+  void Run() override {
+    result_ = client_.LaunchWatcher();
+    if (result_)
+      result_ = client_.EnsureInitialized();
+    complete_.Signal();
+  }
+
+ private:
+  // Returns a command line to launch back into ChromeWatcherClientTestProcess.
+  base::CommandLine GenerateCommandLine(HANDLE parent_handle,
+                                        HANDLE on_initialized_event) {
+    base::CommandLine ret = base::GetMultiProcessTestChildBaseCommandLine();
+    ret.AppendSwitchASCII(switches::kTestChildProcess,
+                          "ChromeWatcherClientTestProcess");
+    ret.AppendSwitchASCII(kEventHandle,
+                          base::UintToString(reinterpret_cast<unsigned int>(
+                              on_initialized_event)));
+    ret.AppendSwitchASCII(
+        kParentHandle,
+        base::UintToString(reinterpret_cast<unsigned int>(parent_handle)));
+    ret.AppendSwitchASCII(kNamedEventSuffix,
+                          base::UTF16ToASCII(NamedEventSuffix()));
+    return ret;
+  }
+
+  // The instance under test.
+  ChromeWatcherClient client_;
+  // Signaled when WaitForInitialization returns.
+  base::WaitableEvent complete_;
+  // The return value of WaitForInitialization.
+  bool result_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeWatcherClientThread);
+};
+
+}  // namespace
+
+class ChromeWatcherClientTest : public testing::Test {
+ protected:
+  // Sends a signal to the simulated watcher process to exit. Returns true if
+  // successful.
+  bool SignalExit() { return ::SetEvent(exit_event_.Get()) != FALSE; }
+
+  // Sends a signal to the simulated watcher process to signal its
+  // "initialization". Returns true if successful.
+  bool SignalInitialize() {
+    return ::SetEvent(initialize_event_.Get()) != FALSE;
+  }
+
+  // The helper thread, which also provides access to the ChromeWatcherClient.
+  ChromeWatcherClientThread& thread() { return thread_; }
+
+  // testing::Test implementation.
+  void SetUp() override {
+    exit_event_.Set(::CreateEvent(
+        NULL, FALSE, FALSE,
+        (kExitEventBaseName + thread_.NamedEventSuffix()).c_str()));
+    ASSERT_TRUE(exit_event_.IsValid());
+    initialize_event_.Set(::CreateEvent(
+        NULL, FALSE, FALSE,
+        (kInitializeEventBaseName + thread_.NamedEventSuffix()).c_str()));
+    ASSERT_TRUE(initialize_event_.IsValid());
+  }
+
+  void TearDown() override {
+    // Even if we never launched, the following is harmless.
+    SignalExit();
+    int exit_code = 0;
+    thread_.client().WaitForExit(&exit_code);
+    thread_.Join();
+  }
+
+ private:
+  // Used to launch and block on the Chrome watcher process in a background
+  // thread.
+  ChromeWatcherClientThread thread_;
+  // Used to signal the Chrome watcher process to exit.
+  base::win::ScopedHandle exit_event_;
+  // Used to signal the Chrome watcher process to signal its own
+  // initialization..
+  base::win::ScopedHandle initialize_event_;
+};
+
+TEST_F(ChromeWatcherClientTest, SuccessTest) {
+  thread().Start();
+  bool result = false;
+  // Give a broken implementation a chance to exit unexpectedly.
+  ASSERT_FALSE(thread().WaitForResultWithTimeout(
+      base::TimeDelta::FromMilliseconds(100), &result));
+  ASSERT_TRUE(SignalInitialize());
+  ASSERT_TRUE(thread().WaitForResult());
+  // The watcher should still be running. Give a broken implementation a chance
+  // to exit unexpectedly, then signal it to exit.
+  int exit_code = 0;
+  ASSERT_FALSE(thread().client().WaitForExitWithTimeout(
+      base::TimeDelta::FromMilliseconds(100), &exit_code));
+  SignalExit();
+  ASSERT_TRUE(thread().client().WaitForExit(&exit_code));
+  ASSERT_EQ(0, exit_code);
+}
+
+TEST_F(ChromeWatcherClientTest, FailureTest) {
+  thread().Start();
+  bool result = false;
+  // Give a broken implementation a chance to exit unexpectedly.
+  ASSERT_FALSE(thread().WaitForResultWithTimeout(
+      base::TimeDelta::FromMilliseconds(100), &result));
+  ASSERT_TRUE(SignalExit());
+  ASSERT_FALSE(thread().WaitForResult());
+  int exit_code = 0;
+  ASSERT_TRUE(
+      thread().client().WaitForExitWithTimeout(base::TimeDelta(), &exit_code));
+  ASSERT_EQ(0, exit_code);
+}
diff --git a/chrome/app/chrome_watcher_client_win.cc b/chrome/app/chrome_watcher_client_win.cc
new file mode 100644
index 0000000..89f0709
--- /dev/null
+++ b/chrome/app/chrome_watcher_client_win.cc
@@ -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.
+
+#include "chrome/app/chrome_watcher_client_win.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "components/browser_watcher/watcher_client_win.h"
+
+namespace {
+
+// Because we can only bind parameters from the left, |parent_process| must be
+// the last parameter of the method that we bind int a
+// BrowserWatcherClient::CommandLineGenerator. The ChromeWatcherClient API is
+// more intuitive if the ChromeWatcherClient::CommandLineGenerator takes
+// |parent_process| as its second (of three) parameters, so we use this
+// intermediate function to swap the order.
+base::CommandLine InvokeCommandLineGenerator(
+    const ChromeWatcherClient::CommandLineGenerator& command_line_generator,
+    HANDLE on_initialized_event,
+    HANDLE parent_process) {
+  return command_line_generator.Run(parent_process, on_initialized_event);
+}
+
+}  // namespace
+
+ChromeWatcherClient::ChromeWatcherClient(
+    const CommandLineGenerator& command_line_generator)
+    : command_line_generator_(command_line_generator) {
+}
+
+ChromeWatcherClient::~ChromeWatcherClient() {
+}
+
+bool ChromeWatcherClient::LaunchWatcher() {
+  // Create an inheritable event that the child process will signal when it has
+  // completed initialization.
+  SECURITY_ATTRIBUTES on_initialized_event_attributes = {
+      sizeof(SECURITY_ATTRIBUTES),  // nLength
+      nullptr,                      // lpSecurityDescriptor
+      TRUE                          // bInheritHandle
+  };
+  on_initialized_event_.Set(::CreateEvent(&on_initialized_event_attributes,
+                                          TRUE,  // manual reset
+                                          FALSE, nullptr));
+  if (!on_initialized_event_.IsValid()) {
+    DPLOG(ERROR) << "Failed to create an event.";
+    return false;
+  }
+
+  // Configure the basic WatcherClient, binding in the initialization event
+  // HANDLE.
+  browser_watcher::WatcherClient watcher_client(
+      base::Bind(&InvokeCommandLineGenerator, command_line_generator_,
+                 on_initialized_event_.Get()));
+  // Indicate that the event HANDLE should be inherited.
+  watcher_client.AddInheritedHandle(on_initialized_event_.Get());
+  // Launch the watcher.
+  watcher_client.LaunchWatcher();
+  // Grab a handle to the watcher so that we may later wait on its
+  // initialization.
+  process_ = watcher_client.process().Duplicate();
+  if (!process_.IsValid())
+    on_initialized_event_.Close();
+  return process_.IsValid();
+}
+
+bool ChromeWatcherClient::EnsureInitialized() {
+  if (!process_.IsValid())
+    return false;
+
+  DCHECK(on_initialized_event_.IsValid());
+
+  HANDLE handles[] = {on_initialized_event_.Get(), process_.Handle()};
+  DWORD result = ::WaitForMultipleObjects(arraysize(handles), handles,
+                                          FALSE, INFINITE);
+
+  switch (result) {
+    case WAIT_OBJECT_0:
+      return true;
+    case WAIT_OBJECT_0 + 1:
+      LOG(ERROR) << "Chrome watcher process failed to launch.";
+      return false;
+    case WAIT_FAILED:
+      DPLOG(ERROR) << "Failure while waiting on Chrome watcher process launch.";
+      return false;
+    default:
+      NOTREACHED() << "Unexpected result while waiting on Chrome watcher "
+                      "process launch: " << result;
+      return false;
+  }
+}
+
+bool ChromeWatcherClient::WaitForExit(int* exit_code) {
+  return process_.IsValid() && process_.WaitForExit(exit_code);
+}
+
+bool ChromeWatcherClient::WaitForExitWithTimeout(base::TimeDelta timeout,
+                                                 int* exit_code) {
+  return process_.IsValid() &&
+         process_.WaitForExitWithTimeout(timeout, exit_code);
+}
diff --git a/chrome/app/chrome_watcher_client_win.h b/chrome/app/chrome_watcher_client_win.h
new file mode 100644
index 0000000..aaa8d140
--- /dev/null
+++ b/chrome/app/chrome_watcher_client_win.h
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_APP_CHROME_WATCHER_CLIENT_WIN_H_
+#define CHROME_APP_CHROME_WATCHER_CLIENT_WIN_H_
+
+#include <windows.h>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "base/process/process.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+
+// Launches a Chrome watcher process and permits the client to wait until the
+// process is fully initialized.
+class ChromeWatcherClient {
+ public:
+  // A CommandLineGenerator generates command lines that will launch a separate
+  // process and pass the supplied HANDLE values to WatcherMain in that process.
+  // The first HANDLE is the process that the watcher process should watch. The
+  // second HANDLE is an event that should be signaled when the watcher process
+  // is fully initialized. The process will be launched such that the HANDLEs
+  // are inherited by the new process.
+  typedef base::Callback<base::CommandLine(HANDLE, HANDLE)>
+      CommandLineGenerator;
+
+  // Constructs an instance that launches its watcher process using the command
+  // line generated by |command_line_generator|.
+  explicit ChromeWatcherClient(
+      const CommandLineGenerator& command_line_generator);
+
+  ~ChromeWatcherClient();
+
+  // Launches the watcher process such that the child process is able to inherit
+  // a handle to the current process. Returns true if the process is
+  // successfully launched.
+  bool LaunchWatcher();
+
+  // Blocks until the process, previously launched by LaunchWatcher, is either
+  // fully initialized or has terminated. Returns true if the process
+  // successfully initializes. May be called multiple times.
+  bool EnsureInitialized();
+
+  // Waits for the process to exit. Returns true on success. It is up to the
+  // client to somehow signal the process to exit.
+  bool WaitForExit(int* exit_code);
+
+  // Same as WaitForExit() but only waits for up to |timeout|.
+  bool WaitForExitWithTimeout(base::TimeDelta timeout, int* exit_code);
+
+ private:
+  CommandLineGenerator command_line_generator_;
+  base::win::ScopedHandle on_initialized_event_;
+  base::Process process_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeWatcherClient);
+};
+
+#endif  // CHROME_APP_CHROME_WATCHER_CLIENT_WIN_H_
diff --git a/chrome/app/chrome_watcher_command_line_unittest_win.cc b/chrome/app/chrome_watcher_command_line_unittest_win.cc
index 0cf6927..771094f0 100644
--- a/chrome/app/chrome_watcher_command_line_unittest_win.cc
+++ b/chrome/app/chrome_watcher_command_line_unittest_win.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/app/chrome_watcher_command_line_win.h"
 
+#include <windows.h>
+
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/process/process_handle.h"
@@ -11,10 +13,19 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(ChromeWatcherCommandLineTest, BasicTest) {
+  // Ownership of these handles is passed to the ScopedHandles below via
+  // InterpretChromeWatcherCommandLine().
   base::ProcessHandle current = nullptr;
   ASSERT_TRUE(base::OpenProcessHandle(base::GetCurrentProcId(), &current));
-  base::CommandLine cmd_line =
-      GenerateChromeWatcherCommandLine(base::FilePath(L"example.exe"), current);
-  base::win::ScopedHandle result = InterpretChromeWatcherCommandLine(cmd_line);
-  ASSERT_EQ(current, result.Get());
+  HANDLE event = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
+
+  base::CommandLine cmd_line = GenerateChromeWatcherCommandLine(
+      base::FilePath(L"example.exe"), current, event);
+
+  base::win::ScopedHandle current_result;
+  base::win::ScopedHandle event_result;
+  ASSERT_TRUE(InterpretChromeWatcherCommandLine(cmd_line, &current_result,
+                                                &event_result));
+  ASSERT_EQ(current, current_result.Get());
+  ASSERT_EQ(event, event_result.Get());
 }
diff --git a/chrome/app/chrome_watcher_command_line_win.cc b/chrome/app/chrome_watcher_command_line_win.cc
index 0093863..1eaf1a66 100644
--- a/chrome/app/chrome_watcher_command_line_win.cc
+++ b/chrome/app/chrome_watcher_command_line_win.cc
@@ -14,41 +14,91 @@
 #include "chrome/common/chrome_switches.h"
 
 namespace {
+
+const char kOnIninitializedEventHandleSwitch[] = "on-initialized-event-handle";
 const char kParentHandleSwitch[] = "parent-handle";
+
+void AppendHandleSwitch(const std::string& switch_name,
+                        HANDLE handle,
+                        base::CommandLine* command_line) {
+  command_line->AppendSwitchASCII(
+      switch_name, base::UintToString(reinterpret_cast<unsigned int>(handle)));
+}
+
+HANDLE ReadHandleFromSwitch(const base::CommandLine& command_line,
+                            const std::string& switch_name) {
+  std::string switch_string = command_line.GetSwitchValueASCII(switch_name);
+  unsigned int switch_uint = 0;
+  if (switch_string.empty() ||
+      !base::StringToUint(switch_string, &switch_uint)) {
+    DLOG(ERROR) << "Missing or invalid " << switch_name << " argument.";
+    return nullptr;
+  }
+  return reinterpret_cast<HANDLE>(switch_uint);
+}
+
 }  // namespace
 
 base::CommandLine GenerateChromeWatcherCommandLine(
     const base::FilePath& chrome_exe,
-    HANDLE parent_process) {
+    HANDLE parent_process,
+    HANDLE on_initialized_event) {
   base::CommandLine command_line(chrome_exe);
   command_line.AppendSwitchASCII(switches::kProcessType, "watcher");
-  command_line.AppendSwitchASCII(
-      kParentHandleSwitch,
-      base::UintToString(reinterpret_cast<unsigned int>(parent_process)));
+  AppendHandleSwitch(kOnIninitializedEventHandleSwitch, on_initialized_event,
+                     &command_line);
+  AppendHandleSwitch(kParentHandleSwitch, parent_process, &command_line);
   return command_line;
 }
 
-base::win::ScopedHandle InterpretChromeWatcherCommandLine(
-    const base::CommandLine& command_line) {
-  std::string parent_handle_str =
-      command_line.GetSwitchValueASCII(kParentHandleSwitch);
-  unsigned parent_handle_uint = 0;
-  if (parent_handle_str.empty() ||
-      !base::StringToUint(parent_handle_str, &parent_handle_uint)) {
-    LOG(ERROR) << "Missing or invalid " << kParentHandleSwitch << " argument.";
-    return base::win::ScopedHandle();
+bool InterpretChromeWatcherCommandLine(
+    const base::CommandLine& command_line,
+    base::win::ScopedHandle* parent_process,
+    base::win::ScopedHandle* on_initialized_event) {
+  DCHECK(on_initialized_event);
+  DCHECK(parent_process);
+
+  // For consistency, always close any existing HANDLEs here.
+  on_initialized_event->Close();
+  parent_process->Close();
+
+  HANDLE parent_handle =
+      ReadHandleFromSwitch(command_line, kParentHandleSwitch);
+  HANDLE on_initialized_event_handle =
+      ReadHandleFromSwitch(command_line, kOnIninitializedEventHandleSwitch);
+
+  if (parent_handle) {
+    // Initial test of the handle, a zero PID indicates invalid handle, or not
+    // a process handle. In this case, parsing fails and we avoid closing the
+    // handle.
+    DWORD process_pid = ::GetProcessId(parent_handle);
+    if (process_pid == 0) {
+      DLOG(ERROR) << "Invalid " << kParentHandleSwitch
+                  << " argument. Can't get parent PID.";
+    } else {
+      parent_process->Set(parent_handle);
+    }
   }
 
-  HANDLE parent_process = reinterpret_cast<HANDLE>(parent_handle_uint);
-  // Initial test of the handle, a zero PID indicates invalid handle, or not
-  // a process handle. In this case, parsing fails and we avoid closing the
-  // handle.
-  DWORD process_pid = ::GetProcessId(parent_process);
-  if (process_pid == 0) {
-    LOG(ERROR) << "Invalid " << kParentHandleSwitch
-               << " argument. Can't get parent PID.";
-    return base::win::ScopedHandle();
+  if (on_initialized_event_handle) {
+    DWORD result = ::WaitForSingleObject(on_initialized_event_handle, 0);
+    if (result == WAIT_FAILED) {
+      DPLOG(ERROR)
+          << "Unexpected error while testing the initialization event.";
+    } else if (result != WAIT_TIMEOUT) {
+      DLOG(ERROR) << "Unexpected result while testing the initialization event "
+                     "with WaitForSingleObject: " << result;
+    } else {
+      on_initialized_event->Set(on_initialized_event_handle);
+    }
   }
 
-  return base::win::ScopedHandle(parent_process);
+  if (!on_initialized_event->IsValid() || !parent_process->IsValid()) {
+    // If one was valid and not the other, free the valid one.
+    on_initialized_event->Close();
+    parent_process->Close();
+    return false;
+  }
+
+  return true;
 }
diff --git a/chrome/app/chrome_watcher_command_line_win.h b/chrome/app/chrome_watcher_command_line_win.h
index 30ff988..4b4596a 100644
--- a/chrome/app/chrome_watcher_command_line_win.h
+++ b/chrome/app/chrome_watcher_command_line_win.h
@@ -15,15 +15,21 @@
 }  // namespace base
 
 // Generates a CommandLine that will launch |chrome_exe| in Chrome Watcher mode
-// to observe |parent_process|.
+// to observe |parent_process|. The watcher process will signal
+// |on_initialized_event| when its initialization is complete.
 base::CommandLine GenerateChromeWatcherCommandLine(
     const base::FilePath& chrome_exe,
-    HANDLE parent_process);
+    HANDLE parent_process,
+    HANDLE on_initialized_event);
 
 // Interprets the Command Line used to launch a Chrome Watcher process and
-// extracts the parent process HANDLE. Verifies that the handle is usable in
-// this process before returning it, and returns NULL in case of a failure.
-base::win::ScopedHandle InterpretChromeWatcherCommandLine(
-    const base::CommandLine& command_line);
+// extracts the parent process and initialization event HANDLEs. Verifies that
+// the handles are usable in this process before returning them. Returns true if
+// both handles are successfully parsed and false otherwise. If only one of the
+// handles can be parsed, it will be closed.
+bool InterpretChromeWatcherCommandLine(
+    const base::CommandLine& command_line,
+    base::win::ScopedHandle* parent_process,
+    base::win::ScopedHandle* on_initialized_event);
 
 #endif  // CHROME_APP_CHROME_WATCHER_COMMAND_LINE_WIN_H_
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 9ca874c..a3c1b9bb 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -6035,11 +6035,11 @@
     System time
   </message>
 
-  <message name="IDS_FLAGS_ENABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME" desc="Title for the flag to enable/disable user setting to automatically update timezone by user geolocation.">
-    Automatically resolve timezone by geolocation
+  <message name="IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME" desc="Title for the flag to disable automatic timezone update on user location change.">
+    Disable automatic timezone update by geolocation
   </message>
-  <message name="IDS_FLAGS_ENABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION" desc="Description for the flag to enable/disable user setting to automatically update timezone by user geolocation.">
-    If enabled, in chrome://settings a new option becomes available which allows automatically updating the timezone by the current geolocation.
+  <message name="IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION" desc="Description for the flag to disable user setting to automatically update timezone by user geolocation.">
+    If set, automatic timezone update by the current geolocation is turned off.
   </message>
   <message name="IDS_OPTIONS_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION" desc="Label for checkbox to allow automatic timezone update by user geolocation.">
     Automatically resolve timezone by geolocation
diff --git a/chrome/app/client_util.cc b/chrome/app/client_util.cc
index 4316226..738ae9e 100644
--- a/chrome/app/client_util.cc
+++ b/chrome/app/client_util.cc
@@ -21,6 +21,7 @@
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
 #include "chrome/app/chrome_crash_reporter_client.h"
+#include "chrome/app/chrome_watcher_client_win.h"
 #include "chrome/app/chrome_watcher_command_line_win.h"
 #include "chrome/app/client_util.h"
 #include "chrome/app/image_pre_reader_win.h"
@@ -33,7 +34,6 @@
 #include "chrome/installer/util/google_update_settings.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/util_constants.h"
-#include "components/browser_watcher/watcher_client_win.h"
 #include "components/crash/app/breakpad_win.h"
 #include "components/crash/app/crash_reporter_client.h"
 #include "components/metrics/client_info.h"
@@ -179,10 +179,12 @@
   }
 
   if (process_type_ == "watcher") {
-    base::win::ScopedHandle parent_process =
-        InterpretChromeWatcherCommandLine(cmd_line);
-    if (!parent_process.IsValid())
+    base::win::ScopedHandle parent_process;
+    base::win::ScopedHandle on_initialized_event;
+    if (!InterpretChromeWatcherCommandLine(cmd_line, &parent_process,
+                                           &on_initialized_event)) {
       return chrome::RESULT_CODE_UNSUPPORTED_PARAM;
+    }
 
     // Intentionally leaked.
     HMODULE watcher_dll = Load(&version, &file);
@@ -193,7 +195,7 @@
         reinterpret_cast<ChromeWatcherMainFunction>(
             ::GetProcAddress(watcher_dll, kChromeWatcherDLLEntrypoint));
     return watcher_main(chrome::kBrowserExitCodesRegistryPath,
-                        parent_process.Take());
+                        parent_process.Take(), on_initialized_event.Take());
   }
 
   // Initialize the sandbox services.
@@ -260,8 +262,7 @@
     if (g_chrome_crash_client.Get().GetCollectStatsConsent()) {
       base::char16 exe_path[MAX_PATH];
       ::GetModuleFileNameW(nullptr, exe_path, arraysize(exe_path));
-
-      browser_watcher::WatcherClient watcher_client(base::Bind(
+      ChromeWatcherClient watcher_client(base::Bind(
           &GenerateChromeWatcherCommandLine, base::FilePath(exe_path)));
       watcher_client.LaunchWatcher();
     }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e266b56..72ac2c8 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5406,6 +5406,14 @@
         </message>
       </if>
 
+      <!-- chrome://md-settings/ - the Material Design Settings page -->
+      <message name="IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_NAME" desc="Name for the flag to enable the material design Settings page.">
+          Enable Material Design settings
+      </message>
+      <message name="IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_DESCRIPTION" desc="Description for the flag to enable the material design Settings page.">
+          If enabled, the chrome://md-settings/ URL loads the Material Design settings page.
+      </message>
+
       <!-- Packaged Apps -->
       <message name="IDS_APP_INSTALL_TITLE" desc="Caption for installing an ephemeral app">
         Install app
@@ -6300,6 +6308,12 @@
       <message name="IDS_FLAGS_ENABLE_SAVE_PASSOWRD_ON_IN_PAGE_NAVIGATION_DESCRIPTION" desc="Description of the flag to enable showing of password save prompt on in-page navigations">
         Enable showing of the password prompt on in-page navigations. This allows for saving passwords on more pages but might sometimes trigger the prompt on unsuccessful login attempts.
       </message>
+      <message name="IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_NAME" desc="Name of the flag to enable affiliation based matching, so that credentials stored for an Android application will also be considered matches for, and be filled into corresponding websites (so-called 'affiliated' websites).">
+        Enable affiliation based matching in password manager.
+      </message>
+      <message name="IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_DESCRIPTION" desc="Description of the flag to enable affiliation based matching, so that credentials stored for an Android application will also be considered matches for, and be filled into corresponding websites (so-called 'affiliated' websites).">
+        Allow credentials stored for Android applications to be filled into corresponding websites.
+      </message>
       <message name="IDS_FLAGS_AUTOFILL_SYNC_CREDENTIAL_NAME" desc="Name of the flag specifying how the browser will handle autofilling the users sync credential.">
         Autofill sync credential
       </message>
@@ -6664,21 +6678,6 @@
       <message name="IDS_FLAGS_OUT_OF_PROCESS_PDF_DESCRIPTION" desc="Description for the flag to enable out of process PDF.">
         Enable the out of process PDF plugin.
       </message>
-      <message name="IDS_FLAGS_TOUCH_SCROLLING_MODE_NAME" desc="Title for the flag to change the touch scrolling mode.">
-        Touch scrolling mode.
-      </message>
-      <message name="IDS_FLAGS_TOUCH_SCROLLING_MODE_DESCRIPTION" desc="Description for the flag to control touch scrolling mode.">
-        Change the touch event behavior while scrolling.  "touchcancel" is what Chrome has historically used, and "async-touchmove" is the new preferred mode.
-      </message>
-      <message name="IDS_FLAGS_TOUCH_SCROLLING_MODE_TOUCHCANCEL" desc="Name for the touchcancel scrolling mode">
-        touchcancel
-      </message>
-      <message name="IDS_FLAGS_TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE" desc="Name for the async-touchmove scrolling mode">
-        async-touchmove
-      </message>
-      <message name="IDS_FLAGS_TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE" desc="Name for the sync-touchmove scrolling mode">
-        sync-touchmove
-      </message>
       <message name="IDS_FLAGS_DISABLE_THREADED_SCROLLING_NAME" desc="Title for the flag to disable threaded scrolling.">
         Disable threaded scrolling.
       </message>
@@ -15264,12 +15263,6 @@
       <message name="IDS_EASY_UNLOCK_SETUP_ERROR_FINDING_PHONE" desc="A generic catch-all error message to display when something goes wrong after the user clicks 'Find my phone' during Easy Unlock setup. Note that the &lt;a&gt; element surrounds a link; these HTML elements should be preserved in the translation.">
         Can’t find your phone. Make sure you’re using a compatible Android phone that’s turned on and within arm’s reach. &lt;a&gt;Learn more&lt;/a&gt;
       </message>
-      <message name="IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_CONNECTION_FAILED" desc="The error message to display when the Bluetooth connection between the phone and the Chromebook is disconnected during Easy Unlock setup. Note that the &lt;a&gt; element surrounds a link; these HTML elements should be preserved in the translation.">
-        Couldn’t establish a connection with your phone. Make sure Bluetooth is turned on for both of your devices. &lt;a&gt;Learn more&lt;/a&gt;
-      </message>
-      <message name="IDS_EASY_UNLOCK_SETUP_ERROR_CONNECT_TO_PHONE_TIMEOUT" desc="The error message to display when the Chromebook is unable to establish connection to the phone within a reasonable amount of time. Note that the &lt;a&gt; element surrounds a link; these HTML elements should be preserved in the translation.">
-        Couldn’t establish a connection with your phone. Make sure you’re using a compatible Android phone that is turned on and within arm’s reach. &lt;a&gt;Learn more&lt;/a&gt;
-      </message>
       <message name="IDS_EASY_UNLOCK_SETUP_ERROR_SYNC_PHONE_STATE_FAILED" desc="The error message to display when the Chromebook fails to sync the phone's state.">
         Smart Lock is currently unavailable. Please try again later.
       </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7359d61..5a65805e 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1016,10 +1016,10 @@
       "chromeos/login/ui/mock_login_display_host.h",
       "chromeos/login/users/avatar/mock_user_image_manager.cc",
       "chromeos/login/users/avatar/mock_user_image_manager.h",
+      "chromeos/login/users/fake_chrome_user_manager.cc",
+      "chromeos/login/users/fake_chrome_user_manager.h",
       "chromeos/login/users/fake_supervised_user_manager.cc",
       "chromeos/login/users/fake_supervised_user_manager.h",
-      "chromeos/login/users/fake_user_manager.cc",
-      "chromeos/login/users/fake_user_manager.h",
       "chromeos/login/users/mock_user_manager.cc",
       "chromeos/login/users/mock_user_manager.h",
       "chromeos/net/network_portal_detector_test_utils.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b002070e..79c734b7 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -334,19 +334,6 @@
   { IDS_FLAGS_ORIGIN_CHIP_ON_SRP, switches::kEnableOriginChipOnSrp, ""}
 };
 
-const Experiment::Choice kTouchScrollingModeChoices[] = {
-  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
-  { IDS_FLAGS_TOUCH_SCROLLING_MODE_TOUCHCANCEL,
-    switches::kTouchScrollingMode,
-    switches::kTouchScrollingModeTouchcancel },
-  { IDS_FLAGS_TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE,
-    switches::kTouchScrollingMode,
-    switches::kTouchScrollingModeAsyncTouchmove },
-  { IDS_FLAGS_TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE,
-    switches::kTouchScrollingMode,
-    switches::kTouchScrollingModeSyncTouchmove },
-};
-
 const Experiment::Choice kExtensionContentVerificationChoices[] = {
   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
   { IDS_FLAGS_EXTENSION_CONTENT_VERIFICATION_BOOTSTRAP,
@@ -1051,6 +1038,15 @@
              autofill::switches::kEnablePasswordSaveOnInPageNavigation)
   },
   {
+    "enable-affiliation-based-matching",
+    IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_NAME,
+    IDS_FLAGS_ENABLE_AFFILIATION_BASED_MATCHING_DESCRIPTION,
+    kOsWin | kOsLinux | kOsCrOS | kOsMac | kOsAndroid,
+    ENABLE_DISABLE_VALUE_TYPE(
+        password_manager::switches::kEnableAffiliationBasedMatching,
+        password_manager::switches::kDisableAffiliationBasedMatching)
+  },
+  {
     "enable-deferred-image-decoding",
     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_NAME,
     IDS_FLAGS_ENABLE_DEFERRED_IMAGE_DECODING_DESCRIPTION,
@@ -1761,13 +1757,6 @@
   },
 #endif
   {
-    "touch-scrolling-mode",
-    IDS_FLAGS_TOUCH_SCROLLING_MODE_NAME,
-    IDS_FLAGS_TOUCH_SCROLLING_MODE_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS | kOsAndroid,
-    MULTI_VALUE_TYPE(kTouchScrollingModeChoices)
-  },
-  {
     "disable-threaded-scrolling",
     IDS_FLAGS_DISABLE_THREADED_SCROLLING_NAME,
     IDS_FLAGS_DISABLE_THREADED_SCROLLING_DESCRIPTION,
@@ -1981,6 +1970,14 @@
     SINGLE_VALUE_TYPE(
         switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)
   },
+  {
+    "enable-md-settings",
+    IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_NAME,
+    IDS_FLAGS_ENABLE_MATERIAL_DESIGN_SETTINGS_DESCRIPTION,
+    kOsDesktop,
+    SINGLE_VALUE_TYPE(
+        switches::kEnableMaterialDesignSettings)
+  },
 #endif
 #if defined(OS_CHROMEOS)
   {
@@ -2148,11 +2145,11 @@
 #endif  // defined(OS_MACOSX)
 #if defined(OS_CHROMEOS)
   {
-    "enable-timezone-tracking",
-    IDS_FLAGS_ENABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME,
-    IDS_FLAGS_ENABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION,
+    "disable-timezone-tracking",
+    IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME,
+    IDS_FLAGS_DISABLE_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION,
     kOsCrOS,
-    SINGLE_VALUE_TYPE(chromeos::switches::kEnableTimeZoneTrackingOption)
+    SINGLE_VALUE_TYPE(chromeos::switches::kDisableTimeZoneTrackingOption)
   },
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/chrome/browser/android/accessibility/font_size_prefs_android.h b/chrome/browser/android/accessibility/font_size_prefs_android.h
index 05985c66..af8f75d6 100644
--- a/chrome/browser/android/accessibility/font_size_prefs_android.h
+++ b/chrome/browser/android/accessibility/font_size_prefs_android.h
@@ -64,8 +64,8 @@
   static bool Register(JNIEnv* env);
 
   // FontSizePrefs::Observer implementation.
-  virtual void OnChangeFontSize(float font) override;
-  virtual void OnChangeForceEnableZoom(bool enabled) override;
+  void OnChangeFontSize(float font) override;
+  void OnChangeForceEnableZoom(bool enabled) override;
 
  private:
   base::android::ScopedJavaGlobalRef<jobject> java_ref_;
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate.cc b/chrome/browser/android/banners/app_banner_infobar_delegate.cc
index 0cd6679..dfa580f 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate.cc
@@ -6,25 +6,26 @@
 
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/ui/android/infobars/app_banner_infobar.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/infobar.h"
+#include "components/infobars/core/infobar_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace banners {
 
 infobars::InfoBar* AppBannerInfoBarDelegate::CreateForWebApp(
-    InfoBarService* infobar_service,
-    const AppDelegate* helper,
+    infobars::InfoBarManager* infobar_manager,
+    const AppDelegate* app_delegate,
     const base::string16& app_name,
     const GURL& url) {
-  AppBannerInfoBarDelegate* const delegate = new AppBannerInfoBarDelegate(
-      helper,
+  scoped_ptr<AppBannerInfoBarDelegate> delegate(new AppBannerInfoBarDelegate(
+      app_delegate,
       app_name,
-      url);
+      url));
 
-  return infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
-      scoped_ptr<ConfirmInfoBarDelegate>(delegate)));
+  return infobar_manager->AddInfoBar(
+      make_scoped_ptr(new AppBannerInfoBar(delegate.Pass(), url)));
 }
 
 AppBannerInfoBarDelegate::AppBannerInfoBarDelegate(
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate.h b/chrome/browser/android/banners/app_banner_infobar_delegate.h
index 5f95a7e9..01fddc6 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate.h
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate.h
@@ -10,7 +10,9 @@
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
 
-class InfoBarService;
+namespace infobars {
+class InfoBarManager;
+}  // namespace infobars
 
 namespace banners {
 
@@ -33,10 +35,13 @@
 
   // Creates a banner for the current page.
   // May return nullptr if the the infobar couldn't be created.
-  static infobars::InfoBar* CreateForWebApp(InfoBarService* infobar_service,
-                                            const AppDelegate* helper,
-                                            const base::string16& app_title,
-                                            const GURL& url);
+  static infobars::InfoBar* CreateForWebApp(
+      infobars::InfoBarManager* infobar_manager,
+      const AppDelegate* delegate,
+      const base::string16& app_title,
+      const GURL& url);
+
+  ~AppBannerInfoBarDelegate() override;
 
   // Changes the label of the button.
   void SetButtonLabel(const std::string& button_text);
@@ -57,8 +62,6 @@
                            const base::string16& app_title,
                            const GURL& url);
 
-  ~AppBannerInfoBarDelegate() override;
-
   const AppDelegate* delegate_;
   base::string16 app_title_;
   GURL url_;
@@ -69,4 +72,6 @@
 
 }  // namespace banners
 
+bool RegisterAppBannerInfoBarDelegate(JNIEnv* env);
+
 #endif  // CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/android/banners/app_banner_manager.cc b/chrome/browser/android/banners/app_banner_manager.cc
index 316a036d..cbd87921 100644
--- a/chrome/browser/android/banners/app_banner_manager.cc
+++ b/chrome/browser/android/banners/app_banner_manager.cc
@@ -9,9 +9,13 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
+#include "base/threading/worker_pool.h"
 #include "chrome/browser/android/banners/app_banner_infobar_delegate.h"
 #include "chrome/browser/android/banners/app_banner_metrics_ids.h"
 #include "chrome/browser/android/banners/app_banner_utilities.h"
+#include "chrome/browser/android/manifest_icon_selector.h"
+#include "chrome/browser/android/shortcut_helper.h"
+#include "chrome/browser/android/shortcut_info.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -28,6 +32,7 @@
 #include "jni/AppBannerManager_jni.h"
 #include "net/base/load_flags.h"
 #include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/screen.h"
 
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
@@ -75,7 +80,7 @@
     return;
 
   if (!manifest_.IsEmpty()) {
-    // TODO(dfalcantara): Trigger shortcut creation.
+    InstallManifestApp(manifest_, *app_icon_.get());
   }
 }
 
@@ -125,8 +130,10 @@
   if (web_contents()->IsBeingDestroyed())
     return;
 
-  if (manifest.IsEmpty()) {
-    // No manifest, see if there is a play store meta tag.
+  if (manifest.IsEmpty()
+      || !manifest.start_url.is_valid()
+      || (manifest.name.is_null() && manifest.short_name.is_null())) {
+    // No usable manifest, see if there is a play store meta tag.
     Send(new ChromeViewMsg_RetrieveMetaTagContent(routing_id(),
                                                   validated_url_,
                                                   kBannerTag));
@@ -139,17 +146,13 @@
   // Create an infobar to promote the manifest's app.
   manifest_ = manifest;
 
-  /* TODO(dfalcantara): Use after landing https://crrev.com/880203004.
   GURL icon_url =
-      ManifestIconSelector::FindBestMatchingIcon(manifest.icons,
-                                                 GetPreferredIconSize(),
-                                                 web_contents());
+      ManifestIconSelector::FindBestMatchingIcon(
+          manifest.icons,
+          GetPreferredIconSize(),
+          gfx::Screen::GetScreenFor(web_contents()->GetNativeView()));
   if (icon_url.is_empty())
     return;
-  */
-  if (manifest.icons.empty())
-    return;
-  GURL icon_url = manifest.icons.back().src;
 
   FetchIcon(icon_url);
 }
@@ -268,6 +271,20 @@
   return Java_AppBannerManager_getPreferredIconSize(env, jobj.obj());
 }
 
+// static
+void AppBannerManager::InstallManifestApp(const content::Manifest& manifest,
+                                          const SkBitmap& icon) {
+  ShortcutInfo info;
+  info.UpdateFromManifest(manifest);
+
+  base::WorkerPool::PostTask(
+      FROM_HERE,
+      base::Bind(&ShortcutHelper::AddShortcutInBackgroundWithSkBitmap,
+                 info,
+                 icon),
+      true);
+}
+
 void RecordDismissEvent(JNIEnv* env, jclass clazz, jint metric) {
   banners::TrackDismissEvent(metric);
 }
diff --git a/chrome/browser/android/banners/app_banner_manager.h b/chrome/browser/android/banners/app_banner_manager.h
index dd30b13e..12ae72a3 100644
--- a/chrome/browser/android/banners/app_banner_manager.h
+++ b/chrome/browser/android/banners/app_banner_manager.h
@@ -64,7 +64,7 @@
                          public AppBannerInfoBarDelegate::AppDelegate {
  public:
   AppBannerManager(JNIEnv* env, jobject obj);
-  virtual ~AppBannerManager();
+  ~AppBannerManager() override;
 
   // Destroys the AppBannerManager.
   void Destroy(JNIEnv* env, jobject obj);
@@ -87,21 +87,26 @@
   // Returns |false| if this couldn't be kicked off.
   bool FetchIcon(const GURL& image_url);
 
+  // Installs the app defined by the manifest.
+  // TODO(dfalcantara): Fold into Install() when more CLs land.
+  static void InstallManifestApp(const content::Manifest& manifest,
+                                 const SkBitmap& icon);
+
   // WebContentsObserver overrides.
-  virtual void DidNavigateMainFrame(
+  void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
-  virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host,
-                             const GURL& validated_url) override;
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
+  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+                     const GURL& validated_url) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
 
   // BitmapFetcherDelegate overrides.
-  virtual void OnFetchComplete(const GURL url, const SkBitmap* bitmap) override;
+  void OnFetchComplete(const GURL url, const SkBitmap* bitmap) override;
 
   // AppBannerInfoBarDelegate::AppDelegate overrides.
-  virtual void Block() const override;
-  virtual void Install() const override;
-  virtual gfx::Image GetIcon() const override;
+  void Block() const override;
+  void Install() const override;
+  gfx::Image GetIcon() const override;
 
  private:
   // Gets the preferred icon size for the banner icons.
diff --git a/chrome/browser/android/bookmarks/bookmarks_bridge.h b/chrome/browser/android/bookmarks/bookmarks_bridge.h
index cb182cf..8a283e8 100644
--- a/chrome/browser/android/bookmarks/bookmarks_bridge.h
+++ b/chrome/browser/android/bookmarks/bookmarks_bridge.h
@@ -152,7 +152,7 @@
   base::string16 GetTitle(const BookmarkNode* node) const;
 
  private:
-  virtual ~BookmarksBridge();
+  ~BookmarksBridge() override;
 
   base::android::ScopedJavaLocalRef<jobject> CreateJavaBookmark(
       const BookmarkNode* node);
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_shim.h b/chrome/browser/android/bookmarks/partner_bookmarks_shim.h
index 75461b78..cddfb02 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_shim.h
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_shim.h
@@ -121,7 +121,7 @@
 
  private:
   explicit PartnerBookmarksShim(PrefService* prefs);
-  virtual ~PartnerBookmarksShim();
+  ~PartnerBookmarksShim() override;
 
   const BookmarkNode* GetNodeByID(const BookmarkNode* parent, int64 id) const;
   void ReloadNodeMapping();
diff --git a/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc b/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc
index 304fc64..ecafdbd 100644
--- a/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc
+++ b/chrome/browser/android/bookmarks/partner_bookmarks_shim_unittest.cc
@@ -60,7 +60,7 @@
 
  protected:
   // testing::Test
-  virtual void SetUp() override {
+  void SetUp() override {
     profile_.reset(new TestingProfile());
     profile_->CreateBookmarkModel(true);
 
@@ -68,7 +68,7 @@
     bookmarks::test::WaitForBookmarkModelToLoad(model_);
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     PartnerBookmarksShim::ClearInBrowserContextForTesting(profile_.get());
     PartnerBookmarksShim::ClearPartnerModelForTesting();
     PartnerBookmarksShim::EnablePartnerBookmarksEditing();
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 5163dac..584af842 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/android/accessibility/font_size_prefs_android.h"
 #include "chrome/browser/android/accessibility_util.h"
 #include "chrome/browser/android/appmenu/app_menu_drag_helper.h"
+#include "chrome/browser/android/banners/app_banner_infobar_delegate.h"
 #include "chrome/browser/android/banners/app_banner_manager.h"
 #include "chrome/browser/android/bookmarks/bookmarks_bridge.h"
 #include "chrome/browser/android/bookmarks/partner_bookmarks_reader.h"
@@ -128,6 +129,7 @@
     {"AndroidProfileOAuth2TokenService",
      AndroidProfileOAuth2TokenService::Register},
     {"AnswersImageBridge", RegisterAnswersImageBridge},
+    {"AppBannerInfoBarDelegate", RegisterAppBannerInfoBarDelegate},
     {"AppBannerManager", banners::RegisterAppBannerManager},
     {"ApplicationLifetime", RegisterApplicationLifetimeAndroid},
     {"AutocompleteControllerAndroid", RegisterAutocompleteControllerAndroid},
diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.cc b/chrome/browser/android/chrome_web_contents_delegate_android.cc
index 0372797..6a71f28 100644
--- a/chrome/browser/android/chrome_web_contents_delegate_android.cc
+++ b/chrome/browser/android/chrome_web_contents_delegate_android.cc
@@ -308,7 +308,7 @@
     WebContents* source,
     WebContents* new_contents,
     WindowOpenDisposition disposition,
-    const gfx::Rect& initial_pos,
+    const gfx::Rect& initial_rect,
     bool user_gesture,
     bool* was_blocked) {
   // No code for this yet.
@@ -320,8 +320,7 @@
 
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
-  AddWebContentsResult add_result =
-      ADD_WEB_CONTENTS_RESULT_STOP_LOAD_AND_DELETE;
+  bool handled = false;
   if (!obj.is_null()) {
     ScopedJavaLocalRef<jobject> jsource;
     if (source)
@@ -330,21 +329,19 @@
     if (new_contents)
       jnew_contents = new_contents->GetJavaWebContents();
 
-    add_result = static_cast<AddWebContentsResult>(
-        Java_ChromeWebContentsDelegateAndroid_addNewContents(
-            env,
-            obj.obj(),
-            jsource.obj(),
-            jnew_contents.obj(),
-            static_cast<jint>(disposition),
-            NULL,
-            user_gesture));
+    handled = Java_ChromeWebContentsDelegateAndroid_addNewContents(
+        env,
+        obj.obj(),
+        jsource.obj(),
+        jnew_contents.obj(),
+        static_cast<jint>(disposition),
+        NULL,
+        user_gesture);
   }
 
   if (was_blocked)
-    *was_blocked = !(add_result == ADD_WEB_CONTENTS_RESULT_PROCEED);
-
-  if (add_result == ADD_WEB_CONTENTS_RESULT_STOP_LOAD_AND_DELETE)
+    *was_blocked = !handled;
+  if (!handled)
     delete new_contents;
 }
 
diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.h b/chrome/browser/android/chrome_web_contents_delegate_android.h
index 2ca7b8c..c1c6811 100644
--- a/chrome/browser/android/chrome_web_contents_delegate_android.h
+++ b/chrome/browser/android/chrome_web_contents_delegate_android.h
@@ -27,16 +27,6 @@
 namespace chrome {
 namespace android {
 
-// An enum with the result of calling AddNewContents() in Java.
-//
-// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser
-enum AddWebContentsResult {
-  ADD_WEB_CONTENTS_RESULT_PROCEED,
-  ADD_WEB_CONTENTS_RESULT_STOP_LOAD,
-  ADD_WEB_CONTENTS_RESULT_STOP_LOAD_AND_DELETE
-};
-
 // Chromium Android specific WebContentsDelegate.
 // Should contain any WebContentsDelegate implementations required by
 // the Chromium Android port but not to be shared with WebView.
@@ -45,53 +35,52 @@
       public content::NotificationObserver {
  public:
   ChromeWebContentsDelegateAndroid(JNIEnv* env, jobject obj);
-  virtual ~ChromeWebContentsDelegateAndroid();
+  ~ChromeWebContentsDelegateAndroid() override;
 
-  virtual void LoadingStateChanged(content::WebContents* source,
-                                   bool to_different_document) override;
-  virtual void RunFileChooser(content::WebContents* web_contents,
-                              const content::FileChooserParams& params)
-                              override;
-  virtual void CloseContents(content::WebContents* web_contents) override;
-  virtual void FindReply(content::WebContents* web_contents,
-                         int request_id,
-                         int number_of_matches,
-                         const gfx::Rect& selection_rect,
-                         int active_match_ordinal,
-                         bool final_update) override;
-  virtual void FindMatchRectsReply(content::WebContents* web_contents,
-                                   int version,
-                                   const std::vector<gfx::RectF>& rects,
-                                   const gfx::RectF& active_rect) override;
-  virtual content::JavaScriptDialogManager*
-  GetJavaScriptDialogManager(content::WebContents* source) override;
-  virtual void RequestMediaAccessPermission(
+  void LoadingStateChanged(content::WebContents* source,
+                           bool to_different_document) override;
+  void RunFileChooser(content::WebContents* web_contents,
+                      const content::FileChooserParams& params) override;
+  void CloseContents(content::WebContents* web_contents) override;
+  void FindReply(content::WebContents* web_contents,
+                 int request_id,
+                 int number_of_matches,
+                 const gfx::Rect& selection_rect,
+                 int active_match_ordinal,
+                 bool final_update) override;
+  void FindMatchRectsReply(content::WebContents* web_contents,
+                           int version,
+                           const std::vector<gfx::RectF>& rects,
+                           const gfx::RectF& active_rect) override;
+  content::JavaScriptDialogManager* GetJavaScriptDialogManager(
+      content::WebContents* source) override;
+  void RequestMediaAccessPermission(
       content::WebContents* web_contents,
       const content::MediaStreamRequest& request,
       const content::MediaResponseCallback& callback) override;
-  virtual bool CheckMediaAccessPermission(
-      content::WebContents* web_contents,
-      const GURL& security_origin,
-      content::MediaStreamType type) override;
-  virtual bool RequestPpapiBrokerPermission(
+  bool CheckMediaAccessPermission(content::WebContents* web_contents,
+                                  const GURL& security_origin,
+                                  content::MediaStreamType type) override;
+  bool RequestPpapiBrokerPermission(
       content::WebContents* web_contents,
       const GURL& url,
       const base::FilePath& plugin_path,
       const base::Callback<void(bool)>& callback) override;
-  virtual content::WebContents* OpenURLFromTab(
+  content::WebContents* OpenURLFromTab(
       content::WebContents* source,
       const content::OpenURLParams& params) override;
-  virtual void AddNewContents(content::WebContents* source,
-                              content::WebContents* new_contents,
-                              WindowOpenDisposition disposition,
-                              const gfx::Rect& initial_pos,
-                              bool user_gesture,
-                              bool* was_blocked) override;
+  void AddNewContents(content::WebContents* source,
+                      content::WebContents* new_contents,
+                      WindowOpenDisposition disposition,
+                      const gfx::Rect& initial_rect,
+                      bool user_gesture,
+                      bool* was_blocked) override;
+
  private:
   // NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) override;
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
 
   void OnFindResultAvailable(content::WebContents* web_contents,
                              const FindNotificationDetails* find_result);
diff --git a/chrome/browser/android/dev_tools_manager_delegate_android.cc b/chrome/browser/android/dev_tools_manager_delegate_android.cc
index a5ea927..b7561ad 100644
--- a/chrome/browser/android/dev_tools_manager_delegate_android.cc
+++ b/chrome/browser/android/dev_tools_manager_delegate_android.cc
@@ -55,17 +55,17 @@
 class TargetBase : public content::DevToolsTarget {
  public:
   // content::DevToolsTarget implementation:
-  virtual std::string GetParentId() const override { return std::string(); }
+  std::string GetParentId() const override { return std::string(); }
 
-  virtual std::string GetTitle() const override { return title_; }
+  std::string GetTitle() const override { return title_; }
 
-  virtual std::string GetDescription() const override { return std::string(); }
+  std::string GetDescription() const override { return std::string(); }
 
-  virtual GURL GetURL() const override { return url_; }
+  GURL GetURL() const override { return url_; }
 
-  virtual GURL GetFaviconURL() const override { return favicon_url_; }
+  GURL GetFaviconURL() const override { return favicon_url_; }
 
-  virtual base::TimeTicks GetLastActivityTime() const override {
+  base::TimeTicks GetLastActivityTime() const override {
     return last_activity_time_;
   }
 
@@ -110,15 +110,11 @@
   }
 
   // content::DevToolsTarget implementation:
-  virtual std::string GetId() const override {
-    return base::IntToString(tab_id_);
-  }
+  std::string GetId() const override { return base::IntToString(tab_id_); }
 
-  virtual std::string GetType() const override {
-    return kTargetTypePage;
-  }
+  std::string GetType() const override { return kTargetTypePage; }
 
-  virtual bool IsAttached() const override {
+  bool IsAttached() const override {
     TabModel* model;
     int index;
     if (!FindTab(&model, &index))
@@ -129,7 +125,7 @@
     return DevToolsAgentHost::IsDebuggerAttached(web_contents);
   }
 
-  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const override {
+  scoped_refptr<DevToolsAgentHost> GetAgentHost() const override {
     TabModel* model;
     int index;
     if (!FindTab(&model, &index))
@@ -151,7 +147,7 @@
     return DevToolsAgentHost::GetOrCreateFor(web_contents);
   }
 
-  virtual bool Activate() const override {
+  bool Activate() const override {
     TabModel* model;
     int index;
     if (!FindTab(&model, &index))
@@ -160,7 +156,7 @@
     return true;
   }
 
-  virtual bool Close() const override {
+  bool Close() const override {
     TabModel* model;
     int index;
     if (!FindTab(&model, &index))
@@ -207,11 +203,9 @@
   }
 
   // content::DevToolsTarget implementation:
-  virtual std::string GetId() const override {
-    return agent_host_->GetId();
-  }
+  std::string GetId() const override { return agent_host_->GetId(); }
 
-  virtual std::string GetType() const override {
+  std::string GetType() const override {
     switch (agent_host_->GetType()) {
       case DevToolsAgentHost::TYPE_WEB_CONTENTS:
         if (TabModelList::begin() == TabModelList::end()) {
@@ -228,21 +222,15 @@
     return kTargetTypeOther;
   }
 
-  virtual bool IsAttached() const override {
-    return agent_host_->IsAttached();
-  }
+  bool IsAttached() const override { return agent_host_->IsAttached(); }
 
-  virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const override {
+  scoped_refptr<DevToolsAgentHost> GetAgentHost() const override {
     return agent_host_;
   }
 
-  virtual bool Activate() const override {
-    return agent_host_->Activate();
-  }
+  bool Activate() const override { return agent_host_->Activate(); }
 
-  virtual bool Close() const override {
-    return agent_host_->Close();
-  }
+  bool Close() const override { return agent_host_->Close(); }
 
  private:
   scoped_refptr<DevToolsAgentHost> agent_host_;
diff --git a/chrome/browser/android/dev_tools_manager_delegate_android.h b/chrome/browser/android/dev_tools_manager_delegate_android.h
index 7e1f459e..1a0f51e4 100644
--- a/chrome/browser/android/dev_tools_manager_delegate_android.h
+++ b/chrome/browser/android/dev_tools_manager_delegate_android.h
@@ -14,20 +14,19 @@
 class DevToolsManagerDelegateAndroid : public content::DevToolsManagerDelegate {
  public:
   DevToolsManagerDelegateAndroid();
-  virtual ~DevToolsManagerDelegateAndroid();
+  ~DevToolsManagerDelegateAndroid() override;
 
   // content::DevToolsManagerDelegate implementation.
-  virtual void Inspect(content::BrowserContext* browser_context,
-                       content::DevToolsAgentHost* agent_host) override;
-  virtual void DevToolsAgentStateChanged(content::DevToolsAgentHost* agent_host,
-                                         bool attached) override;
-  virtual base::DictionaryValue* HandleCommand(
+  void Inspect(content::BrowserContext* browser_context,
+               content::DevToolsAgentHost* agent_host) override;
+  void DevToolsAgentStateChanged(content::DevToolsAgentHost* agent_host,
+                                 bool attached) override;
+  base::DictionaryValue* HandleCommand(
       content::DevToolsAgentHost* agent_host,
       base::DictionaryValue* command_dict) override;
-  virtual scoped_ptr<content::DevToolsTarget> CreateNewTarget(
-      const GURL& url) override;
-  virtual void EnumerateTargets(TargetCallback callback) override;
-  virtual std::string GetPageThumbnailData(const GURL& url) override;
+  scoped_ptr<content::DevToolsTarget> CreateNewTarget(const GURL& url) override;
+  void EnumerateTargets(TargetCallback callback) override;
+  std::string GetPageThumbnailData(const GURL& url) override;
 
  private:
   scoped_ptr<DevToolsNetworkProtocolHandler> network_protocol_handler_;
diff --git a/chrome/browser/android/dom_distiller/feedback_reporter_android.h b/chrome/browser/android/dom_distiller/feedback_reporter_android.h
index 284da3b..7af1562f 100644
--- a/chrome/browser/android/dom_distiller/feedback_reporter_android.h
+++ b/chrome/browser/android/dom_distiller/feedback_reporter_android.h
@@ -23,7 +23,7 @@
 class FeedbackReporterAndroid : content::WebContentsObserver {
  public:
   FeedbackReporterAndroid(JNIEnv* env, jobject obj);
-  virtual ~FeedbackReporterAndroid();
+  ~FeedbackReporterAndroid() override;
 
   // Destroys the FeedbackReporterAndroid.
   void Destroy(JNIEnv* env, jobject obj);
@@ -32,7 +32,7 @@
   void ReplaceWebContents(JNIEnv* env, jobject obj, jobject jweb_contents);
 
   // WebContentsObserver implementation:
-  virtual void DidNavigateMainFrame(
+  void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
 
diff --git a/chrome/browser/android/enhanced_bookmarks/enhanced_bookmarks_bridge.h b/chrome/browser/android/enhanced_bookmarks/enhanced_bookmarks_bridge.h
index ce88776..8018b4c 100644
--- a/chrome/browser/android/enhanced_bookmarks/enhanced_bookmarks_bridge.h
+++ b/chrome/browser/android/enhanced_bookmarks/enhanced_bookmarks_bridge.h
@@ -21,7 +21,7 @@
 class EnhancedBookmarksBridge : public BookmarkServerServiceObserver {
  public:
   EnhancedBookmarksBridge(JNIEnv* env, jobject obj, Profile* profile);
-  virtual ~EnhancedBookmarksBridge();
+  ~EnhancedBookmarksBridge() override;
   void Destroy(JNIEnv*, jobject);
 
   base::android::ScopedJavaLocalRef<jstring> GetBookmarkDescription(
@@ -73,7 +73,7 @@
 
   // BookmarkServerServiceObserver
   // Called on changes to cluster data or search results are returned.
-  virtual void OnChange(BookmarkServerService* service) override;
+  void OnChange(BookmarkServerService* service) override;
 
  private:
   bool IsEditable(const BookmarkNode* node) const;
diff --git a/chrome/browser/android/foreign_session_helper.h b/chrome/browser/android/foreign_session_helper.h
index 0f1ad00..5f79bd40 100644
--- a/chrome/browser/android/foreign_session_helper.h
+++ b/chrome/browser/android/foreign_session_helper.h
@@ -37,14 +37,14 @@
   void DeleteForeignSession(JNIEnv* env, jobject obj, jstring session_tag);
 
   // NotificationObserver implemenation
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) override;
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
 
   static bool RegisterForeignSessionHelper(JNIEnv* env);
 
  private:
-  virtual ~ForeignSessionHelper();
+  ~ForeignSessionHelper() override;
 
   Profile* profile_;  // weak
   base::android::ScopedJavaGlobalRef<jobject> callback_;
diff --git a/chrome/browser/android/intercept_download_resource_throttle.h b/chrome/browser/android/intercept_download_resource_throttle.h
index f476a87..6ecfb439 100644
--- a/chrome/browser/android/intercept_download_resource_throttle.h
+++ b/chrome/browser/android/intercept_download_resource_throttle.h
@@ -25,11 +25,11 @@
                                     int request_id);
 
   // content::ResourceThrottle implementation:
-  virtual void WillProcessResponse(bool* defer) override;
-  virtual const char* GetNameForLogging() const override;
+  void WillProcessResponse(bool* defer) override;
+  const char* GetNameForLogging() const override;
 
  private:
-  virtual ~InterceptDownloadResourceThrottle();
+  ~InterceptDownloadResourceThrottle() override;
 
   void ProcessDownloadRequest();
   // Set to true when if we want chrome to handle the download.
diff --git a/chrome/browser/android/logo_bridge.cc b/chrome/browser/android/logo_bridge.cc
index b673ebca..6c97a04 100644
--- a/chrome/browser/android/logo_bridge.cc
+++ b/chrome/browser/android/logo_bridge.cc
@@ -53,11 +53,11 @@
     j_logo_observer_.Reset(env, j_logo_observer);
   }
 
-  virtual ~LogoObserverAndroid() {}
+  ~LogoObserverAndroid() override {}
 
   // seach_provider_logos::LogoObserver:
-  virtual void OnLogoAvailable(const search_provider_logos::Logo* logo,
-                               bool from_cache) override {
+  void OnLogoAvailable(const search_provider_logos::Logo* logo,
+                       bool from_cache) override {
     if (!logo_bridge_)
       return;
 
@@ -67,9 +67,7 @@
         env, j_logo_observer_.obj(), j_logo.obj(), from_cache);
   }
 
-  virtual void OnObserverRemoved() override {
-    delete this;
-  }
+  void OnObserverRemoved() override { delete this; }
 
  private:
   // The associated LogoBridge. We won't call back to Java if the LogoBridge has
diff --git a/chrome/browser/android/logo_service.cc b/chrome/browser/android/logo_service.cc
index f9d3252..ac0351c 100644
--- a/chrome/browser/android/logo_service.cc
+++ b/chrome/browser/android/logo_service.cc
@@ -5,11 +5,10 @@
 #include "chrome/browser/android/logo_service.h"
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/google/google_profile_helper.h"
 #include "chrome/browser/image_decoder.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "components/google/core/browser/google_util.h"
+#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_provider_logos/google_logo_api.h"
@@ -23,7 +22,6 @@
 
 namespace {
 
-const char kGoogleDoodleURLPath[] = "async/newtab_mobile";
 const char kCachedLogoDirectory[] = "Search Logo";
 const int kDecodeLogoTimeoutSeconds = 30;
 
@@ -31,16 +29,14 @@
 // https://www.google.com/async/newtab_mobile. This depends on the user's
 // Google domain.
 GURL GetGoogleDoodleURL(Profile* profile) {
-  // SetPathStr() requires its argument to stay in scope as long as
-  // |replacements| is, so a std::string is needed, instead of a char*.
-  std::string path = kGoogleDoodleURLPath;
+  GURL google_base_url(UIThreadSearchTermsData(profile).GoogleBaseURLValue());
+  const char kGoogleDoodleURLPath[] = "async/newtab_mobile";
+  // The string passed to SetPathStr() must stay alive until after
+  // ReplaceComponents(), so declare it on the stack here instead of inline.
+  std::string path(kGoogleDoodleURLPath);
   GURL::Replacements replacements;
   replacements.SetPathStr(path);
-
-  GURL base_url(google_util::CommandLineGoogleBaseURL());
-  if (!base_url.is_valid())
-    base_url = google_profile_helper::GetGoogleHomePageURL(profile);
-  return base_url.ReplaceComponents(replacements);
+  return google_base_url.ReplaceComponents(replacements);
 }
 
 class LogoDecoderDelegate : public ImageDecoder::Delegate {
@@ -62,18 +58,16 @@
         base::TimeDelta::FromSeconds(kDecodeLogoTimeoutSeconds));
   }
 
-  virtual ~LogoDecoderDelegate() {
-    image_decoder_->set_delegate(NULL);
-  }
+  ~LogoDecoderDelegate() override { image_decoder_->set_delegate(NULL); }
 
   // ImageDecoder::Delegate:
-  virtual void OnImageDecoded(const ImageDecoder* decoder,
-                              const SkBitmap& decoded_image) override {
+  void OnImageDecoded(const ImageDecoder* decoder,
+                      const SkBitmap& decoded_image) override {
     image_decoded_callback_.Run(decoded_image);
     delete this;
   }
 
-  virtual void OnDecodeImageFailed(const ImageDecoder* decoder) override {
+  void OnDecodeImageFailed(const ImageDecoder* decoder) override {
     image_decoded_callback_.Run(SkBitmap());
     delete this;
   }
@@ -89,10 +83,10 @@
 class ChromeLogoDelegate : public search_provider_logos::LogoDelegate {
  public:
   ChromeLogoDelegate() {}
-  virtual ~ChromeLogoDelegate() {}
+  ~ChromeLogoDelegate() override {}
 
   // search_provider_logos::LogoDelegate:
-  virtual void DecodeUntrustedImage(
+  void DecodeUntrustedImage(
       const scoped_refptr<base::RefCountedString>& encoded_image,
       base::Callback<void(const SkBitmap&)> image_decoded_callback) override {
     scoped_refptr<ImageDecoder> image_decoder = new ImageDecoder(
diff --git a/chrome/browser/android/logo_service.h b/chrome/browser/android/logo_service.h
index fe4075b..441c6e2 100644
--- a/chrome/browser/android/logo_service.h
+++ b/chrome/browser/android/logo_service.h
@@ -22,7 +22,7 @@
 class LogoService : public KeyedService {
  public:
   explicit LogoService(Profile* profile);
-  virtual ~LogoService();
+  ~LogoService() override;
 
   // Gets the logo for the default search provider and notifies |observer|
   // with the results.
@@ -46,10 +46,10 @@
   friend struct DefaultSingletonTraits<LogoServiceFactory>;
 
   LogoServiceFactory();
-  virtual ~LogoServiceFactory();
+  ~LogoServiceFactory() override;
 
   // BrowserContextKeyedServiceFactory:
-  virtual KeyedService* BuildServiceInstanceFor(
+  KeyedService* BuildServiceInstanceFor(
       content::BrowserContext* context) const override;
 };
 
diff --git a/chrome/browser/android/manifest_icon_selector.cc b/chrome/browser/android/manifest_icon_selector.cc
new file mode 100644
index 0000000..4f4cdca
--- /dev/null
+++ b/chrome/browser/android/manifest_icon_selector.cc
@@ -0,0 +1,151 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/manifest_icon_selector.h"
+
+#include <limits>
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/mime_util.h"
+#include "ui/gfx/screen.h"
+
+using content::Manifest;
+
+ManifestIconSelector::ManifestIconSelector(float preferred_icon_size_in_pixels)
+    : preferred_icon_size_in_pixels_(preferred_icon_size_in_pixels) {
+}
+
+bool ManifestIconSelector::IconSizesContainsPreferredSize(
+    const std::vector<gfx::Size>& sizes) {
+  for (size_t i = 0; i < sizes.size(); ++i) {
+    if (sizes[i].height() != sizes[i].width())
+      continue;
+    if (sizes[i].width() == preferred_icon_size_in_pixels_)
+      return true;
+  }
+
+  return false;
+}
+
+GURL ManifestIconSelector::FindBestMatchingIconForDensity(
+    const std::vector<content::Manifest::Icon>& icons,
+    float density) {
+  GURL url;
+  int best_delta = std::numeric_limits<int>::min();
+
+  for (size_t i = 0; i < icons.size(); ++i) {
+    if (icons[i].density != density)
+        continue;
+
+    const std::vector<gfx::Size>& sizes = icons[i].sizes;
+    for (size_t j = 0; j < sizes.size(); ++j) {
+      if (sizes[j].height() != sizes[j].width())
+        continue;
+      int delta = sizes[j].width() - preferred_icon_size_in_pixels_;
+      if (delta == 0)
+        return icons[i].src;
+      if (best_delta > 0 && delta < 0)
+        continue;
+      if ((best_delta > 0 && delta < best_delta) ||
+          (best_delta < 0 && delta > best_delta)) {
+        url = icons[i].src;
+        best_delta = delta;
+      }
+    }
+  }
+
+  return url;
+}
+
+GURL ManifestIconSelector::FindBestMatchingIcon(
+    const std::vector<content::Manifest::Icon>& unfiltered_icons,
+    float density) {
+  GURL url;
+  std::vector<Manifest::Icon> icons = FilterIconsByType(unfiltered_icons);
+
+  // The first pass is to find the ideal icon. That icon is of the right size
+  // with the default density or the device's density.
+  for (size_t i = 0; i < icons.size(); ++i) {
+    if (icons[i].density == density &&
+        IconSizesContainsPreferredSize(icons[i].sizes)) {
+      return icons[i].src;
+    }
+
+    // If there is an icon with the right size but not the right density, keep
+    // it on the side and only use it if nothing better is found.
+    if (icons[i].density == Manifest::Icon::kDefaultDensity &&
+        IconSizesContainsPreferredSize(icons[i].sizes)) {
+      url = icons[i].src;
+    }
+  }
+
+  // The second pass is to find an icon with 'any'. The current device scale
+  // factor is preferred. Otherwise, the default scale factor is used.
+  for (size_t i = 0; i < icons.size(); ++i) {
+    if (icons[i].density == density &&
+        IconSizesContainsAny(icons[i].sizes)) {
+      return icons[i].src;
+    }
+
+    // If there is an icon with 'any' but not the right density, keep it on the
+    // side and only use it if nothing better is found.
+    if (icons[i].density == Manifest::Icon::kDefaultDensity &&
+        IconSizesContainsAny(icons[i].sizes)) {
+      url = icons[i].src;
+    }
+  }
+
+  // The last pass will try to find the best suitable icon for the device's
+  // scale factor. If none, another pass will be run using kDefaultDensity.
+  if (!url.is_valid())
+    url = FindBestMatchingIconForDensity(icons, density);
+  if (!url.is_valid())
+    url = FindBestMatchingIconForDensity(icons,
+                                         Manifest::Icon::kDefaultDensity);
+
+  return url;
+}
+
+
+// static
+bool ManifestIconSelector::IconSizesContainsAny(
+    const std::vector<gfx::Size>& sizes) {
+  for (size_t i = 0; i < sizes.size(); ++i) {
+    if (sizes[i].IsEmpty())
+      return true;
+  }
+
+  return false;
+}
+
+// static
+std::vector<Manifest::Icon> ManifestIconSelector::FilterIconsByType(
+    const std::vector<content::Manifest::Icon>& icons) {
+  std::vector<Manifest::Icon> result;
+
+  for (size_t i = 0; i < icons.size(); ++i) {
+    if (icons[i].type.is_null() ||
+        net::IsSupportedImageMimeType(
+            base::UTF16ToUTF8(icons[i].type.string()))) {
+      result.push_back(icons[i]);
+    }
+  }
+
+  return result;
+}
+
+// static
+GURL ManifestIconSelector::FindBestMatchingIcon(
+    const std::vector<Manifest::Icon>& unfiltered_icons,
+    const float preferred_icon_size_in_dp,
+    const gfx::Screen* screen) {
+  const float device_scale_factor =
+      screen->GetPrimaryDisplay().device_scale_factor();
+  const float preferred_icon_size_in_pixels =
+      preferred_icon_size_in_dp * device_scale_factor;
+
+  ManifestIconSelector selector(preferred_icon_size_in_pixels);
+  return selector.FindBestMatchingIcon(unfiltered_icons, device_scale_factor);
+}
diff --git a/chrome/browser/android/manifest_icon_selector.h b/chrome/browser/android/manifest_icon_selector.h
new file mode 100644
index 0000000..ef3ad27
--- /dev/null
+++ b/chrome/browser/android/manifest_icon_selector.h
@@ -0,0 +1,79 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_MANIFEST_ICON_SELECTOR_H_
+#define CHROME_BROWSER_ANDROID_MANIFEST_ICON_SELECTOR_H_
+
+#include "base/basictypes.h"
+#include "content/public/common/manifest.h"
+#include "url/gurl.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace IPC {
+class Message;
+}  // namespace IPC
+
+namespace gfx {
+class Screen;
+}
+
+// Selects the icon most closely matching the size constraints.  This follows
+// very basic heuristics -- improvements are welcome.
+class ManifestIconSelector {
+ public:
+  // Runs the algorithm to find the best matching icon in the icons listed in
+  // the Manifest.
+  //
+  // Size is defined in Android's density-independent pixels (dp):
+  // http://developer.android.com/guide/practices/screens_support.html
+  // If/when this class is generalized, it may be a good idea to switch this to
+  // taking in pixels, instead.
+  //
+  // Returns the icon url if a suitable icon is found. An empty URL otherwise.
+  static GURL FindBestMatchingIcon(
+      const std::vector<content::Manifest::Icon>& icons,
+      float preferred_icon_size_in_dp,
+      const gfx::Screen* screen);
+
+ private:
+  explicit ManifestIconSelector(float preferred_icon_size_in_pixels);
+  virtual ~ManifestIconSelector() {}
+
+  // Runs the algorithm to find the best matching icon in the icons listed in
+  // the Manifest.
+  // Returns the icon url if a suitable icon is found. An empty URL otherwise.
+  GURL FindBestMatchingIcon(
+      const std::vector<content::Manifest::Icon>& icons,
+      float density);
+
+  // Runs an algorithm only based on icon declared sizes. It will try to find
+  // size that is the closest to preferred_icon_size_in_pixels_ but bigger than
+  // preferred_icon_size_in_pixels_ if possible.
+  // Returns the icon url if a suitable icon is found. An empty URL otherwise.
+  GURL FindBestMatchingIconForDensity(
+      const std::vector<content::Manifest::Icon>& icons,
+      float density);
+
+  // Returns whether the |preferred_icon_size_in_pixels_| is in |sizes|.
+  bool IconSizesContainsPreferredSize(const std::vector<gfx::Size>& sizes);
+
+  // Returns an array containing the items in |icons| without the unsupported
+  // image MIME types.
+  static std::vector<content::Manifest::Icon> FilterIconsByType(
+      const std::vector<content::Manifest::Icon>& icons);
+
+  // Returns whether the 'any' (ie. gfx::Size(0,0)) is in |sizes|.
+  static bool IconSizesContainsAny(const std::vector<gfx::Size>& sizes);
+
+  const int preferred_icon_size_in_pixels_;
+
+  friend class ManifestIconSelectorTest;
+
+  DISALLOW_COPY_AND_ASSIGN(ManifestIconSelector);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_MANIFEST_ICON_SELECTOR_H_
diff --git a/chrome/browser/android/shortcut_helper_unittest.cc b/chrome/browser/android/manifest_icon_selector_unittest.cc
similarity index 81%
rename from chrome/browser/android/shortcut_helper_unittest.cc
rename to chrome/browser/android/manifest_icon_selector_unittest.cc
index 76e1a5e..b2cafbc 100644
--- a/chrome/browser/android/shortcut_helper_unittest.cc
+++ b/chrome/browser/android/manifest_icon_selector_unittest.cc
@@ -1,55 +1,60 @@
-// 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.
 
-#include "chrome/browser/android/shortcut_helper.h"
+#include "chrome/browser/android/manifest_icon_selector.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "content/public/browser/web_contents.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/screen.h"
 #include "ui/gfx/screen_type_delegate.h"
 
-// A dummy implementation of gfx::Screen, since ShortcutHelper needs access to
-// a gfx::Display's device scale factor.
+namespace {
+
+const int kPreferredIconSize = 48;
+
+}
+
+// A dummy implementation of gfx::Screen, since ManifestIconSelector needs
+// access to a gfx::Display's device scale factor.
 // This is inspired by web_contents_video_capture_device_unittest.cc
 // A bug has been opened to merge all those mocks: http://crbug.com/417227
 class FakeScreen : public gfx::Screen {
  public:
   FakeScreen() : display_(0x1337, gfx::Rect(0, 0, 2560, 1440)) {
   }
-  virtual ~FakeScreen() {}
+  ~FakeScreen() override {}
 
   void SetDisplayDeviceScaleFactor(float device_scale_factor) {
     display_.set_device_scale_factor(device_scale_factor);
   }
 
   // gfx::Screen implementation (only what's needed for testing).
-  virtual gfx::Point GetCursorScreenPoint() override { return gfx::Point(); }
-  virtual gfx::NativeWindow GetWindowUnderCursor() override { return NULL; }
-  virtual gfx::NativeWindow GetWindowAtScreenPoint(
-      const gfx::Point& point) override { return NULL; }
-  virtual int GetNumDisplays() const override { return 1; }
-  virtual std::vector<gfx::Display> GetAllDisplays() const override {
+  gfx::Point GetCursorScreenPoint() override { return gfx::Point(); }
+  gfx::NativeWindow GetWindowUnderCursor() override { return nullptr; }
+  gfx::NativeWindow GetWindowAtScreenPoint(
+      const gfx::Point& point) override { return nullptr; }
+  int GetNumDisplays() const override { return 1; }
+  std::vector<gfx::Display> GetAllDisplays() const override {
     return std::vector<gfx::Display>(1, display_);
   }
-  virtual gfx::Display GetDisplayNearestWindow(
+  gfx::Display GetDisplayNearestWindow(
       gfx::NativeView view) const override {
     return display_;
   }
-  virtual gfx::Display GetDisplayNearestPoint(
+  gfx::Display GetDisplayNearestPoint(
       const gfx::Point& point) const override {
     return display_;
   }
-  virtual gfx::Display GetDisplayMatching(
+  gfx::Display GetDisplayMatching(
       const gfx::Rect& match_rect) const override {
     return display_;
   }
-  virtual gfx::Display GetPrimaryDisplay() const override {
+  gfx::Display GetPrimaryDisplay() const override {
     return display_;
   }
-  virtual void AddObserver(gfx::DisplayObserver* observer) override {}
-  virtual void RemoveObserver(gfx::DisplayObserver* observer) override {}
+  void AddObserver(gfx::DisplayObserver* observer) override {}
+  void RemoveObserver(gfx::DisplayObserver* observer) override {}
 
  private:
   gfx::Display display_;
@@ -57,59 +62,24 @@
   DISALLOW_COPY_AND_ASSIGN(FakeScreen);
 };
 
-class ShortcutHelperTest : public ChromeRenderViewHostTestHarness  {
+class ManifestIconSelectorTest : public testing::Test  {
  protected:
-  ShortcutHelperTest() : shortcut_helper_(NULL) {}
-  virtual ~ShortcutHelperTest() {}
-
-  static jobject CreateShortcutHelperJava(JNIEnv* env) {
-    jclass clazz = env->FindClass("org/chromium/chrome/browser/ShortcutHelper");
-    jmethodID constructor =
-        env->GetMethodID(clazz, "<init>",
-                         "(Landroid/content/Context;"
-                             "Lorg/chromium/chrome/browser/Tab;)V");
-    return env->NewObject(clazz, constructor, jobject(), jobject());
-  }
-
-  void ResetShorcutHelper() {
-    if (shortcut_helper_)
-      delete shortcut_helper_;
-
-    JNIEnv* env = base::android::AttachCurrentThread();
-    shortcut_helper_ =
-        new ShortcutHelper(env, CreateShortcutHelperJava(env), web_contents());
-  }
-
-  virtual void SetUp() override {
-    gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, &fake_screen_);
-    ASSERT_EQ(&fake_screen_, gfx::Screen::GetNativeScreen());
-
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    ResetShorcutHelper();
-  }
-
-  virtual void TearDown() override {
-    delete shortcut_helper_;
-    shortcut_helper_ = NULL;
-
-    ChromeRenderViewHostTestHarness::TearDown();
-
-    gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, NULL);
-  }
+  ManifestIconSelectorTest() {}
+  ~ManifestIconSelectorTest() override {}
 
   GURL FindBestMatchingIcon(const std::vector<content::Manifest::Icon>& icons) {
-    return shortcut_helper_->FindBestMatchingIcon(icons);
+    return ManifestIconSelector::FindBestMatchingIcon(
+        icons,
+        GetPreferredIconSizeInDp(),
+        &fake_screen_);
   }
 
   void SetDisplayDeviceScaleFactor(float device_scale_factor) {
     fake_screen_.SetDisplayDeviceScaleFactor(device_scale_factor);
-
-    ResetShorcutHelper();
   }
 
   static int GetPreferredIconSizeInDp() {
-    return ShortcutHelper::kPreferredIconSizeInDp;
+    return kPreferredIconSize;
   }
 
   static content::Manifest::Icon CreateIcon(
@@ -128,20 +98,19 @@
   }
 
  private:
-  ShortcutHelper* shortcut_helper_;
   FakeScreen fake_screen_;
 
-  DISALLOW_COPY_AND_ASSIGN(ShortcutHelperTest);
+  DISALLOW_COPY_AND_ASSIGN(ManifestIconSelectorTest);
 };
 
-TEST_F(ShortcutHelperTest, NoIcons) {
+TEST_F(ManifestIconSelectorTest, NoIcons) {
   // No icons should return the empty URL.
   std::vector<content::Manifest::Icon> icons;
   GURL url = FindBestMatchingIcon(icons);
   EXPECT_TRUE(url.is_empty());
 }
 
-TEST_F(ShortcutHelperTest, NoSizes) {
+TEST_F(ManifestIconSelectorTest, NoSizes) {
   // Icon with no sizes are ignored.
   std::vector<content::Manifest::Icon> icons;
   icons.push_back(
@@ -151,7 +120,7 @@
   EXPECT_TRUE(url.is_empty());
 }
 
-TEST_F(ShortcutHelperTest, MIMETypeFiltering) {
+TEST_F(ManifestIconSelectorTest, MIMETypeFiltering) {
   // Icons with type specified to a MIME type that isn't a valid image MIME type
   // are ignored.
   std::vector<gfx::Size> sizes;
@@ -187,7 +156,7 @@
   EXPECT_EQ("http://foo.com/icon.png", url.spec());
 }
 
-TEST_F(ShortcutHelperTest, PreferredSizeOfCurrentDensityIsUsedFirst) {
+TEST_F(ManifestIconSelectorTest, PreferredSizeOfCurrentDensityIsUsedFirst) {
   // This test has three icons each are marked with sizes set to the preferred
   // icon size for the associated density.
   std::vector<gfx::Size> sizes_1;
@@ -220,7 +189,7 @@
   EXPECT_EQ("http://foo.com/icon_x3.png", url.spec());
 }
 
-TEST_F(ShortcutHelperTest, PreferredSizeOfDefaultDensityIsUsedSecond) {
+TEST_F(ManifestIconSelectorTest, PreferredSizeOfDefaultDensityIsUsedSecond) {
   // This test has three icons. The first one is of density zero and is marked
   // with three sizes which are the preferred icon size for density 1, 2 and 3.
   // The icon for density 2 and 3 have a size set to 2x2 and 3x3.
@@ -258,7 +227,7 @@
   EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
 }
 
-TEST_F(ShortcutHelperTest, DeviceDensityFirst) {
+TEST_F(ManifestIconSelectorTest, DeviceDensityFirst) {
   // If there is no perfect icon but an icon of the current device density is
   // present, it will be picked.
   // This test has three icons each are marked with sizes set to the preferred
@@ -284,7 +253,7 @@
   EXPECT_EQ("http://foo.com/icon_x3.png", url.spec());
 }
 
-TEST_F(ShortcutHelperTest, DeviceDensityFallback) {
+TEST_F(ManifestIconSelectorTest, DeviceDensityFallback) {
   // If there is no perfect icon but and no icon of the current display density,
   // an icon of density 1.0 will be used.
   std::vector<gfx::Size> sizes;
@@ -299,7 +268,7 @@
   EXPECT_EQ("http://foo.com/icon_x1.png", url.spec());
 }
 
-TEST_F(ShortcutHelperTest, DoNotUseOtherDensities) {
+TEST_F(ManifestIconSelectorTest, DoNotUseOtherDensities) {
   // If there are only icons of densities that are not the current display
   // density or the default density, they are ignored.
   std::vector<gfx::Size> sizes;
@@ -313,7 +282,7 @@
   EXPECT_TRUE(url.is_empty());
 }
 
-TEST_F(ShortcutHelperTest, NotSquareIconsAreIgnored) {
+TEST_F(ManifestIconSelectorTest, NotSquareIconsAreIgnored) {
   std::vector<gfx::Size> sizes;
   sizes.push_back(gfx::Size(20, 2));
 
@@ -324,8 +293,8 @@
   EXPECT_TRUE(url.is_empty());
 }
 
-TEST_F(ShortcutHelperTest, ClosestIconToPreferred) {
-  // This test verifies ShortcutHelper::FindBestMatchingIcon by passing
+TEST_F(ManifestIconSelectorTest, ClosestIconToPreferred) {
+  // This test verifies ManifestIconSelector::FindBestMatchingIcon by passing
   // different icon sizes and checking which one is picked.
   // The Device Scale Factor is 1.0 and the preferred icon size is returned by
   // GetPreferredIconSizeInDp().
@@ -441,7 +410,7 @@
   }
 }
 
-TEST_F(ShortcutHelperTest, UseAnyIfNoPreferredSize) {
+TEST_F(ManifestIconSelectorTest, UseAnyIfNoPreferredSize) {
   // 'any' (ie. gfx::Size(0,0)) should be used if there is no icon of a
   // preferred size. An icon with the current device scale factor is preferred
   // over one with the default density.
diff --git a/chrome/browser/android/most_visited_sites.h b/chrome/browser/android/most_visited_sites.h
index b01c56e..6e5a7f52a 100644
--- a/chrome/browser/android/most_visited_sites.h
+++ b/chrome/browser/android/most_visited_sites.h
@@ -45,7 +45,7 @@
   void RecordOpenedMostVisitedItem(JNIEnv* env, jobject obj, jint index);
 
   // ProfileSyncServiceObserver implementation.
-  virtual void OnStateChanged() override;
+  void OnStateChanged() override;
 
   // Registers JNI methods.
   static bool Register(JNIEnv* env);
@@ -57,7 +57,7 @@
     SUGGESTIONS_SERVICE
   };
 
-  virtual ~MostVisitedSites();
+  ~MostVisitedSites() override;
   void QueryMostVisitedURLs();
 
   // Initialize the query to Top Sites. Called if the SuggestionsService is not
diff --git a/chrome/browser/android/omnibox/answers_image_bridge.cc b/chrome/browser/android/omnibox/answers_image_bridge.cc
index 09860af1..41d215d 100644
--- a/chrome/browser/android/omnibox/answers_image_bridge.cc
+++ b/chrome/browser/android/omnibox/answers_image_bridge.cc
@@ -31,11 +31,11 @@
     java_answers_image_observer_.Reset(env, java_answers_image_observer);
   }
 
-  virtual ~AnswersImageObserverAndroid() {}
+  ~AnswersImageObserverAndroid() override {}
 
   // AnswersImageObserver:
-  virtual void OnImageChanged(BitmapFetcherService::RequestId request_id,
-                              const SkBitmap& answers_image) override {
+  void OnImageChanged(BitmapFetcherService::RequestId request_id,
+                      const SkBitmap& answers_image) override {
     DCHECK(!answers_image.empty());
 
     JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index bcac0f2..7a85f8a 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -73,11 +73,11 @@
   explicit ZeroSuggestPrefetcher(Profile* profile);
 
  private:
-  virtual ~ZeroSuggestPrefetcher();
+  ~ZeroSuggestPrefetcher() override;
   void SelfDestruct();
 
   // AutocompleteControllerDelegate:
-  virtual void OnResultChanged(bool default_match_changed) override;
+  void OnResultChanged(bool default_match_changed) override;
 
   scoped_ptr<AutocompleteController> controller_;
   base::OneShotTimer<ZeroSuggestPrefetcher> expire_timer_;
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.h b/chrome/browser/android/omnibox/autocomplete_controller_android.h
index d8e150f6..6ae205c6 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.h
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.h
@@ -71,7 +71,7 @@
           jlong elapsed_time_since_input_change);
 
   // KeyedService:
-  virtual void Shutdown() override;
+  void Shutdown() override;
 
   class Factory : public BrowserContextKeyedServiceFactory {
    public:
@@ -82,26 +82,26 @@
     static Factory* GetInstance();
 
    protected:
-    virtual content::BrowserContext* GetBrowserContextToUse(
+    content::BrowserContext* GetBrowserContextToUse(
         content::BrowserContext* context) const override;
 
    private:
     friend struct DefaultSingletonTraits<Factory>;
 
     Factory();
-    virtual ~Factory();
+    ~Factory() override;
 
     // BrowserContextKeyedServiceFactory
-    virtual KeyedService* BuildServiceInstanceFor(
+    KeyedService* BuildServiceInstanceFor(
         content::BrowserContext* profile) const override;
   };
 
  private:
-  virtual ~AutocompleteControllerAndroid();
+  ~AutocompleteControllerAndroid() override;
   void InitJNI(JNIEnv* env, jobject obj);
 
   // AutocompleteControllerDelegate implementation.
-  virtual void OnResultChanged(bool default_match_changed) override;
+  void OnResultChanged(bool default_match_changed) override;
 
   // Notifies the Java AutocompleteController that suggestions were received
   // based on the text the user typed in last.
diff --git a/chrome/browser/android/password_ui_view_android.h b/chrome/browser/android/password_ui_view_android.h
index 35071a3..2d826d9 100644
--- a/chrome/browser/android/password_ui_view_android.h
+++ b/chrome/browser/android/password_ui_view_android.h
@@ -21,18 +21,17 @@
 class PasswordUIViewAndroid : public PasswordUIView {
  public:
   PasswordUIViewAndroid(JNIEnv* env, jobject);
-  virtual ~PasswordUIViewAndroid();
+  ~PasswordUIViewAndroid() override;
 
   // PasswordUIView implementation.
-  virtual Profile* GetProfile() override;
-  virtual void ShowPassword(size_t index, const base::string16& password_value)
-      override;
-  virtual void SetPasswordList(
+  Profile* GetProfile() override;
+  void ShowPassword(size_t index,
+                    const base::string16& password_value) override;
+  void SetPasswordList(
       const ScopedVector<autofill::PasswordForm>& password_list,
       bool show_passwords) override;
-  virtual void SetPasswordExceptionList(
-      const ScopedVector<autofill::PasswordForm>& password_exception_list)
-      override;
+  void SetPasswordExceptionList(const ScopedVector<autofill::PasswordForm>&
+                                    password_exception_list) override;
 
   // Calls from Java.
   base::android::ScopedJavaLocalRef<jobject> GetSavedPasswordEntry(
diff --git a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc b/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
index b4ffde3..d284d5d 100644
--- a/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
+++ b/chrome/browser/android/preferences/autofill/autofill_profile_bridge.cc
@@ -47,10 +47,10 @@
 
 static jstring GetDefaultCountryCode(JNIEnv* env,
                                     jclass clazz) {
-  std::string defaultCountryCode =
+  std::string default_country_code =
       autofill::AutofillCountry::CountryCodeForLocale(
           g_browser_process->GetApplicationLocale());
-  return ConvertUTF8ToJavaString(env, defaultCountryCode).Release();
+  return ConvertUTF8ToJavaString(env, default_country_code).Release();
 }
 
 static void GetSupportedCountries(JNIEnv* env,
@@ -76,9 +76,10 @@
                                                j_country_name_list);
 }
 
-static void GetAddressUiComponents(JNIEnv* env,
+static jstring GetAddressUiComponents(JNIEnv* env,
                                    jclass clazz,
                                    jstring j_country_code,
+                                   jstring j_language_code,
                                    jobject j_id_list,
                                    jobject j_name_list) {
   std::string best_language_tag;
@@ -87,10 +88,18 @@
   ::i18n::addressinput::Localization localization;
   localization.SetGetter(l10n_util::GetStringUTF8);
 
+  std::string language_code;
+  if (j_language_code != NULL) {
+    language_code = ConvertJavaStringToUTF8(env, j_language_code);
+  }
+  if (language_code.empty()) {
+    language_code = g_browser_process->GetApplicationLocale();
+  }
+
   std::vector<::i18n::addressinput::AddressUiComponent> ui_components =
       ::i18n::addressinput::BuildComponents(
           ConvertJavaStringToUTF8(env, j_country_code), localization,
-          g_browser_process->GetApplicationLocale(), &best_language_tag);
+          language_code, &best_language_tag);
 
   for (auto ui_component : ui_components) {
     component_labels.push_back(ui_component.name);
@@ -136,6 +145,8 @@
                                                ToJavaArrayOfStrings(
                                                    env, component_labels).obj(),
                                                j_name_list);
+
+  return ConvertUTF8ToJavaString(env, best_language_tag).Release();
 }
 
 // static
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index c37b4e0b..b0e8aec 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -284,7 +284,7 @@
       : weak_chrome_native_preferences_(env, obj) {
   }
 
-  virtual void OnBrowsingDataRemoverDone() override {
+  void OnBrowsingDataRemoverDone() override {
     // Just as a BrowsingDataRemover deletes itself when done, we delete ourself
     // when done.  No need to remove ourself as an observer given the lifetime
     // of BrowsingDataRemover.
diff --git a/chrome/browser/android/preferences/website_preference_bridge.cc b/chrome/browser/android/preferences/website_preference_bridge.cc
index 07adbf4b..d21bf9d 100644
--- a/chrome/browser/android/preferences/website_preference_bridge.cc
+++ b/chrome/browser/android/preferences/website_preference_bridge.cc
@@ -366,7 +366,7 @@
  private:
   friend class base::RefCountedThreadSafe<SiteDataDeleteHelper>;
 
-  virtual ~SiteDataDeleteHelper() {}
+  ~SiteDataDeleteHelper() override {}
 
   Profile* profile_;
 
diff --git a/chrome/browser/android/provider/bookmark_model_observer_task.h b/chrome/browser/android/provider/bookmark_model_observer_task.h
index 64385545..eeb644d 100644
--- a/chrome/browser/android/provider/bookmark_model_observer_task.h
+++ b/chrome/browser/android/provider/bookmark_model_observer_task.h
@@ -28,33 +28,32 @@
                                   public bookmarks::BookmarkModelObserver {
  public:
   explicit BookmarkModelObserverTask(bookmarks::BookmarkModel* bookmark_model);
-  virtual ~BookmarkModelObserverTask();
+  ~BookmarkModelObserverTask() override;
 
   // bookmarks::BookmarkModelObserver:
-  virtual void BookmarkModelLoaded(bookmarks::BookmarkModel* model,
-                                   bool ids_reassigned) override;
-  virtual void BookmarkNodeMoved(bookmarks::BookmarkModel* model,
-                                 const BookmarkNode* old_parent,
-                                 int old_index,
-                                 const BookmarkNode* new_parent,
-                                 int new_index) override;
-  virtual void BookmarkNodeAdded(bookmarks::BookmarkModel* model,
-                                 const BookmarkNode* parent,
-                                 int index) override;
-  virtual void BookmarkNodeRemoved(bookmarks::BookmarkModel* model,
-                                   const BookmarkNode* parent,
-                                   int old_index,
-                                   const BookmarkNode* node,
+  void BookmarkModelLoaded(bookmarks::BookmarkModel* model,
+                           bool ids_reassigned) override;
+  void BookmarkNodeMoved(bookmarks::BookmarkModel* model,
+                         const BookmarkNode* old_parent,
+                         int old_index,
+                         const BookmarkNode* new_parent,
+                         int new_index) override;
+  void BookmarkNodeAdded(bookmarks::BookmarkModel* model,
+                         const BookmarkNode* parent,
+                         int index) override;
+  void BookmarkNodeRemoved(bookmarks::BookmarkModel* model,
+                           const BookmarkNode* parent,
+                           int old_index,
+                           const BookmarkNode* node,
+                           const std::set<GURL>& removed_urls) override;
+  void BookmarkAllUserNodesRemoved(bookmarks::BookmarkModel* model,
                                    const std::set<GURL>& removed_urls) override;
-  virtual void BookmarkAllUserNodesRemoved(
-      bookmarks::BookmarkModel* model,
-      const std::set<GURL>& removed_urls) override;
-  virtual void BookmarkNodeChanged(bookmarks::BookmarkModel* model,
-                                   const BookmarkNode* node) override;
-  virtual void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model,
-                                          const BookmarkNode* node) override;
-  virtual void BookmarkNodeChildrenReordered(bookmarks::BookmarkModel* model,
-                                             const BookmarkNode* node) override;
+  void BookmarkNodeChanged(bookmarks::BookmarkModel* model,
+                           const BookmarkNode* node) override;
+  void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model,
+                                  const BookmarkNode* node) override;
+  void BookmarkNodeChildrenReordered(bookmarks::BookmarkModel* model,
+                                     const BookmarkNode* node) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(BookmarkModelObserverTask);
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc
index 946e353..6191d63 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.cc
+++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -248,7 +248,7 @@
       : BookmarkModelObserverTask(model),
         deleted_(0),
         id_to_delete_(kInvalidBookmarkId) {}
-  virtual ~RemoveBookmarkTask() {}
+  ~RemoveBookmarkTask() override {}
 
   int Run(const int64 id) {
     id_to_delete_ = id;
@@ -267,12 +267,11 @@
   }
 
   // Verify that the bookmark was actually removed. Called synchronously.
-  virtual void BookmarkNodeRemoved(
-      BookmarkModel* bookmark_model,
-      const BookmarkNode* parent,
-      int old_index,
-      const BookmarkNode* node,
-      const std::set<GURL>& removed_urls) override {
+  void BookmarkNodeRemoved(BookmarkModel* bookmark_model,
+                           const BookmarkNode* parent,
+                           int old_index,
+                           const BookmarkNode* node,
+                           const std::set<GURL>& removed_urls) override {
     if (bookmark_model == model() && node->id() == id_to_delete_)
         ++deleted_;
   }
@@ -290,7 +289,7 @@
   explicit RemoveAllUserBookmarksTask(BookmarkModel* model)
       : BookmarkModelObserverTask(model) {}
 
-  virtual ~RemoveAllUserBookmarksTask() {}
+  ~RemoveAllUserBookmarksTask() override {}
 
   void Run() {
     RunOnUIThreadBlocking::Run(
@@ -313,7 +312,7 @@
       : BookmarkModelObserverTask(model),
         updated_(0),
         id_to_update_(kInvalidBookmarkId){}
-  virtual ~UpdateBookmarkTask() {}
+  ~UpdateBookmarkTask() override {}
 
   int Run(const int64 id,
           const base::string16& title,
@@ -355,8 +354,8 @@
   }
 
   // Verify that the bookmark was actually updated. Called synchronously.
-  virtual void BookmarkNodeChanged(BookmarkModel* bookmark_model,
-                                   const BookmarkNode* node) override {
+  void BookmarkNodeChanged(BookmarkModel* bookmark_model,
+                           const BookmarkNode* node) override {
     if (bookmark_model == model() && node->id() == id_to_update_)
       ++updated_;
   }
diff --git a/chrome/browser/android/provider/chrome_browser_provider.h b/chrome/browser/android/provider/chrome_browser_provider.h
index a2ff280..3fc4312b 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.h
+++ b/chrome/browser/android/provider/chrome_browser_provider.h
@@ -172,14 +172,13 @@
                                                              jstring url);
 
  private:
-  virtual ~ChromeBrowserProvider();
+  ~ChromeBrowserProvider() override;
 
   // Override bookmarks::BaseBookmarkModelObserver.
-  virtual void BookmarkModelChanged() override;
-  virtual void ExtensiveBookmarkChangesBeginning(
+  void BookmarkModelChanged() override;
+  void ExtensiveBookmarkChangesBeginning(
       bookmarks::BookmarkModel* model) override;
-  virtual void ExtensiveBookmarkChangesEnded(
-      bookmarks::BookmarkModel* model) override;
+  void ExtensiveBookmarkChangesEnded(bookmarks::BookmarkModel* model) override;
 
   // Deals with updates to the history service.
   void OnHistoryChanged();
diff --git a/chrome/browser/android/recently_closed_tabs_bridge.h b/chrome/browser/android/recently_closed_tabs_bridge.h
index ac11f3f..01eb50d 100644
--- a/chrome/browser/android/recently_closed_tabs_bridge.h
+++ b/chrome/browser/android/recently_closed_tabs_bridge.h
@@ -34,16 +34,16 @@
 
   // Observer callback for TabRestoreServiceObserver. Notifies the registered
   // callback that the recently closed tabs list has changed.
-  virtual void TabRestoreServiceChanged(TabRestoreService* service) override;
+  void TabRestoreServiceChanged(TabRestoreService* service) override;
 
   // Observer callback when our associated TabRestoreService is destroyed.
-  virtual void TabRestoreServiceDestroyed(TabRestoreService* service) override;
+  void TabRestoreServiceDestroyed(TabRestoreService* service) override;
 
   // Registers JNI methods.
   static bool Register(JNIEnv* env);
 
  private:
-  virtual ~RecentlyClosedTabsBridge();
+  ~RecentlyClosedTabsBridge() override;
 
   // Construct and initialize tab_restore_service_ if it's NULL.
   // tab_restore_service_ may still be NULL, however, in incognito mode.
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h
index 661f7efd..8f7fe09 100644
--- a/chrome/browser/android/resource_id.h
+++ b/chrome/browser/android/resource_id.h
@@ -51,5 +51,7 @@
 DEFINE_RESOURCE_ID(IDR_AUTOFILL_CC_MASTERCARD, R.drawable.mc_card)
 DEFINE_RESOURCE_ID(IDR_AUTOFILL_CC_VISA, R.drawable.visa_card)
 DEFINE_RESOURCE_ID(IDR_AUTOFILL_CC_SCAN_NEW, android.R.drawable.ic_menu_camera)
+DEFINE_RESOURCE_ID(IDR_CREDIT_CARD_CVC_HINT, R.drawable.cvc_icon)
+DEFINE_RESOURCE_ID(IDR_CREDIT_CARD_CVC_HINT_AMEX, R.drawable.cvc_icon_amex)
 
 #endif  // CHROME_BROWSER_ANDROID_RESOURCE_ID_H_
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index 7661e84a..0131235 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/threading/worker_pool.h"
+#include "chrome/browser/android/manifest_icon_selector.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/favicon/favicon_service.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
@@ -30,6 +31,7 @@
 #include "content/public/common/manifest.h"
 #include "jni/ShortcutHelper_jni.h"
 #include "net/base/mime_util.h"
+#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/color_analysis.h"
@@ -58,10 +60,8 @@
                                content::WebContents* web_contents)
     : WebContentsObserver(web_contents),
       java_ref_(env, obj),
-      url_(dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(
-          web_contents->GetURL())),
-      display_(content::Manifest::DISPLAY_MODE_BROWSER),
-      orientation_(blink::WebScreenOrientationLockDefault),
+      shortcut_info_(dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(
+                     web_contents->GetURL())),
       add_shortcut_requested_(false),
       manifest_icon_status_(MANIFEST_ICON_STATUS_NONE),
       preferred_icon_size_in_px_(kPreferredIconSizeInDp *
@@ -87,12 +87,12 @@
   web_app_info.description =
       web_app_info.description.substr(0, chrome::kMaxMetaTagAttributeLength);
 
-  title_ = web_app_info.title.empty() ? web_contents()->GetTitle()
-                                      : web_app_info.title;
+  shortcut_info_.title = web_app_info.title.empty() ? web_contents()->GetTitle()
+                                                    : web_app_info.title;
 
   if (web_app_info.mobile_capable == WebApplicationInfo::MOBILE_CAPABLE ||
       web_app_info.mobile_capable == WebApplicationInfo::MOBILE_CAPABLE_APPLE) {
-    display_ = content::Manifest::DISPLAY_MODE_STANDALONE;
+    shortcut_info_.display = content::Manifest::DISPLAY_MODE_STANDALONE;
   }
 
   // Record what type of shortcut was added by the user.
@@ -115,161 +115,18 @@
                                          weak_ptr_factory_.GetWeakPtr()));
 }
 
-bool ShortcutHelper::IconSizesContainsPreferredSize(
-    const std::vector<gfx::Size>& sizes) const {
-  for (size_t i = 0; i < sizes.size(); ++i) {
-    if (sizes[i].height() != sizes[i].width())
-      continue;
-    if (sizes[i].width() == preferred_icon_size_in_px_)
-      return true;
-  }
-
-  return false;
-}
-
-bool ShortcutHelper::IconSizesContainsAny(
-    const std::vector<gfx::Size>& sizes) const {
-  for (size_t i = 0; i < sizes.size(); ++i) {
-    if (sizes[i].IsEmpty())
-      return true;
-  }
-
-  return false;
-}
-
-GURL ShortcutHelper::FindBestMatchingIcon(
-    const std::vector<Manifest::Icon>& icons, float density) const {
-  GURL url;
-  int best_delta = std::numeric_limits<int>::min();
-
-  for (size_t i = 0; i < icons.size(); ++i) {
-    if (icons[i].density != density)
-      continue;
-
-    const std::vector<gfx::Size>& sizes = icons[i].sizes;
-    for (size_t j = 0; j < sizes.size(); ++j) {
-      if (sizes[j].height() != sizes[j].width())
-        continue;
-      int delta = sizes[j].width() - preferred_icon_size_in_px_;
-      if (delta == 0)
-        return icons[i].src;
-      if (best_delta > 0 && delta < 0)
-        continue;
-      if ((best_delta > 0 && delta < best_delta) ||
-          (best_delta < 0 && delta > best_delta)) {
-        url = icons[i].src;
-        best_delta = delta;
-      }
-    }
-  }
-
-  return url;
-}
-
-// static
-std::vector<Manifest::Icon> ShortcutHelper::FilterIconsByType(
-    const std::vector<Manifest::Icon>& icons) {
-  std::vector<Manifest::Icon> result;
-
-  for (size_t i = 0; i < icons.size(); ++i) {
-    if (icons[i].type.is_null() ||
-        net::IsSupportedImageMimeType(
-            base::UTF16ToUTF8(icons[i].type.string()))) {
-      result.push_back(icons[i]);
-    }
-  }
-
-  return result;
-}
-
-GURL ShortcutHelper::FindBestMatchingIcon(
-    const std::vector<Manifest::Icon>& unfiltered_icons) const {
-  const float device_scale_factor =
-      gfx::Screen::GetScreenFor(web_contents()->GetNativeView())->
-          GetPrimaryDisplay().device_scale_factor();
-
-  GURL url;
-  std::vector<Manifest::Icon> icons = FilterIconsByType(unfiltered_icons);
-
-  // The first pass is to find the ideal icon. That icon is of the right size
-  // with the default density or the device's density.
-  for (size_t i = 0; i < icons.size(); ++i) {
-    if (icons[i].density == device_scale_factor &&
-        IconSizesContainsPreferredSize(icons[i].sizes)) {
-      return icons[i].src;
-    }
-
-    // If there is an icon with the right size but not the right density, keep
-    // it on the side and only use it if nothing better is found.
-    if (icons[i].density == Manifest::Icon::kDefaultDensity &&
-        IconSizesContainsPreferredSize(icons[i].sizes)) {
-      url = icons[i].src;
-    }
-  }
-
-  // The second pass is to find an icon with 'any'. The current device scale
-  // factor is preferred. Otherwise, the default scale factor is used.
-  for (size_t i = 0; i < icons.size(); ++i) {
-    if (icons[i].density == device_scale_factor &&
-        IconSizesContainsAny(icons[i].sizes)) {
-      return icons[i].src;
-    }
-
-    // If there is an icon with 'any' but not the right density, keep it on the
-    // side and only use it if nothing better is found.
-    if (icons[i].density == Manifest::Icon::kDefaultDensity &&
-        IconSizesContainsAny(icons[i].sizes)) {
-      url = icons[i].src;
-    }
-  }
-
-  // The last pass will try to find the best suitable icon for the device's
-  // scale factor. If none, another pass will be run using kDefaultDensity.
-  if (!url.is_valid())
-    url = FindBestMatchingIcon(icons, device_scale_factor);
-  if (!url.is_valid())
-    url = FindBestMatchingIcon(icons, Manifest::Icon::kDefaultDensity);
-
-  return url;
-}
-
 void ShortcutHelper::OnDidGetManifest(const content::Manifest& manifest) {
   if (!manifest.IsEmpty()) {
       content::RecordAction(
           base::UserMetricsAction("webapps.AddShortcut.Manifest"));
   }
 
-  // Set the title based on the manifest value, if any.
-  if (!manifest.short_name.is_null())
-    title_ = manifest.short_name.string();
-  else if (!manifest.name.is_null())
-    title_ = manifest.name.string();
+  shortcut_info_.UpdateFromManifest(manifest);
 
-  // Set the url based on the manifest value, if any.
-  if (manifest.start_url.is_valid())
-    url_ = manifest.start_url;
-
-  // Set the display based on the manifest value, if any.
-  if (manifest.display != content::Manifest::DISPLAY_MODE_UNSPECIFIED)
-    display_ = manifest.display;
-
-  // 'fullscreen' and 'minimal-ui' are not yet supported, fallback to the right
-  // mode in those cases.
-  if (manifest.display == content::Manifest::DISPLAY_MODE_FULLSCREEN)
-    display_ = content::Manifest::DISPLAY_MODE_STANDALONE;
-  if (manifest.display == content::Manifest::DISPLAY_MODE_MINIMAL_UI)
-    display_ = content::Manifest::DISPLAY_MODE_BROWSER;
-
-  // Set the orientation based on the manifest value, if any.
-  if (manifest.orientation != blink::WebScreenOrientationLockDefault) {
-    // Ignore the orientation if the display mode is different from
-    // 'standalone'.
-    // TODO(mlamouri): send a message to the developer console about this.
-    if (display_ == content::Manifest::DISPLAY_MODE_STANDALONE)
-      orientation_ = manifest.orientation;
-  }
-
-  GURL icon_src = FindBestMatchingIcon(manifest.icons);
+  GURL icon_src = ManifestIconSelector::FindBestMatchingIcon(
+      manifest.icons,
+      kPreferredIconSizeInDp,
+      gfx::Screen::GetScreenFor(web_contents()->GetNativeView()));
   if (icon_src.is_valid()) {
     web_contents()->DownloadImage(icon_src,
                                   false,
@@ -286,7 +143,7 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
   ScopedJavaLocalRef<jstring> j_title =
-      base::android::ConvertUTF16ToJavaString(env, title_);
+      base::android::ConvertUTF16ToJavaString(env, shortcut_info_.title);
 
   Java_ShortcutHelper_onInitialized(env, j_obj.obj(), j_title.obj());
 }
@@ -342,7 +199,7 @@
 
   base::string16 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
   if (!title.empty())
-    title_ = title;
+    shortcut_info_.title = title;
 
   switch (manifest_icon_status_) {
     case MANIFEST_ICON_STATUS_NONE:
@@ -364,11 +221,8 @@
   base::WorkerPool::PostTask(
       FROM_HERE,
       base::Bind(&ShortcutHelper::AddShortcutInBackgroundWithSkBitmap,
-                 url_,
-                 title_,
-                 display_,
-                 manifest_icon_,
-                 orientation_),
+                 shortcut_info_,
+                 manifest_icon_),
       true);
 
   Destroy();
@@ -391,7 +245,9 @@
   // Using favicon if its size is not smaller than platform required size,
   // otherwise using the largest icon among all avaliable icons.
   int threshold_to_get_any_largest_icon = preferred_icon_size_in_px_ - 1;
-  favicon_service->GetLargestRawFaviconForPageURL(url_, icon_types,
+  favicon_service->GetLargestRawFaviconForPageURL(
+      shortcut_info_.url,
+      icon_types,
       threshold_to_get_any_largest_icon,
       base::Bind(&ShortcutHelper::OnDidGetFavicon,
                  base::Unretained(this)),
@@ -406,11 +262,8 @@
   base::WorkerPool::PostTask(
       FROM_HERE,
       base::Bind(&ShortcutHelper::AddShortcutInBackgroundWithRawBitmap,
-                 url_,
-                 title_,
-                 display_,
-                 bitmap_result,
-                 orientation_),
+                 shortcut_info_,
+                 bitmap_result),
       true);
 
   Destroy();
@@ -437,11 +290,8 @@
 }
 
 void ShortcutHelper::AddShortcutInBackgroundWithRawBitmap(
-    const GURL& url,
-    const base::string16& title,
-    content::Manifest::DisplayMode display,
-    const favicon_base::FaviconRawBitmapResult& bitmap_result,
-    blink::WebScreenOrientationLockType orientation) {
+    const ShortcutInfo& info,
+    const favicon_base::FaviconRawBitmapResult& bitmap_result) {
   DCHECK(base::WorkerPool::RunsTasksOnCurrentThread());
 
   SkBitmap icon_bitmap;
@@ -451,16 +301,12 @@
                           &icon_bitmap);
   }
 
-  AddShortcutInBackgroundWithSkBitmap(
-      url, title, display, icon_bitmap, orientation);
+  AddShortcutInBackgroundWithSkBitmap(info, icon_bitmap);
 }
 
 void ShortcutHelper::AddShortcutInBackgroundWithSkBitmap(
-    const GURL& url,
-    const base::string16& title,
-    content::Manifest::DisplayMode display,
-    const SkBitmap& icon_bitmap,
-    blink::WebScreenOrientationLockType orientation) {
+    const ShortcutInfo& info,
+    const SkBitmap& icon_bitmap) {
   DCHECK(base::WorkerPool::RunsTasksOnCurrentThread());
 
   SkColor color = color_utils::CalculateKMeanColorOfBitmap(icon_bitmap);
@@ -471,9 +317,9 @@
   // Send the data to the Java side to create the shortcut.
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jstring> java_url =
-      base::android::ConvertUTF8ToJavaString(env, url.spec());
+      base::android::ConvertUTF8ToJavaString(env, info.url.spec());
   ScopedJavaLocalRef<jstring> java_title =
-      base::android::ConvertUTF16ToJavaString(env, title);
+      base::android::ConvertUTF16ToJavaString(env, info.title);
   ScopedJavaLocalRef<jobject> java_bitmap;
   if (icon_bitmap.getSize())
     java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
@@ -487,6 +333,6 @@
       r_value,
       g_value,
       b_value,
-      display == content::Manifest::DISPLAY_MODE_STANDALONE,
-      orientation);
+      info.display == content::Manifest::DISPLAY_MODE_STANDALONE,
+      info.orientation);
 }
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h
index 7c7b749..5b866df 100644
--- a/chrome/browser/android/shortcut_helper.h
+++ b/chrome/browser/android/shortcut_helper.h
@@ -8,13 +8,12 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/basictypes.h"
-#include "base/strings/string16.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "chrome/browser/android/shortcut_info.h"
 #include "chrome/common/web_application_info.h"
 #include "components/favicon_base/favicon_types.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/manifest.h"
-#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
 
 namespace content {
 class WebContents;
@@ -79,26 +78,20 @@
       const favicon_base::FaviconRawBitmapResult& bitmap_result);
 
   // WebContentsObserver
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
-  virtual void WebContentsDestroyed() override;
+  bool OnMessageReceived(const IPC::Message& message) override;
+  void WebContentsDestroyed() override;
 
   // Adds a shortcut to the launcher using a FaviconRawBitmapResult.
   // Must be called from a WorkerPool task.
   static void AddShortcutInBackgroundWithRawBitmap(
-      const GURL& url,
-      const base::string16& title,
-      content::Manifest::DisplayMode display,
-      const favicon_base::FaviconRawBitmapResult& bitmap_result,
-      blink::WebScreenOrientationLockType orientation);
+      const ShortcutInfo& info,
+      const favicon_base::FaviconRawBitmapResult& bitmap_result);
 
   // Adds a shortcut to the launcher using a SkBitmap.
   // Must be called from a WorkerPool task.
   static void AddShortcutInBackgroundWithSkBitmap(
-      const GURL& url,
-      const base::string16& title,
-      content::Manifest::DisplayMode display,
-      const SkBitmap& icon_bitmap,
-      blink::WebScreenOrientationLockType orientation);
+      const ShortcutInfo& info,
+      const SkBitmap& icon_bitmap);
 
   // Registers JNI hooks.
   static bool RegisterShortcutHelper(JNIEnv* env);
@@ -110,43 +103,15 @@
     MANIFEST_ICON_STATUS_DONE
   };
 
-  virtual ~ShortcutHelper();
+  ~ShortcutHelper() override;
 
   void Destroy();
 
-  // Runs the algorithm to find the best matching icon in the icons listed in
-  // the Manifest.
-  // Returns the icon url if a suitable icon is found. An empty URL otherwise.
-  GURL FindBestMatchingIcon(
-      const std::vector<content::Manifest::Icon>& icons) const;
-
-  // Runs an algorithm only based on icon declared sizes. It will try to find
-  // size that is the closest to preferred_icon_size_in_px_ but bigger than
-  // preferred_icon_size_in_px_ if possible.
-  // Returns the icon url if a suitable icon is found. An empty URL otherwise.
-  GURL FindBestMatchingIcon(const std::vector<content::Manifest::Icon>& icons,
-                            float density) const;
-
-  // Returns an array containing the items in |icons| without the unsupported
-  // image MIME types.
-  static std::vector<content::Manifest::Icon> FilterIconsByType(
-      const std::vector<content::Manifest::Icon>& icons);
-
-  // Returns whether the preferred_icon_size_in_px_ is in the given |sizes|.
-  bool IconSizesContainsPreferredSize(
-      const std::vector<gfx::Size>& sizes) const;
-
-  // Returns whether the 'any' (ie. gfx::Size(0,0)) is in the given |sizes|.
-  bool IconSizesContainsAny(const std::vector<gfx::Size>& sizes) const;
-
   JavaObjectWeakGlobalRef java_ref_;
 
-  GURL url_;
-  base::string16 title_;
-  content::Manifest::DisplayMode display_;
+  ShortcutInfo shortcut_info_;
   SkBitmap manifest_icon_;
   base::CancelableTaskTracker cancelable_task_tracker_;
-  blink::WebScreenOrientationLockType orientation_;
 
   bool add_shortcut_requested_;
 
@@ -156,7 +121,6 @@
 
   base::WeakPtrFactory<ShortcutHelper> weak_ptr_factory_;
 
-  friend class ShortcutHelperTest;
   DISALLOW_COPY_AND_ASSIGN(ShortcutHelper);
 };
 
diff --git a/chrome/browser/android/shortcut_info.cc b/chrome/browser/android/shortcut_info.cc
new file mode 100644
index 0000000..24406b8
--- /dev/null
+++ b/chrome/browser/android/shortcut_info.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 "chrome/browser/android/shortcut_info.h"
+
+ShortcutInfo::ShortcutInfo()
+    : display(content::Manifest::DISPLAY_MODE_BROWSER),
+      orientation(blink::WebScreenOrientationLockDefault) {
+}
+
+ShortcutInfo::ShortcutInfo(const GURL& shortcut_url)
+    : url(shortcut_url),
+      display(content::Manifest::DISPLAY_MODE_BROWSER),
+      orientation(blink::WebScreenOrientationLockDefault) {
+}
+
+void ShortcutInfo::UpdateFromManifest(const content::Manifest& manifest) {
+  if (!manifest.short_name.is_null())
+    title = manifest.short_name.string();
+  else if (!manifest.name.is_null())
+    title = manifest.name.string();
+
+  // Set the url based on the manifest value, if any.
+  if (manifest.start_url.is_valid())
+    url = manifest.start_url;
+
+  // Set the display based on the manifest value, if any.
+  if (manifest.display != content::Manifest::DISPLAY_MODE_UNSPECIFIED)
+    display = manifest.display;
+
+  // 'fullscreen' and 'minimal-ui' are not yet supported, fallback to the right
+  // mode in those cases.
+  if (manifest.display == content::Manifest::DISPLAY_MODE_FULLSCREEN)
+    display = content::Manifest::DISPLAY_MODE_STANDALONE;
+  if (manifest.display == content::Manifest::DISPLAY_MODE_MINIMAL_UI)
+    display = content::Manifest::DISPLAY_MODE_BROWSER;
+
+  // Set the orientation based on the manifest value, if any.
+  if (manifest.orientation != blink::WebScreenOrientationLockDefault) {
+    // Ignore the orientation if the display mode is different from
+    // 'standalone'.
+    // TODO(mlamouri): send a message to the developer console about this.
+    if (display == content::Manifest::DISPLAY_MODE_STANDALONE)
+      orientation = manifest.orientation;
+  }
+}
diff --git a/chrome/browser/android/shortcut_info.h b/chrome/browser/android/shortcut_info.h
new file mode 100644
index 0000000..9415103
--- /dev/null
+++ b/chrome/browser/android/shortcut_info.h
@@ -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.
+
+#ifndef CHROME_BROWSER_ANDROID_SHORTCUT_INFO_H_
+#define CHROME_BROWSER_ANDROID_SHORTCUT_INFO_H_
+
+#include "base/strings/string16.h"
+#include "content/public/common/manifest.h"
+#include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
+#include "url/gurl.h"
+
+// Information needed to create a shortcut via ShortcutHelper.
+struct ShortcutInfo {
+  ShortcutInfo();
+  explicit ShortcutInfo(const GURL& shortcut_url);
+
+  // Updates the info based on the given |manifest|.
+  void UpdateFromManifest(const content::Manifest& manifest);
+
+  GURL url;
+  base::string16 title;
+  content::Manifest::DisplayMode display;
+  blink::WebScreenOrientationLockType orientation;
+};
+
+#endif  // CHROME_BROWSER_ANDROID_SHORTCUT_INFO_H_
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc
index c94d203..a2e96e8 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -61,7 +61,7 @@
     remover_->Remove(BrowsingDataRemover::REMOVE_ALL, BrowsingDataHelper::ALL);
   }
 
-  virtual ~ProfileDataRemover() {}
+  ~ProfileDataRemover() override {}
 
   void OnBrowsingDataRemoverDone() override {
     remover_->RemoveObserver(this);
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h
index ce4a95d..23424f8 100644
--- a/chrome/browser/android/signin/signin_manager_android.h
+++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -67,7 +67,7 @@
   jboolean IsSignedInOnNative(JNIEnv* env, jobject obj);
 
  private:
-  virtual ~SigninManagerAndroid();
+  ~SigninManagerAndroid() override;
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
   void OnPolicyRegisterDone(const std::string& dm_token,
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index 57c019b..182e799 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -71,7 +71,7 @@
   static void AttachTabHelpers(content::WebContents* web_contents);
 
   TabAndroid(JNIEnv* env, jobject obj);
-  virtual ~TabAndroid();
+  ~TabAndroid() override;
 
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
 
@@ -111,25 +111,25 @@
 
   // CoreTabHelperDelegate ----------------------------------------------------
 
-  virtual void SwapTabContents(content::WebContents* old_contents,
-                               content::WebContents* new_contents,
-                               bool did_start_load,
-                               bool did_finish_load) override;
+  void SwapTabContents(content::WebContents* old_contents,
+                       content::WebContents* new_contents,
+                       bool did_start_load,
+                       bool did_finish_load) override;
 
   // Overridden from InstantServiceObserver:
   void DefaultSearchProviderChanged() override;
 
   // Overridden from SearchTabHelperDelegate:
-  virtual void OnWebContentsInstantSupportDisabled(
+  void OnWebContentsInstantSupportDisabled(
       const content::WebContents* web_contents) override;
 
   // NotificationObserver -----------------------------------------------------
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) override;
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
 
   // FaviconTabHelperObserver -----------------------------------------------
-  virtual void OnFaviconAvailable(const gfx::Image& image) override;
+  void OnFaviconAvailable(const gfx::Image& image) override;
 
   // Methods called from Java via JNI -----------------------------------------
 
diff --git a/chrome/browser/android/thumbnail/thumbnail.h b/chrome/browser/android/thumbnail/thumbnail.h
index 49de59c..79ed868 100644
--- a/chrome/browser/android/thumbnail/thumbnail.h
+++ b/chrome/browser/android/thumbnail/thumbnail.h
@@ -42,7 +42,7 @@
       float scale,
       ui::UIResourceProvider* ui_resource_provider,
       ThumbnailDelegate* thumbnail_delegate);
-  virtual ~Thumbnail();
+  ~Thumbnail() override;
 
   TabId tab_id() const { return tab_id_; }
   base::Time time_stamp() const { return time_stamp_; }
@@ -57,11 +57,11 @@
   void CreateUIResource();
 
   // content::UIResourceClient implementation.
-  virtual cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid,
-                                         bool resource_lost) override;
+  cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid,
+                                 bool resource_lost) override;
 
   // ui::UIResourceClientAndroid implementation.
-  virtual void UIResourceIsInvalid() override;
+  void UIResourceIsInvalid() override;
 
  protected:
   Thumbnail(TabId tab_id,
diff --git a/chrome/browser/android/thumbnail/thumbnail_store.h b/chrome/browser/android/thumbnail/thumbnail_store.h
index 94cdbba..8ad0c1a 100644
--- a/chrome/browser/android/thumbnail/thumbnail_store.h
+++ b/chrome/browser/android/thumbnail/thumbnail_store.h
@@ -50,7 +50,7 @@
                  size_t write_queue_max_size,
                  bool use_approximation_thumbnail);
 
-  virtual ~ThumbnailStore();
+  ~ThumbnailStore() override;
 
   void SetUIResourceProvider(ui::UIResourceProvider* ui_resource_provider);
 
@@ -72,7 +72,7 @@
           post_decompress_callback);
 
   // ThumbnailDelegate implementation
-  virtual void InvalidateCachedThumbnail(Thumbnail* thumbnail) override;
+  void InvalidateCachedThumbnail(Thumbnail* thumbnail) override;
 
  private:
   class ThumbnailMetaData {
diff --git a/chrome/browser/android/webapps/single_tab_mode_tab_helper.h b/chrome/browser/android/webapps/single_tab_mode_tab_helper.h
index a79fd2e..744aee3da 100644
--- a/chrome/browser/android/webapps/single_tab_mode_tab_helper.h
+++ b/chrome/browser/android/webapps/single_tab_mode_tab_helper.h
@@ -30,7 +30,7 @@
   // Checks if the ID pair is blocked from creating new windows. IO-thread only.
   static bool IsRegistered(int32 process_id, int32 routing_id);
 
-  virtual ~SingleTabModeTabHelper();
+  ~SingleTabModeTabHelper() override;
 
   // Handles opening the given URL through the TabModel.
   void HandleOpenUrl(const BlockedWindowParams& params);
@@ -40,10 +40,8 @@
   void PermanentlyBlockAllNewWindows();
 
   // content::WebContentsObserver
-  virtual void RenderViewCreated(content::RenderViewHost* render_view_host)
-      override;
-  virtual void RenderViewDeleted(content::RenderViewHost* render_view_host)
-      override;
+  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+  void RenderViewDeleted(content::RenderViewHost* render_view_host) override;
 
  private:
   explicit SingleTabModeTabHelper(content::WebContents* web_contents);
diff --git a/chrome/browser/apps/app_shim/browser_app_shim.gypi b/chrome/browser/apps/app_shim/browser_app_shim.gypi
index 4c6c9aa8..806ebe7a 100644
--- a/chrome/browser/apps/app_shim/browser_app_shim.gypi
+++ b/chrome/browser/apps/app_shim/browser_app_shim.gypi
@@ -10,8 +10,9 @@
       'target_name': 'browser_app_shim',
       'type': 'static_library',
       'dependencies': [
-        # Since browser_app_shim and browser depend on each other, we omit the
-        # dependency on browser here.
+        # Since browser_app_shim and chrome.gyp:browser depend on each other,
+        # we omit the dependency on browser here.
+        '../content/content.gyp:content_browser',
         '../content/content.gyp:content_common',
       ],
       'sources': [
diff --git a/chrome/browser/apps/ephemeral_app_browsertest.cc b/chrome/browser/apps/ephemeral_app_browsertest.cc
index 53c2991..d28dd32 100644
--- a/chrome/browser/apps/ephemeral_app_browsertest.cc
+++ b/chrome/browser/apps/ephemeral_app_browsertest.cc
@@ -273,8 +273,8 @@
       content::Source<extensions::CrxInstaller>(crx_installer));
   ExtensionService* service =
       ExtensionSystem::Get(profile())->extension_service();
-  EXPECT_TRUE(service->UpdateExtension(app_id, app_v2_path, true,
-                                       &crx_installer));
+  EXPECT_TRUE(service->UpdateExtension(
+      extensions::CRXFileInfo(app_id, app_v2_path), true, &crx_installer));
   windowed_observer.Wait();
 
   return ExtensionRegistry::Get(profile())
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.h b/chrome/browser/autofill/android/personal_data_manager_android.h
index b951ff2..ed818a3 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.h
+++ b/chrome/browser/autofill/android/personal_data_manager_android.h
@@ -88,13 +88,13 @@
   void ClearUnmaskedCache(JNIEnv* env, jobject unused_obj);
 
   // PersonalDataManagerObserver:
-  virtual void OnPersonalDataChanged() override;
+  void OnPersonalDataChanged() override;
 
   // Registers the JNI bindings for this class.
   static bool Register(JNIEnv* env);
 
  private:
-  virtual ~PersonalDataManagerAndroid();
+  ~PersonalDataManagerAndroid() override;
 
   // Pointer to the java counterpart.
   JavaObjectWeakGlobalRef weak_java_obj_;
diff --git a/chrome/browser/background/background_contents.cc b/chrome/browser/background/background_contents.cc
index 9d015339..7a1150b3 100644
--- a/chrome/browser/background/background_contents.cc
+++ b/chrome/browser/background/background_contents.cc
@@ -118,11 +118,11 @@
 void BackgroundContents::AddNewContents(WebContents* source,
                                         WebContents* new_contents,
                                         WindowOpenDisposition disposition,
-                                        const gfx::Rect& initial_pos,
+                                        const gfx::Rect& initial_rect,
                                         bool user_gesture,
                                         bool* was_blocked) {
   delegate_->AddWebContents(
-      new_contents, disposition, initial_pos, user_gesture, was_blocked);
+      new_contents, disposition, initial_rect, user_gesture, was_blocked);
 }
 
 bool BackgroundContents::IsNeverVisible(content::WebContents* web_contents) {
diff --git a/chrome/browser/background/background_contents.h b/chrome/browser/background/background_contents.h
index 59711e4b..e7345e3 100644
--- a/chrome/browser/background/background_contents.h
+++ b/chrome/browser/background/background_contents.h
@@ -36,7 +36,7 @@
     // set to true if the popup gets blocked, and left unchanged otherwise.
     virtual void AddWebContents(content::WebContents* new_contents,
                                 WindowOpenDisposition disposition,
-                                const gfx::Rect& initial_pos,
+                                const gfx::Rect& initial_rect,
                                 bool user_gesture,
                                 bool* was_blocked) = 0;
 
@@ -63,7 +63,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   bool IsNeverVisible(content::WebContents* web_contents) override;
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index f502748..361107b 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -767,7 +767,7 @@
 void BackgroundContentsService::AddWebContents(
     WebContents* new_contents,
     WindowOpenDisposition disposition,
-    const gfx::Rect& initial_pos,
+    const gfx::Rect& initial_rect,
     bool user_gesture,
     bool* was_blocked) {
   Browser* browser = chrome::FindLastActiveWithProfile(
@@ -775,6 +775,6 @@
       chrome::GetActiveDesktop());
   if (browser) {
     chrome::AddWebContents(browser, NULL, new_contents, disposition,
-                           initial_pos, user_gesture, was_blocked);
+                           initial_rect, user_gesture, was_blocked);
   }
 }
diff --git a/chrome/browser/background/background_contents_service.h b/chrome/browser/background/background_contents_service.h
index 81243bb..380982b 100644
--- a/chrome/browser/background/background_contents_service.h
+++ b/chrome/browser/background/background_contents_service.h
@@ -91,7 +91,7 @@
   // BackgroundContents::Delegate implementation.
   void AddWebContents(content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
 
diff --git a/chrome/browser/browser_process_platform_part_android.h b/chrome/browser/browser_process_platform_part_android.h
index 7c764fad..9f8ee3c 100644
--- a/chrome/browser/browser_process_platform_part_android.h
+++ b/chrome/browser/browser_process_platform_part_android.h
@@ -11,10 +11,10 @@
 class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase {
  public:
   BrowserProcessPlatformPart();
-  virtual ~BrowserProcessPlatformPart();
+  ~BrowserProcessPlatformPart() override;
 
   // Overridden from BrowserProcessPlatformPartBase:
-  virtual void AttemptExit() override;
+  void AttemptExit() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPart);
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index e9e9933..2b86dc0 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -553,10 +553,6 @@
 
 // BrowserMainParts ------------------------------------------------------------
 
-// static
-bool ChromeBrowserMainParts::disable_enforcing_cookie_policies_for_tests_ =
-    false;
-
 ChromeBrowserMainParts::ChromeBrowserMainParts(
     const content::MainFunctionParams& parameters)
     : parameters_(parameters),
@@ -577,8 +573,7 @@
   // Chrome disallows cookies by default. All code paths that want to use
   // cookies need to go through one of Chrome's URLRequestContexts which have
   // a ChromeNetworkDelegate attached that selectively allows cookies again.
-  if (!disable_enforcing_cookie_policies_for_tests_)
-    net::URLRequest::SetDefaultCookiePolicyToBlock();
+  net::URLRequest::SetDefaultCookiePolicyToBlock();
 }
 
 ChromeBrowserMainParts::~ChromeBrowserMainParts() {
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index aa9d6cc..5d60afa3 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -185,10 +185,6 @@
   // Members needed across shutdown methods.
   bool restart_last_session_;
 
-  // Tests can set this to true to disable restricting cookie access in the
-  // network stack, as this can only be done once.
-  static bool disable_enforcing_cookie_policies_for_tests_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainParts);
 };
 
diff --git a/chrome/browser/chrome_browser_main_android.h b/chrome/browser/chrome_browser_main_android.h
index f0d68d5..8781d982 100644
--- a/chrome/browser/chrome_browser_main_android.h
+++ b/chrome/browser/chrome_browser_main_android.h
@@ -17,15 +17,15 @@
  public:
   explicit ChromeBrowserMainPartsAndroid(
       const content::MainFunctionParams& parameters);
-  virtual ~ChromeBrowserMainPartsAndroid();
+  ~ChromeBrowserMainPartsAndroid() override;
 
   // content::BrowserMainParts overrides.
-  virtual int PreCreateThreads() override;
-  virtual void PostProfileInit() override;
-  virtual void PreEarlyInitialization() override;
+  int PreCreateThreads() override;
+  void PostProfileInit() override;
+  void PreEarlyInitialization() override;
 
   // ChromeBrowserMainParts overrides.
-  virtual void ShowMissingLocaleMessageBox() override;
+  void ShowMissingLocaleMessageBox() override;
 
  private:
   scoped_ptr<base::MessageLoop> main_message_loop_;
diff --git a/chrome/browser/chrome_site_per_process_browsertest.cc b/chrome/browser/chrome_site_per_process_browsertest.cc
index 2f212aa7..1ed8186 100644
--- a/chrome/browser/chrome_site_per_process_browsertest.cc
+++ b/chrome/browser/chrome_site_per_process_browsertest.cc
@@ -41,6 +41,15 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeSitePerProcessTest);
 };
 
+// Verify that browser shutdown path works correctly when there's a
+// RenderFrameProxyHost for a child frame.
+IN_PROC_BROWSER_TEST_F(ChromeSitePerProcessTest, RenderFrameProxyHostShutdown) {
+  GURL main_url(embedded_test_server()->GetURL(
+        "a.com",
+        "/frame_tree/page_with_two_frames_remote_and_local.html"));
+  ui_test_utils::NavigateToURL(browser(), main_url);
+}
+
 // Verify that origin replication allows JS access to localStorage, database,
 // and FileSystem APIs.  These features involve a check on the
 // WebSecurityOrigin of the topmost WebFrame in ContentSettingsObserver, and
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 13f5305..8fa28a3 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -110,6 +110,7 @@
     "//ui/chromeos:ui_chromeos",
     "//ui/compositor",
     "//ui/display",
+    "//ui/events/devices",
     "//ui/events/platform",
     "//ui/events:dom4_keycode_converter",
     "//ui/file_manager",
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index 5c2e583..8407bda 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -575,7 +575,8 @@
   DISALLOW_COPY_AND_ASSIGN(OobeSpokenFeedbackTest);
 };
 
-IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, SpokenFeedbackInOobe) {
+// Test is flaky: http://crbug.com/346797
+IN_PROC_BROWSER_TEST_F(OobeSpokenFeedbackTest, DISABLED_SpokenFeedbackInOobe) {
   ui_controls::EnableUIControls();
   ASSERT_FALSE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
index e9b34015..93b45f37 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -146,12 +146,10 @@
     }
 
     scoped_refptr<extensions::SandboxedUnpacker> unpacker(
-        new extensions::SandboxedUnpacker(crx_file_,
-                                          extensions::Manifest::INTERNAL,
-                                          extensions::Extension::NO_FLAGS,
-                                          temp_dir_.path(),
-                                          task_runner_.get(),
-                                          this));
+        new extensions::SandboxedUnpacker(
+            extensions::CRXFileInfo(crx_file_), extensions::Manifest::INTERNAL,
+            extensions::Extension::NO_FLAGS, temp_dir_.path(),
+            task_runner_.get(), this));
     unpacker->Start();
   }
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.cc b/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.cc
index ed2754e..e1ed18c 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.cc
@@ -14,13 +14,11 @@
 
 KioskExternalUpdateValidator::KioskExternalUpdateValidator(
     const scoped_refptr<base::SequencedTaskRunner>& backend_task_runner,
-    const std::string& app_id,
-    const base::FilePath& crx_dir,
+    const extensions::CRXFileInfo& file,
     const base::FilePath& crx_unpack_dir,
     const base::WeakPtr<KioskExternalUpdateValidatorDelegate>& delegate)
     : backend_task_runner_(backend_task_runner),
-      app_id_(app_id),
-      crx_dir_(crx_dir),
+      crx_file_(file),
       crx_unpack_dir_(crx_unpack_dir),
       delegate_(delegate) {
 }
@@ -30,12 +28,10 @@
 
 void KioskExternalUpdateValidator::Start() {
   scoped_refptr<extensions::SandboxedUnpacker> unpacker(
-      new extensions::SandboxedUnpacker(crx_dir_,
-                                        extensions::Manifest::EXTERNAL_PREF,
-                                        extensions::Extension::NO_FLAGS,
-                                        crx_unpack_dir_,
-                                        backend_task_runner_.get(),
-                                        this));
+      new extensions::SandboxedUnpacker(
+          crx_file_, extensions::Manifest::EXTERNAL_PREF,
+          extensions::Extension::NO_FLAGS, crx_unpack_dir_,
+          backend_task_runner_.get(), this));
   if (!backend_task_runner_->PostTask(
           FROM_HERE,
           base::Bind(&extensions::SandboxedUnpacker::Start, unpacker.get()))) {
@@ -45,15 +41,13 @@
 
 void KioskExternalUpdateValidator::OnUnpackFailure(
     const base::string16& error_message) {
-  LOG(ERROR) << "Failed to unpack external kiosk crx file: " << app_id_ << " "
-             << error_message;
+  LOG(ERROR) << "Failed to unpack external kiosk crx file: "
+             << crx_file_.extension_id << " " << error_message;
   content::BrowserThread::PostTask(
-      content::BrowserThread::UI,
-      FROM_HERE,
+      content::BrowserThread::UI, FROM_HERE,
       base::Bind(
           &KioskExternalUpdateValidatorDelegate::OnExternalUpdateUnpackFailure,
-          delegate_,
-          app_id_));
+          delegate_, crx_file_.extension_id));
 }
 
 void KioskExternalUpdateValidator::OnUnpackSuccess(
@@ -62,26 +56,23 @@
     const base::DictionaryValue* original_manifest,
     const extensions::Extension* extension,
     const SkBitmap& install_icon) {
-  DCHECK(app_id_ == extension->id());
+  DCHECK(crx_file_.extension_id == extension->id());
 
   std::string minimum_browser_version;
   if (!extension->manifest()->GetString(
           extensions::manifest_keys::kMinimumChromeVersion,
           &minimum_browser_version)) {
-    LOG(ERROR) << "Can't find minimum browser version for app " << app_id_;
+    LOG(ERROR) << "Can't find minimum browser version for app "
+               << crx_file_.extension_id;
     minimum_browser_version.clear();
   }
 
   content::BrowserThread::PostTask(
-      content::BrowserThread::UI,
-      FROM_HERE,
+      content::BrowserThread::UI, FROM_HERE,
       base::Bind(
           &KioskExternalUpdateValidatorDelegate::OnExtenalUpdateUnpackSuccess,
-          delegate_,
-          app_id_,
-          extension->VersionString(),
-          minimum_browser_version,
-          temp_dir));
+          delegate_, crx_file_.extension_id, extension->VersionString(),
+          minimum_browser_version, temp_dir));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.h b/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.h
index dd02095..4d85f605 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.h
+++ b/chrome/browser/chromeos/app_mode/kiosk_external_update_validator.h
@@ -39,8 +39,7 @@
  public:
   KioskExternalUpdateValidator(
       const scoped_refptr<base::SequencedTaskRunner>& backend_task_runner,
-      const std::string& app_id,
-      const base::FilePath& crx_path,
+      const extensions::CRXFileInfo& file,
       const base::FilePath& crx_unpack_dir,
       const base::WeakPtr<KioskExternalUpdateValidatorDelegate>& delegate);
 
@@ -60,10 +59,10 @@
 
   // Task runner for executing file I/O tasks.
   const scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
-  std::string app_id_;
 
-  // The directory where the external crx file resides.
-  base::FilePath crx_dir_;
+  // Information about the external crx file.
+  extensions::CRXFileInfo crx_file_;
+
   // The temporary directory used by SandBoxedUnpacker for unpacking extensions.
   const base::FilePath crx_unpack_dir_;
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc b/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc
index bcef462..1617cc8a 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc
@@ -93,6 +93,9 @@
 KioskExternalUpdater::ExternalUpdate::ExternalUpdate() {
 }
 
+KioskExternalUpdater::ExternalUpdate::~ExternalUpdate() {
+}
+
 KioskExternalUpdater::KioskExternalUpdater(
     const scoped_refptr<base::SequencedTaskRunner>& backend_task_runner,
     const base::FilePath& crx_cache_dir,
@@ -196,7 +199,8 @@
   if (CheckExternalUpdateInterrupted())
     return;
 
-  base::FilePath external_crx_path = external_updates_[app_id].external_crx;
+  base::FilePath external_crx_path =
+      external_updates_[app_id].external_crx.path;
   base::FilePath temp_crx_path =
       crx_unpack_dir_.Append(external_crx_path.BaseName());
   bool* success = new bool;
@@ -291,7 +295,8 @@
     } else {
       NOTREACHED();
     }
-    update.external_crx = external_update_path_.AppendASCII(external_crx_str);
+    update.external_crx = extensions::CRXFileInfo(
+        app_id, external_update_path_.AppendASCII(external_crx_str));
     update.update_status = PENDING;
     external_updates_[app_id] = update;
   }
@@ -326,7 +331,6 @@
     if (it->second.update_status == PENDING) {
       scoped_refptr<KioskExternalUpdateValidator> crx_validator =
           new KioskExternalUpdateValidator(backend_task_runner_,
-                                           it->first,
                                            it->second.external_crx,
                                            crx_unpack_dir_,
                                            weak_factory_.GetWeakPtr());
@@ -429,7 +433,7 @@
     external_updates_[app_id].update_status = FAILED;
     external_updates_[app_id].error = l10n_util::GetStringFUTF16(
         IDS_KIOSK_EXTERNAL_UPDATE_CANNOT_INSTALL_IN_LOCAL_CACHE,
-        base::UTF8ToUTF16(external_updates_[app_id].external_crx.value()));
+        base::UTF8ToUTF16(external_updates_[app_id].external_crx.path.value()));
   } else {
     external_updates_[app_id].update_status = SUCCESS;
   }
diff --git a/chrome/browser/chromeos/app_mode/kiosk_external_updater.h b/chrome/browser/chromeos/app_mode/kiosk_external_updater.h
index 02c40dc3..f56b0f72 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_external_updater.h
+++ b/chrome/browser/chromeos/app_mode/kiosk_external_updater.h
@@ -45,9 +45,10 @@
   };
   struct ExternalUpdate {
     ExternalUpdate();
+    ~ExternalUpdate();
 
     std::string app_name;
-    base::FilePath external_crx;
+    extensions::CRXFileInfo external_crx;
     ExternalUpdateStatus update_status;
     base::string16 error;
   };
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 4bdd7dd6c..a7652a3 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -272,8 +272,13 @@
 
 void StartupAppLauncher::OnFinishCrxInstall(const std::string& extension_id,
                                             bool success) {
-  if (extension_id != app_id_)
+  // Wait for pending updates or dependent extensions to download.
+  if (extensions::ExtensionSystem::Get(profile_)
+          ->extension_service()
+          ->pending_extension_manager()
+          ->HasPendingExtensions()) {
     return;
+  }
 
   extensions::InstallTracker* tracker =
       extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc
index 6fb6233..6255d15 100644
--- a/chrome/browser/chromeos/display/display_preferences_unittest.cc
+++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc
@@ -674,20 +674,18 @@
                                       gfx::Display::ROTATE_0);
 
   // Open up 270 degrees to trigger maximize mode
-  ui::AccelerometerUpdate update;
-  update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD,
-             0.0f, 0.0f, kMeanGravity);
-  update.Set(ui::ACCELEROMETER_SOURCE_SCREEN,
-             0.0f, -kMeanGravity, 0.0f);
+  chromeos::AccelerometerUpdate update;
+  update.Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, 0.0f, 0.0f,
+             kMeanGravity);
+  update.Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, 0.0f, -kMeanGravity, 0.0f);
   ash::MaximizeModeController* controller = shell->maximize_mode_controller();
   controller->OnAccelerometerUpdated(update);
   EXPECT_TRUE(controller->IsMaximizeModeWindowManagerEnabled());
 
   // Trigger 90 degree rotation
-  update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD,
-             -kMeanGravity, 0.0f, 0.0f);
-  update.Set(ui::ACCELEROMETER_SOURCE_SCREEN,
-             -kMeanGravity, 0.0f, 0.0f);
+  update.Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, -kMeanGravity,
+             0.0f, 0.0f);
+  update.Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, -kMeanGravity, 0.0f, 0.0f);
   controller->OnAccelerometerUpdated(update);
   shell->screen_orientation_controller()->OnAccelerometerUpdated(update);
   EXPECT_EQ(gfx::Display::ROTATE_90, display_manager->
@@ -814,11 +812,10 @@
   EXPECT_EQ(gfx::Display::ROTATE_0, before_maximize_mode_rotation);
 
   // Open up 270 degrees to trigger maximize mode
-  ui::AccelerometerUpdate update;
-  update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD,
-             0.0f, 0.0f, kMeanGravity);
-  update.Set(ui::ACCELEROMETER_SOURCE_SCREEN,
-             0.0f, -kMeanGravity, 0.0f);
+  chromeos::AccelerometerUpdate update;
+  update.Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, 0.0f, 0.0f,
+             kMeanGravity);
+  update.Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, 0.0f, -kMeanGravity, 0.0f);
   ash::MaximizeModeController* maximize_mode_controller =
       shell->maximize_mode_controller();
   maximize_mode_controller->OnAccelerometerUpdated(update);
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
index 7eaa7b0..aed81d1 100644
--- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc
+++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -17,12 +17,12 @@
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/preferences.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
@@ -222,7 +222,7 @@
 class EventRewriterTest : public ash::test::AshTestBase {
  public:
   EventRewriterTest()
-      : fake_user_manager_(new chromeos::FakeUserManager),
+      : fake_user_manager_(new user_manager::FakeUserManager),
         user_manager_enabler_(fake_user_manager_),
         input_method_manager_mock_(NULL) {}
   ~EventRewriterTest() override {}
@@ -255,7 +255,7 @@
                       : &event;
   }
 
-  chromeos::FakeUserManager* fake_user_manager_;  // Not owned.
+  user_manager::FakeUserManager* fake_user_manager_;  // Not owned.
   chromeos::ScopedUserManagerEnabler user_manager_enabler_;
   chromeos::input_method::MockInputMethodManager* input_method_manager_mock_;
 };
@@ -1821,7 +1821,7 @@
  public:
   EventRewriterAshTest()
       : source_(&buffer_),
-        fake_user_manager_(new chromeos::FakeUserManager),
+        fake_user_manager_(new user_manager::FakeUserManager),
         user_manager_enabler_(fake_user_manager_) {}
   ~EventRewriterAshTest() override {}
 
@@ -1880,7 +1880,7 @@
   EventBuffer buffer_;
   TestEventSource source_;
 
-  chromeos::FakeUserManager* fake_user_manager_;  // Not owned.
+  user_manager::FakeUserManager* fake_user_manager_;  // Not owned.
   chromeos::ScopedUserManagerEnabler user_manager_enabler_;
   TestingPrefServiceSyncable prefs_;
 
diff --git a/chrome/browser/chromeos/extensions/external_cache.cc b/chrome/browser/chromeos/extensions/external_cache.cc
index dd2a00f..c3f7b47b 100644
--- a/chrome/browser/chromeos/extensions/external_cache.cc
+++ b/chrome/browser/chromeos/extensions/external_cache.cc
@@ -179,18 +179,17 @@
 }
 
 void ExternalCache::OnExtensionDownloadFinished(
-    const std::string& id,
-    const base::FilePath& path,
+    const extensions::CRXFileInfo& file,
     bool file_ownership_passed,
     const GURL& download_url,
     const std::string& version,
     const extensions::ExtensionDownloaderDelegate::PingResult& ping_result,
     const std::set<int>& request_ids) {
   DCHECK(file_ownership_passed);
-  local_cache_.PutExtension(id, path, version,
-                            base::Bind(&ExternalCache::OnPutExtension,
-                                       weak_ptr_factory_.GetWeakPtr(),
-                                       id));
+  local_cache_.PutExtension(
+      file.extension_id, file.path, version,
+      base::Bind(&ExternalCache::OnPutExtension, weak_ptr_factory_.GetWeakPtr(),
+                 file.extension_id));
 }
 
 bool ExternalCache::IsExtensionPending(const std::string& id) {
diff --git a/chrome/browser/chromeos/extensions/external_cache.h b/chrome/browser/chromeos/extensions/external_cache.h
index 6b4590a..f85e00a 100644
--- a/chrome/browser/chromeos/extensions/external_cache.h
+++ b/chrome/browser/chromeos/extensions/external_cache.h
@@ -91,8 +91,7 @@
                                  const PingResult& ping_result,
                                  const std::set<int>& request_ids) override;
 
-  void OnExtensionDownloadFinished(const std::string& id,
-                                   const base::FilePath& path,
+  void OnExtensionDownloadFinished(const extensions::CRXFileInfo& file,
                                    bool file_ownership_passed,
                                    const GURL& download_url,
                                    const std::string& version,
diff --git a/chrome/browser/chromeos/extensions/external_cache_unittest.cc b/chrome/browser/chromeos/extensions/external_cache_unittest.cc
index e0c63155..df6baeb1 100644
--- a/chrome/browser/chromeos/extensions/external_cache_unittest.cc
+++ b/chrome/browser/chromeos/extensions/external_cache_unittest.cc
@@ -205,13 +205,9 @@
   base::FilePath temp_dir(CreateTempDir());
   base::FilePath temp_file2 = temp_dir.Append("b.crx");
   CreateFile(temp_file2);
-  external_cache.OnExtensionDownloadFinished(kTestExtensionId2,
-      temp_file2,
-      true,
-      GURL(),
-      "2",
-      extensions::ExtensionDownloaderDelegate::PingResult(),
-      std::set<int>());
+  external_cache.OnExtensionDownloadFinished(
+      extensions::CRXFileInfo(kTestExtensionId2, temp_file2), true, GURL(), "2",
+      extensions::ExtensionDownloaderDelegate::PingResult(), std::set<int>());
 
   WaitForCompletion();
   EXPECT_EQ(provided_prefs()->size(), 3ul);
@@ -234,13 +230,9 @@
   // Update not from Webstore.
   base::FilePath temp_file4 = temp_dir.Append("d.crx");
   CreateFile(temp_file4);
-  external_cache.OnExtensionDownloadFinished(kTestExtensionId4,
-      temp_file4,
-      true,
-      GURL(),
-      "4",
-      extensions::ExtensionDownloaderDelegate::PingResult(),
-      std::set<int>());
+  external_cache.OnExtensionDownloadFinished(
+      extensions::CRXFileInfo(kTestExtensionId4, temp_file4), true, GURL(), "4",
+      extensions::ExtensionDownloaderDelegate::PingResult(), std::set<int>());
 
   WaitForCompletion();
   EXPECT_EQ(provided_prefs()->size(), 4ul);
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
index b7b52fa..df7ec57 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -34,6 +34,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/escape.h"
+#include "storage/browser/blob/file_stream_reader.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_file_util.h"
 #include "storage/browser/fileapi/file_system_operation_context.h"
@@ -212,6 +213,16 @@
   callback.Run(result == base::File::FILE_OK);
 }
 
+// Calls a response callback (on the UI thread) with a file content hash
+// computed on the IO thread.
+void ComputeChecksumRespondOnUIThread(
+    const base::Callback<void(const std::string&)>& callback,
+    const std::string& hash) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(callback, hash));
+}
+
 }  // namespace
 
 void FileManagerPrivateRequestFileSystemFunction::DidFail(
@@ -713,13 +724,23 @@
   SendResponse(true);
 }
 
+FileManagerPrivateComputeChecksumFunction::
+    FileManagerPrivateComputeChecksumFunction()
+    : digester_(new drive::util::FileStreamMd5Digester()) {
+}
+
+FileManagerPrivateComputeChecksumFunction::
+    ~FileManagerPrivateComputeChecksumFunction() {
+}
+
 bool FileManagerPrivateComputeChecksumFunction::RunAsync() {
   using extensions::api::file_manager_private::ComputeChecksum::Params;
+  using drive::util::FileStreamMd5Digester;
   const scoped_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
 
   if (params->file_url.empty()) {
-    // TODO(kenobi): call SetError()
+    SetError("File URL must be provided");
     return false;
   }
 
@@ -727,23 +748,30 @@
       file_manager::util::GetFileSystemContextForRenderViewHost(
           GetProfile(), render_view_host());
 
-  storage::FileSystemURL file_url(
-      file_system_context->CrackURL(GURL(params->file_url)));
+  FileSystemURL file_url(file_system_context->CrackURL(GURL(params->file_url)));
   if (!file_url.is_valid()) {
-    // TODO(kenobi): Call SetError()
+    SetError("File URL was invalid");
     return false;
   }
 
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&drive::util::GetMd5Digest, file_url.path()),
+  scoped_ptr<storage::FileStreamReader> reader =
+      file_system_context->CreateFileStreamReader(
+          file_url, 0, storage::kMaximumLength, base::Time());
+
+  FileStreamMd5Digester::ResultCallback result_callback = base::Bind(
+      &ComputeChecksumRespondOnUIThread,
       base::Bind(&FileManagerPrivateComputeChecksumFunction::Respond, this));
+  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+                          base::Bind(&FileStreamMd5Digester::GetMd5Digest,
+                                     base::Unretained(digester_.get()),
+                                     base::Passed(&reader), result_callback));
 
   return true;
 }
 
 void FileManagerPrivateComputeChecksumFunction::Respond(
     const std::string& hash) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   SetResult(new base::StringValue(hash));
   SendResponse(true);
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h
index 5e3838ed..467873e 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h
@@ -31,6 +31,9 @@
 }  // namespace file_manager
 
 namespace drive {
+namespace util {
+class FileStreamMd5Digester;
+}  // namespace util
 struct HashAndFilePath;
 }  // namespace drive
 
@@ -236,16 +239,20 @@
 class FileManagerPrivateComputeChecksumFunction
     : public LoggedAsyncExtensionFunction {
  public:
+  FileManagerPrivateComputeChecksumFunction();
+
   DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.computeChecksum",
                              FILEMANAGERPRIVATE_COMPUTECHECKSUM)
 
  protected:
-  ~FileManagerPrivateComputeChecksumFunction() override {}
+  ~FileManagerPrivateComputeChecksumFunction() override;
 
   // AsyncExtensionFunction overrides.
   bool RunAsync() override;
 
  private:
+  scoped_ptr<drive::util::FileStreamMd5Digester> digester_;
+
   void Respond(const std::string& hash);
 };
 
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
index 52e2d13d..13eb977f 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/extensions/wallpaper_private_api.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
@@ -27,17 +27,14 @@
 class WallpaperPrivateApiUnittest : public ash::test::AshTestBase {
  public:
   WallpaperPrivateApiUnittest()
-      : fake_user_manager_(new FakeUserManager()),
-        scoped_user_manager_(fake_user_manager_) {
-  }
+      : fake_user_manager_(new FakeChromeUserManager()),
+        scoped_user_manager_(fake_user_manager_) {}
 
  protected:
-  FakeUserManager* fake_user_manager() {
-    return fake_user_manager_;
-  }
+  FakeChromeUserManager* fake_user_manager() { return fake_user_manager_; }
 
  private:
-  FakeUserManager* fake_user_manager_;
+  FakeChromeUserManager* fake_user_manager_;
   ScopedUserManagerEnabler scoped_user_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(WallpaperPrivateApiUnittest);
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 07062b0..8c7ae1b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -1039,11 +1039,13 @@
         TestParameter(NOT_IN_GUEST_MODE, "executeDefaultTaskOnDrive")));
 
 // Slow tests are disabled on debug build. http://crbug.com/327719
-// In addition, this test in particular has become very flaky as of this CL:
-//   https://codereview.chromium.org/838193002/
-// Disable completely until further investigation. See: http://crbug.com/444574.
+#if !defined(NDEBUG)
+#define MAYBE_DefaultActionDialog DISABLED_DefaultActionDialog
+#else
+#define MAYBE_DefaultActionDialog DefaultActionDialog
+#endif
 WRAPPED_INSTANTIATE_TEST_CASE_P(
-    DISABLED_DefaultActionDialog,
+    MAYBE_DefaultActionDialog,
     FileManagerBrowserTest,
     ::testing::Values(
         TestParameter(NOT_IN_GUEST_MODE, "defaultActionDialogOnDownloads"),
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index 86bd587..addd0ef 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -149,3 +149,13 @@
   RunTest(base::FilePath(FILE_PATH_LITERAL(
       "foreground/js/metadata/file_system_metadata_provider_unittest.html")));
 }
+
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ExternalMetadataProvider) {
+  RunTest(base::FilePath(FILE_PATH_LITERAL(
+      "foreground/js/metadata/external_metadata_provider_unittest.html")));
+}
+
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ContentMetadataProvider) {
+  RunTest(base::FilePath(FILE_PATH_LITERAL(
+      "foreground/js/metadata/content_metadata_provider_unittest.html")));
+}
diff --git a/chrome/browser/chromeos/file_manager/open_with_browser.cc b/chrome/browser/chromeos/file_manager/open_with_browser.cc
index 974b34a..7384caf3 100644
--- a/chrome/browser/chromeos/file_manager/open_with_browser.cc
+++ b/chrome/browser/chromeos/file_manager/open_with_browser.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
+#include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
@@ -86,8 +87,8 @@
 bool IsPdfPluginEnabled(Profile* profile) {
   DCHECK(profile);
 
-  base::FilePath plugin_path;
-  PathService::Get(chrome::FILE_PDF_PLUGIN, &plugin_path);
+  base::FilePath plugin_path = base::FilePath::FromUTF8Unsafe(
+      ChromeContentClient::kPDFPluginPath);
   return IsPepperPluginEnabled(profile, plugin_path);
 }
 
diff --git a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
index ba0a05c..d8efb006 100644
--- a/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/mount_path_util_unittest.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
 #include "chrome/browser/chromeos/file_system_provider/service.h"
 #include "chrome/browser/chromeos/file_system_provider/service_factory.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -74,7 +74,7 @@
         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
     ASSERT_TRUE(profile_manager_->SetUp());
     profile_ = profile_manager_->CreateTestingProfile("testing-profile");
-    user_manager_ = new FakeUserManager();
+    user_manager_ = new FakeChromeUserManager();
     user_manager_enabler_.reset(new ScopedUserManagerEnabler(user_manager_));
     user_manager_->AddUser(profile_->GetProfileName());
     ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
@@ -93,7 +93,7 @@
   scoped_ptr<TestingProfileManager> profile_manager_;
   TestingProfile* profile_;  // Owned by TestingProfileManager.
   scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_;
-  FakeUserManager* user_manager_;
+  FakeChromeUserManager* user_manager_;
   Service* file_system_provider_service_;  // Owned by its factory.
 };
 
diff --git a/chrome/browser/chromeos/file_system_provider/service_unittest.cc b/chrome/browser/chromeos/file_system_provider/service_unittest.cc
index d8d23fb..29d4e98 100644
--- a/chrome/browser/chromeos/file_system_provider/service_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/service_unittest.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/chromeos/file_system_provider/observer.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
 #include "chrome/browser/chromeos/file_system_provider/registry_interface.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
@@ -179,7 +179,7 @@
         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
     ASSERT_TRUE(profile_manager_->SetUp());
     profile_ = profile_manager_->CreateTestingProfile("test-user@example.com");
-    user_manager_ = new FakeUserManager();
+    user_manager_ = new FakeChromeUserManager();
     user_manager_->AddUser(profile_->GetProfileName());
     user_manager_enabler_.reset(new ScopedUserManagerEnabler(user_manager_));
     extension_registry_.reset(new extensions::ExtensionRegistry(profile_));
@@ -201,7 +201,7 @@
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<TestingProfileManager> profile_manager_;
   TestingProfile* profile_;
-  FakeUserManager* user_manager_;
+  FakeChromeUserManager* user_manager_;
   scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_;
   scoped_ptr<extensions::ExtensionRegistry> extension_registry_;
   scoped_ptr<Service> service_;
diff --git a/chrome/browser/chromeos/input_method/input_method_persistence_unittest.cc b/chrome/browser/chromeos/input_method/input_method_persistence_unittest.cc
index 35f36c3e8..2d071bf 100644
--- a/chrome/browser/chromeos/input_method/input_method_persistence_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_persistence_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
 #include "chrome/browser/chromeos/language_preferences.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -35,7 +35,7 @@
  protected:
   InputMethodPersistenceTest()
       : mock_profile_manager_(TestingBrowserProcess::GetGlobal()),
-        fake_user_manager_(new chromeos::FakeUserManager()),
+        fake_user_manager_(new chromeos::FakeChromeUserManager()),
         user_manager_enabler_(fake_user_manager_) {}
 
   void SetUp() override {
@@ -71,7 +71,7 @@
   TestingPrefServiceSyncable* mock_user_prefs_;
   MockInputMethodManager mock_manager_;
   TestingProfileManager mock_profile_manager_;
-  chromeos::FakeUserManager* fake_user_manager_;
+  chromeos::FakeChromeUserManager* fake_user_manager_;
   chromeos::ScopedUserManagerEnabler user_manager_enabler_;
 };
 
diff --git a/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc b/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc
index 62d9ccc1..c3dcd6e 100644
--- a/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc
+++ b/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
@@ -44,6 +43,7 @@
 #include "chromeos/login/auth/user_context.h"
 #include "chromeos/login/login_state.h"
 #include "components/ownership/mock_owner_key_util.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_test_nss_chromeos_user.h"
@@ -131,7 +131,7 @@
  public:
   CryptohomeAuthenticatorTest()
       : user_context_("me@nowhere.org"),
-        user_manager_(new FakeUserManager()),
+        user_manager_(new user_manager::FakeUserManager()),
         user_manager_enabler_(user_manager_),
         mock_caller_(NULL),
         mock_homedir_methods_(NULL),
@@ -325,7 +325,7 @@
 
   TestingProfile profile_;
   scoped_ptr<TestingProfileManager> profile_manager_;
-  FakeUserManager* user_manager_;
+  user_manager::FakeUserManager* user_manager_;
   ScopedUserManagerEnabler user_manager_enabler_;
 
   cryptohome::MockAsyncMethodCaller* mock_caller_;
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index c7fe45b7..85d7be0f 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -90,6 +90,7 @@
     ::switches::kDisableSeccompFilterSandbox,
     ::switches::kDisableSetuidSandbox,
     ::switches::kDisableTextBlobs,
+    ::switches::kDisableThreadedGpuRasterization,
     ::switches::kDisableThreadedScrolling,
     ::switches::kDisableTouchDragDrop,
     ::switches::kDisableTouchEditing,
@@ -110,6 +111,7 @@
     ::switches::kEnablePinch,
     ::switches::kEnablePluginPlaceholderShadowDom,
     ::switches::kEnableSlimmingPaint,
+    ::switches::kEnableThreadedGpuRasterization,
     ::switches::kEnableTouchDragDrop,
     ::switches::kEnableTouchEditing,
     ::switches::kEnableViewport,
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
index 2f75006b..286a85e 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
@@ -13,7 +13,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/chrome_constants.h"
@@ -193,10 +193,9 @@
  public:
   EasyUnlockTpmKeyManagerTest()
       : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD),
-        user_manager_(new chromeos::FakeUserManager),
+        user_manager_(new chromeos::FakeChromeUserManager()),
         user_manager_enabler_(user_manager_),
-        profile_manager_(TestingBrowserProcess::GetGlobal()) {
-  }
+        profile_manager_(TestingBrowserProcess::GetGlobal()) {}
   ~EasyUnlockTpmKeyManagerTest() override {}
 
   void SetUp() override {
@@ -286,7 +285,7 @@
   scoped_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_;
 
   // Needed to properly set up signin and user profiles for test.
-  chromeos::FakeUserManager* user_manager_;
+  user_manager::FakeUserManager* user_manager_;
   chromeos::ScopedUserManagerEnabler user_manager_enabler_;
   TestingProfileManager profile_manager_;
 
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 079e937..340dff9 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -9,12 +9,16 @@
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/fake_cws.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
@@ -25,13 +29,16 @@
 #include "chrome/browser/chromeos/login/test/app_window_waiter.h"
 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -47,6 +54,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/disks/disk_mount_manager.h"
+#include "chromeos/settings/cros_settings_provider.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/common/signin_pref_names.h"
 #include "content/public/browser/browser_thread.h"
@@ -395,6 +403,68 @@
   DISALLOW_COPY_AND_ASSIGN(AppDataLoadWaiter);
 };
 
+class CrosSettingsPermanentlyUntrustedMaker :
+    public DeviceSettingsService::Observer {
+ public:
+  CrosSettingsPermanentlyUntrustedMaker();
+
+  // DeviceSettingsService::Observer:
+  void OwnershipStatusChanged() override;
+  void DeviceSettingsUpdated() override;
+  void OnDeviceSettingsServiceShutdown() override;
+
+ private:
+  bool untrusted_check_running_;
+  base::RunLoop run_loop_;
+
+  void CheckIfUntrusted();
+
+  DISALLOW_COPY_AND_ASSIGN(CrosSettingsPermanentlyUntrustedMaker);
+};
+
+CrosSettingsPermanentlyUntrustedMaker::CrosSettingsPermanentlyUntrustedMaker()
+    : untrusted_check_running_(false) {
+  DeviceSettingsService::Get()->AddObserver(this);
+
+  policy::DevicePolicyCrosTestHelper().InstallOwnerKey();
+  DeviceSettingsService::Get()->OwnerKeySet(true);
+
+  run_loop_.Run();
+}
+
+void CrosSettingsPermanentlyUntrustedMaker::OwnershipStatusChanged() {
+  if (untrusted_check_running_)
+    return;
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&CrosSettingsPermanentlyUntrustedMaker::CheckIfUntrusted,
+                 base::Unretained(this)));
+}
+
+void CrosSettingsPermanentlyUntrustedMaker::DeviceSettingsUpdated() {
+}
+
+void CrosSettingsPermanentlyUntrustedMaker::OnDeviceSettingsServiceShutdown() {
+}
+
+void CrosSettingsPermanentlyUntrustedMaker::CheckIfUntrusted() {
+  untrusted_check_running_ = true;
+  const CrosSettingsProvider::TrustedStatus trusted_status =
+      CrosSettings::Get()->PrepareTrustedValues(
+          base::Bind(&CrosSettingsPermanentlyUntrustedMaker::CheckIfUntrusted,
+                     base::Unretained(this)));
+  if (trusted_status == CrosSettingsProvider::TEMPORARILY_UNTRUSTED)
+    return;
+  untrusted_check_running_ = false;
+
+  if (trusted_status == CrosSettingsProvider::TRUSTED)
+    return;
+
+  DeviceSettingsService::Get()->RemoveObserver(this);
+  run_loop_.Quit();
+}
+
 }  // namespace
 
 class KioskTest : public OobeBaseTest {
@@ -703,11 +773,6 @@
     return auto_lock.Pass();
   }
 
-  void MakeCrosSettingsPermanentlyUntrusted() {
-    policy::DevicePolicyCrosTestHelper().InstallOwnerKey();
-    DeviceSettingsService::Get()->OwnerKeySet(true);
-  }
-
   MockUserManager* mock_user_manager() { return mock_user_manager_.get(); }
 
   void set_test_app_id(const std::string& test_app_id) {
@@ -1135,7 +1200,7 @@
   SimulateNetworkOnline();
 
   // Make cros settings untrusted.
-  MakeCrosSettingsPermanentlyUntrusted();
+  CrosSettingsPermanentlyUntrustedMaker();
 
   // Check that the attempt to start a kiosk app fails with an error.
   LaunchApp(test_app_id(), false);
@@ -1153,7 +1218,9 @@
       &ignored));
 }
 
-IN_PROC_BROWSER_TEST_F(KioskTest, NoAutoLaunchWhenUntrusted) {
+// Verifies that a consumer device does not auto-launch kiosk mode when cros
+// settings are untrusted.
+IN_PROC_BROWSER_TEST_F(KioskTest, NoConsumerAutoLaunchWhenUntrusted) {
   EnableConsumerKioskMode();
 
   // Wait for and confirm the auto-launch warning.
@@ -1172,12 +1239,32 @@
       base::FundamentalValue(true));
 
   // Make cros settings untrusted.
-  MakeCrosSettingsPermanentlyUntrusted();
+  CrosSettingsPermanentlyUntrustedMaker();
 
   // Check that the attempt to auto-launch a kiosk app fails with an error.
   OobeScreenWaiter(OobeDisplay::SCREEN_ERROR_MESSAGE).Wait();
 }
 
+// Verifies that an enterprise device does not auto-launch kiosk mode when cros
+// settings are untrusted.
+IN_PROC_BROWSER_TEST_F(KioskTest, NoEnterpriseAutoLaunchWhenUntrusted) {
+  PrepareAppLaunch();
+  SimulateNetworkOnline();
+
+  // Make cros settings untrusted.
+  CrosSettingsPermanentlyUntrustedMaker();
+
+  // Trigger the code that handles auto-launch on enterprise devices. This would
+  // normally be called from ShowLoginWizard(), which runs so early that it is
+  // not to inject an auto-launch policy before it runs.
+  LoginDisplayHost* login_display_host = LoginDisplayHostImpl::default_host();
+  ASSERT_TRUE(login_display_host);
+  login_display_host->StartAppLaunch(test_app_id(), false);
+
+  // Check that no launch has started.
+  EXPECT_FALSE(login_display_host->GetAppLaunchController());
+}
+
 class KioskUpdateTest : public KioskTest {
  public:
   KioskUpdateTest() {}
@@ -1865,15 +1952,14 @@
 
 IN_PROC_BROWSER_TEST_F(KioskHiddenWebUITest, AutolaunchWarning) {
   // Add a device owner.
-  FakeUserManager* user_manager = new FakeUserManager();
+  FakeChromeUserManager* user_manager = new FakeChromeUserManager();
   user_manager->AddUser(kTestOwnerEmail);
   ScopedUserManagerEnabler enabler(user_manager);
 
   // Set kiosk app to autolaunch.
   EnableConsumerKioskMode();
-  chromeos::WizardController::SkipPostLoginScreensForTesting();
-  chromeos::WizardController* wizard_controller =
-      chromeos::WizardController::default_controller();
+  WizardController::SkipPostLoginScreensForTesting();
+  WizardController* wizard_controller = WizardController::default_controller();
   CHECK(wizard_controller);
 
   // Start login screen after configuring auto launch app since the warning
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.cc b/chrome/browser/chromeos/login/screens/mock_update_screen.cc
index cf914ce..02da115 100644
--- a/chrome/browser/chromeos/login/screens/mock_update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/mock_update_screen.cc
@@ -4,32 +4,36 @@
 
 #include "chrome/browser/chromeos/login/screens/mock_update_screen.h"
 
+using ::testing::AtLeast;
+using ::testing::_;
+
 namespace chromeos {
 
-using ::testing::AtLeast;
-using ::testing::NotNull;
-
 MockUpdateScreen::MockUpdateScreen(BaseScreenDelegate* base_screen_delegate,
-                                   UpdateScreenActor* actor)
-    : UpdateScreen(base_screen_delegate, actor, NULL) {
+                                   UpdateView* view)
+    : UpdateScreen(base_screen_delegate, view, NULL) {
 }
 
 MockUpdateScreen::~MockUpdateScreen() {
 }
 
-MockUpdateScreenActor::MockUpdateScreenActor()
-    : screen_(NULL) {
-  EXPECT_CALL(*this, MockSetDelegate(NotNull())).Times(AtLeast(1));
+MockUpdateView::MockUpdateView() : model_(nullptr) {
+  EXPECT_CALL(*this, MockBind(_)).Times(AtLeast(1));
 }
 
-MockUpdateScreenActor::~MockUpdateScreenActor() {
-  if (screen_)
-    screen_->OnActorDestroyed(this);
+MockUpdateView::~MockUpdateView() {
+  if (model_)
+    model_->OnViewDestroyed(this);
 }
 
-void MockUpdateScreenActor::SetDelegate(UpdateScreenActor::Delegate* screen) {
-  screen_ = screen;
-  MockSetDelegate(screen);
+void MockUpdateView::Bind(UpdateModel& model) {
+  model_ = &model;
+  MockBind(model);
+}
+
+void MockUpdateView::Unbind() {
+  model_ = nullptr;
+  MockUnbind();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.h b/chrome/browser/chromeos/login/screens/mock_update_screen.h
index 583347d5..e6b0334 100644
--- a/chrome/browser/chromeos/login/screens/mock_update_screen.h
+++ b/chrome/browser/chromeos/login/screens/mock_update_screen.h
@@ -6,43 +6,37 @@
 #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_UPDATE_SCREEN_H_
 
 #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
+#include "chrome/browser/chromeos/login/screens/update_model.h"
 #include "chrome/browser/chromeos/login/screens/update_screen.h"
-#include "chrome/browser/chromeos/login/screens/update_screen_actor.h"
+#include "chrome/browser/chromeos/login/screens/update_view.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace chromeos {
 
 class MockUpdateScreen : public UpdateScreen {
  public:
-  MockUpdateScreen(BaseScreenDelegate* base_screen_delegate,
-                   UpdateScreenActor* actor);
+  MockUpdateScreen(BaseScreenDelegate* base_screen_delegate, UpdateView* view);
   virtual ~MockUpdateScreen();
 
   MOCK_METHOD0(StartNetworkCheck, void());
 };
 
-class MockUpdateScreenActor : public UpdateScreenActor {
+class MockUpdateView : public UpdateView {
  public:
-  MockUpdateScreenActor();
-  virtual ~MockUpdateScreenActor();
+  MockUpdateView();
+  virtual ~MockUpdateView();
 
-  virtual void SetDelegate(UpdateScreenActor::Delegate* screen) override;
+  void Bind(UpdateModel& model) override;
+  void Unbind() override;
 
-  MOCK_METHOD1(MockSetDelegate, void(UpdateScreenActor::Delegate* screen));
+  MOCK_METHOD0(PrepareToShow, void());
   MOCK_METHOD0(Show, void());
   MOCK_METHOD0(Hide, void());
-  MOCK_METHOD0(PrepareToShow, void());
-  MOCK_METHOD0(ShowManualRebootInfo, void());
-  MOCK_METHOD1(SetProgress, void(int progress));
-  MOCK_METHOD1(ShowEstimatedTimeLeft, void(bool enable));
-  MOCK_METHOD1(SetEstimatedTimeLeft, void(const base::TimeDelta& time));
-  MOCK_METHOD1(ShowProgressMessage, void(bool enable));
-  MOCK_METHOD1(SetProgressMessage, void(ProgressMessage message));
-  MOCK_METHOD1(ShowCurtain, void(bool enable));
-  MOCK_METHOD1(ShowPreparingUpdatesInfo, void(bool enable));
+  MOCK_METHOD1(MockBind, void(UpdateModel& model));
+  MOCK_METHOD0(MockUnbind, void());
 
  private:
-  UpdateScreenActor::Delegate* screen_;
+  UpdateModel* model_;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/network_screen.h b/chrome/browser/chromeos/login/screens/network_screen.h
index 00fc13a..8350d06 100644
--- a/chrome/browser/chromeos/login/screens/network_screen.h
+++ b/chrome/browser/chromeos/login/screens/network_screen.h
@@ -13,7 +13,6 @@
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "base/timer/timer.h"
-#include "chrome/browser/chromeos/login/screens/base_screen.h"
 #include "chrome/browser/chromeos/login/screens/network_model.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chromeos/network/network_state_handler_observer.h"
diff --git a/chrome/browser/chromeos/login/screens/update_model.cc b/chrome/browser/chromeos/login/screens/update_model.cc
new file mode 100644
index 0000000..d8f2be49
--- /dev/null
+++ b/chrome/browser/chromeos/login/screens/update_model.cc
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/screens/update_model.h"
+
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+
+namespace chromeos {
+
+const char UpdateModel::kUserActionCancelUpdateShortcut[] = "cancel-update";
+const char UpdateModel::kContextKeyEstimatedTimeLeftSec[] = "time-left-sec";
+const char UpdateModel::kContextKeyShowEstimatedTimeLeft[] = "show-time-left";
+const char UpdateModel::kContextKeyUpdateMessage[] = "update-msg";
+const char UpdateModel::kContextKeyShowCurtain[] = "show-curtain";
+const char UpdateModel::kContextKeyShowProgressMessage[] = "show-progress-msg";
+const char UpdateModel::kContextKeyProgress[] = "progress";
+const char UpdateModel::kContextKeyProgressMessage[] = "progress-msg";
+const char UpdateModel::kContextKeyCancelUpdateShortcutEnabled[] =
+    "cancel-update-enabled";
+
+UpdateModel::UpdateModel(BaseScreenDelegate* base_screen_delegate)
+    : BaseScreen(base_screen_delegate) {
+}
+
+UpdateModel::~UpdateModel() {
+}
+
+std::string UpdateModel::GetName() const {
+  return WizardController::kUpdateScreenName;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/update_model.h b/chrome/browser/chromeos/login/screens/update_model.h
new file mode 100644
index 0000000..1d1d7c5
--- /dev/null
+++ b/chrome/browser/chromeos/login/screens/update_model.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 CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_MODEL_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_MODEL_H_
+
+#include "chrome/browser/chromeos/login/screens/base_screen.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace chromeos {
+
+class BaseScreenDelegate;
+class UpdateView;
+
+class UpdateModel : public BaseScreen {
+ public:
+  static const char kUserActionCancelUpdateShortcut[];
+  static const char kContextKeyEstimatedTimeLeftSec[];
+  static const char kContextKeyShowEstimatedTimeLeft[];
+  static const char kContextKeyUpdateMessage[];
+  static const char kContextKeyShowCurtain[];
+  static const char kContextKeyShowProgressMessage[];
+  static const char kContextKeyProgress[];
+  static const char kContextKeyProgressMessage[];
+  static const char kContextKeyCancelUpdateShortcutEnabled[];
+
+  explicit UpdateModel(BaseScreenDelegate* base_screen_delegate);
+  ~UpdateModel() override;
+
+  // BaseScreen implementation:
+  std::string GetName() const override;
+
+  // This method is called, when view is being destroyed. Note, if model
+  // is destroyed earlier then it has to call Unbind().
+  virtual void OnViewDestroyed(UpdateView* view) = 0;
+
+  // Called any time a new network connect request occurs.
+  virtual void OnConnectToNetworkRequested() = 0;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_MODEL_H_
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc
index e6872c0..0457421 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -15,12 +15,15 @@
 #include "chrome/browser/chromeos/login/screen_manager.h"
 #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
 #include "chrome/browser/chromeos/login/screens/error_screen.h"
-#include "chrome/browser/chromeos/login/screens/update_screen_actor.h"
+#include "chrome/browser/chromeos/login/screens/update_view.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/network/network_state.h"
 #include "content/public/browser/browser_thread.h"
+#include "ui/base/l10n/l10n_util.h"
 
 using content::BrowserThread;
 using pairing_chromeos::HostPairingController;
@@ -29,6 +32,9 @@
 
 namespace {
 
+// If reboot didn't happen, ask user to reboot device manually.
+const int kWaitForRebootTimeSec = 3;
+
 // Progress bar stages. Each represents progress bar value
 // at the beginning of each stage.
 // TODO(nkostylev): Base stage progress values on approximate time.
@@ -94,41 +100,39 @@
 }
 
 UpdateScreen::UpdateScreen(BaseScreenDelegate* base_screen_delegate,
-                           UpdateScreenActor* actor,
+                           UpdateView* view,
                            HostPairingController* remora_controller)
-    : BaseScreen(base_screen_delegate),
+    : UpdateModel(base_screen_delegate),
       state_(STATE_IDLE),
-      reboot_check_delay_(0),
+      reboot_check_delay_(kWaitForRebootTimeSec),
       is_checking_for_update_(true),
       is_downloading_update_(false),
-      is_ignore_update_deadlines_(false),
+      is_ignore_update_deadlines_(true),
       is_shown_(false),
       ignore_idle_status_(true),
-      actor_(actor),
+      view_(view),
       remora_controller_(remora_controller),
       is_first_detection_notification_(true),
       is_first_portal_notification_(true),
       histogram_helper_(new ErrorScreensHistogramHelper("Update")),
       weak_factory_(this) {
-  DCHECK(actor_);
-  if (actor_)
-    actor_->SetDelegate(this);
+  if (view_)
+    view_->Bind(*this);
+
   GetInstanceSet().insert(this);
 }
 
 UpdateScreen::~UpdateScreen() {
+  if (view_)
+    view_->Unbind();
+
   DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
   NetworkPortalDetector::Get()->RemoveObserver(this);
   GetInstanceSet().erase(this);
-  if (actor_)
-    actor_->SetDelegate(NULL);
 }
 
 void UpdateScreen::UpdateStatusChanged(
     const UpdateEngineClient::Status& status) {
-  if (!actor_)
-    return;
-
   if (is_checking_for_update_ &&
       status.status > UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE) {
     is_checking_for_update_ = false;
@@ -147,17 +151,19 @@
       break;
     case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
       MakeSureScreenIsShown();
-      actor_->SetProgress(kBeforeDownloadProgress);
-      actor_->ShowEstimatedTimeLeft(false);
+      GetContextEditor()
+          .SetInteger(kContextKeyProgress, kBeforeDownloadProgress)
+          .SetBoolean(kContextKeyShowEstimatedTimeLeft, false);
       if (!HasCriticalUpdate()) {
         VLOG(1) << "Noncritical update available: " << status.new_version;
         ExitUpdate(REASON_UPDATE_NON_CRITICAL);
       } else {
         VLOG(1) << "Critical update available: " << status.new_version;
-        actor_->SetProgressMessage(
-            UpdateScreenActor::PROGRESS_MESSAGE_UPDATE_AVAILABLE);
-        actor_->ShowProgressMessage(true);
-        actor_->ShowCurtain(false);
+        GetContextEditor()
+            .SetString(kContextKeyProgressMessage,
+                       l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE))
+            .SetBoolean(kContextKeyShowProgressMessage, true)
+            .SetBoolean(kContextKeyShowCurtain, false);
       }
       break;
     case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
@@ -177,10 +183,11 @@
             ExitUpdate(REASON_UPDATE_NON_CRITICAL);
           } else {
             VLOG(1) << "Critical update available: " << status.new_version;
-            actor_->SetProgressMessage(
-                UpdateScreenActor::PROGRESS_MESSAGE_INSTALLING_UPDATE);
-            actor_->ShowProgressMessage(true);
-            actor_->ShowCurtain(false);
+            GetContextEditor()
+                .SetString(kContextKeyProgressMessage,
+                           l10n_util::GetStringUTF16(IDS_INSTALLING_UPDATE))
+                .SetBoolean(kContextKeyShowProgressMessage, true)
+                .SetBoolean(kContextKeyShowCurtain, false);
           }
         }
         UpdateDownloadingStats(status);
@@ -188,23 +195,27 @@
       break;
     case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
       MakeSureScreenIsShown();
-      actor_->SetProgress(kBeforeVerifyingProgress);
-      actor_->SetProgressMessage(UpdateScreenActor::PROGRESS_MESSAGE_VERIFYING);
-      actor_->ShowProgressMessage(true);
+      GetContextEditor()
+          .SetInteger(kContextKeyProgress, kBeforeVerifyingProgress)
+          .SetString(kContextKeyProgressMessage,
+                     l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING))
+          .SetBoolean(kContextKeyShowProgressMessage, true);
       break;
     case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
       MakeSureScreenIsShown();
-      actor_->SetProgress(kBeforeFinalizingProgress);
-      actor_->SetProgressMessage(
-          UpdateScreenActor::PROGRESS_MESSAGE_FINALIZING);
-      actor_->ShowProgressMessage(true);
+      GetContextEditor()
+          .SetInteger(kContextKeyProgress, kBeforeFinalizingProgress)
+          .SetString(kContextKeyProgressMessage,
+                     l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING))
+          .SetBoolean(kContextKeyShowProgressMessage, true);
       break;
     case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
       MakeSureScreenIsShown();
-      actor_->SetProgress(kProgressComplete);
-      actor_->ShowEstimatedTimeLeft(false);
+      GetContextEditor()
+          .SetInteger(kContextKeyProgress, kProgressComplete)
+          .SetBoolean(kContextKeyShowEstimatedTimeLeft, false);
       if (HasCriticalUpdate()) {
-        actor_->ShowCurtain(false);
+        GetContextEditor().SetBoolean(kContextKeyShowCurtain, false);
         VLOG(1) << "Initiate reboot after update";
         SetHostPairingControllerStatus(
             HostPairingController::UPDATE_STATUS_REBOOTING);
@@ -298,33 +309,59 @@
   NetworkPortalDetector::Get()->AddAndFireObserver(this);
 }
 
-void UpdateScreen::CancelUpdate() {
-  VLOG(1) << "Forced update cancel";
-  ExitUpdate(REASON_UPDATE_CANCELED);
+void UpdateScreen::PrepareToShow() {
+  if (!view_)
+    return;
+
+  view_->PrepareToShow();
 }
 
 void UpdateScreen::Show() {
   is_shown_ = true;
   histogram_helper_->OnScreenShow();
-  if (actor_) {
-    actor_->Show();
-    actor_->SetProgress(kBeforeUpdateCheckProgress);
-  }
+
+#if !defined(OFFICIAL_BUILD)
+  GetContextEditor().SetBoolean(kContextKeyCancelUpdateShortcutEnabled, true);
+#endif
+  GetContextEditor().SetInteger(kContextKeyProgress,
+                                kBeforeUpdateCheckProgress);
+
+  if (view_)
+    view_->Show();
 }
 
 void UpdateScreen::Hide() {
-  if (actor_)
-    actor_->Hide();
+  if (view_)
+    view_->Hide();
   is_shown_ = false;
 }
 
-std::string UpdateScreen::GetName() const {
-  return WizardController::kUpdateScreenName;
+void UpdateScreen::Initialize(::login::ScreenContext* context) {
+  UpdateModel::Initialize(context);
 }
 
-void UpdateScreen::PrepareToShow() {
-  if (actor_)
-    actor_->PrepareToShow();
+void UpdateScreen::OnViewDestroyed(UpdateView* view) {
+  if (view_ == view)
+    view_ = nullptr;
+}
+
+void UpdateScreen::OnUserAction(const std::string& action_id) {
+#if !defined(OFFICIAL_BUILD)
+  if (action_id == kUserActionCancelUpdateShortcut)
+    CancelUpdate();
+#endif
+}
+
+void UpdateScreen::OnContextKeyUpdated(
+    const ::login::ScreenContext::KeyType& key) {
+  UpdateModel::OnContextKeyUpdated(key);
+}
+
+void UpdateScreen::OnConnectToNetworkRequested() {
+  if (state_ == STATE_ERROR) {
+    LOG(WARNING) << "Hiding error message since AP was reselected";
+    StartUpdateCheck();
+  }
 }
 
 void UpdateScreen::ExitUpdate(UpdateScreen::ExitReason reason) {
@@ -378,8 +415,8 @@
 void UpdateScreen::OnWaitForRebootTimeElapsed() {
   LOG(ERROR) << "Unable to reboot - asking user for a manual reboot.";
   MakeSureScreenIsShown();
-  if (actor_)
-    actor_->ShowManualRebootInfo();
+  GetContextEditor().SetString(kContextKeyUpdateMessage,
+                               l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED));
 }
 
 void UpdateScreen::MakeSureScreenIsShown() {
@@ -387,21 +424,17 @@
     get_base_screen_delegate()->ShowCurrentScreen();
 }
 
-void UpdateScreen::SetRebootCheckDelay(int seconds) {
-  if (seconds <= 0)
-    reboot_timer_.Stop();
-  DCHECK(!reboot_timer_.IsRunning());
-  reboot_check_delay_ = seconds;
-}
-
 void UpdateScreen::SetIgnoreIdleStatus(bool ignore_idle_status) {
   ignore_idle_status_ = ignore_idle_status;
 }
 
+void UpdateScreen::CancelUpdate() {
+  VLOG(1) << "Forced update cancel";
+  ExitUpdate(REASON_UPDATE_CANCELED);
+}
+
 void UpdateScreen::UpdateDownloadingStats(
     const UpdateEngineClient::Status& status) {
-  if (!actor_)
-    return;
   base::Time download_current_time = base::Time::Now();
   if (download_current_time >= download_last_time_ + kMinTimeStep) {
     // Estimate downloading rate.
@@ -437,14 +470,16 @@
     // |bound possible estimations.
     time_left = std::min(time_left, kMaxTimeLeft);
 
-    actor_->ShowEstimatedTimeLeft(true);
-    actor_->SetEstimatedTimeLeft(
-        base::TimeDelta::FromSeconds(static_cast<int64>(time_left)));
+    GetContextEditor()
+        .SetBoolean(kContextKeyShowEstimatedTimeLeft, true)
+        .SetInteger(kContextKeyEstimatedTimeLeftSec,
+                    static_cast<int>(time_left));
   }
 
   int download_progress = static_cast<int>(
       status.download_progress * kDownloadProgressIncrement);
-  actor_->SetProgress(kBeforeDownloadProgress + download_progress);
+  GetContextEditor().SetInteger(kContextKeyProgress,
+                                kBeforeDownloadProgress + download_progress);
 }
 
 bool UpdateScreen::HasCriticalUpdate() {
@@ -466,18 +501,6 @@
   return true;
 }
 
-void UpdateScreen::OnActorDestroyed(UpdateScreenActor* actor) {
-  if (actor_ == actor)
-    actor_ = NULL;
-}
-
-void UpdateScreen::OnConnectToNetworkRequested() {
-  if (state_ == STATE_ERROR) {
-    LOG(WARNING) << "Hiding error message since AP was reselected";
-    StartUpdateCheck();
-  }
-}
-
 ErrorScreen* UpdateScreen::GetErrorScreen() {
   return get_base_screen_delegate()->GetErrorScreen();
 }
diff --git a/chrome/browser/chromeos/login/screens/update_screen.h b/chrome/browser/chromeos/login/screens/update_screen.h
index 6b39389..e9b291e 100644
--- a/chrome/browser/chromeos/login/screens/update_screen.h
+++ b/chrome/browser/chromeos/login/screens/update_screen.h
@@ -13,8 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "chrome/browser/chromeos/login/screens/base_screen.h"
-#include "chrome/browser/chromeos/login/screens/update_screen_actor.h"
+#include "chrome/browser/chromeos/login/screens/update_model.h"
 #include "chromeos/dbus/update_engine_client.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
 #include "components/pairing/host_pairing_controller.h"
@@ -26,40 +25,33 @@
 class ErrorScreensHistogramHelper;
 class NetworkState;
 class ScreenManager;
+class UpdateView;
 
-// Controller for the update screen. It does not depend on the specific
-// implementation of the screen showing (Views of WebUI based), the dependency
-// is moved to the UpdateScreenActor instead.
-class UpdateScreen : public UpdateEngineClient::Observer,
-                     public UpdateScreenActor::Delegate,
-                     public BaseScreen,
+// Controller for the update screen.
+class UpdateScreen : public UpdateModel,
+                     public UpdateEngineClient::Observer,
                      public NetworkPortalDetector::Observer {
  public:
   UpdateScreen(BaseScreenDelegate* base_screen_delegate,
-               UpdateScreenActor* actor,
+               UpdateView* view,
                pairing_chromeos::HostPairingController* remora_controller);
   ~UpdateScreen() override;
 
   static UpdateScreen* Get(ScreenManager* manager);
 
-  // Overridden from BaseScreen.
+  // UpdateModel:
   void PrepareToShow() override;
   void Show() override;
   void Hide() override;
-  std::string GetName() const override;
-
-  // UpdateScreenActor::Delegate implementation:
-  void CancelUpdate() override;
-  void OnActorDestroyed(UpdateScreenActor* actor) override;
+  void Initialize(::login::ScreenContext* context) override;
+  void OnViewDestroyed(UpdateView* view) override;
+  void OnUserAction(const std::string& action_id) override;
+  void OnContextKeyUpdated(const ::login::ScreenContext::KeyType& key) override;
   void OnConnectToNetworkRequested() override;
 
   // Starts network check. Made virtual to simplify mocking.
   virtual void StartNetworkCheck();
 
-  // Reboot check delay get/set, in seconds.
-  int reboot_check_delay() const { return reboot_check_delay_; }
-  void SetRebootCheckDelay(int seconds);
-
   // Returns true if this instance is still active (i.e. has not been deleted).
   static bool HasInstance(UpdateScreen* inst);
 
@@ -82,6 +74,9 @@
       const NetworkState* network,
       const NetworkPortalDetector::CaptivePortalState& state) override;
 
+  // Skip update UI, usually used only in debug builds/tests.
+  void CancelUpdate();
+
  private:
   FRIEND_TEST_ALL_PREFIXES(UpdateScreenTest, TestBasic);
   FRIEND_TEST_ALL_PREFIXES(UpdateScreenTest, TestUpdateAvailable);
@@ -149,8 +144,7 @@
   // Ignore fist IDLE status that is sent before update screen initiated check.
   bool ignore_idle_status_;
 
-  // Keeps actor which is delegated with all showing operations.
-  UpdateScreenActor* actor_;
+  UpdateView* view_;
 
   // Used to track updates over Bluetooth.
   pairing_chromeos::HostPairingController* remora_controller_;
diff --git a/chrome/browser/chromeos/login/screens/update_screen_actor.h b/chrome/browser/chromeos/login/screens/update_screen_actor.h
deleted file mode 100644
index 064e2ce3..0000000
--- a/chrome/browser/chromeos/login/screens/update_screen_actor.h
+++ /dev/null
@@ -1,73 +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 CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_SCREEN_ACTOR_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_SCREEN_ACTOR_H_
-
-#include "base/time/time.h"
-
-namespace chromeos {
-
-class UpdateScreenActor {
- public:
-  // Indices for corresponding info messages during update stage.
-  enum ProgressMessage {
-    PROGRESS_MESSAGE_UPDATE_AVAILABLE = 0,
-    PROGRESS_MESSAGE_INSTALLING_UPDATE,
-    PROGRESS_MESSAGE_VERIFYING,
-    PROGRESS_MESSAGE_FINALIZING
-  };
-
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    // Force cancel update.
-    virtual void CancelUpdate() = 0;
-
-    // Called prior to destroying |actor|.
-    virtual void OnActorDestroyed(UpdateScreenActor* actor) = 0;
-
-    // Called any time a new network connect request occurs.
-    virtual void OnConnectToNetworkRequested() = 0;
-  };
-
-  virtual ~UpdateScreenActor() {}
-
-  // Sets screen this actor belongs to.
-  virtual void SetDelegate(Delegate* screen) = 0;
-
-  // Shows the screen.
-  virtual void Show() = 0;
-
-  // Hides the screen.
-  virtual void Hide() = 0;
-
-  virtual void PrepareToShow() = 0;
-
-  // Shows manual reboot info message.
-  virtual void ShowManualRebootInfo() = 0;
-
-  // Sets current progress in percents.
-  virtual void SetProgress(int progress) = 0;
-
-  // Shows estimated time left message.
-  virtual void ShowEstimatedTimeLeft(bool visible) = 0;
-
-  // Sets current estimation for time left in the downloading stage.
-  virtual void SetEstimatedTimeLeft(const base::TimeDelta& time) = 0;
-
-  // Shows message under progress bar.
-  virtual void ShowProgressMessage(bool visible) = 0;
-
-  // Sets message under progress bar.
-  virtual void SetProgressMessage(ProgressMessage message) = 0;
-
-  // Shows screen curtains.
-  virtual void ShowCurtain(bool visible) = 0;
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_SCREEN_ACTOR_H_
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
index 489232f3..d517ee66 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -126,7 +126,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestBasic) {
-  ASSERT_TRUE(update_screen_->actor_ != NULL);
+  ASSERT_TRUE(update_screen_->view_ != NULL);
 }
 
 IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestNoUpdate) {
diff --git a/chrome/browser/chromeos/login/screens/update_view.h b/chrome/browser/chromeos/login/screens/update_view.h
new file mode 100644
index 0000000..b188aff
--- /dev/null
+++ b/chrome/browser/chromeos/login/screens/update_view.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_VIEW_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_VIEW_H_
+
+#include "base/strings/string16.h"
+
+namespace chromeos {
+
+class UpdateModel;
+
+// Interface for dependency injection between NetworkScreen and its actual
+// representation. Owned by UpdateScreen.
+class UpdateView {
+ public:
+  virtual ~UpdateView() {}
+
+  // Prepare the contents to showing.
+  virtual void PrepareToShow() = 0;
+
+  // Shows the contents of the screen.
+  virtual void Show() = 0;
+
+  // Hides the contents of the screen.
+  virtual void Hide() = 0;
+
+  // Binds |model| to the view.
+  virtual void Bind(UpdateModel& model) = 0;
+
+  // Unbinds model from the view.
+  virtual void Unbind() = 0;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_UPDATE_VIEW_H_
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
index 095359ec..20064c8 100644
--- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -37,6 +37,7 @@
 const char kKeyPublicAccount[] = "publicAccount";
 const char kKeySupervisedUser[] = "supervisedUser";
 const char kKeyChildUser[] = "childUser";
+const char kKeyDesktopUser[] = "isDesktopUser";
 const char kKeySignedIn[] = "signedIn";
 const char kKeyCanRemove[] = "canRemove";
 const char kKeyIsOwner[] = "isOwner";
@@ -150,6 +151,7 @@
   user_dict->SetBoolean(kKeyPublicAccount, is_public_session);
   user_dict->SetBoolean(kKeySupervisedUser, is_supervised_user);
   user_dict->SetBoolean(kKeyChildUser, is_child_user);
+  user_dict->SetBoolean(kKeyDesktopUser, false);
   user_dict->SetInteger(kKeyInitialAuthType, auth_type);
   user_dict->SetBoolean(kKeySignedIn, user->is_logged_in());
   user_dict->SetBoolean(kKeyIsOwner, is_owner);
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc
index 544f74e..ea0d3f0d 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.cc
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -9,13 +9,13 @@
 #include "base/path_service.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/fake_shill_manager_client.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.h b/chrome/browser/chromeos/login/test/oobe_base_test.h
index 6530ff4e..0337845 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.h
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.h
@@ -19,11 +19,10 @@
 
 namespace content {
 class WebUI;
-}  // namespace content
+}
 
 namespace chromeos {
 
-class FakeUserManager;
 class NetworkPortalDetectorTestImpl;
 
 // Base class for OOBE and Kiosk tests.
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
index 0f64d5f..b1634642 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -49,6 +49,8 @@
 #include "chrome/browser/chromeos/net/delay_network_call.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/system/device_disabling_manager.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
 #include "chrome/browser/chromeos/ui/focus_ring_controller.h"
@@ -65,6 +67,8 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/login/login_state.h"
+#include "chromeos/settings/cros_settings_names.h"
+#include "chromeos/settings/cros_settings_provider.h"
 #include "chromeos/settings/timezone_settings.h"
 #include "chromeos/timezone/timezone_resolver.h"
 #include "components/session_manager/core/session_manager.h"
@@ -667,6 +671,35 @@
                                           bool diagnostic_mode) {
   VLOG(1) << "Login WebUI >> start app launch.";
   SetStatusAreaVisible(false);
+
+  // Wait for the |CrosSettings| to become either trusted or permanently
+  // untrusted.
+  const CrosSettingsProvider::TrustedStatus status =
+      CrosSettings::Get()->PrepareTrustedValues(base::Bind(
+          &LoginDisplayHostImpl::StartAppLaunch,
+          pointer_factory_.GetWeakPtr(),
+          app_id,
+          diagnostic_mode));
+  if (status == CrosSettingsProvider::TEMPORARILY_UNTRUSTED)
+    return;
+
+  if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
+    // If the |CrosSettings| are permanently untrusted, refuse to launch a
+    // single-app kiosk mode session.
+    LOG(ERROR) << "Login WebUI >> Refusing to launch single-app kiosk mode.";
+    SetStatusAreaVisible(true);
+    return;
+  }
+
+  bool device_disabled = false;
+  CrosSettings::Get()->GetBoolean(kDeviceDisabled, &device_disabled);
+  if (device_disabled && system::DeviceDisablingManager::
+                             HonorDeviceDisablingDuringNormalOperation()) {
+    // If the device is disabled, bail out. A device disabled screen will be
+    // shown by the DeviceDisablingManager.
+    return;
+  }
+
   finalize_animation_type_ = ANIMATION_FADE_OUT;
   if (!login_window_)
     LoadURL(GURL(kAppLaunchSplashURL));
@@ -1090,8 +1123,8 @@
 }
 
 void LoginDisplayHostImpl::StartTimeZoneResolve() {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kEnableTimeZoneTrackingOption)) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kDisableTimeZoneTrackingOption)) {
     return;
   }
 
diff --git a/chrome/browser/chromeos/login/ui/oobe_display.h b/chrome/browser/chromeos/login/ui/oobe_display.h
index d6a8cad..ca699b7 100644
--- a/chrome/browser/chromeos/login/ui/oobe_display.h
+++ b/chrome/browser/chromeos/login/ui/oobe_display.h
@@ -30,7 +30,7 @@
 class ResetScreenActor;
 class SupervisedUserCreationScreenHandler;
 class TermsOfServiceScreenActor;
-class UpdateScreenActor;
+class UpdateView;
 class UserImageView;
 class UserBoardView;
 class WrongHWIDScreenActor;
@@ -74,9 +74,9 @@
   // Pointers to actors which should be used by the specific screens. Actors
   // must be owned by the OobeDisplay implementation.
   virtual CoreOobeActor* GetCoreOobeActor() = 0;
-  virtual UpdateScreenActor* GetUpdateScreenActor() = 0;
   virtual NetworkView* GetNetworkView() = 0;
   virtual EulaView* GetEulaView() = 0;
+  virtual UpdateView* GetUpdateView() = 0;
   virtual EnableDebuggingScreenActor* GetEnableDebuggingScreenActor() = 0;
   virtual EnrollmentScreenActor* GetEnrollmentScreenActor() = 0;
   virtual ResetScreenActor* GetResetScreenActor() = 0;
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager.cc b/chrome/browser/chromeos/login/users/chrome_user_manager.cc
index eccc602..d2c6a7d 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
+#include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 
 namespace chromeos {
@@ -28,9 +29,8 @@
     const user_manager::UserList& user_list) {
   user_manager::UserList result;
   for (user_manager::User* user : user_list) {
-    if (user->GetType() == user_manager::USER_TYPE_REGULAR) {
+    if (user->GetType() == user_manager::USER_TYPE_REGULAR)
       result.push_back(user);
-    }
   }
   return result;
 }
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager.h b/chrome/browser/chromeos/login/users/chrome_user_manager.h
index 5ec3b8f..d97d2d75 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager.h
@@ -6,22 +6,16 @@
 #define CHROME_BROWSER_CHROMEOS_LOGIN_USERS_CHROME_USER_MANAGER_H_
 
 #include "base/basictypes.h"
-#include "components/user_manager/user.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "chrome/browser/chromeos/login/users/user_manager_interface.h"
 #include "components/user_manager/user_manager_base.h"
 
-namespace base {
-class TaskRunner;
-}
-
 namespace chromeos {
 
-class MultiProfileUserController;
-class SupervisedUserManager;
-class UserFlow;
-class UserImageManager;
-
 // Chrome specific interface of the UserManager.
-class ChromeUserManager : public user_manager::UserManagerBase {
+class ChromeUserManager : public user_manager::UserManagerBase,
+                          public UserManagerInterface {
  public:
   ChromeUserManager(scoped_refptr<base::TaskRunner> task_runner,
                     scoped_refptr<base::TaskRunner> blocking_task_runner);
@@ -36,29 +30,6 @@
   static user_manager::UserList GetUsersAllowedAsSupervisedUserManagers(
       const user_manager::UserList& user_list);
 
-  virtual MultiProfileUserController* GetMultiProfileUserController() = 0;
-  virtual UserImageManager* GetUserImageManager(const std::string& user_id) = 0;
-  virtual SupervisedUserManager* GetSupervisedUserManager() = 0;
-
-  // Method that allows to set |flow| for user identified by |user_id|.
-  // Flow should be set before login attempt.
-  // Takes ownership of the |flow|, |flow| will be deleted in case of login
-  // failure.
-  virtual void SetUserFlow(const std::string& user_id, UserFlow* flow) = 0;
-
-  // Return user flow for current user. Returns instance of DefaultUserFlow if
-  // no flow was defined for current user, or user is not logged in.
-  // Returned value should not be cached.
-  virtual UserFlow* GetCurrentUserFlow() const = 0;
-
-  // Return user flow for user identified by |user_id|. Returns instance of
-  // DefaultUserFlow if no flow was defined for user.
-  // Returned value should not be cached.
-  virtual UserFlow* GetUserFlow(const std::string& user_id) const = 0;
-
-  // Resets user flow for user identified by |user_id|.
-  virtual void ResetUserFlow(const std::string& user_id) = 0;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeUserManager);
 };
 
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 61530d8..738015f 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -1048,8 +1048,8 @@
 }
 
 void ChromeUserManagerImpl::UpdateUserTimeZoneRefresher(Profile* profile) {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kEnableTimeZoneTrackingOption)) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kDisableTimeZoneTrackingOption)) {
     return;
   }
 
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
index 5d4a2a1..3e1ec1b 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -63,7 +63,7 @@
   // Registers user manager preferences.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
-  // ChromeUserManager implementation:
+  // UserManagerInterface implementation:
   MultiProfileUserController* GetMultiProfileUserController() override;
   UserImageManager* GetUserImageManager(const std::string& user_id) override;
   SupervisedUserManager* GetSupervisedUserManager() override;
diff --git a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
new file mode 100644
index 0000000..48309e4
--- /dev/null
+++ b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
@@ -0,0 +1,153 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
+
+#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_supervised_user_manager.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/grit/theme_resources.h"
+#include "components/user_manager/user_image/user_image.h"
+#include "components/user_manager/user_type.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace chromeos {
+
+class FakeSupervisedUserManager;
+
+FakeChromeUserManager::FakeChromeUserManager()
+    : supervised_user_manager_(new FakeSupervisedUserManager),
+      multi_profile_user_controller_(NULL) {
+}
+
+FakeChromeUserManager::~FakeChromeUserManager() {
+}
+
+const user_manager::User* FakeChromeUserManager::AddUser(
+    const std::string& email) {
+  user_manager::User* user = user_manager::User::CreateRegularUser(email);
+  user->set_username_hash(
+      ProfileHelper::GetUserIdHashByUserIdForTesting(email));
+  user->SetStubImage(user_manager::UserImage(
+                         *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+                             IDR_PROFILE_PICTURE_LOADING)),
+                     user_manager::User::USER_IMAGE_PROFILE, false);
+  users_.push_back(user);
+  return user;
+}
+
+const user_manager::User* FakeChromeUserManager::AddPublicAccountUser(
+    const std::string& email) {
+  user_manager::User* user = user_manager::User::CreatePublicAccountUser(email);
+  user->set_username_hash(
+      ProfileHelper::GetUserIdHashByUserIdForTesting(email));
+  user->SetStubImage(user_manager::UserImage(
+                         *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+                             IDR_PROFILE_PICTURE_LOADING)),
+                     user_manager::User::USER_IMAGE_PROFILE, false);
+  users_.push_back(user);
+  return user;
+}
+
+void FakeChromeUserManager::AddKioskAppUser(
+    const std::string& kiosk_app_username) {
+  user_manager::User* user =
+      user_manager::User::CreateKioskAppUser(kiosk_app_username);
+  user->set_username_hash(
+      ProfileHelper::GetUserIdHashByUserIdForTesting(kiosk_app_username));
+  users_.push_back(user);
+}
+
+void FakeChromeUserManager::LoginUser(const std::string& email) {
+  UserLoggedIn(email, ProfileHelper::GetUserIdHashByUserIdForTesting(email),
+               false /* browser_restart */);
+}
+
+MultiProfileUserController*
+FakeChromeUserManager::GetMultiProfileUserController() {
+  return multi_profile_user_controller_;
+}
+
+SupervisedUserManager* FakeChromeUserManager::GetSupervisedUserManager() {
+  return supervised_user_manager_.get();
+}
+
+UserImageManager* FakeChromeUserManager::GetUserImageManager(
+    const std::string& /* user_id */) {
+  return nullptr;
+}
+
+void FakeChromeUserManager::SetUserFlow(const std::string& email,
+                                        UserFlow* flow) {
+}
+
+UserFlow* FakeChromeUserManager::GetCurrentUserFlow() const {
+  return nullptr;
+}
+
+UserFlow* FakeChromeUserManager::GetUserFlow(const std::string& email) const {
+  return nullptr;
+}
+
+void FakeChromeUserManager::ResetUserFlow(const std::string& email) {
+}
+
+void FakeChromeUserManager::SwitchActiveUser(const std::string& email) {
+  active_user_id_ = email;
+  ProfileHelper::Get()->ActiveUserHashChanged(
+      ProfileHelper::GetUserIdHashByUserIdForTesting(email));
+  if (!users_.empty() && !active_user_id_.empty()) {
+    for (user_manager::User* user : users_)
+      user->set_is_active(user->email() == active_user_id_);
+  }
+}
+
+const std::string& FakeChromeUserManager::GetOwnerEmail() const {
+  return owner_email_;
+}
+
+void FakeChromeUserManager::SessionStarted() {
+}
+
+void FakeChromeUserManager::RemoveUser(
+    const std::string& email,
+    user_manager::RemoveUserDelegate* delegate) {
+}
+
+user_manager::UserList
+FakeChromeUserManager::GetUsersAllowedForSupervisedUsersCreation() const {
+  CrosSettings* cros_settings = CrosSettings::Get();
+  bool allow_new_user = true;
+  cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
+  bool supervised_users_allowed = AreSupervisedUsersAllowed();
+
+  // Restricted either by policy or by owner.
+  if (!allow_new_user || !supervised_users_allowed)
+    return user_manager::UserList();
+
+  return ChromeUserManager::GetUsersAllowedAsSupervisedUserManagers(GetUsers());
+}
+
+user_manager::UserList FakeChromeUserManager::GetUsersAllowedForMultiProfile()
+    const {
+  // Supervised users are not allowed to use multi-profiles.
+  if (GetLoggedInUsers().size() == 1 &&
+      GetPrimaryUser()->GetType() != user_manager::USER_TYPE_REGULAR) {
+    return user_manager::UserList();
+  }
+
+  user_manager::UserList result;
+  const user_manager::UserList& users = GetUsers();
+  for (user_manager::User* user : users) {
+    if (user->GetType() == user_manager::USER_TYPE_REGULAR &&
+        !user->is_logged_in()) {
+      result.push_back(user);
+    }
+  }
+
+  return result;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.h b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.h
new file mode 100644
index 0000000..3a51cf4
--- /dev/null
+++ b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.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 CHROME_BROWSER_CHROMEOS_LOGIN_USERS_FAKE_CHROME_USER_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_USERS_FAKE_CHROME_USER_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/chromeos/login/user_flow.h"
+#include "chrome/browser/chromeos/login/users/user_manager_interface.h"
+#include "components/user_manager/fake_user_manager.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_image/user_image.h"
+#include "components/user_manager/user_manager_base.h"
+
+namespace chromeos {
+
+class FakeSupervisedUserManager;
+
+// Fake chrome user manager with a barebones implementation. Users can be added
+// and set as logged in, and those users can be returned.
+class FakeChromeUserManager : public user_manager::FakeUserManager,
+                              public UserManagerInterface {
+ public:
+  FakeChromeUserManager();
+  ~FakeChromeUserManager() override;
+
+  // Create and add a kiosk app user.
+  void AddKioskAppUser(const std::string& kiosk_app_username);
+
+  // Create and add a public account user.
+  const user_manager::User* AddPublicAccountUser(const std::string& email);
+
+  // Calculates the user name hash and calls UserLoggedIn to login a user.
+  void LoginUser(const std::string& email);
+
+  // UserManager overrides.
+  user_manager::UserList GetUsersAllowedForMultiProfile() const override;
+
+  // user_manager::FakeUserManager override.
+  const user_manager::User* AddUser(const std::string& email) override;
+
+  // UserManagerInterface implementation.
+  MultiProfileUserController* GetMultiProfileUserController() override;
+  UserImageManager* GetUserImageManager(const std::string& user_id) override;
+  SupervisedUserManager* GetSupervisedUserManager() override;
+  void SetUserFlow(const std::string& email, UserFlow* flow) override;
+  UserFlow* GetCurrentUserFlow() const override;
+  UserFlow* GetUserFlow(const std::string& email) const override;
+  void ResetUserFlow(const std::string& email) override;
+  user_manager::UserList GetUsersAllowedForSupervisedUsersCreation()
+      const override;
+  void SwitchActiveUser(const std::string& email) override;
+  const std::string& GetOwnerEmail() const override;
+  void SessionStarted() override;
+  void RemoveUser(const std::string& email,
+                  user_manager::RemoveUserDelegate* delegate) override;
+
+  void set_owner_email(const std::string& owner_email) {
+    owner_email_ = owner_email;
+  }
+
+  void set_multi_profile_user_controller(
+      MultiProfileUserController* controller) {
+    multi_profile_user_controller_ = controller;
+  }
+
+ private:
+  scoped_ptr<FakeSupervisedUserManager> supervised_user_manager_;
+  std::string owner_email_;
+
+  MultiProfileUserController* multi_profile_user_controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeChromeUserManager);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_USERS_FAKE_CHROME_USER_MANAGER_H_
diff --git a/chrome/browser/chromeos/login/users/fake_user_manager.cc b/chrome/browser/chromeos/login/users/fake_user_manager.cc
deleted file mode 100644
index fac64ea..0000000
--- a/chrome/browser/chromeos/login/users/fake_user_manager.cc
+++ /dev/null
@@ -1,357 +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.
-
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
-
-#include "base/task_runner.h"
-#include "chrome/browser/chromeos/login/users/fake_supervised_user_manager.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/grit/theme_resources.h"
-#include "components/user_manager/user_image/user_image.h"
-#include "components/user_manager/user_type.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace {
-
-class FakeTaskRunner : public base::TaskRunner {
- public:
-  bool PostDelayedTask(const tracked_objects::Location& from_here,
-                       const base::Closure& task,
-                       base::TimeDelta delay) override {
-    task.Run();
-    return true;
-  }
-  bool RunsTasksOnCurrentThread() const override { return true; }
-
- protected:
-  ~FakeTaskRunner() override {}
-};
-
-}  // namespace
-
-namespace chromeos {
-
-FakeUserManager::FakeUserManager()
-    : ChromeUserManager(new FakeTaskRunner(), new FakeTaskRunner()),
-      supervised_user_manager_(new FakeSupervisedUserManager),
-      primary_user_(NULL),
-      multi_profile_user_controller_(NULL) {
-}
-
-FakeUserManager::~FakeUserManager() {
-  // Can't use STLDeleteElements because of the private destructor of User.
-  for (user_manager::UserList::iterator it = user_list_.begin();
-       it != user_list_.end();
-       it = user_list_.erase(it)) {
-    delete *it;
-  }
-}
-
-const user_manager::User* FakeUserManager::AddUser(const std::string& email) {
-  user_manager::User* user = user_manager::User::CreateRegularUser(email);
-  user->set_username_hash(
-      ProfileHelper::GetUserIdHashByUserIdForTesting(email));
-  user->SetStubImage(user_manager::UserImage(
-                         *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-                             IDR_PROFILE_PICTURE_LOADING)),
-                     user_manager::User::USER_IMAGE_PROFILE,
-                     false);
-  user_list_.push_back(user);
-  return user;
-}
-
-const user_manager::User* FakeUserManager::AddPublicAccountUser(
-    const std::string& email) {
-  user_manager::User* user = user_manager::User::CreatePublicAccountUser(email);
-  user->set_username_hash(
-      ProfileHelper::GetUserIdHashByUserIdForTesting(email));
-  user->SetStubImage(user_manager::UserImage(
-                         *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-                             IDR_PROFILE_PICTURE_LOADING)),
-                     user_manager::User::USER_IMAGE_PROFILE,
-                     false);
-  user_list_.push_back(user);
-  return user;
-}
-
-void FakeUserManager::AddKioskAppUser(const std::string& kiosk_app_username) {
-  user_manager::User* user =
-      user_manager::User::CreateKioskAppUser(kiosk_app_username);
-  user->set_username_hash(
-      ProfileHelper::GetUserIdHashByUserIdForTesting(kiosk_app_username));
-  user_list_.push_back(user);
-}
-
-void FakeUserManager::RemoveUserFromList(const std::string& email) {
-  user_manager::UserList::iterator it = user_list_.begin();
-  while (it != user_list_.end() && (*it)->email() != email) ++it;
-  if (it != user_list_.end()) {
-    delete *it;
-    user_list_.erase(it);
-  }
-}
-
-void FakeUserManager::LoginUser(const std::string& email) {
-  UserLoggedIn(
-      email, ProfileHelper::GetUserIdHashByUserIdForTesting(email), false);
-}
-
-const user_manager::UserList& FakeUserManager::GetUsers() const {
-  return user_list_;
-}
-
-user_manager::UserList FakeUserManager::GetUsersAllowedForMultiProfile() const {
-  user_manager::UserList result;
-  for (user_manager::UserList::const_iterator it = user_list_.begin();
-       it != user_list_.end();
-       ++it) {
-    if ((*it)->GetType() == user_manager::USER_TYPE_REGULAR &&
-        !(*it)->is_logged_in())
-      result.push_back(*it);
-  }
-  return result;
-}
-
-user_manager::UserList
-FakeUserManager::GetUsersAllowedForSupervisedUsersCreation() const {
-  return ChromeUserManager::GetUsersAllowedAsSupervisedUserManagers(user_list_);
-}
-
-const user_manager::UserList& FakeUserManager::GetLoggedInUsers() const {
-  return logged_in_users_;
-}
-
-void FakeUserManager::UserLoggedIn(const std::string& email,
-                                   const std::string& username_hash,
-                                   bool browser_restart) {
-  for (user_manager::UserList::const_iterator it = user_list_.begin();
-       it != user_list_.end();
-       ++it) {
-    if ((*it)->username_hash() == username_hash) {
-      (*it)->set_is_logged_in(true);
-      (*it)->set_profile_is_created();
-      logged_in_users_.push_back(*it);
-
-      if (!primary_user_)
-        primary_user_ = *it;
-      break;
-    }
-  }
-}
-
-user_manager::User* FakeUserManager::GetActiveUserInternal() const {
-  if (user_list_.size()) {
-    if (!active_user_id_.empty()) {
-      for (user_manager::UserList::const_iterator it = user_list_.begin();
-           it != user_list_.end();
-           ++it) {
-        if ((*it)->email() == active_user_id_)
-          return *it;
-      }
-    }
-    return user_list_[0];
-  }
-  return NULL;
-}
-
-const user_manager::User* FakeUserManager::GetActiveUser() const {
-  return GetActiveUserInternal();
-}
-
-user_manager::User* FakeUserManager::GetActiveUser() {
-  return GetActiveUserInternal();
-}
-
-void FakeUserManager::SwitchActiveUser(const std::string& email) {
-  active_user_id_ = email;
-  ProfileHelper::Get()->ActiveUserHashChanged(
-      ProfileHelper::GetUserIdHashByUserIdForTesting(email));
-  if (user_list_.size() && !active_user_id_.empty()) {
-    for (user_manager::UserList::const_iterator it = user_list_.begin();
-         it != user_list_.end(); ++it) {
-      (*it)->set_is_active((*it)->email() == active_user_id_);
-    }
-  }
-}
-
-void FakeUserManager::SaveUserDisplayName(
-    const std::string& username,
-    const base::string16& display_name) {
-  for (user_manager::UserList::iterator it = user_list_.begin();
-       it != user_list_.end();
-       ++it) {
-    if ((*it)->email() == username) {
-      (*it)->set_display_name(display_name);
-      return;
-    }
-  }
-}
-
-MultiProfileUserController* FakeUserManager::GetMultiProfileUserController() {
-  return multi_profile_user_controller_;
-}
-
-SupervisedUserManager* FakeUserManager::GetSupervisedUserManager() {
-  return supervised_user_manager_.get();
-}
-
-UserImageManager* FakeUserManager::GetUserImageManager(
-    const std::string& /* user_id */) {
-  return NULL;
-}
-
-const user_manager::UserList& FakeUserManager::GetLRULoggedInUsers() const {
-  return user_list_;
-}
-
-user_manager::UserList FakeUserManager::GetUnlockUsers() const {
-  return user_list_;
-}
-
-const std::string& FakeUserManager::GetOwnerEmail() const {
-  return owner_email_;
-}
-
-bool FakeUserManager::IsKnownUser(const std::string& email) const {
-  return true;
-}
-
-const user_manager::User* FakeUserManager::FindUser(
-    const std::string& email) const {
-  const user_manager::UserList& users = GetUsers();
-  for (user_manager::UserList::const_iterator it = users.begin();
-       it != users.end();
-       ++it) {
-    if ((*it)->email() == email)
-      return *it;
-  }
-  return NULL;
-}
-
-user_manager::User* FakeUserManager::FindUserAndModify(
-    const std::string& email) {
-  return NULL;
-}
-
-const user_manager::User* FakeUserManager::GetLoggedInUser() const {
-  return NULL;
-}
-
-user_manager::User* FakeUserManager::GetLoggedInUser() {
-  return NULL;
-}
-
-const user_manager::User* FakeUserManager::GetPrimaryUser() const {
-  return primary_user_;
-}
-
-base::string16 FakeUserManager::GetUserDisplayName(
-    const std::string& username) const {
-  return base::string16();
-}
-
-std::string FakeUserManager::GetUserDisplayEmail(
-    const std::string& username) const {
-  return std::string();
-}
-
-bool FakeUserManager::IsCurrentUserOwner() const {
-  return false;
-}
-
-bool FakeUserManager::IsCurrentUserNew() const {
-  return false;
-}
-
-bool FakeUserManager::IsCurrentUserNonCryptohomeDataEphemeral() const {
-  return false;
-}
-
-bool FakeUserManager::CanCurrentUserLock() const {
-  return false;
-}
-
-bool FakeUserManager::IsUserLoggedIn() const {
-  return logged_in_users_.size() > 0;
-}
-
-bool FakeUserManager::IsLoggedInAsUserWithGaiaAccount() const {
-  return true;
-}
-
-bool FakeUserManager::IsLoggedInAsPublicAccount() const {
-  return false;
-}
-
-bool FakeUserManager::IsLoggedInAsGuest() const {
-  return false;
-}
-
-bool FakeUserManager::IsLoggedInAsSupervisedUser() const {
-  return false;
-}
-
-bool FakeUserManager::IsLoggedInAsKioskApp() const {
-  const user_manager::User* active_user = GetActiveUser();
-  return active_user
-             ? active_user->GetType() == user_manager::USER_TYPE_KIOSK_APP
-             : false;
-}
-
-bool FakeUserManager::IsLoggedInAsStub() const {
-  return false;
-}
-
-bool FakeUserManager::IsSessionStarted() const {
-  return false;
-}
-
-bool FakeUserManager::IsUserNonCryptohomeDataEphemeral(
-    const std::string& email) const {
-  return false;
-}
-
-UserFlow* FakeUserManager::GetCurrentUserFlow() const {
-  return NULL;
-}
-
-UserFlow* FakeUserManager::GetUserFlow(const std::string& email) const {
-  return NULL;
-}
-
-bool FakeUserManager::AreSupervisedUsersAllowed() const {
-  return true;
-}
-
-bool FakeUserManager::AreEphemeralUsersEnabled() const {
-  return false;
-}
-
-const std::string& FakeUserManager::GetApplicationLocale() const {
-  static const std::string default_locale("en-US");
-  return default_locale;
-}
-
-PrefService* FakeUserManager::GetLocalState() const {
-  return NULL;
-}
-
-bool FakeUserManager::IsEnterpriseManaged() const {
-  return false;
-}
-
-bool FakeUserManager::IsDemoApp(const std::string& user_id) const {
-  return false;
-}
-
-bool FakeUserManager::IsKioskApp(const std::string& user_id) const {
-  return false;
-}
-
-bool FakeUserManager::IsPublicAccountMarkedForRemoval(
-    const std::string& user_id) const {
-  return false;
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
index bd822ac..126d6f1 100644
--- a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
+++ b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller_delegate.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
@@ -114,7 +114,7 @@
       public MultiProfileUserControllerDelegate {
  public:
   MultiProfileUserControllerTest()
-      : fake_user_manager_(new FakeUserManager),
+      : fake_user_manager_(new FakeChromeUserManager),
         user_manager_enabler_(fake_user_manager_),
         user_not_allowed_count_(0) {}
   ~MultiProfileUserControllerTest() override {}
@@ -203,7 +203,7 @@
   content::TestBrowserThreadBundle threads_;
   scoped_ptr<policy::PolicyCertVerifier> cert_verifier_;
   scoped_ptr<TestingProfileManager> profile_manager_;
-  FakeUserManager* fake_user_manager_;  // Not owned
+  FakeChromeUserManager* fake_user_manager_;  // Not owned
   ScopedUserManagerEnabler user_manager_enabler_;
 
   scoped_ptr<MultiProfileUserController> controller_;
diff --git a/chrome/browser/chromeos/login/users/user_manager_interface.h b/chrome/browser/chromeos/login/users/user_manager_interface.h
new file mode 100644
index 0000000..b17c543
--- /dev/null
+++ b/chrome/browser/chromeos/login/users/user_manager_interface.h
@@ -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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USERS_USER_MANAGER_INTERFACE_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_USERS_USER_MANAGER_INTERFACE_H_
+
+#include "base/basictypes.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_type.h"
+
+namespace chromeos {
+
+class MultiProfileUserController;
+class SupervisedUserManager;
+class UserFlow;
+class UserImageManager;
+
+// Chrome specific add-ons interface for the UserManager.
+class UserManagerInterface {
+ public:
+  UserManagerInterface() {}
+  virtual ~UserManagerInterface() {}
+
+  virtual MultiProfileUserController* GetMultiProfileUserController() = 0;
+  virtual UserImageManager* GetUserImageManager(const std::string& user_id) = 0;
+  virtual SupervisedUserManager* GetSupervisedUserManager() = 0;
+
+  // Method that allows to set |flow| for user identified by |user_id|.
+  // Flow should be set before login attempt.
+  // Takes ownership of the |flow|, |flow| will be deleted in case of login
+  // failure.
+  virtual void SetUserFlow(const std::string& user_id, UserFlow* flow) = 0;
+
+  // Return user flow for current user. Returns instance of DefaultUserFlow if
+  // no flow was defined for current user, or user is not logged in.
+  // Returned value should not be cached.
+  virtual UserFlow* GetCurrentUserFlow() const = 0;
+
+  // Return user flow for user identified by |user_id|. Returns instance of
+  // DefaultUserFlow if no flow was defined for user.
+  // Returned value should not be cached.
+  virtual UserFlow* GetUserFlow(const std::string& user_id) const = 0;
+
+  // Resets user flow for user identified by |user_id|.
+  virtual void ResetUserFlow(const std::string& user_id) = 0;
+
+  // Returns list of users allowed for supervised user creation.
+  // Returns an empty list in cases when supervised user creation or adding new
+  // users is restricted.
+  virtual user_manager::UserList GetUsersAllowedForSupervisedUsersCreation()
+      const = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(UserManagerInterface);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_USERS_USER_MANAGER_INTERFACE_H_
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc
index b8f2b564..12ab229d 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_unittest.cc
@@ -19,7 +19,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/prefs/testing_pref_service.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -39,14 +39,13 @@
 class WallpaperManagerCacheTest : public test::AshTestBase {
  public:
   WallpaperManagerCacheTest()
-      : fake_user_manager_(new FakeUserManager()),
-        scoped_user_manager_(fake_user_manager_) {
-  }
+      : fake_user_manager_(new FakeChromeUserManager()),
+        scoped_user_manager_(fake_user_manager_) {}
 
  protected:
   ~WallpaperManagerCacheTest() override {}
 
-  FakeUserManager* fake_user_manager() { return fake_user_manager_; }
+  FakeChromeUserManager* fake_user_manager() { return fake_user_manager_; }
 
   void SetUp() override { test::AshTestBase::SetUp(); }
 
@@ -59,7 +58,7 @@
   }
 
  private:
-  FakeUserManager* fake_user_manager_;
+  FakeChromeUserManager* fake_user_manager_;
   ScopedUserManagerEnabler scoped_user_manager_;
 };
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index a9c66d1..b48c7d80 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -85,9 +85,6 @@
 using content::BrowserThread;
 
 namespace {
-// If reboot didn't happen, ask user to reboot device manually.
-const int kWaitForRebootTimeSec = 3;
-
 // Interval in ms which is used for smooth screen showing.
 static int kShowDelayMs = 400;
 
@@ -194,8 +191,8 @@
 
 PrefService* WizardController::local_state_for_testing_ = NULL;
 
-WizardController::WizardController(chromeos::LoginDisplayHost* host,
-                                   chromeos::OobeDisplay* oobe_display)
+WizardController::WizardController(LoginDisplayHost* host,
+                                   OobeDisplay* oobe_display)
     : current_screen_(NULL),
       previous_screen_(NULL),
 #if defined(GOOGLE_CHROME_BUILD)
@@ -280,61 +277,54 @@
     ShowWrongHWIDScreen();
 }
 
-chromeos::ErrorScreen* WizardController::GetErrorScreen() {
-  return static_cast<chromeos::ErrorScreen*>(GetScreen(kErrorScreenName));
+ErrorScreen* WizardController::GetErrorScreen() {
+  return static_cast<ErrorScreen*>(GetScreen(kErrorScreenName));
 }
 
 BaseScreen* WizardController::CreateScreen(const std::string& screen_name) {
   if (screen_name == kNetworkScreenName) {
-    scoped_ptr<NetworkScreen> screen(new chromeos::NetworkScreen(
-        this, this, oobe_display_->GetNetworkView()));
+    scoped_ptr<NetworkScreen> screen(
+        new NetworkScreen(this, this, oobe_display_->GetNetworkView()));
     screen->Initialize(nullptr /* context */);
     return screen.release();
   } else if (screen_name == kErrorScreenName) {
-    return new chromeos::ErrorScreen(this,
-                                     oobe_display_->GetErrorScreenActor());
+    return new ErrorScreen(this, oobe_display_->GetErrorScreenActor());
   } else if (screen_name == kUpdateScreenName) {
-    chromeos::UpdateScreen* result =
-        new chromeos::UpdateScreen(this,
-                                   oobe_display_->GetUpdateScreenActor(),
-                                   remora_controller_.get());
-    result->SetRebootCheckDelay(kWaitForRebootTimeSec);
-    return result;
+    scoped_ptr<UpdateScreen> screen(new UpdateScreen(
+        this, oobe_display_->GetUpdateView(), remora_controller_.get()));
+    screen->Initialize(nullptr /* context */);
+    return screen.release();
   } else if (screen_name == kUserImageScreenName) {
-    return new chromeos::UserImageScreen(this,
-                                         oobe_display_->GetUserImageView());
+    return new UserImageScreen(this, oobe_display_->GetUserImageView());
   } else if (screen_name == kEulaScreenName) {
-    return new chromeos::EulaScreen(this, this, oobe_display_->GetEulaView());
+    return new EulaScreen(this, this, oobe_display_->GetEulaView());
   } else if (screen_name == kEnrollmentScreenName) {
-    return new chromeos::EnrollmentScreen(
-        this, oobe_display_->GetEnrollmentScreenActor());
+    return new EnrollmentScreen(this,
+                                oobe_display_->GetEnrollmentScreenActor());
   } else if (screen_name == kResetScreenName) {
-    return new chromeos::ResetScreen(this,
-                                     oobe_display_->GetResetScreenActor());
+    return new ResetScreen(this, oobe_display_->GetResetScreenActor());
   } else if (screen_name == kEnableDebuggingScreenName) {
-    return new chromeos::EnableDebuggingScreen(
-        this,
-        oobe_display_->GetEnableDebuggingScreenActor());
+    return new EnableDebuggingScreen(
+        this, oobe_display_->GetEnableDebuggingScreenActor());
   } else if (screen_name == kKioskEnableScreenName) {
-    return new chromeos::KioskEnableScreen(
-        this, oobe_display_->GetKioskEnableScreenActor());
+    return new KioskEnableScreen(this,
+                                 oobe_display_->GetKioskEnableScreenActor());
   } else if (screen_name == kKioskAutolaunchScreenName) {
-    return new chromeos::KioskAutolaunchScreen(
+    return new KioskAutolaunchScreen(
         this, oobe_display_->GetKioskAutolaunchScreenActor());
   } else if (screen_name == kTermsOfServiceScreenName) {
-    return new chromeos::TermsOfServiceScreen(
+    return new TermsOfServiceScreen(
         this, oobe_display_->GetTermsOfServiceScreenActor());
   } else if (screen_name == kWrongHWIDScreenName) {
-    return new chromeos::WrongHWIDScreen(
-        this, oobe_display_->GetWrongHWIDScreenActor());
+    return new WrongHWIDScreen(this, oobe_display_->GetWrongHWIDScreenActor());
   } else if (screen_name == kSupervisedUserCreationScreenName) {
-    return new chromeos::SupervisedUserCreationScreen(
+    return new SupervisedUserCreationScreen(
         this, oobe_display_->GetSupervisedUserCreationScreenActor());
   } else if (screen_name == kHIDDetectionScreenName) {
-    return new chromeos::HIDDetectionScreen(
-        this, oobe_display_->GetHIDDetectionScreenActor());
+    return new HIDDetectionScreen(this,
+                                  oobe_display_->GetHIDDetectionScreenActor());
   } else if (screen_name == kAutoEnrollmentCheckScreenName) {
-    return new chromeos::AutoEnrollmentCheckScreen(
+    return new AutoEnrollmentCheckScreen(
         this, oobe_display_->GetAutoEnrollmentCheckScreenActor());
   } else if (screen_name == kControllerPairingScreenName) {
     if (!shark_controller_) {
@@ -357,7 +347,7 @@
                                  oobe_display_->GetHostPairingScreenActor(),
                                  remora_controller_.get());
   } else if (screen_name == kDeviceDisabledScreenName) {
-    return new chromeos::DeviceDisabledScreen(
+    return new DeviceDisabledScreen(
         this, oobe_display_->GetDeviceDisabledScreenActor());
   }
 
@@ -656,10 +646,9 @@
 
   // Launch browser and delete login host controller.
   BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(&chromeos::LoginUtils::DoBrowserLaunch,
-                 base::Unretained(chromeos::LoginUtils::Get()),
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&LoginUtils::DoBrowserLaunch,
+                 base::Unretained(LoginUtils::Get()),
                  ProfileManager::GetActiveUserProfile(), host_));
   host_ = NULL;
 }
@@ -932,7 +921,7 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// WizardController, chromeos::BaseScreenDelegate overrides:
+// WizardController, BaseScreenDelegate overrides:
 void WizardController::OnExit(BaseScreen& /* screen */,
                               ExitCodes exit_code,
                               const ::login::ScreenContext* /* context */) {
@@ -1193,8 +1182,8 @@
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   if (connector->IsEnterpriseManaged()) {
     std::string policy_timezone;
-    if (chromeos::CrosSettings::Get()->GetString(
-            chromeos::kSystemTimezonePolicy, &policy_timezone) &&
+    if (CrosSettings::Get()->GetString(kSystemTimezonePolicy,
+                                       &policy_timezone) &&
         !policy_timezone.empty()) {
       VLOG(1) << "Resolve TimeZone: TimeZone settings are overridden"
               << " by DevicePolicy.";
@@ -1206,7 +1195,7 @@
     VLOG(1) << "Resolve TimeZone: setting timezone to '" << timezone->timeZoneId
             << "'";
 
-    chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
+    system::TimezoneSettings::GetInstance()->SetTimezoneFromID(
         base::UTF8ToUTF16(timezone->timeZoneId));
   }
 }
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 0fe3ced..a075f8d 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -436,10 +436,8 @@
     EXPECT_CALL(*mock_network_screen_, Show()).Times(0);
     EXPECT_CALL(*mock_network_screen_, Hide()).Times(0);
 
-    MOCK(mock_update_screen_,
-         kUpdateScreenName,
-         MockUpdateScreen,
-         MockUpdateScreenActor);
+    MOCK(mock_update_screen_, kUpdateScreenName, MockUpdateScreen,
+         MockUpdateView);
     MOCK_WITH_DELEGATE(mock_eula_screen_, kEulaScreenName, MockEulaScreen,
                        MockEulaView);
     MOCK(mock_enrollment_screen_,
@@ -533,7 +531,7 @@
   }
 
   linked_ptr<MockNetworkScreen> mock_network_screen_;
-  MockOutShowHide<MockUpdateScreen, MockUpdateScreenActor>* mock_update_screen_;
+  MockOutShowHide<MockUpdateScreen, MockUpdateView>* mock_update_screen_;
   MockOutShowHide<MockEulaScreen, MockEulaView>* mock_eula_screen_;
   MockOutShowHide<MockEnrollmentScreen,
       MockEnrollmentScreenActor>* mock_enrollment_screen_;
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
index 7ba138c..b4bdd1c 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -17,7 +17,6 @@
 
 namespace {
 
-const char kErrorInternal[] = "Internal Error.";
 const char kErrorKeyNotAllowedForSigning[] =
     "This key is not allowed for signing. Either it was used for signing "
     "before or it was not correctly generated.";
@@ -30,16 +29,10 @@
   return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64));
 }
 
-// Wraps |callback| into a void(bool) callback which forwards
-// |public_key_spki_der| if |true| is passed to it.
-void WrapGenerateKeyCallback(
+void RunGenerateKeyCallback(
     const PlatformKeysService::GenerateKeyCallback& callback,
-    const std::string& public_key_spki_der,
-    bool success) {
-  if (success)
-    callback.Run(public_key_spki_der, std::string() /* no error */);
-  else
-    callback.Run(std::string() /* no public key */, kErrorInternal);
+    const std::string& public_key_spki_der) {
+  callback.Run(public_key_spki_der, std::string() /* no error */);
 }
 
 // Callback used by |PlatformKeysService::Sign|.
@@ -118,7 +111,7 @@
 void PlatformKeysService::RegisterPublicKey(
     const std::string& extension_id,
     const std::string& public_key_spki_der,
-    const base::Callback<void(bool)>& callback) {
+    const base::Closure& callback) {
   GetPlatformKeysOfExtension(
       extension_id,
       base::Bind(&PlatformKeysService::RegisterPublicKeyGotPlatformKeys,
@@ -144,12 +137,16 @@
     const std::string& extension_id,
     const GetPlatformKeysCallback& callback) {
   state_store_->GetExtensionValue(
-      extension_id,
-      kStateStorePlatformKeys,
+      extension_id, kStateStorePlatformKeys,
       base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension,
-                 weak_factory_.GetWeakPtr(),
-                 extension_id,
-                 callback));
+                 weak_factory_.GetWeakPtr(), extension_id, callback));
+}
+
+void PlatformKeysService::SetPlatformKeysOfExtension(
+    const std::string& extension_id,
+    scoped_ptr<base::ListValue> platform_keys) {
+  state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys,
+                                  platform_keys.Pass());
 }
 
 void PlatformKeysService::GenerateRSAKeyCallback(
@@ -161,22 +158,16 @@
     callback.Run(std::string() /* no public key */, error_message);
     return;
   }
-  base::Callback<void(bool)> wrapped_callback(
-      base::Bind(&WrapGenerateKeyCallback, callback, public_key_spki_der));
+  base::Closure wrapped_callback(
+      base::Bind(&RunGenerateKeyCallback, callback, public_key_spki_der));
   RegisterPublicKey(extension_id, public_key_spki_der, wrapped_callback);
 }
 
 void PlatformKeysService::RegisterPublicKeyGotPlatformKeys(
     const std::string& extension_id,
     const std::string& public_key_spki_der,
-    const base::Callback<void(bool)>& callback,
+    const base::Closure& callback,
     scoped_ptr<base::ListValue> platform_keys) {
-  if (!platform_keys) {
-    LOG(ERROR) << "Error while reading the platform keys.";
-    callback.Run(false);
-    return;
-  }
-
   scoped_ptr<base::StringValue> key_value(
       GetPublicKeyValue(public_key_spki_der));
 
@@ -184,10 +175,8 @@
       << "Keys are assumed to be generated and not to be registered multiple "
          "times.";
   platform_keys->Append(key_value.release());
-
-  state_store_->SetExtensionValue(
-      extension_id, kStateStorePlatformKeys, platform_keys.Pass());
-  callback.Run(true);
+  SetPlatformKeysOfExtension(extension_id, platform_keys.Pass());
+  callback.Run();
 }
 
 void PlatformKeysService::InvalidateKey(
@@ -205,8 +194,7 @@
     return;
   }
 
-  state_store_->SetExtensionValue(
-      extension_id, kStateStorePlatformKeys, platform_keys.Pass());
+  SetPlatformKeysOfExtension(extension_id, platform_keys.Pass());
   callback.Run(true);
 }
 
@@ -220,8 +208,11 @@
   base::ListValue* keys = NULL;
   if (!value->GetAsList(&keys)) {
     LOG(ERROR) << "Found a value of wrong type.";
-    value.reset();
+
+    keys = new base::ListValue;
+    value.reset(keys);
   }
+
   ignore_result(value.release());
   callback.Run(make_scoped_ptr(keys));
 }
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.h b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
index f903d4d..79342d7 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
@@ -85,8 +85,8 @@
             const SignCallback& callback);
 
  private:
-  typedef base::Callback<void(scoped_ptr<base::ListValue> platform_keys)>
-      GetPlatformKeysCallback;
+  using GetPlatformKeysCallback =
+      base::Callback<void(scoped_ptr<base::ListValue> platform_keys)>;
 
   // Registers the given public key as newly generated key, which is allowed to
   // be used for signing for a single time. Afterwards, calls |callback|. If
@@ -94,7 +94,7 @@
   // callback.
   void RegisterPublicKey(const std::string& extension_id,
                          const std::string& public_key_spki_der,
-                         const base::Callback<void(bool)>& callback);
+                         const base::Closure& callback);
 
   // Gets the current validity of the given public key by reading StateStore.
   // Invalidates the key if it was found to be valid. Finally, calls |callback|
@@ -109,6 +109,11 @@
   void GetPlatformKeysOfExtension(const std::string& extension_id,
                                   const GetPlatformKeysCallback& callback);
 
+  // Writes |platform_keys| to the state store of the extension with id
+  // |extension_id|.
+  void SetPlatformKeysOfExtension(const std::string& extension_id,
+                                  scoped_ptr<base::ListValue> platform_keys);
+
   // Callback used by |GenerateRSAKey|.
   // If the key generation was successful, registers the generated public key
   // for the given extension. If any error occurs during key generation or
@@ -125,7 +130,7 @@
   void RegisterPublicKeyGotPlatformKeys(
       const std::string& extension_id,
       const std::string& public_key_spki_der,
-      const base::Callback<void(bool)>& callback,
+      const base::Closure& callback,
       scoped_ptr<base::ListValue> platform_keys);
 
   // Callback used by |ReadValidityAndInvalidateKey|.
diff --git a/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.cc b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.cc
new file mode 100644
index 0000000..952cab4c
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
+
+#include "base/logging.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
+#include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
+
+namespace policy {
+
+AffiliatedCloudPolicyInvalidator::AffiliatedCloudPolicyInvalidator(
+    enterprise_management::DeviceRegisterRequest::Type type,
+    CloudPolicyCore* core,
+    AffiliatedInvalidationServiceProvider* invalidation_service_provider)
+    : type_(type),
+      core_(core),
+      invalidation_service_provider_(invalidation_service_provider),
+      highest_handled_invalidation_version_(0) {
+  invalidation_service_provider_->RegisterConsumer(this);
+}
+
+AffiliatedCloudPolicyInvalidator::~AffiliatedCloudPolicyInvalidator() {
+  DestroyInvalidator();
+  invalidation_service_provider_->UnregisterConsumer(this);
+}
+
+void AffiliatedCloudPolicyInvalidator::OnInvalidationServiceSet(
+    invalidation::InvalidationService* invalidation_service) {
+  DestroyInvalidator();
+  if (invalidation_service)
+    CreateInvalidator(invalidation_service);
+}
+
+CloudPolicyInvalidator*
+AffiliatedCloudPolicyInvalidator::GetInvalidatorForTest() const {
+  return invalidator_.get();
+}
+
+void AffiliatedCloudPolicyInvalidator::CreateInvalidator(
+    invalidation::InvalidationService* invalidation_service) {
+  DCHECK(!invalidator_);
+  invalidator_.reset(new CloudPolicyInvalidator(
+      type_,
+      core_,
+      base::ThreadTaskRunnerHandle::Get(),
+      scoped_ptr<base::Clock>(new base::DefaultClock()),
+      highest_handled_invalidation_version_));
+  invalidator_->Initialize(invalidation_service);
+}
+
+void AffiliatedCloudPolicyInvalidator::DestroyInvalidator() {
+  if (!invalidator_)
+    return;
+
+  highest_handled_invalidation_version_ =
+      invalidator_->highest_handled_invalidation_version();
+  invalidator_->Shutdown();
+  invalidator_.reset();
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h
new file mode 100644
index 0000000..162f39b1
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_CLOUD_POLICY_INVALIDATOR_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_CLOUD_POLICY_INVALIDATOR_H_
+
+#include "base/basictypes.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
+#include "policy/proto/device_management_backend.pb.h"
+
+namespace invalidation {
+class InvalidationService;
+}
+
+namespace policy {
+
+class CloudPolicyCore;
+class CloudPolicyInvalidator;
+
+// This class provides policy invalidations for a |CloudPolicyCore| that wishes
+// to use a shared |InvalidationService| affiliated with the device's enrollment
+// domain. This is the case e.g. for device policy and device-local account
+// policy.
+// It relies on an |AffiliatedInvalidationServiceProvider| to provide it with
+// access to a shared |InvalidationService| to back the
+// |CloudPolicyInvalidator|. Whenever the shared |InvalidationService| changes,
+// the |CloudPolicyInvalidator| is destroyed and re-created.
+class AffiliatedCloudPolicyInvalidator
+    : public AffiliatedInvalidationServiceProvider::Consumer {
+ public:
+  AffiliatedCloudPolicyInvalidator(
+      enterprise_management::DeviceRegisterRequest::Type type,
+      CloudPolicyCore* core,
+      AffiliatedInvalidationServiceProvider* invalidation_service_provider);
+  ~AffiliatedCloudPolicyInvalidator() override;
+
+  // AffiliatedInvalidationServiceProvider::Consumer:
+  void OnInvalidationServiceSet(
+      invalidation::InvalidationService* invalidation_service) override;
+
+  CloudPolicyInvalidator* GetInvalidatorForTest() const;
+
+ private:
+  // Create a |CloudPolicyInvalidator| backed by the |invalidation_service|.
+  void CreateInvalidator(
+      invalidation::InvalidationService* invalidation_service);
+
+  // Destroy the current |CloudPolicyInvalidator|, if any.
+  void DestroyInvalidator();
+
+  const enterprise_management::DeviceRegisterRequest::Type type_;
+  CloudPolicyCore* const core_;
+
+  AffiliatedInvalidationServiceProvider* const invalidation_service_provider_;
+
+  // The highest invalidation version that was handled already.
+  int64 highest_handled_invalidation_version_;
+
+  // The current |CloudPolicyInvalidator|. nullptr if no connected invalidation
+  // service is available.
+  scoped_ptr<CloudPolicyInvalidator> invalidator_;
+
+  DISALLOW_COPY_AND_ASSIGN(AffiliatedCloudPolicyInvalidator);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_CLOUD_POLICY_INVALIDATOR_H_
diff --git a/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
new file mode 100644
index 0000000..f277324a
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
@@ -0,0 +1,194 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
+
+#include <string>
+
+#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h"
+#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
+#include "chrome/browser/invalidation/fake_invalidation_service.h"
+#include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
+#include "components/invalidation/invalidation.h"
+#include "components/invalidation/object_id_invalidation_map.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
+#include "components/policy/core/common/cloud/cloud_policy_core.h"
+#include "components/policy/core/common/cloud/cloud_policy_store.h"
+#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "google/cacheinvalidation/include/types.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace em = enterprise_management;
+
+using testing::Invoke;
+using testing::Mock;
+using testing::WithArgs;
+
+namespace policy {
+
+namespace {
+
+const int kInvalidationSource = 123;
+const char kInvalidationName[] = "invalidation";
+
+class FakeCloudPolicyStore : public CloudPolicyStore {
+ public:
+  FakeCloudPolicyStore();
+
+  // CloudPolicyStore:
+  void Store(const em::PolicyFetchResponse& policy) override;
+  void Load() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeCloudPolicyStore);
+};
+
+FakeCloudPolicyStore::FakeCloudPolicyStore() {
+}
+
+void FakeCloudPolicyStore::Store(const em::PolicyFetchResponse& policy) {
+  policy_.reset(new em::PolicyData);
+  policy_->ParseFromString(policy.policy_data());
+  Load();
+}
+
+void FakeCloudPolicyStore::Load() {
+  NotifyStoreLoaded();
+}
+
+}  // namespace
+
+// Verifies that an invalidator is created/destroyed as an invalidation service
+// becomes available/unavailable. Also verifies that invalidations are handled
+// correctly and the highest handled invalidation version is preserved when
+// switching invalidation services.
+TEST(AffiliatedCloudPolicyInvalidatorTest, CreateUseDestroy) {
+  content::TestBrowserThreadBundle thread_bundle;
+
+  // Set up a CloudPolicyCore backed by a simple CloudPolicyStore that does no
+  // signature verification and stores policy in memory.
+  FakeCloudPolicyStore store;
+  CloudPolicyCore core(dm_protocol::kChromeDevicePolicyType,
+                       std::string(),
+                       &store,
+                       base::ThreadTaskRunnerHandle::Get());
+
+  // Connect |core|. Expect it to send a registration request. Let the
+  // registration succeed.
+  scoped_ptr<MockCloudPolicyClient> policy_client_owner(
+      new MockCloudPolicyClient);
+  MockCloudPolicyClient* policy_client = policy_client_owner.get();
+  EXPECT_CALL(*policy_client, SetupRegistration("token", "device-id"))
+      .WillOnce(WithArgs<1>(Invoke(policy_client,
+                                   &MockCloudPolicyClient::SetDMToken)));
+  core.Connect(policy_client_owner.Pass());
+  Mock::VerifyAndClearExpectations(&policy_client);
+  core.StartRefreshScheduler();
+
+  DevicePolicyBuilder policy;
+  policy.policy_data().set_invalidation_source(kInvalidationSource);
+  policy.policy_data().set_invalidation_name(kInvalidationName);
+  policy.Build();
+  store.Store(policy.policy());
+
+  FakeAffiliatedInvalidationServiceProvider provider;
+  AffiliatedCloudPolicyInvalidator affiliated_invalidator(
+      em::DeviceRegisterRequest::DEVICE,
+      &core,
+      &provider);
+
+  // Verify that no invalidator exists initially.
+  EXPECT_FALSE(affiliated_invalidator.GetInvalidatorForTest());
+
+  // Make a first invalidation service available.
+  invalidation::FakeInvalidationService invalidation_service_1;
+  affiliated_invalidator.OnInvalidationServiceSet(&invalidation_service_1);
+
+  // Verify that an invalidator backed by the first invalidation service has
+  // been created and its highest handled invalidation version starts out as
+  // zero.
+  CloudPolicyInvalidator* invalidator =
+      affiliated_invalidator.GetInvalidatorForTest();
+  ASSERT_TRUE(invalidator);
+  EXPECT_EQ(0, invalidator->highest_handled_invalidation_version());
+  EXPECT_EQ(&invalidation_service_1,
+            invalidator->invalidation_service_for_test());
+
+  // Trigger an invalidation. The invalidation version is interpreted as a
+  // timestamp in microseconds. The policy blob contains a timestamp in
+  // milliseconds. Convert from one to the other by multiplying by 1000.
+  const int64 invalidation_version = policy.policy_data().timestamp() * 1000;
+  syncer::Invalidation invalidation = syncer::Invalidation::Init(
+      invalidation::ObjectId(kInvalidationSource, kInvalidationName),
+      invalidation_version,
+      "dummy payload");
+  syncer::ObjectIdInvalidationMap invalidation_map;
+  invalidation_map.Insert(invalidation);
+  invalidator->OnIncomingInvalidation(invalidation_map);
+
+  // Allow the invalidation to be handled.
+  policy_client->SetFetchedInvalidationVersion(invalidation_version);
+  policy.payload().mutable_reboot_on_shutdown()->set_reboot_on_shutdown(true);
+  policy.Build();
+  policy_client->SetPolicy(dm_protocol::kChromeDevicePolicyType,
+                           std::string(),
+                           policy.policy());
+  EXPECT_CALL(*policy_client, FetchPolicy())
+      .WillOnce(Invoke(policy_client,
+                       &MockCloudPolicyClient::NotifyPolicyFetched));
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that the invalidator's highest handled invalidation version was
+  // updated and the new policy was stored.
+  EXPECT_EQ(invalidation_version,
+            invalidator->highest_handled_invalidation_version());
+  ASSERT_TRUE(store.policy());
+  em::ChromeDeviceSettingsProto device_policy;
+  device_policy.ParseFromString(store.policy()->policy_value());
+  EXPECT_EQ(true, device_policy.reboot_on_shutdown().reboot_on_shutdown());
+
+  // Make the first invalidation service unavailable. Verify that the
+  // invalidator is destroyed.
+  affiliated_invalidator.OnInvalidationServiceSet(nullptr);
+  EXPECT_FALSE(affiliated_invalidator.GetInvalidatorForTest());
+
+  // Make a second invalidation service available.
+  invalidation::FakeInvalidationService invalidation_service_2;
+  affiliated_invalidator.OnInvalidationServiceSet(&invalidation_service_2);
+
+  // Verify that an invalidator backed by the second invalidation service has
+  // been created and its highest handled invalidation version does not start
+  // out as zero.
+  invalidator = affiliated_invalidator.GetInvalidatorForTest();
+  ASSERT_TRUE(invalidator);
+  EXPECT_EQ(invalidation_version,
+            invalidator->highest_handled_invalidation_version());
+  EXPECT_EQ(&invalidation_service_2,
+            invalidator->invalidation_service_for_test());
+
+  // Make the first invalidation service available again. This implies that the
+  // second invalidation service is no longer available.
+  affiliated_invalidator.OnInvalidationServiceSet(&invalidation_service_1);
+
+  // Verify that the invalidator backed by the second invalidation service was
+  // destroyed and an invalidation backed by the first invalidation service has
+  // been created instead. Also verify that its highest handled invalidation
+  // version does not start out as zero.
+  invalidator = affiliated_invalidator.GetInvalidatorForTest();
+  ASSERT_TRUE(invalidator);
+  EXPECT_EQ(invalidation_version,
+            invalidator->highest_handled_invalidation_version());
+  EXPECT_EQ(&invalidation_service_1,
+            invalidator->invalidation_service_for_test());
+
+  provider.Shutdown();
+  affiliated_invalidator.OnInvalidationServiceSet(nullptr);
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc
index 7fbbdf3..6cc2a87 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.cc
@@ -4,340 +4,19 @@
 
 #include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
 
-#include <vector>
-
-#include "base/logging.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_process_platform_part_chromeos.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/ticl_device_settings_provider.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/settings/device_identity_provider.h"
-#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
-#include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_content_client.h"
-#include "components/invalidation/invalidation_handler.h"
-#include "components/invalidation/invalidation_service.h"
-#include "components/invalidation/invalidation_state_tracker.h"
-#include "components/invalidation/invalidator_state.h"
-#include "components/invalidation/invalidator_storage.h"
-#include "components/invalidation/profile_invalidation_provider.h"
-#include "components/invalidation/ticl_invalidation_service.h"
-#include "components/invalidation/ticl_settings_provider.h"
-#include "components/policy/core/common/cloud/cloud_policy_constants.h"
-#include "components/user_manager/user.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_service.h"
-#include "google_apis/gaia/identity_provider.h"
-
 namespace policy {
 
+AffiliatedInvalidationServiceProvider::Consumer::Consumer() {
+}
+
 AffiliatedInvalidationServiceProvider::Consumer::~Consumer() {
 }
 
-class AffiliatedInvalidationServiceProvider::InvalidationServiceObserver
-    : public syncer::InvalidationHandler {
- public:
-  explicit InvalidationServiceObserver(
-      AffiliatedInvalidationServiceProvider* parent,
-      invalidation::InvalidationService* invalidation_service);
-  ~InvalidationServiceObserver() override;
-
-  invalidation::InvalidationService* GetInvalidationService();
-  bool IsServiceConnected() const;
-
-  // public syncer::InvalidationHandler:
-  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
-  void OnIncomingInvalidation(
-      const syncer::ObjectIdInvalidationMap& invalidation_map) override;
-  std::string GetOwnerName() const override;
-
- private:
-  AffiliatedInvalidationServiceProvider* parent_;
-  invalidation::InvalidationService* invalidation_service_;
-  bool is_service_connected_;
-  bool is_observer_ready_;
-
-  DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
-};
-
-AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
-    InvalidationServiceObserver(
-        AffiliatedInvalidationServiceProvider* parent,
-        invalidation::InvalidationService* invalidation_service)
-    : parent_(parent),
-      invalidation_service_(invalidation_service),
-      is_service_connected_(false),
-      is_observer_ready_(false) {
-  invalidation_service_->RegisterInvalidationHandler(this);
-  is_service_connected_ = invalidation_service->GetInvalidatorState() ==
-      syncer::INVALIDATIONS_ENABLED;
-  is_observer_ready_ = true;
-}
-
-AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
-    ~InvalidationServiceObserver() {
-  is_observer_ready_ = false;
-  invalidation_service_->UnregisterInvalidationHandler(this);
-}
-
-invalidation::InvalidationService*
-AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
-    GetInvalidationService() {
-  return invalidation_service_;
-}
-
-bool AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
-         IsServiceConnected() const {
-  return is_service_connected_;
-}
-
-void AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
-    OnInvalidatorStateChange(syncer::InvalidatorState state) {
-  if (!is_observer_ready_)
-    return;
-
-  const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
-  if (is_service_connected == is_service_connected_)
-    return;
-
-  is_service_connected_ = is_service_connected;
-  if (is_service_connected_)
-    parent_->OnInvalidationServiceConnected(invalidation_service_);
-  else
-    parent_->OnInvalidationServiceDisconnected(invalidation_service_);
-}
-
-void AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
-    OnIncomingInvalidation(
-        const syncer::ObjectIdInvalidationMap& invalidation_map) {
-}
-
-std::string AffiliatedInvalidationServiceProvider::InvalidationServiceObserver::
-    GetOwnerName() const {
-  return "AffiliatedInvalidationService";
-}
-
-AffiliatedInvalidationServiceProvider::AffiliatedInvalidationServiceProvider()
-    : invalidation_service_(nullptr),
-      consumer_count_(0),
-      is_shut_down_(false) {
-  // The AffiliatedInvalidationServiceProvider should be created before any user
-  // Profiles.
-  DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
-
-  // Subscribe to notification about new user profiles becoming available.
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
-                 content::NotificationService::AllSources());
+AffiliatedInvalidationServiceProvider::AffiliatedInvalidationServiceProvider() {
 }
 
 AffiliatedInvalidationServiceProvider::
 ~AffiliatedInvalidationServiceProvider() {
-  // Verify that the provider was shut down first.
-  DCHECK(is_shut_down_);
-}
-
-void AffiliatedInvalidationServiceProvider::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, type);
-  DCHECK(!is_shut_down_);
-  Profile* profile = content::Details<Profile>(details).ptr();
-  invalidation::ProfileInvalidationProvider* invalidation_provider =
-      invalidation::ProfileInvalidationProviderFactory::GetForProfile(profile);
-  if (!invalidation_provider) {
-    // If the Profile does not support invalidation (e.g. guest, incognito),
-    // ignore it.
-    return;
-  }
-  user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
-  if (!user ||
-      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
-          GetUserAffiliation(user->email()) != USER_AFFILIATION_MANAGED) {
-    // If the Profile belongs to a user who is not affiliated with the device's
-    // enrollment domain, ignore it.
-    return;
-  }
-
-  // Create a state observer for the user's invalidation service.
-  invalidation::InvalidationService* invalidation_service =
-      invalidation_provider->GetInvalidationService();
-  profile_invalidation_service_observers_.push_back(
-      new InvalidationServiceObserver(this, invalidation_service));
-
-  if (profile_invalidation_service_observers_.back()->IsServiceConnected()) {
-    // If the invalidation service is connected, check whether to switch to it.
-    OnInvalidationServiceConnected(invalidation_service);
-  }
-}
-
-void AffiliatedInvalidationServiceProvider::RegisterConsumer(
-    Consumer* consumer) {
-  if (consumers_.HasObserver(consumer) || is_shut_down_)
-    return;
-
-  consumers_.AddObserver(consumer);
-  ++consumer_count_;
-
-  if (invalidation_service_)
-    consumer->OnInvalidationServiceSet(invalidation_service_);
-  else if (consumer_count_ == 1)
-    FindConnectedInvalidationService();
-}
-
-void AffiliatedInvalidationServiceProvider::UnregisterConsumer(
-    Consumer* consumer) {
-  if (!consumers_.HasObserver(consumer))
-    return;
-
-  consumers_.RemoveObserver(consumer);
-  --consumer_count_;
-
-  if (invalidation_service_ && consumer_count_ == 0) {
-    invalidation_service_ = nullptr;
-    DestroyDeviceInvalidationService();
-  }
-}
-
-void AffiliatedInvalidationServiceProvider::Shutdown() {
-  is_shut_down_ = true;
-
-  registrar_.RemoveAll();
-  profile_invalidation_service_observers_.clear();
-  DestroyDeviceInvalidationService();
-
-  if (invalidation_service_) {
-    invalidation_service_ = nullptr;
-    // Explicitly notify consumers that the invalidation service they were using
-    // is no longer available.
-    SetInvalidationService(nullptr);
-  }
-}
-
-invalidation::TiclInvalidationService*
-AffiliatedInvalidationServiceProvider::
-    GetDeviceInvalidationServiceForTest() const {
-  return device_invalidation_service_.get();
-}
-
-void AffiliatedInvalidationServiceProvider::OnInvalidationServiceConnected(
-    invalidation::InvalidationService* invalidation_service) {
-  DCHECK(!is_shut_down_);
-
-  if (consumer_count_ == 0) {
-    // If there are no consumers, no invalidation service is required.
-    return;
-  }
-
-  if (!device_invalidation_service_) {
-    // The lack of a device-global invalidation service implies that another
-    // connected invalidation service is being made available to consumers
-    // already. There is no need to switch from that to the service which just
-    // connected.
-    return;
-  }
-
-  if (invalidation_service != device_invalidation_service_.get()) {
-    // If an invalidation service other than the device-global one connected,
-    // destroy the device-global service.
-    invalidation_service_ = nullptr;
-    DestroyDeviceInvalidationService();
-  }
-
-  // Make the invalidation service that just connected available to consumers.
-  SetInvalidationService(invalidation_service);
-}
-
-void AffiliatedInvalidationServiceProvider::OnInvalidationServiceDisconnected(
-    invalidation::InvalidationService* invalidation_service) {
-  DCHECK(!is_shut_down_);
-
-  if (invalidation_service != invalidation_service_) {
-    // If the invalidation service which disconnected was not being made
-    // available to consumers, return.
-    return;
-  }
-
-  // The invalidation service which disconnected was being made available to
-  // consumers. Stop making it available.
-  DCHECK(consumer_count_);
-  invalidation_service_ = nullptr;
-
-  // Try to make another invalidation service available to consumers.
-  FindConnectedInvalidationService();
-
-  // If no other connected invalidation service was found, explicitly notify
-  // consumers that the invalidation service they were using is no longer
-  // available.
-  if (!invalidation_service_)
-    SetInvalidationService(nullptr);
-}
-
-void AffiliatedInvalidationServiceProvider::FindConnectedInvalidationService() {
-  DCHECK(!invalidation_service_);
-  DCHECK(consumer_count_);
-  DCHECK(!is_shut_down_);
-
-  for (ScopedVector<InvalidationServiceObserver>::const_iterator it =
-           profile_invalidation_service_observers_.begin();
-           it != profile_invalidation_service_observers_.end(); ++it) {
-    if ((*it)->IsServiceConnected()) {
-      // If a connected invalidation service belonging to an affiliated
-      // logged-in user is found, make it available to consumers.
-      DestroyDeviceInvalidationService();
-      SetInvalidationService((*it)->GetInvalidationService());
-      return;
-    }
-  }
-
-  if (!device_invalidation_service_) {
-    // If no other connected invalidation service was found and no device-global
-    // invalidation service exists, create one.
-    device_invalidation_service_.reset(
-        new invalidation::TiclInvalidationService(
-            GetUserAgent(),
-            scoped_ptr<IdentityProvider>(new chromeos::DeviceIdentityProvider(
-                chromeos::DeviceOAuth2TokenServiceFactory::Get())),
-            scoped_ptr<invalidation::TiclSettingsProvider>(
-                new TiclDeviceSettingsProvider),
-            g_browser_process->gcm_driver(),
-            g_browser_process->system_request_context()));
-    device_invalidation_service_->Init(
-        scoped_ptr<syncer::InvalidationStateTracker>(
-            new invalidation::InvalidatorStorage(
-                    g_browser_process->local_state())));
-    device_invalidation_service_observer_.reset(
-        new InvalidationServiceObserver(
-                this,
-                device_invalidation_service_.get()));
-  }
-
-  if (device_invalidation_service_observer_->IsServiceConnected()) {
-    // If the device-global invalidation service is connected already, make it
-    // available to consumers immediately. Otherwise, the invalidation service
-    // will be made available to clients when it successfully connects.
-    OnInvalidationServiceConnected(device_invalidation_service_.get());
-  }
-}
-
-void AffiliatedInvalidationServiceProvider::SetInvalidationService(
-    invalidation::InvalidationService* invalidation_service) {
-  DCHECK(!invalidation_service_);
-  invalidation_service_ = invalidation_service;
-  FOR_EACH_OBSERVER(Consumer,
-                    consumers_,
-                    OnInvalidationServiceSet(invalidation_service_));
-}
-
-void AffiliatedInvalidationServiceProvider::DestroyDeviceInvalidationService() {
-  device_invalidation_service_observer_.reset();
-  device_invalidation_service_.reset();
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h
index 548435507..c1b3b36 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h
@@ -6,15 +6,9 @@
 #define CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_H_
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/observer_list.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 namespace invalidation {
 class InvalidationService;
-class TiclInvalidationService;
 }
 
 namespace policy {
@@ -34,11 +28,12 @@
 // between them whenever the service currently in use disconnects or the
 // device-global invalidation service can be replaced with another service that
 // just connected.
-class AffiliatedInvalidationServiceProvider
-    : public content::NotificationObserver {
+class AffiliatedInvalidationServiceProvider {
  public:
   class Consumer {
    public:
+    Consumer();
+
     // This method is called when the invalidation service that the consumer
     // should use changes:
     // * If |invalidation_service| is a nullptr, no invalidation service is
@@ -51,15 +46,12 @@
 
    protected:
     virtual ~Consumer();
+
+    DISALLOW_ASSIGN(Consumer);
   };
 
   AffiliatedInvalidationServiceProvider();
-  ~AffiliatedInvalidationServiceProvider() override;
-
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  virtual ~AffiliatedInvalidationServiceProvider();
 
   // Indicates that |consumer| is interested in using the shared
   // |InvalidationService|. The consumer's OnInvalidationServiceSet() method
@@ -67,72 +59,20 @@
   // available. If an invalidation service is available already, the callback
   // will occur synchronously. The |consumer| must be unregistered before |this|
   // is destroyed.
-  void RegisterConsumer(Consumer* consumer);
+  virtual void RegisterConsumer(Consumer* consumer) = 0;
 
   // Indicates that |consumer| is no longer interested in using the
   // shared |InvalidationService|.
-  void UnregisterConsumer(Consumer* consumer);
+  virtual void UnregisterConsumer(Consumer* consumer) = 0;
 
   // Shuts down the provider. Once the provider is shut down, it no longer makes
   // any invalidation service available to consumers, no longer observes any
   // per-profile invalidation services and no longer maintains a device-global
   // invalidation service.
-  void Shutdown();
-
-  invalidation::TiclInvalidationService*
-      GetDeviceInvalidationServiceForTest() const;
+  virtual void Shutdown() = 0;
 
  private:
-  // Helper that monitors the status of a single |InvalidationService|.
-  class InvalidationServiceObserver;
-
-  // Status updates received from |InvalidationServiceObserver|s.
-  void OnInvalidationServiceConnected(
-      invalidation::InvalidationService* invalidation_service);
-  void OnInvalidationServiceDisconnected(
-      invalidation::InvalidationService* invalidation_service);
-
-  // Checks whether a connected |InvalidationService| affiliated with the
-  // device's enrollment domain is available. If so, notifies the consumers.
-  // Otherwise, consumers will be notified once such an invalidation service
-  // becomes available.
-  // Further ensures that a device-global invalidation service is running iff
-  // there is no other connected service available for use and there is at least
-  // one registered consumer.
-  void FindConnectedInvalidationService();
-
-  // Choose |invalidation_service| as the shared invalidation service and notify
-  // consumers.
-  void SetInvalidationService(
-      invalidation::InvalidationService* invalidation_service);
-
-  // Destroy the device-global invalidation service, if any.
-  void DestroyDeviceInvalidationService();
-
-  content::NotificationRegistrar registrar_;
-
-  // Device-global invalidation service.
-  scoped_ptr<invalidation::TiclInvalidationService>
-      device_invalidation_service_;
-
-  // State observer for the device-global invalidation service.
-  scoped_ptr<InvalidationServiceObserver> device_invalidation_service_observer_;
-
-  // State observers for logged-in users' invalidation services.
-  ScopedVector<InvalidationServiceObserver>
-      profile_invalidation_service_observers_;
-
-  // The invalidation service currently used by consumers. nullptr if there are
-  // no registered consumers or no connected invalidation service is available
-  // for use.
-  invalidation::InvalidationService* invalidation_service_;
-
-  ObserverList<Consumer, true> consumers_;
-  int consumer_count_;
-
-  bool is_shut_down_;
-
-  DISALLOW_COPY_AND_ASSIGN(AffiliatedInvalidationServiceProvider);
+  DISALLOW_ASSIGN(AffiliatedInvalidationServiceProvider);
 };
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
new file mode 100644
index 0000000..353662c
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
@@ -0,0 +1,345 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part_chromeos.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/ticl_device_settings_provider.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/settings/device_identity_provider.h"
+#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
+#include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_content_client.h"
+#include "components/invalidation/invalidation_handler.h"
+#include "components/invalidation/invalidation_service.h"
+#include "components/invalidation/invalidation_state_tracker.h"
+#include "components/invalidation/invalidator_state.h"
+#include "components/invalidation/invalidator_storage.h"
+#include "components/invalidation/profile_invalidation_provider.h"
+#include "components/invalidation/ticl_invalidation_service.h"
+#include "components/invalidation/ticl_settings_provider.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
+#include "components/user_manager/user.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "google_apis/gaia/identity_provider.h"
+
+namespace policy {
+
+class AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver
+    : public syncer::InvalidationHandler {
+ public:
+  explicit InvalidationServiceObserver(
+      AffiliatedInvalidationServiceProviderImpl* parent,
+      invalidation::InvalidationService* invalidation_service);
+  ~InvalidationServiceObserver() override;
+
+  invalidation::InvalidationService* GetInvalidationService();
+  bool IsServiceConnected() const;
+
+  // public syncer::InvalidationHandler:
+  void OnInvalidatorStateChange(syncer::InvalidatorState state) override;
+  void OnIncomingInvalidation(
+      const syncer::ObjectIdInvalidationMap& invalidation_map) override;
+  std::string GetOwnerName() const override;
+
+ private:
+  AffiliatedInvalidationServiceProviderImpl* parent_;
+  invalidation::InvalidationService* invalidation_service_;
+  bool is_service_connected_;
+  bool is_observer_ready_;
+
+  DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
+};
+
+AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+    InvalidationServiceObserver(
+        AffiliatedInvalidationServiceProviderImpl* parent,
+        invalidation::InvalidationService* invalidation_service)
+    : parent_(parent),
+      invalidation_service_(invalidation_service),
+      is_service_connected_(false),
+      is_observer_ready_(false) {
+  invalidation_service_->RegisterInvalidationHandler(this);
+  is_service_connected_ = invalidation_service->GetInvalidatorState() ==
+      syncer::INVALIDATIONS_ENABLED;
+  is_observer_ready_ = true;
+}
+
+AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+    ~InvalidationServiceObserver() {
+  is_observer_ready_ = false;
+  invalidation_service_->UnregisterInvalidationHandler(this);
+}
+
+invalidation::InvalidationService*
+AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+    GetInvalidationService() {
+  return invalidation_service_;
+}
+
+bool AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+         IsServiceConnected() const {
+  return is_service_connected_;
+}
+
+void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+    OnInvalidatorStateChange(syncer::InvalidatorState state) {
+  if (!is_observer_ready_)
+    return;
+
+  const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
+  if (is_service_connected == is_service_connected_)
+    return;
+
+  is_service_connected_ = is_service_connected;
+  if (is_service_connected_)
+    parent_->OnInvalidationServiceConnected(invalidation_service_);
+  else
+    parent_->OnInvalidationServiceDisconnected(invalidation_service_);
+}
+
+void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+    OnIncomingInvalidation(
+        const syncer::ObjectIdInvalidationMap& invalidation_map) {
+}
+
+std::string
+AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+    GetOwnerName() const {
+  return "AffiliatedInvalidationService";
+}
+
+AffiliatedInvalidationServiceProviderImpl::
+AffiliatedInvalidationServiceProviderImpl()
+    : invalidation_service_(nullptr),
+      consumer_count_(0),
+      is_shut_down_(false) {
+  // The AffiliatedInvalidationServiceProviderImpl should be created before any
+  // user Profiles.
+  DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
+
+  // Subscribe to notification about new user profiles becoming available.
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
+                 content::NotificationService::AllSources());
+}
+
+AffiliatedInvalidationServiceProviderImpl::
+~AffiliatedInvalidationServiceProviderImpl() {
+  // Verify that the provider was shut down first.
+  DCHECK(is_shut_down_);
+}
+
+void AffiliatedInvalidationServiceProviderImpl::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, type);
+  DCHECK(!is_shut_down_);
+  Profile* profile = content::Details<Profile>(details).ptr();
+  invalidation::ProfileInvalidationProvider* invalidation_provider =
+      invalidation::ProfileInvalidationProviderFactory::GetForProfile(profile);
+  if (!invalidation_provider) {
+    // If the Profile does not support invalidation (e.g. guest, incognito),
+    // ignore it.
+    return;
+  }
+  user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  if (!user ||
+      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
+          GetUserAffiliation(user->email()) != USER_AFFILIATION_MANAGED) {
+    // If the Profile belongs to a user who is not affiliated with the device's
+    // enrollment domain, ignore it.
+    return;
+  }
+
+  // Create a state observer for the user's invalidation service.
+  invalidation::InvalidationService* invalidation_service =
+      invalidation_provider->GetInvalidationService();
+  profile_invalidation_service_observers_.push_back(
+      new InvalidationServiceObserver(this, invalidation_service));
+
+  if (profile_invalidation_service_observers_.back()->IsServiceConnected()) {
+    // If the invalidation service is connected, check whether to switch to it.
+    OnInvalidationServiceConnected(invalidation_service);
+  }
+}
+
+void AffiliatedInvalidationServiceProviderImpl::RegisterConsumer(
+    Consumer* consumer) {
+  if (consumers_.HasObserver(consumer) || is_shut_down_)
+    return;
+
+  consumers_.AddObserver(consumer);
+  ++consumer_count_;
+
+  if (invalidation_service_)
+    consumer->OnInvalidationServiceSet(invalidation_service_);
+  else if (consumer_count_ == 1)
+    FindConnectedInvalidationService();
+}
+
+void AffiliatedInvalidationServiceProviderImpl::UnregisterConsumer(
+    Consumer* consumer) {
+  if (!consumers_.HasObserver(consumer))
+    return;
+
+  consumers_.RemoveObserver(consumer);
+  --consumer_count_;
+
+  if (invalidation_service_ && consumer_count_ == 0) {
+    invalidation_service_ = nullptr;
+    DestroyDeviceInvalidationService();
+  }
+}
+
+void AffiliatedInvalidationServiceProviderImpl::Shutdown() {
+  is_shut_down_ = true;
+
+  registrar_.RemoveAll();
+  profile_invalidation_service_observers_.clear();
+  DestroyDeviceInvalidationService();
+
+  if (invalidation_service_) {
+    invalidation_service_ = nullptr;
+    // Explicitly notify consumers that the invalidation service they were using
+    // is no longer available.
+    SetInvalidationService(nullptr);
+  }
+}
+
+invalidation::TiclInvalidationService*
+AffiliatedInvalidationServiceProviderImpl::
+    GetDeviceInvalidationServiceForTest() const {
+  return device_invalidation_service_.get();
+}
+
+void AffiliatedInvalidationServiceProviderImpl::OnInvalidationServiceConnected(
+    invalidation::InvalidationService* invalidation_service) {
+  DCHECK(!is_shut_down_);
+
+  if (consumer_count_ == 0) {
+    // If there are no consumers, no invalidation service is required.
+    return;
+  }
+
+  if (!device_invalidation_service_) {
+    // The lack of a device-global invalidation service implies that another
+    // connected invalidation service is being made available to consumers
+    // already. There is no need to switch from that to the service which just
+    // connected.
+    return;
+  }
+
+  if (invalidation_service != device_invalidation_service_.get()) {
+    // If an invalidation service other than the device-global one connected,
+    // destroy the device-global service.
+    invalidation_service_ = nullptr;
+    DestroyDeviceInvalidationService();
+  }
+
+  // Make the invalidation service that just connected available to consumers.
+  SetInvalidationService(invalidation_service);
+}
+
+void
+AffiliatedInvalidationServiceProviderImpl::OnInvalidationServiceDisconnected(
+    invalidation::InvalidationService* invalidation_service) {
+  DCHECK(!is_shut_down_);
+
+  if (invalidation_service != invalidation_service_) {
+    // If the invalidation service which disconnected was not being made
+    // available to consumers, return.
+    return;
+  }
+
+  // The invalidation service which disconnected was being made available to
+  // consumers. Stop making it available.
+  DCHECK(consumer_count_);
+  invalidation_service_ = nullptr;
+
+  // Try to make another invalidation service available to consumers.
+  FindConnectedInvalidationService();
+
+  // If no other connected invalidation service was found, explicitly notify
+  // consumers that the invalidation service they were using is no longer
+  // available.
+  if (!invalidation_service_)
+    SetInvalidationService(nullptr);
+}
+
+void
+AffiliatedInvalidationServiceProviderImpl::FindConnectedInvalidationService() {
+  DCHECK(!invalidation_service_);
+  DCHECK(consumer_count_);
+  DCHECK(!is_shut_down_);
+
+  for (ScopedVector<InvalidationServiceObserver>::const_iterator it =
+           profile_invalidation_service_observers_.begin();
+           it != profile_invalidation_service_observers_.end(); ++it) {
+    if ((*it)->IsServiceConnected()) {
+      // If a connected invalidation service belonging to an affiliated
+      // logged-in user is found, make it available to consumers.
+      DestroyDeviceInvalidationService();
+      SetInvalidationService((*it)->GetInvalidationService());
+      return;
+    }
+  }
+
+  if (!device_invalidation_service_) {
+    // If no other connected invalidation service was found and no device-global
+    // invalidation service exists, create one.
+    device_invalidation_service_.reset(
+        new invalidation::TiclInvalidationService(
+            GetUserAgent(),
+            scoped_ptr<IdentityProvider>(new chromeos::DeviceIdentityProvider(
+                chromeos::DeviceOAuth2TokenServiceFactory::Get())),
+            scoped_ptr<invalidation::TiclSettingsProvider>(
+                new TiclDeviceSettingsProvider),
+            g_browser_process->gcm_driver(),
+            g_browser_process->system_request_context()));
+    device_invalidation_service_->Init(
+        scoped_ptr<syncer::InvalidationStateTracker>(
+            new invalidation::InvalidatorStorage(
+                    g_browser_process->local_state())));
+    device_invalidation_service_observer_.reset(
+        new InvalidationServiceObserver(
+                this,
+                device_invalidation_service_.get()));
+  }
+
+  if (device_invalidation_service_observer_->IsServiceConnected()) {
+    // If the device-global invalidation service is connected already, make it
+    // available to consumers immediately. Otherwise, the invalidation service
+    // will be made available to clients when it successfully connects.
+    OnInvalidationServiceConnected(device_invalidation_service_.get());
+  }
+}
+
+void AffiliatedInvalidationServiceProviderImpl::SetInvalidationService(
+    invalidation::InvalidationService* invalidation_service) {
+  DCHECK(!invalidation_service_);
+  invalidation_service_ = invalidation_service;
+  FOR_EACH_OBSERVER(Consumer,
+                    consumers_,
+                    OnInvalidationServiceSet(invalidation_service_));
+}
+
+void
+AffiliatedInvalidationServiceProviderImpl::DestroyDeviceInvalidationService() {
+  device_invalidation_service_observer_.reset();
+  device_invalidation_service_.reset();
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.h b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.h
new file mode 100644
index 0000000..1ab8216b
--- /dev/null
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.h
@@ -0,0 +1,98 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace invalidation {
+class InvalidationService;
+class TiclInvalidationService;
+}
+
+namespace policy {
+
+class AffiliatedInvalidationServiceProviderImpl
+    : public AffiliatedInvalidationServiceProvider,
+      public content::NotificationObserver {
+ public:
+  AffiliatedInvalidationServiceProviderImpl();
+  ~AffiliatedInvalidationServiceProviderImpl() override;
+
+  // content::NotificationObserver:
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
+  // AffiliatedInvalidationServiceProvider:
+  void RegisterConsumer(Consumer* consumer) override;
+  void UnregisterConsumer(Consumer* consumer) override;
+  void Shutdown() override;
+
+  invalidation::TiclInvalidationService*
+      GetDeviceInvalidationServiceForTest() const;
+
+ private:
+  // Helper that monitors the status of a single |InvalidationService|.
+  class InvalidationServiceObserver;
+
+  // Status updates received from |InvalidationServiceObserver|s.
+  void OnInvalidationServiceConnected(
+      invalidation::InvalidationService* invalidation_service);
+  void OnInvalidationServiceDisconnected(
+      invalidation::InvalidationService* invalidation_service);
+
+  // Checks whether a connected |InvalidationService| affiliated with the
+  // device's enrollment domain is available. If so, notifies the consumers.
+  // Otherwise, consumers will be notified once such an invalidation service
+  // becomes available.
+  // Further ensures that a device-global invalidation service is running iff
+  // there is no other connected service available for use and there is at least
+  // one registered consumer.
+  void FindConnectedInvalidationService();
+
+  // Choose |invalidation_service| as the shared invalidation service and notify
+  // consumers.
+  void SetInvalidationService(
+      invalidation::InvalidationService* invalidation_service);
+
+  // Destroy the device-global invalidation service, if any.
+  void DestroyDeviceInvalidationService();
+
+  content::NotificationRegistrar registrar_;
+
+  // Device-global invalidation service.
+  scoped_ptr<invalidation::TiclInvalidationService>
+      device_invalidation_service_;
+
+  // State observer for the device-global invalidation service.
+  scoped_ptr<InvalidationServiceObserver> device_invalidation_service_observer_;
+
+  // State observers for logged-in users' invalidation services.
+  ScopedVector<InvalidationServiceObserver>
+      profile_invalidation_service_observers_;
+
+  // The invalidation service currently used by consumers. nullptr if there are
+  // no registered consumers or no connected invalidation service is available
+  // for use.
+  invalidation::InvalidationService* invalidation_service_;
+
+  ObserverList<Consumer, true> consumers_;
+  int consumer_count_;
+
+  bool is_shut_down_;
+
+  DISALLOW_COPY_AND_ASSIGN(AffiliatedInvalidationServiceProviderImpl);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_IMPL_H_
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
similarity index 87%
rename from chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc
rename to chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
index c0798064..370d4a7 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.h"
 
 #include <string>
 
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -68,9 +68,9 @@
   DISALLOW_COPY_AND_ASSIGN(MockConsumer);
 };
 
-class AffiliatedInvalidationServiceProviderTest : public testing::Test {
+class AffiliatedInvalidationServiceProviderImplTest : public testing::Test {
  public:
-  AffiliatedInvalidationServiceProviderTest();
+  AffiliatedInvalidationServiceProviderImplTest();
 
   // testing::Test:
   virtual void SetUp() override;
@@ -105,14 +105,14 @@
       bool create);
 
  protected:
-  scoped_ptr<AffiliatedInvalidationServiceProvider> provider_;
+  scoped_ptr<AffiliatedInvalidationServiceProviderImpl> provider_;
   StrictMock<MockConsumer> consumer_;
   invalidation::TiclInvalidationService* device_invalidation_service_;
   invalidation::FakeInvalidationService* profile_invalidation_service_;
 
  private:
   content::TestBrowserThreadBundle thread_bundle_;
-  chromeos::FakeUserManager* fake_user_manager_;
+  chromeos::FakeChromeUserManager* fake_user_manager_;
   chromeos::ScopedUserManagerEnabler user_manager_enabler_;
   ScopedStubEnterpriseInstallAttributes install_attributes_;
   scoped_ptr<chromeos::ScopedTestDeviceSettingsService>
@@ -127,11 +127,11 @@
 MockConsumer::~MockConsumer() {
 }
 
-AffiliatedInvalidationServiceProviderTest::
-AffiliatedInvalidationServiceProviderTest()
+AffiliatedInvalidationServiceProviderImplTest::
+AffiliatedInvalidationServiceProviderImplTest()
     : device_invalidation_service_(nullptr),
       profile_invalidation_service_(nullptr),
-      fake_user_manager_(new chromeos::FakeUserManager),
+      fake_user_manager_(new chromeos::FakeChromeUserManager),
       user_manager_enabler_(fake_user_manager_),
       install_attributes_("example.com",
                           "user@example.com",
@@ -140,7 +140,7 @@
       profile_manager_(TestingBrowserProcess::GetGlobal()) {
 }
 
-void AffiliatedInvalidationServiceProviderTest::SetUp() {
+void AffiliatedInvalidationServiceProviderImplTest::SetUp() {
   chromeos::SystemSaltGetter::Initialize();
   chromeos::DBusThreadManager::Initialize();
   ASSERT_TRUE(profile_manager_.SetUp());
@@ -153,10 +153,10 @@
   invalidation::ProfileInvalidationProviderFactory::GetInstance()->
       RegisterTestingFactory(BuildProfileInvalidationProvider);
 
-  provider_.reset(new AffiliatedInvalidationServiceProvider);
+  provider_.reset(new AffiliatedInvalidationServiceProviderImpl);
 }
 
-void AffiliatedInvalidationServiceProviderTest::TearDown() {
+void AffiliatedInvalidationServiceProviderImplTest::TearDown() {
   provider_->Shutdown();
   provider_.reset();
 
@@ -167,7 +167,7 @@
   chromeos::SystemSaltGetter::Shutdown();
 }
 
-Profile* AffiliatedInvalidationServiceProviderTest::LogInAndReturnProfile(
+Profile* AffiliatedInvalidationServiceProviderImplTest::LogInAndReturnProfile(
     const std::string& user_id) {
   fake_user_manager_->AddUser(user_id);
   Profile* profile = profile_manager_.CreateTestingProfile(user_id);
@@ -178,7 +178,7 @@
   return profile;
 }
 
-void AffiliatedInvalidationServiceProviderTest::
+void AffiliatedInvalidationServiceProviderImplTest::
     LogInAsAffiliatedUserAndConnectInvalidationService() {
   Mock::VerifyAndClearExpectations(&consumer_);
 
@@ -209,7 +209,7 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-void AffiliatedInvalidationServiceProviderTest::
+void AffiliatedInvalidationServiceProviderImplTest::
     LogInAsUnaffiliatedUserAndConnectInvalidationService() {
   Mock::VerifyAndClearExpectations(&consumer_);
 
@@ -236,7 +236,7 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-void AffiliatedInvalidationServiceProviderTest::
+void AffiliatedInvalidationServiceProviderImplTest::
     ConnectDeviceGlobalInvalidationService() {
   Mock::VerifyAndClearExpectations(&consumer_);
 
@@ -255,7 +255,7 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-void AffiliatedInvalidationServiceProviderTest::
+void AffiliatedInvalidationServiceProviderImplTest::
     DisconnectPerProfileInvalidationService() {
   Mock::VerifyAndClearExpectations(&consumer_);
 
@@ -274,7 +274,7 @@
 }
 
 invalidation::FakeInvalidationService*
-AffiliatedInvalidationServiceProviderTest::GetProfileInvalidationService(
+AffiliatedInvalidationServiceProviderImplTest::GetProfileInvalidationService(
     Profile* profile, bool create) {
   invalidation::ProfileInvalidationProvider* invalidation_provider =
       static_cast<invalidation::ProfileInvalidationProvider*>(
@@ -286,10 +286,11 @@
       invalidation_provider->GetInvalidationService());
 }
 
-// No consumers are registered with the AffiliatedInvalidationServiceProvider.
-// Verifies that no device-global invalidation service is created, whether an
-// affiliated user is logged in or not.
-TEST_F(AffiliatedInvalidationServiceProviderTest, NoConsumers) {
+// No consumers are registered with the
+// AffiliatedInvalidationServiceProviderImpl. Verifies that no device-global
+// invalidation service is created, whether an affiliated user is logged in or
+// not.
+TEST_F(AffiliatedInvalidationServiceProviderImplTest, NoConsumers) {
   // Verify that no device-global invalidation service has been created.
   EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
 
@@ -300,12 +301,12 @@
   EXPECT_FALSE(provider_->GetDeviceInvalidationServiceForTest());
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider.
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
 // Verifies that when no per-profile invalidation service belonging to an
 // affiliated user is available, a device-global invalidation service is
 // created. Further verifies that when the device-global invalidation service
 // connects, it is made available to the consumer.
-TEST_F(AffiliatedInvalidationServiceProviderTest,
+TEST_F(AffiliatedInvalidationServiceProviderImplTest,
        UseDeviceInvalidationService) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
@@ -330,10 +331,10 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider.
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
 // Verifies that when a per-profile invalidation service belonging to an
 // affiliated user connects, it is made available to the consumer.
-TEST_F(AffiliatedInvalidationServiceProviderTest,
+TEST_F(AffiliatedInvalidationServiceProviderImplTest,
        UseAffiliatedProfileInvalidationService) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
@@ -358,10 +359,10 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider.
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
 // Verifies that when a per-profile invalidation service belonging to an
 // unaffiliated user connects, it is ignored.
-TEST_F(AffiliatedInvalidationServiceProviderTest,
+TEST_F(AffiliatedInvalidationServiceProviderImplTest,
        DoNotUseUnaffiliatedProfileInvalidationService) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
@@ -381,12 +382,12 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
-// device-global invalidation service exists, is connected and is made available
-// to the consumer. Verifies that when a per-profile invalidation service
-// belonging to an affiliated user connects, it is made available to the
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
+// A device-global invalidation service exists, is connected and is made
+// available to the consumer. Verifies that when a per-profile invalidation
+// service belonging to an affiliated user connects, it is made available to the
 // consumer instead and the device-global invalidation service is destroyed.
-TEST_F(AffiliatedInvalidationServiceProviderTest,
+TEST_F(AffiliatedInvalidationServiceProviderImplTest,
        SwitchToAffiliatedProfileInvalidationService) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
@@ -407,13 +408,13 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
-// device-global invalidation service exists, is connected and is made available
-// to the consumer. Verifies that when a per-profile invalidation service
-// belonging to an unaffiliated user connects, it is ignored and the
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
+// A device-global invalidation service exists, is connected and is made
+// available to the consumer. Verifies that when a per-profile invalidation
+// service belonging to an unaffiliated user connects, it is ignored and the
 // device-global invalidation service continues to be made available to the
 // consumer.
-TEST_F(AffiliatedInvalidationServiceProviderTest,
+TEST_F(AffiliatedInvalidationServiceProviderImplTest,
        DoNotSwitchToUnaffiliatedProfileInvalidationService) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
@@ -434,13 +435,13 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
-// per-profile invalidation service belonging to an affiliated user exists, is
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
+// A per-profile invalidation service belonging to an affiliated user exists, is
 // connected and is made available to the consumer. Verifies that when the
 // per-profile invalidation service disconnects, a device-global invalidation
 // service is created. Further verifies that when the device-global invalidation
 // service connects, it is made available to the consumer.
-TEST_F(AffiliatedInvalidationServiceProviderTest,
+TEST_F(AffiliatedInvalidationServiceProviderImplTest,
        SwitchToDeviceInvalidationService) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
@@ -469,14 +470,14 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
-// per-profile invalidation service belonging to a first affiliated user exists,
-// is connected and is made available to the consumer. A per-profile
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
+// A per-profile invalidation service belonging to a first affiliated user
+// exists, is connected and is made available to the consumer. A per-profile
 // invalidation service belonging to a second affiliated user also exists and is
 // connected. Verifies that when the per-profile invalidation service belonging
 // to the first user disconnects, the per-profile invalidation service belonging
 // to the second user is made available to the consumer instead.
-TEST_F(AffiliatedInvalidationServiceProviderTest,
+TEST_F(AffiliatedInvalidationServiceProviderImplTest,
        SwitchBetweenAffiliatedProfileInvalidationServices) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
@@ -529,15 +530,15 @@
   Mock::VerifyAndClearExpectations(&consumer_);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
-// device-global invalidation service exists, is connected and is made available
-// to the consumer. Verifies that when a second consumer registers, the
-// device-global invalidation service is made available to it as well. Further
-// verifies that when the first consumer unregisters, the device-global
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
+// A device-global invalidation service exists, is connected and is made
+// available to the consumer. Verifies that when a second consumer registers,
+// the device-global invalidation service is made available to it as well.
+// Further verifies that when the first consumer unregisters, the device-global
 // invalidation service is not destroyed and remains available to the second
 // consumer. Further verifies that when the second consumer also unregisters,
 // the device-global invalidation service is destroyed.
-TEST_F(AffiliatedInvalidationServiceProviderTest, MultipleConsumers) {
+TEST_F(AffiliatedInvalidationServiceProviderImplTest, MultipleConsumers) {
   // Register a first consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
   provider_->RegisterConsumer(&consumer_);
@@ -569,14 +570,15 @@
   Mock::VerifyAndClearExpectations(&second_consumer);
 }
 
-// A consumer is registered with the AffiliatedInvalidationServiceProvider. A
-// per-profile invalidation service belonging to a first affiliated user exists,
-// is connected and is made available to the consumer. Verifies that when the
-// provider is shut down, the consumer is informed that no invalidation service
-// is available for use anymore. Also verifies that no device-global
-// invalidation service is created and a per-profile invalidation service
-// belonging to a second affiliated user that subsequently connects is ignored.
-TEST_F(AffiliatedInvalidationServiceProviderTest, NoServiceAfterShutdown) {
+// A consumer is registered with the AffiliatedInvalidationServiceProviderImpl.
+// A per-profile invalidation service belonging to a first affiliated user
+// exists, is connected and is made available to the consumer. Verifies that
+// when the provider is shut down, the consumer is informed that no
+// invalidation service is available for use anymore. Also verifies that no
+// device-global invalidation service is created and a per-profile invalidation
+// service belonging to a second affiliated user that subsequently connects is
+// ignored.
+TEST_F(AffiliatedInvalidationServiceProviderImplTest, NoServiceAfterShutdown) {
   // Register a consumer. Verify that the consumer is not called back
   // immediately as no connected invalidation service exists yet.
   provider_->RegisterConsumer(&consumer_);
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index e1e1c656..07883e40 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -17,10 +17,11 @@
 #include "base/sequenced_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
 #include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.h"
 #include "chrome/browser/chromeos/policy/consumer_management_service.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
-#include "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
@@ -49,6 +50,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "policy/proto/device_management_backend.pb.h"
 
 using content::BrowserThread;
 
@@ -155,7 +157,7 @@
   ChromeBrowserPolicyConnector::Init(local_state, request_context);
 
   affiliated_invalidation_service_provider_.reset(
-      new AffiliatedInvalidationServiceProvider);
+      new AffiliatedInvalidationServiceProviderImpl);
 
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
@@ -185,6 +187,7 @@
           chromeos::DBusThreadManager::Get()->GetSessionManagerClient(),
           chromeos::DeviceSettingsService::Get(),
           chromeos::CrosSettings::Get(),
+          affiliated_invalidation_service_provider_.get(),
           GetBackgroundTaskRunner(),
           GetBackgroundTaskRunner(),
           GetBackgroundTaskRunner(),
@@ -192,8 +195,12 @@
               content::BrowserThread::IO),
           request_context));
   device_local_account_policy_service_->Connect(device_management_service());
-  device_cloud_policy_invalidator_.reset(new DeviceCloudPolicyInvalidator(
-      affiliated_invalidation_service_provider_.get()));
+  if (device_cloud_policy_manager_) {
+    device_cloud_policy_invalidator_.reset(new AffiliatedCloudPolicyInvalidator(
+        enterprise_management::DeviceRegisterRequest::DEVICE,
+        device_cloud_policy_manager_->core(),
+        affiliated_invalidation_service_provider_.get()));
+  }
 
   SetTimezoneIfPolicyAvailable();
 
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
index cb3ec6f..878eda22 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
@@ -27,7 +27,7 @@
 class AffiliatedInvalidationServiceProvider;
 class ConsumerManagementService;
 class DeviceCloudPolicyInitializer;
-class DeviceCloudPolicyInvalidator;
+class AffiliatedCloudPolicyInvalidator;
 class DeviceLocalAccountPolicyService;
 class DeviceManagementService;
 struct EnrollmentConfig;
@@ -160,7 +160,7 @@
   scoped_ptr<DeviceCloudPolicyInitializer> device_cloud_policy_initializer_;
   scoped_ptr<DeviceLocalAccountPolicyService>
       device_local_account_policy_service_;
-  scoped_ptr<DeviceCloudPolicyInvalidator> device_cloud_policy_invalidator_;
+  scoped_ptr<AffiliatedCloudPolicyInvalidator> device_cloud_policy_invalidator_;
 
   // This policy provider is used on Chrome OS to feed user policy into the
   // global PolicyService instance. This works by installing the cloud policy
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
index d076ae9b..29f5ede 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/chromeos/policy/device_local_account_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_provider.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
+#include "chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h"
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -140,6 +141,8 @@
   chromeos::CrosSettings cros_settings_;
   scoped_ptr<DeviceLocalAccountPolicyService>
       device_local_account_policy_service_;
+  FakeAffiliatedInvalidationServiceProvider
+      affiliated_invalidation_service_provider_;
   net::TestURLFetcherFactory url_fetcher_factory_;
 
   scoped_ptr<DeviceLocalAccountPolicyProvider>
@@ -177,16 +180,20 @@
 
 void CloudExternalDataPolicyObserverTest::SetUp() {
   chromeos::DeviceSettingsTestBase::SetUp();
+
   ASSERT_TRUE(profile_manager_.SetUp());
+
   device_local_account_policy_service_.reset(
-      new DeviceLocalAccountPolicyService(&device_settings_test_helper_,
-                                          &device_settings_service_,
-                                          &cros_settings_,
-                                          base::MessageLoopProxy::current(),
-                                          base::MessageLoopProxy::current(),
-                                          base::MessageLoopProxy::current(),
-                                          base::MessageLoopProxy::current(),
-                                          NULL));
+      new DeviceLocalAccountPolicyService(
+          &device_settings_test_helper_,
+          &device_settings_service_,
+          &cros_settings_,
+          &affiliated_invalidation_service_provider_,
+          base::MessageLoopProxy::current(),
+          base::MessageLoopProxy::current(),
+          base::MessageLoopProxy::current(),
+          base::MessageLoopProxy::current(),
+          nullptr));
   url_fetcher_factory_.set_remove_fetcher_on_delete(true);
 
   EXPECT_CALL(user_policy_provider_, IsInitializationComplete(_))
diff --git a/chrome/browser/chromeos/policy/consumer_enrollment_handler_factory_unittest.cc b/chrome/browser/chromeos/policy/consumer_enrollment_handler_factory_unittest.cc
index 5f8b595c..8e56c19 100644
--- a/chrome/browser/chromeos/policy/consumer_enrollment_handler_factory_unittest.cc
+++ b/chrome/browser/chromeos/policy/consumer_enrollment_handler_factory_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/consumer_management_service.h"
@@ -27,10 +27,10 @@
  public:
   ConsumerEnrollmentHandlerFactoryTest()
       : fake_service_(new FakeConsumerManagementService()),
-        fake_user_manager_(new chromeos::FakeUserManager()),
+        fake_user_manager_(new chromeos::FakeChromeUserManager()),
         scoped_user_manager_enabler_(fake_user_manager_),
-        testing_profile_manager_(new TestingProfileManager(
-            TestingBrowserProcess::GetGlobal())) {
+        testing_profile_manager_(
+            new TestingProfileManager(TestingBrowserProcess::GetGlobal())) {
     // Set up FakeConsumerManagementService.
     fake_service_->SetStatusAndStage(
         ConsumerManagementService::STATUS_ENROLLING,
@@ -42,7 +42,7 @@
     connector->SetConsumerManagementServiceForTesting(
         make_scoped_ptr(fake_service_));
 
-    // Set up FakeUserManager.
+    // Set up FakeChromeUserManager.
     fake_user_manager_->AddUser(kTestOwner);
     fake_user_manager_->AddUser(kTestUser);
     fake_user_manager_->set_owner_email(kTestOwner);
@@ -53,7 +53,7 @@
   }
 
   FakeConsumerManagementService* fake_service_;
-  chromeos::FakeUserManager* fake_user_manager_;
+  chromeos::FakeChromeUserManager* fake_user_manager_;
   chromeos::ScopedUserManagerEnabler scoped_user_manager_enabler_;
   scoped_ptr<TestingProfileManager> testing_profile_manager_;
 };
diff --git a/chrome/browser/chromeos/policy/consumer_enrollment_handler_unittest.cc b/chrome/browser/chromeos/policy/consumer_enrollment_handler_unittest.cc
index 4c518c0..15ecd7e3 100644
--- a/chrome/browser/chromeos/policy/consumer_enrollment_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/consumer_enrollment_handler_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/run_loop.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/consumer_management_service.h"
@@ -40,10 +40,10 @@
   ConsumerEnrollmentHandlerTest()
       : fake_service_(new FakeConsumerManagementService()),
         fake_initializer_(new FakeDeviceCloudPolicyInitializer()),
-        fake_user_manager_(new chromeos::FakeUserManager()),
+        fake_user_manager_(new chromeos::FakeChromeUserManager()),
         scoped_user_manager_enabler_(fake_user_manager_),
-        testing_profile_manager_(new TestingProfileManager(
-            TestingBrowserProcess::GetGlobal())) {
+        testing_profile_manager_(
+            new TestingProfileManager(TestingBrowserProcess::GetGlobal())) {
     // Set up FakeConsumerManagementService.
     fake_service_->SetStatusAndStage(
         ConsumerManagementService::STATUS_ENROLLING,
@@ -57,7 +57,7 @@
     connector->SetDeviceCloudPolicyInitializerForTesting(
         make_scoped_ptr(fake_initializer_));
 
-    // Set up FakeUserManager.
+    // Set up FakeChromeUserManager.
     fake_user_manager_->AddUser(kTestOwner);
     fake_user_manager_->AddUser(kTestUser);
     fake_user_manager_->set_owner_email(kTestOwner);
@@ -92,7 +92,7 @@
   content::TestBrowserThreadBundle thread_bundle;
   FakeConsumerManagementService* fake_service_;
   FakeDeviceCloudPolicyInitializer* fake_initializer_;
-  chromeos::FakeUserManager* fake_user_manager_;
+  chromeos::FakeChromeUserManager* fake_user_manager_;
   chromeos::ScopedUserManagerEnabler scoped_user_manager_enabler_;
   scoped_ptr<TestingProfileManager> testing_profile_manager_;
   Profile* profile_;
diff --git a/chrome/browser/chromeos/policy/consumer_management_notifier_factory_unittest.cc b/chrome/browser/chromeos/policy/consumer_management_notifier_factory_unittest.cc
index d29be20..ca78a43d 100644
--- a/chrome/browser/chromeos/policy/consumer_management_notifier_factory_unittest.cc
+++ b/chrome/browser/chromeos/policy/consumer_management_notifier_factory_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/consumer_management_service.h"
@@ -27,10 +27,10 @@
  public:
   ConsumerManagementNotifierFactoryTest()
       : fake_service_(new FakeConsumerManagementService()),
-        fake_user_manager_(new chromeos::FakeUserManager()),
+        fake_user_manager_(new chromeos::FakeChromeUserManager()),
         scoped_user_manager_enabler_(fake_user_manager_),
-        testing_profile_manager_(new TestingProfileManager(
-            TestingBrowserProcess::GetGlobal())) {
+        testing_profile_manager_(
+            new TestingProfileManager(TestingBrowserProcess::GetGlobal())) {
     // Set up FakeConsumerManagementService.
     fake_service_->SetStatusAndStage(
         ConsumerManagementService::STATUS_UNENROLLED,
@@ -42,7 +42,7 @@
     connector->SetConsumerManagementServiceForTesting(
         make_scoped_ptr(fake_service_));
 
-    // Set up FakeUserManager.
+    // Set up FakeChromeUserManager.
     fake_user_manager_->AddUser(kTestOwner);
     fake_user_manager_->AddUser(kTestUser);
     fake_user_manager_->set_owner_email(kTestOwner);
@@ -53,7 +53,7 @@
   }
 
   FakeConsumerManagementService* fake_service_;
-  chromeos::FakeUserManager* fake_user_manager_;
+  chromeos::FakeChromeUserManager* fake_user_manager_;
   chromeos::ScopedUserManagerEnabler scoped_user_manager_enabler_;
   scoped_ptr<TestingProfileManager> testing_profile_manager_;
 };
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator.cc b/chrome/browser/chromeos/policy/device_cloud_policy_invalidator.cc
deleted file mode 100644
index e41442e0..0000000
--- a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator.cc
+++ /dev/null
@@ -1,67 +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.
-
-#include "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h"
-
-#include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/time/clock.h"
-#include "base/time/default_clock.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_process_platform_part_chromeos.h"
-#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
-#include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
-#include "policy/proto/device_management_backend.pb.h"
-
-namespace policy {
-
-DeviceCloudPolicyInvalidator::DeviceCloudPolicyInvalidator(
-    AffiliatedInvalidationServiceProvider* invalidation_service_provider)
-    : invalidation_service_provider_(invalidation_service_provider),
-      highest_handled_invalidation_version_(0) {
-  invalidation_service_provider_->RegisterConsumer(this);
-}
-
-DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() {
-  DestroyInvalidator();
-  invalidation_service_provider_->UnregisterConsumer(this);
-}
-
-void DeviceCloudPolicyInvalidator::OnInvalidationServiceSet(
-    invalidation::InvalidationService* invalidation_service) {
-  DestroyInvalidator();
-  if (invalidation_service)
-    CreateInvalidator(invalidation_service);
-}
-
-CloudPolicyInvalidator*
-DeviceCloudPolicyInvalidator::GetInvalidatorForTest() const {
-  return invalidator_.get();
-}
-
-void DeviceCloudPolicyInvalidator::CreateInvalidator(
-    invalidation::InvalidationService* invalidation_service) {
-  DCHECK(!invalidator_);
-  invalidator_.reset(new CloudPolicyInvalidator(
-      enterprise_management::DeviceRegisterRequest::DEVICE,
-      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
-          GetDeviceCloudPolicyManager()->core(),
-      base::MessageLoopProxy::current(),
-      scoped_ptr<base::Clock>(new base::DefaultClock()),
-      highest_handled_invalidation_version_));
-  invalidator_->Initialize(invalidation_service);
-}
-
-void DeviceCloudPolicyInvalidator::DestroyInvalidator() {
-  if (!invalidator_)
-    return;
-
-  highest_handled_invalidation_version_ =
-      invalidator_->highest_handled_invalidation_version();
-  invalidator_->Shutdown();
-  invalidator_.reset();
-}
-
-}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h b/chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h
deleted file mode 100644
index e767514..0000000
--- a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h
+++ /dev/null
@@ -1,62 +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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_POLICY_INVALIDATOR_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_POLICY_INVALIDATOR_H_
-
-#include "base/basictypes.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
-
-namespace invalidation {
-class InvalidationService;
-}
-
-namespace policy {
-
-class CloudPolicyInvalidator;
-
-// This class manages the lifetime of a device-global |CloudPolicyInvalidator|
-// that handles device policy invalidations. It relies on an
-// |AffiliatedInvalidationServiceProvider| to provide it with access to a shared
-// |InvalidationService| to back the |CloudPolicyInvalidator|. Whenever the
-// shared |InvalidationService| changes, the |CloudPolicyInvalidator| destroyed
-// and re-created.
-class DeviceCloudPolicyInvalidator
-    : public AffiliatedInvalidationServiceProvider::Consumer {
- public:
-  explicit DeviceCloudPolicyInvalidator(
-      AffiliatedInvalidationServiceProvider* invalidation_service_provider);
-  ~DeviceCloudPolicyInvalidator() override;
-
-  // AffiliatedInvalidationServiceProvider::Consumer:
-  void OnInvalidationServiceSet(
-      invalidation::InvalidationService* invalidation_service) override;
-
-  CloudPolicyInvalidator* GetInvalidatorForTest() const;
-
- private:
-  // Create a |CloudPolicyInvalidator| backed by the |invalidation_service|.
-  void CreateInvalidator(
-      invalidation::InvalidationService* invalidation_service);
-
-  // Destroy the current |CloudPolicyInvalidator|, if any.
-  void DestroyInvalidator();
-
-  AffiliatedInvalidationServiceProvider* invalidation_service_provider_;
-
-  // The highest invalidation version that was handled already.
-  int64 highest_handled_invalidation_version_;
-
-  // The current |CloudPolicyInvalidator|. nullptr if no connected invalidation
-  // service is available.
-  scoped_ptr<CloudPolicyInvalidator> invalidator_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeviceCloudPolicyInvalidator);
-};
-
-}  // namespace policy
-
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_CLOUD_POLICY_INVALIDATOR_H_
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_invalidator_unittest.cc
deleted file mode 100644
index 3c80871..0000000
--- a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator_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.
-
-#include "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h"
-
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
-#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
-#include "chrome/browser/chromeos/policy/device_policy_builder.h"
-#include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
-#include "chrome/browser/chromeos/settings/device_settings_service.h"
-#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
-#include "chrome/browser/invalidation/fake_invalidation_service.h"
-#include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/cryptohome/system_salt_getter.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "components/ownership/mock_owner_key_util.h"
-#include "components/policy/core/common/cloud/cloud_policy_constants.h"
-#include "components/policy/core/common/cloud/cloud_policy_core.h"
-#include "components/policy/core/common/cloud/cloud_policy_store.h"
-#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_test_util.h"
-#include "policy/proto/device_management_backend.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace policy {
-
-class DeviceCloudPolicyInvalidatorTest : public testing::Test {
- public:
-  DeviceCloudPolicyInvalidatorTest();
-  ~DeviceCloudPolicyInvalidatorTest() override;
-
-  // testing::Test:
-  void SetUp() override;
-  void TearDown() override;
-
- protected:
-  DevicePolicyBuilder device_policy_;
-
- private:
-  content::TestBrowserThreadBundle thread_bundle_;
-  scoped_refptr<net::URLRequestContextGetter> system_request_context_;
-  ScopedStubEnterpriseInstallAttributes install_attributes_;
-  scoped_ptr<chromeos::ScopedTestDeviceSettingsService>
-      test_device_settings_service_;
-  scoped_ptr<chromeos::ScopedTestCrosSettings> test_cros_settings_;
-  chromeos::DeviceSettingsTestHelper device_settings_test_helper_;
-  TestingProfileManager profile_manager_;
-};
-
-DeviceCloudPolicyInvalidatorTest::DeviceCloudPolicyInvalidatorTest()
-    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-      system_request_context_(new net::TestURLRequestContextGetter(
-          base::MessageLoopProxy::current())),
-      install_attributes_("example.com",
-                          "user@example.com",
-                          "device_id",
-                          DEVICE_MODE_ENTERPRISE),
-      profile_manager_(TestingBrowserProcess::GetGlobal()) {
-}
-
-DeviceCloudPolicyInvalidatorTest::~DeviceCloudPolicyInvalidatorTest() {
-}
-
-void DeviceCloudPolicyInvalidatorTest::SetUp() {
-  chromeos::SystemSaltGetter::Initialize();
-  chromeos::DBusThreadManager::Initialize();
-  TestingBrowserProcess::GetGlobal()->SetSystemRequestContext(
-      system_request_context_.get());
-  ASSERT_TRUE(profile_manager_.SetUp());
-
-  test_device_settings_service_.reset(new
-      chromeos::ScopedTestDeviceSettingsService);
-  test_cros_settings_.reset(new chromeos::ScopedTestCrosSettings);
-  chromeos::DeviceOAuth2TokenServiceFactory::Initialize();
-
-  scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util(
-      new ownership::MockOwnerKeyUtil);
-  owner_key_util->SetPublicKeyFromPrivateKey(
-      *device_policy_.GetSigningKey());
-  chromeos::DeviceSettingsService::Get()->SetSessionManager(
-      &device_settings_test_helper_,
-      owner_key_util);
-
-  device_policy_.policy_data().set_invalidation_source(123);
-  device_policy_.policy_data().set_invalidation_name("invalidation");
-  device_policy_.Build();
-  device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
-  device_settings_test_helper_.Flush();
-
-  scoped_ptr<MockCloudPolicyClient> policy_client(new MockCloudPolicyClient);
-  EXPECT_CALL(*policy_client, SetupRegistration("token", "device-id"));
-  CloudPolicyCore* core = TestingBrowserProcess::GetGlobal()->platform_part()->
-      browser_policy_connector_chromeos()->GetDeviceCloudPolicyManager()->
-          core();
-  core->Connect(policy_client.Pass());
-  core->StartRefreshScheduler();
-}
-
-void DeviceCloudPolicyInvalidatorTest::TearDown() {
-  chromeos::DeviceSettingsService::Get()->UnsetSessionManager();
-  TestingBrowserProcess::GetGlobal()->SetBrowserPolicyConnector(nullptr);
-  chromeos::DeviceOAuth2TokenServiceFactory::Shutdown();
-  chromeos::DBusThreadManager::Shutdown();
-  chromeos::SystemSaltGetter::Shutdown();
-}
-
-// Verifies that an invalidator is created/destroyed as an invalidation service
-// becomes available/unavailable. Also verifies that the highest handled
-// invalidation version is preserved when switching invalidation services.
-TEST_F(DeviceCloudPolicyInvalidatorTest, CreateUseDestroy) {
-  CloudPolicyStore* store = static_cast<CloudPolicyStore*>(
-      TestingBrowserProcess::GetGlobal()->platform_part()->
-          browser_policy_connector_chromeos()->GetDeviceCloudPolicyManager()->
-              device_store());
-  ASSERT_TRUE(store);
-
-  AffiliatedInvalidationServiceProvider provider;
-  DeviceCloudPolicyInvalidator device_policy_invalidator(&provider);
-
-  // Verify that no invalidator exists initially.
-  EXPECT_FALSE(device_policy_invalidator.GetInvalidatorForTest());
-
-  // Make a first invalidation service available.
-  invalidation::FakeInvalidationService invalidation_service_1;
-  device_policy_invalidator.OnInvalidationServiceSet(&invalidation_service_1);
-
-  // Verify that an invalidator backed by the first invalidation service has
-  // been created and its highest handled invalidation version starts out as 0.
-  CloudPolicyInvalidator* invalidator =
-      device_policy_invalidator.GetInvalidatorForTest();
-  ASSERT_TRUE(invalidator);
-  EXPECT_EQ(0, invalidator->highest_handled_invalidation_version());
-  EXPECT_EQ(&invalidation_service_1,
-            invalidator->invalidation_service_for_test());
-
-  // Handle an invalidation with version 1. Verify that the invalidator's
-  // highest handled invalidation version is updated accordingly.
-  store->Store(device_policy_.policy(), 1);
-  invalidator->OnStoreLoaded(store);
-  EXPECT_EQ(1, invalidator->highest_handled_invalidation_version());
-
-  // Make the first invalidation service unavailable. Verify that the
-  // invalidator is destroyed.
-  device_policy_invalidator.OnInvalidationServiceSet(nullptr);
-  EXPECT_FALSE(device_policy_invalidator.GetInvalidatorForTest());
-
-  // Make a second invalidation service available.
-  invalidation::FakeInvalidationService invalidation_service_2;
-  device_policy_invalidator.OnInvalidationServiceSet(&invalidation_service_2);
-
-  // Verify that an invalidator backed by the second invalidation service has
-  // been created and its highest handled invalidation version starts out as 1.
-  invalidator = device_policy_invalidator.GetInvalidatorForTest();
-  ASSERT_TRUE(invalidator);
-  EXPECT_EQ(1, invalidator->highest_handled_invalidation_version());
-  EXPECT_EQ(&invalidation_service_2,
-            invalidator->invalidation_service_for_test());
-
-  // Make the first invalidation service available again. This implies that the
-  // second invalidation service is no longer available.
-  device_policy_invalidator.OnInvalidationServiceSet(&invalidation_service_1);
-
-  // Verify that the invalidator backed by the second invalidation service was
-  // destroyed and an invalidation backed by the first invalidation service has
-  // been created instead. Also verify that its highest handled invalidation
-  // version starts out as 1.
-  invalidator = device_policy_invalidator.GetInvalidatorForTest();
-  ASSERT_TRUE(invalidator);
-  EXPECT_EQ(1, invalidator->highest_handled_invalidation_version());
-  EXPECT_EQ(&invalidation_service_1,
-            invalidator->invalidation_service_for_test());
-
-  provider.Shutdown();
-  device_policy_invalidator.OnInvalidationServiceSet(nullptr);
-}
-
-}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index 150095c..f93d637 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -18,7 +18,9 @@
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
@@ -120,8 +122,10 @@
     scoped_ptr<DeviceLocalAccountPolicyStore> store,
     scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager,
     const base::Closure& policy_update_callback,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : account_id_(account.account_id),
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    AffiliatedInvalidationServiceProvider* invalidation_service_provider)
+    : invalidation_service_provider_(invalidation_service_provider),
+      account_id_(account.account_id),
       user_id_(account.user_id),
       component_policy_cache_path_(component_policy_cache_path),
       store_(store.Pass()),
@@ -160,6 +164,10 @@
   store_->Load();
 }
 
+bool DeviceLocalAccountPolicyBroker::HasInvalidatorForTest() const {
+  return invalidator_;
+}
+
 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
     chromeos::DeviceSettingsService* device_settings_service,
     DeviceManagementService* device_management_service,
@@ -178,6 +186,10 @@
   external_data_manager_->Connect(request_context);
   core_.StartRefreshScheduler();
   UpdateRefreshDelay();
+  invalidator_.reset(new AffiliatedCloudPolicyInvalidator(
+      em::DeviceRegisterRequest::DEVICE,
+      &core_,
+      invalidation_service_provider_));
 }
 
 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
@@ -243,6 +255,7 @@
     chromeos::SessionManagerClient* session_manager_client,
     chromeos::DeviceSettingsService* device_settings_service,
     chromeos::CrosSettings* cros_settings,
+    AffiliatedInvalidationServiceProvider* invalidation_service_provider,
     scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
     scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
     scoped_refptr<base::SequencedTaskRunner>
@@ -252,6 +265,7 @@
     : session_manager_client_(session_manager_client),
       device_settings_service_(device_settings_service),
       cros_settings_(cros_settings),
+      invalidation_service_provider_(invalidation_service_provider),
       device_management_service_(nullptr),
       waiting_for_cros_settings_(false),
       orphan_extension_cache_deletion_state_(NOT_STARTED),
@@ -462,7 +476,8 @@
           base::Bind(&DeviceLocalAccountPolicyService::NotifyPolicyUpdated,
                      base::Unretained(this),
                      it->user_id),
-          base::MessageLoopProxy::current()));
+          base::ThreadTaskRunnerHandle::Get(),
+          invalidation_service_provider_));
     }
 
     // Fire up the cloud connection for fetching policy for the account from
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.h b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
index 3230a64e..de76639 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
@@ -41,6 +41,8 @@
 
 namespace policy {
 
+class AffiliatedCloudPolicyInvalidator;
+class AffiliatedInvalidationServiceProvider;
 struct DeviceLocalAccount;
 class DeviceLocalAccountExternalDataService;
 class DeviceLocalAccountPolicyStore;
@@ -52,6 +54,7 @@
     : public CloudPolicyStore::Observer,
       public ComponentCloudPolicyService::Delegate {
  public:
+  // |invalidation_service_provider| must outlive |this|.
   // |policy_update_callback| will be invoked to notify observers that the
   // policy for |account| has been updated.
   // |task_runner| is the runner for policy refresh tasks.
@@ -62,7 +65,8 @@
       scoped_refptr<DeviceLocalAccountExternalDataManager>
           external_data_manager,
       const base::Closure& policy_updated_callback,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      AffiliatedInvalidationServiceProvider* invalidation_service_provider);
   ~DeviceLocalAccountPolicyBroker() override;
 
   // Initialize the broker, loading its |store_|.
@@ -89,6 +93,8 @@
 
   SchemaRegistry* schema_registry() { return &schema_registry_; }
 
+  bool HasInvalidatorForTest() const;
+
   // Fire up the cloud connection for fetching policy for the account from the
   // cloud if this is an enterprise-managed device.
   void ConnectIfPossible(
@@ -115,6 +121,7 @@
       const scoped_refptr<net::URLRequestContextGetter>& request_context,
       CloudPolicyClient* client);
 
+  AffiliatedInvalidationServiceProvider* const invalidation_service_provider_;
   const std::string account_id_;
   const std::string user_id_;
   const base::FilePath component_policy_cache_path_;
@@ -127,6 +134,7 @@
   CloudPolicyCore core_;
   scoped_ptr<ComponentCloudPolicyService> component_policy_service_;
   base::Closure policy_update_callback_;
+  scoped_ptr<AffiliatedCloudPolicyInvalidator> invalidator_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountPolicyBroker);
 };
@@ -153,6 +161,7 @@
       chromeos::SessionManagerClient* session_manager_client,
       chromeos::DeviceSettingsService* device_settings_service,
       chromeos::CrosSettings* cros_settings,
+      AffiliatedInvalidationServiceProvider* invalidation_service_provider,
       scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
       scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
       scoped_refptr<base::SequencedTaskRunner>
@@ -227,6 +236,7 @@
   chromeos::SessionManagerClient* session_manager_client_;
   chromeos::DeviceSettingsService* device_settings_service_;
   chromeos::CrosSettings* cros_settings_;
+  AffiliatedInvalidationServiceProvider* invalidation_service_provider_;
 
   DeviceManagementService* device_management_service_;
 
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
index 155e2e3..1355846 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
@@ -22,6 +22,7 @@
 #include "base/test/test_simple_task_runner.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_provider.h"
+#include "chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h"
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -98,6 +99,8 @@
   chromeos::CrosSettings cros_settings_;
   scoped_refptr<base::TestSimpleTaskRunner> extension_cache_task_runner_;
   MockDeviceManagementService mock_device_management_service_;
+  FakeAffiliatedInvalidationServiceProvider
+      affiliated_invalidation_service_provider_;
   scoped_ptr<DeviceLocalAccountPolicyService> service_;
 
  private:
@@ -162,6 +165,7 @@
       &device_settings_test_helper_,
       &device_settings_service_,
       &cros_settings_,
+      &affiliated_invalidation_service_provider_,
       base::MessageLoopProxy::current(),
       extension_cache_task_runner_,
       base::MessageLoopProxy::current(),
@@ -231,6 +235,7 @@
   EXPECT_EQ(CloudPolicyStore::STATUS_OK, broker->core()->store()->status());
   EXPECT_FALSE(broker->core()->client());
   EXPECT_FALSE(broker->core()->store()->policy_map().empty());
+  EXPECT_FALSE(broker->HasInvalidatorForTest());
 }
 
 TEST_F(DeviceLocalAccountPolicyServiceTest, LoadNoPolicy) {
@@ -246,6 +251,7 @@
   EXPECT_EQ(CloudPolicyStore::STATUS_LOAD_ERROR,
             broker->core()->store()->status());
   EXPECT_TRUE(broker->core()->store()->policy_map().empty());
+  EXPECT_FALSE(broker->HasInvalidatorForTest());
   EXPECT_FALSE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
@@ -265,6 +271,7 @@
   EXPECT_EQ(CloudPolicyStore::STATUS_VALIDATION_ERROR,
             broker->core()->store()->status());
   EXPECT_TRUE(broker->core()->store()->policy_map().empty());
+  EXPECT_FALSE(broker->HasInvalidatorForTest());
   EXPECT_FALSE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
@@ -285,6 +292,7 @@
             broker->core()->store()->policy()->SerializeAsString());
   EXPECT_TRUE(expected_policy_map_.Equals(
       broker->core()->store()->policy_map()));
+  EXPECT_FALSE(broker->HasInvalidatorForTest());
   EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
@@ -311,6 +319,7 @@
             broker->core()->store()->status());
   EXPECT_EQ(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE,
             broker->core()->store()->validation_status());
+  EXPECT_FALSE(broker->HasInvalidatorForTest());
   EXPECT_FALSE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
@@ -339,6 +348,7 @@
             broker->core()->store()->policy()->SerializeAsString());
   EXPECT_TRUE(expected_policy_map_.Equals(
       broker->core()->store()->policy_map()));
+  EXPECT_FALSE(broker->HasInvalidatorForTest());
   EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
@@ -377,6 +387,7 @@
             broker->core()->store()->policy()->SerializeAsString());
   EXPECT_TRUE(expected_policy_map_.Equals(
       broker->core()->store()->policy_map()));
+  EXPECT_FALSE(broker->HasInvalidatorForTest());
   EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
@@ -411,7 +422,6 @@
   // This will be called twice, because the ComponentCloudPolicyService will
   // also become ready after flushing all the pending tasks.
   EXPECT_CALL(service_observer_, OnPolicyUpdated(account_1_user_id_)).Times(2);
-  broker->core()->client()->FetchPolicy();
   FlushDeviceSettings();
   Mock::VerifyAndClearExpectations(&service_observer_);
   Mock::VerifyAndClearExpectations(&mock_device_management_service_);
@@ -446,6 +456,7 @@
             broker->core()->store()->policy()->SerializeAsString());
   EXPECT_TRUE(expected_policy_map_.Equals(
       broker->core()->store()->policy_map()));
+  EXPECT_TRUE(broker->HasInvalidatorForTest());
   EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
@@ -485,6 +496,7 @@
             broker->core()->store()->status());
   EXPECT_TRUE(expected_policy_map_.Equals(
       broker->core()->store()->policy_map()));
+  EXPECT_TRUE(broker->HasInvalidatorForTest());
   EXPECT_TRUE(service_->IsPolicyAvailableForUser(account_1_user_id_));
 }
 
diff --git a/chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.cc b/chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.cc
new file mode 100644
index 0000000..0fe5740
--- /dev/null
+++ b/chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.cc
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h"
+
+namespace policy {
+
+FakeAffiliatedInvalidationServiceProvider::
+FakeAffiliatedInvalidationServiceProvider() {
+}
+
+void FakeAffiliatedInvalidationServiceProvider::RegisterConsumer(
+    Consumer* consumer) {
+}
+
+void FakeAffiliatedInvalidationServiceProvider::UnregisterConsumer(
+    Consumer* consumer) {
+}
+
+void FakeAffiliatedInvalidationServiceProvider::Shutdown() {
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h b/chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h
new file mode 100644
index 0000000..e184c3f
--- /dev/null
+++ b/chrome/browser/chromeos/policy/fake_affiliated_invalidation_service_provider.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 CHROME_BROWSER_CHROMEOS_POLICY_FAKE_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_FAKE_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_H_
+
+#include "chrome/browser/chromeos/policy/affiliated_invalidation_service_provider.h"
+#include "base/macros.h"
+
+namespace policy {
+
+class FakeAffiliatedInvalidationServiceProvider
+    : public AffiliatedInvalidationServiceProvider {
+ public:
+  FakeAffiliatedInvalidationServiceProvider();
+
+  // AffiliatedInvalidationServiceProvider:
+  void RegisterConsumer(Consumer* consumer) override;
+  void UnregisterConsumer(Consumer* consumer) override;
+  void Shutdown() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeAffiliatedInvalidationServiceProvider);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_FAKE_AFFILIATED_INVALIDATION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
index 5d75fb87..0b496e7 100644
--- a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
+++ b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
@@ -98,6 +98,10 @@
   optional bool report_network_interfaces = 5;
   optional bool report_users = 6;
   optional bool report_hardware_status = 7;
+  optional bool report_session_status = 8 [default = true];
+
+  // Frequency to report device status, default to 3 hours.
+  optional int64 device_status_frequency = 9 [default = 10800000];
 }
 
 message EphemeralUsersEnabledProto {
@@ -594,6 +598,17 @@
   optional bool reboot_on_shutdown = 1 [default = false];
 }
 
+// Settings that control whether a device would send heartbeat messages to GCM,
+// and how frequently to send these.
+message DeviceHeartbeatSettingsProto {
+  // Whether the device should send heartbeat messages. The default is false.
+  optional bool heartbeat_enabled = 1 [default = false];
+
+  // How frequently devices send heartbeats back to server. The unit is in
+  // milliseconds. The default is 2 minutes.
+  optional int64 heartbeat_frequency = 2 [default = 120000];
+}
+
 message ChromeDeviceSettingsProto {
   optional DevicePolicyRefreshRateProto device_policy_refresh_rate = 1;
   optional UserWhitelistProto user_whitelist = 2;
@@ -631,4 +646,5 @@
   optional SystemSettingsProto system_settings = 32;
   optional SAMLSettingsProto saml_settings = 33;
   optional RebootOnShutdownProto reboot_on_shutdown = 34;
+  optional DeviceHeartbeatSettingsProto device_heartbeat_settings = 35;
 }
diff --git a/chrome/browser/chromeos/power/extension_event_observer_unittest.cc b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
index acc30b7..d35a7401 100644
--- a/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
+++ b/chrome/browser/chromeos/power/extension_event_observer_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -36,7 +36,7 @@
  public:
   ExtensionEventObserverTest()
       : power_manager_client_(new FakePowerManagerClient()),
-        fake_user_manager_(new FakeUserManager()),
+        fake_user_manager_(new FakeChromeUserManager()),
         scoped_user_manager_enabler_(fake_user_manager_) {
     DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
         make_scoped_ptr(power_manager_client_));
@@ -132,7 +132,7 @@
   ScopedTestCrosSettings test_cros_settings_;
 
   // Owned by |scoped_user_manager_enabler_|.
-  FakeUserManager* fake_user_manager_;
+  FakeChromeUserManager* fake_user_manager_;
   ScopedUserManagerEnabler scoped_user_manager_enabler_;
 
   std::vector<scoped_refptr<extensions::Extension>> created_apps_;
diff --git a/chrome/browser/chromeos/power/power_prefs_unittest.cc b/chrome/browser/chromeos/power/power_prefs_unittest.cc
index cd881fa..9bf1e9c57 100644
--- a/chrome/browser/chromeos/power/power_prefs_unittest.cc
+++ b/chrome/browser/chromeos/power/power_prefs_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/extension_special_storage_policy.h"
@@ -234,7 +234,7 @@
 }
 
 TEST_F(PowerPrefsTest, UserSession) {
-  FakeUserManager* user_manager = new FakeUserManager();
+  FakeChromeUserManager* user_manager = new FakeChromeUserManager();
   ScopedUserManagerEnabler user_manager_enabler(user_manager);
 
   // Set up user profile.
diff --git a/chrome/browser/chromeos/preferences_unittest.cc b/chrome/browser/chromeos/preferences_unittest.cc
index b4f6c95..b58fb5d2 100644
--- a/chrome/browser/chromeos/preferences_unittest.cc
+++ b/chrome/browser/chromeos/preferences_unittest.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/system/fake_input_device_settings.h"
 #include "chrome/common/chrome_constants.h"
@@ -149,7 +149,8 @@
         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
     ASSERT_TRUE(profile_manager_->SetUp());
 
-    chromeos::FakeUserManager* user_manager = new chromeos::FakeUserManager();
+    chromeos::FakeChromeUserManager* user_manager =
+        new chromeos::FakeChromeUserManager();
     user_manager_enabler_.reset(
         new chromeos::ScopedUserManagerEnabler(user_manager));
 
diff --git a/chrome/browser/chromeos/profiles/profile_helper.h b/chrome/browser/chromeos/profiles/profile_helper.h
index 654a98b3..cac7855 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.h
+++ b/chrome/browser/chromeos/profiles/profile_helper.h
@@ -126,7 +126,7 @@
   friend class CryptohomeAuthenticatorTest;
   friend class DeviceSettingsTestBase;
   friend class extensions::ExtensionGarbageCollectorChromeOSUnitTest;
-  friend class FakeUserManager;
+  friend class FakeChromeUserManager;
   friend class KioskTest;
   friend class MockUserManager;
   friend class MultiProfileUserControllerTest;
diff --git a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
index c5fefff..09f7c18 100644
--- a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
@@ -58,22 +58,24 @@
     // AvatarMenu and multiple profiles works after user logged in.
     manager_.SetLoggedIn(true);
 
-    // Initialize the UserManager singleton to a fresh FakeUserManager instance.
+    // Initialize the UserManager singleton to a fresh FakeChromeUserManager
+    // instance.
     user_manager_enabler_.reset(
-        new ScopedUserManagerEnabler(new FakeUserManager));
+        new ScopedUserManagerEnabler(new FakeChromeUserManager));
   }
 
-  FakeUserManager* GetFakeUserManager() {
-    return static_cast<FakeUserManager*>(user_manager::UserManager::Get());
+  FakeChromeUserManager* GetFakeChromeUserManager() {
+    return static_cast<FakeChromeUserManager*>(
+        user_manager::UserManager::Get());
   }
 
   void AddProfile(base::string16 name, bool log_in) {
     std::string email_string = base::UTF16ToASCII(name) + "@example.com";
 
     // Add a user to the fake user manager.
-    GetFakeUserManager()->AddUser(email_string);
+    GetFakeChromeUserManager()->AddUser(email_string);
     if (log_in)
-      GetFakeUserManager()->LoginUser(email_string);
+      GetFakeChromeUserManager()->LoginUser(email_string);
 
     // Create a profile for the user.
     manager()->CreateTestingProfile(email_string);
@@ -96,7 +98,7 @@
 
   void ActiveUserChanged(const base::string16& name) {
     std::string email_string = base::UTF16ToASCII(name) + "@example.com";
-    GetFakeUserManager()->SwitchActiveUser(email_string);
+    GetFakeChromeUserManager()->SwitchActiveUser(email_string);
   }
 
   TestingProfileManager* manager() { return &manager_; }
@@ -163,7 +165,7 @@
       cache->GetUserDataDir().AppendASCII("p2"), supervised_name,
       base::string16(), 0, "TEST_ID");
 
-  GetFakeUserManager()->AddUser(base::UTF16ToASCII(supervised_name));
+  GetFakeChromeUserManager()->AddUser(base::UTF16ToASCII(supervised_name));
 
   AvatarMenu* menu = GetAvatarMenu();
   ASSERT_EQ(1U, menu->GetNumberOfItems());
@@ -238,7 +240,7 @@
 
   // Change name of the first profile, to trigger resorting of the profiles:
   // now the first menu item should be named "beta", and the second be "gamma".
-  GetFakeUserManager()->SaveUserDisplayName(
+  GetFakeChromeUserManager()->SaveUserDisplayName(
       base::UTF16ToASCII(name1) + "@example.com", newname1);
   manager()->profile_info_cache()->SetNameOfProfileAtIndex(0, newname1);
 
diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
index 56366f8..d6e9b6c 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/path_service.h"
 #include "base/test/scoped_path_override.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
@@ -21,6 +20,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/settings/cros_settings_names.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "components/user_manager/user.h"
 #include "policy/proto/device_management_backend.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.cc b/chrome/browser/chromeos/settings/device_settings_test_helper.cc
index 712b356..abc8caf 100644
--- a/chrome/browser/chromeos/settings/device_settings_test_helper.cc
+++ b/chrome/browser/chromeos/settings/device_settings_test_helper.cc
@@ -200,7 +200,8 @@
 }
 
 DeviceSettingsTestBase::DeviceSettingsTestBase()
-    : user_manager_(new FakeUserManager()),
+    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+      user_manager_(new FakeChromeUserManager()),
       user_manager_enabler_(user_manager_),
       owner_key_util_(new ownership::MockOwnerKeyUtil()) {
   OwnerSettingsServiceChromeOSFactory::SetDeviceSettingsServiceForTesting(
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.h b/chrome/browser/chromeos/settings/device_settings_test_helper.h
index 05c6be2..0e5742e 100644
--- a/chrome/browser/chromeos/settings/device_settings_test_helper.h
+++ b/chrome/browser/chromeos/settings/device_settings_test_helper.h
@@ -15,7 +15,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -180,7 +180,7 @@
   DeviceSettingsTestHelper device_settings_test_helper_;
   // Note that FakeUserManager is used by ProfileHelper, which some of the
   // tested classes depend on implicitly.
-  FakeUserManager* user_manager_;
+  FakeChromeUserManager* user_manager_;
   ScopedUserManagerEnabler user_manager_enabler_;
   scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_;
   // Local DeviceSettingsService instance for tests. Avoid using in combination
diff --git a/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc b/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc
index e3186fb..9eda36b 100644
--- a/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc
+++ b/chrome/browser/chromeos/settings/session_manager_operation_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
@@ -25,6 +24,7 @@
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
 #include "components/policy/core/common/cloud/policy_builder.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_utils.h"
 #include "crypto/rsa_private_key.h"
@@ -45,7 +45,7 @@
       : ui_thread_(content::BrowserThread::UI, &message_loop_),
         file_thread_(content::BrowserThread::FILE, &message_loop_),
         owner_key_util_(new ownership::MockOwnerKeyUtil()),
-        user_manager_(new FakeUserManager()),
+        user_manager_(new user_manager::FakeUserManager()),
         user_manager_enabler_(user_manager_),
         validated_(false) {
     OwnerSettingsServiceChromeOSFactory::GetInstance()
@@ -91,7 +91,7 @@
   DeviceSettingsTestHelper device_settings_test_helper_;
   scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_;
 
-  FakeUserManager* user_manager_;
+  user_manager::FakeUserManager* user_manager_;
   ScopedUserManagerEnabler user_manager_enabler_;
 
   scoped_ptr<TestingProfile> profile_;
diff --git a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc b/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
index 5453267..771b719 100644
--- a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
+++ b/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
@@ -25,6 +24,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "components/ownership/mock_owner_key_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "policy/proto/device_management_backend.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -73,7 +73,7 @@
   policy::ScopedStubEnterpriseInstallAttributes install_attributes_;
   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
   chromeos::ScopedTestCrosSettings test_cros_settings_;
-  FakeUserManager fake_user_manager_;
+  user_manager::FakeUserManager fake_user_manager_;
   scoped_ptr<DeviceDisablingManager> device_disabling_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceDisablingManagerTestBase);
diff --git a/chrome/browser/chromeos/system/pointer_device_observer.cc b/chrome/browser/chromeos/system/pointer_device_observer.cc
index 29bbd67..2de1305 100644
--- a/chrome/browser/chromeos/system/pointer_device_observer.cc
+++ b/chrome/browser/chromeos/system/pointer_device_observer.cc
@@ -9,6 +9,7 @@
 #include "base/bind_helpers.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "content/public/browser/browser_thread.h"
+#include "ui/events/devices/device_data_manager.h"
 
 #if defined(USE_X11)
 #include "chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h"
@@ -27,6 +28,8 @@
 #if defined(USE_X11)
   XInputHierarchyChangedEventListener::GetInstance()
       ->RemoveObserver(this);
+#elif defined(USE_OZONE)
+  ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
 #endif
 }
 
@@ -34,6 +37,8 @@
 #if defined(USE_X11)
   XInputHierarchyChangedEventListener::GetInstance()
       ->AddObserver(this);
+#elif defined(USE_OZONE)
+  ui::DeviceDataManager::GetInstance()->AddObserver(this);
 #endif
 }
 
@@ -54,6 +59,14 @@
   CheckDevices();
 }
 
+void PointerDeviceObserver::OnMouseDeviceConfigurationChanged() {
+  CheckDevices();
+}
+
+void PointerDeviceObserver::OnTouchpadDeviceConfigurationChanged() {
+  CheckDevices();
+}
+
 void PointerDeviceObserver::CheckTouchpadExists() {
   InputDeviceSettings::Get()->TouchpadExists(
       base::Bind(&PointerDeviceObserver::OnTouchpadExists,
diff --git a/chrome/browser/chromeos/system/pointer_device_observer.h b/chrome/browser/chromeos/system/pointer_device_observer.h
index 51ce2a8..b5911cb 100644
--- a/chrome/browser/chromeos/system/pointer_device_observer.h
+++ b/chrome/browser/chromeos/system/pointer_device_observer.h
@@ -8,11 +8,13 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/chromeos/device_hierarchy_observer.h"
+#include "ui/events/devices/input_device_event_observer.h"
 
 namespace chromeos {
 namespace system {
 
-class PointerDeviceObserver : public DeviceHierarchyObserver {
+class PointerDeviceObserver : public DeviceHierarchyObserver,
+                              public ui::InputDeviceEventObserver {
  public:
   PointerDeviceObserver();
   ~PointerDeviceObserver() override;
@@ -36,11 +38,17 @@
   void RemoveObserver(Observer* observer);
 
  private:
-  // DeviceHierarchyObserver implementation.
+  // DeviceHierarchyObserver:
   void DeviceHierarchyChanged() override;
   void DeviceAdded(int device_id) override {}
   void DeviceRemoved(int device_id) override {}
 
+  // InputDeviceEventObserver:
+  void OnTouchscreenDeviceConfigurationChanged() override {}
+  void OnKeyboardDeviceConfigurationChanged() override {}
+  void OnMouseDeviceConfigurationChanged() override;
+  void OnTouchpadDeviceConfigurationChanged() override;
+
   // Check for pointer devices.
   void CheckTouchpadExists();
   void CheckMouseExists();
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 3a8eafe..cf0f241 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -958,6 +958,18 @@
                    extension, http_host, CONTENT_SETTINGS_TYPE_COOKIES));
 }
 
+TEST_F(HostContentSettingsMapTest, IsSettingAllowedForType) {
+  TestingProfile profile;
+  PrefService* prefs = profile.GetPrefs();
+
+  EXPECT_TRUE(HostContentSettingsMap::IsSettingAllowedForType(
+                  prefs, CONTENT_SETTING_ASK,
+                  CONTENT_SETTINGS_TYPE_FULLSCREEN));
+
+  // TODO(msramek): Add more checks for setting type - setting pairs where
+  // it is not obvious whether or not they are allowed.
+}
+
 TEST_F(HostContentSettingsMapTest, AddContentSettingsObserver) {
   TestingProfile profile;
   HostContentSettingsMap* host_content_settings_map =
diff --git a/chrome/browser/content_settings/permission_context_base.cc b/chrome/browser/content_settings/permission_context_base.cc
index c188377..045ac48 100644
--- a/chrome/browser/content_settings/permission_context_base.cc
+++ b/chrome/browser/content_settings/permission_context_base.cc
@@ -18,6 +18,12 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
+using chromeos::attestation::PlatformVerificationDialog;
+using chromeos::attestation::PlatformVerificationFlow;
+#endif
+
 PermissionContextBase::PermissionContextBase(
     Profile* profile,
     const ContentSettingsType permission_type)
@@ -126,6 +132,19 @@
   PermissionContextUmaUtil::PermissionRequested(
       permission_type_, requesting_origin);
 
+#if defined(OS_CHROMEOS)
+  // TODO(xhwang): This is to use the existing platform verification UI. Remove
+  // it when the infobar/bubble UI can satisfy our requirements.
+  if (permission_type_ == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER) {
+    PlatformVerificationDialog::ShowDialog(
+        web_contents,
+        base::Bind(&PermissionContextBase::OnPlatformVerificationResult,
+                   weak_factory_.GetWeakPtr(), id, requesting_origin,
+                   embedding_origin, callback));
+    return;
+  }
+#endif
+
   if (PermissionBubbleManager::Enabled()) {
     if (pending_bubbles_.get(id.ToString()) != NULL)
       return;
@@ -229,3 +248,25 @@
       ContentSettingsPattern::FromURLNoWildcard(embedding_origin),
       permission_type_, std::string(), content_setting);
 }
+
+#if defined(OS_CHROMEOS)
+void PermissionContextBase::OnPlatformVerificationResult(
+    const PermissionRequestID& id,
+    const GURL& requesting_origin,
+    const GURL& embedding_origin,
+    const BrowserPermissionCallback& callback,
+    chromeos::attestation::PlatformVerificationFlow::ConsentResponse response) {
+  if (response == PlatformVerificationFlow::CONSENT_RESPONSE_NONE) {
+    // Deny request and do not save to content settings.
+    PermissionDecided(id, requesting_origin, embedding_origin, callback,
+                      false,   // Do not save to content settings.
+                      false);  // Do not allow the permission.
+    return;
+  }
+
+  PermissionDecided(
+      id, requesting_origin, embedding_origin, callback,
+      true,  // Save to content settings.
+      response == PlatformVerificationFlow::CONSENT_RESPONSE_ALLOW);
+}
+#endif
diff --git a/chrome/browser/content_settings/permission_context_base.h b/chrome/browser/content_settings/permission_context_base.h
index 740aa8f..fe711ecc 100644
--- a/chrome/browser/content_settings/permission_context_base.h
+++ b/chrome/browser/content_settings/permission_context_base.h
@@ -15,6 +15,10 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
+#endif
+
 class PermissionQueueController;
 class PermissionRequestID;
 class Profile;
@@ -127,6 +131,16 @@
   // Called when a bubble is no longer used so it can be cleaned up.
   void CleanUpBubble(const PermissionRequestID& id);
 
+#if defined(OS_CHROMEOS)
+  void OnPlatformVerificationResult(
+      const PermissionRequestID& id,
+      const GURL& requesting_origin,
+      const GURL& embedding_origin,
+      const BrowserPermissionCallback& callback,
+      chromeos::attestation::PlatformVerificationFlow::ConsentResponse
+          response);
+#endif
+
   Profile* profile_;
   const ContentSettingsType permission_type_;
   scoped_ptr<PermissionQueueController> permission_queue_controller_;
diff --git a/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc b/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc
index 635fcedb..4a34f9a 100644
--- a/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc
+++ b/chrome/browser/copresence/chrome_whispernet_client_browsertest.cc
@@ -176,35 +176,52 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeWhispernetClientTest);
 };
 
-IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, Initialize) {
+// These tests are irrelevant if NACL is disabled. See crbug.com/449198
+#if defined(DISABLE_NACL)
+#define MAYBE_Initialize DISABLED_Initialize
+#define MAYBE_EncodeToken DISABLED_EncodeToken
+#define MAYBE_DecodeSamples DISABLED_DecodeSamples
+#define MAYBE_DetectBroadcast DISABLED_DetectBroadcast
+#define MAYBE_Audible DISABLED_Audible
+#define MAYBE_TokenLengths DISABLED_TokenLengths
+#else
+#define MAYBE_Initialize Initialize
+#define MAYBE_EncodeToken EncodeToken
+#define MAYBE_DecodeSamples DecodeSamples
+#define MAYBE_DetectBroadcast DetectBroadcast
+#define MAYBE_Audible Audible
+#define MAYBE_TokenLengths TokenLengths
+#endif
+
+IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_Initialize) {
   InitializeWhispernet();
 }
 
-IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, EncodeToken) {
+IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_EncodeToken) {
   InitializeWhispernet();
   EncodeTokenAndSaveSamples(false, kSixZeros);
 }
 
-IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, DecodeSamples) {
+IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_DecodeSamples) {
   InitializeWhispernet();
   EncodeTokenAndSaveSamples(false, kSixZeros);
   DecodeSamplesAndVerifyToken(false, kSixZeros, kTokenLengths);
 }
 
-IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, DetectBroadcast) {
+IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_DetectBroadcast) {
   InitializeWhispernet();
   EncodeTokenAndSaveSamples(false, kSixZeros);
   DecodeSamplesAndVerifyToken(false, kSixZeros, kTokenLengths);
   DetectBroadcast();
 }
 
-IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, Audible) {
+IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_Audible) {
   InitializeWhispernet();
   EncodeTokenAndSaveSamples(true, kSixZeros);
   DecodeSamplesAndVerifyToken(true, kSixZeros, kTokenLengths);
 }
 
-IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, TokenLengths) {
+IN_PROC_BROWSER_TEST_F(ChromeWhispernetClientTest, MAYBE_TokenLengths) {
   InitializeWhispernet();
   size_t kLongTokenLengths[2] = {8, 9};
 
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 75f824a..da7853c0 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -828,7 +828,7 @@
 void DevToolsWindow::AddNewContents(WebContents* source,
                                     WebContents* new_contents,
                                     WindowOpenDisposition disposition,
-                                    const gfx::Rect& initial_pos,
+                                    const gfx::Rect& initial_rect,
                                     bool user_gesture,
                                     bool* was_blocked) {
   if (new_contents == toolbox_web_contents_) {
@@ -848,7 +848,7 @@
   WebContents* inspected_web_contents = GetInspectedWebContents();
   if (inspected_web_contents) {
     inspected_web_contents->GetDelegate()->AddNewContents(
-        source, new_contents, disposition, initial_pos, user_gesture,
+        source, new_contents, disposition, initial_rect, user_gesture,
         was_blocked);
   }
 }
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index dd605b4..f1471e1 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -233,7 +233,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   void WebContentsCreated(content::WebContents* source_contents,
diff --git a/chrome/browser/download/download_ui_controller.cc b/chrome/browser/download/download_ui_controller.cc
index 6f8b219..5c249cd 100644
--- a/chrome/browser/download/download_ui_controller.cc
+++ b/chrome/browser/download/download_ui_controller.cc
@@ -29,11 +29,11 @@
     : public DownloadUIController::Delegate {
  public:
   DefaultUIControllerDelegateAndroid() {}
-  virtual ~DefaultUIControllerDelegateAndroid() {}
+  ~DefaultUIControllerDelegateAndroid() override {}
 
  private:
   // DownloadUIController::Delegate
-  virtual void OnNewDownloadReady(content::DownloadItem* item) override;
+  void OnNewDownloadReady(content::DownloadItem* item) override;
 };
 
 void DefaultUIControllerDelegateAndroid::OnNewDownloadReady(
diff --git a/chrome/browser/drive/drive_api_util.cc b/chrome/browser/drive/drive_api_util.cc
index 064f4a2..d23a782 100644
--- a/chrome/browser/drive/drive_api_util.cc
+++ b/chrome/browser/drive/drive_api_util.cc
@@ -16,6 +16,9 @@
 #include "base/values.h"
 #include "google_apis/drive/drive_api_parser.h"
 #include "net/base/escape.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "storage/browser/blob/file_stream_reader.h"
 #include "third_party/re2/re2/re2.h"
 #include "url/gurl.h"
 
@@ -40,6 +43,8 @@
 
 const char kUnknownHostedDocumentExtension[] = ".glink";
 
+const int kMd5DigestBufferSize = 512 * 1024;  // 512 kB.
+
 }  // namespace
 
 std::string EscapeQueryStringValue(const std::string& str) {
@@ -131,8 +136,6 @@
 }
 
 std::string GetMd5Digest(const base::FilePath& file_path) {
-  const int kBufferSize = 512 * 1024;  // 512kB.
-
   base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
   if (!file.IsValid())
     return std::string();
@@ -141,9 +144,9 @@
   base::MD5Init(&context);
 
   int64 offset = 0;
-  scoped_ptr<char[]> buffer(new char[kBufferSize]);
+  scoped_ptr<char[]> buffer(new char[kMd5DigestBufferSize]);
   while (true) {
-    int result = file.Read(offset, buffer.get(), kBufferSize);
+    int result = file.Read(offset, buffer.get(), kMd5DigestBufferSize);
     if (result < 0) {
       // Found an error.
       return std::string();
@@ -163,6 +166,53 @@
   return MD5DigestToBase16(digest);
 }
 
+FileStreamMd5Digester::FileStreamMd5Digester()
+    : buffer_(new net::IOBuffer(kMd5DigestBufferSize)) {
+}
+
+FileStreamMd5Digester::~FileStreamMd5Digester() {
+}
+
+void FileStreamMd5Digester::GetMd5Digest(
+    scoped_ptr<storage::FileStreamReader> stream_reader,
+    const ResultCallback& callback) {
+  reader_ = stream_reader.Pass();
+  callback_ = callback;
+  base::MD5Init(&md5_context_);
+
+  // Start the read/hash.
+  ReadNextChunk();
+}
+
+void FileStreamMd5Digester::ReadNextChunk() {
+  const int result = reader_->Read(
+      buffer_.get(), kMd5DigestBufferSize,
+      base::Bind(&FileStreamMd5Digester::OnChunkRead, base::Unretained(this)));
+  if (result != net::ERR_IO_PENDING)
+    OnChunkRead(result);
+}
+
+void FileStreamMd5Digester::OnChunkRead(int result) {
+  if (result < 0) {
+    // Error - just return empty string.
+    callback_.Run("");
+    return;
+  } else if (result == 0) {
+    // EOF.
+    base::MD5Digest digest;
+    base::MD5Final(&digest, &md5_context_);
+    std::string result = MD5DigestToBase16(digest);
+    callback_.Run(result);
+    return;
+  }
+
+  // Read data and digest it.
+  base::MD5Update(&md5_context_, base::StringPiece(buffer_->data(), result));
+
+  // Kick off the next read.
+  ReadNextChunk();
+}
+
 std::string GetHostedDocumentExtension(const std::string& mime_type) {
   for (size_t i = 0; i < arraysize(kHostedDocumentKinds); ++i) {
     if (mime_type == kHostedDocumentKinds[i].mime_type)
diff --git a/chrome/browser/drive/drive_api_util.h b/chrome/browser/drive/drive_api_util.h
index 95771ca2..def1199 100644
--- a/chrome/browser/drive/drive_api_util.h
+++ b/chrome/browser/drive/drive_api_util.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/md5.h"
 #include "base/memory/scoped_ptr.h"
 #include "google_apis/drive/drive_api_error_codes.h"
 #include "google_apis/drive/drive_common_callbacks.h"
@@ -26,6 +27,14 @@
 class ResourceEntry;
 }  // namespace google_apis
 
+namespace net {
+class IOBuffer;
+}  // namespace net
+
+namespace storage {
+class FileStreamReader;
+}  // namespace storage
+
 namespace drive {
 namespace util {
 
@@ -64,6 +73,38 @@
 // or an empty string if an error is found.
 std::string GetMd5Digest(const base::FilePath& file_path);
 
+// Computes the (base-16 encoded) MD5 digest of data extracted from a file
+// stream.
+class FileStreamMd5Digester {
+ public:
+  typedef base::Callback<void(const std::string&)> ResultCallback;
+
+  FileStreamMd5Digester();
+  ~FileStreamMd5Digester();
+
+  // Computes an MD5 digest of data read from the given |streamReader|.  The
+  // work occurs asynchronously, and the resulting hash is returned via the
+  // |callback|.  If an error occurs, |callback| is called with an empty string.
+  // Only one stream can be processed at a time by each digester.  Do not call
+  // GetMd5Digest before the results of a previous call have been returned.
+  void GetMd5Digest(scoped_ptr<storage::FileStreamReader> stream_reader,
+                    const ResultCallback& callback);
+
+ private:
+  // Kicks off a read of the next chunk from the stream.
+  void ReadNextChunk();
+  // Handles the incoming chunk of data from a stream read.
+  void OnChunkRead(int result);
+
+  // Maximum chunk size for read operations.
+  scoped_ptr<storage::FileStreamReader> reader_;
+  ResultCallback callback_;
+  scoped_refptr<net::IOBuffer> buffer_;
+  base::MD5Context md5_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileStreamMd5Digester);
+};
+
 // Returns preferred file extension for hosted documents which have given mime
 // type.
 std::string GetHostedDocumentExtension(const std::string& mime_type);
diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc
index 289898ba..6c4708a 100644
--- a/chrome/browser/errorpage_browsertest.cc
+++ b/chrome/browser/errorpage_browsertest.cc
@@ -15,9 +15,9 @@
 #include "base/synchronization/lock.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_remover.h"
-#include "chrome/browser/google/google_profile_helper.h"
 #include "chrome/browser/net/url_request_mock_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -279,10 +279,11 @@
   // Add a mock for the search engine the error page will use.
   base::FilePath root_http;
   PathService::Get(chrome::DIR_TEST_DATA, &root_http);
-  net::URLRequestMockHTTPJob::AddHostnameToFileHandler(
-      search_url.host(),
-      root_http.AppendASCII("title3.html"),
-      BrowserThread::GetBlockingPool());
+  net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
+      search_url.scheme(), search_url.host(),
+      net::URLRequestMockHTTPJob::CreateInterceptorForSingleFile(
+          root_http.AppendASCII("title3.html"),
+          BrowserThread::GetBlockingPool()));
 }
 
 class ErrorPageTest : public InProcessBrowserTest {
@@ -412,12 +413,11 @@
     // Ownership of the |interceptor_| is passed to an object the IO thread, but
     // a pointer is kept in the test fixture.  As soon as anything calls
     // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
+    UIThreadSearchTermsData search_terms_data(browser()->profile());
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
         base::Bind(&InstallMockInterceptors,
-                   google_util::GetGoogleSearchURL(
-                       google_profile_helper::GetGoogleHomePageURL(
-                           browser()->profile())),
+                   GURL(search_terms_data.GoogleBaseURLValue()),
                    base::Passed(&owned_interceptor)));
   }
 
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
index 747b84a..2643257 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
@@ -109,6 +109,11 @@
     EXPECT_EQ(CONTENT_SETTING_ASK,
               map->GetContentSetting(example_url,
                                      example_url,
+                                     CONTENT_SETTINGS_TYPE_FULLSCREEN,
+                                     std::string()));
+    EXPECT_EQ(CONTENT_SETTING_ASK,
+              map->GetContentSetting(example_url,
+                                     example_url,
                                      CONTENT_SETTINGS_TYPE_MOUSELOCK,
                                      std::string()));
     EXPECT_EQ(CONTENT_SETTING_ASK,
@@ -121,6 +126,16 @@
                                      example_url,
                                      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
                                      std::string()));
+    EXPECT_EQ(CONTENT_SETTING_ASK,
+              map->GetContentSetting(example_url,
+                                     example_url,
+                                     CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
+                                     std::string()));
+    EXPECT_EQ(CONTENT_SETTING_ASK,
+              map->GetContentSetting(example_url,
+                                     example_url,
+                                     CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+                                     std::string()));
 
     // Check content settings for www.google.com
     GURL url("http://www.google.com");
@@ -144,6 +159,9 @@
         CONTENT_SETTING_BLOCK,
         map->GetContentSetting(
             url, url, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string()));
+    EXPECT_EQ(CONTENT_SETTING_ALLOW,
+        map->GetContentSetting(
+            url, url, CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string()));
     EXPECT_EQ(CONTENT_SETTING_BLOCK,
         map->GetContentSetting(
             url, url, CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string()));
@@ -153,6 +171,13 @@
     EXPECT_EQ(CONTENT_SETTING_BLOCK,
         map->GetContentSetting(
             url, url, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string()));
+    EXPECT_EQ(CONTENT_SETTING_BLOCK,
+        map->GetContentSetting(
+            url, url, CONTENT_SETTINGS_TYPE_PPAPI_BROKER, std::string()));
+    EXPECT_EQ(CONTENT_SETTING_BLOCK,
+        map->GetContentSetting(
+            url, url, CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+            std::string()));
   }
 
   void CheckContentSettingsDefault() {
@@ -187,6 +212,9 @@
             url, url, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string()));
     EXPECT_EQ(CONTENT_SETTING_ASK,
         map->GetContentSetting(
+            url, url, CONTENT_SETTINGS_TYPE_FULLSCREEN, std::string()));
+    EXPECT_EQ(CONTENT_SETTING_ASK,
+        map->GetContentSetting(
             url, url, CONTENT_SETTINGS_TYPE_MOUSELOCK, std::string()));
     EXPECT_EQ(CONTENT_SETTING_ASK,
         map->GetContentSetting(
@@ -194,6 +222,13 @@
     EXPECT_EQ(CONTENT_SETTING_ASK,
         map->GetContentSetting(
             url, url, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string()));
+    EXPECT_EQ(CONTENT_SETTING_ASK,
+        map->GetContentSetting(
+            url, url, CONTENT_SETTINGS_TYPE_PPAPI_BROKER, std::string()));
+    EXPECT_EQ(CONTENT_SETTING_ASK,
+        map->GetContentSetting(
+            url, url, CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+            std::string()));
   }
 
  private:
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_helpers.cc b/chrome/browser/extensions/api/content_settings/content_settings_helpers.cc
index 8ae4730..a262d23 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_helpers.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_helpers.cc
@@ -31,7 +31,10 @@
   "mixed-script",
   "media-stream",
   "media-stream-mic",
-  "media-stream-camera"
+  "media-stream-camera",
+  "register-protocol-handler",
+  "ppapi-broker",
+  "multiple-automatic-downloads"
 };
 
 // TODO(msramek): Assert that |kContentSettingsTypeNames| is synced with
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
index 92a387f..d2aa388f 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -306,20 +306,6 @@
   strings->SetString(
       "setupErrorFindingPhone",
       l10n_util::GetStringUTF16(IDS_EASY_UNLOCK_SETUP_ERROR_FINDING_PHONE));
-  // TODO(isherman): Remove the setupErrorBluetoothConnectionFailed string; it
-  // is unused.
-  strings->SetString(
-      "setupErrorBluetoothConnectionFailed",
-      l10n_util::GetStringFUTF16(
-          IDS_EASY_UNLOCK_SETUP_ERROR_BLUETOOTH_CONNECTION_FAILED,
-          device_type));
-  // TODO(isherman): Remove the setupErrorConnectionToPhoneTimeout string; it is
-  // identical to the setupErrorConnectingToPhone string, and hence obsolete.
-  strings->SetString(
-      "setupErrorConnectionToPhoneTimeout",
-       l10n_util::GetStringFUTF16(
-           IDS_EASY_UNLOCK_SETUP_ERROR_CONNECT_TO_PHONE_TIMEOUT,
-           device_type));
   strings->SetString(
       "setupErrorSyncPhoneState",
        l10n_util::GetStringUTF16(
@@ -329,9 +315,6 @@
       l10n_util::GetStringFUTF16(
           IDS_EASY_UNLOCK_SETUP_ERROR_CONNECTING_TO_PHONE, device_type));
 
-  // TODO(isherman): Remove this string once the app has been updated.
-  strings->SetString("setupIntroHeaderFootnote", base::string16());
-
   SetResult(strings.release());
   return true;
 }
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.cc b/chrome/browser/extensions/api/notifications/notifications_api.cc
index 6afb8850..05d5c8a 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_api.cc
@@ -476,9 +476,9 @@
 
   const std::string extension_id(extension_->id());
   std::string notification_id;
-  if (!params_->notification_id.empty()) {
+  if (params_->notification_id.get() && !params_->notification_id->empty()) {
     // If the caller provided a notificationId, use that.
-    notification_id = params_->notification_id;
+    notification_id = *params_->notification_id;
   } else {
     // Otherwise, use a randomly created GUID. In case that GenerateGUID returns
     // the empty string, simply generate a random string.
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc
index b9a2e1e..bafa06b 100644
--- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc
+++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc
@@ -101,6 +101,7 @@
         base::ThreadTaskRunnerHandle::Get(),  // ui_task_runner
         MakeSequencedTaskRunner(),
         MakeSequencedTaskRunner(),
+        content::BrowserThread::GetBlockingPool(),
         base_dir_.path(),
         NULL,  // task_logger
         NULL,  // notification_manager
diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.cc b/chrome/browser/extensions/chrome_extension_host_delegate.cc
index c8d2b58..8cb4ec6 100644
--- a/chrome/browser/extensions/chrome_extension_host_delegate.cc
+++ b/chrome/browser/extensions/chrome_extension_host_delegate.cc
@@ -41,10 +41,10 @@
 void ChromeExtensionHostDelegate::CreateTab(content::WebContents* web_contents,
                                             const std::string& extension_id,
                                             WindowOpenDisposition disposition,
-                                            const gfx::Rect& initial_pos,
+                                            const gfx::Rect& initial_rect,
                                             bool user_gesture) {
   ExtensionTabUtil::CreateTab(
-      web_contents, extension_id, disposition, initial_pos, user_gesture);
+      web_contents, extension_id, disposition, initial_rect, user_gesture);
 }
 
 void ChromeExtensionHostDelegate::ProcessMediaAccessRequest(
diff --git a/chrome/browser/extensions/chrome_extension_host_delegate.h b/chrome/browser/extensions/chrome_extension_host_delegate.h
index c4a481a..0ba69555 100644
--- a/chrome/browser/extensions/chrome_extension_host_delegate.h
+++ b/chrome/browser/extensions/chrome_extension_host_delegate.h
@@ -22,7 +22,7 @@
   void CreateTab(content::WebContents* web_contents,
                  const std::string& extension_id,
                  WindowOpenDisposition disposition,
-                 const gfx::Rect& initial_pos,
+                 const gfx::Rect& initial_rect,
                  bool user_gesture) override;
   void ProcessMediaAccessRequest(content::WebContents* web_contents,
                                  const content::MediaStreamRequest& request,
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 3841dba..2ee48167 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -626,12 +626,7 @@
 #endif  // defined(GOOGLE_CHROME_BUILD)
 
 #if defined(ENABLE_PLUGINS)
-  base::FilePath pdf_path;
-  content::PluginService* plugin_service =
-      content::PluginService::GetInstance();
-  if (switches::OutOfProcessPdfEnabled() &&
-      PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path) &&
-      plugin_service->GetRegisteredPpapiPluginInfo(pdf_path)) {
+  if (switches::OutOfProcessPdfEnabled()) {
     if (switches::PdfMaterialUIEnabled())
       Add(IDR_PDF_MANIFEST_MATERIAL, base::FilePath(FILE_PATH_LITERAL("pdf")));
     else
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index a4207e7..17cc1a95 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -170,13 +170,17 @@
 }
 
 void CrxInstaller::InstallCrx(const base::FilePath& source_file) {
+  InstallCrxFile(CRXFileInfo(source_file));
+}
+
+void CrxInstaller::InstallCrxFile(const CRXFileInfo& source_file) {
   ExtensionService* service = service_weak_.get();
   if (!service || service->browser_terminating())
     return;
 
   NotifyCrxInstallBegin();
 
-  source_file_ = source_file;
+  source_file_ = source_file.path;
 
   scoped_refptr<SandboxedUnpacker> unpacker(
       new SandboxedUnpacker(source_file,
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 769ca30..9d014bf 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -98,6 +98,7 @@
 
   // Install the crx in |source_file|.
   void InstallCrx(const base::FilePath& source_file);
+  void InstallCrxFile(const CRXFileInfo& source_file);
 
   // Convert the specified user script into an extension and install it.
   void InstallUserScript(const base::FilePath& source_file,
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index ffbf01e..13d8da7 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -46,7 +46,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
 #include "chromeos/chromeos_switches.h"
@@ -533,8 +533,8 @@
 #if defined(OS_CHROMEOS)
   // Simulate ChromeOS kiosk mode. |scoped_user_manager| will take over
   // lifetime of |user_manager|.
-  chromeos::FakeUserManager* fake_user_manager =
-      new chromeos::FakeUserManager();
+  chromeos::FakeChromeUserManager* fake_user_manager =
+      new chromeos::FakeChromeUserManager();
   fake_user_manager->AddKioskAppUser("example@example.com");
   fake_user_manager->LoginUser("example@example.com");
   chromeos::ScopedUserManagerEnabler scoped_user_manager(fake_user_manager);
diff --git a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
index 61724981..622f324a 100644
--- a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_util.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
@@ -66,9 +66,10 @@
     ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(cache_dir());
     ExtensionGarbageCollectorChromeOS::ClearGarbageCollectedForTesting();
 
-    // Initialize the UserManager singleton to a fresh FakeUserManager instance.
-    user_manager_enabler_.reset(
-        new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
+    // Initialize the UserManager singleton to a fresh FakeChromeUserManager
+    // instance.
+    user_manager_enabler_.reset(new chromeos::ScopedUserManagerEnabler(
+        new chromeos::FakeChromeUserManager));
 
     GetFakeUserManager()->AddUser(chromeos::login::kStubUser);
     GetFakeUserManager()->LoginUser(chromeos::login::kStubUser);
@@ -144,8 +145,8 @@
     return ExtensionPrefs::Get(profile_.get());
   }
 
-  chromeos::FakeUserManager* GetFakeUserManager() {
-    return static_cast<chromeos::FakeUserManager*>(
+  chromeos::FakeChromeUserManager* GetFakeUserManager() {
+    return static_cast<chromeos::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
   }
 
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index ecf8310..4cf7f77 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -306,7 +306,7 @@
         extensions::NOTIFICATION_CRX_INSTALLER_DONE,
         base::Bind(&IsCrxInstallerDone, &installer));
     extension_service_->UpdateExtension(
-        extension->id(), path, true, &installer);
+        extensions::CRXFileInfo(extension->id(), path), true, &installer);
 
     if (installer)
       observer.Wait();
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 53d907bd..94e4b52 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -474,8 +474,7 @@
   }
 }
 
-bool ExtensionService::UpdateExtension(const std::string& id,
-                                       const base::FilePath& extension_path,
+bool ExtensionService::UpdateExtension(const extensions::CRXFileInfo& file,
                                        bool file_ownership_passed,
                                        CrxInstaller** out_crx_installer) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -487,6 +486,8 @@
     return false;
   }
 
+  const std::string& id = file.extension_id;
+
   const extensions::PendingExtensionInfo* pending_extension_info =
       pending_extension_manager()->GetById(id);
 
@@ -498,8 +499,7 @@
     // that would do it for us.
     if (!GetFileTaskRunner()->PostTask(
             FROM_HERE,
-            base::Bind(
-                &extensions::file_util::DeleteFile, extension_path, false)))
+            base::Bind(&extensions::file_util::DeleteFile, file.path, false)))
       NOTREACHED();
 
     return false;
@@ -557,7 +557,7 @@
 
   installer->set_delete_source(file_ownership_passed);
   installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
-  installer->InstallCrx(extension_path);
+  installer->InstallCrxFile(file);
 
   if (out_crx_installer)
     *out_crx_installer = installer.get();
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index b65a45f..4b6005d 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -21,6 +21,7 @@
 #include "chrome/browser/extensions/pending_extension_manager.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/browser/crx_file_info.h"
 #include "extensions/browser/external_provider_interface.h"
 #include "extensions/browser/install_flag.h"
 #include "extensions/browser/management_policy.h"
@@ -83,8 +84,7 @@
   // TODO(aa): This method can be removed. ExtensionUpdater could use
   // CrxInstaller directly instead.
   virtual bool UpdateExtension(
-      const std::string& id,
-      const base::FilePath& path,
+      const extensions::CRXFileInfo& file,
       bool file_ownership_passed,
       extensions::CrxInstaller** out_crx_installer) = 0;
 
@@ -207,8 +207,7 @@
       bool include_disabled) const override;
   const extensions::Extension* GetInstalledExtension(
       const std::string& id) const override;
-  bool UpdateExtension(const std::string& id,
-                       const base::FilePath& extension_path,
+  bool UpdateExtension(const extensions::CRXFileInfo& file,
                        bool file_ownership_passed,
                        extensions::CrxInstaller** out_crx_installer) override;
   bool IsExtensionEnabled(const std::string& extension_id) const override;
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 947c600..679c7eb 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -826,7 +826,8 @@
     content::WindowedNotificationObserver observer(
         extensions::NOTIFICATION_CRX_INSTALLER_DONE,
         base::Bind(&IsCrxInstallerDone, &installer));
-    service()->UpdateExtension(id, path, true, &installer);
+    service()->UpdateExtension(extensions::CRXFileInfo(id, path), true,
+                               &installer);
 
     if (installer)
       observer.Wait();
@@ -2717,7 +2718,8 @@
 
   // Update should fail and extension should not be updated.
   path = data_dir().AppendASCII("good2.crx");
-  bool updated = service()->UpdateExtension(good_crx, path, true, NULL);
+  bool updated = service()->UpdateExtension(
+      extensions::CRXFileInfo(good_crx, path), true, NULL);
   ASSERT_FALSE(updated);
   ASSERT_EQ(
       "1.0.0.0",
@@ -6763,7 +6765,7 @@
 
   // We don't want the extension to be installed.  A path that doesn't
   // point to a valid CRX ensures this.
-  const base::FilePath kInvalidPathToCrx = base::FilePath();
+  const base::FilePath kInvalidPathToCrx(FILE_PATH_LITERAL("invalid_path"));
 
   const int kCreationFlags = 0;
   const bool kDontMarkAcknowledged = false;
@@ -6967,7 +6969,7 @@
   Version kVersion123("1.2.3");
   Version kVersion124("1.2.4");
   Version kVersion125("1.2.5");
-  const base::FilePath kInvalidPathToCrx = base::FilePath();
+  const base::FilePath kInvalidPathToCrx(FILE_PATH_LITERAL("invalid_path"));
   const int kCreationFlags = 0;
   const bool kDontMarkAcknowledged = false;
 
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 9551132..4009221 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -171,7 +171,7 @@
 
   GURL url;
   if (params.url.get()) {
-    std::string url_string= *params.url;
+    std::string url_string = *params.url;
     url = ExtensionTabUtil::ResolvePossiblyRelativeURL(url_string,
                                                        function->extension());
     if (!url.is_valid()) {
@@ -528,7 +528,7 @@
 void ExtensionTabUtil::CreateTab(WebContents* web_contents,
                                  const std::string& extension_id,
                                  WindowOpenDisposition disposition,
-                                 const gfx::Rect& initial_pos,
+                                 const gfx::Rect& initial_rect,
                                  bool user_gesture) {
   Profile* profile =
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
@@ -548,7 +548,7 @@
     params.extension_app_id = extension_id;
 
   params.disposition = disposition;
-  params.window_bounds = initial_pos;
+  params.window_bounds = initial_rect;
   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
   params.user_gesture = user_gesture;
   chrome::Navigate(&params);
diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h
index 0f185d2..5a45abf 100644
--- a/chrome/browser/extensions/extension_tab_util.h
+++ b/chrome/browser/extensions/extension_tab_util.h
@@ -161,7 +161,7 @@
   static void CreateTab(content::WebContents* web_contents,
                         const std::string& extension_id,
                         WindowOpenDisposition disposition,
-                        const gfx::Rect& initial_pos,
+                        const gfx::Rect& initial_rect,
                         bool user_gesture);
 
   // Executes the specified callback for all tabs in all browser windows.
diff --git a/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc b/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc
index 5793068d..edf428d2 100644
--- a/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc
+++ b/chrome/browser/extensions/external_provider_impl_chromeos_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/customization/customization_document.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_service_test_base.h"
@@ -21,6 +20,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "chromeos/system/statistics_provider.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
 
@@ -33,9 +33,8 @@
 class ExternalProviderImplChromeOSTest : public ExtensionServiceTestBase {
  public:
   ExternalProviderImplChromeOSTest()
-      : fake_user_manager_(new chromeos::FakeUserManager()),
-        scoped_user_manager_(fake_user_manager_) {
-  }
+      : fake_user_manager_(new user_manager::FakeUserManager()),
+        scoped_user_manager_(fake_user_manager_) {}
 
   ~ExternalProviderImplChromeOSTest() override {}
 
@@ -75,7 +74,7 @@
   TestingPrefServiceSimple local_state_;
   scoped_ptr<base::ScopedPathOverride> external_externsions_overrides_;
   chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
-  chromeos::FakeUserManager* fake_user_manager_;
+  user_manager::FakeUserManager* fake_user_manager_;
   chromeos::ScopedUserManagerEnabler scoped_user_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(ExternalProviderImplChromeOSTest);
diff --git a/chrome/browser/extensions/external_provider_impl_unittest.cc b/chrome/browser/extensions/external_provider_impl_unittest.cc
index 011d032b..486eac6 100644
--- a/chrome/browser/extensions/external_provider_impl_unittest.cc
+++ b/chrome/browser/extensions/external_provider_impl_unittest.cc
@@ -33,10 +33,10 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/customization/customization_document.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chromeos/system/fake_statistics_provider.h"
 #include "chromeos/system/statistics_provider.h"
+#include "components/user_manager/fake_user_manager.h"
 #endif
 
 using ::testing::NotNull;
@@ -60,7 +60,7 @@
   void InitServiceWithExternalProviders() {
 #if defined(OS_CHROMEOS)
     chromeos::ScopedUserManagerEnabler scoped_user_manager(
-        new chromeos::FakeUserManager);
+        new user_manager::FakeUserManager);
 #endif
     InitializeExtensionServiceWithUpdaterAndPrefs();
 
diff --git a/chrome/browser/extensions/startup_helper.cc b/chrome/browser/extensions/startup_helper.cc
index a69f73d..b00df110 100644
--- a/chrome/browser/extensions/startup_helper.cc
+++ b/chrome/browser/extensions/startup_helper.cc
@@ -120,11 +120,14 @@
 
 class ValidateCrxHelper : public SandboxedUnpackerClient {
  public:
-  ValidateCrxHelper(const base::FilePath& crx_file,
+  ValidateCrxHelper(const CRXFileInfo& file,
                     const base::FilePath& temp_dir,
                     base::RunLoop* run_loop)
-      : crx_file_(crx_file), temp_dir_(temp_dir), run_loop_(run_loop),
-        finished_(false), success_(false) {}
+      : crx_file_(file),
+        temp_dir_(temp_dir),
+        run_loop_(run_loop),
+        finished_(false),
+        success_(false) {}
 
   bool finished() { return finished_; }
   bool success() { return success_; }
@@ -185,7 +188,7 @@
   }
 
   // The file being validated.
-  const base::FilePath& crx_file_;
+  const CRXFileInfo& crx_file_;
 
   // The temporary directory where the sandboxed unpacker will do work.
   const base::FilePath& temp_dir_;
@@ -222,8 +225,9 @@
   }
 
   base::RunLoop run_loop;
+  CRXFileInfo file(path);
   scoped_refptr<ValidateCrxHelper> helper(
-      new ValidateCrxHelper(path, temp_dir.path(), &run_loop));
+      new ValidateCrxHelper(file, temp_dir.path(), &run_loop));
   helper->Start();
   if (!helper->finished())
     run_loop.Run();
diff --git a/chrome/browser/extensions/test_extension_service.cc b/chrome/browser/extensions/test_extension_service.cc
index c5ae36a..ae2c2b8 100644
--- a/chrome/browser/extensions/test_extension_service.cc
+++ b/chrome/browser/extensions/test_extension_service.cc
@@ -17,8 +17,7 @@
 }
 
 bool TestExtensionService::UpdateExtension(
-    const std::string& id,
-    const base::FilePath& path,
+    const extensions::CRXFileInfo& file,
     bool file_ownership_passed,
     extensions::CrxInstaller** out_crx_installer) {
   ADD_FAILURE();
diff --git a/chrome/browser/extensions/test_extension_service.h b/chrome/browser/extensions/test_extension_service.h
index e4409e35..64d0ab38 100644
--- a/chrome/browser/extensions/test_extension_service.h
+++ b/chrome/browser/extensions/test_extension_service.h
@@ -25,8 +25,7 @@
   // ExtensionServiceInterface implementation.
   extensions::PendingExtensionManager* pending_extension_manager() override;
 
-  bool UpdateExtension(const std::string& id,
-                       const base::FilePath& path,
+  bool UpdateExtension(const extensions::CRXFileInfo& file,
                        bool file_ownership_passed,
                        extensions::CrxInstaller** out_crx_installer) override;
   const extensions::Extension* GetExtensionById(
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index 0a373a9..ee47c897 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -189,17 +189,17 @@
 ExtensionUpdater::CheckParams::~CheckParams() {}
 
 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
-    const std::string& i,
-    const base::FilePath& p,
+    const CRXFileInfo& file,
     bool file_ownership_passed,
     const std::set<int>& request_ids)
-    : extension_id(i),
-      path(p),
+    : info(file),
       file_ownership_passed(file_ownership_passed),
-      request_ids(request_ids) {}
+      request_ids(request_ids) {
+}
 
 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
-    : path(), file_ownership_passed(true) {}
+    : file_ownership_passed(true) {
+}
 
 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
 
@@ -591,19 +591,18 @@
 }
 
 void ExtensionUpdater::OnExtensionDownloadFinished(
-    const std::string& id,
-    const base::FilePath& path,
+    const CRXFileInfo& file,
     bool file_ownership_passed,
     const GURL& download_url,
     const std::string& version,
     const PingResult& ping,
     const std::set<int>& request_ids) {
   DCHECK(alive_);
-  UpdatePingData(id, ping);
+  UpdatePingData(file.extension_id, ping);
 
-  VLOG(2) << download_url << " written to " << path.value();
+  VLOG(2) << download_url << " written to " << file.path.value();
 
-  FetchedCRXFile fetched(id, path, file_ownership_passed, request_ids);
+  FetchedCRXFile fetched(file, file_ownership_passed, request_ids);
   fetched_crx_files_.push(fetched);
 
   // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
@@ -682,14 +681,13 @@
   while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
     const FetchedCRXFile& crx_file = fetched_crx_files_.top();
 
-    VLOG(2) << "updating " << crx_file.extension_id
-            << " with " << crx_file.path.value();
+    VLOG(2) << "updating " << crx_file.info.extension_id
+            << " with " << crx_file.info.path.value();
 
     // The ExtensionService is now responsible for cleaning up the temp file
-    // at |crx_file.path|.
+    // at |crx_file.info.path|.
     CrxInstaller* installer = NULL;
-    if (service_->UpdateExtension(crx_file.extension_id,
-                                  crx_file.path,
+    if (service_->UpdateExtension(crx_file.info,
                                   crx_file.file_ownership_passed,
                                   &installer)) {
       crx_install_is_running_ = true;
@@ -713,7 +711,7 @@
       for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
            it != crx_file.request_ids.end(); ++it) {
         InProgressCheck& request = requests_in_progress_[*it];
-        request.in_progress_ids_.remove(crx_file.extension_id);
+        request.in_progress_ids_.remove(crx_file.info.extension_id);
       }
       request_ids.insert(crx_file.request_ids.begin(),
                          crx_file.request_ids.end());
@@ -739,7 +737,7 @@
   for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
       it != crx_file.request_ids.end(); ++it) {
     InProgressCheck& request = requests_in_progress_[*it];
-    request.in_progress_ids_.remove(crx_file.extension_id);
+    request.in_progress_ids_.remove(crx_file.info.extension_id);
     NotifyIfFinished(*it);
   }
 
diff --git a/chrome/browser/extensions/updater/extension_updater.h b/chrome/browser/extensions/updater/extension_updater.h
index 7e09908cf..169534fc 100644
--- a/chrome/browser/extensions/updater/extension_updater.h
+++ b/chrome/browser/extensions/updater/extension_updater.h
@@ -139,14 +139,12 @@
   // but have not yet installed.
   struct FetchedCRXFile {
     FetchedCRXFile();
-    FetchedCRXFile(const std::string& id,
-                   const base::FilePath& path,
+    FetchedCRXFile(const CRXFileInfo& file,
                    bool file_ownership_passed,
                    const std::set<int>& request_ids);
     ~FetchedCRXFile();
 
-    std::string extension_id;
-    base::FilePath path;
+    CRXFileInfo info;
     bool file_ownership_passed;
     std::set<int> request_ids;
   };
@@ -198,8 +196,7 @@
                                  Error error,
                                  const PingResult& ping,
                                  const std::set<int>& request_ids) override;
-  void OnExtensionDownloadFinished(const std::string& id,
-                                   const base::FilePath& path,
+  void OnExtensionDownloadFinished(const CRXFileInfo& file,
                                    bool file_ownership_passed,
                                    const GURL& download_url,
                                    const std::string& version,
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index b1e2f51..6afb075 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -145,13 +145,13 @@
                                                Error,
                                                const PingResult&,
                                                const std::set<int>&));
-  MOCK_METHOD7(OnExtensionDownloadFinished, void(const std::string&,
-                                                 const base::FilePath&,
-                                                 bool,
-                                                 const GURL&,
-                                                 const std::string&,
-                                                 const PingResult&,
-                                                 const std::set<int>&));
+  MOCK_METHOD6(OnExtensionDownloadFinished,
+               void(const extensions::CRXFileInfo&,
+                    bool,
+                    const GURL&,
+                    const std::string&,
+                    const PingResult&,
+                    const std::set<int>&));
   MOCK_METHOD2(GetPingDataForExtension,
                bool(const std::string&, ManifestFetchData::PingData*));
   MOCK_METHOD1(GetUpdateUrlData, std::string(const std::string&));
@@ -175,9 +175,10 @@
     ON_CALL(*this, OnExtensionDownloadFailed(_, _, _, _))
         .WillByDefault(Invoke(delegate,
             &ExtensionDownloaderDelegate::OnExtensionDownloadFailed));
-    ON_CALL(*this, OnExtensionDownloadFinished(_, _, _, _, _, _, _))
-        .WillByDefault(Invoke(delegate,
-            &ExtensionDownloaderDelegate::OnExtensionDownloadFinished));
+    ON_CALL(*this, OnExtensionDownloadFinished(_, _, _, _, _, _))
+        .WillByDefault(
+            Invoke(delegate,
+                   &ExtensionDownloaderDelegate::OnExtensionDownloadFinished));
     ON_CALL(*this, GetPingDataForExtension(_, _))
         .WillByDefault(Invoke(delegate,
             &ExtensionDownloaderDelegate::GetPingDataForExtension));
@@ -499,15 +500,14 @@
     fake_crx_installers_[id] = crx_installer;
   }
 
-  bool UpdateExtension(const std::string& id,
-                       const base::FilePath& extension_path,
+  bool UpdateExtension(const CRXFileInfo& file,
                        bool file_ownership_passed,
                        CrxInstaller** out_crx_installer) override {
-    extension_id_ = id;
-    install_path_ = extension_path;
+    extension_id_ = file.extension_id;
+    install_path_ = file.path;
 
-    if (ContainsKey(fake_crx_installers_, id)) {
-      *out_crx_installer = fake_crx_installers_[id];
+    if (ContainsKey(fake_crx_installers_, extension_id_)) {
+      *out_crx_installer = fake_crx_installers_[extension_id_];
       return true;
     }
 
@@ -1221,7 +1221,8 @@
       fetcher->set_response_code(200);
       fetcher->SetResponseFilePath(extension_file_path);
       EXPECT_CALL(delegate, OnExtensionDownloadFinished(
-          id, _, _, _, version.GetString(), _, requests));
+                                CRXFileInfo(id, extension_file_path, hash), _,
+                                _, version.GetString(), _, requests));
     }
     fetcher->delegate()->OnURLFetchComplete(fetcher);
 
diff --git a/chrome/browser/google/google_profile_helper.cc b/chrome/browser/google/google_profile_helper.cc
deleted file mode 100644
index d216622..0000000
--- a/chrome/browser/google/google_profile_helper.cc
+++ /dev/null
@@ -1,21 +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.
-
-#include "chrome/browser/google/google_profile_helper.h"
-
-#include "chrome/browser/google/google_url_tracker_factory.h"
-#include "components/google/core/browser/google_url_tracker.h"
-#include "components/google/core/browser/google_util.h"
-#include "url/gurl.h"
-
-namespace google_profile_helper {
-
-GURL GetGoogleHomePageURL(Profile* profile) {
-  const GoogleURLTracker* tracker =
-      GoogleURLTrackerFactory::GetForProfile(profile);
-  return tracker ?
-      tracker->google_url() : GURL(GoogleURLTracker::kDefaultGoogleHomepage);
-}
-
-}  // namespace google_profile_helper
diff --git a/chrome/browser/google/google_profile_helper.h b/chrome/browser/google/google_profile_helper.h
deleted file mode 100644
index ea58960..0000000
--- a/chrome/browser/google/google_profile_helper.h
+++ /dev/null
@@ -1,26 +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.
-//
-// Provides Google-related information for a given Profile.
-
-#ifndef CHROME_BROWSER_GOOGLE_GOOGLE_PROFILE_HELPER_H__
-#define CHROME_BROWSER_GOOGLE_GOOGLE_PROFILE_HELPER_H__
-
-#include <string>
-
-#include "base/basictypes.h"
-
-class GURL;
-class Profile;
-
-namespace google_profile_helper {
-
-// Returns the current Google homepage URL. Guaranteed to synchronously return
-// a value at all times (even during startup, in unittest mode or if |profile|
-// is NULL).
-GURL GetGoogleHomePageURL(Profile* profile);
-
-}  // namespace google_profile_helper
-
-#endif  // CHROME_BROWSER_GOOGLE_GOOGLE_PROFILE_HELPER_H__
diff --git a/chrome/browser/google/google_search_counter_android.h b/chrome/browser/google/google_search_counter_android.h
index b13013f4..89830c3 100644
--- a/chrome/browser/google/google_search_counter_android.h
+++ b/chrome/browser/google/google_search_counter_android.h
@@ -17,7 +17,7 @@
 class GoogleSearchCounterAndroid : content::NotificationObserver {
  public:
   explicit GoogleSearchCounterAndroid(Profile* profile);
-  virtual ~GoogleSearchCounterAndroid();
+  ~GoogleSearchCounterAndroid() override;
 
  private:
   friend class GoogleSearchCounterAndroidTest;
@@ -26,9 +26,9 @@
                              const content::NotificationDetails& details);
 
   // content::NotificationObserver:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) override;
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
 
   Profile* profile_;
   content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/google/google_search_counter_android_unittest.cc b/chrome/browser/google/google_search_counter_android_unittest.cc
index 3b8bf6e..0bd7d12 100644
--- a/chrome/browser/google/google_search_counter_android_unittest.cc
+++ b/chrome/browser/google/google_search_counter_android_unittest.cc
@@ -31,11 +31,11 @@
 class GoogleSearchCounterAndroidTest : public testing::Test {
  protected:
   GoogleSearchCounterAndroidTest();
-  virtual ~GoogleSearchCounterAndroidTest();
+  ~GoogleSearchCounterAndroidTest() override;
 
   // testing::Test
-  virtual void SetUp();
-  virtual void TearDown();
+  void SetUp() override;
+  void TearDown() override;
 
   // Test if |url| is a Google search for specific types. When |is_omnibox| is
   // true, this method will append Omnibox identifiers to the simulated URL
diff --git a/chrome/browser/history/android/android_cache_database_unittest.cc b/chrome/browser/history/android/android_cache_database_unittest.cc
index d67c997..8d51ffa 100644
--- a/chrome/browser/history/android/android_cache_database_unittest.cc
+++ b/chrome/browser/history/android/android_cache_database_unittest.cc
@@ -21,10 +21,10 @@
 class AndroidCacheDatabaseTest : public testing::Test {
  public:
   AndroidCacheDatabaseTest() {}
-  virtual ~AndroidCacheDatabaseTest() {}
+  ~AndroidCacheDatabaseTest() override {}
 
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     // Get a temporary directory for the test DB files.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     base::FilePath history_db_name_ =
diff --git a/chrome/browser/history/android/android_history_provider_service_unittest.cc b/chrome/browser/history/android/android_history_provider_service_unittest.cc
index ca59252..2fadfdc 100644
--- a/chrome/browser/history/android/android_history_provider_service_unittest.cc
+++ b/chrome/browser/history/android/android_history_provider_service_unittest.cc
@@ -40,11 +40,10 @@
         ui_thread_(BrowserThread::UI, &message_loop_),
         file_thread_(BrowserThread::FILE, &message_loop_) {
   }
-  virtual ~AndroidHistoryProviderServiceTest() {
-  }
+  ~AndroidHistoryProviderServiceTest() override {}
 
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     // Setup the testing profile, so the bookmark_model_sql_handler could
     // get the bookmark model from it.
     ASSERT_TRUE(profile_manager_.SetUp());
@@ -60,7 +59,7 @@
     service_.reset(new AndroidHistoryProviderService(testing_profile_));
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     testing_profile_->DestroyHistoryService();
     profile_manager_.DeleteTestingProfile(chrome::kInitialProfile);
     testing_profile_=NULL;
diff --git a/chrome/browser/history/android/android_provider_backend.cc b/chrome/browser/history/android/android_provider_backend.cc
index beecfe39..bf8d5b2 100644
--- a/chrome/browser/history/android/android_provider_backend.cc
+++ b/chrome/browser/history/android/android_provider_backend.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/history/android/android_provider_backend.h"
 
 #include "base/i18n/case_conversion.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/history/android/bookmark_model_sql_handler.h"
 #include "chrome/browser/history/history_backend.h"
 #include "components/history/core/browser/android/android_time.h"
diff --git a/chrome/browser/history/android/android_urls_database_unittest.cc b/chrome/browser/history/android/android_urls_database_unittest.cc
index cbc2755..dc1b65a 100644
--- a/chrome/browser/history/android/android_urls_database_unittest.cc
+++ b/chrome/browser/history/android/android_urls_database_unittest.cc
@@ -20,10 +20,10 @@
 class AndroidURLsMigrationTest : public HistoryUnitTestBase {
  public:
   AndroidURLsMigrationTest() {}
-  virtual ~AndroidURLsMigrationTest() {}
+  ~AndroidURLsMigrationTest() override {}
 
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     profile_.reset(new TestingProfile);
 
     base::FilePath data_path;
diff --git a/chrome/browser/history/android/bookmark_model_sql_handler.cc b/chrome/browser/history/android/bookmark_model_sql_handler.cc
index 4625f37..cd57bcba 100644
--- a/chrome/browser/history/android/bookmark_model_sql_handler.cc
+++ b/chrome/browser/history/android/bookmark_model_sql_handler.cc
@@ -6,7 +6,6 @@
 
 #include "base/logging.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
diff --git a/chrome/browser/history/android/bookmark_model_sql_handler.h b/chrome/browser/history/android/bookmark_model_sql_handler.h
index 58b14dc4..7f15600b 100644
--- a/chrome/browser/history/android/bookmark_model_sql_handler.h
+++ b/chrome/browser/history/android/bookmark_model_sql_handler.h
@@ -22,13 +22,13 @@
  public:
   explicit BookmarkModelSQLHandler(URLDatabase* url_database);
 
-  virtual ~BookmarkModelSQLHandler();
+  ~BookmarkModelSQLHandler() override;
 
   // SQLHandler overrides:
-  virtual bool Update(const HistoryAndBookmarkRow& row,
-                      const TableIDRows& ids_set) override;
-  virtual bool Delete(const TableIDRows& ids_set) override;
-  virtual bool Insert(HistoryAndBookmarkRow* row) override;
+  bool Update(const HistoryAndBookmarkRow& row,
+              const TableIDRows& ids_set) override;
+  bool Delete(const TableIDRows& ids_set) override;
+  bool Insert(HistoryAndBookmarkRow* row) override;
 
  private:
   // This class helps to modify the bookmark model in UI thread.
diff --git a/chrome/browser/history/android/bookmark_model_sql_handler_unittest.cc b/chrome/browser/history/android/bookmark_model_sql_handler_unittest.cc
index 5f7f1be33..508c7e2 100644
--- a/chrome/browser/history/android/bookmark_model_sql_handler_unittest.cc
+++ b/chrome/browser/history/android/bookmark_model_sql_handler_unittest.cc
@@ -34,10 +34,10 @@
         bookmark_model_(NULL),
         ui_thread_(BrowserThread::UI, &message_loop_),
         file_thread_(BrowserThread::FILE, &message_loop_) {}
-  virtual ~BookmarkModelSQLHandlerTest() {}
+  ~BookmarkModelSQLHandlerTest() override {}
 
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     // Setup the testing profile, so the bookmark_model_sql_handler could
     // get the bookmark model from it.
     ASSERT_TRUE(profile_manager_.SetUp());
diff --git a/chrome/browser/history/android/sqlite_cursor_unittest.cc b/chrome/browser/history/android/sqlite_cursor_unittest.cc
index 076eb449..c7aa0c2 100644
--- a/chrome/browser/history/android/sqlite_cursor_unittest.cc
+++ b/chrome/browser/history/android/sqlite_cursor_unittest.cc
@@ -48,11 +48,10 @@
         ui_thread_(BrowserThread::UI, &message_loop_),
         file_thread_(BrowserThread::FILE, &message_loop_) {
   }
-  virtual ~SQLiteCursorTest() {
-  }
+  ~SQLiteCursorTest() override {}
 
  protected:
-  virtual void SetUp() override {
+  void SetUp() override {
     // Setup the testing profile, so the bookmark_model_sql_handler could
     // get the bookmark model from it.
     ASSERT_TRUE(profile_manager_.SetUp());
@@ -72,28 +71,20 @@
         testing_profile_, ServiceAccessType::EXPLICIT_ACCESS);
   }
 
-  virtual void TearDown() override {
+  void TearDown() override {
     testing_profile_->DestroyHistoryService();
     profile_manager_.DeleteTestingProfile(chrome::kInitialProfile);
     testing_profile_ = NULL;
   }
 
   // Override SQLiteCursor::TestObserver.
-  virtual void OnPostMoveToTask() override {
-    base::MessageLoop::current()->Run();
-  }
+  void OnPostMoveToTask() override { base::MessageLoop::current()->Run(); }
 
-  virtual void OnGetMoveToResult() override {
-    base::MessageLoop::current()->Quit();
-  }
+  void OnGetMoveToResult() override { base::MessageLoop::current()->Quit(); }
 
-  virtual void OnPostGetFaviconTask() override {
-    base::MessageLoop::current()->Run();
-  }
+  void OnPostGetFaviconTask() override { base::MessageLoop::current()->Run(); }
 
-  virtual void OnGetFaviconResult() override {
-    base::MessageLoop::current()->Quit();
-  }
+  void OnGetFaviconResult() override { base::MessageLoop::current()->Quit(); }
 
  protected:
   TestingProfileManager profile_manager_;
diff --git a/chrome/browser/history/android/urls_sql_handler_unittest.cc b/chrome/browser/history/android/urls_sql_handler_unittest.cc
index 2c92eca3..623110b5 100644
--- a/chrome/browser/history/android/urls_sql_handler_unittest.cc
+++ b/chrome/browser/history/android/urls_sql_handler_unittest.cc
@@ -26,10 +26,10 @@
   UrlsSQLHandlerTest()
       : urls_sql_handler_(&history_db_),
         visit_sql_handler_(&history_db_, &history_db_) {}
-  virtual ~UrlsSQLHandlerTest() {}
+  ~UrlsSQLHandlerTest() override {}
 
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     // Get a temporary directory for the test DB files.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     base::FilePath history_db_name =
@@ -37,8 +37,7 @@
     ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name));
   }
 
-  virtual void TearDown() {
-  }
+  void TearDown() override {}
 
   TestHistoryDatabase history_db_;
   base::ScopedTempDir temp_dir_;
diff --git a/chrome/browser/history/android/visit_sql_handler_unittest.cc b/chrome/browser/history/android/visit_sql_handler_unittest.cc
index 3229d7ae..723b0fe 100644
--- a/chrome/browser/history/android/visit_sql_handler_unittest.cc
+++ b/chrome/browser/history/android/visit_sql_handler_unittest.cc
@@ -26,10 +26,10 @@
   VisitSQLHandlerTest()
       : urls_sql_handler_(&history_db_),
         visit_sql_handler_(&history_db_, &history_db_) {}
-  virtual ~VisitSQLHandlerTest() {}
+  ~VisitSQLHandlerTest() override {}
 
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     // Get a temporary directory for the test DB files.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     base::FilePath history_db_name =
@@ -37,8 +37,7 @@
     ASSERT_EQ(sql::INIT_OK, history_db_.Init(history_db_name));
   }
 
-  virtual void TearDown() {
-  }
+  void TearDown() override {}
 
   TestHistoryDatabase history_db_;
   base::ScopedTempDir temp_dir_;
diff --git a/chrome/browser/history/history_service.cc b/chrome/browser/history/history_service.cc
index e46633d..6adc6755b 100644
--- a/chrome/browser/history/history_service.cc
+++ b/chrome/browser/history/history_service.cc
@@ -741,8 +741,7 @@
       callback);
 }
 
-void HistoryService::GetNextDownloadId(
-    const content::DownloadIdCallback& callback) {
+void HistoryService::GetNextDownloadId(const DownloadIdCallback& callback) {
   DCHECK(thread_) << "History service being called after cleanup";
   DCHECK(thread_checker_.CalledOnValidThread());
   PostTaskAndReplyWithResult(
diff --git a/chrome/browser/history/history_service.h b/chrome/browser/history/history_service.h
index c14dafc4..b167f43 100644
--- a/chrome/browser/history/history_service.h
+++ b/chrome/browser/history/history_service.h
@@ -24,13 +24,11 @@
 #include "base/time/time.h"
 #include "chrome/browser/history/delete_directive_handler.h"
 #include "chrome/browser/history/typed_url_syncable_service.h"
-#include "chrome/common/ref_counted_util.h"
 #include "components/favicon_base/favicon_callback.h"
 #include "components/history/core/browser/history_client.h"
 #include "components/history/core/browser/keyword_id.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/visitedlink/browser/visitedlink_delegate.h"
-#include "content/public/browser/download_manager_delegate.h"
 #include "sql/init_status.h"
 #include "sync/api/syncable_service.h"
 #include "ui/base/page_transition_types.h"
@@ -379,9 +377,13 @@
       const history::DownloadRow& info,
       const DownloadCreateCallback& callback);
 
+  // Implemented by the caller of 'GetNextDownloadId' below, and is called with
+  // the maximum id of all downloads records in the database plus 1.
+  typedef base::Callback<void(uint32)> DownloadIdCallback;
+
   // Responds on the calling thread with the maximum id of all downloads records
   // in the database plus 1.
-  void GetNextDownloadId(const content::DownloadIdCallback& callback);
+  void GetNextDownloadId(const DownloadIdCallback& callback);
 
   // Implemented by the caller of 'QueryDownloads' below, and is called when the
   // history service has retrieved a list of all download state. The call
diff --git a/chrome/browser/interstitials/security_interstitial_uma_helper.cc b/chrome/browser/interstitials/security_interstitial_metrics_helper.cc
similarity index 64%
rename from chrome/browser/interstitials/security_interstitial_uma_helper.cc
rename to chrome/browser/interstitials/security_interstitial_metrics_helper.cc
index aade7ff..322220e 100644
--- a/chrome/browser/interstitials/security_interstitial_uma_helper.cc
+++ b/chrome/browser/interstitials/security_interstitial_metrics_helper.cc
@@ -2,56 +2,88 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/interstitials/security_interstitial_uma_helper.h"
+#include "chrome/browser/interstitials/security_interstitial_metrics_helper.h"
+
+#include <string>
 
 #include "base/metrics/histogram.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/webdata/web_data_service_factory.h"
+#include "components/rappor/rappor_service.h"
 #include "content/public/browser/web_contents.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 
 #if defined(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
 #endif
 
-SecurityInterstitialUmaHelper::SecurityInterstitialUmaHelper(
+SecurityInterstitialMetricsHelper::SecurityInterstitialMetricsHelper(
     content::WebContents* web_contents,
     const GURL& request_url,
-    const std::string& histogram_prefix,
+    const std::string& uma_prefix,
+    const std::string& rappor_prefix,
+    RapporReporting rappor_reporting,
     const std::string& sampling_event_name)
     : web_contents_(web_contents),
       request_url_(request_url),
-      histogram_prefix_(histogram_prefix),
+      uma_prefix_(uma_prefix),
+      rappor_prefix_(rappor_prefix),
+      rappor_reporting_(rappor_reporting),
       sampling_event_name_(sampling_event_name),
       num_visits_(-1) {
+  DCHECK(!uma_prefix_.empty());
+  DCHECK(!rappor_prefix_.empty());
+  DCHECK(!sampling_event_name_.empty());
   HistoryService* history_service = HistoryServiceFactory::GetForProfile(
       Profile::FromBrowserContext(web_contents->GetBrowserContext()),
       ServiceAccessType::EXPLICIT_ACCESS);
   if (history_service) {
     history_service->GetVisibleVisitCountToHost(
         request_url_,
-        base::Bind(&SecurityInterstitialUmaHelper::OnGotHistoryCount,
+        base::Bind(&SecurityInterstitialMetricsHelper::OnGotHistoryCount,
                    base::Unretained(this)),
         &request_tracker_);
   }
 }
 
-SecurityInterstitialUmaHelper::~SecurityInterstitialUmaHelper() {
+SecurityInterstitialMetricsHelper::~SecurityInterstitialMetricsHelper() {
 }
 
-// Directly adds to the histograms, using the same properties as
+// Directly adds to the UMA histograms, using the same properties as
 // UMA_HISTOGRAM_ENUMERATION, because the macro doesn't allow non-constant
-// histogram names.
-void SecurityInterstitialUmaHelper::RecordUserDecision(
+// histogram names.  Reports to Rappor for certain decisions.
+void SecurityInterstitialMetricsHelper::RecordUserDecision(
     SecurityInterstitialDecision decision) {
+  // UMA
   std::string decision_histogram_name(
-      "interstitial." + histogram_prefix_ + ".decision");
+      "interstitial." + uma_prefix_ + ".decision");
   base::HistogramBase* decision_histogram = base::LinearHistogram::FactoryGet(
       decision_histogram_name, 1, MAX_DECISION, MAX_DECISION + 1,
       base::HistogramBase::kUmaTargetedHistogramFlag);
   decision_histogram->Add(decision);
 
+  // Rappor
+  rappor::RapporService* rappor_service = g_browser_process->rappor_service();
+  if (rappor_service && rappor_reporting_ == REPORT_RAPPOR &&
+      (decision == PROCEED || decision == DONT_PROCEED)) {
+    // |domain| will be empty for hosts w/o TLDs (localhost, ip addrs)
+    const std::string domain =
+        net::registry_controlled_domains::GetDomainAndRegistry(
+            request_url_,
+            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+
+    // e.g. "interstitial.malware.domain" or "interstitial.ssl.domain"
+    const std::string metric_name =
+        "interstitial." + rappor_prefix_ + ".domain";
+    rappor_service->RecordSample(metric_name, rappor::COARSE_RAPPOR_TYPE,
+                                 domain);
+    // TODO(nparker): Add reporting of (num_visits > 0) and decision
+    // once http://crbug.com/451647 is fixed.
+  }
+
 #if defined(ENABLE_EXTENSIONS)
   if (!sampling_event_.get()) {
     sampling_event_.reset(new extensions::ExperienceSamplingEvent(
@@ -81,7 +113,7 @@
   if (num_visits_ < 1 || (decision != PROCEED && decision != DONT_PROCEED))
     return;
   std::string history_histogram_name(
-      "interstitial." + histogram_prefix_ + ".decision.repeat_visit");
+      "interstitial." + uma_prefix_ + ".decision.repeat_visit");
   base::HistogramBase* history_histogram = base::LinearHistogram::FactoryGet(
       history_histogram_name, 1, MAX_DECISION, MAX_DECISION + 1,
       base::HistogramBase::kUmaTargetedHistogramFlag);
@@ -89,10 +121,10 @@
   history_histogram->Add(decision);
 }
 
-void SecurityInterstitialUmaHelper::RecordUserInteraction(
+void SecurityInterstitialMetricsHelper::RecordUserInteraction(
     SecurityInterstitialInteraction interaction) {
   std::string interaction_histogram_name(
-      "interstitial." + histogram_prefix_ + ".interaction");
+      "interstitial." + uma_prefix_ + ".interaction");
   base::HistogramBase* interaction_histogram =
       base::LinearHistogram::FactoryGet(
           interaction_histogram_name, 1, MAX_INTERACTION, MAX_INTERACTION + 1,
@@ -125,7 +157,7 @@
 #endif
 }
 
-void SecurityInterstitialUmaHelper::OnGotHistoryCount(
+void SecurityInterstitialMetricsHelper::OnGotHistoryCount(
     bool success,
     int num_visits,
     base::Time first_visit) {
diff --git a/chrome/browser/interstitials/security_interstitial_metrics_helper.h b/chrome/browser/interstitials/security_interstitial_metrics_helper.h
new file mode 100644
index 0000000..1808852
--- /dev/null
+++ b/chrome/browser/interstitials/security_interstitial_metrics_helper.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_INTERSTITIALS_SECURITY_INTERSTITIAL_METRICS_HELPER_H_
+#define CHROME_BROWSER_INTERSTITIALS_SECURITY_INTERSTITIAL_METRICS_HELPER_H_
+
+#include <string>
+
+#include "base/task/cancelable_task_tracker.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+class ExperienceSamplingEvent;
+}
+
+// Most of the security interstitials share a common layout and set of
+// choices. SecurityInterstitialMetricsHelper is intended to help the security
+// interstitials record user choices in a common way via METRICS histograms
+// and RAPPOR metrics.
+class SecurityInterstitialMetricsHelper {
+ public:
+  // These enums are used for histograms.  Don't reorder, delete, or insert
+  // elements. New elements should be added at the end (right before the max).
+  enum SecurityInterstitialDecision {
+    SHOW,
+    PROCEED,
+    DONT_PROCEED,
+    PROCEEDING_DISABLED,
+    MAX_DECISION
+  };
+  enum SecurityInterstitialInteraction {
+    TOTAL_VISITS,
+    SHOW_ADVANCED,
+    SHOW_PRIVACY_POLICY,
+    SHOW_DIAGNOSTIC,
+    SHOW_LEARN_MORE,
+    RELOAD,
+    OPEN_TIME_SETTINGS,
+    MAX_INTERACTION
+  };
+
+  enum RapporReporting {
+    REPORT_RAPPOR,
+    SKIP_RAPPOR,
+  };
+
+  // Args:
+  //   url: URL of page that triggered the interstitial. Only origin is used.
+  //   uma_prefix: Histogram prefix for UMA.
+  //               examples: "phishing", "ssl_overridable"
+  //   rappor_prefix: Metric prefix for Rappor.
+  //               examples: "phishing", "ssl"
+  //   rappor_reporting: Used to skip rappor rapporting if desired.
+  //   sampling_event_name: Event name for Experience Sampling.
+  //                        e.g. "phishing_interstitial_"
+  SecurityInterstitialMetricsHelper(content::WebContents* web_contents,
+                                    const GURL& url,
+                                    const std::string& uma_prefix,
+                                    const std::string& rappor_prefix,
+                                    RapporReporting rappor_reporting,
+                                    const std::string& sampling_event_name);
+  ~SecurityInterstitialMetricsHelper();
+
+  // Record a user decision or interaction to the appropriate UMA histogram
+  // and potentially in a RAPPOR metric.
+  void RecordUserDecision(SecurityInterstitialDecision decision);
+  void RecordUserInteraction(SecurityInterstitialInteraction interaction);
+
+ private:
+  // Used to query the HistoryService to see if the URL is in history.
+  void OnGotHistoryCount(bool success, int num_visits, base::Time first_visit);
+
+  content::WebContents* web_contents_;
+  const GURL request_url_;
+  const std::string uma_prefix_;
+  const std::string rappor_prefix_;
+  const RapporReporting rappor_reporting_;
+  const std::string sampling_event_name_;
+  int num_visits_;
+  base::CancelableTaskTracker request_tracker_;
+#if defined(ENABLE_EXTENSIONS)
+  scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(SecurityInterstitialMetricsHelper);
+};
+
+#endif  // CHROME_BROWSER_INTERSTITIALS_SECURITY_INTERSTITIAL_METRICS_HELPER_H_
diff --git a/chrome/browser/interstitials/security_interstitial_uma_helper.h b/chrome/browser/interstitials/security_interstitial_uma_helper.h
deleted file mode 100644
index ffb465d4..0000000
--- a/chrome/browser/interstitials/security_interstitial_uma_helper.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_INTERSTITIALS_SECURITY_INTERSTITIAL_UMA_HELPER_H_
-#define CHROME_BROWSER_INTERSTITIALS_SECURITY_INTERSTITIAL_UMA_HELPER_H_
-
-#include "base/task/cancelable_task_tracker.h"
-#include "base/time/time.h"
-#include "url/gurl.h"
-
-namespace content {
-class WebContents;
-}
-
-namespace extensions {
-class ExperienceSamplingEvent;
-}
-
-// Most of the security interstitials share a common layout and set of
-// choices. SecurityInterstitialUmaHelper is intended to help the security
-// interstitials record user choices in a common way via UMA histograms.
-class SecurityInterstitialUmaHelper {
- public:
-  // These enums are used for histograms.  Don't reorder, delete, or insert
-  // elements. New elements should be added at the end (right before the max).
-  enum SecurityInterstitialDecision {
-    SHOW,
-    PROCEED,
-    DONT_PROCEED,
-    PROCEEDING_DISABLED,
-    MAX_DECISION
-  };
-  enum SecurityInterstitialInteraction {
-    TOTAL_VISITS,
-    SHOW_ADVANCED,
-    SHOW_PRIVACY_POLICY,
-    SHOW_DIAGNOSTIC,
-    SHOW_LEARN_MORE,
-    RELOAD,
-    OPEN_TIME_SETTINGS,
-    MAX_INTERACTION
-  };
-
-  SecurityInterstitialUmaHelper(content::WebContents* web_contents,
-                                const GURL& url,
-                                const std::string& histogram_prefix,
-                                const std::string& sampling_event_name);
-  ~SecurityInterstitialUmaHelper();
-
-  // Record a user decision or interaction to the appropriate UMA histogram.
-  void RecordUserDecision(SecurityInterstitialDecision decision);
-  void RecordUserInteraction(SecurityInterstitialInteraction interaction);
-
- private:
-  // Used to query the HistoryService to see if the URL is in history.
-  void OnGotHistoryCount(bool success, int num_visits, base::Time first_visit);
-
-  content::WebContents* web_contents_;
-  const GURL request_url_;
-  const std::string histogram_prefix_;
-  const std::string sampling_event_name_;
-  int num_visits_;
-  base::CancelableTaskTracker request_tracker_;
-#if defined(ENABLE_EXTENSIONS)
-  scoped_ptr<extensions::ExperienceSamplingEvent> sampling_event_;
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(SecurityInterstitialUmaHelper);
-};
-
-#endif  // CHROME_BROWSER_INTERSTITIALS_SECURITY_INTERSTITIAL_UMA_HELPER_H_
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.h b/chrome/browser/invalidation/profile_invalidation_provider_factory.h
index 2e45328..5d475cd 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.h
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.h
@@ -10,8 +10,7 @@
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 namespace policy {
-class AffiliatedInvalidationServiceProviderTest;
-class DeviceCloudPolicyInvalidatorTest;
+class AffiliatedInvalidationServiceProviderImplTest;
 }
 
 namespace user_prefs {
@@ -49,8 +48,7 @@
 
  private:
   friend class ProfileInvalidationProviderFactoryTestBase;
-  friend class policy::AffiliatedInvalidationServiceProviderTest;
-  friend class policy::DeviceCloudPolicyInvalidatorTest;
+  friend class policy::AffiliatedInvalidationServiceProviderImplTest;
   friend struct DefaultSingletonTraits<ProfileInvalidationProviderFactory>;
 
   ProfileInvalidationProviderFactory();
diff --git a/chrome/browser/media/OWNERS b/chrome/browser/media/OWNERS
index 28093d9..6bd9a3c 100644
--- a/chrome/browser/media/OWNERS
+++ b/chrome/browser/media/OWNERS
@@ -3,7 +3,6 @@
 scherkus@chromium.org
 sergeyu@chromium.org
 tommi@chromium.org
-vrk@chromium.org
 xhwang@chromium.org
 
 per-file cast_*=hclam@chromium.org
diff --git a/chrome/browser/metrics/android_metrics_provider.h b/chrome/browser/metrics/android_metrics_provider.h
index 23ff210..6582682 100644
--- a/chrome/browser/metrics/android_metrics_provider.h
+++ b/chrome/browser/metrics/android_metrics_provider.h
@@ -21,12 +21,12 @@
  public:
   // Creates the AndroidMetricsProvider with the given |local_state|.
   explicit AndroidMetricsProvider(PrefService* local_state);
-  virtual ~AndroidMetricsProvider();
+  ~AndroidMetricsProvider() override;
 
   // metrics::MetricsProvider:
-  virtual void ProvideStabilityMetrics(
+  void ProvideStabilityMetrics(
       metrics::SystemProfileProto* system_profile_proto) override;
-  virtual void ProvideGeneralMetrics(
+  void ProvideGeneralMetrics(
       metrics::ChromeUserMetricsExtension* uma_proto) override;
 
   // Called when the Activity that the user interacts with is swapped out.
diff --git a/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc b/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
index 2bd9218..89707577 100644
--- a/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/chromeos_metrics_provider_unittest.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/metrics/chromeos_metrics_provider.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -120,7 +120,8 @@
   std::string user3("user3@example.com");
 
   // |scoped_enabler| takes over the lifetime of |user_manager|.
-  chromeos::FakeUserManager* user_manager = new chromeos::FakeUserManager();
+  chromeos::FakeChromeUserManager* user_manager =
+      new chromeos::FakeChromeUserManager();
   chromeos::ScopedUserManagerEnabler scoped_enabler(user_manager);
   user_manager->AddKioskAppUser(user1);
   user_manager->AddKioskAppUser(user2);
@@ -142,7 +143,8 @@
   std::string user3("user3@example.com");
 
   // |scoped_enabler| takes over the lifetime of |user_manager|.
-  chromeos::FakeUserManager* user_manager = new chromeos::FakeUserManager();
+  chromeos::FakeChromeUserManager* user_manager =
+      new chromeos::FakeChromeUserManager();
   chromeos::ScopedUserManagerEnabler scoped_enabler(user_manager);
   user_manager->AddKioskAppUser(user1);
   user_manager->AddKioskAppUser(user2);
diff --git a/chrome/browser/net/spdyproxy/OWNERS b/chrome/browser/net/spdyproxy/OWNERS
index a46d1ea..952891ee 100644
--- a/chrome/browser/net/spdyproxy/OWNERS
+++ b/chrome/browser/net/spdyproxy/OWNERS
@@ -1,2 +1,3 @@
 bengr@chromium.org
 marq@chromium.org
+sclittle@chromium.org
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
index ce1f7c96..1297c62 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -30,8 +30,17 @@
 // hierarchy. This method removes the Data Reduction Proxy configuration from
 // prefs, if present. |proxy_pref_name| is the name of the proxy pref.
 void MigrateDataReductionProxyOffProxyPrefs(PrefService* prefs) {
-  DictionaryPrefUpdate update(prefs, prefs::kProxy);
-  base::DictionaryValue* dict = update.Get();
+  base::DictionaryValue* dict =
+      (base::DictionaryValue*) prefs->GetUserPrefValue(prefs::kProxy);
+  if (!dict)
+    return;
+
+  // Clear empty "proxy" dictionary created by a bug. See http://crbug/448172
+  if (dict->empty()) {
+    prefs->ClearPref(prefs::kProxy);
+    return;
+  }
+
   std::string mode;
   if (!dict->GetString("mode", &mode))
     return;
@@ -46,9 +55,7 @@
           ContainsDataReductionProxy(proxy_rules)) {
     return;
   }
-  dict->SetString("mode", ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
-  dict->SetString("server", "");
-  dict->SetString("bypass_list", "");
+  prefs->ClearPref(prefs::kProxy);
 }
 
 DataReductionProxyChromeSettings::DataReductionProxyChromeSettings(
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
index d60ba1d4..4248c272 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
@@ -39,9 +39,7 @@
         settings_(settings) {}
 
   // Returns the provided setting object. Used by wrapping methods.
-  virtual DataReductionProxySettings* Settings() override {
-    return settings_;
-  }
+  DataReductionProxySettings* Settings() override { return settings_; }
 
   // The wrapped settings object.
   DataReductionProxySettings* settings_;
@@ -126,7 +124,7 @@
           DataReductionProxyChromeSettings> {
  public:
   // DataReductionProxySettingsTest implementation:
-  virtual void SetUp() override {
+  void SetUp() override {
     env_ = base::android::AttachCurrentThread();
     DataReductionProxySettingsAndroid::Register(env_);
     DataReductionProxySettingsTestBase::SetUp();
diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
index 4b44208..cd8e18b 100644
--- a/chrome/browser/notifications/message_center_settings_controller_unittest.cc
+++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
@@ -21,7 +21,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/system/system_notifier.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #endif
 
@@ -74,8 +74,8 @@
     MessageCenterSettingsControllerBaseTest::SetUp();
 
     // Initialize the UserManager singleton to a fresh FakeUserManager instance.
-    user_manager_enabler_.reset(
-        new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
+    user_manager_enabler_.reset(new chromeos::ScopedUserManagerEnabler(
+        new chromeos::FakeChromeUserManager));
   }
 
   void TearDown() override {
@@ -98,8 +98,8 @@
   }
 
  private:
-  chromeos::FakeUserManager* GetFakeUserManager() {
-    return static_cast<chromeos::FakeUserManager*>(
+  chromeos::FakeChromeUserManager* GetFakeUserManager() {
+    return static_cast<chromeos::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
   }
 
diff --git a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h
index be155f8..1122cf4 100644
--- a/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h
+++ b/chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h
@@ -39,8 +39,8 @@
   GeneratedPasswordSavedInfoBarDelegateAndroid();
 
   // InfoBarDelegate implementation:
-  virtual int GetIconID() const override;
-  virtual Type GetInfoBarType() const override;
+  int GetIconID() const override;
+  Type GetInfoBarType() const override;
 
   // The translated text of the message to display.
   base::string16 message_text_;
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc
index b3571d6..bf98cd1 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x.cc
@@ -31,6 +31,10 @@
 using base::UTF16ToUTF8;
 using content::BrowserThread;
 
+namespace {
+const int kMaxPossibleTimeTValue = std::numeric_limits<int>::max();
+}
+
 #define GNOME_KEYRING_DEFINE_POINTER(name) \
   typeof(&::gnome_keyring_##name) GnomeKeyringLoader::gnome_keyring_##name;
 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_DEFINE_POINTER)
@@ -131,7 +135,15 @@
   bool date_ok = base::StringToInt64(string_attr_map["date_created"],
                                      &date_created);
   DCHECK(date_ok);
-  form->date_created = base::Time::FromTimeT(date_created);
+  // In the past |date_created| was stored as time_t. Currently is stored as
+  // base::Time's internal value. We need to distinguish, which format the
+  // number in |date_created| was stored in. We use the fact that
+  // kMaxPossibleTimeTValue interpreted as the internal value corresponds to an
+  // unlikely date back in 17th century, and anything above
+  // kMaxPossibleTimeTValue clearly must be in the internal value format.
+  form->date_created = date_created < kMaxPossibleTimeTValue
+                           ? base::Time::FromTimeT(date_created)
+                           : base::Time::FromInternalValue(date_created);
   form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"];
   form->type = static_cast<PasswordForm::Type>(uint_attr_map["type"]);
   form->times_used = uint_attr_map["times_used"];
@@ -142,7 +154,7 @@
   form->display_name = UTF8ToUTF16(string_attr_map["display_name"]);
   form->avatar_url = GURL(string_attr_map["avatar_url"]);
   form->federation_url = GURL(string_attr_map["federation_url"]);
-  form->is_zero_click = uint_attr_map["is_zero_click"];
+  form->skip_zero_click = uint_attr_map["skip_zero_click"];
 
   return form.Pass();
 }
@@ -230,7 +242,7 @@
     { "display_name", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
     { "avatar_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
     { "federation_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
-    { "is_zero_click", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
+    { "skip_zero_click", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32 },
     // This field is always "chrome" so that we can search for it.
     { "application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
     { NULL }
@@ -317,11 +329,11 @@
 
 void GKRMethod::AddLogin(const PasswordForm& form, const char* app_string) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  time_t date_created = form.date_created.ToTimeT();
+  int64 date_created = form.date_created.ToInternalValue();
   // If we are asked to save a password with 0 date, use the current time.
-  // We don't want to actually save passwords as though on January 1, 1970.
+  // We don't want to actually save passwords as though on January 1, 1601.
   if (!date_created)
-    date_created = time(NULL);
+    date_created = base::Time::Now().ToInternalValue();
   int64 date_synced = form.date_synced.ToInternalValue();
   gnome_keyring_store_password(
       &kGnomeSchema,
@@ -349,7 +361,7 @@
       "display_name", UTF16ToUTF8(form.display_name).c_str(),
       "avatar_url", form.avatar_url.spec().c_str(),
       "federation_url", form.federation_url.spec().c_str(),
-      "is_zero_click", form.is_zero_click,
+      "skip_zero_click", form.skip_zero_click,
       "application", app_string,
       NULL);
 }
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
index 0f144b9e..8a1c29624 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
@@ -298,8 +298,7 @@
     EXPECT_EQ(expected.signon_realm, actual.signon_realm);
     EXPECT_EQ(expected.ssl_valid, actual.ssl_valid);
     EXPECT_EQ(expected.preferred, actual.preferred);
-    // We don't check the date created. It varies due to bug in the
-    // serialization. Integer seconds are saved instead of microseconds.
+    EXPECT_EQ(expected.date_created, actual.date_created);
     EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user);
     EXPECT_EQ(expected.type, actual.type);
     EXPECT_EQ(expected.times_used, actual.times_used);
@@ -308,7 +307,7 @@
     EXPECT_EQ(expected.display_name, actual.display_name);
     EXPECT_EQ(expected.avatar_url, actual.avatar_url);
     EXPECT_EQ(expected.federation_url, actual.federation_url);
-    EXPECT_EQ(expected.is_zero_click, actual.is_zero_click);
+    EXPECT_EQ(expected.skip_zero_click, actual.skip_zero_click);
   }
 }
 
@@ -356,7 +355,7 @@
     form_google_.display_name = UTF8ToUTF16("Joe Schmoe");
     form_google_.avatar_url = GURL("http://www.google.com/avatar");
     form_google_.federation_url = GURL("http://www.google.com/federation_url");
-    form_google_.is_zero_click = true;
+    form_google_.skip_zero_click = true;
 
     form_facebook_.origin = GURL("http://www.facebook.com/");
     form_facebook_.action = GURL("http://www.facebook.com/login");
@@ -371,7 +370,7 @@
     form_facebook_.display_name = UTF8ToUTF16("Joe Schmoe");
     form_facebook_.avatar_url = GURL("http://www.facebook.com/avatar");
     form_facebook_.federation_url = GURL("http://www.facebook.com/federation");
-    form_facebook_.is_zero_click = true;
+    form_facebook_.skip_zero_click = true;
 
     form_isc_.origin = GURL("http://www.isc.org/");
     form_isc_.action = GURL("http://www.isc.org/auth");
@@ -469,7 +468,7 @@
     CheckStringAttribute(item, "display_name", UTF16ToUTF8(form.display_name));
     CheckStringAttribute(item, "avatar_url", form.avatar_url.spec());
     CheckStringAttribute(item, "federation_url", form.federation_url.spec());
-    CheckUint32Attribute(item, "is_zero_click", form.is_zero_click);
+    CheckUint32Attribute(item, "skip_zero_click", form.skip_zero_click);
     CheckStringAttribute(item, "application", app_string);
   }
 
@@ -663,15 +662,13 @@
     NativeBackendGnome backend(42);
     backend.Init();
 
-    form_google_.date_synced = base::Time();
-    form_isc_.date_synced = base::Time();
-    form_google_.date_created = base::Time();
-    form_isc_.date_created = base::Time();
     base::Time now = base::Time::Now();
     base::Time next_day = now + base::TimeDelta::FromDays(1);
+    form_google_.date_synced = base::Time();
+    form_isc_.date_synced = base::Time();
+    form_google_.date_created = now;
+    form_isc_.date_created = now;
     if (date_to_test == CREATED) {
-      // crbug/374132. Remove the next line once it's fixed.
-      next_day = base::Time::FromTimeT(next_day.ToTimeT());
       form_google_.date_created = now;
       form_isc_.date_created = next_day;
     } else {
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.cc b/chrome/browser/password_manager/native_backend_kwallet_x.cc
index 55958b1..f31310b 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.cc
@@ -722,7 +722,7 @@
     pickle->WriteBool(form->ssl_valid);
     pickle->WriteBool(form->preferred);
     pickle->WriteBool(form->blacklisted_by_user);
-    pickle->WriteInt64(form->date_created.ToTimeT());
+    pickle->WriteInt64(form->date_created.ToInternalValue());
     pickle->WriteInt(form->type);
     pickle->WriteInt(form->times_used);
     autofill::SerializeFormData(form->form_data, pickle);
@@ -730,7 +730,7 @@
     pickle->WriteString16(form->display_name);
     pickle->WriteString(form->avatar_url.spec());
     pickle->WriteString(form->federation_url.spec());
-    pickle->WriteBool(form->is_zero_click);
+    pickle->WriteBool(form->skip_zero_click);
   }
 }
 
@@ -801,7 +801,6 @@
       return false;
     }
     form->scheme = static_cast<PasswordForm::Scheme>(scheme);
-    form->date_created = base::Time::FromTimeT(date_created);
 
     if (version > 1) {
       if (!iter.ReadInt(&type) ||
@@ -826,12 +825,18 @@
       if (!iter.ReadString16(&form->display_name) ||
           !ReadGURL(&iter, warn_only, &form->avatar_url) ||
           !ReadGURL(&iter, warn_only, &form->federation_url) ||
-          !iter.ReadBool(&form->is_zero_click)) {
+          !iter.ReadBool(&form->skip_zero_click)) {
         LogDeserializationWarning(version, signon_realm, false);
         return false;
       }
     }
 
+    if (version > 4) {
+      form->date_created = base::Time::FromInternalValue(date_created);
+    } else {
+      form->date_created = base::Time::FromTimeT(date_created);
+    }
+
     forms->push_back(form.release());
   }
 
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.h b/chrome/browser/password_manager/native_backend_kwallet_x.h
index 2ed7aab..116cf6fa 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.h
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.h
@@ -142,7 +142,7 @@
 
   // In case the fields in the pickle ever change, version them so we can try to
   // read old pickles. (Note: do not eat old pickles past the expiration date.)
-  static const int kPickleVersion = 4;
+  static const int kPickleVersion = 5;
 
   // Generates a profile-specific folder name based on profile_id_.
   std::string GetProfileSpecificFolderName() const;
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
index 53de5ba..edfbdc05 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
@@ -157,6 +157,7 @@
     old_form_google_.password_value = UTF8ToUTF16("seekrit");
     old_form_google_.submit_element = UTF8ToUTF16("submit");
     old_form_google_.signon_realm = "Google";
+    old_form_google_.date_created = base::Time::Now();
 
     form_google_ = old_form_google_;
     form_google_.times_used = 3;
@@ -164,10 +165,11 @@
     form_google_.form_data.name = UTF8ToUTF16("form_name");
     form_google_.form_data.user_submitted = true;
     form_google_.date_synced = base::Time::Now();
+    form_google_.date_created = old_form_google_.date_created;
     form_google_.display_name = UTF8ToUTF16("Joe Schmoe");
     form_google_.avatar_url = GURL("http://www.google.com/avatar");
     form_google_.federation_url = GURL("http://www.google.com/federation_url");
-    form_google_.is_zero_click = true;
+    form_google_.skip_zero_click = true;
 
     form_isc_.origin = GURL("http://www.isc.org/");
     form_isc_.action = GURL("http://www.isc.org/auth");
@@ -178,10 +180,12 @@
     form_isc_.submit_element = UTF8ToUTF16("login");
     form_isc_.signon_realm = "ISC";
     form_isc_.date_synced = base::Time::Now();
+    form_isc_.date_created = base::Time::Now();
   }
 
   static void CheckPasswordForm(const PasswordForm& expected,
-                                const PasswordForm& actual);
+                                const PasswordForm& actual,
+                                bool check_date_created);
   static void CheckPasswordChanges(const PasswordStoreChangeList& expected,
                                    const PasswordStoreChangeList& actual);
   static void CheckPasswordChangesWithResult(
@@ -196,7 +200,9 @@
 
 // static
 void NativeBackendKWalletTestBase::CheckPasswordForm(
-    const PasswordForm& expected, const PasswordForm& actual) {
+    const PasswordForm& expected,
+    const PasswordForm& actual,
+    bool check_date_created) {
   EXPECT_EQ(expected.origin, actual.origin);
   EXPECT_EQ(expected.password_value, actual.password_value);
   EXPECT_EQ(expected.action, actual.action);
@@ -207,7 +213,9 @@
   EXPECT_EQ(expected.signon_realm, actual.signon_realm);
   EXPECT_EQ(expected.ssl_valid, actual.ssl_valid);
   EXPECT_EQ(expected.preferred, actual.preferred);
-  // We don't check the date created. It varies.
+  if (check_date_created) {
+    EXPECT_EQ(expected.date_created, actual.date_created);
+  }
   EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user);
   EXPECT_EQ(expected.type, actual.type);
   EXPECT_EQ(expected.times_used, actual.times_used);
@@ -216,7 +224,7 @@
   EXPECT_EQ(expected.display_name, actual.display_name);
   EXPECT_EQ(expected.avatar_url, actual.avatar_url);
   EXPECT_EQ(expected.federation_url, actual.federation_url);
-  EXPECT_EQ(expected.is_zero_click, actual.is_zero_click);
+  EXPECT_EQ(expected.skip_zero_click, actual.skip_zero_click);
 }
 
 // static
@@ -226,7 +234,7 @@
   ASSERT_EQ(expected.size(), actual.size());
   for (size_t i = 0; i < expected.size(); ++i) {
     EXPECT_EQ(expected[i].type(), actual[i].type());
-    CheckPasswordForm(expected[i].form(), actual[i].form());
+    CheckPasswordForm(expected[i].form(), actual[i].form(), true);
   }
 }
 
@@ -365,8 +373,6 @@
   base::Time now = base::Time::Now();
   base::Time next_day = now + base::TimeDelta::FromDays(1);
   if (date_to_test == CREATED) {
-    // crbug/374132. Remove the next line once it's fixed.
-    next_day = base::Time::FromTimeT(next_day.ToTimeT());
     form_google_.date_created = now;
     form_isc_.date_created = next_day;
   } else {
@@ -604,7 +610,7 @@
     const std::vector<const PasswordForm*>& expect = sorted_expected[i].second;
     EXPECT_EQ(expect.size(), forms.size());
     for (size_t j = 0; j < forms.size() && j < expect.size(); ++j)
-      CheckPasswordForm(*expect[j], *forms[j]);
+      CheckPasswordForm(*expect[j], *forms[j], true);
   }
 }
 
@@ -923,25 +929,49 @@
 
 class NativeBackendKWalletPickleTest : public NativeBackendKWalletTestBase {
  protected:
+  void CreateVersion5Pickle(const PasswordForm& form, Pickle* pickle);
   void CreateVersion3Pickle(const PasswordForm& form, Pickle* pickle);
   void CreateVersion2Pickle(const PasswordForm& form, Pickle* pickle);
   void CreateVersion1Pickle(const PasswordForm& form, Pickle* pickle);
   void CreateVersion0Pickle(bool size_32,
                             const PasswordForm& form,
                             Pickle* pickle);
+  void CheckVersion5Pickle();
   void CheckVersion3Pickle();
   void CheckVersion2Pickle();
   void CheckVersion1Pickle();
   void CheckVersion0Pickle(bool size_32, PasswordForm::Scheme scheme);
 
  private:
-  void CreatePickle(bool size_32, const PasswordForm& form, Pickle* pickle);
+  // Creates a Pickle from |form|. If |size_32| is true, stores the number of
+  // forms in the pickle as a 32bit uint, otherwise as 64 bit size_t. The latter
+  // should be the case for versions > 0. If |date_created_internal| is true,
+  // stores |date_created| as base::Time's internal value, otherwise as time_t.
+  void CreatePickle(bool size_32,
+                    bool date_created_internal,
+                    const PasswordForm& form,
+                    Pickle* pickle);
 };
 
+void NativeBackendKWalletPickleTest::CreateVersion5Pickle(
+    const PasswordForm& form,
+    Pickle* pickle) {
+  pickle->WriteInt(5);
+  CreatePickle(false, true, form, pickle);
+  pickle->WriteInt(form.type);
+  pickle->WriteInt(form.times_used);
+  autofill::SerializeFormData(form.form_data, pickle);
+  pickle->WriteInt64(form.date_synced.ToInternalValue());
+  pickle->WriteString16(form.display_name);
+  pickle->WriteString(form.avatar_url.spec());
+  pickle->WriteString(form.federation_url.spec());
+  pickle->WriteBool(form.skip_zero_click);
+}
+
 void NativeBackendKWalletPickleTest::CreateVersion3Pickle(
     const PasswordForm& form, Pickle* pickle) {
   pickle->WriteInt(3);
-  CreatePickle(false, form, pickle);
+  CreatePickle(false, false, form, pickle);
   pickle->WriteInt(form.type);
   pickle->WriteInt(form.times_used);
   autofill::SerializeFormData(form.form_data, pickle);
@@ -951,7 +981,7 @@
 void NativeBackendKWalletPickleTest::CreateVersion2Pickle(
     const PasswordForm& form, Pickle* pickle) {
   pickle->WriteInt(2);
-  CreatePickle(false, form, pickle);
+  CreatePickle(false, false, form, pickle);
   pickle->WriteInt(form.type);
   pickle->WriteInt(form.times_used);
   autofill::SerializeFormData(form.form_data, pickle);
@@ -960,17 +990,19 @@
 void NativeBackendKWalletPickleTest::CreateVersion1Pickle(
     const PasswordForm& form, Pickle* pickle) {
   pickle->WriteInt(1);
-  CreatePickle(false, form, pickle);
+  CreatePickle(false, false, form, pickle);
 }
 
 void NativeBackendKWalletPickleTest::CreateVersion0Pickle(
     bool size_32, const PasswordForm& form, Pickle* pickle) {
   pickle->WriteInt(0);
-  CreatePickle(size_32, form, pickle);
+  CreatePickle(size_32, false, form, pickle);
 }
 
-void NativeBackendKWalletPickleTest::CreatePickle(
-    bool size_32, const PasswordForm& form, Pickle* pickle) {
+void NativeBackendKWalletPickleTest::CreatePickle(bool size_32,
+                                                  bool date_created_internal,
+                                                  const PasswordForm& form,
+                                                  Pickle* pickle) {
   if (size_32)
     pickle->WriteUInt32(1);  // Size of form list. 32 bits.
   else
@@ -986,7 +1018,24 @@
   pickle->WriteBool(form.ssl_valid);
   pickle->WriteBool(form.preferred);
   pickle->WriteBool(form.blacklisted_by_user);
-  pickle->WriteInt64(form.date_created.ToTimeT());
+  if (date_created_internal)
+    pickle->WriteInt64(form.date_created.ToInternalValue());
+  else
+    pickle->WriteInt64(form.date_created.ToTimeT());
+}
+
+void NativeBackendKWalletPickleTest::CheckVersion5Pickle() {
+  Pickle pickle;
+  PasswordForm form = form_google_;
+  CreateVersion5Pickle(form, &pickle);
+
+  ScopedVector<PasswordForm> form_list;
+  NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle,
+                                             &form_list);
+
+  EXPECT_EQ(1u, form_list.size());
+  if (form_list.size() > 0)
+    CheckPasswordForm(form, *form_list[0], true);
 }
 
 void NativeBackendKWalletPickleTest::CheckVersion3Pickle() {
@@ -996,7 +1045,7 @@
   form.display_name.clear();
   form.avatar_url = GURL();
   form.federation_url = GURL();
-  form.is_zero_click = false;
+  form.skip_zero_click = false;
   CreateVersion3Pickle(form, &pickle);
 
   ScopedVector<PasswordForm> form_list;
@@ -1005,7 +1054,7 @@
 
   EXPECT_EQ(1u, form_list.size());
   if (form_list.size() > 0)
-    CheckPasswordForm(form, *form_list[0]);
+    CheckPasswordForm(form, *form_list[0], false);
 }
 
 void NativeBackendKWalletPickleTest::CheckVersion2Pickle() {
@@ -1022,7 +1071,7 @@
 
   EXPECT_EQ(1u, form_list.size());
   if (form_list.size() > 0)
-    CheckPasswordForm(form, *form_list[0]);
+    CheckPasswordForm(form, *form_list[0], false);
 }
 
 // Make sure that we can still read version 1 pickles.
@@ -1039,7 +1088,7 @@
   // |form_google_| will be deserialized.
   EXPECT_EQ(1u, form_list.size());
   if (form_list.size() > 0)
-    CheckPasswordForm(old_form_google_, *form_list[0]);
+    CheckPasswordForm(old_form_google_, *form_list[0], false);
 }
 
 void NativeBackendKWalletPickleTest::CheckVersion0Pickle(
@@ -1053,7 +1102,7 @@
                                              pickle, &form_list);
   EXPECT_EQ(1u, form_list.size());
   if (form_list.size() > 0)
-    CheckPasswordForm(form, *form_list[0]);
+    CheckPasswordForm(form, *form_list[0], false);
 }
 
 // Check that if KWallet fails to respond, the backend propagates the error.
@@ -1113,3 +1162,7 @@
 TEST_F(NativeBackendKWalletPickleTest, CheckVersion3Pickle) {
   CheckVersion3Pickle();
 }
+
+TEST_F(NativeBackendKWalletPickleTest, CheckVersion5Pickle) {
+  CheckVersion5Pickle();
+}
diff --git a/chrome/browser/password_manager/native_backend_libsecret.cc b/chrome/browser/password_manager/native_backend_libsecret.cc
index 7cc94af..d23ac45 100644
--- a/chrome/browser/password_manager/native_backend_libsecret.cc
+++ b/chrome/browser/password_manager/native_backend_libsecret.cc
@@ -21,6 +21,7 @@
 
 namespace {
 const char kEmptyString[] = "";
+const int kMaxPossibleTimeTValue = std::numeric_limits<int>::max();
 }
 
 typeof(&::secret_password_store_sync)
@@ -118,7 +119,7 @@
      {"display_name", SECRET_SCHEMA_ATTRIBUTE_STRING},
      {"avatar_url", SECRET_SCHEMA_ATTRIBUTE_STRING},
      {"federation_url", SECRET_SCHEMA_ATTRIBUTE_STRING},
-     {"is_zero_click", SECRET_SCHEMA_ATTRIBUTE_INTEGER},
+     {"skip_zero_click", SECRET_SCHEMA_ATTRIBUTE_INTEGER},
      // This field is always "chrome-profile_id" so that we can search for it.
      {"application", SECRET_SCHEMA_ATTRIBUTE_STRING},
      {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING}}};
@@ -164,7 +165,15 @@
   bool date_ok = base::StringToInt64(
       GetStringFromAttributes(attrs, "date_created"), &date_created);
   DCHECK(date_ok);
-  form->date_created = base::Time::FromTimeT(date_created);
+  // In the past |date_created| was stored as time_t. Currently is stored as
+  // base::Time's internal value. We need to distinguish, which format the
+  // number in |date_created| was stored in. We use the fact that
+  // kMaxPossibleTimeTValue interpreted as the internal value corresponds to an
+  // unlikely date back in 17th century, and anything above
+  // kMaxPossibleTimeTValue clearly must be in the internal value format.
+  form->date_created = date_created < kMaxPossibleTimeTValue
+                           ? base::Time::FromTimeT(date_created)
+                           : base::Time::FromInternalValue(date_created);
   form->blacklisted_by_user =
       GetUintFromAttributes(attrs, "blacklisted_by_user");
   form->type =
@@ -180,7 +189,7 @@
       UTF8ToUTF16(GetStringFromAttributes(attrs, "display_name"));
   form->avatar_url = GURL(GetStringFromAttributes(attrs, "avatar_url"));
   form->federation_url = GURL(GetStringFromAttributes(attrs, "federation_url"));
-  form->is_zero_click = GetUintFromAttributes(attrs, "is_zero_click");
+  form->skip_zero_click = GetUintFromAttributes(attrs, "skip_zero_click");
 
   return form.Pass();
 }
@@ -397,11 +406,11 @@
 }
 
 bool NativeBackendLibsecret::RawAddLogin(const PasswordForm& form) {
-  time_t date_created = form.date_created.ToTimeT();
+  int64 date_created = form.date_created.ToInternalValue();
   // If we are asked to save a password with 0 date, use the current time.
-  // We don't want to actually save passwords as though on January 1, 1970.
+  // We don't want to actually save passwords as though on January 1, 1601.
   if (!date_created)
-    date_created = time(nullptr);
+    date_created = base::Time::Now().ToInternalValue();
   int64 date_synced = form.date_synced.ToInternalValue();
   GError* error = nullptr;
   secret_password_store_sync(
@@ -410,20 +419,26 @@
       form.origin.spec().c_str(),  // Display name.
       UTF16ToUTF8(form.password_value).c_str(),
       nullptr,  // no cancellable ojbect
-      &error, "origin_url", form.origin.spec().c_str(), "action_url",
-      form.action.spec().c_str(), "username_element",
-      UTF16ToUTF8(form.username_element).c_str(), "username_value",
-      UTF16ToUTF8(form.username_value).c_str(), "password_element",
-      UTF16ToUTF8(form.password_element).c_str(), "submit_element",
-      UTF16ToUTF8(form.submit_element).c_str(), "signon_realm",
-      form.signon_realm.c_str(), "ssl_valid", form.ssl_valid, "preferred",
-      form.preferred, "date_created", base::Int64ToString(date_created).c_str(),
-      "blacklisted_by_user", form.blacklisted_by_user, "type", form.type,
-      "times_used", form.times_used, "scheme", form.scheme, "date_synced",
-      base::Int64ToString(date_synced).c_str(), "display_name",
-      UTF16ToUTF8(form.display_name).c_str(), "avatar_url",
-      form.avatar_url.spec().c_str(), "federation_url",
-      form.federation_url.spec().c_str(), "is_zero_click", form.is_zero_click,
+      &error,
+      "origin_url", form.origin.spec().c_str(),
+      "action_url", form.action.spec().c_str(),
+      "username_element", UTF16ToUTF8(form.username_element).c_str(),
+      "username_value", UTF16ToUTF8(form.username_value).c_str(),
+      "password_element", UTF16ToUTF8(form.password_element).c_str(),
+      "submit_element", UTF16ToUTF8(form.submit_element).c_str(),
+      "signon_realm", form.signon_realm.c_str(),
+      "ssl_valid", form.ssl_valid,
+      "preferred", form.preferred,
+      "date_created", base::Int64ToString(date_created).c_str(),
+      "blacklisted_by_user", form.blacklisted_by_user,
+      "type", form.type,
+      "times_used", form.times_used,
+      "scheme", form.scheme,
+      "date_synced", base::Int64ToString(date_synced).c_str(),
+      "display_name", UTF16ToUTF8(form.display_name).c_str(),
+      "avatar_url", form.avatar_url.spec().c_str(),
+      "federation_url", form.federation_url.spec().c_str(),
+      "skip_zero_click", form.skip_zero_click,
       "application", app_string_.c_str(), nullptr);
 
   if (error) {
diff --git a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
index b7ae4be0..2e531ce 100644
--- a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
@@ -236,8 +236,7 @@
     EXPECT_EQ(expected.signon_realm, actual.signon_realm);
     EXPECT_EQ(expected.ssl_valid, actual.ssl_valid);
     EXPECT_EQ(expected.preferred, actual.preferred);
-    // We don't check the date created. It varies due to bug in the
-    // serialization. Integer seconds are saved instead of microseconds.
+    EXPECT_EQ(expected.date_created, actual.date_created);
     EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user);
     EXPECT_EQ(expected.type, actual.type);
     EXPECT_EQ(expected.times_used, actual.times_used);
@@ -246,7 +245,7 @@
     EXPECT_EQ(expected.display_name, actual.display_name);
     EXPECT_EQ(expected.avatar_url, actual.avatar_url);
     EXPECT_EQ(expected.federation_url, actual.federation_url);
-    EXPECT_EQ(expected.is_zero_click, actual.is_zero_click);
+    EXPECT_EQ(expected.skip_zero_click, actual.skip_zero_click);
   }
 }
 
@@ -289,7 +288,7 @@
     form_google_.display_name = UTF8ToUTF16("Joe Schmoe");
     form_google_.avatar_url = GURL("http://www.google.com/avatar");
     form_google_.federation_url = GURL("http://www.google.com/federation_url");
-    form_google_.is_zero_click = true;
+    form_google_.skip_zero_click = true;
 
     form_facebook_.origin = GURL("http://www.facebook.com/");
     form_facebook_.action = GURL("http://www.facebook.com/login");
@@ -304,7 +303,7 @@
     form_facebook_.display_name = UTF8ToUTF16("Joe Schmoe");
     form_facebook_.avatar_url = GURL("http://www.facebook.com/avatar");
     form_facebook_.federation_url = GURL("http://www.facebook.com/federation");
-    form_facebook_.is_zero_click = true;
+    form_facebook_.skip_zero_click = true;
 
     form_isc_.origin = GURL("http://www.isc.org/");
     form_isc_.action = GURL("http://www.isc.org/auth");
@@ -388,7 +387,7 @@
     CheckStringAttribute(item, "display_name", UTF16ToUTF8(form.display_name));
     CheckStringAttribute(item, "avatar_url", form.avatar_url.spec());
     CheckStringAttribute(item, "federation_url", form.federation_url.spec());
-    CheckUint32Attribute(item, "is_zero_click", form.is_zero_click);
+    CheckUint32Attribute(item, "skip_zero_click", form.skip_zero_click);
     CheckStringAttribute(item, "application", app_string);
   }
 
@@ -528,15 +527,13 @@
   void CheckRemoveLoginsBetween(RemoveBetweenMethod date_to_test) {
     NativeBackendLibsecret backend(42);
 
-    form_google_.date_synced = base::Time();
-    form_isc_.date_synced = base::Time();
-    form_google_.date_created = base::Time();
-    form_isc_.date_created = base::Time();
     base::Time now = base::Time::Now();
     base::Time next_day = now + base::TimeDelta::FromDays(1);
+    form_google_.date_synced = base::Time();
+    form_isc_.date_synced = base::Time();
+    form_google_.date_created = now;
+    form_isc_.date_created = now;
     if (date_to_test == CREATED) {
-      // http://crbug.com/374132. Remove the next line once it's fixed.
-      next_day = base::Time::FromTimeT(next_day.ToTimeT());
       form_google_.date_created = now;
       form_isc_.date_created = next_day;
     } else {
diff --git a/chrome/browser/password_manager/password_store_mac_unittest.cc b/chrome/browser/password_manager/password_store_mac_unittest.cc
index 29a3f90..4576c28 100644
--- a/chrome/browser/password_manager/password_store_mac_unittest.cc
+++ b/chrome/browser/password_manager/password_store_mac_unittest.cc
@@ -255,7 +255,7 @@
   if (form_data.username_value) {
     form->username_value = WideToUTF16(form_data.username_value);
     form->display_name = form->username_value;
-    form->is_zero_click = true;
+    form->skip_zero_click = true;
     if (form_data.password_value)
       form->password_value = WideToUTF16(form_data.password_value);
   } else {
@@ -307,7 +307,7 @@
                 form->username_value) << test_label;
       EXPECT_EQ(WideToUTF16(expectation->username_value),
                 form->display_name) << test_label;
-      EXPECT_TRUE(form->is_zero_click) << test_label;
+      EXPECT_TRUE(form->skip_zero_click) << test_label;
       EXPECT_EQ(WideToUTF16(expectation->password_value),
                 form->password_value) << test_label;
     } else {
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index 1075f61..ad996d3 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -52,9 +52,8 @@
 
 void EnableInternalPDFPluginForContents(WebContents* preview_dialog) {
   // Always enable the internal PDF plugin for the print preview page.
-  base::FilePath pdf_plugin_path;
-  if (!PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_plugin_path))
-    return;
+  base::FilePath pdf_plugin_path = base::FilePath::FromUTF8Unsafe(
+      ChromeContentClient::kPDFPluginPath);
 
   content::WebPluginInfo pdf_plugin;
   if (!content::PluginService::GetInstance()->GetPluginInfoByPath(
diff --git a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
index 367a92d3..f6a9321 100644
--- a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
+++ b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
@@ -22,7 +22,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/scoped_native_library.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/printing/print_preview_dialog_controller.h"
@@ -39,6 +38,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "ipc/ipc_message_macros.h"
 #include "net/base/filename_util.h"
+#include "pdf/pdf.h"
 #include "printing/pdf_render_settings.h"
 #include "printing/units.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -323,33 +323,6 @@
     ASSERT_TRUE(pdf_file.IsValid());
   }
 
-  // Initializes function pointers from the PDF library. Called once when the
-  // test starts. The library is closed when the browser test ends.
-  void InitPdfFunctions() {
-    base::FilePath pdf_module_path;
-
-    ASSERT_TRUE(PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path));
-    ASSERT_TRUE(base::PathExists(pdf_module_path));
-    pdf_lib_.Reset(base::LoadNativeLibrary(pdf_module_path, NULL));
-
-    ASSERT_TRUE(pdf_lib_.is_valid());
-    pdf_to_bitmap_func_ =
-        reinterpret_cast<PDFPageToBitmapProc>(
-            pdf_lib_.GetFunctionPointer("RenderPDFPageToBitmap"));
-
-    pdf_doc_info_func_ =
-        reinterpret_cast<GetPDFDocInfoProc>(
-            pdf_lib_.GetFunctionPointer("GetPDFDocInfo"));
-
-    pdf_page_size_func_ =
-        reinterpret_cast<GetPDFPageSizeByIndexProc>(
-            pdf_lib_.GetFunctionPointer("GetPDFPageSizeByIndex"));
-
-    ASSERT_TRUE(pdf_to_bitmap_func_);
-    ASSERT_TRUE(pdf_doc_info_func_);
-    ASSERT_TRUE(pdf_page_size_func_);
-  }
-
   // Converts the PDF to a PNG file so that the layout test can do an image
   // diff on this image and a reference image.
   void PdfToPng() {
@@ -360,10 +333,10 @@
     std::string pdf_data;
 
     ASSERT_TRUE(base::ReadFileToString(pdf_file_save_path_, &pdf_data));
-    ASSERT_TRUE(pdf_doc_info_func_(pdf_data.data(),
-                                   pdf_data.size(),
-                                   &num_pages,
-                                   &max_width_in_points));
+    ASSERT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_data.data(),
+                                          pdf_data.size(),
+                                          &num_pages,
+                                          &max_width_in_points));
 
     ASSERT_GT(num_pages, 0);
     double max_width_in_pixels =
@@ -371,11 +344,11 @@
 
     for (int i = 0; i < num_pages; ++i) {
       double width_in_points, height_in_points;
-      ASSERT_TRUE(pdf_page_size_func_(pdf_data.data(),
-                                      pdf_data.size(),
-                                      i,
-                                      &width_in_points,
-                                      &height_in_points));
+      ASSERT_TRUE(chrome_pdf::GetPDFPageSizeByIndex(pdf_data.data(),
+                                                    pdf_data.size(),
+                                                    i,
+                                                    &width_in_points,
+                                                    &height_in_points));
 
       double width_in_pixels = ConvertUnitDouble(
           width_in_points, kPointsPerInch, kDpi);
@@ -405,15 +378,15 @@
       std::vector<uint8_t> page_bitmap_data(
           kColorChannels * settings.area().size().GetArea());
 
-      ASSERT_TRUE(pdf_to_bitmap_func_(pdf_data.data(),
-                                      pdf_data.size(),
-                                      i,
-                                      page_bitmap_data.data(),
-                                      settings.area().size().width(),
-                                      settings.area().size().height(),
-                                      settings.dpi(),
-                                      settings.dpi(),
-                                      true));
+      ASSERT_TRUE(chrome_pdf::RenderPDFPageToBitmap(
+          pdf_data.data(),
+          pdf_data.size(),
+          i,
+          page_bitmap_data.data(),
+          settings.area().size().width(),
+          settings.area().size().height(),
+          settings.dpi(),
+          true));
       FillPng(&page_bitmap_data,
               width_in_pixels,
               max_width_in_pixels,
@@ -572,41 +545,6 @@
   scoped_ptr<PrintPreviewObserver> print_preview_observer_;
   base::FilePath pdf_file_save_path_;
 
-  // These typedefs are function pointers to pdflib functions that give
-  // information about the PDF as a whole and about specific pages.
-
-  // Converts the PDF to a bitmap.
-  typedef bool (*PDFPageToBitmapProc)(const void* pdf_buffer,
-                                      int pdf_buffer_size,
-                                      int page_number,
-                                      void* bitmap_buffer,
-                                      int bitmap_width,
-                                      int bitmap_height,
-                                      int dpi_x,
-                                      int dpi_y,
-                                      bool autorotate);
-
-  // Gets the page count and maximum page width of the PDF in points.
-  typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer,
-                                    int buffer_size,
-                                    int* pages_count,
-                                    double* max_page_width);
-
-  // Gets the dimensions of a specific page within a PDF.
-  typedef bool (*GetPDFPageSizeByIndexProc)(const void* pdf_buffer,
-                                            int buffer_size,
-                                            int index,
-                                            double* width,
-                                            double* height);
-
-  // Instantiations of the function pointers described above.
-  PDFPageToBitmapProc pdf_to_bitmap_func_;
-  GetPDFDocInfoProc pdf_doc_info_func_;
-  GetPDFPageSizeByIndexProc pdf_page_size_func_;
-
-  // Used to open up the pdf plugin, which contains the functions above.
-  base::ScopedNativeLibrary pdf_lib_;
-
   // Vector for storing the PNG to be sent to the layout test framework.
   // TODO(ivandavid): Eventually change this to uint32_t and make everything
   // work with that. It might be a bit tricky to fix everything to work with
@@ -641,8 +579,7 @@
   // to send data to the browser test. Writing "EOF\n" to |std::cout| indicates
   // that whatever block of data that the test was expecting has been completely
   // sent. Sometimes EOF is printed to stderr because the test will expect it
-  // from stderr in addition to stdout for certain blocks of data.
-  InitPdfFunctions();
+  // from stderr in addition to stdout for certain blocks of data.=
   SetupStdinAndSavePath();
 
   while (true) {
diff --git a/chrome/browser/printing/print_view_manager_basic.h b/chrome/browser/printing/print_view_manager_basic.h
index 553c555..afcdfb2 100644
--- a/chrome/browser/printing/print_view_manager_basic.h
+++ b/chrome/browser/printing/print_view_manager_basic.h
@@ -19,7 +19,7 @@
     : public PrintViewManagerBase,
       public content::WebContentsUserData<PrintViewManagerBasic> {
  public:
-  virtual ~PrintViewManagerBasic();
+  ~PrintViewManagerBasic() override;
 
 #if defined(OS_ANDROID)
   // Sets the file descriptor into which the PDF will be written.
@@ -32,10 +32,10 @@
 
   // content::WebContentsObserver implementation.
   // Terminates or cancels the print job if one was pending.
-  virtual void RenderProcessGone(base::TerminationStatus status) override;
+  void RenderProcessGone(base::TerminationStatus status) override;
 
   // content::WebContentsObserver implementation.
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
 #endif
 
  private:
@@ -43,7 +43,7 @@
   friend class content::WebContentsUserData<PrintViewManagerBasic>;
 
 #if defined(OS_ANDROID)
-  virtual void OnPrintingFailed(int cookie) override;
+  void OnPrintingFailed(int cookie) override;
 
   // The file descriptor into which the PDF of the page will be written.
   base::FileDescriptor file_descriptor_;
diff --git a/chrome/browser/profiles/profile_android.h b/chrome/browser/profiles/profile_android.h
index 7a202811..b336342 100644
--- a/chrome/browser/profiles/profile_android.h
+++ b/chrome/browser/profiles/profile_android.h
@@ -45,7 +45,7 @@
   jboolean IsOffTheRecord(JNIEnv* env, jobject obj);
 
   explicit ProfileAndroid(Profile* profile);
-  virtual ~ProfileAndroid();
+  ~ProfileAndroid() override;
 
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
 
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 89238a2b..48463fa 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -44,7 +44,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -222,7 +222,8 @@
             profile_manager->GetInitialProfileDir().value());
 
   const char kTestUserName[] = "test-user@example.com";
-  chromeos::FakeUserManager* user_manager = new chromeos::FakeUserManager();
+  chromeos::FakeChromeUserManager* user_manager =
+      new chromeos::FakeChromeUserManager();
   chromeos::ScopedUserManagerEnabler enabler(user_manager);
 
   const user_manager::User* active_user = user_manager->AddUser(kTestUserName);
diff --git a/chrome/browser/renderer_host/OWNERS b/chrome/browser/renderer_host/OWNERS
new file mode 100644
index 0000000..db2d1f0
--- /dev/null
+++ b/chrome/browser/renderer_host/OWNERS
@@ -0,0 +1,15 @@
+# Mac files
+per-file *.mm=avi@chromium.org
+per-file *.mm=ccameron@chromium.org
+per-file *.mm=erikchen@chromium.org
+per-file *.mm=mark@chromium.org
+per-file *.mm=rsesek@chromium.org
+per-file *.mm=thakis@chromium.org
+
+per-file *_mac.h=avi@chromium.org
+per-file *_mac.h=ccameron@chromium.org
+per-file *_mac.h=erikchen@chromium.org
+per-file *_mac.h=mark@chromium.org
+per-file *_mac.h=rsesek@chromium.org
+per-file *_mac.h=thakis@chromium.org
+
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm
index 471b921..c064f72 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper_browsertest.mm
@@ -124,6 +124,26 @@
 
   // Create mock events --------------------------------------------------------
 
+  // Create a gesture event with no useful data. Used to create Begin and End
+  // events.
+  id MockGestureEvent(NSEventType type) {
+    id event = [OCMockObject mockForClass:[NSEvent class]];
+    NSPoint locationInWindow = NSMakePoint(0, 0);
+    CGFloat deltaX = 0;
+    CGFloat deltaY = 0;
+    NSTimeInterval timestamp = 0;
+    NSUInteger modifierFlags = 0;
+    [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type];
+    [(NSEvent*)[[event stub]
+        andReturnValue:OCMOCK_VALUE(locationInWindow)] locationInWindow];
+    [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(deltaX)] deltaX];
+    [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(deltaY)] deltaY];
+    [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(timestamp)] timestamp];
+    [(NSEvent*)[[event stub]
+        andReturnValue:OCMOCK_VALUE(modifierFlags)] modifierFlags];
+    return event;
+  }
+
   // Creates a mock scroll wheel event that is backed by a real CGEvent.
   id MockScrollWheelEvent(NSPoint delta, NSEventType type) {
     CGEventRef cg_event =
@@ -189,18 +209,14 @@
 
   // Queues a gesture begin event (e.g. [NSView gestureDidBegin:])
   void QueueGestureBegin() {
-    id event = [OCMockObject mockForClass:[NSEvent class]];
-    NSEventType type = NSEventTypeBeginGesture;
-    [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type];
-    QueueEvent(event, DEPLOYMENT_GESTURE_BEGIN, NO);
+    QueueEvent(MockGestureEvent(NSEventTypeBeginGesture),
+               DEPLOYMENT_GESTURE_BEGIN, NO);
   }
 
   // Queues a gesture end event (e.g. [NSView gestureDidEnd:])
   void QueueGestureEnd() {
-    id event = [OCMockObject mockForClass:[NSEvent class]];
-    NSEventType type = NSEventTypeEndGesture;
-    [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(type)] type];
-    QueueEvent(event, DEPLOYMENT_GESTURE_END, NO);
+    QueueEvent(MockGestureEvent(NSEventTypeEndGesture),
+               DEPLOYMENT_GESTURE_BEGIN, NO);
   }
 
   // Queues a touch event with absolute coordinates |x| and |y|.
diff --git a/chrome/browser/resources/app_list/start_page.css b/chrome/browser/resources/app_list/start_page.css
index 2a6049f..a83d4408 100644
--- a/chrome/browser/resources/app_list/start_page.css
+++ b/chrome/browser/resources/app_list/start_page.css
@@ -4,6 +4,7 @@
 
 html,
 body {
+  -webkit-user-select: none;
   background-color: rgb(245, 245, 245);
   height: 100%;
   margin: 0;
@@ -12,7 +13,12 @@
   width: 100%;
 }
 
-#logo {
+#doodle {
+  display: none;
+  justify-content: center;
+}
+
+#default_logo {
   background-image: -webkit-image-set(
     url(chrome://theme/IDR_LOCAL_NTP_IMAGES_LOGO_PNG) 1x,
     url(chrome://theme/IDR_LOCAL_NTP_IMAGES_LOGO_PNG@2x) 2x);
@@ -20,3 +26,9 @@
   margin: auto;
   width: 269px;
 }
+
+#logo_container {
+  bottom: 0;
+  position: absolute;
+  width: 100%;
+}
diff --git a/chrome/browser/resources/app_list/start_page.html b/chrome/browser/resources/app_list/start_page.html
index 4a51a183..e360a16 100644
--- a/chrome/browser/resources/app_list/start_page.html
+++ b/chrome/browser/resources/app_list/start_page.html
@@ -11,10 +11,13 @@
   <script src="chrome://resources/js/util.js"></script>
   <script src="chrome://app-list/strings.js"></script>
   <script src="chrome://app-list/start_page.js"></script>
+  <base id="base">
 </head>
 
 <body>
-  <div id="logo"></div>
+  <div id="logo_container">
+    <div id="default_logo"></div>
+  </div>
   <script src="chrome://resources/js/i18n_template2.js"></script>
 </body>
 </html>
diff --git a/chrome/browser/resources/app_list/start_page.js b/chrome/browser/resources/app_list/start_page.js
index 21ccc4e..e205592 100644
--- a/chrome/browser/resources/app_list/start_page.js
+++ b/chrome/browser/resources/app_list/start_page.js
@@ -13,6 +13,9 @@
 
   var speechManager = null;
 
+  // The element containing the current Google Doodle.
+  var doodle = null;
+
   /**
    * Initialize the page.
    */
@@ -48,6 +51,75 @@
   }
 
   /**
+   * Sets the doodle's visibility, hiding or showing the default logo.
+   *
+   * @param {boolean} visible Whether the doodle should be made visible.
+   */
+  function setDoodleVisible(visible) {
+    var doodle = $('doodle');
+    var defaultLogo = $('default_logo');
+    if (visible) {
+      doodle.style.display = 'flex';
+      defaultLogo.style.display = 'none';
+    } else {
+      if (doodle)
+        doodle.style.display = 'none';
+
+      defaultLogo.style.display = 'block';
+    }
+  }
+
+  /**
+   * Invoked when the app-list doodle is updated.
+   *
+   * @param {Object} data The data object representing the current doodle.
+   */
+  function onAppListDoodleUpdated(data, base_url) {
+    if (this.doodle) {
+      this.doodle.parentNode.removeChild(this.doodle);
+      this.doodle = null;
+    }
+
+    var doodleData = data.ddljson;
+    if (!doodleData || !doodleData.transparent_large_image) {
+      setDoodleVisible(false);
+      return;
+    }
+
+    // Set the page's base URL so that links will resolve relative to the Google
+    // homepage.
+    $('base').href = base_url;
+
+    this.doodle = document.createElement('div');
+    this.doodle.id = 'doodle';
+    this.doodle.style.display = 'none';
+
+    var doodleImage = document.createElement('img');
+    doodleImage.id = 'doodle_image';
+    if (doodleData.alt_text) {
+      doodleImage.alt = doodleData.alt_text;
+      doodleImage.title = doodleData.alt_text;
+    }
+
+    doodleImage.onload = function() {
+      setDoodleVisible(true);
+    };
+    doodleImage.src = doodleData.transparent_large_image.url;
+
+    if (doodleData.target_url) {
+      var doodleLink = document.createElement('a');
+      doodleLink.id = 'doodle_link';
+      doodleLink.href = doodleData.target_url;
+      doodleLink.target = '_blank';
+      doodleLink.appendChild(doodleImage);
+      this.doodle.appendChild(doodleLink);
+    } else {
+      this.doodle.appendChild(doodleImage);
+    }
+    $('logo_container').appendChild(this.doodle);
+  }
+
+  /**
    * Invoked when the app-list bubble is hidden.
    */
   function onAppListHidden() {
@@ -66,10 +138,12 @@
     initialize: initialize,
     setHotwordEnabled: setHotwordEnabled,
     setNaclArch: setNaclArch,
+    onAppListDoodleUpdated: onAppListDoodleUpdated,
     onAppListShown: onAppListShown,
     onAppListHidden: onAppListHidden,
     toggleSpeechRecognition: toggleSpeechRecognition
   };
 });
 
+document.addEventListener('contextmenu', function(e) { e.preventDefault(); });
 document.addEventListener('DOMContentLoaded', appList.startPage.initialize);
diff --git a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
index f3d312211..41edd0e21 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
@@ -1511,6 +1511,7 @@
     unknown: 'unknown',
     tooltip: 'tooltip',
     webArea: 'webArea',
+    webView: 'webView',
     window: 'window'
 };
 /**
diff --git a/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js
index d7d7bd4..5731239 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js
@@ -6,6 +6,7 @@
 goog.provide('cvox.TextChangeEvent');
 goog.provide('cvox.TypingEcho');
 
+goog.require('cvox.AbstractTts');
 goog.require('cvox.ChromeVox');
 goog.require('cvox.TtsInterface');
 goog.require('goog.i18n.MessageFormat');
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
index d5d9956..16f7506 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util.js
@@ -88,8 +88,12 @@
   while (cur) {
     var next = dir == Dir.BACKWARD ?
         cur.previousSibling : cur.nextSibling;
+    if (!AutomationUtil.isInSameTree(cur, next))
+      return null;
     if (next)
       return next;
+    if (!AutomationUtil.isInSameTree(cur, cur.parent))
+      return null;
     cur = cur.parent;
   }
 };
@@ -164,6 +168,10 @@
   var candidate = node;
   while (candidate) {
     ret.push(candidate);
+
+    if (!AutomationUtil.isInSameTree(candidate, candidate.parent))
+      break;
+
     candidate = candidate.parent;
   }
   return ret.reverse();
@@ -226,4 +234,17 @@
   return divA.indexInParent <= divB.indexInParent ? Dir.FORWARD : Dir.BACKWARD;
 };
 
+/**
+ * Determines whether the two given nodes come from the same tree source.
+ * @param {AutomationNode} a
+ * @param {AutomationNode} b
+ * @return {boolean}
+ */
+AutomationUtil.isInSameTree = function(a, b) {
+  if (!a || !b)
+    return true;
+
+  return a.root === b.root;
+};
+
 });  // goog.scope
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index c330608..7659707e 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -16,7 +16,6 @@
 goog.require('Output.EventType');
 goog.require('cursors.Cursor');
 goog.require('cvox.ChromeVoxEditableTextBase');
-goog.require('cvox.TabsApiHandler');
 
 goog.scope(function() {
 var AutomationNode = chrome.automation.AutomationNode;
@@ -37,14 +36,6 @@
   this.whitelist_ = ['chromevox_next_test'];
 
   /**
-   * @type {cvox.TabsApiHandler}
-   * @private
-   */
-  this.tabsHandler_ = new cvox.TabsApiHandler(cvox.ChromeVox.tts,
-                                              cvox.ChromeVox.braille,
-                                              cvox.ChromeVox.earcons);
-
-  /**
    * @type {cursors.Range}
    * @private
    */
@@ -82,43 +73,29 @@
 
   // Register listeners for ...
   // Desktop.
-  chrome.automation.getDesktop(this.onGotTree);
-
-  // Tabs.
-  chrome.tabs.onUpdated.addListener(this.onTabUpdated);
+  chrome.automation.getDesktop(this.onGotDesktop);
 };
 
 Background.prototype = {
   /**
-   * Handles chrome.tabs.onUpdated.
-   * @param {number} tabId
-   * @param {Object} changeInfo
-   */
-  onTabUpdated: function(tabId, changeInfo) {
-    if (changeInfo.status != 'complete')
-      return;
-    chrome.tabs.get(tabId, function(tab) {
-      if (!tab.url)
-        return;
-
-      var next = this.isWhitelisted_(tab.url);
-
-      this.toggleChromeVoxVersion({next: next, classic: !next});
-    }.bind(this));
-  },
-
-  /**
    * Handles all setup once a new automation tree appears.
-   * @param {chrome.automation.AutomationNode} root
+   * @param {chrome.automation.AutomationNode} desktop
    */
-  onGotTree: function(root) {
+  onGotDesktop: function(desktop) {
     // Register all automation event listeners.
     for (var eventType in this.listeners_)
-      root.addEventListener(eventType, this.listeners_[eventType], true);
+      desktop.addEventListener(eventType, this.listeners_[eventType], true);
 
-    if (root.attributes.docLoaded) {
-      this.onLoadComplete(
-          {target: root, type: chrome.automation.EventType.loadComplete});
+    // The focused state gets set on the containing webView node.
+    var webView = desktop.find({role: chrome.automation.RoleType.webView,
+                                state: {focused: true}});
+    if (webView) {
+      var root = webView.find({role: chrome.automation.RoleType.rootWebArea});
+      if (root) {
+        this.onLoadComplete(
+            {target: root,
+             type: chrome.automation.EventType.loadComplete});
+      }
     }
   },
 
@@ -270,14 +247,28 @@
    * @param {Object} evt
    */
   onLoadComplete: function(evt) {
+    var next = this.isWhitelisted_(evt.target.attributes.url);
+    this.toggleChromeVoxVersion({next: next, classic: !next});
     // Don't process nodes inside of web content if ChromeVox Next is inactive.
     if (evt.target.root.role != chrome.automation.RoleType.desktop &&
         !this.active_)
       return;
 
-    var node = AutomationUtil.findNodePost(evt.target,
+    if (this.currentRange_)
+      return;
+
+    var root = evt.target;
+    var webView = root;
+    while (webView && webView.role != chrome.automation.RoleType.webView)
+      webView = webView.parent;
+
+    if (!webView || !webView.state.focused)
+      return;
+
+    var node = AutomationUtil.findNodePost(root,
         Dir.FORWARD,
         AutomationPredicate.leaf);
+
     if (node)
       this.currentRange_ = cursors.Range.fromNode(node);
 
@@ -362,21 +353,11 @@
 
     if (opt_options.next) {
       if (!chrome.commands.onCommand.hasListener(this.onGotCommand))
-        chrome.commands.onCommand.addListener(this.onGotCommand);
-
-      if (!this.active_)
-        chrome.automation.getTree(this.onGotTree);
-      this.active_ = true;
+          chrome.commands.onCommand.addListener(this.onGotCommand);
+        this.active_ = true;
     } else {
       if (chrome.commands.onCommand.hasListener(this.onGotCommand))
         chrome.commands.onCommand.removeListener(this.onGotCommand);
-
-      if (this.active_) {
-        for (var eventType in this.listeners_) {
-          this.currentRange_.getStart().getNode().root.removeEventListener(
-              eventType, this.listeners_[eventType], true);
-        }
-      }
       this.active_ = false;
     }
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 7ed70f7c..d37e4d9 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -97,7 +97,7 @@
   }, true);
   cvox.ChromeVox.tts.expectSpeech('end', testDone, true);
 
-  this.runWithDocument(function() {/*!
+  this.runWithAutomation(function() {/*!
     <p>start
     <p>end
   */},
@@ -107,7 +107,7 @@
 /** Tests consistency of navigating forward and backward. */
 TEST_F('BackgroundTest', 'ForwardBackwardNavigation', function() {
   cvox.ChromeVox.tts.expectSpeech('start', null, true);
-  this.runWithDocument(this.linksAndHeadingsDoc, function() {
+  this.runWithAutomation(this.linksAndHeadingsDoc, function() {
       var doCmd = this.doCmd.bind(this);
       var expectAfter =
           cvox.ChromeVox.tts.expectSpeechAfter.bind(cvox.ChromeVox.tts);
@@ -138,7 +138,7 @@
 
 TEST_F('BackgroundTest', 'CaretNavigation', function() {
   cvox.ChromeVox.tts.expectSpeech('start', null, true);
-  this.runWithDocument(this.linksAndHeadingsDoc, function() {
+  this.runWithAutomation(this.linksAndHeadingsDoc, function() {
       var doCmd = this.doCmd.bind(this);
       var expectAfter =
           cvox.ChromeVox.tts.expectSpeechAfter.bind(cvox.ChromeVox.tts);
@@ -168,7 +168,7 @@
 
 // Flaky: http://crbug.com/451362
 TEST_F('BackgroundTest', 'DISABLED_SelectSingleBasic', function() {
-  this.runWithDocument(this.formsDoc, function(tabId) {
+  this.runWithAutomation(this.formsDoc, function(tabId) {
     var sendDownToSelect =
         this.sendKeyToElement.bind(this, tabId, 'Down', '#fruitSelect');
     var expect = cvox.ChromeVox.tts.expectSpeech.bind(cvox.ChromeVox.tts);
@@ -181,7 +181,7 @@
 
 TEST_F('BackgroundTest', 'ContinuousRead', function() {
   cvox.ChromeVox.tts.expectSpeech('start', null, true);
-  this.runWithDocument(this.linksAndHeadingsDoc, function() {
+  this.runWithAutomation(this.linksAndHeadingsDoc, function() {
     var doCmd = this.doCmd.bind(this);
     var expect =
         cvox.ChromeVox.tts.expectSpeechAfter.bind(cvox.ChromeVox.tts);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
index 7cc281a4b..d5b9fd3 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
@@ -70,6 +70,7 @@
       range = range.move(move[0], move[1]);
       var expectedStart = move[2];
       var expectedEnd = move[3];
+
       this.makeCursorAssertion(expectedStart, range.getStart());
       this.makeCursorAssertion(expectedEnd, range.getEnd());
     }
@@ -93,27 +94,25 @@
    * @param {string=} opt_testType Either CURSOR or RANGE.
    */
   runCursorMovesOnDocument: function(doc, moves, opt_testType) {
-    this.runWithDocument(doc,
-    function() {
-      chrome.automation.getTree(function(root) {
-        var start = null;
+    this.runWithAutomation(doc,
+    function(root) {
+      var start = null;
 
-        // This occurs as a result of a load complete.
-        var start = AutomationUtil.findNodePost(root,
-            FORWARD,
-            AutomationPredicate.leaf);
+      // This occurs as a result of a load complete.
+      var start = AutomationUtil.findNodePost(root,
+          FORWARD,
+          AutomationPredicate.leaf);
 
+      var cursor = new cursors.Cursor(start, 0);
+      if (!opt_testType || opt_testType == this.CURSOR) {
         var cursor = new cursors.Cursor(start, 0);
-        if (!opt_testType || opt_testType == this.CURSOR) {
-          var cursor = new cursors.Cursor(start, 0);
-          this.cursorMoveAndAssert(cursor, moves);
-          testDone();
-        } else if (opt_testType == this.RANGE) {
-          var range = new cursors.Range(cursor, cursor);
-          this.rangeMoveAndAssert(range, moves);
-          testDone();
-        }
-      }.bind(this));
+        this.cursorMoveAndAssert(cursor, moves);
+        testDone();
+      } else if (opt_testType == this.RANGE) {
+        var range = new cursors.Range(cursor, cursor);
+        this.rangeMoveAndAssert(range, moves);
+        testDone();
+      }
     }.bind(this));
   },
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index 101e896d2..7fb786b7 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -13,6 +13,8 @@
 goog.require('cursors.Cursor');
 goog.require('cursors.Range');
 goog.require('cursors.Unit');
+goog.require('cvox.AbstractEarcons');
+goog.require('cvox.NavBraille');
 goog.require('cvox.Spannable');
 goog.require('cvox.ValueSelectionSpan');
 goog.require('cvox.ValueSpan');
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js b/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js
index e432a998..038155f 100644
--- a/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js
+++ b/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js
@@ -32,7 +32,14 @@
   runWithAutomation: function(doc, callback) {
     this.runWithDocument(doc, function() {
       chrome.automation.getTree(function(root) {
-        callback(root);
+        if (root.children.length == 0) {
+          root.addEventListener('loadComplete',
+                                function() {
+                                  callback(root);
+                                }.bind(this), true);
+        } else {
+          callback(root);
+        }
       }.bind(this));
     }.bind(this));
   }
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/mock_tts.js b/chrome/browser/resources/chromeos/chromevox/testing/mock_tts.js
index 0915e112..fb34e1a 100644
--- a/chrome/browser/resources/chromeos/chromevox/testing/mock_tts.js
+++ b/chrome/browser/resources/chromeos/chromevox/testing/mock_tts.js
@@ -113,7 +113,7 @@
     // Process any idleUtterances.
     this.idleUtterances_.forEach(function(utterance) {
       this.process_(utterance, true);
-    });
+    }.bind(this));
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/print_js_deps.py b/chrome/browser/resources/chromeos/chromevox/tools/print_js_deps.py
new file mode 100755
index 0000000..4782c3d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/tools/print_js_deps.py
@@ -0,0 +1,89 @@
+#!/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.
+
+'''Print the dependency tree for a JavaScript module.
+
+Given one or more root directories, specified by -r options and one top-level
+file, walk the dependency tree and print all modules encountered.
+A module is only expanded once; on a second encounter, its dependencies
+are represented by a line containing the characters '[...]' as a short-hand.
+'''
+
+import optparse
+import os
+import sys
+
+from jsbundler import ReadSources
+
+
+def Die(message):
+  '''Prints an error message and exit the program.'''
+  print >>sys.stderr, message
+  sys.exit(1)
+
+
+def CreateOptionParser():
+  parser = optparse.OptionParser(description=__doc__)
+  parser.usage = '%prog [options] <top_level_file>'
+  parser.add_option('-r', '--root', dest='roots', action='append', default=[],
+                    metavar='ROOT',
+                    help='Roots of directory trees to scan for sources. '
+                    'If none specified, all of ChromeVox and closure sources '
+                    'are scanned.')
+  return parser
+
+
+def DefaultRoots():
+  script_dir = os.path.dirname(os.path.abspath(__file__))
+  source_root_dir = os.path.join(script_dir, *[os.path.pardir] * 6)
+  return [os.path.relpath(os.path.join(script_dir, os.path.pardir)),
+          os.path.relpath(
+            os.path.join(source_root_dir, 'chrome', 'third_party',
+                         'chromevox', 'third_party',
+                         'closure-library', 'closure'))]
+
+
+def WalkDeps(sources, start_source):
+  def Walk(source, depth):
+    indent = '  ' * depth
+    if source.GetInPath() in expanded and len(source.requires) > 0:
+      print '%s[...]' % indent
+      return
+    expanded.add(source.GetInPath())
+    for require in source.requires:
+      if not require in providers:
+        Die('%s not provided, required by %s' % (require, source.GetInPath()))
+      require_source = providers[require]
+      print '%s%s (%s)' % (indent, require, require_source.GetInPath())
+      Walk(require_source, depth + 1)
+
+  # Create a map from provided module names to source objects.
+  providers = {}
+  expanded = set()
+  for source in sources.values():
+    for provide in source.provides:
+      if provide in providers:
+        Die('%s provided multiple times' % provide)
+      providers[provide] = source
+
+  print '(%s)' % start_source.GetInPath()
+  Walk(start_source, 1)
+
+
+def main():
+  parser = CreateOptionParser()
+  options, args = parser.parse_args()
+  if len(args) != 1:
+    Die('Exactly one top-level source file must be specified.')
+  start_path = args[0]
+  roots = options.roots or DefaultRoots()
+  sources = ReadSources(roots=roots, source_files=[start_path])
+  start_source = sources[start_path]
+  WalkDeps(sources, start_source)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_update.css b/chrome/browser/resources/chromeos/login/oobe_screen_update.css
index bd650cf..f522347 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_update.css
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_update.css
@@ -33,7 +33,7 @@
 #update #update-cancel-hint {
   -webkit-margin-start: 45px;
   color: rgb(170, 0, 0);
-  margin-top: 15px;
+  margin-top: 30px;
   position: absolute;
 }
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_update.js b/chrome/browser/resources/chromeos/login/oobe_screen_update.js
index 34c9f03..1fa14c97 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_update.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_update.js
@@ -7,17 +7,56 @@
  */
 
 login.createScreen('UpdateScreen', 'update', function() {
+  var USER_ACTION_CANCEL_UPDATE_SHORTCUT = 'cancel-update';
+  var CONTEXT_KEY_TIME_LEFT_SEC = 'time-left-sec';
+  var CONTEXT_KEY_SHOW_TIME_LEFT = 'show-time-left';
+  var CONTEXT_KEY_UPDATE_MESSAGE = 'update-msg';
+  var CONTEXT_KEY_SHOW_CURTAIN = 'show-curtain';
+  var CONTEXT_KEY_SHOW_PROGRESS_MESSAGE = 'show-progress-msg';
+  var CONTEXT_KEY_PROGRESS = 'progress';
+  var CONTEXT_KEY_PROGRESS_MESSAGE = 'progress-msg';
+  var CONTEXT_KEY_CANCEL_UPDATE_SHORTCUT_ENABLED = 'cancel-update-enabled';
+
   return {
-    EXTERNAL_API: [
-      'enableUpdateCancel',
-      'setUpdateProgress',
-      'showEstimatedTimeLeft',
-      'setEstimatedTimeLeft',
-      'showProgressMessage',
-      'setProgressMessage',
-      'setUpdateMessage',
-      'showUpdateCurtain'
-    ],
+    EXTERNAL_API: [],
+
+    /** @override */
+    decorate: function() {
+      var self = this;
+
+      this.context.addObserver(CONTEXT_KEY_TIME_LEFT_SEC,
+                               function(time_left_sec) {
+        self.setEstimatedTimeLeft(time_left_sec);
+      });
+      this.context.addObserver(CONTEXT_KEY_SHOW_TIME_LEFT,
+                               function(show_time_left) {
+        self.showEstimatedTimeLeft(show_time_left);
+      });
+      this.context.addObserver(CONTEXT_KEY_UPDATE_MESSAGE,
+                               function(update_msg) {
+        self.setUpdateMessage(update_msg);
+      });
+      this.context.addObserver(CONTEXT_KEY_SHOW_CURTAIN,
+                               function(show_curtain) {
+        self.showUpdateCurtain(show_curtain);
+      });
+      this.context.addObserver(CONTEXT_KEY_SHOW_PROGRESS_MESSAGE,
+                               function(show_progress_msg) {
+        self.showProgressMessage(show_progress_msg);
+      });
+      this.context.addObserver(CONTEXT_KEY_PROGRESS,
+                               function(progress) {
+        self.setUpdateProgress(progress);
+      });
+      this.context.addObserver(CONTEXT_KEY_PROGRESS_MESSAGE,
+                               function(progress_msg) {
+        self.setProgressMessage(progress_msg);
+      });
+      this.context.addObserver(CONTEXT_KEY_CANCEL_UPDATE_SHORTCUT_ENABLED,
+                               function(enabled) {
+        $('update-cancel-hint').hidden = !enabled;
+      });
+    },
 
     /**
      * Header text of the screen.
@@ -32,18 +71,12 @@
      */
     cancel: function() {
       // It's safe to act on the accelerator even if it's disabled on official
-      // builds, since Chrome will just ignore the message in that case.
+      // builds, since Chrome will just ignore this user action in that case.
       var updateCancelHint = $('update-cancel-hint').firstElementChild;
       updateCancelHint.textContent =
           loadTimeData.getString('cancelledUpdateMessage');
-      chrome.send('cancelUpdate');
-    },
-
-    /**
-     * Makes 'press Escape to cancel update' hint visible.
-     */
-    enableUpdateCancel: function() {
-      $('update-cancel-hint').hidden = false;
+      this.send(login.Screen.CALLBACK_USER_ACTED,
+                USER_ACTION_CANCEL_UPDATE_SHORTCUT);
     },
 
     /**
diff --git a/chrome/browser/resources/downloads/downloads.css b/chrome/browser/resources/downloads/downloads.css
index 2e632ec..f95268e 100644
--- a/chrome/browser/resources/downloads/downloads.css
+++ b/chrome/browser/resources/downloads/downloads.css
@@ -29,6 +29,10 @@
   position: relative;
 }
 
+.focus-row-active {
+  background-color: rgba(0, 0, 0, .05);
+}
+
 .download,
 #no-downloads-or-results {
   margin-top: 6px;
diff --git a/chrome/browser/resources/downloads/downloads.html b/chrome/browser/resources/downloads/downloads.html
index 7cae33b3..c87227e 100644
--- a/chrome/browser/resources/downloads/downloads.html
+++ b/chrome/browser/resources/downloads/downloads.html
@@ -12,6 +12,10 @@
   <script src="chrome://resources/js/cr/ui/command.js"></script>
   <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="chrome://resources/js/util.js"></script>
+  <script src="chrome://resources/js/assert.js"></script>
+  <script src="chrome://resources/js/event_tracker.js"></script>
+  <script src="chrome://resources/js/cr/ui/focus_row.js"></script>
+  <script src="chrome://resources/js/cr/ui/focus_grid.js"></script>
   <script src="chrome://downloads/downloads.js"></script>
 </head>
 <body>
diff --git a/chrome/browser/resources/downloads/downloads.js b/chrome/browser/resources/downloads/downloads.js
index fd7ccc9..5a3aeb40 100644
--- a/chrome/browser/resources/downloads/downloads.js
+++ b/chrome/browser/resources/downloads/downloads.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 // TODO(jhawkins): Use hidden instead of showInline* and display:none.
+// TODO(hcarmona): This file is big: it may be good to split it up.
 
 /**
  * The type of the download object. The definition is based on
@@ -77,6 +78,103 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// DownloadFocusRow:
+
+/**
+ * Provides an implementation for a single column grid.
+ * @constructor
+ * @extends {cr.ui.FocusRow}
+ */
+function DownloadFocusRow() {}
+
+/**
+ * Decorates |focusRow| so that it can be treated as a DownloadFocusRow.
+ * @param {Element} focusRow The element that has all the columns represented
+ *     by |download|.
+ * @param {Download} download The Download representing this row.
+ * @param {Node} boundary Focus events are ignored outside of this node.
+ */
+DownloadFocusRow.decorate = function(focusRow, download, boundary) {
+  focusRow.__proto__ = DownloadFocusRow.prototype;
+  focusRow.decorate(boundary);
+
+  // Add all clickable elements as a row into the grid.
+  focusRow.addElementIfFocusable_(download.nodeFileLink_, 'name');
+  focusRow.addElementIfFocusable_(download.nodeURL_, 'url');
+  focusRow.addElementIfFocusable_(download.controlShow_, 'show');
+  focusRow.addElementIfFocusable_(download.controlRetry_, 'retry');
+  focusRow.addElementIfFocusable_(download.controlPause_, 'pause');
+  focusRow.addElementIfFocusable_(download.controlResume_, 'resume');
+  focusRow.addElementIfFocusable_(download.controlRemove_, 'remove');
+  focusRow.addElementIfFocusable_(download.controlCancel_, 'cancel');
+  focusRow.addElementIfFocusable_(download.malwareSave_, 'save');
+  focusRow.addElementIfFocusable_(download.dangerSave_, 'save');
+  focusRow.addElementIfFocusable_(download.malwareDiscard_, 'discard');
+  focusRow.addElementIfFocusable_(download.dangerDiscard_, 'discard');
+  focusRow.addElementIfFocusable_(download.controlByExtensionLink_,
+                                  'extension');
+};
+
+DownloadFocusRow.prototype = {
+  __proto__: cr.ui.FocusRow.prototype,
+
+  /** @override */
+  getEquivalentElement: function(element) {
+    if (this.contains(element))
+      return element;
+
+    // All elements default to another element with the same type.
+    var columnType = element.getAttribute('column-type');
+    var equivalent = this.querySelector('[column-type=' + columnType + ']');
+
+    if (!equivalent) {
+      var equivalentTypes =
+          ['show', 'retry', 'pause', 'resume', 'remove', 'cancel'];
+      if (equivalentTypes.indexOf(columnType) != -1) {
+        var allTypes = equivalentTypes.map(function(type) {
+          return '[column-type=' + type + ']';
+        }).join(', ');
+        equivalent = this.querySelector(allTypes);
+      }
+    }
+
+    // Return the first focusable element if no equivalent type is found.
+    return equivalent || this.focusableElements[0];
+  },
+
+  /**
+   * @param {Element} element The element that should be added.
+   * @param {string} type The column type to use for the element.
+   * @private
+   */
+  addElementIfFocusable_: function(element, type) {
+    if (this.shouldFocus_(element)) {
+      this.addFocusableElement(element);
+      element.setAttribute('column-type', type);
+    }
+  },
+
+  /**
+   * Determines if element should be focusable.
+   * @param {!Element} element
+   * @return {boolean}
+   * @private
+   */
+  shouldFocus_: function(element) {
+    if (!element)
+      return false;
+
+    // Hidden elements are not focusable.
+    var style = window.getComputedStyle(element);
+    if (style.visibility == 'hidden' || style.display == 'none')
+      return false;
+
+    // Verify all ancestors are focusable.
+    return !element.parentElement || this.shouldFocus_(element.parentElement);
+  },
+};
+
+///////////////////////////////////////////////////////////////////////////////
 // Downloads
 /**
  * Class to hold all the information about the visible downloads.
@@ -91,6 +189,7 @@
   this.node_ = $('downloads-display');
   this.summary_ = $('downloads-summary-text');
   this.searchText_ = '';
+  this.focusGrid_ = new cr.ui.FocusGrid();
 
   // Keep track of the dates of the newest and oldest downloads so that we
   // know where to insert them.
@@ -176,6 +275,29 @@
 
   if (loadTimeData.getBoolean('allow_deleting_history'))
     $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0;
+
+  this.rebuildFocusGrid_();
+};
+
+/**
+ * Rebuild the focusGrid_ using the elements that each download will have.
+ * @private
+ */
+Downloads.prototype.rebuildFocusGrid_ = function() {
+  this.focusGrid_.destroy();
+
+  var keys = Object.keys(this.downloads_);
+  for (var i = 0; i < keys.length; ++i) {
+    var download = this.downloads_[keys[i]];
+    DownloadFocusRow.decorate(download.node, download, this.node_);
+  }
+
+  // The ordering of the keys is not guaranteed, and downloads should be added
+  // to the FocusGrid in the order they will be in the UI.
+  var downloads = document.querySelectorAll('.download');
+  for (var i = 0; i < downloads.length; ++i) {
+    this.focusGrid_.addRow(downloads[i]);
+  }
 };
 
 /**
diff --git a/chrome/browser/resources/gaia_auth/manifest_keyboard.json b/chrome/browser/resources/gaia_auth/manifest_keyboard.json
index 63d07a19..7718c0b 100644
--- a/chrome/browser/resources/gaia_auth/manifest_keyboard.json
+++ b/chrome/browser/resources/gaia_auth/manifest_keyboard.json
@@ -27,6 +27,7 @@
   ],
   "content_security_policy": "default-src 'self'; script-src 'self'; frame-src *; style-src 'self' 'unsafe-inline'",
   "description": "GAIA Component Extension",
+  "incognito": "split",
   "web_accessible_resources": [
     "main.css",
     "main.html",
diff --git a/chrome/browser/resources/hangout_services/OWNERS b/chrome/browser/resources/hangout_services/OWNERS
index f85f435..b6caf7a 100644
--- a/chrome/browser/resources/hangout_services/OWNERS
+++ b/chrome/browser/resources/hangout_services/OWNERS
@@ -1,2 +1 @@
 bemasc@chromium.org
-vrk@chromium.org
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js
index 9d0cae3e..24a6736 100644
--- a/chrome/browser/resources/history/history.js
+++ b/chrome/browser/resources/history/history.js
@@ -250,6 +250,10 @@
       e.preventDefault();
     }.bind(this));
   }
+
+  if (focusless)
+    bookmarkSection.tabIndex = -1;
+
   entryBox.appendChild(bookmarkSection);
 
   var visitEntryWrapper = /** @type {HTMLElement} */(
@@ -884,69 +888,87 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
-// HistoryFocusObserver:
+// HistoryFocusRow:
 
 /**
+ * Provides an implementation for a single column grid.
  * @constructor
- * @implements {cr.ui.FocusRow.Observer}
+ * @extends {cr.ui.FocusRow}
  */
-function HistoryFocusObserver() {}
+function HistoryFocusRow() {}
 
-HistoryFocusObserver.prototype = {
+/**
+ * Decorates |rowElement| so that it can be treated as a HistoryFocusRow item.
+ * @param {Element} rowElement The element representing this row.
+ * @param {Node} boundary Focus events are ignored outside of this node.
+ */
+HistoryFocusRow.decorate = function(rowElement, boundary) {
+  rowElement.__proto__ = HistoryFocusRow.prototype;
+  rowElement.decorate(boundary);
+
+  rowElement.addElementIfPresent_('.entry-box input', 'checkbox');
+  rowElement.addElementIfPresent_('.domain-checkbox', 'checkbox');
+  rowElement.addElementIfPresent_('.bookmark-section.starred', 'star');
+  rowElement.addElementIfPresent_('[is="action-link"]', 'domain');
+  rowElement.addElementIfPresent_('.title a', 'title');
+  rowElement.addElementIfPresent_('.drop-down', 'menu');
+};
+
+HistoryFocusRow.prototype = {
+  __proto__: cr.ui.FocusRow.prototype,
+
   /** @override */
-  onActivate: function(row) {
-    this.getActiveRowElement_(row).classList.add('active');
+  onActiveStateChanged: function(state) {
+    this.classList.toggle('active', state);
   },
 
   /** @override */
-  onDeactivate: function(row) {
-    this.getActiveRowElement_(row).classList.remove('active');
+  getEquivalentElement: function(element) {
+    if (this.contains(element))
+      return element;
+
+    // All elements default to another element with the same type.
+    var equivalent = this.getColumn_(element.getAttribute('column-type'));
+
+    if (!equivalent) {
+      switch (element.getAttribute('column-type')) {
+        case 'star':
+          equivalent = this.getColumn_('title') || this.getColumn_('domain');
+          break;
+        case 'domain':
+          equivalent = this.getColumn_('title');
+          break;
+        case 'title':
+          equivalent = this.getColumn_('domain');
+          break;
+        case 'menu':
+          return this.focusableElements[this.focusableElements.length - 1];
+      }
+    }
+
+    return equivalent || this.focusableElements[0];
   },
 
   /**
-   * @param {cr.ui.FocusRow} row The row to find an element for.
-   * @return {Element} |row|'s "active" element.
+   * @param {string} type The type of column to return.
+   * @return {?Element} The column matching the type.
    * @private
    */
-  getActiveRowElement_: function(row) {
-    return findAncestorByClass(row.items[0], 'entry') ||
-           findAncestorByClass(row.items[0], 'site-domain-wrapper');
+  getColumn_: function(type) {
+    return this.querySelector('[column-type=' + type + ']');
   },
-};
 
-///////////////////////////////////////////////////////////////////////////////
-// HistoryFocusGrid:
-
-/**
- * @param {Node=} opt_boundary
- * @param {cr.ui.FocusRow.Observer=} opt_observer
- * @constructor
- * @extends {cr.ui.FocusGrid}
- */
-function HistoryFocusGrid(opt_boundary, opt_observer) {
-  cr.ui.FocusGrid.apply(this, arguments);
-}
-
-HistoryFocusGrid.prototype = {
-  __proto__: cr.ui.FocusGrid.prototype,
-
-  /** @override */
-  onMousedown: function(row, e) {
-    // TODO(dbeam): Can cr.ui.FocusGrid know about cr.ui.MenuButton? If so, bake
-    // this logic into the base class directly.
-    var menuButton = findAncestorByClass(e.target, 'menu-button');
-    if (menuButton) {
-      // Deactivate any other active row.
-      this.rows.some(function(r) {
-        if (r.activeIndex >= 0 && r != row) {
-          r.activeIndex = -1;
-          return true;
-        }
-      });
-      // Activate only the row with a pressed menu button.
-      row.activeIndex = row.items.indexOf(menuButton);
+  /**
+   * @param {string} query A query to select the appropriate element.
+   * @param {string} type The type to use for the element.
+   * @private
+   */
+  addElementIfPresent_: function(query, type) {
+    var element = this.querySelector(query);
+    if (element) {
+      this.addFocusableElement(element);
+      element.setAttribute('column-type', type);
     }
-    return !!menuButton;
   },
 };
 
@@ -964,8 +986,7 @@
   this.editButtonTd_ = $('edit-button');
   this.editingControlsDiv_ = $('editing-controls');
   this.resultDiv_ = $('results-display');
-  this.focusGrid_ = new HistoryFocusGrid(this.resultDiv_,
-                                         new HistoryFocusObserver);
+  this.focusGrid_ = new cr.ui.FocusGrid();
   this.pageDiv_ = $('results-pagination');
   this.model_ = model;
   this.pageIndex_ = 0;
@@ -1197,14 +1218,14 @@
 HistoryView.prototype.onBeforeRemove = function(visit) {
   assert(this.currentVisits_.indexOf(visit) >= 0);
 
-  var pos = this.focusGrid_.getPositionForTarget(document.activeElement);
-  if (!pos)
+  var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement);
+  if (rowIndex == -1)
     return;
 
-  var row = this.focusGrid_.rows[pos.row + 1] ||
-            this.focusGrid_.rows[pos.row - 1];
-  if (row)
-    row.focusIndex(Math.min(pos.col, row.items.length - 1));
+  var rowToFocus = this.focusGrid_.rows[rowIndex + 1] ||
+                   this.focusGrid_.rows[rowIndex - 1];
+  if (rowToFocus)
+    rowToFocus.getEquivalentElement(document.activeElement).focus();
 };
 
 /** @param {Visit} visit The visit about to be unstarred. */
@@ -1212,9 +1233,12 @@
   assert(this.currentVisits_.indexOf(visit) >= 0);
   assert(visit.bookmarkStar == document.activeElement);
 
-  var pos = this.focusGrid_.getPositionForTarget(document.activeElement);
-  var row = this.focusGrid_.rows[pos.row];
-  row.focusIndex(Math.min(pos.col + 1, row.items.length - 1));
+  var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement);
+  var row = this.focusGrid_.rows[rowIndex];
+
+  // Focus the title or domain when the bookmarked star is removed because the
+  // star will no longer be focusable.
+  row.querySelector('[column-type=title], [column-type=domain]').focus();
 };
 
 /** @param {Visit} visit The visit that was just unstarred. */
@@ -1312,7 +1336,7 @@
  * @return {boolean} Whether |el| is in |this.focusGrid_|.
  */
 HistoryView.prototype.isInFocusGrid = function(el) {
-  return !!this.focusGrid_.getPositionForTarget(el);
+  return this.focusGrid_.getRowIndexForTarget(el) != -1;
 };
 
 // HistoryView, private: ------------------------------------------------------
@@ -1674,26 +1698,16 @@
   '.site-domain-wrapper'
 ].join(', ');
 
-var focusGridColumnSelector = [
-  '.entry-box input',
-  '.bookmark-section.starred',
-  '.title a',
-  '.drop-down',
-  '.domain-checkbox',
-  '[is="action-link"]',
-].join(', ');
-
 /** @private */
 HistoryView.prototype.updateFocusGrid_ = function() {
   var rows = this.resultDiv_.querySelectorAll(focusGridRowSelector);
-  var grid = [];
+  this.focusGrid_.destroy();
 
   for (var i = 0; i < rows.length; ++i) {
     assert(rows[i].parentNode);
-    grid.push(rows[i].querySelectorAll(focusGridColumnSelector));
+    HistoryFocusRow.decorate(rows[i], this.resultDiv_);
+    this.focusGrid_.addRow(rows[i]);
   }
-
-  this.focusGrid_.setGrid(grid);
 };
 
 /**
diff --git a/chrome/browser/resources/history/history_mobile.css b/chrome/browser/resources/history/history_mobile.css
index fc73e7c..8cd9bcc6 100644
--- a/chrome/browser/resources/history/history_mobile.css
+++ b/chrome/browser/resources/history/history_mobile.css
@@ -4,6 +4,10 @@
 
 /* This file contains styles specific to Android and iOS. */
 
+html:not(.focus-outline-visible) :focus {
+  outline: none;
+}
+
 html {
   height: 100%;
 }
diff --git a/chrome/browser/resources/history/other_devices.js b/chrome/browser/resources/history/other_devices.js
index 33e4bd4..f0ebe80 100644
--- a/chrome/browser/resources/history/other_devices.js
+++ b/chrome/browser/resources/history/other_devices.js
@@ -427,6 +427,33 @@
 // DevicesView, Private -------------------------------------------------------
 
 /**
+ * Provides an implementation for a single column grid.
+ * @constructor
+ * @extends {cr.ui.FocusRow}
+ */
+function DevicesViewFocusRow() {}
+
+/**
+ * Decorates |rowElement| so that it can be treated as a DevicesViewFocusRow.
+ * @param {Element} rowElement The element representing this row.
+ * @param {Node} boundary Focus events are ignored outside of this node.
+ */
+DevicesViewFocusRow.decorate = function(rowElement, boundary) {
+  rowElement.__proto__ = DevicesViewFocusRow.prototype;
+  rowElement.decorate(boundary);
+  rowElement.addFocusableElement(rowElement);
+};
+
+DevicesViewFocusRow.prototype = {
+  __proto__: cr.ui.FocusRow.prototype,
+
+  /** @override */
+  getEquivalentElement: function(element) {
+    return this;
+  },
+};
+
+/**
  * Update the page with results.
  * @private
  */
@@ -479,16 +506,17 @@
   this.focusGrids_.forEach(function(grid) { grid.destroy(); });
   this.focusGrids_.length = 0;
 
-  var singleColumn = function(e) { return [e]; };
-
   var devices = this.resultDiv_.querySelectorAll('.device-contents');
   for (var i = 0; i < devices.length; ++i) {
     var rows = devices[i].querySelectorAll('.device-tab-entry, button');
     if (!rows.length)
       continue;
 
-    var grid = new cr.ui.FocusGrid(devices[i]);
-    grid.setGrid(Array.prototype.map.call(rows, singleColumn));
+    var grid = new cr.ui.FocusGrid();
+    for (var i = 0; i < rows.length; ++i) {
+      DevicesViewFocusRow.decorate(rows[i], devices[i]);
+      grid.addRow(rows[i]);
+    }
     this.focusGrids_.push(grid);
   }
 };
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index 8ce8fe00..96ad0ca6 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -17,13 +17,14 @@
  * are available, the Javascript formats them and displays them.
  */
 define('main', [
+    'mojo/public/js/bindings',
+    'mojo/public/js/core',
     'mojo/public/js/connection',
     'chrome/browser/ui/webui/omnibox/omnibox.mojom',
     'content/public/renderer/service_provider',
-], function(connector, browser, serviceProvider) {
+], function(bindings, core, connection, browser, serviceProvider) {
   'use strict';
 
-  var connection;
   var page;
 
   /**
@@ -71,12 +72,17 @@
     // - forth element: the value of prefer-keyword
     // - fifth element: the value of page-classification
     cursorPositionUsed = $('input-text').selectionEnd;
+    var pipe = core.createMessagePipe();
+    var stub = connection.bindHandleToStub(pipe.handle0, browser.OmniboxPage);
+    bindings.StubBindings(stub).delegate = page;
+    page.stub_ = stub;
     page.browser_.startOmniboxQuery(
         $('input-text').value,
         cursorPositionUsed,
         $('prevent-inline-autocomplete').checked,
         $('prefer-keyword').checked,
-        parseInt($('page-classification').value));
+        parseInt($('page-classification').value),
+        pipe.handle1);
     // Cancel the submit action.  i.e., don't submit the form.  (We handle
     // display the results solely with Javascript.)
     event.preventDefault();
@@ -421,7 +427,6 @@
 
   function OmniboxPageImpl(browser) {
     this.browser_ = browser;
-    page = this;
     initialize();
   }
 
@@ -434,10 +439,10 @@
   };
 
   return function() {
-    connection = new connector.Connection(
+    var browserProxy = connection.bindHandleToProxy(
         serviceProvider.connectToService(
             browser.OmniboxUIHandlerMojo.name),
-        OmniboxPageImpl,
-        browser.OmniboxUIHandlerMojo.proxyClass);
+        browser.OmniboxUIHandlerMojo);
+    page = new OmniboxPageImpl(browserProxy);
   };
 });
diff --git a/chrome/browser/resources/pdf/elements/viewer-pane/viewer-pane.css b/chrome/browser/resources/pdf/elements/viewer-pane/viewer-pane.css
index a84a0b5f3..b9c35e50 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pane/viewer-pane.css
+++ b/chrome/browser/resources/pdf/elements/viewer-pane/viewer-pane.css
@@ -10,10 +10,10 @@
    */
   direction: rtl;
   font-family: Roboto, 'Helvetica Neue', Helvetica, Arial;
-  height: calc(100% - 64px);
+  height: calc(100% - 56px);
   margin: 0;
   right: 0;
-  top: 64px;
+  top: 56px;
   width: 22em;
 }
 
diff --git a/chrome/browser/resources/pdf/index-material.css b/chrome/browser/resources/pdf/index-material.css
index e9b12c6..f38941a 100644
--- a/chrome/browser/resources/pdf/index-material.css
+++ b/chrome/browser/resources/pdf/index-material.css
@@ -26,6 +26,10 @@
   z-index: 3;
 }
 
+core-toolbar /deep/ ::selection {
+  background: rgb(187, 222, 251);
+}
+
 #toolbar-shadow {
   position: fixed;
   width: 100%;
diff --git a/chrome/browser/resources/pdf/index-material.html b/chrome/browser/resources/pdf/index-material.html
index af1870c..2f34e4b2 100644
--- a/chrome/browser/resources/pdf/index-material.html
+++ b/chrome/browser/resources/pdf/index-material.html
@@ -9,6 +9,7 @@
   <link rel="import" href="elements/viewer-password-screen/viewer-password-screen.html">
   <link rel="import" href="elements/viewer-toolbar/viewer-toolbar.html">
 
+  <link rel="import" href="chrome://resources/polymer/core-icons/image-icons.html">
   <link rel="import" href="chrome://resources/polymer/core-toolbar/core-toolbar.html">
   <link rel="import" href="chrome://resources/polymer/paper-icon-button/paper-icon-button.html">
   <link rel="import" href="chrome://resources/polymer/paper-progress/paper-progress.html">
@@ -25,6 +26,7 @@
 
     <viewer-page-selector id="page-indicator" flex></viewer-page-selector>
 
+    <paper-icon-button icon="image:rotate-right" id="rotate-right-button"></paper-icon-button>
     <paper-icon-button icon="bookmark-outline" id="bookmarks-button"></paper-icon-button>
     <paper-icon-button icon="file-download" id="save-button"></paper-icon-button>
     <paper-icon-button icon="print" id="print-button"></paper-icon-button>
diff --git a/chrome/browser/resources/pdf/pdf.js b/chrome/browser/resources/pdf/pdf.js
index ef62ca7..c1c9931 100644
--- a/chrome/browser/resources/pdf/pdf.js
+++ b/chrome/browser/resources/pdf/pdf.js
@@ -162,6 +162,8 @@
     $('bookmarks-button').addEventListener('click', function() {
       this.bookmarksPane.toggle();
     }.bind(this));
+    $('rotate-right-button').addEventListener('click',
+        this.rotateClockwise_.bind(this));
   }
 
   // Setup the keyboard event listener.
@@ -206,7 +208,7 @@
   handleKeyEvent_: function(e) {
     var position = this.viewport_.position;
     // Certain scroll events may be sent from outside of the extension.
-    var fromScriptingAPI = e.type == 'scriptingKeypress';
+    var fromScriptingAPI = e.fromScriptingAPI;
 
     var pageUpHandler = function() {
       // Go to the previous page if we are fit-to-page.
@@ -306,20 +308,42 @@
         }
         return;
       case 219:  // left bracket.
-        if (e.ctrlKey) {
-          this.plugin_.postMessage({
-            type: 'rotateCounterclockwise'
-          });
-        }
+        if (e.ctrlKey)
+          this.rotateCounterClockwise_();
         return;
       case 221:  // right bracket.
-        if (e.ctrlKey) {
-          this.plugin_.postMessage({
-            type: 'rotateClockwise'
-          });
-        }
+        if (e.ctrlKey)
+          this.rotateClockwise_();
         return;
     }
+
+    // Give print preview a chance to handle the key event.
+    if (!fromScriptingAPI && this.isPrintPreview_) {
+      this.sendScriptingMessage_({
+        type: 'sendKeyEvent',
+        keyEvent: SerializeKeyEvent(e)
+      });
+    }
+  },
+
+  /**
+   * @private
+   * Rotate the plugin clockwise.
+   */
+  rotateClockwise_: function() {
+    this.plugin_.postMessage({
+      type: 'rotateClockwise'
+    });
+  },
+
+  /**
+   * @private
+   * Rotate the plugin counter-clockwise.
+   */
+  rotateCounterClockwise_: function() {
+    this.plugin_.postMessage({
+      type: 'rotateCounterclockwise'
+    });
   },
 
   /**
@@ -699,10 +723,7 @@
         });
         return true;
       case 'sendKeyEvent':
-        var e = document.createEvent('Event');
-        e.initEvent('scriptingKeypress');
-        e.keyCode = message.data.keyCode;
-        this.handleKeyEvent_(e);
+        this.handleKeyEvent_(DeserializeKeyEvent(message.data.keyEvent));
         return true;
     }
 
diff --git a/chrome/browser/resources/pdf/pdf_extension_test.cc b/chrome/browser/resources/pdf/pdf_extension_test.cc
index 6a56a91..d89c474 100644
--- a/chrome/browser/resources/pdf/pdf_extension_test.cc
+++ b/chrome/browser/resources/pdf/pdf_extension_test.cc
@@ -41,11 +41,6 @@
   }
 
   void RunTestsInFile(std::string filename, std::string pdf_filename) {
-    base::FilePath pdf_path;
-    ASSERT_TRUE(PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path));
-    ASSERT_TRUE(
-        content::PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(
-            pdf_path));
     ExtensionService* service = extensions::ExtensionSystem::Get(
         profile())->extension_service();
     service->component_loader()->Add(IDR_PDF_MANIFEST,
diff --git a/chrome/browser/resources/pdf/pdf_scripting_api.js b/chrome/browser/resources/pdf/pdf_scripting_api.js
index 59c4d40..03f14de6 100644
--- a/chrome/browser/resources/pdf/pdf_scripting_api.js
+++ b/chrome/browser/resources/pdf/pdf_scripting_api.js
@@ -3,6 +3,38 @@
 // found in the LICENSE file.
 
 /**
+ * Turn a dictionary received from postMessage into a key event.
+ * @param {Object} dict A dictionary representing the key event.
+ * @return {Event} A key event.
+ */
+function DeserializeKeyEvent(dict) {
+  var e = document.createEvent('Event');
+  e.initEvent('keydown');
+  e.keyCode = dict.keyCode;
+  e.shiftKey = dict.shiftKey;
+  e.ctrlKey = dict.ctrlKey;
+  e.altKey = dict.altKey;
+  e.metaKey = dict.metaKey;
+  e.fromScriptingAPI = true;
+  return e;
+}
+
+/**
+ * Turn a key event into a dictionary which can be sent over postMessage.
+ * @param {Event} event A key event.
+ * @return {Object} A dictionary representing the key event.
+ */
+function SerializeKeyEvent(event) {
+  return {
+    keyCode: event.keyCode,
+    shiftKey: event.shiftKey,
+    ctrlKey: event.ctrlKey,
+    altKey: event.altKey,
+    metaKey: event.metaKey
+  };
+}
+
+/**
  * Create a new PDFScriptingAPI. This provides a scripting interface to
  * the PDF viewer so that it can be customized by things like print preview.
  * @param {Window} window the window of the page containing the pdf viewer.
@@ -45,6 +77,10 @@
           this.selectedTextCallback_ = null;
         }
         break;
+      case 'sendKeyEvent':
+        if (this.keyEventCallback_)
+          this.keyEventCallback_(DeserializeKeyEvent(event.data.keyEvent));
+        break;
     }
   }.bind(this), false);
 }
@@ -104,6 +140,14 @@
   },
 
   /**
+   * Sets a callback that gets run when a key event is fired in the PDF viewer.
+   * @param {Function} callback the callback to be called with a key event.
+   */
+  setKeyEventCallback: function(callback) {
+    this.keyEventCallback_ = callback;
+  },
+
+  /**
    * Resets the PDF viewer into print preview mode.
    * @param {string} url the url of the PDF to load.
    * @param {boolean} grayscale whether or not to display the PDF in grayscale.
@@ -196,12 +240,12 @@
 
   /**
    * Send a key event to the extension.
-   * @param {number} keyCode the key code to send to the extension.
+   * @param {Event} keyEvent the key event to send to the extension.
    */
-  sendKeyEvent: function(keyCode) {
+  sendKeyEvent: function(keyEvent) {
     this.sendMessage_({
       type: 'sendKeyEvent',
-      keyCode: keyCode
+      keyEvent: SerializeKeyEvent(keyEvent)
     });
   },
 };
@@ -227,6 +271,7 @@
   iframe.setViewportChangedCallback =
       client.setViewportChangedCallback.bind(client);
   iframe.setLoadCallback = client.setLoadCallback.bind(client);
+  iframe.setKeyEventCallback = client.setKeyEventCallback.bind(client);
   iframe.resetPrintPreviewMode = client.resetPrintPreviewMode.bind(client);
   iframe.loadPreviewPage = client.loadPreviewPage.bind(client);
   iframe.sendKeyEvent = client.sendKeyEvent.bind(client);
diff --git a/chrome/browser/resources/plugin_metadata/OWNERS b/chrome/browser/resources/plugin_metadata/OWNERS
index e7e17284..981dd0a 100644
--- a/chrome/browser/resources/plugin_metadata/OWNERS
+++ b/chrome/browser/resources/plugin_metadata/OWNERS
@@ -1,2 +1,3 @@
 bauerb@chromium.org
 jschuh@chromium.org
+wfh@chromium.org
diff --git a/chrome/browser/resources/print_preview/data/app_state.js b/chrome/browser/resources/print_preview/data/app_state.js
index a8ebb06..6d90373 100644
--- a/chrome/browser/resources/print_preview/data/app_state.js
+++ b/chrome/browser/resources/print_preview/data/app_state.js
@@ -39,6 +39,7 @@
     SELECTED_DESTINATION_ORIGIN: 'selectedDestinationOrigin',
     SELECTED_DESTINATION_CAPABILITIES: 'selectedDestinationCapabilities',
     SELECTED_DESTINATION_NAME: 'selectedDestinationName',
+    SELECTED_DESTINATION_EXTENSION_ID: 'selectedDestinationExtensionId',
     IS_GCP_PROMO_DISMISSED: 'isGcpPromoDismissed',
     DPI: 'dpi',
     MEDIA_SIZE: 'mediaSize',
@@ -99,6 +100,13 @@
       return this.state_[AppState.Field.SELECTED_DESTINATION_NAME];
     },
 
+    /**
+     * @return {?string} Extension ID associated with the selected destination.
+     */
+    get selectedDestinationExtensionId() {
+      return this.state_[AppState.Field.SELECTED_DESTINATION_EXTENSION_ID];
+    },
+
     /** @return {boolean} Whether the GCP promotion has been dismissed. */
     get isGcpPromoDismissed() {
       return this.state_[AppState.Field.IS_GCP_PROMO_DISMISSED];
@@ -193,6 +201,8 @@
       this.state_[AppState.Field.SELECTED_DESTINATION_CAPABILITIES] =
           dest.capabilities;
       this.state_[AppState.Field.SELECTED_DESTINATION_NAME] = dest.displayName;
+      this.state_[AppState.Field.SELECTED_DESTINATION_EXTENSION_ID] =
+          dest.extensionId;
       this.persist_();
     },
 
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index 4bbaeb12..a644acb8b 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -54,6 +54,7 @@
    *          lastAccessTime: (number|undefined),
    *          isTosAccepted: (boolean|undefined),
    *          cloudID: (string|undefined),
+   *          extensionId: (string|undefined),
    *          description: (string|undefined)}=} opt_params Optional parameters
    *     for the destination.
    * @constructor
@@ -153,6 +154,12 @@
      * @private {string}
      */
     this.cloudID_ = (opt_params && opt_params.cloudID) || '';
+
+    /**
+     * Extension ID for extension managed printers.
+     * @private {string}
+     */
+    this.extensionId_ = (opt_params && opt_params.extensionId) || '';
   };
 
   /**
@@ -195,7 +202,8 @@
     COOKIES: 'cookies',
     PROFILE: 'profile',
     DEVICE: 'device',
-    PRIVET: 'privet'
+    PRIVET: 'privet',
+    EXTENSION: 'extension'
   };
 
   /**
@@ -280,6 +288,7 @@
     /** @return {boolean} Whether the destination is local or cloud-based. */
     get isLocal() {
       return this.origin_ == Destination.Origin.LOCAL ||
+             this.origin_ == Destination.Origin.EXTENSION ||
              (this.origin_ == Destination.Origin.PRIVET &&
               this.connectionStatus_ !=
               Destination.ConnectionStatus.UNREGISTERED);
@@ -291,6 +300,14 @@
     },
 
     /**
+     * @return {boolean} Whether the destination is an extension managed
+     *     printer.
+     */
+    get isExtension() {
+      return this.origin_ == Destination.Origin.EXTENSION;
+    },
+
+    /**
      * @return {string} The location of the destination, or an empty string if
      *     the location is unknown.
      */
@@ -339,6 +356,14 @@
       return this.cloudID_;
     },
 
+    /**
+     * @return {string} Extension ID associated with the destination. Non-empty
+     *     only for extension managed printers.
+     */
+    get extensionId() {
+      return this.extensionId_;
+    },
+
     /** @return {?print_preview.Cdd} Print capabilities of the destination. */
     get capabilities() {
       return this.capabilities_;
@@ -410,6 +435,10 @@
         return Destination.IconUrl_.FEDEX;
       } else if (this.id_ == Destination.GooglePromotedId.SAVE_AS_PDF) {
         return Destination.IconUrl_.PDF;
+      } else if (this.isExtension) {
+        // TODO(tbarzic): Update the way extension printers are displayed in the
+        // destination list when the desired UX is defined.
+        return 'chrome://extension-icon/' + this.extensionId + '/48/1';
       } else if (this.isLocal) {
         return Destination.IconUrl_.LOCAL;
       } else if (this.type_ == Destination.Type.MOBILE && this.isOwned_) {
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index b3249f2..267cb8b 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -154,6 +154,29 @@
     this.privetSearchTimeout_ = null;
 
     /**
+     * Whether a search for extension destinations is in progress.
+     * @type {boolean}
+     * @private
+     */
+    this.isExtensionDestinationSearchInProgress_ = false;
+
+    /**
+     * Whether the destination store has already loaded all extension
+     * destinations.
+     * @type {boolean}
+     * @private
+     */
+    this.hasLoadedAllExtensionDestinations_ = false;
+
+    /**
+     * ID of a timeout set at the start of an extension destination search. The
+     * timeout ends the search.
+     * @type {?number}
+     * @private
+     */
+    this.extensionSearchTimeout_ = null;
+
+    /**
      * MDNS service name of destination that we are waiting to register.
      * @type {?string}
      * @private
@@ -201,6 +224,15 @@
   DestinationStore.PRIVET_SEARCH_DURATION_ = 2000;
 
   /**
+   * Maximum amount of time spent searching for extension destinations, in
+   * milliseconds.
+   * @type {number}
+   * @const
+   * @private
+   */
+  DestinationStore.EXTENSION_SEARCH_DURATION_ = 5000;
+
+  /**
    * Localizes printer capabilities.
    * @param {!Object} capabilities Printer capabilities to localize.
    * @return {!Object} Localized capabilities.
@@ -267,7 +299,8 @@
      */
     get isLocalDestinationSearchInProgress() {
       return this.isLocalDestinationSearchInProgress_ ||
-        this.isPrivetDestinationSearchInProgress_;
+        this.isPrivetDestinationSearchInProgress_ ||
+        this.isExtensionDestinationSearchInProgress_;
     },
 
     /**
@@ -339,6 +372,28 @@
           cr.dispatchSimpleEvent(
             this,
             DestinationStore.EventType.CACHED_SELECTED_DESTINATION_INFO_READY);
+        } else if (this.appState_.selectedDestinationOrigin ==
+                   print_preview.Destination.Origin.EXTENSION) {
+          // TODO(tbarzic): Add support for requesting a single extension's
+          // printer list.
+          this.startLoadExtensionDestinations();
+
+          this.selectedDestination_ =
+              print_preview.ExtensionDestinationParser.parse({
+                extensionId: this.appState_.selectedDestinationExtensionId,
+                id: this.appState_.selectedDestinationId,
+                name: this.appState_.selectedDestinationName || ''
+              });
+
+          if (this.appState_.selectedDestinationCapabilities) {
+            this.selectedDestination_.capabilities =
+                this.appState_.selectedDestinationCapabilities;
+
+            cr.dispatchSimpleEvent(
+                this,
+                DestinationStore.EventType
+                    .CACHED_SELECTED_DESTINATION_INFO_READY);
+          }
         } else {
           this.selectDefaultDestination_();
         }
@@ -437,8 +492,10 @@
         if (destination.isPrivet) {
           this.nativeLayer_.startGetPrivetDestinationCapabilities(
               destination.id);
-        }
-        else if (destination.isLocal) {
+        } else if (destination.isExtension) {
+          this.nativeLayer_.startGetExtensionDestinationCapabilities(
+              destination.id);
+        } else if (destination.isLocal) {
           this.nativeLayer_.startGetLocalDestinationCapabilities(
               destination.id);
         } else {
@@ -481,18 +538,35 @@
     /** Initiates loading of privet print destinations. */
     startLoadPrivetDestinations: function() {
       if (!this.hasLoadedAllPrivetDestinations_) {
+        if (this.privetDestinationSearchInProgress_)
+          clearTimeout(this.privetSearchTimeout_);
         this.isPrivetDestinationSearchInProgress_ = true;
         this.nativeLayer_.startGetPrivetDestinations();
         cr.dispatchSimpleEvent(
             this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED);
-        if (this.privetDestinationSearchInProgress_)
-          clearTimeout(this.privetSearchTimeout_);
         this.privetSearchTimeout_ = setTimeout(
             this.endPrivetPrinterSearch_.bind(this),
             DestinationStore.PRIVET_SEARCH_DURATION_);
       }
     },
 
+    /** Initializes loading of extension managed print destinations. */
+    startLoadExtensionDestinations: function() {
+      if (this.hasLoadedAllExtensionDestinations_)
+        return;
+
+      if (this.isExtensionDestinationSearchInProgress_)
+        clearTimeout(this.extensionSearchTimeout_);
+
+      this.isExtensionDestinationSearchInProgress_ = true;
+      this.nativeLayer_.startGetExtensionDestinations();
+      cr.dispatchSimpleEvent(
+          this, DestinationStore.EventType.DESTINATION_SEARCH_STARTED);
+      this.extensionSearchTimeout_ = setTimeout(
+          this.endExtensionPrinterSearch_.bind(this),
+          DestinationStore.EXTENSION_SEARCH_DURATION_);
+    },
+
     /**
      * Initiates loading of cloud destinations.
      * @param {print_preview.Destination.Origin=} opt_origin Search destinations
@@ -528,6 +602,7 @@
       this.startLoadCloudDestinations();
       this.startLoadLocalDestinations();
       this.startLoadPrivetDestinations();
+      this.startLoadExtensionDestinations();
     },
 
     /**
@@ -632,6 +707,21 @@
     },
 
     /**
+     * Called when loading of extension managed printers is done.
+     * @private
+     */
+    endExtensionPrinterSearch_: function() {
+      this.isExtensionDestinationSearchInProgress_ = false;
+      this.hasLoadedAllExtensionDestinations_ = true;
+      cr.dispatchSimpleEvent(
+          this, DestinationStore.EventType.DESTINATION_SEARCH_DONE);
+      // Clear initially selected (cached) extension destination if it hasn't
+      // been found among reported extension destinations.
+      if (this.isInAutoSelectMode_ && this.selectedDestination_.isExtension)
+        this.selectDefaultDestination_();
+    },
+
+    /**
      * Inserts a destination into the store without dispatching any events.
      * @return {boolean} Whether the inserted destination was not already in the
      *     store.
@@ -684,6 +774,14 @@
           this.nativeLayer_,
           print_preview.NativeLayer.EventType.PRIVET_CAPABILITIES_SET,
           this.onPrivetCapabilitiesSet_.bind(this));
+      this.tracker_.add(
+          this.nativeLayer_,
+          print_preview.NativeLayer.EventType.EXTENSION_PRINTERS_ADDED,
+          this.onExtensionPrintersAdded_.bind(this));
+      this.tracker_.add(
+          this.nativeLayer_,
+          print_preview.NativeLayer.EventType.EXTENSION_CAPABILITIES_SET,
+          this.onExtensionCapabilitiesSet_.bind(this));
     },
 
     /**
@@ -716,6 +814,7 @@
       this.loadedCloudOrigins_ = {};
       this.hasLoadedAllLocalDestinations_ = false;
       this.hasLoadedAllPrivetDestinations_ = false;
+      this.hasLoadedAllExtensionDestinations_ = false;
 
       clearTimeout(this.autoSelectTimeout_);
       this.autoSelectTimeout_ = setTimeout(
@@ -891,7 +990,6 @@
      * @private
      */
     onPrivetCapabilitiesSet_: function(event) {
-      var destinationId = event.printerId;
       var destinations =
           print_preview.PrivetDestinationParser.parse(event.printer);
       destinations.forEach(function(dest) {
@@ -901,6 +999,43 @@
     },
 
     /**
+     * Called when an extension responds to a getExtensionDestinations
+     * request.
+     * @param {Object} event Contains information about list of printers
+     *     reported by the extension.
+     *     {@code done} parameter is set iff this is the final list of printers
+     *     returned as part of getExtensionDestinations request.
+     * @private
+     */
+    onExtensionPrintersAdded_: function(event) {
+      this.insertDestinations_(event.printers.map(function(printer) {
+        return print_preview.ExtensionDestinationParser.parse(printer);
+      }));
+
+      if (event.done && this.isExtensionDestinationSearchInProgress_) {
+        clearTimeout(this.extensionSearchTimeout_);
+        this.endExtensionPrinterSearch_();
+      }
+    },
+
+    /**
+     * Called when capabilities for an extension managed printer are set.
+     * @param {Object} event Contains the printer's capabilities and ID.
+     * @private
+     */
+    onExtensionCapabilitiesSet_: function(event) {
+      var destinationKey = this.getDestinationKey_(
+          print_preview.Destination.Origin.EXTENSION,
+          event.printerId,
+          '' /* account */);
+      var destination = this.destinationMap_[destinationKey];
+      if (!destination)
+        return;
+      destination.capabilities = event.capabilities;
+      this.updateDestination_(destination);
+    },
+
+    /**
      * Called from native layer after the user was requested to sign in, and did
      * so successfully.
      * @private
diff --git a/chrome/browser/resources/print_preview/data/local_parsers.js b/chrome/browser/resources/print_preview/data/local_parsers.js
index c15fb59..c7c3e19 100644
--- a/chrome/browser/resources/print_preview/data/local_parsers.js
+++ b/chrome/browser/resources/print_preview/data/local_parsers.js
@@ -66,9 +66,30 @@
     return returnedPrinters;
   };
 
+  function ExtensionDestinationParser() {}
+
+  /**
+   * Parses an extension destination from an extension supplied printer
+   * description.
+   * @param {!Object} destinationInfo Object describing an extension printer.
+   * @return {!print_preview.Destination} Parsed destination.
+   */
+  ExtensionDestinationParser.parse = function(destinationInfo) {
+    return new print_preview.Destination(
+        destinationInfo.id,
+        print_preview.Destination.Type.LOCAL,
+        print_preview.Destination.Origin.EXTENSION,
+        destinationInfo.name,
+        false /* isRecent */,
+        print_preview.Destination.ConnectionStatus.ONLINE,
+        {description: destinationInfo.description || '',
+         extensionId: destinationInfo.extensionId});
+  };
+
   // Export
   return {
     LocalDestinationParser: LocalDestinationParser,
-    PrivetDestinationParser: PrivetDestinationParser
+    PrivetDestinationParser: PrivetDestinationParser,
+    ExtensionDestinationParser: ExtensionDestinationParser
   };
 });
diff --git a/chrome/browser/resources/print_preview/native_layer.js b/chrome/browser/resources/print_preview/native_layer.js
index d4beb89..d61da749 100644
--- a/chrome/browser/resources/print_preview/native_layer.js
+++ b/chrome/browser/resources/print_preview/native_layer.js
@@ -36,6 +36,8 @@
         this.onFailedToGetPrinterCapabilities_.bind(this);
     global.failedToGetPrivetPrinterCapabilities =
       this.onFailedToGetPrivetPrinterCapabilities_.bind(this);
+    global.failedToGetExtensionPrinterCapabilities =
+        this.onFailedToGetExtensionPrinterCapabilities_.bind(this);
     global.reloadPrintersList = this.onReloadPrintersList_.bind(this);
     global.printToCloud = this.onPrintToCloud_.bind(this);
     global.fileSelectionCancelled =
@@ -57,6 +59,10 @@
     global.onPrivetCapabilitiesSet =
         this.onPrivetCapabilitiesSet_.bind(this);
     global.onPrivetPrintFailed = this.onPrivetPrintFailed_.bind(this);
+    global.onExtensionPrintersAdded =
+        this.onExtensionPrintersAdded_.bind(this);
+    global.onExtensionCapabilitiesSet =
+        this.onExtensionCapabilitiesSet_.bind(this);
     global.onEnableManipulateSettingsForTest =
         this.onEnableManipulateSettingsForTest_.bind(this);
     global.printPresetOptionsFromDocument =
@@ -95,6 +101,10 @@
     PRIVET_CAPABILITIES_SET:
         'print_preview.NativeLayer.PRIVET_CAPABILITIES_SET',
     PRIVET_PRINT_FAILED: 'print_preview.NativeLayer.PRIVET_PRINT_FAILED',
+    EXTENSION_PRINTERS_ADDED:
+        'print_preview.NativeLayer.EXTENSION_PRINTERS_ADDED',
+    EXTENSION_CAPABILITIES_SET:
+        'print_preview.NativeLayer.EXTENSION_CAPABILITIES_SET',
     PRINT_PRESET_OPTIONS: 'print_preview.NativeLayer.PRINT_PRESET_OPTIONS',
   };
 
@@ -177,6 +187,24 @@
     },
 
     /**
+     * Requests that extension system dispatches an event requesting the list of
+     * extension managed printers.
+     */
+    startGetExtensionDestinations: function() {
+      chrome.send('getExtensionPrinters');
+    },
+
+    /**
+     * Requests an extension destination's printing capabilities. A
+     * EXTENSION_CAPABILITIES_SET event will be dispatched in response.
+     * @param {string} destinationId The ID of the destination whose
+     *     capabilities are requested.
+     */
+    startGetExtensionDestinationCapabilities: function(destinationId) {
+      chrome.send('getExtensionPrinterCapabilities', [destinationId]);
+    },
+
+    /**
      * Requests the destination's printing capabilities. A CAPABILITIES_SET
      * event will be dispatched in response.
      * @param {string} destinationId ID of the destination.
@@ -299,6 +327,10 @@
       assert(!opt_showSystemDialog || (cr.isWindows && destination.isLocal),
              'Implemented for Windows only');
 
+      // TODO(tbarzic): Implement this.
+      assert(!destination.isExtension,
+             'Printing to extension printers not yet implemented.');
+
       var ticket = {
         'pageRange': printTicketStore.pageRange.getDocumentPageRanges(),
         'mediaSize': printTicketStore.mediaSize.getValue(),
@@ -514,6 +546,21 @@
       this.dispatchEvent(getCapsFailEvent);
     },
 
+    /**
+     * Called when native layer fails to get settings information for a
+     * requested extension destination.
+     * @param {string} destinationId Printer affected by error.
+     * @private
+     */
+    onFailedToGetExtensionPrinterCapabilities_: function(destinationId) {
+      var getCapsFailEvent = new Event(
+          NativeLayer.EventType.GET_CAPABILITIES_FAIL);
+      getCapsFailEvent.destinationId = destinationId;
+      getCapsFailEvent.destinationOrigin =
+          print_preview.Destination.Origin.EXTENSION;
+      this.dispatchEvent(getCapsFailEvent);
+    },
+
     /** Reloads the printer list. */
     onReloadPrintersList_: function() {
       cr.dispatchSimpleEvent(this, NativeLayer.EventType.DESTINATIONS_RELOAD);
@@ -720,6 +767,36 @@
     },
 
     /**
+     * @param {Array.<!{extensionId: string,
+     *                  id: string,
+     *                  name: string,
+     *                  description: (string|undefined)}>} printers The list
+     *     containing information about printers added by an extension.
+     * @param {boolean} done Whether this is the final list of extension
+     *     managed printers.
+     */
+    onExtensionPrintersAdded_: function(printers, done) {
+      var event = new Event(NativeLayer.EventType.EXTENSION_PRINTERS_ADDED);
+      event.printers = printers;
+      event.done = done;
+      this.dispatchEvent(event);
+    },
+
+    /**
+     * Called when an extension responds to a request for an extension printer
+     * capabilities.
+     * @param {string} printerId The printer's ID.
+     * @param {!Object} capabilities The reported printer capabilities.
+     */
+    onExtensionCapabilitiesSet_: function(printerId,
+                                          capabilities) {
+      var event = new Event(NativeLayer.EventType.EXTENSION_CAPABILITIES_SET);
+      event.printerId = printerId;
+      event.capabilities = capabilities;
+      this.dispatchEvent(event);
+    },
+
+   /**
      * Allows for onManipulateSettings to be called
      * from the native layer.
      * @private
diff --git a/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chrome/browser/resources/print_preview/previewarea/preview_area.js
index ca06dd84..e437621 100644
--- a/chrome/browser/resources/print_preview/previewarea/preview_area.js
+++ b/chrome/browser/resources/print_preview/previewarea/preview_area.js
@@ -301,11 +301,21 @@
 
       // No scroll bar anywhere, or the active element is something else, like a
       // button. Note: buttons have a bigger scrollHeight than clientHeight.
-      this.plugin_.sendKeyEvent(e.keyCode);
+      this.plugin_.sendKeyEvent(e);
       e.preventDefault();
     },
 
     /**
+     * Set a callback that gets called when a key event is received that
+     * originates in the plugin.
+     * @param {function(Event)} callback The callback to be called with a key
+     *     event.
+     */
+    setPluginKeyEventCallback: function(callback) {
+      this.keyEventCallback_ = callback;
+    },
+
+    /**
      * Shows a custom message on the preview area's overlay.
      * @param {string} message Custom message to show.
      */
@@ -564,6 +574,7 @@
       } else {
         this.plugin_ = /** @type {print_preview.PDFPlugin} */(
             PDFCreateOutOfProcessPlugin(srcUrl));
+        this.plugin_.setKeyEventCallback(this.keyEventCallback_);
       }
 
       this.plugin_.setAttribute('class', 'preview-area-plugin');
diff --git a/chrome/browser/resources/print_preview/print_header.js b/chrome/browser/resources/print_preview/print_header.js
index cc08956..6d623fa 100644
--- a/chrome/browser/resources/print_preview/print_header.js
+++ b/chrome/browser/resources/print_preview/print_header.js
@@ -142,6 +142,9 @@
     updatePrintButtonEnabledState_: function() {
       this.getChildElement('button.print').disabled =
           this.destinationStore_.selectedDestination == null ||
+          // TODO(tbarzic): Remove this when print request for extension
+          // destinations is wired up.
+          this.destinationStore_.selectedDestination.isExtension ||
           !this.isEnabled_ ||
           !this.isPrintButtonEnabled_ ||
           !this.printTicketStore_.isTicketValid();
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index 3e48478..3e7cd38 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -412,6 +412,7 @@
           this.onCancelButtonClick_.bind(this));
 
       this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this));
+      this.previewArea_.setPluginKeyEventCallback(this.onKeyDown_.bind(this));
 
       this.tracker.add(
           this.destinationSettings_,
diff --git a/chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h b/chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h
deleted file mode 100644
index 7e0e497..0000000
--- a/chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h
+++ /dev/null
@@ -1,21 +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.
-
-#ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_ADD_INCIDENT_CALLBACK_H_
-#define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_ADD_INCIDENT_CALLBACK_H_
-
-#include "base/callback_forward.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace safe_browsing {
-
-class Incident;
-
-// A callback used by external components to add an incident to the incident
-// reporting service.
-typedef base::Callback<void(scoped_ptr<Incident>)> AddIncidentCallback;
-
-}  // namespace safe_browsing
-
-#endif  // CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_ADD_INCIDENT_CALLBACK_H_
diff --git a/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.cc b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.cc
index 7692892..4473c96 100644
--- a/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/safe_browsing/binary_feature_extractor.h"
 #include "chrome/browser/safe_browsing/incident_reporting/binary_integrity_incident.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 
@@ -51,7 +52,7 @@
 #endif
 }
 
-void VerifyBinaryIntegrity(const AddIncidentCallback& callback) {
+void VerifyBinaryIntegrity(scoped_ptr<IncidentReceiver> incident_receiver) {
   scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor(
       new BinaryFeatureExtractor());
 
@@ -78,8 +79,8 @@
       incident->set_allocated_signature(signature_info.release());
 
       // Send the report.
-      callback.Run(make_scoped_ptr(
-          new BinaryIntegrityIncident(incident.Pass())));
+      incident_receiver->AddIncidentForProcess(
+          make_scoped_ptr(new BinaryIntegrityIncident(incident.Pass())));
     }
   }
 }
diff --git a/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h
index 1b37533..6ac4532 100644
--- a/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h
+++ b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h"
+#include "base/memory/scoped_ptr.h"
 
 namespace base {
 class FilePath;
@@ -15,6 +15,8 @@
 
 namespace safe_browsing {
 
+class IncidentReceiver;
+
 // Registers a process-wide analysis with the incident reporting service that
 // will verify the signature of the most critical binaries used by Chrome. It
 // will send an incident report every time a signature verification fails.
@@ -22,7 +24,7 @@
 
 // Callback to pass to the incident reporting service. The incident reporting
 // service will decide when to start the analysis.
-void VerifyBinaryIntegrity(const AddIncidentCallback& callback);
+void VerifyBinaryIntegrity(scoped_ptr<IncidentReceiver> incident_receiver);
 
 // Returns a vector containing the paths to all the binaries to verify.
 std::vector<base::FilePath> GetCriticalBinariesPath();
diff --git a/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_win_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_win_unittest.cc
index 255117d..ee931d7 100644
--- a/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_win_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_win_unittest.cc
@@ -11,12 +11,16 @@
 #include "base/path_service.h"
 #include "base/test/scoped_path_override.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
+#include "chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "version.h"  // NOLINT
 
+using ::testing::_;
+using ::testing::StrictMock;
+
 namespace safe_browsing {
 
 namespace {
@@ -45,18 +49,13 @@
  public:
   BinaryIntegrityAnalyzerWinTest();
 
-  void OnAddIncident(scoped_ptr<Incident> incident);
-
  protected:
-  bool callback_called_;
   base::FilePath test_data_dir_;
   base::ScopedTempDir temp_dir_;
   scoped_ptr<base::ScopedPathOverride> exe_dir_override_;
-  scoped_ptr<Incident> incident_;
 };
 
-BinaryIntegrityAnalyzerWinTest::BinaryIntegrityAnalyzerWinTest()
-    : callback_called_(false) {
+BinaryIntegrityAnalyzerWinTest::BinaryIntegrityAnalyzerWinTest() {
   temp_dir_.CreateUniqueTempDir();
   base::CreateDirectory(temp_dir_.path().AppendASCII(CHROME_VERSION_STRING));
 
@@ -69,16 +68,6 @@
       new base::ScopedPathOverride(base::DIR_EXE, temp_dir_.path()));
 }
 
-// Mock the AddIncidentCallback so we can test that VerifyBinaryIntegrity
-// adds an incident callback when a signature verification fails.
-void BinaryIntegrityAnalyzerWinTest::OnAddIncident(
-    scoped_ptr<Incident> incident) {
-  callback_called_ = true;
-
-  // Take ownership of the incident so that the text fixture can inspect it.
-  incident_ = incident.Pass();
-}
-
 TEST_F(BinaryIntegrityAnalyzerWinTest, GetCriticalBinariesPath) {
   // Expected paths.
   std::vector<base::FilePath> critical_binaries_path_expected;
@@ -112,20 +101,22 @@
 
   ASSERT_TRUE(base::CopyFile(signed_binary_path, chrome_elf_path));
 
-  AddIncidentCallback callback = base::Bind(
-      &BinaryIntegrityAnalyzerWinTest::OnAddIncident, base::Unretained(this));
-
-  VerifyBinaryIntegrity(callback);
-  ASSERT_FALSE(callback_called_);
+  scoped_ptr<MockIncidentReceiver> mock_receiver(
+      new StrictMock<MockIncidentReceiver>());
+  VerifyBinaryIntegrity(mock_receiver.Pass());
 
   ASSERT_TRUE(EraseFileContent(chrome_elf_path));
 
-  VerifyBinaryIntegrity(callback);
-  ASSERT_TRUE(callback_called_);
+  mock_receiver.reset(new MockIncidentReceiver());
+  scoped_ptr<Incident> incident;
+  EXPECT_CALL(*mock_receiver, DoAddIncidentForProcess(_))
+      .WillOnce(TakeIncident(&incident));
+
+  VerifyBinaryIntegrity(mock_receiver.Pass());
 
   // Verify that the incident report contains the expected data.
   scoped_ptr<ClientIncidentReport_IncidentData> incident_data(
-      incident_->TakePayload());
+      incident->TakePayload());
   ASSERT_TRUE(incident_data->has_binary_integrity());
   ASSERT_TRUE(incident_data->binary_integrity().has_file_basename());
   ASSERT_EQ("chrome_elf.dll",
diff --git a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.cc b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.cc
index 34527eb..0bfe254 100644
--- a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h"
 
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 
 namespace safe_browsing {
@@ -21,7 +21,7 @@
 }
 
 #if !defined(OS_WIN)
-void VerifyBlacklistLoadState(const AddIncidentCallback& callback) {
+void VerifyBlacklistLoadState(scoped_ptr<IncidentReceiver> incident_receiver) {
 }
 
 bool GetLoadedBlacklistedModules(std::vector<base::string16>* module_names) {
diff --git a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h
index 8c5d13f..d3c2cc0 100644
--- a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h
+++ b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h
@@ -7,11 +7,13 @@
 
 #include <vector>
 
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h"
 
 namespace safe_browsing {
 
+class IncidentReceiver;
+
 // Registers a process-wide analysis with the incident reporting service that
 // will examine how effective the blacklist was.
 void RegisterBlacklistLoadAnalysis();
@@ -22,7 +24,7 @@
 
 // Callback to pass to the incident reporting service. The incident reporting
 // service will decide when to start the analysis.
-void VerifyBlacklistLoadState(const AddIncidentCallback& callback);
+void VerifyBlacklistLoadState(scoped_ptr<IncidentReceiver> incident_receiver);
 
 }  // namespace safe_browsing
 
diff --git a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc
index 462644f3..a40fd08 100644
--- a/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer_win.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/install_verification/win/module_verification_common.h"
 #include "chrome/browser/safe_browsing/binary_feature_extractor.h"
 #include "chrome/browser/safe_browsing/incident_reporting/blacklist_load_incident.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/path_sanitizer.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
@@ -43,7 +44,7 @@
   return true;
 }
 
-void VerifyBlacklistLoadState(const AddIncidentCallback& callback) {
+void VerifyBlacklistLoadState(scoped_ptr<IncidentReceiver> incident_receiver) {
   std::vector<base::string16> module_names;
   if (GetLoadedBlacklistedModules(&module_names)) {
     PathSanitizer path_sanitizer;
@@ -95,7 +96,7 @@
           module_path, blacklist_load->mutable_image_headers());
 
       // Send the report.
-      callback.Run(
+      incident_receiver->AddIncidentForProcess(
           make_scoped_ptr(new BlacklistLoadIncident(blacklist_load.Pass())));
     }
   }
diff --git a/chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h b/chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h
index a5bf108..7840402 100644
--- a/chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h
+++ b/chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h
@@ -6,15 +6,17 @@
 #define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_DELAYED_ANALYSIS_CALLBACK_H_
 
 #include "base/callback_forward.h"
-#include "chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h"
+#include "base/memory/scoped_ptr.h"
 
 namespace safe_browsing {
 
+class IncidentReceiver;
+
 // A callback used by external components to register a process-wide analysis
 // step. The callback will be run after some delay following process launch in
-// the blocking pool. The argument is a callback by which the consumer can add
+// the blocking pool. The argument is a receiver by which the consumer can add
 // incidents to the incident reporting service.
-typedef base::Callback<void(const AddIncidentCallback&)>
+typedef base::Callback<void(scoped_ptr<IncidentReceiver>)>
     DelayedAnalysisCallback;
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_receiver.h b/chrome/browser/safe_browsing/incident_reporting/incident_receiver.h
new file mode 100644
index 0000000..eb1a019
--- /dev/null
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_receiver.h
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_INCIDENT_RECEIVER_H_
+#define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_INCIDENT_RECEIVER_H_
+
+#include "base/memory/scoped_ptr.h"
+
+class Profile;
+
+namespace safe_browsing {
+
+class Incident;
+
+// An interface by which incidents may be added to the incident reporting
+// service.
+class IncidentReceiver {
+ public:
+  virtual ~IncidentReceiver() {}
+
+  // Adds an incident relating to |profile|. Must be called from the UI thread.
+  virtual void AddIncidentForProfile(Profile* profile,
+                                     scoped_ptr<Incident> incident) = 0;
+
+  // Adds an incident relating to the entire browser process. May be called from
+  // any thread.
+  virtual void AddIncidentForProcess(scoped_ptr<Incident> incident) = 0;
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_INCIDENT_RECEIVER_H_
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
index f5bafc5..44ab0b1 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/safe_browsing/database_manager.h"
 #include "chrome/browser/safe_browsing/incident_reporting/environment_data_collection.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident_report_uploader_impl.h"
 #include "chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -166,19 +167,6 @@
     pref_update.Get()->RemoveWithoutPathExpansion(incident_type, NULL);
 }
 
-// Runs |callback| on the thread to which |thread_runner| belongs. The callback
-// is run immediately if this function is called on |thread_runner|'s thread.
-void AddIncidentOnOriginThread(
-    const AddIncidentCallback& callback,
-    scoped_refptr<base::SingleThreadTaskRunner> thread_runner,
-    scoped_ptr<Incident> incident) {
-  if (thread_runner->BelongsToCurrentThread())
-    callback.Run(incident.Pass());
-  else
-    thread_runner->PostTask(FROM_HERE,
-                            base::Bind(callback, base::Passed(&incident)));
-}
-
 }  // namespace
 
 struct IncidentReportingService::ProfileContext {
@@ -217,6 +205,70 @@
   DISALLOW_COPY_AND_ASSIGN(UploadContext);
 };
 
+// An IncidentReceiver that is weakly-bound to the service and transparently
+// bounces process-wide incidents back to the main thread for handling.
+class IncidentReportingService::Receiver : public IncidentReceiver {
+ public:
+  explicit Receiver(const base::WeakPtr<IncidentReportingService>& service);
+  ~Receiver() override;
+
+  // IncidentReceiver methods:
+  void AddIncidentForProfile(Profile* profile,
+                             scoped_ptr<Incident> incident) override;
+  void AddIncidentForProcess(scoped_ptr<Incident> incident) override;
+
+ private:
+  static void AddIncidentOnMainThread(
+      const base::WeakPtr<IncidentReportingService>& service,
+      Profile* profile,
+      scoped_ptr<Incident> incident);
+
+  base::WeakPtr<IncidentReportingService> service_;
+  scoped_refptr<base::SingleThreadTaskRunner> thread_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(Receiver);
+};
+
+IncidentReportingService::Receiver::Receiver(
+    const base::WeakPtr<IncidentReportingService>& service)
+    : service_(service),
+      thread_runner_(base::ThreadTaskRunnerHandle::Get()) {
+}
+
+IncidentReportingService::Receiver::~Receiver() {
+}
+
+void IncidentReportingService::Receiver::AddIncidentForProfile(
+    Profile* profile,
+    scoped_ptr<Incident> incident) {
+  DCHECK(thread_runner_->BelongsToCurrentThread());
+  DCHECK(profile);
+  AddIncidentOnMainThread(service_, profile, incident.Pass());
+}
+
+void IncidentReportingService::Receiver::AddIncidentForProcess(
+    scoped_ptr<Incident> incident) {
+  if (thread_runner_->BelongsToCurrentThread()) {
+    AddIncidentOnMainThread(service_, nullptr, incident.Pass());
+  } else if (!thread_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&IncidentReportingService::Receiver::AddIncidentOnMainThread,
+                 service_, nullptr, base::Passed(&incident)))) {
+    LogIncidentDataType(DISCARDED, *incident);
+  }
+}
+
+// static
+void IncidentReportingService::Receiver::AddIncidentOnMainThread(
+    const base::WeakPtr<IncidentReportingService>& service,
+    Profile* profile,
+    scoped_ptr<Incident> incident) {
+  if (service)
+    service->AddIncident(profile, incident.Pass());
+  else
+    LogIncidentDataType(DISCARDED, *incident);
+}
+
 IncidentReportingService::ProfileContext::ProfileContext() : added() {
 }
 
@@ -293,16 +345,8 @@
   STLDeleteValues(&profiles_);
 }
 
-AddIncidentCallback IncidentReportingService::GetAddIncidentCallback(
-    Profile* profile) {
-  // Force the context to be created so that incidents added before
-  // OnProfileAdded is called are held until the profile's preferences can be
-  // queried.
-  ignore_result(GetOrCreateProfileContext(profile));
-
-  return base::Bind(&IncidentReportingService::AddIncident,
-                    receiver_weak_ptr_factory_.GetWeakPtr(),
-                    profile);
+scoped_ptr<IncidentReceiver> IncidentReportingService::GetIncidentReceiver() {
+  return make_scoped_ptr(new Receiver(receiver_weak_ptr_factory_.GetWeakPtr()));
 }
 
 scoped_ptr<TrackedPreferenceValidationDelegate>
@@ -312,21 +356,17 @@
   if (profile->IsOffTheRecord())
     return scoped_ptr<TrackedPreferenceValidationDelegate>();
   return scoped_ptr<TrackedPreferenceValidationDelegate>(
-      new PreferenceValidationDelegate(GetAddIncidentCallback(profile)));
+      new PreferenceValidationDelegate(profile, GetIncidentReceiver()));
 }
 
 void IncidentReportingService::RegisterDelayedAnalysisCallback(
     const DelayedAnalysisCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  // |callback| will be run on the blocking pool, so it will likely run the
-  // AddIncidentCallback there as well. Bounce the run of that callback back to
-  // the current thread via AddIncidentOnOriginThread.
+  // |callback| will be run on the blocking pool. The receiver will bounce back
+  // to the origin thread if needed.
   delayed_analysis_callbacks_.RegisterCallback(
-      base::Bind(callback,
-                 base::Bind(&AddIncidentOnOriginThread,
-                            GetAddIncidentCallback(NULL),
-                            base::ThreadTaskRunnerHandle::Get())));
+      base::Bind(callback, base::Passed(GetIncidentReceiver())));
 
   // Start running the callbacks if any profiles are participating in safe
   // browsing. If none are now, running will commence if/when a participaing
@@ -518,9 +558,11 @@
                                            scoped_ptr<Incident> incident) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  ProfileContext* context = GetProfileContext(profile);
-  // It is forbidden to call this function with a destroyed profile.
-  DCHECK(context);
+  // Ignore incidents from off-the-record profiles.
+  if (profile && profile->IsOffTheRecord())
+    return;
+
+  ProfileContext* context = GetOrCreateProfileContext(profile);
   // If this is a process-wide incident, the context must not indicate that the
   // profile (which is NULL) has been added to the profile manager.
   DCHECK(profile || !context->added);
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
index 1fac481..e638da6 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
@@ -19,7 +19,6 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/safe_browsing/download_protection_service.h"
-#include "chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h"
 #include "chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h"
 #include "chrome/browser/safe_browsing/incident_reporting/delayed_callback_runner.h"
 #include "chrome/browser/safe_browsing/incident_reporting/download_metadata_manager.h"
@@ -54,6 +53,8 @@
 class ClientIncidentReport_DownloadDetails;
 class ClientIncidentReport_EnvironmentData;
 class ClientIncidentReport_IncidentData;
+class Incident;
+class IncidentReceiver;
 
 // A class that manages the collection of incidents and submission of incident
 // reports to the safe browsing client-side detection service. The service
@@ -77,17 +78,15 @@
   // dropped at destruction.
   ~IncidentReportingService() override;
 
-  // Returns a callback by which external components can add an incident to the
-  // service on behalf of |profile|. The callback may outlive the service, but
-  // will no longer have any effect after the service is deleted. The callback
-  // must not be run after |profile| has been destroyed.
-  AddIncidentCallback GetAddIncidentCallback(Profile* profile);
+  // Returns an object by which external components can add an incident to the
+  // service. The object may outlive the service, but will no longer have any
+  // effect after the service is deleted.
+  scoped_ptr<IncidentReceiver> GetIncidentReceiver();
 
   // Returns a preference validation delegate that adds incidents to the service
   // for validation failures in |profile|. The delegate may outlive the service,
   // but incidents reported by it will no longer have any effect after the
-  // service is deleted. The lifetime of the delegate should not extend beyond
-  // that of the profile it services.
+  // service is deleted.
   scoped_ptr<TrackedPreferenceValidationDelegate>
       CreatePreferenceValidationDelegate(Profile* profile);
 
@@ -143,6 +142,7 @@
  private:
   struct ProfileContext;
   class UploadContext;
+  class Receiver;
 
   // A mapping of profiles to contexts holding state about received incidents.
   typedef std::map<Profile*, ProfileContext*> ProfileContextCollection;
@@ -161,8 +161,7 @@
   // participating in extended safe browsing are preferred.
   Profile* FindEligibleProfile() const;
 
-  // Adds |incident_data| to the service. The incident_time_msec field is
-  // populated with the current time if the caller has not already done so.
+  // Adds |incident_data| relating to the optional |profile| to the service.
   void AddIncident(Profile* profile, scoped_ptr<Incident> incident);
 
   // Begins processing a report. If processing is already underway, ensures that
@@ -321,7 +320,7 @@
   // Non-NULL while such a search is outstanding.
   scoped_ptr<LastDownloadFinder> last_download_finder_;
 
-  // A factory for handing out weak pointers for AddIncident callbacks.
+  // A factory for handing out weak pointers for IncidentReceiver objects.
   base::WeakPtrFactory<IncidentReportingService> receiver_weak_ptr_factory_;
 
   // A factory for handing out weak pointers for internal asynchronous tasks
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
index 6625305..4202bf1 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/threading/thread_local.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident_report_uploader.h"
 #include "chrome/browser/safe_browsing/incident_reporting/last_download_finder.h"
 #include "chrome/browser/safe_browsing/incident_reporting/tracked_preference_incident.h"
@@ -246,7 +247,12 @@
 
   // Adds a test incident to the service.
   void AddTestIncident(Profile* profile) {
-    instance_->GetAddIncidentCallback(profile).Run(MakeTestIncident(nullptr));
+    scoped_ptr<safe_browsing::IncidentReceiver> receiver(
+        instance_->GetIncidentReceiver());
+    if (profile)
+      receiver->AddIncidentForProfile(profile, MakeTestIncident(nullptr));
+    else
+      receiver->AddIncidentForProcess(MakeTestIncident(nullptr));
   }
 
   // Registers the callback to be run for delayed analysis.
@@ -459,10 +465,10 @@
   void OnDownloadFinderDestroyed() { download_finder_destroyed_ = true; }
   void OnUploaderDestroyed() { uploader_destroyed_ = true; }
 
-  void OnDelayedAnalysis(const safe_browsing::AddIncidentCallback& callback) {
+  void OnDelayedAnalysis(scoped_ptr<safe_browsing::IncidentReceiver> receiver) {
     delayed_analysis_ran_ = true;
     if (on_delayed_analysis_action_ == ON_DELAYED_ANALYSIS_ADD_INCIDENT)
-      callback.Run(MakeTestIncident(nullptr));
+      receiver->AddIncidentForProcess(MakeTestIncident(nullptr));
   }
 
   // A mapping of profile name to its corresponding properties.
@@ -637,7 +643,8 @@
   ExpectTestIncidentUploaded(1);
 
   // Add a variation on the incident to the service.
-  instance_->GetAddIncidentCallback(profile).Run(MakeTestIncident("leeches"));
+  instance_->GetIncidentReceiver()->AddIncidentForProfile(
+      profile, MakeTestIncident("leeches"));
 
   // Let all tasks run.
   task_runner_->RunUntilIdle();
@@ -755,9 +762,9 @@
                 nullptr);
 
   // Add the test incident.
-  safe_browsing::AddIncidentCallback add_incident(
-      instance_->GetAddIncidentCallback(NULL));
-  add_incident.Run(MakeTestIncident(nullptr));
+  scoped_ptr<safe_browsing::IncidentReceiver> receiver(
+      instance_->GetIncidentReceiver());
+  receiver->AddIncidentForProcess(MakeTestIncident(nullptr));
 
   // Let all tasks run.
   task_runner_->RunUntilIdle();
@@ -766,7 +773,7 @@
   ExpectTestIncidentUploaded(1);
 
   // Add a variation on the incident to the service.
-  add_incident.Run(MakeTestIncident("leeches"));
+  receiver->AddIncidentForProcess(MakeTestIncident("leeches"));
 
   // Let all tasks run.
   task_runner_->RunUntilIdle();
diff --git a/chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.cc b/chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.cc
new file mode 100644
index 0000000..4a4bd57ec
--- /dev/null
+++ b/chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.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 "chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h"
+
+#include "chrome/browser/safe_browsing/incident_reporting/incident.h"
+
+namespace safe_browsing {
+
+MockIncidentReceiver::MockIncidentReceiver() {}
+
+MockIncidentReceiver::~MockIncidentReceiver() {}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h b/chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h
new file mode 100644
index 0000000..1cd2e053
--- /dev/null
+++ b/chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_MOCK_INCIDENT_RECEIVER_H_
+#define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_MOCK_INCIDENT_RECEIVER_H_
+
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace safe_browsing {
+
+class MockIncidentReceiver : public IncidentReceiver {
+ public:
+  MockIncidentReceiver();
+  ~MockIncidentReceiver();
+
+  MOCK_METHOD2(DoAddIncidentForProfile, void(Profile*, scoped_ptr<Incident>*));
+  MOCK_METHOD1(DoAddIncidentForProcess, void(scoped_ptr<Incident>*));
+
+ protected:
+  void AddIncidentForProfile(Profile* profile,
+                             scoped_ptr<Incident> incident) override {
+    DoAddIncidentForProfile(profile, &incident);
+  }
+
+  void AddIncidentForProcess(scoped_ptr<Incident> incident) override {
+    DoAddIncidentForProcess(&incident);
+  }
+};
+
+// An action that passes ownership of the incident in |arg0| to |recipient|.
+ACTION_P(TakeIncident, recipient) {
+  *recipient = arg0->Pass();
+}
+
+// An action that passes ownership of the incident in |arg0| to the vector in
+// |incidents|.
+ACTION_P(TakeIncidentToVector, incidents) {
+  incidents->push_back(arg0->release());
+}
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_MOCK_INCIDENT_RECEIVER_H_
diff --git a/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.h b/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.h
index fb75cae..f0ab04f0 100644
--- a/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.h
+++ b/chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.h
@@ -42,8 +42,8 @@
   };
 
   // TODO(gab): Hook the OffDomainInclusionDetector to the
-  // IncidentReportingService and use an AddIncidentCallback instead of this
-  // custom callback type.
+  // IncidentReportingService and use an IncidentReceiver instead of this custom
+  // callback type.
   typedef base::Callback<void(AnalysisEvent event)> ReportAnalysisEventCallback;
 
   // Constructs an OffDomainInclusionDetector which will use |database_manager|
diff --git a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
index 1c96036..6ac435dc 100644
--- a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
@@ -7,10 +7,10 @@
 #include <string>
 #include <vector>
 
-#include "base/callback.h"
 #include "base/json/json_writer.h"
 #include "chrome/browser/prefs/tracked/pref_hash_store_transaction.h"
 #include "chrome/browser/prefs/tracked/tracked_preference_helper.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/incident_reporting/tracked_preference_incident.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 
@@ -41,8 +41,10 @@
 }  // namespace
 
 PreferenceValidationDelegate::PreferenceValidationDelegate(
-    const AddIncidentCallback& add_incident)
-    : add_incident_(add_incident) {
+    Profile* profile,
+    scoped_ptr<IncidentReceiver> incident_receiver)
+    : profile_(profile),
+      incident_receiver_(incident_receiver.Pass()) {
 }
 
 PreferenceValidationDelegate::~PreferenceValidationDelegate() {
@@ -64,8 +66,9 @@
       incident->clear_atomic_value();
     }
     incident->set_value_state(proto_value_state);
-    add_incident_.Run(make_scoped_ptr(
-        new TrackedPreferenceIncident(incident.Pass(), is_personal)));
+    incident_receiver_->AddIncidentForProfile(
+        profile_, make_scoped_ptr(new TrackedPreferenceIncident(incident.Pass(),
+                                                                is_personal)));
   }
 }
 
@@ -87,8 +90,9 @@
       incident->add_split_key(*scan);
     }
     incident->set_value_state(proto_value_state);
-    add_incident_.Run(make_scoped_ptr(
-        new TrackedPreferenceIncident(incident.Pass(), is_personal)));
+    incident_receiver_->AddIncidentForProfile(
+        profile_, make_scoped_ptr(new TrackedPreferenceIncident(incident.Pass(),
+                                                                is_personal)));
   }
 }
 
diff --git a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h
index 6516c0c..1fb789e 100644
--- a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h
+++ b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.h
@@ -5,21 +5,25 @@
 #ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PREFERENCE_VALIDATION_DELEGATE_H_
 #define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_PREFERENCE_VALIDATION_DELEGATE_H_
 
-#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
-#include "chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h"
+
+class Profile;
 
 namespace safe_browsing {
 
+class IncidentReceiver;
+
 // A preference validation delegate that adds incidents to a given receiver
-// for preference validation failures.
+// for preference validation failures. The profile for which the delegate
+// operates must outlive the delegate itself.
 class PreferenceValidationDelegate
     : public TrackedPreferenceValidationDelegate {
  public:
-  explicit PreferenceValidationDelegate(
-      const AddIncidentCallback& add_incident);
+  PreferenceValidationDelegate(Profile* profile,
+                               scoped_ptr<IncidentReceiver> incident_receiver);
   ~PreferenceValidationDelegate() override;
 
  private:
@@ -36,7 +40,8 @@
       PrefHashStoreTransaction::ValueState value_state,
       bool is_personal) override;
 
-  AddIncidentCallback add_incident_;
+  Profile* profile_;
+  scoped_ptr<IncidentReceiver> incident_receiver_;
 
   DISALLOW_COPY_AND_ASSIGN(PreferenceValidationDelegate);
 };
diff --git a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate_unittest.cc
index 547fb09..9571f0c 100644
--- a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate_unittest.cc
@@ -12,9 +12,16 @@
 #include "base/memory/scoped_vector.h"
 #include "base/values.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident.h"
+#include "chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::_;
+using ::testing::IsNull;
+using ::testing::NiceMock;
+using ::testing::WithArg;
+
 // A basic test harness that creates a delegate instance for which it stores all
 // incidents. Tests can push data to the delegate and verify that the test
 // instance was provided with the expected data.
@@ -30,13 +37,12 @@
     testing::Test::SetUp();
     invalid_keys_.push_back(std::string("one"));
     invalid_keys_.push_back(std::string("two"));
+    scoped_ptr<safe_browsing::MockIncidentReceiver> receiver(
+        new NiceMock<safe_browsing::MockIncidentReceiver>());
+    ON_CALL(*receiver, DoAddIncidentForProfile(IsNull(), _))
+        .WillByDefault(WithArg<1>(TakeIncidentToVector(&incidents_)));
     instance_.reset(new safe_browsing::PreferenceValidationDelegate(
-        base::Bind(&PreferenceValidationDelegateTest::AddIncident,
-                   base::Unretained(this))));
-  }
-
-  void AddIncident(scoped_ptr<safe_browsing::Incident> incident) {
-    incidents_.push_back(incident.release());
+        nullptr, receiver.Pass()));
   }
 
   static void ExpectValueStatesEquate(
diff --git a/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.cc b/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.cc
index 6fe04e1..04c2f4d1 100644
--- a/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.cc
@@ -10,6 +10,7 @@
 #include "base/location.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/variations/variations_service.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_incident.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
@@ -20,7 +21,7 @@
 namespace {
 
 void VerifyVariationsSeedSignatureOnUIThread(
-    const AddIncidentCallback& callback) {
+    scoped_ptr<IncidentReceiver> incident_receiver) {
   chrome_variations::VariationsService* variations_service =
       g_browser_process->variations_service();
   if (!variations_service)
@@ -33,7 +34,7 @@
         variations_seed_signature(
             new ClientIncidentReport_IncidentData_VariationsSeedSignatureIncident());
     variations_seed_signature->set_variations_seed_signature(invalid_signature);
-    callback.Run(make_scoped_ptr(
+    incident_receiver->AddIncidentForProcess(make_scoped_ptr(
         new VariationsSeedSignatureIncident(variations_seed_signature.Pass())));
   }
 }
@@ -48,11 +49,13 @@
       base::Bind(&VerifyVariationsSeedSignature));
 }
 
-void VerifyVariationsSeedSignature(const AddIncidentCallback& callback) {
+void VerifyVariationsSeedSignature(
+    scoped_ptr<IncidentReceiver> incident_receiver) {
   content::BrowserThread::PostTask(
       content::BrowserThread::UI,
       FROM_HERE,
-      base::Bind(&VerifyVariationsSeedSignatureOnUIThread, callback));
+      base::Bind(&VerifyVariationsSeedSignatureOnUIThread,
+                 base::Passed(&incident_receiver)));
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.h b/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.h
index 9a56a5a..042efe2d 100644
--- a/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.h
+++ b/chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.h
@@ -5,18 +5,21 @@
 #ifndef CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_VARIATIONS_SEED_SIGNATURE_ANALYZER_H_
 #define CHROME_BROWSER_SAFE_BROWSING_INCIDENT_REPORTING_VARIATIONS_SEED_SIGNATURE_ANALYZER_H_
 
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/safe_browsing/incident_reporting/add_incident_callback.h"
 
 namespace safe_browsing {
 
+class IncidentReceiver;
+
 // Registers a process-wide analysis with the incident reporting service that
 // will verify the variations seed signature.
 void RegisterVariationsSeedSignatureAnalysis();
 
 // Callback to pass to the incident reporting service. The incident reporting
 // service will verify if the variations seed signature is invalid.
-void VerifyVariationsSeedSignature(const AddIncidentCallback& callback);
+void VerifyVariationsSeedSignature(
+    scoped_ptr<IncidentReceiver> incident_receiver);
 
 }  // namespace safe_browsing
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 0515ecd..67f2cc4 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -175,15 +175,17 @@
     interstitial_reason_ = SB_REASON_PHISHING;
 
   // This must be done after calculating |interstitial_reason_| above.
-  uma_helper_.reset(new SecurityInterstitialUmaHelper(
-      web_contents, request_url(),
-      GetHistogramPrefix(), GetSamplingEventName()));
-  uma_helper_->RecordUserDecision(SecurityInterstitialUmaHelper::SHOW);
-  uma_helper_->RecordUserInteraction(
-      SecurityInterstitialUmaHelper::TOTAL_VISITS);
+  // Use same prefix for UMA as for Rappor.
+  metrics_helper_.reset(new SecurityInterstitialMetricsHelper(
+      web_contents, request_url(), GetMetricPrefix(), GetMetricPrefix(),
+      SecurityInterstitialMetricsHelper::REPORT_RAPPOR,
+      GetSamplingEventName()));
+  metrics_helper_->RecordUserDecision(SecurityInterstitialMetricsHelper::SHOW);
+  metrics_helper_->RecordUserInteraction(
+      SecurityInterstitialMetricsHelper::TOTAL_VISITS);
   if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
-    uma_helper_->RecordUserDecision(
-        SecurityInterstitialUmaHelper::PROCEEDING_DISABLED);
+    metrics_helper_->RecordUserDecision(
+        SecurityInterstitialMetricsHelper::PROCEEDING_DISABLED);
   }
 
   if (!is_main_frame_load_blocked_) {
@@ -239,8 +241,8 @@
 
   if (command == kLearnMoreCommand) {
     // User pressed "Learn more".
-    uma_helper_->RecordUserInteraction(
-        SecurityInterstitialUmaHelper::SHOW_LEARN_MORE);
+    metrics_helper_->RecordUserInteraction(
+        SecurityInterstitialMetricsHelper::SHOW_LEARN_MORE);
     GURL learn_more_url(
         interstitial_reason_ == SB_REASON_PHISHING ?
         kLearnMorePhishingUrlV2 : kLearnMoreMalwareUrlV2);
@@ -257,8 +259,8 @@
 
   if (command == kShowPrivacyCommand) {
     // User pressed "Safe Browsing privacy policy".
-    uma_helper_->RecordUserInteraction(
-        SecurityInterstitialUmaHelper::SHOW_PRIVACY_POLICY);
+    metrics_helper_->RecordUserInteraction(
+        SecurityInterstitialMetricsHelper::SHOW_PRIVACY_POLICY);
     GURL privacy_url(
         l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_PRIVACY_POLICY_URL));
     privacy_url = google_util::AppendGoogleLocaleParam(
@@ -277,7 +279,8 @@
     if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
       proceed_blocked = true;
     } else {
-      uma_helper_->RecordUserDecision(SecurityInterstitialUmaHelper::PROCEED);
+      metrics_helper_->RecordUserDecision(
+          SecurityInterstitialMetricsHelper::PROCEED);
       interstitial_page()->Proceed();
       // |this| has been deleted after Proceed() returns.
       return;
@@ -333,8 +336,8 @@
   std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
   if (command == kShowDiagnosticCommand) {
     // We're going to take the user to Google's SafeBrowsing diagnostic page.
-    uma_helper_->RecordUserInteraction(
-        SecurityInterstitialUmaHelper::SHOW_DIAGNOSTIC);
+    metrics_helper_->RecordUserInteraction(
+        SecurityInterstitialMetricsHelper::SHOW_DIAGNOSTIC);
     std::string diagnostic =
         base::StringPrintf(kSbDiagnosticUrl,
             net::EscapeQueryParamValue(bad_url_spec, true).c_str());
@@ -355,8 +358,8 @@
   }
 
   if (command == kExpandedSeeMoreCommand) {
-    uma_helper_->RecordUserInteraction(
-        SecurityInterstitialUmaHelper::SHOW_ADVANCED);
+    metrics_helper_->RecordUserInteraction(
+        SecurityInterstitialMetricsHelper::SHOW_ADVANCED);
     return;
   }
 
@@ -421,8 +424,8 @@
     return;
 
   if (!IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
-    uma_helper_->RecordUserDecision(
-        SecurityInterstitialUmaHelper::DONT_PROCEED);
+    metrics_helper_->RecordUserDecision(
+        SecurityInterstitialMetricsHelper::DONT_PROCEED);
   }
 
   // Send the malware details, if we opted to.
@@ -555,7 +558,7 @@
   return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
 }
 
-std::string SafeBrowsingBlockingPage::GetHistogramPrefix() const {
+std::string SafeBrowsingBlockingPage::GetMetricPrefix() const {
   switch (interstitial_reason_) {
     case SB_REASON_MALWARE:
       return "malware";
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index 27ee2e6..424e5167 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -34,8 +34,8 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "chrome/browser/interstitials/security_interstitial_metrics_helper.h"
 #include "chrome/browser/interstitials/security_interstitial_page.h"
-#include "chrome/browser/interstitials/security_interstitial_uma_helper.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "url/gurl.h"
 
@@ -191,10 +191,10 @@
   void PopulateHarmfulLoadTimeData(base::DictionaryValue* load_time_data);
   void PopulatePhishingLoadTimeData(base::DictionaryValue* load_time_data);
 
-  std::string GetHistogramPrefix() const;
+  std::string GetMetricPrefix() const;
   std::string GetSamplingEventName() const;
 
-  scoped_ptr<SecurityInterstitialUmaHelper> uma_helper_;
+  scoped_ptr<SecurityInterstitialMetricsHelper> metrics_helper_;
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
 };
diff --git a/chrome/browser/search/contextual_search_promo_source_android.h b/chrome/browser/search/contextual_search_promo_source_android.h
index 1a2319f6..4ed5bbb 100644
--- a/chrome/browser/search/contextual_search_promo_source_android.h
+++ b/chrome/browser/search/contextual_search_promo_source_android.h
@@ -13,20 +13,19 @@
 class ContextualSearchPromoSourceAndroid : public content::URLDataSource {
  public:
   ContextualSearchPromoSourceAndroid();
-  virtual ~ContextualSearchPromoSourceAndroid();
+  ~ContextualSearchPromoSourceAndroid() override;
 
  protected:
   // Overridden from content::URLDataSource:
-  virtual void StartDataRequest(
+  void StartDataRequest(
       const std::string& path_and_query,
       int render_process_id,
       int render_frame_id,
       const content::URLDataSource::GotDataCallback& callback) override;
-  virtual std::string GetSource() const override;
-  virtual std::string GetMimeType(
-      const std::string& path_and_query) const override;
-  virtual bool ShouldDenyXFrameOptions() const override;
-  virtual bool ShouldAddContentSecurityPolicy() const override;
+  std::string GetSource() const override;
+  std::string GetMimeType(const std::string& path_and_query) const override;
+  bool ShouldDenyXFrameOptions() const override;
+  bool ShouldAddContentSecurityPolicy() const override;
 
   // Sends unmodified resource bytes.
   void SendResource(
diff --git a/chrome/browser/search/search_android_unittest.cc b/chrome/browser/search/search_android_unittest.cc
index 7c30dcb..5b8004ba 100644
--- a/chrome/browser/search/search_android_unittest.cc
+++ b/chrome/browser/search/search_android_unittest.cc
@@ -25,7 +25,7 @@
 
 class SearchUtilTest : public testing::Test {
  protected:
-  virtual void SetUp() {
+  void SetUp() override {
     field_trial_list_.reset(new base::FieldTrialList(
         new metrics::SHA1EntropyProvider("42")));
     base::StatisticsRecorder::Initialize();
diff --git a/chrome/browser/search_engines/template_url_service_android.h b/chrome/browser/search_engines/template_url_service_android.h
index 8c4971f0..7d94432 100644
--- a/chrome/browser/search_engines/template_url_service_android.h
+++ b/chrome/browser/search_engines/template_url_service_android.h
@@ -56,7 +56,7 @@
   static bool Register(JNIEnv* env);
 
  private:
-  ~TemplateUrlServiceAndroid();
+  ~TemplateUrlServiceAndroid() override;
 
   bool IsPrepopulatedTemplate(TemplateURL* url);
 
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index 813aa33..067a2863 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -10,7 +10,7 @@
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_brand.h"
-#include "chrome/browser/google/google_profile_helper.h"
+#include "chrome/browser/google/google_url_tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
@@ -19,6 +19,7 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
+#include "components/google/core/browser/google_url_tracker.h"
 #include "components/google/core/browser/google_util.h"
 #include "components/omnibox/omnibox_field_trial.h"
 #include "components/search/search.h"
@@ -49,9 +50,14 @@
   GURL base_url(google_util::CommandLineGoogleBaseURL());
   if (base_url.is_valid())
     return base_url.spec();
-  return profile_ ?
-      google_profile_helper::GetGoogleHomePageURL(profile_).spec() :
-      SearchTermsData::GoogleBaseURLValue();
+
+  if (!profile_)
+    return SearchTermsData::GoogleBaseURLValue();
+
+  const GoogleURLTracker* tracker =
+      GoogleURLTrackerFactory::GetForProfile(profile_);
+  return tracker ?
+      tracker->google_url().spec() : GoogleURLTracker::kDefaultGoogleHomepage;
 }
 
 std::string UIThreadSearchTermsData::GetApplicationLocale() const {
diff --git a/chrome/browser/services/gcm/push_messaging_browsertest.cc b/chrome/browser/services/gcm/push_messaging_browsertest.cc
index 5b20c30..b244392d 100644
--- a/chrome/browser/services/gcm/push_messaging_browsertest.cc
+++ b/chrome/browser/services/gcm/push_messaging_browsertest.cc
@@ -30,6 +30,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
+#include "ui/base/window_open_disposition.h"
 
 namespace gcm {
 
@@ -170,10 +171,16 @@
   }
 
   bool RunScript(const std::string& script, std::string* result) {
-    return content::ExecuteScriptAndExtractString(
-        browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
-        script,
-        result);
+    return RunScript(script, result, nullptr);
+  }
+
+  bool RunScript(const std::string& script, std::string* result,
+                 content::WebContents* web_contents) {
+    if (!web_contents)
+      web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+    return content::ExecuteScriptAndExtractString(web_contents->GetMainFrame(),
+                                                  script,
+                                                  result);
   }
 
   void TryToRegisterSuccessfully(
@@ -486,12 +493,30 @@
   notification_manager()->CancelAll();
   ASSERT_EQ(0u, notification_manager()->GetNotificationCount());
 
-  // If the Service Worker push event handler shows a notification, we should
-  // not show a forced one.
+  // We'll need to specify the web_contents in which to eval script, since we're
+  // going to run script in a background tab.
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // If the site is visible in an active tab, we should not force a notification
+  // to be shown.
   GCMClient::IncomingMessage message;
-  message.data["data"] = "shownotification";
+  message.data["data"] = "testdata";
   push_service()->OnMessage(app_id.ToString(), message);
   ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result));
+  EXPECT_EQ("testdata", script_result);
+  ASSERT_EQ(0u, notification_manager()->GetNotificationCount());
+
+  // Open a blank foreground tab so site is no longer visible.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), GURL("about:blank"), NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+
+  // If the Service Worker push event handler shows a notification, we should
+  // not show a forced one.
+  message.data["data"] = "shownotification";
+  push_service()->OnMessage(app_id.ToString(), message);
+  ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
   EXPECT_EQ("shownotification", script_result);
   ASSERT_EQ(1u, notification_manager()->GetNotificationCount());
   EXPECT_EQ(base::ASCIIToUTF16("push_test_tag"),
@@ -504,7 +529,7 @@
   // notification, we should show a forced one.
   message.data["data"] = "testdata";
   push_service()->OnMessage(app_id.ToString(), message);
-  ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result));
+  ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
   EXPECT_EQ("testdata", script_result);
   ASSERT_EQ(1u, notification_manager()->GetNotificationCount());
   EXPECT_EQ(base::ASCIIToUTF16(kPushMessagingForcedNotificationTag),
@@ -514,7 +539,7 @@
   // explicitly dismisses it (though we may change this later).
   message.data["data"] = "shownotification";
   push_service()->OnMessage(app_id.ToString(), message);
-  ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result));
+  ASSERT_TRUE(RunScript("resultQueue.pop()", &script_result, web_contents));
   EXPECT_EQ("shownotification", script_result);
   ASSERT_EQ(2u, notification_manager()->GetNotificationCount());
 }
diff --git a/chrome/browser/services/gcm/push_messaging_service_impl.cc b/chrome/browser/services/gcm/push_messaging_service_impl.cc
index 6a59cbe6..6722e11 100644
--- a/chrome/browser/services/gcm/push_messaging_service_impl.cc
+++ b/chrome/browser/services/gcm/push_messaging_service_impl.cc
@@ -33,9 +33,19 @@
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/platform_notification_data.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/ui/android/tab_model/tab_model.h"
+#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
+#else
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_iterator.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#endif
+
 namespace gcm {
 
 namespace {
@@ -243,6 +253,51 @@
   if (notification_count > 0)
     return;
 
+  // Sites with a currently visible tab don't need to show notifications.
+#if defined(OS_ANDROID)
+  for (auto it = TabModelList::begin(); it != TabModelList::end(); ++it) {
+    Profile* profile = (*it)->GetProfile();
+    content::WebContents* active_web_contents =
+        (*it)->GetActiveWebContents();
+#else
+  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
+    Profile* profile = it->profile();
+    content::WebContents* active_web_contents =
+        it->tab_strip_model()->GetActiveWebContents();
+#endif
+    if (!active_web_contents)
+      continue;
+
+    // Don't leak information from other profiles.
+    if (profile != profile_)
+      continue;
+
+    // Ignore minimized windows etc.
+    switch (active_web_contents->GetMainFrame()->GetVisibilityState()) {
+     case blink::WebPageVisibilityStateHidden:
+     case blink::WebPageVisibilityStatePrerender:
+      continue;
+     case blink::WebPageVisibilityStateVisible:
+      break;
+    }
+
+    // Use the visible URL since that's the one the user is aware of (and it
+    // doesn't matter whether the page loaded successfully).
+    const GURL& active_url = active_web_contents->GetVisibleURL();
+
+    // Allow https://foo.example.com Service Worker to not show notification if
+    // an https://bar.example.com tab is visible (and hence might conceivably
+    // be showing UI in response to the push message); but http:// doesn't count
+    // as the Service Worker can't talk to it, even with navigator.connect.
+    if (application_id.origin.scheme() != active_url.scheme())
+      continue;
+    if (net::registry_controlled_domains::SameDomainOrHost(
+        application_id.origin, active_url,
+        net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
+      return;
+    }
+  }
+
   // If we haven't returned yet, the site failed to show a notification, so we
   // will show a generic notification. See https://crbug.com/437277
   // TODO(johnme): The generic notification should probably automatically close
diff --git a/chrome/browser/sessions/in_memory_tab_restore_service.h b/chrome/browser/sessions/in_memory_tab_restore_service.h
index 78557cd..deef49c2 100644
--- a/chrome/browser/sessions/in_memory_tab_restore_service.h
+++ b/chrome/browser/sessions/in_memory_tab_restore_service.h
@@ -22,30 +22,29 @@
   InMemoryTabRestoreService(Profile* profile,
                             TimeFactory* time_factory);
 
-  virtual ~InMemoryTabRestoreService();
+  ~InMemoryTabRestoreService() override;
 
   // TabRestoreService:
-  virtual void AddObserver(TabRestoreServiceObserver* observer) override;
-  virtual void RemoveObserver(TabRestoreServiceObserver* observer) override;
-  virtual void CreateHistoricalTab(content::WebContents* contents,
-                                   int index) override;
-  virtual void BrowserClosing(TabRestoreServiceDelegate* delegate) override;
-  virtual void BrowserClosed(TabRestoreServiceDelegate* delegate) override;
-  virtual void ClearEntries() override;
-  virtual const Entries& entries() const override;
-  virtual std::vector<content::WebContents*> RestoreMostRecentEntry(
+  void AddObserver(TabRestoreServiceObserver* observer) override;
+  void RemoveObserver(TabRestoreServiceObserver* observer) override;
+  void CreateHistoricalTab(content::WebContents* contents, int index) override;
+  void BrowserClosing(TabRestoreServiceDelegate* delegate) override;
+  void BrowserClosed(TabRestoreServiceDelegate* delegate) override;
+  void ClearEntries() override;
+  const Entries& entries() const override;
+  std::vector<content::WebContents*> RestoreMostRecentEntry(
       TabRestoreServiceDelegate* delegate,
       chrome::HostDesktopType host_desktop_type) override;
-  virtual Tab* RemoveTabEntryById(SessionID::id_type id) override;
-  virtual std::vector<content::WebContents*>
-    RestoreEntryById(TabRestoreServiceDelegate* delegate,
-                     SessionID::id_type id,
-                     chrome::HostDesktopType host_desktop_type,
-                     WindowOpenDisposition disposition) override;
-  virtual void LoadTabsFromLastSession() override;
-  virtual bool IsLoaded() const override;
-  virtual void DeleteLastSession() override;
-  virtual void Shutdown() override;
+  Tab* RemoveTabEntryById(SessionID::id_type id) override;
+  std::vector<content::WebContents*> RestoreEntryById(
+      TabRestoreServiceDelegate* delegate,
+      SessionID::id_type id,
+      chrome::HostDesktopType host_desktop_type,
+      WindowOpenDisposition disposition) override;
+  void LoadTabsFromLastSession() override;
+  bool IsLoaded() const override;
+  void DeleteLastSession() override;
+  void Shutdown() override;
 
  private:
   TabRestoreServiceHelper helper_;
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.cc b/chrome/browser/signin/android_profile_oauth2_token_service.cc
index abccb27..e62353cb 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.cc
@@ -39,13 +39,13 @@
  public:
   AndroidAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer,
                             const std::string& account_id);
-  virtual ~AndroidAccessTokenFetcher();
+  ~AndroidAccessTokenFetcher() override;
 
   // Overrides from OAuth2AccessTokenFetcher:
-  virtual void Start(const std::string& client_id,
-                     const std::string& client_secret,
-                     const std::vector<std::string>& scopes) override;
-  virtual void CancelRequest() override;
+  void Start(const std::string& client_id,
+             const std::string& client_secret,
+             const std::vector<std::string>& scopes) override;
+  void CancelRequest() override;
 
   // Handles an access token response.
   void OnAccessTokenResponse(const GoogleServiceAuthError& error,
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.h b/chrome/browser/signin/android_profile_oauth2_token_service.h
index cae22f71..f4cb0a5 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.h
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.h
@@ -44,15 +44,12 @@
   }
 
   // ProfileOAuth2TokenService overrides:
-  virtual void Initialize(
-      SigninClient* client,
-      SigninErrorController* signin_error_controller) override;
-  virtual bool RefreshTokenIsAvailable(
-      const std::string& account_id) const override;
-  virtual void UpdateAuthError(
-      const std::string& account_id,
-      const GoogleServiceAuthError& error) override;
-  virtual std::vector<std::string> GetAccounts() override;
+  void Initialize(SigninClient* client,
+                  SigninErrorController* signin_error_controller) override;
+  bool RefreshTokenIsAvailable(const std::string& account_id) const override;
+  void UpdateAuthError(const std::string& account_id,
+                       const GoogleServiceAuthError& error) override;
+  std::vector<std::string> GetAccounts() override;
 
   // Lists account at the OS level.
   std::vector<std::string> GetSystemAccounts();
@@ -86,32 +83,31 @@
 
   // Overridden from OAuth2TokenService to complete signout of all
   // OA2TService aware accounts.
-  virtual void RevokeAllCredentials() override;
+  void RevokeAllCredentials() override;
 
  protected:
   friend class ProfileOAuth2TokenServiceFactory;
   AndroidProfileOAuth2TokenService();
-  virtual ~AndroidProfileOAuth2TokenService();
+  ~AndroidProfileOAuth2TokenService() override;
 
-  virtual OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
+  OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
       net::URLRequestContextGetter* getter,
       OAuth2AccessTokenConsumer* consumer) override;
 
   // Overridden from OAuth2TokenService to intercept token fetch requests and
   // redirect them to the Account Manager.
-  virtual void InvalidateOAuth2Token(const std::string& account_id,
-                                     const std::string& client_id,
-                                     const ScopeSet& scopes,
-                                     const std::string& access_token) override;
+  void InvalidateOAuth2Token(const std::string& account_id,
+                             const std::string& client_id,
+                             const ScopeSet& scopes,
+                             const std::string& access_token) override;
 
   // Called to notify observers when a refresh token is available.
-  virtual void FireRefreshTokenAvailable(
-      const std::string& account_id) override;
+  void FireRefreshTokenAvailable(const std::string& account_id) override;
   // Called to notify observers when a refresh token has been revoked.
-  virtual void FireRefreshTokenRevoked(const std::string& account_id) override;
+  void FireRefreshTokenRevoked(const std::string& account_id) override;
   // Called to notify observers when refresh tokans have been loaded.
-  virtual void FireRefreshTokensLoaded() override;
+  void FireRefreshTokensLoaded() override;
 
  private:
   // Return whether |signed_in_account| is valid and we have access
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index d3d2746..3315642 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -248,7 +248,7 @@
 #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
   // Don't store password hash except when lock is available for the user.
   if (!password.empty() && profiles::IsLockAvailable(profile_))
-    chrome::SetLocalAuthCredentials(profile_, password);
+    LocalAuth::SetLocalAuthCredentials(profile_, password);
 #endif
 }
 
diff --git a/chrome/browser/signin/local_auth.cc b/chrome/browser/signin/local_auth.cc
index 7748898..9b20c322 100644
--- a/chrome/browser/signin/local_auth.cc
+++ b/chrome/browser/signin/local_auth.cc
@@ -22,21 +22,81 @@
 
 namespace {
 
+struct HashEncoding {
+  char version;
+  unsigned hash_bits;
+  unsigned hash_bytes;
+  unsigned iteration_count;
+  unsigned stored_bits;
+  unsigned stored_bytes;
+
+  public:
+   HashEncoding(char version,
+                unsigned hash_bits,
+                unsigned hash_bytes,
+                unsigned iteration_count,
+                unsigned stored_bits,
+                unsigned stored_bytes) :
+      version(version),
+      hash_bits(hash_bits),
+      hash_bytes(hash_bytes),
+      iteration_count(iteration_count),
+      stored_bits(stored_bits),
+      stored_bytes(stored_bytes) {}
+};
+
 // WARNING: Changing these values will make it impossible to do off-line
 // authentication until the next successful on-line authentication.  To change
-// these safely, change the "encoding" version below and make verification
-// handle multiple values.
-const char kHash1Encoding = '1';
+// these safely, add a new HashEncoding object below and increment
+// NUM_HASH_ENCODINGS.
+const char kHash1Version = '1';
 const unsigned kHash1Bits = 256;
 const unsigned kHash1Bytes = kHash1Bits / 8;
 const unsigned kHash1IterationCount = 100000;
 
+// Store 13 bits to provide pin-like security (8192 possible values), without
+// providing a complete oracle for the user's GAIA password.
+const char kHash2Version = '2';
+const unsigned kHash2Bits = 256;
+const unsigned kHash2Bytes = kHash2Bits / 8;
+const unsigned kHash2IterationCount = 100000;
+const unsigned kHash2StoredBits = 13;
+const unsigned kHash2StoredBytes = (kHash2StoredBits + 7) / 8;
+
+const int NUM_HASH_ENCODINGS = 2;
+HashEncoding encodings[NUM_HASH_ENCODINGS] = {
+  HashEncoding(
+      kHash1Version, kHash1Bits, kHash1Bytes, kHash1IterationCount, 0, 0),
+  HashEncoding(
+      kHash2Version, kHash2Bits, kHash2Bytes, kHash2IterationCount,
+          kHash2StoredBits, kHash2StoredBytes)
+};
+
+const HashEncoding* GetEncodingForVersion(char version) {
+  // Note that versions are 1-indexed.
+  DCHECK(version > '0' && version <= ('0' + NUM_HASH_ENCODINGS));
+  return &encodings[(version - '0') - 1];
+}
+
+std::string TruncateStringByBits(const std::string& str,
+                                 const size_t len_bits) {
+  if (len_bits % 8 == 0)
+    return str.substr(0, len_bits / 8);
+
+  // The initial truncation copies whole bytes
+  int number_bytes = (len_bits + 7) / 8;
+  std::string truncated_string = str.substr(0, number_bytes);
+
+  // Keep the prescribed number of bits from the last byte.
+  unsigned last_char_bitmask = (1 << (len_bits % 8)) - 1;
+  truncated_string[number_bytes - 1] &= last_char_bitmask;
+  return truncated_string;
+}
+
 std::string CreateSecurePasswordHash(const std::string& salt,
                                      const std::string& password,
-                                     char encoding) {
-  DCHECK_EQ(kHash1Bytes, salt.length());
-  DCHECK_EQ(kHash1Encoding, encoding);  // Currently support only one method.
-
+                                     const HashEncoding& encoding) {
+  DCHECK_EQ(encoding.hash_bytes, salt.length());
   base::Time start_time = base::Time::Now();
 
   // Library call to create secure password hash as SymmetricKey (uses PBKDF2).
@@ -44,22 +104,26 @@
       crypto::SymmetricKey::DeriveKeyFromPassword(
           crypto::SymmetricKey::AES,
           password, salt,
-          kHash1IterationCount, kHash1Bits));
+          encoding.iteration_count, encoding.hash_bits));
   std::string password_hash;
   const bool success = password_key->GetRawKey(&password_hash);
   DCHECK(success);
-  DCHECK_EQ(kHash1Bytes, password_hash.length());
+  DCHECK_EQ(encoding.hash_bytes, password_hash.length());
 
   UMA_HISTOGRAM_TIMES("PasswordHash.CreateTime",
                       base::Time::Now() - start_time);
 
+  if (encoding.stored_bits) {
+    password_hash = TruncateStringByBits(password_hash, encoding.stored_bits);
+    DCHECK_EQ(encoding.stored_bytes, password_hash.length());
+  }
+  DCHECK_EQ(encoding.stored_bytes ? encoding.stored_bytes : encoding.hash_bytes,
+            password_hash.length());
   return password_hash;
 }
 
 std::string EncodePasswordHashRecord(const std::string& record,
-                                     char encoding) {
-  DCHECK_EQ(kHash1Encoding, encoding);  // Currently support only one method.
-
+                                     const HashEncoding& encoding) {
   // Encrypt the hash using the OS account-password protection (if available).
   std::string encoded;
   const bool success = OSCrypt::EncryptString(record, &encoded);
@@ -70,7 +134,7 @@
   base::Base64Encode(encoded, &encoded64);
 
   // Stuff the "encoding" value into the first byte.
-  encoded64.insert(0, &encoding, sizeof(encoding));
+  encoded64.insert(0, &encoding.version, sizeof(encoding.version));
 
   return encoded64;
 }
@@ -82,7 +146,7 @@
   if (encoded.length() < 1)
     return false;
   *encoding = encoded[0];
-  if (*encoding != kHash1Encoding)
+  if (!GetEncodingForVersion(*encoding))
     return false;
 
   // Stored record is base64; convert to binary.
@@ -104,33 +168,33 @@
 
 }  // namespace
 
-namespace chrome {
+std::string LocalAuth::TruncateStringByBits(const std::string& str,
+                                            const size_t len_bits) {
+  return ::TruncateStringByBits(str, len_bits);
+}
 
-void RegisterLocalAuthPrefs(user_prefs::PrefRegistrySyncable* registry) {
+void LocalAuth::RegisterLocalAuthPrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterStringPref(
       prefs::kGoogleServicesPasswordHash,
       std::string(),
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
-void SetLocalAuthCredentials(size_t info_index,
-                             const std::string& password) {
-  if (info_index == std::string::npos) {
-    NOTREACHED();
-    return;
-  }
-  DCHECK(password.length());
+void LocalAuth::SetLocalAuthCredentialsWithEncoding(size_t info_index,
+                                                    const std::string& password,
+                                                    char encoding_version) {
+  const HashEncoding& encoding = encodings[(encoding_version - '0') - 1];
 
   // Salt should be random data, as long as the hash length, and different with
   // every save.
   std::string salt_str;
-  crypto::RandBytes(WriteInto(&salt_str, kHash1Bytes + 1), kHash1Bytes);
-  DCHECK_EQ(kHash1Bytes, salt_str.length());
+  crypto::RandBytes(WriteInto(&salt_str, encoding.hash_bytes + 1),
+                              encoding.hash_bytes);
 
   // Perform secure hash of password for storage.
   std::string password_hash = CreateSecurePasswordHash(
-      salt_str, password, kHash1Encoding);
-  DCHECK_EQ(kHash1Bytes, password_hash.length());
+      salt_str, password, encoding);
 
   // Group all fields into a single record for storage;
   std::string record;
@@ -138,19 +202,30 @@
   record.append(password_hash);
 
   // Encode it and store it.
-  std::string encoded = EncodePasswordHashRecord(record, kHash1Encoding);
+  std::string encoded = EncodePasswordHashRecord(record, encoding);
   ProfileInfoCache& info =
       g_browser_process->profile_manager()->GetProfileInfoCache();
   info.SetLocalAuthCredentialsOfProfileAtIndex(info_index, encoded);
 }
 
-void SetLocalAuthCredentials(const Profile* profile,
-                             const std::string& password) {
+void LocalAuth::SetLocalAuthCredentials(size_t info_index,
+                                        const std::string& password) {
+  if (info_index == std::string::npos) {
+    NOTREACHED();
+    return;
+  }
+  DCHECK(password.length());
+  SetLocalAuthCredentialsWithEncoding(
+      info_index, password, '0' + NUM_HASH_ENCODINGS);
+}
+
+void LocalAuth::SetLocalAuthCredentials(const Profile* profile,
+                                        const std::string& password) {
   SetLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile), password);
 }
 
-bool ValidateLocalAuthCredentials(size_t info_index,
-                                  const std::string& password) {
+bool LocalAuth::ValidateLocalAuthCredentials(size_t info_index,
+                                             const std::string& password) {
   if (info_index == std::string::npos) {
     NOTREACHED();
     return false;
@@ -174,28 +249,31 @@
   const char* password_check;
   size_t password_length;
 
-  if (encoding == '1') {
-    // Validate correct length; extract salt and password hash.
-    if (record.length() != 2 * kHash1Bytes)
-      return false;
-    std::string salt_str(record.data(), kHash1Bytes);
-    password_saved = record.data() + kHash1Bytes;
-    password_hash = CreateSecurePasswordHash(salt_str, password, encoding);
-    password_check = password_hash.data();
-    password_length = kHash1Bytes;
-  } else {
-    // unknown encoding
+  const HashEncoding* hash_encoding = GetEncodingForVersion(encoding);
+  if (!hash_encoding) {
+    // Unknown encoding.
     return false;
   }
 
-  return crypto::SecureMemEqual(password_saved, password_check,
-                                password_length);
+  // Extract salt.
+  std::string salt_str(record.data(), hash_encoding->hash_bytes);
+  // Extract password.
+  password_saved = record.data() + hash_encoding->hash_bytes;
+  password_hash = CreateSecurePasswordHash(salt_str, password, *hash_encoding);
+  password_length = hash_encoding->stored_bytes;
+  password_check = password_hash.data();
+
+  bool passwords_match = crypto::SecureMemEqual(
+      password_saved, password_check, password_length);
+
+  // Update the stored credentials to the latest encoding if necessary.
+  if (passwords_match && (hash_encoding->version - '0') != NUM_HASH_ENCODINGS)
+    SetLocalAuthCredentials(info_index, password);
+  return passwords_match;
 }
 
-bool ValidateLocalAuthCredentials(const Profile* profile,
-                                  const std::string& password) {
+bool LocalAuth::ValidateLocalAuthCredentials(const Profile* profile,
+                                             const std::string& password) {
   return ValidateLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile),
                                       password);
 }
-
-}  // namespace chrome
diff --git a/chrome/browser/signin/local_auth.h b/chrome/browser/signin/local_auth.h
index 2342a81..570b5bc3 100644
--- a/chrome/browser/signin/local_auth.h
+++ b/chrome/browser/signin/local_auth.h
@@ -11,28 +11,46 @@
 
 #include <string>
 
+#include "base/gtest_prod_util.h"
+
+class LocalAuthTest;
 class Profile;
 
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
 
-namespace chrome {
+class LocalAuth {
+ public:
+  static void RegisterLocalAuthPrefs(
+      user_prefs::PrefRegistrySyncable* registry);
 
-void RegisterLocalAuthPrefs(user_prefs::PrefRegistrySyncable* registry);
+  static void SetLocalAuthCredentials(size_t profile_info_index,
+                                      const std::string& password);
 
-void SetLocalAuthCredentials(size_t profile_info_index,
-                             const std::string& password);
 
-void SetLocalAuthCredentials(const Profile* profile,
-                             const std::string& password);
+  static void SetLocalAuthCredentials(const Profile* profile,
+                                      const std::string& password);
 
-bool ValidateLocalAuthCredentials(size_t profile_info_index,
-                                  const std::string& password);
+  static bool ValidateLocalAuthCredentials(size_t profile_info_index,
+                                           const std::string& password);
 
-bool ValidateLocalAuthCredentials(const Profile* profile,
-                                  const std::string& password);
+  static bool ValidateLocalAuthCredentials(const Profile* profile,
+                                           const std::string& password);
 
-}  // namespace chrome
+ private:
+  FRIEND_TEST_ALL_PREFIXES(LocalAuthTest, SetUpgradeAndCheckCredentials);
+  FRIEND_TEST_ALL_PREFIXES(LocalAuthTest, TruncateStringEvenly);
+  FRIEND_TEST_ALL_PREFIXES(LocalAuthTest, TruncateStringUnevenly);
+
+  // Return only the first |len_bits| bits of the string |str|. Defined here for
+  // testing.
+  static std::string TruncateStringByBits(const std::string& str,
+                                          const size_t len_bits);
+
+  static void SetLocalAuthCredentialsWithEncoding(size_t profile_info_index,
+                                                  const std::string& password,
+                                                  char encoding_version);
+};
 
 #endif  // CHROME_BROWSER_SIGNIN_LOCAL_AUTH_H_
diff --git a/chrome/browser/signin/local_auth_unittest.cc b/chrome/browser/signin/local_auth_unittest.cc
index 68ee397..14aea881 100644
--- a/chrome/browser/signin/local_auth_unittest.cc
+++ b/chrome/browser/signin/local_auth_unittest.cc
@@ -15,8 +15,6 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-using namespace chrome;
-
 TEST(LocalAuthTest, SetAndCheckCredentials) {
   TestingProfileManager testing_profile_manager(
       TestingBrowserProcess::GetGlobal());
@@ -32,9 +30,9 @@
 #endif
 
   std::string password("Some Password");
-  EXPECT_FALSE(ValidateLocalAuthCredentials(prof, password));
+  EXPECT_FALSE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
 
-  SetLocalAuthCredentials(prof, password);
+  LocalAuth::SetLocalAuthCredentials(prof, password);
   std::string passhash = cache.GetLocalAuthCredentialsOfProfileAtIndex(0);
 
   // We perform basic validation on the written record to ensure bugs don't slip
@@ -42,7 +40,7 @@
   //  - The encoding exists (we can guarantee future backward compatibility).
   //  - The plaintext version of the password is not mistakenly stored anywhere.
   EXPECT_FALSE(passhash.empty());
-  EXPECT_EQ('1', passhash[0]);
+  EXPECT_EQ('2', passhash[0]);
   EXPECT_EQ(passhash.find(password), std::string::npos);
 
   std::string decodedhash;
@@ -50,9 +48,68 @@
   EXPECT_FALSE(decodedhash.empty());
   EXPECT_EQ(decodedhash.find(password), std::string::npos);
 
-  EXPECT_TRUE(ValidateLocalAuthCredentials(prof, password));
-  EXPECT_FALSE(ValidateLocalAuthCredentials(prof, password + "1"));
+  EXPECT_TRUE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
+  EXPECT_FALSE(LocalAuth::ValidateLocalAuthCredentials(prof, password + "1"));
 
-  SetLocalAuthCredentials(prof, password);  // makes different salt
+  LocalAuth::SetLocalAuthCredentials(prof, password);  // makes different salt
   EXPECT_NE(passhash, cache.GetLocalAuthCredentialsOfProfileAtIndex(0));
 }
+
+
+TEST(LocalAuthTest, SetUpgradeAndCheckCredentials) {
+  TestingProfileManager testing_profile_manager(
+      TestingBrowserProcess::GetGlobal());
+  ASSERT_TRUE(testing_profile_manager.SetUp());
+  Profile* prof = testing_profile_manager.CreateTestingProfile("p1");
+  ProfileInfoCache& cache =
+      testing_profile_manager.profile_manager()->GetProfileInfoCache();
+
+#if defined(OS_MACOSX)
+  OSCrypt::UseMockKeychain(true);
+#endif
+
+  std::string password("Some Password");
+  size_t profile_index = cache.GetIndexOfProfileWithPath(prof->GetPath());
+  LocalAuth::SetLocalAuthCredentialsWithEncoding(profile_index, password, '1');
+
+  // Ensure we indeed persisted the correct encoding.
+  std::string oldpasshash = cache.GetLocalAuthCredentialsOfProfileAtIndex(
+      profile_index);
+  EXPECT_EQ('1', oldpasshash[0]);
+
+  // Validate, ensure we can validate against the old encoding.
+  EXPECT_TRUE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
+
+  // Ensure we updated the encoding.
+  std::string newpasshash = cache.GetLocalAuthCredentialsOfProfileAtIndex(
+      profile_index);
+  EXPECT_EQ('2', newpasshash[0]);
+  // Encoding '2' writes fewer bytes than encoding '1'.
+  EXPECT_LE(newpasshash.length(), oldpasshash.length());
+
+  // Validate, ensure we validate against the new encoding.
+  EXPECT_TRUE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
+}
+
+// Test truncation where each byte is left whole.
+TEST(LocalAuthTest, TruncateStringEvenly) {
+  std::string two_chars = "A6";
+  std::string three_chars = "A6C";
+  EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(two_chars, 16));
+  EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(three_chars, 16));
+
+  EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(two_chars, 14));
+  EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(three_chars, 14));
+}
+
+// Test truncation that affects the results within a byte.
+TEST(LocalAuthTest, TruncateStringUnevenly) {
+  std::string two_chars = "Az";
+  std::string three_chars = "AzC";
+  // 'z' = 0x7A, ':' = 0x3A.
+  std::string two_chars_truncated = "A:";
+  EXPECT_EQ(two_chars_truncated,
+      LocalAuth::TruncateStringByBits(two_chars, 14));
+  EXPECT_EQ(two_chars_truncated,
+      LocalAuth::TruncateStringByBits(three_chars, 14));
+}
diff --git a/chrome/browser/signin/signin_manager_factory.cc b/chrome/browser/signin/signin_manager_factory.cc
index a7915f3..7867c69 100644
--- a/chrome/browser/signin/signin_manager_factory.cc
+++ b/chrome/browser/signin/signin_manager_factory.cc
@@ -103,7 +103,7 @@
       prefs::kSignedInTime,
       base::Time().ToInternalValue(),
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  chrome::RegisterLocalAuthPrefs(registry);
+  LocalAuth::RegisterLocalAuthPrefs(registry);
 }
 
 // static
diff --git a/chrome/browser/speech/tts_android.h b/chrome/browser/speech/tts_android.h
index 898418bb..6dcf02b 100644
--- a/chrome/browser/speech/tts_android.h
+++ b/chrome/browser/speech/tts_android.h
@@ -12,18 +12,17 @@
 class TtsPlatformImplAndroid : public TtsPlatformImpl {
  public:
   // TtsPlatformImpl implementation.
-  virtual bool PlatformImplAvailable() override;
-  virtual bool Speak(
-      int utterance_id,
-      const std::string& utterance,
-      const std::string& lang,
-      const VoiceData& voice,
-      const UtteranceContinuousParameters& params) override;
-  virtual bool StopSpeaking() override;
-  virtual void Pause() override;
-  virtual void Resume() override;
-  virtual bool IsSpeaking() override;
-  virtual void GetVoices(std::vector<VoiceData>* out_voices) override;
+  bool PlatformImplAvailable() override;
+  bool Speak(int utterance_id,
+             const std::string& utterance,
+             const std::string& lang,
+             const VoiceData& voice,
+             const UtteranceContinuousParameters& params) override;
+  bool StopSpeaking() override;
+  void Pause() override;
+  void Resume() override;
+  bool IsSpeaking() override;
+  void GetVoices(std::vector<VoiceData>* out_voices) override;
 
   // Methods called from Java via JNI.
   void VoicesChanged(JNIEnv* env, jobject obj);
@@ -39,7 +38,7 @@
   friend struct DefaultSingletonTraits<TtsPlatformImplAndroid>;
 
   TtsPlatformImplAndroid();
-  virtual ~TtsPlatformImplAndroid();
+  ~TtsPlatformImplAndroid() override;
 
   void SendFinalTtsEvent(
       int utterance_id, TtsEventType event_type, int char_index);
diff --git a/chrome/browser/ssl/captive_portal_blocking_page.cc b/chrome/browser/ssl/captive_portal_blocking_page.cc
index 5c954774..9d9d23f 100644
--- a/chrome/browser/ssl/captive_portal_blocking_page.cc
+++ b/chrome/browser/ssl/captive_portal_blocking_page.cc
@@ -34,38 +34,44 @@
   CAPTIVE_PORTAL_BLOCKING_PAGE_EVENT_COUNT
 };
 
+const char kOpenLoginPageCommand[] = "openLoginPage";
+
 void RecordUMA(CaptivePortalBlockingPageEvent event) {
   UMA_HISTOGRAM_ENUMERATION("interstitial.captive_portal",
                             event,
                             CAPTIVE_PORTAL_BLOCKING_PAGE_EVENT_COUNT);
 }
 
-bool IsWifiConnection() {
-  // |net::NetworkChangeNotifier::GetConnectionType| isn't accurate on Linux and
-  // Windows. See https://crbug.com/160537 for details.
-  // TODO(meacer): Add heuristics to get a more accurate connection type on
-  //               these platforms.
-  return net::NetworkChangeNotifier::GetConnectionType() ==
-      net::NetworkChangeNotifier::CONNECTION_WIFI;
-}
+class ConnectionInfoDelegate : public CaptivePortalBlockingPage::Delegate {
+ public:
+  ConnectionInfoDelegate() {}
+  ~ConnectionInfoDelegate() override {}
 
-std::string GetWiFiName() {
-  std::string ssid;
+  bool IsWifiConnection() const override {
+    // |net::NetworkChangeNotifier::GetConnectionType| isn't accurate on Linux
+    // and Windows. See https://crbug.com/160537 for details.
+    // TODO(meacer): Add heuristics to get a more accurate connection type on
+    //               these platforms.
+    return net::NetworkChangeNotifier::GetConnectionType() ==
+           net::NetworkChangeNotifier::CONNECTION_WIFI;
+  }
+
+  std::string GetWiFiSSID() const override {
+    std::string ssid;
 #if defined(OS_WIN) || defined(OS_MACOSX)
-  scoped_ptr<wifi::WiFiService> wifi_service(wifi::WiFiService::Create());
-  wifi_service->Initialize(NULL);
-  std::string error;
-  wifi_service->GetConnectedNetworkSSID(&ssid, &error);
-  if (!error.empty())
-    return "";
+    scoped_ptr<wifi::WiFiService> wifi_service(wifi::WiFiService::Create());
+    wifi_service->Initialize(NULL);
+    std::string error;
+    wifi_service->GetConnectedNetworkSSID(&ssid, &error);
+    if (!error.empty())
+      return "";
 #endif
-  // TODO(meacer): Handle non UTF8 SSIDs.
-  if (!base::IsStringUTF8(ssid))
-    return "";
-  return ssid;
-}
-
-const char kOpenLoginPageCommand[] = "openLoginPage";
+    // TODO(meacer): Handle non UTF8 SSIDs.
+    if (!base::IsStringUTF8(ssid))
+      return "";
+    return ssid;
+  }
+};
 
 } // namespace
 
@@ -80,7 +86,7 @@
     const base::Callback<void(bool)>& callback)
     : SecurityInterstitialPage(web_contents, request_url),
       login_url_(login_url),
-      is_wifi_connection_(IsWifiConnection()),
+      delegate_(new ConnectionInfoDelegate),
       callback_(callback) {
   DCHECK(login_url_.is_valid());
   RecordUMA(SHOW_ALL);
@@ -109,81 +115,67 @@
   load_time_data->SetString("type", "CAPTIVE_PORTAL");
   load_time_data->SetBoolean("overridable", false);
 
+  // |IsWifiConnection| isn't accurate on some platforms, so always try to get
+  // the Wi-Fi SSID even if |IsWifiConnection| is false.
+  std::string wifi_ssid = delegate_.get()->GetWiFiSSID();
+  bool is_wifi_connection = !wifi_ssid.empty() ||
+                            delegate_.get()->IsWifiConnection();
+
   load_time_data->SetString(
       "primaryButtonText",
       l10n_util::GetStringUTF16(IDS_CAPTIVE_PORTAL_BUTTON_OPEN_LOGIN_PAGE));
-  load_time_data->SetString("tabTitle",
-      l10n_util::GetStringUTF16(
-          is_wifi_connection_ ?
-          IDS_CAPTIVE_PORTAL_HEADING_WIFI :
-          IDS_CAPTIVE_PORTAL_HEADING_WIRED));
-  load_time_data->SetString("heading",
-      l10n_util::GetStringUTF16(
-          is_wifi_connection_ ?
-          IDS_CAPTIVE_PORTAL_HEADING_WIFI :
-          IDS_CAPTIVE_PORTAL_HEADING_WIRED));
+  load_time_data->SetString(
+      "tabTitle", l10n_util::GetStringUTF16(
+                      is_wifi_connection ? IDS_CAPTIVE_PORTAL_HEADING_WIFI
+                                         : IDS_CAPTIVE_PORTAL_HEADING_WIRED));
+  load_time_data->SetString(
+      "heading", l10n_util::GetStringUTF16(
+                     is_wifi_connection ? IDS_CAPTIVE_PORTAL_HEADING_WIFI
+                                        : IDS_CAPTIVE_PORTAL_HEADING_WIRED));
 
   if (login_url_.spec() == captive_portal::CaptivePortalDetector::kDefaultURL) {
     // Captive portal may intercept requests without HTTP redirects, in which
     // case the login url would be the same as the captive portal detection url.
     // Don't show the login url in that case.
-    if (is_wifi_connection_) {
-      if (wifi_ssid_.empty())
-        wifi_ssid_ = GetWiFiName();
-      if (wifi_ssid_.empty()) {
-        load_time_data->SetString(
-            "primaryParagraph",
-            l10n_util::GetStringUTF16(
-                IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIFI));
-      } else {
-        load_time_data->SetString(
-            "primaryParagraph",
-            l10n_util::GetStringFUTF16(
-                IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIFI_SSID,
-                net::EscapeForHTML(base::UTF8ToUTF16(wifi_ssid_))));
-      }
-    } else {
-      // Non-WiFi connection:
+    if (wifi_ssid.empty()) {
       load_time_data->SetString(
           "primaryParagraph",
           l10n_util::GetStringUTF16(
-              IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIRED));
+              is_wifi_connection
+                  ? IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIFI
+                  : IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIRED));
+    } else {
+      load_time_data->SetString(
+          "primaryParagraph",
+          l10n_util::GetStringFUTF16(
+              IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_NO_LOGIN_URL_WIFI_SSID,
+              net::EscapeForHTML(base::UTF8ToUTF16(wifi_ssid))));
     }
   } else {
-    // Portal redirection was done with HTTP redirects, show the login URL.
+    // Portal redirection was done with HTTP redirects, so show the login URL.
+    // If |languages| is empty, punycode in |login_host| will always be decoded.
     std::string languages;
     Profile* profile = Profile::FromBrowserContext(
         web_contents()->GetBrowserContext());
     if (profile)
       languages = profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
-
     base::string16 login_host = net::IDNToUnicode(login_url_.host(), languages);
     if (base::i18n::IsRTL())
       base::i18n::WrapStringWithLTRFormatting(&login_host);
 
-    if (is_wifi_connection_) {
-      if (wifi_ssid_.empty())
-        wifi_ssid_ = GetWiFiName();
-      if (wifi_ssid_.empty()) {
-        load_time_data->SetString(
-            "primaryParagraph",
-            l10n_util::GetStringFUTF16(
-                IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI,
-                login_host));
-      } else {
-        load_time_data->SetString(
-            "primaryParagraph",
-                l10n_util::GetStringFUTF16(
-                IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI_SSID,
-                net::EscapeForHTML(base::UTF8ToUTF16(wifi_ssid_)),
-                login_host));
-      }
-    } else {
-      // Non-WiFi connection:
+    if (wifi_ssid.empty()) {
       load_time_data->SetString(
           "primaryParagraph",
-          l10n_util::GetStringFUTF16(IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIRED,
-                                     login_host));
+          l10n_util::GetStringFUTF16(
+              is_wifi_connection ? IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI
+                                 : IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIRED,
+              login_host));
+    } else {
+      load_time_data->SetString(
+          "primaryParagraph",
+          l10n_util::GetStringFUTF16(
+              IDS_CAPTIVE_PORTAL_PRIMARY_PARAGRAPH_WIFI_SSID,
+              net::EscapeForHTML(base::UTF8ToUTF16(wifi_ssid)), login_host));
     }
   }
 
diff --git a/chrome/browser/ssl/captive_portal_blocking_page.h b/chrome/browser/ssl/captive_portal_blocking_page.h
index e5cdd897..0b150cb6 100644
--- a/chrome/browser/ssl/captive_portal_blocking_page.h
+++ b/chrome/browser/ssl/captive_portal_blocking_page.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/interstitials/security_interstitial_page.h"
 #include "url/gurl.h"
 
@@ -28,6 +29,16 @@
   // Interstitial type, for testing.
   static const void* kTypeForTesting;
 
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Returns true if the connection is a Wi-Fi connection.
+    virtual bool IsWifiConnection() const = 0;
+    // Returns the SSID of the connected Wi-Fi network, if any.
+    virtual std::string GetWiFiSSID() const = 0;
+  };
+
   CaptivePortalBlockingPage(content::WebContents* web_contents,
                             const GURL& request_url,
                             const GURL& login_url,
@@ -37,13 +48,7 @@
   // SecurityInterstitialPage method:
   const void* GetTypeForTesting() const override;
 
-  void SetWiFiConnectionForTesting(bool is_wifi_connection) {
-    is_wifi_connection_ = is_wifi_connection;
-  }
-
-  void SetWiFiSSIDForTesting(const std::string& wifi_ssid) {
-    wifi_ssid_ = wifi_ssid;
-  }
+  void SetDelegateForTesting(Delegate* delegate) { delegate_.reset(delegate); }
 
  protected:
   // SecurityInterstitialPage methods:
@@ -57,11 +62,7 @@
  private:
   // URL of the login page, opened when the user clicks the "Connect" button.
   GURL login_url_;
-  // True if on a Wi-Fi connection.
-  bool is_wifi_connection_;
-  // SSID of the connected network if the connection is a Wi-Fi connection.
-  std::string wifi_ssid_;
-
+  scoped_ptr<Delegate> delegate_;
   base::Callback<void(bool)> callback_;
 
   DISALLOW_COPY_AND_ASSIGN(CaptivePortalBlockingPage);
diff --git a/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc b/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc
index 857d469..2e6b6cd 100644
--- a/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc
+++ b/chrome/browser/ssl/captive_portal_blocking_page_browsertest.cc
@@ -64,6 +64,22 @@
 
 }  // namespace
 
+class FakeConnectionInfoDelegate : public CaptivePortalBlockingPage::Delegate {
+ public:
+  FakeConnectionInfoDelegate(bool is_wifi_connection, std::string wifi_ssid)
+      : is_wifi_connection_(is_wifi_connection), wifi_ssid_(wifi_ssid) {}
+  ~FakeConnectionInfoDelegate() override {}
+
+  bool IsWifiConnection() const override { return is_wifi_connection_; }
+  std::string GetWiFiSSID() const override { return wifi_ssid_; }
+
+ private:
+  const bool is_wifi_connection_;
+  const std::string wifi_ssid_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeConnectionInfoDelegate);
+};
+
 class CaptivePortalBlockingPageTest : public InProcessBrowserTest {
  public:
   CaptivePortalBlockingPageTest() {}
@@ -98,11 +114,13 @@
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   DCHECK(contents);
+  // Delegate is owned by the blocking page.
+  FakeConnectionInfoDelegate* delegate =
+      new FakeConnectionInfoDelegate(is_wifi_connection, wifi_ssid);
   // Blocking page is owned by the interstitial.
   CaptivePortalBlockingPage* blocking_page = new CaptivePortalBlockingPage(
       contents, GURL(kBrokenSSL), login_url, base::Callback<void(bool)>());
-  blocking_page->SetWiFiConnectionForTesting(is_wifi_connection);
-  blocking_page->SetWiFiSSIDForTesting(wifi_ssid);
+  blocking_page->SetDelegateForTesting(delegate);
   blocking_page->Show();
 
   WaitForInterstitialAttach(contents);
@@ -140,9 +158,16 @@
 // captive portal interstitial should be displayed.
 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest,
                        WiredNetwork_LoginURL) {
-  TestInterstitial(false, kWiFiSSID, GURL("http://captive.portal/landing_url"),
+  TestInterstitial(false, "", GURL("http://captive.portal/landing_url"),
                    EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_YES);
+}
 
+// Same as above, but SSID is available, so the connection should be assumed to
+// be Wi-Fi.
+IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest,
+                       WiredNetwork_LoginURL_With_SSID) {
+  TestInterstitial(false, kWiFiSSID, GURL("http://captive.portal/landing_url"),
+                   EXPECT_WIFI_YES, EXPECT_WIFI_SSID_YES, EXPECT_LOGIN_URL_YES);
 }
 
 // Same as above, expect the login URL is the same as the captive portal ping
@@ -151,8 +176,17 @@
 IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest,
                        WiredNetwork_NoLoginURL) {
   const GURL kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL);
-  TestInterstitial(false, kWiFiSSID, kLandingUrl,
-                   EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_NO);
+  TestInterstitial(false, "", kLandingUrl, EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO,
+                   EXPECT_LOGIN_URL_NO);
+}
+
+// Same as above, but SSID is available, so the connection should be assumed to
+// be Wi-Fi.
+IN_PROC_BROWSER_TEST_F(CaptivePortalBlockingPageTest,
+                       WiredNetwork_NoLoginURL_With_SSID) {
+  const GURL kLandingUrl(captive_portal::CaptivePortalDetector::kDefaultURL);
+  TestInterstitial(false, kWiFiSSID, kLandingUrl, EXPECT_WIFI_YES,
+                   EXPECT_WIFI_SSID_YES, EXPECT_LOGIN_URL_NO);
 }
 
 // If the connection is a Wi-Fi connection, the Wi-Fi version of the captive
@@ -209,7 +243,6 @@
       base::StringPrintf("http://%s/landing_url", kHostname);
   GURL landing_url(landing_url_spec);
 
-  TestInterstitial(false, kWiFiSSID, landing_url,
-                   EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO, EXPECT_LOGIN_URL_YES,
-                   kHostnameJSUnicode);
+  TestInterstitial(false, "", landing_url, EXPECT_WIFI_NO, EXPECT_WIFI_SSID_NO,
+                   EXPECT_LOGIN_URL_YES, kHostnameJSUnicode);
 }
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index 214c0353..7ef848d01 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -87,6 +87,9 @@
   END_OF_SSL_EXPIRATION_AND_DECISION,
 };
 
+// Rappor prefix
+const char kSSLRapporPrefix[] = "ssl";
+
 void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed,
                                        bool proceed,
                                        bool overridable) {
@@ -233,12 +236,19 @@
       IsErrorDueToBadClock(base::Time::NowFromSystemTime(), cert_error_) ?
       SSL_REASON_BAD_CLOCK : SSL_REASON_SSL;
 
+  // We collapse the Rappor metric name to just "ssl" so we don't leak
+  // the "overridable" bit.  We skip Rappor altogether for bad clocks.
   // This must be done after calculating |interstitial_reason_| above.
-  uma_helper_.reset(new SecurityInterstitialUmaHelper(
-      web_contents, request_url, GetHistogramPrefix(), GetSamplingEventName()));
-  uma_helper_->RecordUserDecision(SecurityInterstitialUmaHelper::SHOW);
-  uma_helper_->RecordUserInteraction(
-      SecurityInterstitialUmaHelper::TOTAL_VISITS);
+  metrics_helper_.reset(new SecurityInterstitialMetricsHelper(
+      web_contents, request_url, GetUmaHistogramPrefix(), kSSLRapporPrefix,
+      (interstitial_reason_ == SSL_REASON_BAD_CLOCK
+           ? SecurityInterstitialMetricsHelper::SKIP_RAPPOR
+           : SecurityInterstitialMetricsHelper::REPORT_RAPPOR),
+      GetSamplingEventName()));
+
+  metrics_helper_->RecordUserDecision(SecurityInterstitialMetricsHelper::SHOW);
+  metrics_helper_->RecordUserInteraction(
+      SecurityInterstitialMetricsHelper::TOTAL_VISITS);
 
   ssl_error_classification_.reset(new SSLErrorClassification(
       web_contents,
@@ -267,8 +277,8 @@
   if (!callback_.is_null()) {
     // The page is closed without the user having chosen what to do, default to
     // deny.
-    uma_helper_->RecordUserDecision(
-        SecurityInterstitialUmaHelper::DONT_PROCEED);
+    metrics_helper_->RecordUserDecision(
+        SecurityInterstitialMetricsHelper::DONT_PROCEED);
     RecordSSLExpirationPageEventState(
         expired_but_previously_allowed_, false, overridable_);
     NotifyDenyCertificate();
@@ -451,20 +461,20 @@
       break;
     }
     case CMD_MORE: {
-      uma_helper_->RecordUserInteraction(
-          SecurityInterstitialUmaHelper::SHOW_ADVANCED);
+      metrics_helper_->RecordUserInteraction(
+          SecurityInterstitialMetricsHelper::SHOW_ADVANCED);
       break;
     }
     case CMD_RELOAD: {
-      uma_helper_->RecordUserInteraction(
-          SecurityInterstitialUmaHelper::RELOAD);
+      metrics_helper_->RecordUserInteraction(
+          SecurityInterstitialMetricsHelper::RELOAD);
       // The interstitial can't refresh itself.
       web_contents()->GetController().Reload(true);
       break;
     }
     case CMD_HELP: {
-      uma_helper_->RecordUserInteraction(
-          SecurityInterstitialUmaHelper::SHOW_LEARN_MORE);
+      metrics_helper_->RecordUserInteraction(
+          SecurityInterstitialMetricsHelper::SHOW_LEARN_MORE);
       content::NavigationController::LoadURLParams help_page_params(
           google_util::AppendGoogleLocaleParam(
               GURL(kHelpURL), g_browser_process->GetApplicationLocale()));
@@ -472,8 +482,8 @@
       break;
     }
     case CMD_CLOCK: {
-      uma_helper_->RecordUserInteraction(
-          SecurityInterstitialUmaHelper::OPEN_TIME_SETTINGS);
+      metrics_helper_->RecordUserInteraction(
+          SecurityInterstitialMetricsHelper::OPEN_TIME_SETTINGS);
       LaunchDateAndTimeSettings();
       break;
     }
@@ -492,7 +502,8 @@
 }
 
 void SSLBlockingPage::OnProceed() {
-  uma_helper_->RecordUserDecision(SecurityInterstitialUmaHelper::PROCEED);
+  metrics_helper_->RecordUserDecision(
+      SecurityInterstitialMetricsHelper::PROCEED);
   RecordSSLExpirationPageEventState(
       expired_but_previously_allowed_, true, overridable_);
   // Accepting the certificate resumes the loading of the page.
@@ -500,7 +511,8 @@
 }
 
 void SSLBlockingPage::OnDontProceed() {
-  uma_helper_->RecordUserDecision(SecurityInterstitialUmaHelper::DONT_PROCEED);
+  metrics_helper_->RecordUserDecision(
+      SecurityInterstitialMetricsHelper::DONT_PROCEED);
   RecordSSLExpirationPageEventState(
       expired_but_previously_allowed_, false, overridable_);
   NotifyDenyCertificate();
@@ -524,7 +536,7 @@
   callback_.Reset();
 }
 
-std::string SSLBlockingPage::GetHistogramPrefix() const {
+std::string SSLBlockingPage::GetUmaHistogramPrefix() const {
   switch (interstitial_reason_) {
     case SSL_REASON_SSL:
       if (overridable_)
diff --git a/chrome/browser/ssl/ssl_blocking_page.h b/chrome/browser/ssl/ssl_blocking_page.h
index 1a6b3da..dac5ab41 100644
--- a/chrome/browser/ssl/ssl_blocking_page.h
+++ b/chrome/browser/ssl/ssl_blocking_page.h
@@ -12,8 +12,8 @@
 #include "base/strings/string16.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/time/time.h"
+#include "chrome/browser/interstitials/security_interstitial_metrics_helper.h"
 #include "chrome/browser/interstitials/security_interstitial_page.h"
-#include "chrome/browser/interstitials/security_interstitial_uma_helper.h"
 #include "net/ssl/ssl_info.h"
 #include "url/gurl.h"
 
@@ -95,7 +95,7 @@
   void NotifyDenyCertificate();
   void NotifyAllowCertificate();
 
-  std::string GetHistogramPrefix() const;
+  std::string GetUmaHistogramPrefix() const;
   std::string GetSamplingEventName() const;
 
   base::Callback<void(bool)> callback_;
@@ -117,9 +117,9 @@
   // expired?
   const bool expired_but_previously_allowed_;
   scoped_ptr<SSLErrorClassification> ssl_error_classification_;
-  scoped_ptr<SecurityInterstitialUmaHelper> uma_helper_;
+  scoped_ptr<SecurityInterstitialMetricsHelper> metrics_helper_;
 
-  // Which type of Safe Browsing interstitial this is.
+  // Which type of interstitial this is.
   enum SSLInterstitialReason {
     SSL_REASON_SSL,
     SSL_REASON_BAD_CLOCK
diff --git a/chrome/browser/sync/glue/synced_tab_delegate_android.h b/chrome/browser/sync/glue/synced_tab_delegate_android.h
index cd485ea3..15168727 100644
--- a/chrome/browser/sync/glue/synced_tab_delegate_android.h
+++ b/chrome/browser/sync/glue/synced_tab_delegate_android.h
@@ -22,31 +22,31 @@
 class SyncedTabDelegateAndroid : public browser_sync::SyncedTabDelegate {
  public:
   explicit SyncedTabDelegateAndroid(TabAndroid* owning_tab_);
-  virtual ~SyncedTabDelegateAndroid();
+  ~SyncedTabDelegateAndroid() override;
 
   // Methods from SyncedTabDelegate.
-  virtual SessionID::id_type GetWindowId() const override;
-  virtual SessionID::id_type GetSessionId() const override;
-  virtual bool IsBeingDestroyed() const override;
-  virtual Profile* profile() const override;
-  virtual std::string GetExtensionAppId() const override;
-  virtual int GetCurrentEntryIndex() const override;
-  virtual int GetEntryCount() const override;
-  virtual int GetPendingEntryIndex() const override;
-  virtual content::NavigationEntry* GetPendingEntry() const override;
-  virtual content::NavigationEntry* GetEntryAtIndex(int i) const override;
-  virtual content::NavigationEntry* GetActiveEntry() const override;
-  virtual bool IsPinned() const override;
-  virtual bool HasWebContents() const override;
-  virtual content::WebContents* GetWebContents() const override;
-  virtual int GetSyncId() const override;
-  virtual void SetSyncId(int sync_id) override;
+  SessionID::id_type GetWindowId() const override;
+  SessionID::id_type GetSessionId() const override;
+  bool IsBeingDestroyed() const override;
+  Profile* profile() const override;
+  std::string GetExtensionAppId() const override;
+  int GetCurrentEntryIndex() const override;
+  int GetEntryCount() const override;
+  int GetPendingEntryIndex() const override;
+  content::NavigationEntry* GetPendingEntry() const override;
+  content::NavigationEntry* GetEntryAtIndex(int i) const override;
+  content::NavigationEntry* GetActiveEntry() const override;
+  bool IsPinned() const override;
+  bool HasWebContents() const override;
+  content::WebContents* GetWebContents() const override;
+  int GetSyncId() const override;
+  void SetSyncId(int sync_id) override;
 
   // Supervised user related methods.
 
-  virtual bool ProfileIsSupervised() const override;
-  virtual const std::vector<const content::NavigationEntry*>*
-      GetBlockedNavigations() const override;
+  bool ProfileIsSupervised() const override;
+  const std::vector<const content::NavigationEntry*>* GetBlockedNavigations()
+      const override;
 
   // Set the web contents for this tab. Also creates
   // TabContentsSyncedTabDelegate for this tab.
diff --git a/chrome/browser/sync/glue/synced_window_delegate_android.h b/chrome/browser/sync/glue/synced_window_delegate_android.h
index 13b717f9..0c3d1f48 100644
--- a/chrome/browser/sync/glue/synced_window_delegate_android.h
+++ b/chrome/browser/sync/glue/synced_window_delegate_android.h
@@ -18,21 +18,21 @@
 class SyncedWindowDelegateAndroid : public browser_sync::SyncedWindowDelegate {
  public:
   explicit SyncedWindowDelegateAndroid(TabModel* tab_model);
-  virtual ~SyncedWindowDelegateAndroid();
+  ~SyncedWindowDelegateAndroid() override;
 
   // browser_sync::SyncedWindowDelegate implementation.
 
-  virtual bool HasWindow() const override;
-  virtual SessionID::id_type GetSessionId() const override;
-  virtual int GetTabCount() const override;
-  virtual int GetActiveIndex() const override;
-  virtual bool IsApp() const override;
-  virtual bool IsTypeTabbed() const override;
-  virtual bool IsTypePopup() const override;
-  virtual bool IsTabPinned(const SyncedTabDelegate* tab) const override;
-  virtual SyncedTabDelegate* GetTabAt(int index) const override;
-  virtual SessionID::id_type GetTabIdAt(int index) const override;
-  virtual bool IsSessionRestoreInProgress() const override;
+  bool HasWindow() const override;
+  SessionID::id_type GetSessionId() const override;
+  int GetTabCount() const override;
+  int GetActiveIndex() const override;
+  bool IsApp() const override;
+  bool IsTypeTabbed() const override;
+  bool IsTypePopup() const override;
+  bool IsTabPinned(const SyncedTabDelegate* tab) const override;
+  SyncedTabDelegate* GetTabAt(int index) const override;
+  SessionID::id_type GetTabIdAt(int index) const override;
+  bool IsSessionRestoreInProgress() const override;
 
  private:
   TabModel* tab_model_;
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 721c174..cb305b5 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -62,6 +62,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/invalidation/invalidation_service.h"
 #include "components/invalidation/profile_invalidation_provider.h"
@@ -1153,6 +1154,9 @@
 
   profile()->GetPrefs()->SetBoolean(prefs::kInvalidationServiceUseGCMChannel,
                                     experiments.gcm_invalidations_enabled);
+  profile()->GetPrefs()->SetBoolean(
+      autofill::prefs::kAutofillWalletSyncExperimentEnabled,
+      experiments.wallet_sync_enabled);
 
   if (experiments.enhanced_bookmarks_enabled) {
     profile_->GetPrefs()->SetString(
diff --git a/chrome/browser/sync/profile_sync_service_android.h b/chrome/browser/sync/profile_sync_service_android.h
index 703c69e..2b2f34e 100644
--- a/chrome/browser/sync/profile_sync_service_android.h
+++ b/chrome/browser/sync/profile_sync_service_android.h
@@ -187,7 +187,7 @@
   jint GetAuthError(JNIEnv* env, jobject obj);
 
   // ProfileSyncServiceObserver:
-  virtual void OnStateChanged() override;
+  void OnStateChanged() override;
 
   // Returns a timestamp for when a sync was last executed. The return value is
   // the internal value of base::Time.
@@ -217,7 +217,7 @@
                    int64,
                    syncer::ObjectIdLessThan> ObjectIdVersionMap;
 
-  virtual ~ProfileSyncServiceAndroid();
+  ~ProfileSyncServiceAndroid() override;
   // Remove observers to profile sync service.
   void RemoveObserver();
 
diff --git a/chrome/browser/sync/profile_sync_service_android_unittest.cc b/chrome/browser/sync/profile_sync_service_android_unittest.cc
index ef5d248..14c6d0b 100644
--- a/chrome/browser/sync/profile_sync_service_android_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_android_unittest.cc
@@ -37,9 +37,9 @@
  public:
   ProfileSyncServiceAndroidTest()
       : command_line_(base::CommandLine::NO_PROGRAM) {}
-  virtual ~ProfileSyncServiceAndroidTest() {}
+  ~ProfileSyncServiceAndroidTest() override {}
 
-  virtual void SetUp() override {
+  void SetUp() override {
     ProfileOAuth2TokenService* token_service =
         ProfileOAuth2TokenServiceFactory::GetForProfile(&profile_);
     ProfileSyncComponentsFactory* factory =
diff --git a/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
index 4c2b4731..84ffaf19e 100644
--- a/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/conflict_resolver_unittest.cc
@@ -70,9 +70,10 @@
 
     context_.reset(new SyncEngineContext(fake_drive_service.Pass(),
                                          drive_uploader.Pass(),
-                                         nullptr,
+                                         nullptr /* task_logger */,
                                          base::ThreadTaskRunnerHandle::Get(),
-                                         base::ThreadTaskRunnerHandle::Get()));
+                                         base::ThreadTaskRunnerHandle::Get(),
+                                         nullptr /* worker_pool */));
     context_->SetRemoteChangeProcessor(remote_change_processor_.get());
 
     RegisterSyncableFileSystem();
@@ -80,7 +81,8 @@
     sync_task_manager_.reset(new SyncTaskManager(
         base::WeakPtr<SyncTaskManager::Client>(),
         10 /* maximum_background_task */,
-        base::ThreadTaskRunnerHandle::Get()));
+        base::ThreadTaskRunnerHandle::Get(),
+        nullptr /* worker_pool */));
     sync_task_manager_->Initialize(SYNC_STATUS_OK);
   }
 
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc
index f98da48..ce49be9 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_backend_sync_unittest.cc
@@ -118,6 +118,7 @@
         new SyncEngine(base::ThreadTaskRunnerHandle::Get(),  // ui_task_runner
                        worker_task_runner_.get(),
                        drive_task_runner.get(),
+                       worker_pool.get(),
                        base_dir_.path(),
                        nullptr,  // task_logger
                        nullptr,  // notification_manager
diff --git a/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc
index 479b92c..ee4fd8d 100644
--- a/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/list_changes_task_unittest.cc
@@ -59,14 +59,16 @@
     sync_task_manager_.reset(new SyncTaskManager(
         base::WeakPtr<SyncTaskManager::Client>(),
         10 /* maximum_background_task */,
-        base::ThreadTaskRunnerHandle::Get()));
+        base::ThreadTaskRunnerHandle::Get(),
+        nullptr /* worker_pool */));
     sync_task_manager_->Initialize(SYNC_STATUS_OK);
 
     context_.reset(new SyncEngineContext(fake_drive_service.Pass(),
                                          drive_uploader.Pass(),
-                                         nullptr,
+                                         nullptr /* task_logger */,
                                          base::ThreadTaskRunnerHandle::Get(),
-                                         base::ThreadTaskRunnerHandle::Get()));
+                                         base::ThreadTaskRunnerHandle::Get(),
+                                         nullptr /* worker_pool */));
 
     SetUpRemoteFolders();
 
diff --git a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc
index 9131454..9364d1c 100644
--- a/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer_unittest.cc
@@ -71,9 +71,10 @@
 
     context_.reset(new SyncEngineContext(fake_drive_service.Pass(),
                                          drive_uploader.Pass(),
-                                         nullptr,
+                                         nullptr /* task_logger */,
                                          base::ThreadTaskRunnerHandle::Get(),
-                                         base::ThreadTaskRunnerHandle::Get()));
+                                         base::ThreadTaskRunnerHandle::Get(),
+                                         nullptr /* worker_pool */));
     context_->SetRemoteChangeProcessor(remote_change_processor_.get());
 
     RegisterSyncableFileSystem();
@@ -81,7 +82,8 @@
     sync_task_manager_.reset(new SyncTaskManager(
         base::WeakPtr<SyncTaskManager::Client>(),
         10 /* maximum_background_task */,
-        base::ThreadTaskRunnerHandle::Get()));
+        base::ThreadTaskRunnerHandle::Get(),
+        nullptr /* worker_pool */));
     sync_task_manager_->Initialize(SYNC_STATUS_OK);
   }
 
diff --git a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
index 2b87fd0..1de4b37 100644
--- a/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/register_app_task_unittest.cc
@@ -60,9 +60,10 @@
 
     context_.reset(new SyncEngineContext(fake_drive_service.Pass(),
                                          drive_uploader.Pass(),
-                                         nullptr,
+                                         nullptr /* task_logger */,
                                          base::ThreadTaskRunnerHandle::Get(),
-                                         base::ThreadTaskRunnerHandle::Get()));
+                                         base::ThreadTaskRunnerHandle::Get(),
+                                         nullptr /* worker_pool */));
 
     ASSERT_EQ(google_apis::HTTP_CREATED,
               fake_drive_service_helper_->AddOrphanedFolder(
diff --git a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc
index 22cbbfdd..0541e95c 100644
--- a/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer_unittest.cc
@@ -71,9 +71,10 @@
 
     context_.reset(new SyncEngineContext(fake_drive_service.Pass(),
                                          drive_uploader.Pass(),
-                                         nullptr,
+                                         nullptr /* task_logger */,
                                          base::ThreadTaskRunnerHandle::Get(),
-                                         base::ThreadTaskRunnerHandle::Get()));
+                                         base::ThreadTaskRunnerHandle::Get(),
+                                         nullptr /* worker_pool*/));
     context_->SetRemoteChangeProcessor(remote_change_processor_.get());
 
     RegisterSyncableFileSystem();
@@ -81,7 +82,8 @@
     sync_task_manager_.reset(new SyncTaskManager(
         base::WeakPtr<SyncTaskManager::Client>(),
         10 /* max_parallel_task */,
-        base::ThreadTaskRunnerHandle::Get()));
+        base::ThreadTaskRunnerHandle::Get(),
+        nullptr /* worker_pool */));
     sync_task_manager_->Initialize(SYNC_STATUS_OK);
   }
 
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
index af03581..890cfed 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.cc
@@ -164,25 +164,6 @@
   callback.Run(status);
 }
 
-template <typename T>
-void DeleteSoonHelper(scoped_ptr<T>) {}
-
-template <typename T>
-void DeleteSoon(const tracked_objects::Location& from_here,
-                base::TaskRunner* task_runner,
-                scoped_ptr<T> obj) {
-  if (!obj)
-    return;
-
-  T* obj_ptr = obj.get();
-  base::Closure deleter =
-      base::Bind(&DeleteSoonHelper<T>, base::Passed(&obj));
-  if (!task_runner->PostTask(from_here, deleter)) {
-    obj_ptr->DetachFromSequence();
-    deleter.Run();
-  }
-}
-
 }  // namespace
 
 scoped_ptr<SyncEngine> SyncEngine::CreateForBrowserContext(
@@ -218,6 +199,7 @@
       new SyncEngine(ui_task_runner.get(),
                      worker_task_runner.get(),
                      drive_task_runner.get(),
+                     worker_pool.get(),
                      GetSyncFileSystemDir(context->GetPath()),
                      task_logger,
                      notification_manager,
@@ -256,11 +238,10 @@
   if (drive_service_)
     drive_service_->RemoveObserver(this);
 
-  DeleteSoon(FROM_HERE, worker_task_runner_.get(), sync_worker_.Pass());
-  DeleteSoon(FROM_HERE, worker_task_runner_.get(), worker_observer_.Pass());
-  DeleteSoon(FROM_HERE,
-             worker_task_runner_.get(),
-             remote_change_processor_on_worker_.Pass());
+  worker_task_runner_->DeleteSoon(FROM_HERE, sync_worker_.release());
+  worker_task_runner_->DeleteSoon(FROM_HERE, worker_observer_.release());
+  worker_task_runner_->DeleteSoon(FROM_HERE,
+                                  remote_change_processor_on_worker_.release());
 
   drive_service_wrapper_.reset();
   drive_service_.reset();
@@ -326,7 +307,8 @@
                             drive_uploader_on_worker.Pass(),
                             task_logger_,
                             ui_task_runner_.get(),
-                            worker_task_runner_.get()));
+                            worker_task_runner_.get(),
+                            worker_pool_.get()));
 
   worker_observer_.reset(new WorkerObserver(ui_task_runner_.get(),
                                             weak_ptr_factory_.GetWeakPtr()));
@@ -736,6 +718,7 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
     const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner,
     const scoped_refptr<base::SequencedTaskRunner>& drive_task_runner,
+    const scoped_refptr<base::SequencedWorkerPool>& worker_pool,
     const base::FilePath& sync_file_system_dir,
     TaskLogger* task_logger,
     drive::DriveNotificationManager* notification_manager,
@@ -748,6 +731,7 @@
     : ui_task_runner_(ui_task_runner),
       worker_task_runner_(worker_task_runner),
       drive_task_runner_(drive_task_runner),
+      worker_pool_(worker_pool),
       sync_file_system_dir_(sync_file_system_dir),
       task_logger_(task_logger),
       notification_manager_(notification_manager),
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.h b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
index fc5388e..81315db 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
@@ -159,6 +159,7 @@
   SyncEngine(const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
              const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner,
              const scoped_refptr<base::SequencedTaskRunner>& drive_task_runner,
+             const scoped_refptr<base::SequencedWorkerPool>& worker_pool,
              const base::FilePath& sync_file_system_dir,
              TaskLogger* task_logger,
              drive::DriveNotificationManager* notification_manager,
@@ -184,6 +185,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
   scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
   scoped_refptr<base::SequencedTaskRunner> drive_task_runner_;
+  scoped_refptr<base::SequencedWorkerPool> worker_pool_;
 
   const base::FilePath sync_file_system_dir_;
   TaskLogger* task_logger_;
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_context.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_context.cc
index 867075e..e487003 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine_context.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_context.cc
@@ -23,14 +23,16 @@
     scoped_ptr<drive::DriveUploaderInterface> drive_uploader,
     TaskLogger* task_logger,
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
-    const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner)
+    const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner,
+    const scoped_refptr<base::SequencedWorkerPool>& worker_pool)
     : drive_service_(drive_service.Pass()),
       drive_uploader_(drive_uploader.Pass()),
       task_logger_(task_logger ? task_logger->AsWeakPtr()
                                : base::WeakPtr<TaskLogger>()),
       remote_change_processor_(nullptr),
       ui_task_runner_(ui_task_runner),
-      worker_task_runner_(worker_task_runner) {
+      worker_task_runner_(worker_task_runner),
+      worker_pool_(worker_pool) {
   sequence_checker_.DetachFromSequence();
 }
 
@@ -78,6 +80,11 @@
   return worker_task_runner_.get();
 }
 
+base::SequencedWorkerPool* SyncEngineContext::GetWorkerPool() {
+  DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+  return worker_pool_.get();
+}
+
 void SyncEngineContext::SetMetadataDatabase(
     scoped_ptr<MetadataDatabase> metadata_database) {
   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_context.h b/chrome/browser/sync_file_system/drive_backend/sync_engine_context.h
index ee1d4cd..8aaaf15 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine_context.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_context.h
@@ -37,7 +37,8 @@
       scoped_ptr<drive::DriveUploaderInterface> drive_uploader,
       TaskLogger* task_logger,
       const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
-      const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner);
+      const scoped_refptr<base::SequencedTaskRunner>& worker_task_runner,
+      const scoped_refptr<base::SequencedWorkerPool>& worker_pool);
   ~SyncEngineContext();
 
   void SetMetadataDatabase(scoped_ptr<MetadataDatabase> metadata_database);
@@ -51,6 +52,7 @@
   RemoteChangeProcessor* GetRemoteChangeProcessor();
   base::SingleThreadTaskRunner* GetUITaskRunner();
   base::SequencedTaskRunner* GetWorkerTaskRunner();
+  base::SequencedWorkerPool* GetWorkerPool();
 
   scoped_ptr<MetadataDatabase> PassMetadataDatabase();
 
@@ -67,6 +69,7 @@
   scoped_ptr<MetadataDatabase> metadata_database_;
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
   scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
+  scoped_refptr<base::SequencedWorkerPool> worker_pool_;
 
   base::SequenceChecker sequence_checker_;
 
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc
index 2ff8196..06e3ba1 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_initializer_unittest.cc
@@ -54,14 +54,16 @@
     sync_context_.reset(new SyncEngineContext(
         fake_drive_service.Pass(),
         scoped_ptr<drive::DriveUploaderInterface>(),
-        nullptr,
+        nullptr /* task_logger */,
         base::ThreadTaskRunnerHandle::Get(),
-        base::ThreadTaskRunnerHandle::Get()));
+        base::ThreadTaskRunnerHandle::Get(),
+        nullptr /* worker_pool */));
 
     sync_task_manager_.reset(new SyncTaskManager(
         base::WeakPtr<SyncTaskManager::Client>(),
         1 /* maximum_parallel_task */,
-        base::ThreadTaskRunnerHandle::Get()));
+        base::ThreadTaskRunnerHandle::Get(),
+        nullptr /* worker_pool */));
     sync_task_manager_->Initialize(SYNC_STATUS_OK);
   }
 
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc
index 0519881..8bab99c6 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine_unittest.cc
@@ -49,6 +49,7 @@
         ui_task_runner.get(),
         worker_task_runner_.get(),
         nullptr /* drive_task_runner */,
+        worker_pool_.get(),
         profile_dir_.path(),
         nullptr /* task_logger */,
         nullptr /* notification_manager */,
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_task_manager.cc b/chrome/browser/sync_file_system/drive_backend/sync_task_manager.cc
index d6ecbae..16e1f9bf 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_task_manager.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_task_manager.cc
@@ -55,12 +55,14 @@
 SyncTaskManager::SyncTaskManager(
     base::WeakPtr<Client> client,
     size_t maximum_background_task,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    const scoped_refptr<base::SequencedWorkerPool>& worker_pool)
     : client_(client),
       maximum_background_task_(maximum_background_task),
       pending_task_seq_(0),
       task_token_seq_(SyncTaskToken::kMinimumBackgroundTaskTokenID),
       task_runner_(task_runner),
+      worker_pool_(worker_pool),
       weak_ptr_factory_(this) {
 }
 
@@ -204,6 +206,10 @@
   sequence_checker_.DetachFromSequence();
 }
 
+bool SyncTaskManager::ShouldTrackTaskToken() const {
+  return !worker_pool_ || !worker_pool_->IsShutdownInProgress();
+}
+
 void SyncTaskManager::NotifyTaskDoneBody(scoped_ptr<SyncTaskToken> token,
                                          SyncStatusCode status) {
   DCHECK(sequence_checker_.CalledOnValidSequencedThread());
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_task_manager.h b/chrome/browser/sync_file_system/drive_backend/sync_task_manager.h
index de03d577..656e646 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_task_manager.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_task_manager.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/sync_file_system/drive_backend/task_dependency_manager.h"
 #include "chrome/browser/sync_file_system/sync_callbacks.h"
 #include "chrome/browser/sync_file_system/sync_status_code.h"
@@ -70,7 +71,8 @@
   // If |maximum_background_tasks| is zero, all task runs as foreground task.
   SyncTaskManager(base::WeakPtr<Client> client,
                   size_t maximum_background_task,
-                  const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+                  const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+                  const scoped_refptr<base::SequencedWorkerPool>& worker_pool);
   virtual ~SyncTaskManager();
 
   // This needs to be called to start task scheduling.
@@ -120,6 +122,7 @@
   bool IsRunningTask(int64 task_token_id) const;
 
   void DetachFromSequence();
+  bool ShouldTrackTaskToken() const;
 
  private:
   struct PendingTask {
@@ -195,6 +198,7 @@
   TaskDependencyManager dependency_manager_;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  scoped_refptr<base::SequencedWorkerPool> worker_pool_;
   base::SequenceChecker sequence_checker_;
 
   base::WeakPtrFactory<SyncTaskManager> weak_ptr_factory_;;
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_task_manager_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_task_manager_unittest.cc
index cd24f6e..cf01a067 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_task_manager_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_task_manager_unittest.cc
@@ -62,7 +62,8 @@
         last_operation_status_(SYNC_STATUS_OK) {
     task_manager_.reset(new SyncTaskManager(
         AsWeakPtr(), maximum_background_task,
-        base::ThreadTaskRunnerHandle::Get()));
+        base::ThreadTaskRunnerHandle::Get(),
+        nullptr /* worker_pool */));
     task_manager_->Initialize(SYNC_STATUS_OK);
     base::MessageLoop::current()->RunUntilIdle();
     maybe_schedule_next_task_count_ = 0;
@@ -392,7 +393,8 @@
   {
     SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
                                  0 /* maximum_background_task */,
-                                 base::ThreadTaskRunnerHandle::Get());
+                                 base::ThreadTaskRunnerHandle::Get(),
+                                 nullptr /* worker_pool */);
     task_manager.Initialize(SYNC_STATUS_OK);
     message_loop.RunUntilIdle();
     task_manager.ScheduleSyncTask(
@@ -414,7 +416,8 @@
   base::MessageLoop message_loop;
   SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
                                0 /* maximum_background_task */,
-                               base::ThreadTaskRunnerHandle::Get());
+                               base::ThreadTaskRunnerHandle::Get(),
+                               nullptr /* worker_pool */);
   task_manager.Initialize(SYNC_STATUS_OK);
   message_loop.RunUntilIdle();
 
@@ -475,7 +478,8 @@
   base::MessageLoop message_loop;
   SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
                                10 /* maximum_background_task */,
-                               base::ThreadTaskRunnerHandle::Get());
+                               base::ThreadTaskRunnerHandle::Get(),
+                               nullptr /* worker_pool */);
   task_manager.Initialize(SYNC_STATUS_OK);
 
   SyncStatusCode status = SYNC_STATUS_FAILED;
@@ -516,7 +520,8 @@
   base::MessageLoop message_loop;
   SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
                                10 /* maximum_background_task */,
-                               base::ThreadTaskRunnerHandle::Get());
+                               base::ThreadTaskRunnerHandle::Get(),
+                               nullptr /* worker_pool */);
   task_manager.Initialize(SYNC_STATUS_OK);
 
   SyncStatusCode status = SYNC_STATUS_FAILED;
@@ -557,7 +562,8 @@
   base::MessageLoop message_loop;
   SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
                                2 /* maximum_background_task */,
-                               base::ThreadTaskRunnerHandle::Get());
+                               base::ThreadTaskRunnerHandle::Get(),
+                               nullptr /* worker_pool */);
   task_manager.Initialize(SYNC_STATUS_OK);
 
   SyncStatusCode status = SYNC_STATUS_FAILED;
@@ -598,7 +604,8 @@
   base::MessageLoop message_loop;
   SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
                                10 /* maximum_background_task */,
-                               base::ThreadTaskRunnerHandle::Get());
+                               base::ThreadTaskRunnerHandle::Get(),
+                               nullptr /* worker_pool */);
   task_manager.Initialize(SYNC_STATUS_OK);
 
   SyncStatusCode status1 = SYNC_STATUS_FAILED;
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc b/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc
index 590e9a80..b4d58bf8 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_task_token.cc
@@ -70,6 +70,9 @@
   // dropped by a task without returning.
   if (task_runner_.get() && task_runner_->RunsTasksOnCurrentThread() &&
       manager_ && manager_->IsRunningTask(token_id_)) {
+    if (!manager_->ShouldTrackTaskToken())
+      return;
+
     NOTREACHED()
         << "Unexpected TaskToken deletion from: " << location_.ToString();
 
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_worker.cc b/chrome/browser/sync_file_system/drive_backend/sync_worker.cc
index 9ae8560..e73ad16 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_worker.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_worker.cc
@@ -73,7 +73,8 @@
 
   task_manager_.reset(new SyncTaskManager(
       weak_ptr_factory_.GetWeakPtr(), 0 /* maximum_background_task */,
-      context_->GetWorkerTaskRunner()));
+      context_->GetWorkerTaskRunner(),
+      context_->GetWorkerPool()));
   task_manager_->Initialize(SYNC_STATUS_OK);
 
   PostInitializeTask();
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc b/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc
index 8c2d173..7240de9 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/sync_worker_unittest.cc
@@ -113,7 +113,8 @@
             nullptr /* drive_uploader */,
             nullptr /* task_logger */,
             base::ThreadTaskRunnerHandle::Get() /* ui_task_runner */,
-            base::ThreadTaskRunnerHandle::Get() /* worker_task_runner */));
+            base::ThreadTaskRunnerHandle::Get() /* worker_task_runner */,
+            nullptr /* worker_pool */));
 
     sync_worker_.reset(new SyncWorker(
         profile_dir_.path(),
diff --git a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
index 69d1fb2..21209e8 100644
--- a/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
+++ b/chrome/browser/sync_file_system/local/syncable_file_operation_runner_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
@@ -131,6 +132,7 @@
     SCOPED_TRACE(testing::Message() << location.ToString());
     EXPECT_EQ(expect, status);
     ++callback_count_;
+    base::MessageLoop::current()->Quit();
   }
 
   bool CreateTempFile(base::FilePath* path) {
@@ -170,13 +172,13 @@
   file_system_.operation_runner()->Truncate(
       URL(kFile), 1,
       ExpectStatus(FROM_HERE, File::FILE_OK));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, callback_count_);
 
   // Read operations are not blocked (and are executed before queued ones).
   file_system_.operation_runner()->FileExists(
       URL(kFile), ExpectStatus(FROM_HERE, File::FILE_ERROR_NOT_FOUND));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, callback_count_);
 
   // End syncing (to enable write).
@@ -184,14 +186,14 @@
   ASSERT_TRUE(sync_status()->IsWritable(URL(kFile)));
 
   ResetCallbackStatus();
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2, callback_count_);
 
   // Now the file must have been created and updated.
   ResetCallbackStatus();
   file_system_.operation_runner()->FileExists(
       URL(kFile), ExpectStatus(FROM_HERE, File::FILE_OK));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, callback_count_);
 }
 
@@ -211,13 +213,13 @@
   file_system_.operation_runner()->Remove(
       URL(kParent), true /* recursive */,
       ExpectStatus(FROM_HERE, File::FILE_OK));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, callback_count_);
 
   // Read operations are not blocked (and are executed before queued ones).
   file_system_.operation_runner()->DirectoryExists(
       URL(kDir), ExpectStatus(FROM_HERE, File::FILE_OK));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().Run();
   EXPECT_EQ(1, callback_count_);
 
   // Writes to unrelated files must succeed as well.
@@ -225,7 +227,7 @@
   file_system_.operation_runner()->CreateDirectory(
       URL(kOther), false /* exclusive */, false /* recursive */,
       ExpectStatus(FROM_HERE, File::FILE_OK));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().Run();
   EXPECT_EQ(1, callback_count_);
 
   // End syncing (to enable write).
@@ -233,7 +235,7 @@
   ASSERT_TRUE(sync_status()->IsWritable(URL(kDir)));
 
   ResetCallbackStatus();
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().Run();
   EXPECT_EQ(2, callback_count_);
 }
 
@@ -259,7 +261,7 @@
       URL("dest-move"),
       storage::FileSystemOperation::OPTION_NONE,
       ExpectStatus(FROM_HERE, File::FILE_OK));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().Run();
   EXPECT_EQ(1, callback_count_);
 
   // Only "dest-copy1" should exist.
@@ -279,13 +281,13 @@
       storage::FileSystemOperation::OPTION_NONE,
       storage::FileSystemOperationRunner::CopyProgressCallback(),
       ExpectStatus(FROM_HERE, File::FILE_OK));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, callback_count_);
 
   // Finish syncing the "dest-copy2" directory to unlock Copy.
   sync_status()->EndSyncing(URL("dest-copy2"));
   ResetCallbackStatus();
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().Run();
   EXPECT_EQ(1, callback_count_);
 
   // Now we should have "dest-copy2".
@@ -295,7 +297,7 @@
   // Finish syncing the kParent to unlock Move.
   sync_status()->EndSyncing(URL(kParent));
   ResetCallbackStatus();
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().Run();
   EXPECT_EQ(1, callback_count_);
 
   // Now we should have "dest-move".
@@ -314,7 +316,7 @@
   file_system_.operation_runner()->Write(
       &url_request_context_,
       URL(kFile), blob.GetBlobDataHandle(), 0, GetWriteCallback(FROM_HERE));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, callback_count_);
 
   sync_status()->EndSyncing(URL(kFile));
@@ -404,7 +406,7 @@
           URL(kFile), 10, ExpectStatus(FROM_HERE, File::FILE_OK));
   file_system_.operation_runner()->Cancel(
       id, ExpectStatus(FROM_HERE, File::FILE_ERROR_INVALID_OPERATION));
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().Run();
   EXPECT_EQ(2, callback_count_);
 }
 
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.cc b/chrome/browser/sync_file_system/sync_file_system_service.cc
index 5f30648..6d345e9 100644
--- a/chrome/browser/sync_file_system/sync_file_system_service.cc
+++ b/chrome/browser/sync_file_system/sync_file_system_service.cc
@@ -494,7 +494,12 @@
 
   // Local side of initialization for the app is done.
   // Continue on initializing the remote side.
-  GetRemoteService(app_origin)->RegisterOrigin(
+  if (!remote_service_) {
+    callback.Run(SYNC_STATUS_ABORT);
+    return;
+  }
+
+  remote_service_->RegisterOrigin(
       app_origin,
       base::Bind(&SyncFileSystemService::DidRegisterOrigin,
                  AsWeakPtr(), app_origin, callback));
@@ -509,8 +514,13 @@
             app_origin.spec().c_str(),
             SyncStatusCodeToString(status));
 
+  if (!remote_service_) {
+    callback.Run(SYNC_STATUS_ABORT);
+    return;
+  }
+
   UMA_HISTOGRAM_ENUMERATION("SyncFileSystem.RegisterOriginResult",
-                            GetRemoteService(app_origin)->GetCurrentState(),
+                            remote_service_->GetCurrentState(),
                             REMOTE_SERVICE_STATE_MAX);
 
   if (status == SYNC_STATUS_FAILED) {
@@ -541,6 +551,11 @@
     return;
   }
 
+  if (!remote_service_) {
+    callback.Run(base::ListValue());
+    return;
+  }
+
   GetRemoteService(origin)->DumpFiles(
       origin,
       base::Bind(
@@ -554,7 +569,8 @@
     const GURL& origin,
     const DumpFilesCallback& callback,
     scoped_ptr<base::ListValue> dump_files) {
-  if (!dump_files || !dump_files->GetSize()) {
+  if (!dump_files || !dump_files->GetSize() ||
+      !local_service_ || !remote_service_) {
     callback.Run(base::ListValue());
     return;
   }
diff --git a/chrome/browser/test_presubmit.py b/chrome/browser/test_presubmit.py
index d37a6b3e..ac0e13b90 100755
--- a/chrome/browser/test_presubmit.py
+++ b/chrome/browser/test_presubmit.py
@@ -804,7 +804,7 @@
     -webkit-margin-before: 10px; (replace with margin-top)
     -webkit-padding-after: 3px; (replace with padding-bottom)""")
 
-  def testCssZeroLengthTerms(self):
+  def testCssZeroWidthLengths(self):
     self.VerifyContentsProducesOutput("""
 @-webkit-keyframe anim {
   0% { /* Ignore key frames */
@@ -836,10 +836,7 @@
 .media-button[state='0']:not(.disabled):hover > .state0.hover {
   -webkit-animation: anim 0s;
   -webkit-animation-duration: anim 0ms;
-  -webkit-transform: scale(0%),
-                     translateX(0deg),
-                     translateY(0rad),
-                     translateZ(0grad);
+  -webkit-transform: scale(0%);
   background-position-x: 0em;
   background-position-y: 0ex;
   border-width: 0em;
@@ -854,15 +851,9 @@
   height: 0cm;
   width: 0in;
 }""", """
-- Make all zero length terms (i.e. 0px) 0 unless inside of hsl() or part of"""
-""" @keyframe.
+- Use "0" for zero-width lengths (i.e. 0px -> 0)
     width: 0px;
-    -webkit-animation: anim 0s;
-    -webkit-animation-duration: anim 0ms;
-    -webkit-transform: scale(0%),
-    translateX(0deg),
-    translateY(0rad),
-    translateZ(0grad);
+    -webkit-transform: scale(0%);
     background-position-x: 0em;
     background-position-y: 0ex;
     border-width: 0em;
diff --git a/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.h b/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.h
index 07e9be1..fa66a0b 100644
--- a/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.h
+++ b/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.h
@@ -30,12 +30,12 @@
       const GURL& source_url,
       const AutofillClient::ResultCallback& callback);
 
-  virtual ~AutofillDialogControllerAndroid();
+  ~AutofillDialogControllerAndroid() override;
 
   // AutofillDialogController implementation:
-  virtual void Show() override;
-  virtual void Hide() override;
-  virtual void TabActivated() override;
+  void Show() override;
+  void Hide() override;
+  void TabActivated() override;
 
   // JNI bindings for Java-side AutofillDialogDelegate:
   void DialogCancel(JNIEnv* env, jobject obj);
diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.h b/chrome/browser/ui/android/autofill/autofill_popup_view_android.h
index d6c7c74..8d4211b 100644
--- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.h
+++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.h
@@ -35,13 +35,13 @@
 
  protected:
   // AutofillPopupView implementation.
-  virtual void Show() override;
-  virtual void Hide() override;
-  virtual void InvalidateRow(size_t row) override;
-  virtual void UpdateBoundsAndRedrawPopup() override;
+  void Show() override;
+  void Hide() override;
+  void InvalidateRow(size_t row) override;
+  void UpdateBoundsAndRedrawPopup() override;
 
  private:
-  virtual ~AutofillPopupViewAndroid();
+  ~AutofillPopupViewAndroid() override;
 
   AutofillPopupController* controller_;  // weak.
 
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
index e155ff6..d4437cba 100644
--- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
+++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h"
 
+#include "chrome/browser/android/resource_mapper.h"
 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "jni/CardUnmaskBridge_jni.h"
@@ -43,7 +44,9 @@
           env, controller_->GetInstructionsMessage());
   java_object_.Reset(Java_CardUnmaskBridge_create(
       env, reinterpret_cast<intptr_t>(this), dialog_title.obj(),
-      instructions.obj(), controller_->ShouldRequestExpirationDate(),
+      instructions.obj(),
+      ResourceMapper::MapFromChromiumId(controller_->GetCvcImageRid()),
+      controller_->ShouldRequestExpirationDate(),
       view_android->GetWindowAndroid()->GetJavaObject().obj()));
 
   Java_CardUnmaskBridge_show(env, java_object_.obj());
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h
index fbed584..1b8570e 100644
--- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h
+++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h
@@ -36,7 +36,7 @@
   static bool Register(JNIEnv* env);
 
  private:
-  virtual ~CardUnmaskPromptViewAndroid();
+  ~CardUnmaskPromptViewAndroid() override;
 
   // The corresponding java object.
   base::android::ScopedJavaGlobalRef<jobject> java_object_;
diff --git a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.h b/chrome/browser/ui/android/autofill/password_generation_popup_view_android.h
index c904870..806efa48 100644
--- a/chrome/browser/ui/android/autofill/password_generation_popup_view_android.h
+++ b/chrome/browser/ui/android/autofill/password_generation_popup_view_android.h
@@ -39,12 +39,12 @@
   virtual ~PasswordGenerationPopupViewAndroid();
 
   // PasswordGenerationPopupView implementation.
-  virtual void Show() override;
-  virtual void Hide() override;
-  virtual gfx::Size GetPreferredSizeOfPasswordView() override;
-  virtual void UpdateBoundsAndRedrawPopup() override;
-  virtual void PasswordSelectionUpdated() override;
-  virtual bool IsPointInPasswordBounds(const gfx::Point& point) override;
+  void Show() override;
+  void Hide() override;
+  gfx::Size GetPreferredSizeOfPasswordView() override;
+  void UpdateBoundsAndRedrawPopup() override;
+  void PasswordSelectionUpdated() override;
+  bool IsPointInPasswordBounds(const gfx::Point& point) override;
 
   // Weak pointer to the controller.
   PasswordGenerationPopupController* controller_;
diff --git a/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h b/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h
index 6a1790e..3296ead 100644
--- a/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h
+++ b/chrome/browser/ui/android/content_settings/popup_blocked_infobar_delegate.h
@@ -20,7 +20,7 @@
   // |infobar_service|.
   static void Create(content::WebContents* web_contents, int num_popups);
 
-  virtual ~PopupBlockedInfoBarDelegate();
+  ~PopupBlockedInfoBarDelegate() override;
 
  private:
   PopupBlockedInfoBarDelegate(int num_popups,
@@ -28,12 +28,12 @@
                               HostContentSettingsMap* map);
 
   // ConfirmInfoBarDelegate:
-  virtual int GetIconID() const override;
-  virtual PopupBlockedInfoBarDelegate* AsPopupBlockedInfoBarDelegate() override;
-  virtual base::string16 GetMessageText() const override;
-  virtual int GetButtons() const override;
-  virtual base::string16 GetButtonLabel(InfoBarButton button) const override;
-  virtual bool Accept() override;
+  int GetIconID() const override;
+  PopupBlockedInfoBarDelegate* AsPopupBlockedInfoBarDelegate() override;
+  base::string16 GetMessageText() const override;
+  int GetButtons() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+  bool Accept() override;
 
   int num_popups_;
   GURL url_;
diff --git a/chrome/browser/ui/android/context_menu_helper.h b/chrome/browser/ui/android/context_menu_helper.h
index cf018186..e66e351 100644
--- a/chrome/browser/ui/android/context_menu_helper.h
+++ b/chrome/browser/ui/android/context_menu_helper.h
@@ -19,7 +19,7 @@
 class ContextMenuHelper
     : public content::WebContentsUserData<ContextMenuHelper> {
  public:
-  virtual ~ContextMenuHelper();
+  ~ContextMenuHelper() override;
 
   void ShowContextMenu(const content::ContextMenuParams& params);
 
diff --git a/chrome/browser/ui/android/infobars/app_banner_infobar.cc b/chrome/browser/ui/android/infobars/app_banner_infobar.cc
new file mode 100644
index 0000000..367586f
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/app_banner_infobar.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/android/infobars/app_banner_infobar.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/android/banners/app_banner_infobar_delegate.h"
+#include "jni/AppBannerInfoBarDelegate_jni.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/image/image.h"
+
+AppBannerInfoBar::AppBannerInfoBar(
+    scoped_ptr<banners::AppBannerInfoBarDelegate> delegate,
+    const GURL& app_url)
+    : ConfirmInfoBar(delegate.Pass()),
+      app_url_(app_url) {
+}
+
+AppBannerInfoBar::~AppBannerInfoBar() {
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+AppBannerInfoBar::CreateRenderInfoBar(JNIEnv* env) {
+  java_delegate_.Reset(Java_AppBannerInfoBarDelegate_create(env));
+
+  base::android::ScopedJavaLocalRef<jstring> ok_button_text =
+      base::android::ConvertUTF16ToJavaString(
+          env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK));
+
+  ConfirmInfoBarDelegate* delegate = GetDelegate();
+  base::android::ScopedJavaLocalRef<jstring> app_title =
+      base::android::ConvertUTF16ToJavaString(
+          env, delegate->GetMessageText());
+
+  base::android::ScopedJavaLocalRef<jstring> app_url =
+      base::android::ConvertUTF8ToJavaString(env, app_url_.spec());
+
+  ScopedJavaLocalRef<jobject> java_bitmap;
+  if (!delegate->GetIcon().IsEmpty()) {
+    java_bitmap = gfx::ConvertToJavaBitmap(delegate->GetIcon().ToSkBitmap());
+  }
+
+  return Java_AppBannerInfoBarDelegate_showInfoBar(
+      env,
+      java_delegate_.obj(),
+      reinterpret_cast<intptr_t>(this),
+      app_title.obj(),
+      java_bitmap.obj(),
+      ok_button_text.obj(),
+      app_url.obj());
+}
+
+// Native JNI methods ---------------------------------------------------------
+
+bool RegisterAppBannerInfoBarDelegate(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
diff --git a/chrome/browser/ui/android/infobars/app_banner_infobar.h b/chrome/browser/ui/android/infobars/app_banner_infobar.h
new file mode 100644
index 0000000..b43462c
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/app_banner_infobar.h
@@ -0,0 +1,41 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_ANDROID_INFOBARS_APP_BANNER_INFOBAR_H_
+#define CHROME_BROWSER_UI_ANDROID_INFOBARS_APP_BANNER_INFOBAR_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "chrome/browser/ui/android/infobars/confirm_infobar.h"
+#include "url/gurl.h"
+
+namespace banners {
+class AppBannerInfoBarDelegate;
+}  // namespace banners
+
+
+class AppBannerInfoBar : public ConfirmInfoBar {
+ public:
+  // Constructs an AppBannerInfoBar promoting a web app.
+  AppBannerInfoBar(
+      scoped_ptr<banners::AppBannerInfoBarDelegate> delegate,
+      const GURL& app_url);
+
+  ~AppBannerInfoBar() override;
+
+ private:
+  // InfoBarAndroid overrides.
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+      JNIEnv* env) override;
+
+  // Web app: URL for the app.
+  GURL app_url_;
+
+  // Java delegate for creating AppBannerInfoBars.
+  base::android::ScopedJavaGlobalRef<jobject> java_delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppBannerInfoBar);
+};
+
+#endif  // CHROME_BROWSER_UI_ANDROID_INFOBARS_APP_BANNER_INFOBAR_H_
diff --git a/chrome/browser/ui/android/infobars/confirm_infobar.h b/chrome/browser/ui/android/infobars/confirm_infobar.h
index 55e43d41..68e305d3 100644
--- a/chrome/browser/ui/android/infobars/confirm_infobar.h
+++ b/chrome/browser/ui/android/infobars/confirm_infobar.h
@@ -13,19 +13,19 @@
 class ConfirmInfoBar : public InfoBarAndroid {
  public:
   explicit ConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate> delegate);
-  virtual ~ConfirmInfoBar();
+  ~ConfirmInfoBar() override;
+
+ protected:
+  base::string16 GetTextFor(ConfirmInfoBarDelegate::InfoBarButton button);
+  ConfirmInfoBarDelegate* GetDelegate();
+
+  // InfoBarAndroid overrides.
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+      JNIEnv* env) override;
 
  private:
-  // InfoBarAndroid:
-  virtual base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
-      JNIEnv* env) override;
-  virtual void OnLinkClicked(JNIEnv* env, jobject obj) override;
-  virtual void ProcessButton(int action,
-                             const std::string& action_value) override;
-
-  base::string16 GetTextFor(ConfirmInfoBarDelegate::InfoBarButton button);
-
-  ConfirmInfoBarDelegate* GetDelegate();
+  void OnLinkClicked(JNIEnv* env, jobject obj) override;
+  void ProcessButton(int action, const std::string& action_value) override;
 
   base::android::ScopedJavaGlobalRef<jobject> java_confirm_delegate_;
 
diff --git a/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.h b/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.h
index 4658a03..2a22524 100644
--- a/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.h
+++ b/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.h
@@ -22,11 +22,11 @@
   explicit DataReductionProxyInfoBar(
       scoped_ptr<DataReductionProxyInfoBarDelegate> delegate);
 
-  virtual ~DataReductionProxyInfoBar();
+  ~DataReductionProxyInfoBar() override;
 
  private:
   // ConfirmInfoBar:
-  virtual base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
       JNIEnv* env) override;
 
   DataReductionProxyInfoBarDelegate* GetDelegate();
diff --git a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.h b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.h
index 9999e46..4bf80e6 100644
--- a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.h
+++ b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.h
@@ -24,11 +24,10 @@
 
  private:
   // InfoBarAndroid implementation:
-  virtual base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
       JNIEnv* env) override;
-  virtual void OnLinkClicked(JNIEnv* env, jobject obj) override;
-  virtual void ProcessButton(int action,
-                             const std::string& action_value) override;
+  void OnLinkClicked(JNIEnv* env, jobject obj) override;
+  void ProcessButton(int action, const std::string& action_value) override;
 
   DISALLOW_COPY_AND_ASSIGN(GeneratedPasswordSavedInfoBar);
 };
diff --git a/chrome/browser/ui/android/infobars/infobar_android.h b/chrome/browser/ui/android/infobars/infobar_android.h
index 14112191..39bd0e44 100644
--- a/chrome/browser/ui/android/infobars/infobar_android.h
+++ b/chrome/browser/ui/android/infobars/infobar_android.h
@@ -35,7 +35,7 @@
   };
 
   explicit InfoBarAndroid(scoped_ptr<infobars::InfoBarDelegate> delegate);
-  virtual ~InfoBarAndroid();
+  ~InfoBarAndroid() override;
 
   // InfoBar:
   virtual base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
diff --git a/chrome/browser/ui/android/infobars/infobar_container_android.h b/chrome/browser/ui/android/infobars/infobar_container_android.h
index 83432587..f29942e 100644
--- a/chrome/browser/ui/android/infobars/infobar_container_android.h
+++ b/chrome/browser/ui/android/infobars/infobar_container_android.h
@@ -31,16 +31,14 @@
   }
 
  private:
-  virtual ~InfoBarContainerAndroid() override;
+  ~InfoBarContainerAndroid() override;
 
   // InfobarContainer:
-  virtual void PlatformSpecificAddInfoBar(infobars::InfoBar* infobar,
-                                          size_t position) override;
-  virtual void PlatformSpecificRemoveInfoBar(infobars::InfoBar* infobar)
-      override;
-  virtual void PlatformSpecificReplaceInfoBar(
-      infobars::InfoBar* old_infobar,
-      infobars::InfoBar* new_infobar) override;
+  void PlatformSpecificAddInfoBar(infobars::InfoBar* infobar,
+                                  size_t position) override;
+  void PlatformSpecificRemoveInfoBar(infobars::InfoBar* infobar) override;
+  void PlatformSpecificReplaceInfoBar(infobars::InfoBar* old_infobar,
+                                      infobars::InfoBar* new_infobar) override;
 
   // Create the Java equivalent of |android_bar| and add it to the java
   // container.
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.h b/chrome/browser/ui/android/infobars/translate_infobar.h
index f03148c..e210a0ca 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.h
+++ b/chrome/browser/ui/android/infobars/translate_infobar.h
@@ -18,7 +18,7 @@
  public:
   explicit TranslateInfoBar(
       scoped_ptr<translate::TranslateInfoBarDelegate> delegate);
-  virtual ~TranslateInfoBar();
+  ~TranslateInfoBar() override;
 
   // JNI methods specific to translate.
   void ApplyTranslateOptions(JNIEnv* env,
@@ -31,11 +31,10 @@
 
  private:
   // InfoBarAndroid:
-  virtual base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
       JNIEnv* env) override;
-  virtual void ProcessButton(int action,
-                             const std::string& action_value) override;
-  virtual void PassJavaInfoBar(InfoBarAndroid* source) override;
+  void ProcessButton(int action, const std::string& action_value) override;
+  void PassJavaInfoBar(InfoBarAndroid* source) override;
 
   void TransferOwnership(TranslateInfoBar* destination,
                          translate::TranslateStep new_type);
diff --git a/chrome/browser/ui/android/javascript_app_modal_dialog_android.h b/chrome/browser/ui/android/javascript_app_modal_dialog_android.h
index 18c2fd6..bef14655 100644
--- a/chrome/browser/ui/android/javascript_app_modal_dialog_android.h
+++ b/chrome/browser/ui/android/javascript_app_modal_dialog_android.h
@@ -21,13 +21,13 @@
       gfx::NativeWindow parent);
 
   // NativeAppModalDialog:
-  virtual int GetAppModalDialogButtons() const override;
-  virtual void ShowAppModalDialog() override;
-  virtual void ActivateAppModalDialog() override;
-  virtual void CloseAppModalDialog() override;
-  virtual void AcceptAppModalDialog() override;
-  virtual void CancelAppModalDialog() override;
-  virtual bool IsShowing() const override;
+  int GetAppModalDialogButtons() const override;
+  void ShowAppModalDialog() override;
+  void ActivateAppModalDialog() override;
+  void CloseAppModalDialog() override;
+  void AcceptAppModalDialog() override;
+  void CancelAppModalDialog() override;
+  bool IsShowing() const override;
 
   // Called when java confirms or cancels the dialog.
   void DidAcceptAppModalDialog(JNIEnv* env,
@@ -42,7 +42,7 @@
 
  private:
   // The object deletes itself.
-  virtual ~JavascriptAppModalDialogAndroid();
+  ~JavascriptAppModalDialogAndroid() override;
 
   scoped_ptr<app_modal::JavaScriptAppModalDialog> dialog_;
   base::android::ScopedJavaGlobalRef<jobject> dialog_jobject_;
diff --git a/chrome/browser/ui/android/login_prompt_android.cc b/chrome/browser/ui/android/login_prompt_android.cc
index 9f5058a..a62e761 100644
--- a/chrome/browser/ui/android/login_prompt_android.cc
+++ b/chrome/browser/ui/android/login_prompt_android.cc
@@ -28,19 +28,17 @@
 
   // LoginHandler methods:
 
-  virtual void OnAutofillDataAvailable(
-      const base::string16& username,
-      const base::string16& password) override {
+  void OnAutofillDataAvailable(const base::string16& username,
+                               const base::string16& password) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     DCHECK(chrome_http_auth_handler_.get() != NULL);
     chrome_http_auth_handler_->OnAutofillDataAvailable(
         username, password);
   }
-  virtual void OnLoginModelDestroying() override {}
+  void OnLoginModelDestroying() override {}
 
-  virtual void BuildViewForPasswordManager(
-      password_manager::PasswordManager* manager,
-      const base::string16& explanation) override {
+  void BuildViewForPasswordManager(password_manager::PasswordManager* manager,
+                                   const base::string16& explanation) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
     // Get pointer to TabAndroid
@@ -68,9 +66,9 @@
   }
 
  protected:
-  virtual ~LoginHandlerAndroid() {}
+  ~LoginHandlerAndroid() override {}
 
-  virtual void CloseDialog() override {}
+  void CloseDialog() override {}
 
  private:
   scoped_ptr<ChromeHttpAuthHandler> chrome_http_auth_handler_;
diff --git a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h
index 054ba11..10afe4a 100644
--- a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h
+++ b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.h
@@ -20,15 +20,14 @@
  public:
   explicit ChromeWebContentsViewDelegateAndroid(
       content::WebContents* web_contents);
-  virtual ~ChromeWebContentsViewDelegateAndroid();
+  ~ChromeWebContentsViewDelegateAndroid() override;
 
   // WebContentsViewDelegate:
-  virtual void ShowContextMenu(
-      content::RenderFrameHost* render_frame_host,
-      const content::ContextMenuParams& params) override;
+  void ShowContextMenu(content::RenderFrameHost* render_frame_host,
+                       const content::ContextMenuParams& params) override;
 
   // WebContentsViewDelegate:
-  virtual content::WebDragDestDelegate* GetDragDestDelegate() override;
+  content::WebDragDestDelegate* GetDragDestDelegate() override;
 
  private:
   // The WebContents that owns the view and this delegate transitively.
diff --git a/chrome/browser/ui/android/tab_model/tab_model.cc b/chrome/browser/ui/android/tab_model/tab_model.cc
index 2d5bd6a0..1c07f77 100644
--- a/chrome/browser/ui/android/tab_model/tab_model.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model.cc
@@ -14,6 +14,10 @@
 
 using content::NotificationService;
 
+// Keep this in sync with
+// chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabList.java
+static int INVALID_TAB_INDEX = -1;
+
 TabModel::TabModel(Profile* profile)
   : profile_(profile),
     synced_window_delegate_(
@@ -58,6 +62,13 @@
   return session_id_.id();
 }
 
+content::WebContents* TabModel::GetActiveWebContents() const {
+  int active_index = GetActiveIndex();
+  if (active_index == INVALID_TAB_INDEX)
+    return nullptr;
+  return GetWebContentsAt(active_index);
+}
+
 void TabModel::BroadcastSessionRestoreComplete() {
   if (profile_) {
     NotificationService::current()->Notify(
diff --git a/chrome/browser/ui/android/tab_model/tab_model.h b/chrome/browser/ui/android/tab_model/tab_model.h
index 0125f97..8a48f09 100644
--- a/chrome/browser/ui/android/tab_model/tab_model.h
+++ b/chrome/browser/ui/android/tab_model/tab_model.h
@@ -37,6 +37,7 @@
 
   virtual int GetTabCount() const = 0;
   virtual int GetActiveIndex() const = 0;
+  virtual content::WebContents* GetActiveWebContents() const;
   virtual content::WebContents* GetWebContentsAt(int index) const = 0;
   // This will return NULL if the tab has not yet been initialized.
   virtual TabAndroid* GetTabAt(int index) const = 0;
diff --git a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h
index 77a614d2..0de051d 100644
--- a/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h
+++ b/chrome/browser/ui/android/tab_model/tab_model_jni_bridge.h
@@ -28,7 +28,7 @@
  public:
   TabModelJniBridge(JNIEnv* env, jobject obj, bool is_incognito);
   void Destroy(JNIEnv* env, jobject obj);
-  virtual ~TabModelJniBridge();
+  ~TabModelJniBridge() override;
 
   // Registers the JNI bindings.
   static bool Register(JNIEnv* env);
@@ -39,22 +39,21 @@
   void TabAddedToModel(JNIEnv* env, jobject obj, jobject jtab);
 
   // TabModel::
-  virtual int GetTabCount() const override;
-  virtual int GetActiveIndex() const override;
-  virtual content::WebContents* GetWebContentsAt(int index) const override;
-  virtual TabAndroid* GetTabAt(int index) const override;
+  int GetTabCount() const override;
+  int GetActiveIndex() const override;
+  content::WebContents* GetWebContentsAt(int index) const override;
+  TabAndroid* GetTabAt(int index) const override;
 
-  virtual void SetActiveIndex(int index) override;
-  virtual void CloseTabAt(int index) override;
+  void SetActiveIndex(int index) override;
+  void CloseTabAt(int index) override;
 
-  virtual void CreateTab(content::WebContents* web_contents,
-                         int parent_tab_id) override;
+  void CreateTab(content::WebContents* web_contents,
+                 int parent_tab_id) override;
 
-  virtual content::WebContents* CreateNewTabForDevTools(
-      const GURL& url) override;
+  content::WebContents* CreateNewTabForDevTools(const GURL& url) override;
 
   // Return true if we are currently restoring sessions asynchronously.
-  virtual bool IsSessionRestoreInProgress() const override;
+  bool IsSessionRestoreInProgress() const override;
 
   // Instructs the TabModel to broadcast a notification that all tabs are now
   // loaded from storage.
diff --git a/chrome/browser/ui/android/tab_model/tab_model_list_unittest.cc b/chrome/browser/ui/android/tab_model/tab_model_list_unittest.cc
index 1fb6b4b0..5cc57f3 100644
--- a/chrome/browser/ui/android/tab_model/tab_model_list_unittest.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model_list_unittest.cc
@@ -17,21 +17,20 @@
  public:
   explicit TestTabModel(Profile* profile) : TabModel(profile), tab_count_(0) {}
 
-  virtual int GetTabCount() const override { return tab_count_; }
-  virtual int GetActiveIndex() const override { return 0; }
-  virtual content::WebContents* GetWebContentsAt(int index) const override {
+  int GetTabCount() const override { return tab_count_; }
+  int GetActiveIndex() const override { return 0; }
+  content::WebContents* GetWebContentsAt(int index) const override {
     return nullptr;
   }
-  virtual void CreateTab(content::WebContents* web_contents,
-                         int parent_tab_id) override {}
-  virtual content::WebContents* CreateNewTabForDevTools(
-      const GURL& url) override {
+  void CreateTab(content::WebContents* web_contents,
+                 int parent_tab_id) override {}
+  content::WebContents* CreateNewTabForDevTools(const GURL& url) override {
     return nullptr;
   }
-  virtual bool IsSessionRestoreInProgress() const override { return false; }
-  virtual TabAndroid* GetTabAt(int index) const override { return nullptr; }
-  virtual void SetActiveIndex(int index) override {}
-  virtual void CloseTabAt(int index) override {}
+  bool IsSessionRestoreInProgress() const override { return false; }
+  TabAndroid* GetTabAt(int index) const override { return nullptr; }
+  void SetActiveIndex(int index) override {}
+  void CloseTabAt(int index) override {}
 
   // A fake value for the current number of tabs.
   int tab_count_;
diff --git a/chrome/browser/ui/android/tab_model/tab_model_unittest.cc b/chrome/browser/ui/android/tab_model/tab_model_unittest.cc
index 9808857..8f099e0a 100644
--- a/chrome/browser/ui/android/tab_model/tab_model_unittest.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model_unittest.cc
@@ -29,23 +29,20 @@
   explicit TestTabModel(Profile* profile)
     : TabModel(profile) {}
 
-  virtual int GetTabCount() const override { return 0; }
-  virtual int GetActiveIndex() const override { return 0; }
-  virtual content::WebContents* GetWebContentsAt(int index) const override {
+  int GetTabCount() const override { return 0; }
+  int GetActiveIndex() const override { return 0; }
+  content::WebContents* GetWebContentsAt(int index) const override {
     return NULL;
   }
-  virtual void CreateTab(content::WebContents* web_contents,
-                         int parent_tab_id) override {}
-  virtual content::WebContents* CreateNewTabForDevTools(
-      const GURL& url) override {
+  void CreateTab(content::WebContents* web_contents,
+                 int parent_tab_id) override {}
+  content::WebContents* CreateNewTabForDevTools(const GURL& url) override {
     return NULL;
   }
-  virtual bool IsSessionRestoreInProgress() const override { return false; }
-  virtual TabAndroid* GetTabAt(int index) const override {
-    return NULL;
-  }
-  virtual void SetActiveIndex(int index) override {}
-  virtual void CloseTabAt(int index) override {}
+  bool IsSessionRestoreInProgress() const override { return false; }
+  TabAndroid* GetTabAt(int index) const override { return NULL; }
+  void SetActiveIndex(int index) override {}
+  void CloseTabAt(int index) override {}
 };
 
 TEST_F(TabModelTest, TestProfileHandling) {
diff --git a/chrome/browser/ui/android/toolbar/toolbar_model_android.h b/chrome/browser/ui/android/toolbar/toolbar_model_android.h
index 210f17e..60015e4 100644
--- a/chrome/browser/ui/android/toolbar/toolbar_model_android.h
+++ b/chrome/browser/ui/android/toolbar/toolbar_model_android.h
@@ -21,7 +21,7 @@
 class ToolbarModelAndroid : public ToolbarModelDelegate {
  public:
   explicit ToolbarModelAndroid(JNIEnv* env, jobject jdelegate);
-  virtual ~ToolbarModelAndroid();
+  ~ToolbarModelAndroid() override;
 
   void Destroy(JNIEnv* env, jobject obj);
   base::android::ScopedJavaLocalRef<jstring> GetText(
@@ -35,8 +35,8 @@
       jobject obj);
 
   // ToolbarDelegate:
-  virtual content::WebContents* GetActiveWebContents() const override;
-  virtual bool InTabbedBrowser() const override;
+  content::WebContents* GetActiveWebContents() const override;
+  bool InTabbedBrowser() const override;
 
   static bool RegisterToolbarModelAndroid(JNIEnv* env);
 
diff --git a/chrome/browser/ui/android/website_settings_popup_android.h b/chrome/browser/ui/android/website_settings_popup_android.h
index 57f5ec0..33bb7713 100644
--- a/chrome/browser/ui/android/website_settings_popup_android.h
+++ b/chrome/browser/ui/android/website_settings_popup_android.h
@@ -33,7 +33,7 @@
   WebsiteSettingsPopupAndroid(JNIEnv* env,
                               jobject java_website_settings,
                               content::WebContents* web_contents);
-  virtual ~WebsiteSettingsPopupAndroid();
+  ~WebsiteSettingsPopupAndroid() override;
   void Destroy(JNIEnv* env, jobject obj);
   void OnPermissionSettingChanged(JNIEnv* env,
                                   jobject obj,
@@ -41,12 +41,12 @@
                                   jint setting);
 
   // WebsiteSettingsUI implementations.
-  virtual void SetCookieInfo(const CookieInfoList& cookie_info_list) override;
-  virtual void SetPermissionInfo(
+  void SetCookieInfo(const CookieInfoList& cookie_info_list) override;
+  void SetPermissionInfo(
       const PermissionInfoList& permission_info_list) override;
-  virtual void SetIdentityInfo(const IdentityInfo& identity_info) override;
-  virtual void SetFirstVisit(const base::string16& first_visit) override;
-  virtual void SetSelectedTab(WebsiteSettingsUI::TabId tab_id) override;
+  void SetIdentityInfo(const IdentityInfo& identity_info) override;
+  void SetFirstVisit(const base::string16& first_visit) override;
+  void SetSelectedTab(WebsiteSettingsUI::TabId tab_id) override;
 
   static bool RegisterWebsiteSettingsPopupAndroid(JNIEnv* env);
 
diff --git a/chrome/browser/ui/android/website_settings_popup_legacy_android.h b/chrome/browser/ui/android/website_settings_popup_legacy_android.h
index 66a8d8f..10f2b8c5 100644
--- a/chrome/browser/ui/android/website_settings_popup_legacy_android.h
+++ b/chrome/browser/ui/android/website_settings_popup_legacy_android.h
@@ -22,7 +22,7 @@
   WebsiteSettingsPopupLegacyAndroid(JNIEnv* env,
                                     jobject java_website_settings,
                                     content::WebContents* web_contents);
-  virtual ~WebsiteSettingsPopupLegacyAndroid();
+  ~WebsiteSettingsPopupLegacyAndroid() override;
   void Destroy(JNIEnv* env, jobject obj);
 
   // Revokes any current user exceptions for bypassing SSL error interstitials
@@ -30,12 +30,12 @@
   void ResetCertDecisions(JNIEnv* env, jobject obj, jobject java_web_contents);
 
   // WebsiteSettingsUI implementations.
-  virtual void SetCookieInfo(const CookieInfoList& cookie_info_list) override;
-  virtual void SetPermissionInfo(
+  void SetCookieInfo(const CookieInfoList& cookie_info_list) override;
+  void SetPermissionInfo(
       const PermissionInfoList& permission_info_list) override;
-  virtual void SetIdentityInfo(const IdentityInfo& identity_info) override;
-  virtual void SetFirstVisit(const base::string16& first_visit) override;
-  virtual void SetSelectedTab(WebsiteSettingsUI::TabId tab_id) override;
+  void SetIdentityInfo(const IdentityInfo& identity_info) override;
+  void SetFirstVisit(const base::string16& first_visit) override;
+  void SetSelectedTab(WebsiteSettingsUI::TabId tab_id) override;
 
   static bool RegisterWebsiteSettingsPopupLegacyAndroid(JNIEnv* env);
 
diff --git a/chrome/browser/ui/android/window_android_helper.h b/chrome/browser/ui/android/window_android_helper.h
index 925ca67..e097d11 100644
--- a/chrome/browser/ui/android/window_android_helper.h
+++ b/chrome/browser/ui/android/window_android_helper.h
@@ -15,7 +15,7 @@
 class WindowAndroidHelper
     : public content::WebContentsUserData<WindowAndroidHelper> {
  public:
-  virtual ~WindowAndroidHelper();
+  ~WindowAndroidHelper() override;
 
   void SetWindowAndroid(ui::WindowAndroid* window_android);
   ui::WindowAndroid* GetWindowAndroid();
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc
index e08d8ef3..833d3bbe 100644
--- a/chrome/browser/ui/app_list/start_page_service.cc
+++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/json/json_string_value_serializer.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/user_metrics.h"
 #include "base/prefs/pref_service.h"
@@ -17,10 +18,14 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/hotword_service.h"
 #include "chrome/browser/search/hotword_service_factory.h"
+#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/browser/ui/app_list/speech_auth_helper.h"
 #include "chrome/browser/ui/app_list/speech_recognizer.h"
 #include "chrome/browser/ui/app_list/start_page_observer.h"
 #include "chrome/browser/ui/app_list/start_page_service_factory.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -37,7 +42,9 @@
 #include "extensions/browser/extension_system_provider.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/common/extension.h"
+#include "net/base/load_flags.h"
 #include "net/base/network_change_notifier.h"
+#include "net/url_request/url_fetcher.h"
 #include "ui/app_list/app_list_switches.h"
 
 #if defined(OS_CHROMEOS)
@@ -51,6 +58,12 @@
 
 namespace {
 
+// Path to google.com's doodle JSON.
+const char kDoodleJsonPath[] = "async/ddljson";
+
+// Delay between checking for a new doodle when no doodle is found.
+const int kDefaultDoodleRecheckDelayMinutes = 30;
+
 bool InSpeechRecognition(SpeechRecognitionState state) {
   return state == SPEECH_RECOGNITION_RECOGNIZING ||
       state == SPEECH_RECOGNITION_IN_SPEECH;
@@ -88,7 +101,7 @@
 class StartPageService::StartPageWebContentsDelegate
     : public content::WebContentsDelegate {
  public:
-  StartPageWebContentsDelegate() {}
+  explicit StartPageWebContentsDelegate(Profile* profile) : profile_(profile) {}
   ~StartPageWebContentsDelegate() override {}
 
   void RequestMediaAccessPermission(
@@ -106,7 +119,50 @@
         ->CheckMediaAccessPermission(web_contents, security_origin, type);
   }
 
+  void AddNewContents(content::WebContents* source,
+                      content::WebContents* new_contents,
+                      WindowOpenDisposition disposition,
+                      const gfx::Rect& initial_pos,
+                      bool user_gesture,
+                      bool* was_blocked) override {
+    chrome::ScopedTabbedBrowserDisplayer displayer(
+        profile_, chrome::GetActiveDesktop());
+    // Force all links to open in a new tab, even if they were trying to open a
+    // new window.
+    disposition =
+        disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
+    chrome::AddWebContents(displayer.browser(),
+                           nullptr,
+                           new_contents,
+                           disposition,
+                           initial_pos,
+                           user_gesture,
+                           was_blocked);
+  }
+
+  content::WebContents* OpenURLFromTab(
+      content::WebContents* source,
+      const content::OpenURLParams& params) override {
+    // Force all links to open in a new tab, even if they were trying to open a
+    // window.
+    chrome::NavigateParams new_tab_params(
+        static_cast<Browser*>(nullptr), params.url, params.transition);
+    if (params.disposition == NEW_BACKGROUND_TAB) {
+      new_tab_params.disposition = NEW_BACKGROUND_TAB;
+    } else {
+      new_tab_params.disposition = NEW_FOREGROUND_TAB;
+      new_tab_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
+    }
+
+    new_tab_params.initiating_profile = profile_;
+    chrome::Navigate(&new_tab_params);
+
+    return new_tab_params.target_contents;
+  }
+
  private:
+  Profile* profile_;
+
   DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate);
 };
 
@@ -283,6 +339,7 @@
   if (HotwordService::IsExperimentalHotwordingEnabled() &&
       speech_recognizer_) {
     speech_recognizer_->Stop();
+    speech_recognizer_.reset();
   }
 
 #if defined(OS_CHROMEOS)
@@ -472,12 +529,14 @@
   for (const auto& cb : pending_webui_callbacks_)
     cb.Run();
   pending_webui_callbacks_.clear();
+
+  FetchDoodleJson();
 }
 
 void StartPageService::LoadContents() {
   contents_.reset(content::WebContents::Create(
       content::WebContents::CreateParams(profile_)));
-  contents_delegate_.reset(new StartPageWebContentsDelegate());
+  contents_delegate_.reset(new StartPageWebContentsDelegate(profile_));
   contents_->SetDelegate(contents_delegate_.get());
 
   // The ZoomController needs to be created before the web contents is observed
@@ -498,4 +557,63 @@
   webui_finished_loading_ = false;
 }
 
+void StartPageService::FetchDoodleJson() {
+  // SetPathStr() requires its argument to stay in scope as long as
+  // |replacements| is, so a std::string is needed, instead of a char*.
+  std::string path = kDoodleJsonPath;
+  GURL::Replacements replacements;
+  replacements.SetPathStr(path);
+
+  GURL google_base_url(UIThreadSearchTermsData(profile_).GoogleBaseURLValue());
+  GURL doodle_url = google_base_url.ReplaceComponents(replacements);
+  doodle_fetcher_.reset(
+      net::URLFetcher::Create(0, doodle_url, net::URLFetcher::GET, this));
+  doodle_fetcher_->SetRequestContext(profile_->GetRequestContext());
+  doodle_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
+  doodle_fetcher_->Start();
+}
+
+void StartPageService::OnURLFetchComplete(const net::URLFetcher* source) {
+  std::string json_data;
+  source->GetResponseAsString(&json_data);
+
+  // Remove XSSI guard for JSON parsing.
+  size_t json_start_index = json_data.find("{");
+  if (json_start_index != std::string::npos)
+    json_data.erase(0, json_start_index);
+
+  JSONStringValueSerializer deserializer(json_data);
+  deserializer.set_allow_trailing_comma(true);
+  int error_code = 0;
+  scoped_ptr<base::Value> doodle_json(
+      deserializer.Deserialize(&error_code, nullptr));
+
+  base::TimeDelta recheck_delay =
+      base::TimeDelta::FromMinutes(kDefaultDoodleRecheckDelayMinutes);
+
+  if (error_code == 0) {
+    base::DictionaryValue* doodle_dictionary = nullptr;
+    // Use the supplied TTL as the recheck delay if available.
+    if (doodle_json->GetAsDictionary(&doodle_dictionary)) {
+      int time_to_live = 0;
+      if (doodle_dictionary->GetInteger("ddljson.time_to_live_ms",
+                                        &time_to_live)) {
+        recheck_delay = base::TimeDelta::FromMilliseconds(time_to_live);
+      }
+    }
+
+    contents_->GetWebUI()->CallJavascriptFunction(
+        "appList.startPage.onAppListDoodleUpdated", *doodle_json,
+        base::StringValue(
+            UIThreadSearchTermsData(profile_).GoogleBaseURLValue()));
+  }
+
+  // Check for a new doodle.
+  content::BrowserThread::PostDelayedTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&StartPageService::FetchDoodleJson,
+                 weak_factory_.GetWeakPtr()),
+      recheck_delay);
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/start_page_service.h b/chrome/browser/ui/app_list/start_page_service.h
index 84590fb..7a7872b 100644
--- a/chrome/browser/ui/app_list/start_page_service.h
+++ b/chrome/browser/ui/app_list/start_page_service.h
@@ -21,6 +21,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "net/url_request/url_fetcher_delegate.h"
 #include "ui/app_list/speech_ui_model_observer.h"
 
 namespace content {
@@ -33,6 +34,10 @@
 class Extension;
 }
 
+namespace net {
+class URLFetcher;
+}
+
 class Profile;
 
 namespace app_list {
@@ -45,6 +50,7 @@
 // and hosts the start page contents.
 class StartPageService : public KeyedService,
                          public content::WebContentsObserver,
+                         public net::URLFetcherDelegate,
                          public SpeechRecognizerDelegate {
  public:
   typedef std::vector<scoped_refptr<const extensions::Extension> >
@@ -112,6 +118,12 @@
   void LoadContents();
   void UnloadContents();
 
+  // Fetch the Google Doodle JSON data and update the app list start page.
+  void FetchDoodleJson();
+
+  // net::URLFetcherDelegate overrides:
+  void OnURLFetchComplete(const net::URLFetcher* source) override;
+
   // KeyedService overrides:
   void Shutdown() override;
 
@@ -152,6 +164,8 @@
 #endif
   scoped_ptr<NetworkChangeObserver> network_change_observer_;
 
+  scoped_ptr<net::URLFetcher> doodle_fetcher_;
+
   base::WeakPtrFactory<StartPageService> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(StartPageService);
diff --git a/chrome/browser/ui/apps/chrome_app_delegate.cc b/chrome/browser/ui/apps/chrome_app_delegate.cc
index 36a96d22..d5740a1 100644
--- a/chrome/browser/ui/apps/chrome_app_delegate.cc
+++ b/chrome/browser/ui/apps/chrome_app_delegate.cc
@@ -219,7 +219,7 @@
 void ChromeAppDelegate::AddNewContents(content::BrowserContext* context,
                                        content::WebContents* new_contents,
                                        WindowOpenDisposition disposition,
-                                       const gfx::Rect& initial_pos,
+                                       const gfx::Rect& initial_rect,
                                        bool user_gesture,
                                        bool* was_blocked) {
   if (!disable_external_open_for_testing_) {
@@ -240,7 +240,7 @@
                          NULL,
                          new_contents,
                          disposition,
-                         initial_pos,
+                         initial_rect,
                          user_gesture,
                          was_blocked);
 }
diff --git a/chrome/browser/ui/apps/chrome_app_delegate.h b/chrome/browser/ui/apps/chrome_app_delegate.h
index 4e7c7d4f..e1224a3 100644
--- a/chrome/browser/ui/apps/chrome_app_delegate.h
+++ b/chrome/browser/ui/apps/chrome_app_delegate.h
@@ -40,7 +40,7 @@
   void AddNewContents(content::BrowserContext* context,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   content::ColorChooser* ShowColorChooser(content::WebContents* web_contents,
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 930954b..504d04e4 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -50,7 +50,7 @@
 #include "ash/test/test_session_state_delegate.h"
 #include "ash/test/test_shell_delegate.h"
 #include "chrome/browser/apps/scoped_keep_alive.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
@@ -62,6 +62,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/app_window/app_window_contents.h"
@@ -779,8 +780,8 @@
     profile_manager_->SetLoggedIn(true);
 
     // Initialize the UserManager singleton to a fresh FakeUserManager instance.
-    user_manager_enabler_.reset(
-        new chromeos::ScopedUserManagerEnabler(new chromeos::FakeUserManager));
+    user_manager_enabler_.reset(new chromeos::ScopedUserManagerEnabler(
+        new chromeos::FakeChromeUserManager));
 
     // Initialize the rest.
     ChromeLauncherControllerTest::SetUp();
@@ -906,8 +907,8 @@
   typedef std::map<Profile*, std::string> ProfileToNameMap;
   TestingProfileManager* profile_manager() { return profile_manager_.get(); }
 
-  chromeos::FakeUserManager* GetFakeUserManager() {
-    return static_cast<chromeos::FakeUserManager*>(
+  chromeos::FakeChromeUserManager* GetFakeUserManager() {
+    return static_cast<chromeos::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
   }
 
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc b/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc
index 8f0b79f..37da1a4b 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos_unittest.cc
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
@@ -50,8 +50,9 @@
   ~SessionStateDelegateChromeOSTest() override {}
 
   void SetUp() override {
-    // Initialize the UserManager singleton to a fresh FakeUserManager instance.
-    user_manager_ = new chromeos::FakeUserManager;
+    // Initialize the UserManager singleton to a fresh FakeChromeUserManager
+    // instance.
+    user_manager_ = new FakeChromeUserManager;
     user_manager_enabler_.reset(
         new chromeos::ScopedUserManagerEnabler(user_manager_));
 
@@ -89,7 +90,7 @@
     return user_manager::UserManager::Get()->GetActiveUser()->email();
   }
 
-  chromeos::FakeUserManager* user_manager() { return user_manager_; }
+  FakeChromeUserManager* user_manager() { return user_manager_; }
   SessionStateDelegateChromeos* session_state_delegate() {
     return session_state_delegate_.get();
   }
@@ -119,7 +120,7 @@
   scoped_ptr<SessionStateDelegateChromeos> session_state_delegate_;
 
   // Not owned.
-  chromeos::FakeUserManager* user_manager_;
+  FakeChromeUserManager* user_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(SessionStateDelegateChromeOSTest);
 };
diff --git a/chrome/browser/ui/auto_login_infobar_delegate.cc b/chrome/browser/ui/auto_login_infobar_delegate.cc
index c4e20c0f..9cb09d7 100644
--- a/chrome/browser/ui/auto_login_infobar_delegate.cc
+++ b/chrome/browser/ui/auto_login_infobar_delegate.cc
@@ -49,15 +49,15 @@
  public:
   AutoLoginRedirector(content::WebContents* web_contents,
                       const std::string& args);
-  virtual ~AutoLoginRedirector();
+  ~AutoLoginRedirector() override;
 
  private:
   // Overriden from UbertokenConsumer:
-  virtual void OnUbertokenSuccess(const std::string& token) override;
-  virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) override;
+  void OnUbertokenSuccess(const std::string& token) override;
+  void OnUbertokenFailure(const GoogleServiceAuthError& error) override;
 
   // Implementation of content::WebContentsObserver
-  virtual void WebContentsDestroyed() override;
+  void WebContentsDestroyed() override;
 
   // Redirect tab to MergeSession URL, logging the user in and navigating
   // to the desired page.
diff --git a/chrome/browser/ui/auto_login_infobar_delegate.h b/chrome/browser/ui/auto_login_infobar_delegate.h
index 7877240b..07b4f5b 100644
--- a/chrome/browser/ui/auto_login_infobar_delegate.h
+++ b/chrome/browser/ui/auto_login_infobar_delegate.h
@@ -50,24 +50,24 @@
   };
 
   AutoLoginInfoBarDelegate(const Params& params, Profile* profile);
-  virtual ~AutoLoginInfoBarDelegate();
+  ~AutoLoginInfoBarDelegate() override;
 
   void RecordHistogramAction(Actions action);
 
  private:
   // ConfirmInfoBarDelegate:
-  virtual void InfoBarDismissed() override;
-  virtual int GetIconID() const override;
-  virtual Type GetInfoBarType() const override;
-  virtual AutoLoginInfoBarDelegate* AsAutoLoginInfoBarDelegate() override;
-  virtual base::string16 GetMessageText() const override;
-  virtual base::string16 GetButtonLabel(InfoBarButton button) const override;
-  virtual bool Accept() override;
-  virtual bool Cancel() override;
+  void InfoBarDismissed() override;
+  int GetIconID() const override;
+  Type GetInfoBarType() const override;
+  AutoLoginInfoBarDelegate* AsAutoLoginInfoBarDelegate() override;
+  base::string16 GetMessageText() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+  bool Accept() override;
+  bool Cancel() override;
 
   // SigninManagerBase::Observer:
-  virtual void GoogleSignedOut(const std::string& account_id,
-                               const std::string& username) override;
+  void GoogleSignedOut(const std::string& account_id,
+                       const std::string& username) override;
 
   const Params params_;
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc
index b1737ea..5dba33b 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.cc
@@ -89,12 +89,12 @@
     content::WebContents* source,
     content::WebContents* new_contents,
     WindowOpenDisposition disposition,
-    const gfx::Rect& initial_pos,
+    const gfx::Rect& initial_rect,
     bool user_gesture,
     bool* was_blocked) {
   chrome::AddWebContents(
       chrome::FindBrowserWithWebContents(originating_web_contents_),
-      source, new_contents, disposition, initial_pos, user_gesture,
+      source, new_contents, disposition, initial_rect, user_gesture,
       was_blocked);
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h
index cd4b6378..e81bf808 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_sign_in_delegate.h
@@ -38,7 +38,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   bool PreHandleGestureEvent(content::WebContents* source,
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 436a15ed..f438efd2 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1391,10 +1391,10 @@
 void Browser::AddNewContents(WebContents* source,
                              WebContents* new_contents,
                              WindowOpenDisposition disposition,
-                             const gfx::Rect& initial_pos,
+                             const gfx::Rect& initial_rect,
                              bool user_gesture,
                              bool* was_blocked) {
-  chrome::AddWebContents(this, source, new_contents, disposition, initial_pos,
+  chrome::AddWebContents(this, source, new_contents, disposition, initial_rect,
                          user_gesture, was_blocked);
 }
 
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 8478d97..ff72aa55 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -548,7 +548,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   void ActivateContents(content::WebContents* contents) override;
diff --git a/chrome/browser/ui/browser_tabstrip.cc b/chrome/browser/ui/browser_tabstrip.cc
index b307c93a..bb20e62 100644
--- a/chrome/browser/ui/browser_tabstrip.cc
+++ b/chrome/browser/ui/browser_tabstrip.cc
@@ -48,7 +48,7 @@
                     content::WebContents* source_contents,
                     content::WebContents* new_contents,
                     WindowOpenDisposition disposition,
-                    const gfx::Rect& initial_pos,
+                    const gfx::Rect& initial_rect,
                     bool user_gesture,
                     bool* was_blocked) {
   // No code for this yet.
@@ -59,7 +59,7 @@
   NavigateParams params(browser, new_contents);
   params.source_contents = source_contents;
   params.disposition = disposition;
-  params.window_bounds = initial_pos;
+  params.window_bounds = initial_rect;
   params.window_action = NavigateParams::SHOW_WINDOW;
   // At this point, we're already beyond the popup blocker. Even if the popup
   // was created without a user gesture, we have to set |user_gesture| to true,
diff --git a/chrome/browser/ui/browser_tabstrip.h b/chrome/browser/ui/browser_tabstrip.h
index 6a21c28..958b5815 100644
--- a/chrome/browser/ui/browser_tabstrip.h
+++ b/chrome/browser/ui/browser_tabstrip.h
@@ -37,14 +37,15 @@
 
 // Creates a new tab with the already-created WebContents 'new_contents'.
 // The window for the added contents will be reparented correctly when this
-// method returns.  If |disposition| is NEW_POPUP, |pos| should hold the
-// initial position. If |was_blocked| is non-NULL, then |*was_blocked| will be
-// set to true if the popup gets blocked, and left unchanged otherwise.
+// method returns.  If |disposition| is NEW_POPUP, |initial_rect| should hold
+// the initial position and size. If |was_blocked| is non-NULL, then
+// |*was_blocked| will be set to true if the popup gets blocked, and left
+// unchanged otherwise.
 void AddWebContents(Browser* browser,
                     content::WebContents* source_contents,
                     content::WebContents* new_contents,
                     WindowOpenDisposition disposition,
-                    const gfx::Rect& initial_pos,
+                    const gfx::Rect& initial_rect,
                     bool user_gesture,
                     bool* was__blocked);
 
diff --git a/chrome/browser/ui/cocoa/background_gradient_view.h b/chrome/browser/ui/cocoa/background_gradient_view.h
index e8b6c2d..1f6c7e8 100644
--- a/chrome/browser/ui/cocoa/background_gradient_view.h
+++ b/chrome/browser/ui/cocoa/background_gradient_view.h
@@ -7,9 +7,11 @@
 
 #import <Cocoa/Cocoa.h>
 
+#import "chrome/browser/ui/cocoa/themed_window.h"
+
 // A custom view that draws a 'standard' background gradient.
 // Base class for other Chromium views.
-@interface BackgroundGradientView : NSView {
+@interface BackgroundGradientView : NSView<ThemedWindowDrawing> {
  @private
   BOOL showsDivider_;
 }
diff --git a/chrome/browser/ui/cocoa/background_gradient_view.mm b/chrome/browser/ui/cocoa/background_gradient_view.mm
index 1cb6c2f6..fe58356 100644
--- a/chrome/browser/ui/cocoa/background_gradient_view.mm
+++ b/chrome/browser/ui/cocoa/background_gradient_view.mm
@@ -111,43 +111,14 @@
   return themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR);
 }
 
-- (void)windowFocusDidChange:(NSNotification*)notification {
-  // Some child views will indirectly use BackgroundGradientView by calling an
-  // ancestor's draw function (e.g, BookmarkButtonView). Call setNeedsDisplay
-  // on all descendants to ensure that these views re-draw.
-  // TODO(ccameron): Enable these views to listen for focus notifications
-  // directly.
-  [self cr_recursivelySetNeedsDisplay:YES];
-}
-
-- (void)viewWillMoveToWindow:(NSWindow*)window {
+- (void)viewDidMoveToWindow {
+  [super viewDidMoveToWindow];
   if ([self window]) {
-    [[NSNotificationCenter defaultCenter]
-        removeObserver:self
-                  name:NSWindowDidBecomeKeyNotification
-                object:[self window]];
-    [[NSNotificationCenter defaultCenter]
-        removeObserver:self
-                  name:NSWindowDidBecomeMainNotification
-                object:[self window]];
-  }
-  if (window) {
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(windowFocusDidChange:)
-               name:NSWindowDidBecomeMainNotification
-             object:window];
-    [[NSNotificationCenter defaultCenter]
-        addObserver:self
-           selector:@selector(windowFocusDidChange:)
-               name:NSWindowDidResignMainNotification
-             object:window];
     // The new window for the view may have a different focus state than the
     // last window this view was part of. Force a re-draw to ensure that the
     // view draws the right state.
-    [self windowFocusDidChange:nil];
+    [self windowDidChangeActive];
   }
-  [super viewWillMoveToWindow:window];
 }
 
 - (void)setFrameOrigin:(NSPoint)origin {
@@ -159,4 +130,14 @@
   [super setFrameOrigin:origin];
 }
 
+// ThemedWindowDrawing implementation.
+
+- (void)windowDidChangeTheme {
+  [self setNeedsDisplay:YES];
+}
+
+- (void)windowDidChangeActive {
+  [self setNeedsDisplay:YES];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
index 83c6fbe..51bad93 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.h
@@ -5,6 +5,7 @@
 #import <Cocoa/Cocoa.h>
 #include <vector>
 #import "chrome/browser/ui/cocoa/draggable_button.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
 #include "ui/base/window_open_disposition.h"
 
 @class BookmarkBarFolderController;
@@ -189,7 +190,7 @@
 
 
 // Class for bookmark bar buttons that can be drag sources.
-@interface BookmarkButton : DraggableButton {
+@interface BookmarkButton : DraggableButton<ThemedWindowDrawing> {
  @private
   IBOutlet NSObject<BookmarkButtonDelegate>* delegate_;  // Weak.
 
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
index ffaefda..449e766 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button.mm
@@ -416,6 +416,16 @@
   [super drawRect:rect];
 }
 
+// ThemedWindowDrawing implementation.
+
+- (void)windowDidChangeTheme {
+  [self setNeedsDisplay:YES];
+}
+
+- (void)windowDidChangeActive {
+  [self setNeedsDisplay:YES];
+}
+
 @end
 
 @implementation BookmarkButton(Private)
diff --git a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h
index 7293b4b..cfcd3452 100644
--- a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.h
@@ -48,8 +48,6 @@
   ui::ScopedCrTrackingArea trackingArea_;
 }
 
-@property(nonatomic) ZoomBubbleControllerDelegate* delegate;
-
 // Creates the bubble for a parent window but does not show it.
 - (id)initWithParentWindow:(NSWindow*)parentWindow
                   delegate:(ZoomBubbleControllerDelegate*)delegate;
diff --git a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
index 05c9221..234eb6d 100644
--- a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
@@ -75,8 +75,6 @@
 
 @implementation ZoomBubbleController
 
-@synthesize delegate = delegate_;
-
 - (id)initWithParentWindow:(NSWindow*)parentWindow
                   delegate:(ZoomBubbleControllerDelegate*)delegate {
   base::scoped_nsobject<InfoBubbleWindow> window(
@@ -128,10 +126,6 @@
 }
 
 - (void)onZoomChanged {
-  // |delegate_| may be set null by this object's owner.
-  if (!delegate_)
-    return;
-
   // TODO(shess): It may be appropriate to close the window if
   // |contents| or |zoomController| are NULL.  But they can be NULL in
   // tests.
@@ -175,11 +169,8 @@
 }
 
 - (void)windowWillClose:(NSNotification*)notification {
-  // |delegate_| may be set null by this object's owner.
-  if (delegate_) {
-    delegate_->OnClose();
-    delegate_ = NULL;
-  }
+  delegate_->OnClose();
+  delegate_ = NULL;
   [NSObject cancelPreviousPerformRequestsWithTarget:self
                                            selector:@selector(autoCloseBubble)
                                              object:nil];
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index dbc7b22..151ae0e 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -619,26 +619,20 @@
   BrowserList::SetLastActive(browser_.get());
   [self saveWindowPositionIfNeeded];
 
-  // TODO(dmaclach): Instead of redrawing the whole window, views that care
-  // about the active window state should be registering for notifications.
-  [[self window] setViewsNeedDisplay:YES];
-
-  // TODO(viettrungluu): For some reason, the above doesn't suffice.
-  if ([self isInAnyFullscreenMode])
-    [floatingBarBackingView_ setNeedsDisplay:YES];  // Okay even if nil.
+  [[[self window] contentView] cr_recursivelyInvokeBlock:^(id view) {
+      if ([view conformsToProtocol:@protocol(ThemedWindowDrawing)])
+        [view windowDidChangeActive];
+  }];
 
   extensions::ExtensionCommandsGlobalRegistry::Get(browser_->profile())
       ->set_registry_for_active_window(extension_keybinding_registry_.get());
 }
 
 - (void)windowDidResignMain:(NSNotification*)notification {
-  // TODO(dmaclach): Instead of redrawing the whole window, views that care
-  // about the active window state should be registering for notifications.
-  [[self window] setViewsNeedDisplay:YES];
-
-  // TODO(viettrungluu): For some reason, the above doesn't suffice.
-  if ([self isInAnyFullscreenMode])
-    [floatingBarBackingView_ setNeedsDisplay:YES];  // Okay even if nil.
+  [[[self window] contentView] cr_recursivelyInvokeBlock:^(id view) {
+      if ([view conformsToProtocol:@protocol(ThemedWindowDrawing)])
+        [view windowDidChangeActive];
+  }];
 
   extensions::ExtensionCommandsGlobalRegistry::Get(browser_->profile())
       ->set_registry_for_active_window(nullptr);
@@ -1702,7 +1696,15 @@
 }
 
 - (void)userChangedTheme {
-  [[[[self window] contentView] superview] cr_recursivelySetNeedsDisplay:YES];
+  NSView* rootView = [[[self window] contentView] superview];
+  [rootView cr_recursivelyInvokeBlock:^(id view) {
+      if ([view conformsToProtocol:@protocol(ThemedWindowDrawing)])
+        [view windowDidChangeTheme];
+
+      // TODO(andresantoso): Remove this once all themed views respond to
+      // windowDidChangeTheme above.
+      [view setNeedsDisplay:YES];
+  }];
 }
 
 - (ui::ThemeProvider*)themeProvider {
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.h b/chrome/browser/ui/cocoa/download/download_item_button.h
index ecc2ee3..e012491 100644
--- a/chrome/browser/ui/cocoa/download/download_item_button.h
+++ b/chrome/browser/ui/cocoa/download/download_item_button.h
@@ -6,12 +6,14 @@
 
 #include "base/files/file_path.h"
 #import "chrome/browser/ui/cocoa/draggable_button.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
 
 @class DownloadItemController;
 
 // A button that is a drag source for a file and that displays a context menu
 // instead of firing an action when clicked in a certain area.
-@interface DownloadItemButton : DraggableButton<NSMenuDelegate> {
+@interface DownloadItemButton
+    : DraggableButton<NSMenuDelegate, ThemedWindowDrawing> {
  @private
   base::FilePath downloadPath_;
   DownloadItemController* controller_;  // weak
diff --git a/chrome/browser/ui/cocoa/download/download_item_button.mm b/chrome/browser/ui/cocoa/download/download_item_button.mm
index 7c88b1d1..141976df 100644
--- a/chrome/browser/ui/cocoa/download/download_item_button.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_button.mm
@@ -74,4 +74,14 @@
   [super drawRect:rect];
 }
 
+// ThemedWindowDrawing implementation.
+
+- (void)windowDidChangeTheme {
+  [self setNeedsDisplay:YES];
+}
+
+- (void)windowDidChangeActive {
+  [self setNeedsDisplay:YES];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/download/download_show_all_button.h b/chrome/browser/ui/cocoa/download/download_show_all_button.h
index ceb51f6..6e1afe1 100644
--- a/chrome/browser/ui/cocoa/download/download_show_all_button.h
+++ b/chrome/browser/ui/cocoa/download/download_show_all_button.h
@@ -4,7 +4,9 @@
 
 #import <Cocoa/Cocoa.h>
 
+#import "chrome/browser/ui/cocoa/themed_window.h"
+
 // The "Show All" button on the download shelf. This is a subclass for custom
 // -sizeToFit logic.
-@interface DownloadShowAllButton : NSButton
+@interface DownloadShowAllButton : NSButton<ThemedWindowDrawing>
 @end
diff --git a/chrome/browser/ui/cocoa/download/download_show_all_button.mm b/chrome/browser/ui/cocoa/download/download_show_all_button.mm
index 12201122..6a91543 100644
--- a/chrome/browser/ui/cocoa/download/download_show_all_button.mm
+++ b/chrome/browser/ui/cocoa/download/download_show_all_button.mm
@@ -48,4 +48,14 @@
   [super drawRect:rect];
 }
 
+// ThemedWindowDrawing implementation.
+
+- (void)windowDidChangeTheme {
+  [self setNeedsDisplay:YES];
+}
+
+- (void)windowDidChangeActive {
+  [self setNeedsDisplay:YES];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view.h b/chrome/browser/ui/cocoa/floating_bar_backing_view.h
index 9240d063..bfd4114 100644
--- a/chrome/browser/ui/cocoa/floating_bar_backing_view.h
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view.h
@@ -7,8 +7,10 @@
 
 #import <Cocoa/Cocoa.h>
 
+#import "chrome/browser/ui/cocoa/themed_window.h"
+
 // A custom view that draws the tab strip background for fullscreen windows.
-@interface FloatingBarBackingView : NSView
+@interface FloatingBarBackingView : NSView<ThemedWindowDrawing>
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_FLOATING_BAR_BACKING_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
index 8e54948..96a5fff 100644
--- a/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
@@ -45,4 +45,14 @@
     ui::WindowTitlebarReceivedDoubleClick([self window], self);
 }
 
+// ThemedWindowDrawing implementation.
+
+- (void)windowDidChangeTheme {
+  [self setNeedsDisplay:YES];
+}
+
+- (void)windowDidChangeActive {
+  [self setNeedsDisplay:YES];
+}
+
 @end  // @implementation FloatingBarBackingView
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
index db09902..90ef008 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
@@ -33,7 +33,6 @@
 
   // Shows the zoom bubble for this decoration. If |auto_close| is YES, then
   // the bubble will automatically close after a fixed period of time.
-  // If a bubble is already showing, the |auto_close| timer is reset.
   void ShowBubble(BOOL auto_close);
 
   // Closes the zoom bubble.
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
index 3db743d..7306dd1 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
@@ -23,7 +23,6 @@
 
 ZoomDecoration::~ZoomDecoration() {
   [bubble_ closeWithoutAnimation];
-  bubble_.delegate = nil;
 }
 
 bool ZoomDecoration::UpdateIfNecessary(
@@ -49,11 +48,8 @@
 }
 
 void ZoomDecoration::ShowBubble(BOOL auto_close) {
-  if (bubble_) {
-    bubble_.delegate = nil;
-    [bubble_.window orderOut:nil];
-    [bubble_ closeWithoutAnimation];
-  }
+  if (bubble_)
+    return;
 
   content::WebContents* web_contents = owner_->GetWebContents();
   if (!web_contents)
@@ -142,7 +138,6 @@
 }
 
 void ZoomDecoration::OnClose() {
-  bubble_.delegate = nil;
   bubble_ = nil;
 
   // If the page is at default zoom then hiding the zoom decoration
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
index b86fd554..cc43140 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -25,7 +25,6 @@
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/profiles/profiles_state.h"
-#include "chrome/browser/signin/local_auth.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_header_helper.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index c08665e..f309e443 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -276,9 +276,6 @@
   return NO;
 }
 
-- (void)drawRect:(NSRect)rect {
-}
-
 - (id)initWithFrame:(NSRect)frameRect
          controller:(TabStripController*)controller {
   if ((self = [super initWithFrame:frameRect])) {
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.h b/chrome/browser/ui/cocoa/tabs/tab_strip_view.h
index c919671..931ad3f 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.h
@@ -8,7 +8,7 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/background_gradient_view.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
 #import "chrome/browser/ui/cocoa/url_drop_target.h"
 
 @class NewTabButton;
@@ -17,7 +17,7 @@
 // A view class that handles rendering the tab strip and drops of URLS with
 // a positioning locator for drop feedback.
 
-@interface TabStripView : BackgroundGradientView<URLDropTarget> {
+@interface TabStripView : NSView<ThemedWindowDrawing, URLDropTarget> {
  @private
   TabStripController* controller_;  // Weak; owns us.
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
index e3ccd72..c2951e43 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
@@ -64,8 +64,8 @@
 
     // Themes don't have an inactive image so only look for one if there's no
     // theme.
-    bool active = [[self window] isKeyWindow] || [[self window] isMainWindow] ||
-                  !themeProvider->UsingDefaultTheme();
+    bool active =
+        [[self window] isMainWindow] || !themeProvider->UsingDefaultTheme();
     int resource_id = active ? IDR_THEME_TOOLBAR : IDR_THEME_TOOLBAR_INACTIVE;
     [themeProvider->GetNSImageColorNamed(resource_id) set];
     NSRectFill(
@@ -81,7 +81,7 @@
   borderRect.size.height = [image size].height;
   borderRect.origin.y = 0;
 
-  BOOL focused = [[self window] isKeyWindow] || [[self window] isMainWindow];
+  BOOL focused = [[self window] isMainWindow];
   NSDrawThreePartImage(borderRect, nil, image, nil, /*vertical=*/ NO,
                        NSCompositeSourceOver,
                        focused ?  1.0 : tabs::kImageNoFocusAlpha,
@@ -296,4 +296,14 @@
   controller_ = controller;
 }
 
+// ThemedWindowDrawing implementation.
+
+- (void)windowDidChangeTheme {
+  [self setNeedsDisplay:YES];
+}
+
+- (void)windowDidChangeActive {
+  [self setNeedsDisplay:YES];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.h b/chrome/browser/ui/cocoa/tabs/tab_view.h
index a307bab..e549e0c 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.h
@@ -11,6 +11,7 @@
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_nsobject.h"
 #import "chrome/browser/ui/cocoa/hover_close_button.h"
+#import "chrome/browser/ui/cocoa/themed_window.h"
 
 namespace tabs {
 
@@ -42,7 +43,7 @@
 // on the tab strip. Relies on an associated TabController to provide a
 // target/action for selecting the tab.
 
-@interface TabView : NSView {
+@interface TabView : NSView<ThemedWindowDrawing> {
  @private
   TabController* controller_;
   base::scoped_nsobject<NSTextField> titleView_;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index 640e194..34acb5c 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -314,8 +314,8 @@
 
   // Themes don't have an inactive image so only look for one if there's no
   // theme.
-  bool active = [[self window] isKeyWindow] || [[self window] isMainWindow] ||
-                !themeProvider->UsingDefaultTheme();
+  bool active =
+      [[self window] isMainWindow] || !themeProvider->UsingDefaultTheme();
   return themeProvider->GetNSImageColorNamed(bitmapResources[active][selected]);
 }
 
@@ -429,7 +429,7 @@
 
 // Draws the tab outline.
 - (void)drawStroke:(NSRect)dirtyRect {
-  BOOL focused = [[self window] isKeyWindow] || [[self window] isMainWindow];
+  BOOL focused = [[self window] isMainWindow];
   CGFloat alpha = focused ? 1.0 : tabs::kImageNoFocusAlpha;
 
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
@@ -641,6 +641,16 @@
   return VIEW_ID_TAB;
 }
 
+// ThemedWindowDrawing implementation.
+
+- (void)windowDidChangeTheme {
+  [self setNeedsDisplay:YES];
+}
+
+- (void)windowDidChangeActive {
+  [self setNeedsDisplay:YES];
+}
+
 @end  // @implementation TabView
 
 @implementation TabView (TabControllerInterface)
diff --git a/chrome/browser/ui/cocoa/themed_window.h b/chrome/browser/ui/cocoa/themed_window.h
index 592e5672..ab4b18c 100644
--- a/chrome/browser/ui/cocoa/themed_window.h
+++ b/chrome/browser/ui/cocoa/themed_window.h
@@ -32,7 +32,6 @@
 };
 
 // Implemented by windows that support theming.
-
 @interface NSWindow (ThemeProvider)
 - (ThemeProvider*)themeProvider;
 - (ThemedWindowStyle)themedWindowStyle;
@@ -45,4 +44,17 @@
 - (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment;
 @end
 
+// Adopted by views that want to redraw when the theme changed, or when the
+// window's active status changed.
+@protocol ThemedWindowDrawing
+
+// Called by the window controller when the theme changed.
+- (void)windowDidChangeTheme;
+
+// Called by the window controller when the window gained or lost main window
+// status.
+- (void)windowDidChangeActive;
+
+@end
+
 #endif  // CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm
index f4ef84d8..3034b38 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm
@@ -7,6 +7,7 @@
 #import "chrome/browser/ui/cocoa/themed_window.h"
 #import "chrome/browser/ui/cocoa/view_id_util.h"
 #import "ui/base/cocoa/nsgraphics_context_additions.h"
+#import "ui/base/cocoa/nsview_additions.h"
 
 @implementation ToolbarView
 
@@ -48,4 +49,11 @@
   return YES;
 }
 
+// ThemedWindowDrawing overrides.
+
+- (void)windowDidChangeActive {
+  // Need to redraw the omnibox and toolbar buttons as well.
+  [self cr_recursivelySetNeedsDisplay:YES];
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/web_dialog_window_controller.mm b/chrome/browser/ui/cocoa/web_dialog_window_controller.mm
index 2c9f2db..b66c86c 100644
--- a/chrome/browser/ui/cocoa/web_dialog_window_controller.mm
+++ b/chrome/browser/ui/cocoa/web_dialog_window_controller.mm
@@ -67,7 +67,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   void LoadingStateChanged(content::WebContents* source,
@@ -225,15 +225,15 @@
     content::WebContents* source,
     content::WebContents* new_contents,
     WindowOpenDisposition disposition,
-    const gfx::Rect& initial_pos,
+    const gfx::Rect& initial_rect,
     bool user_gesture,
     bool* was_blocked) {
   if (delegate_ && delegate_->HandleAddNewContents(
-          source, new_contents, disposition, initial_pos, user_gesture)) {
+          source, new_contents, disposition, initial_rect, user_gesture)) {
     return;
   }
   WebDialogWebContentsDelegate::AddNewContents(
-      source, new_contents, disposition, initial_pos, user_gesture,
+      source, new_contents, disposition, initial_rect, user_gesture,
       was_blocked);
 }
 
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index 0b55989..f2d1ce3 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -288,7 +288,8 @@
   if (popup_host_) {
     // Lazily register for notifications about extension host destructions.
     static const int kType = extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED;
-    content::Source<content::BrowserContext> source(browser_->profile());
+    content::Source<content::BrowserContext> source(
+        browser_->profile()->GetOriginalProfile());
     if (!registrar_.IsRegistered(this, kType, source))
       registrar_.Add(this, kType, source);
 
diff --git a/chrome/browser/ui/navigation_correction_tab_observer.cc b/chrome/browser/ui/navigation_correction_tab_observer.cc
index d59f3e9e..6be6a9f 100644
--- a/chrome/browser/ui/navigation_correction_tab_observer.cc
+++ b/chrome/browser/ui/navigation_correction_tab_observer.cc
@@ -7,9 +7,9 @@
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/google/google_profile_helper.h"
 #include "chrome/browser/google/google_url_tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/render_messages.h"
 #include "components/google/core/browser/google_util.h"
@@ -95,13 +95,12 @@
 void NavigationCorrectionTabObserver::UpdateNavigationCorrectionInfo(
     RenderViewHost* rvh) {
   RenderFrameHost* rfh = rvh->GetMainFrame();
+  GURL google_base_url(UIThreadSearchTermsData(profile_).GoogleBaseURLValue());
   rfh->Send(new ChromeViewMsg_SetNavigationCorrectionInfo(
       rfh->GetRoutingID(),
       GetNavigationCorrectionURL(),
       google_util::GetGoogleLocale(g_browser_process->GetApplicationLocale()),
-      google_util::GetGoogleCountryCode(
-          google_profile_helper::GetGoogleHomePageURL(profile_)),
+      google_util::GetGoogleCountryCode(google_base_url),
       google_apis::GetAPIKey(),
-      google_util::GetGoogleSearchURL(
-          google_profile_helper::GetGoogleHomePageURL(profile_))));
+      google_util::GetGoogleSearchURL(google_base_url)));
 }
diff --git a/chrome/browser/ui/panels/panel_host.cc b/chrome/browser/ui/panels/panel_host.cc
index c3353cf..e1113d8 100644
--- a/chrome/browser/ui/panels/panel_host.cc
+++ b/chrome/browser/ui/panels/panel_host.cc
@@ -138,7 +138,7 @@
 void PanelHost::AddNewContents(content::WebContents* source,
                                content::WebContents* new_contents,
                                WindowOpenDisposition disposition,
-                               const gfx::Rect& initial_pos,
+                               const gfx::Rect& initial_rect,
                                bool user_gesture,
                                bool* was_blocked) {
   chrome::NavigateParams navigate_params(profile_, new_contents->GetURL(),
@@ -150,7 +150,7 @@
   navigate_params.disposition =
       disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
 
-  navigate_params.window_bounds = initial_pos;
+  navigate_params.window_bounds = initial_rect;
   navigate_params.user_gesture = user_gesture;
   navigate_params.extension_app_id = panel_->extension_id();
   chrome::Navigate(&navigate_params);
diff --git a/chrome/browser/ui/panels/panel_host.h b/chrome/browser/ui/panels/panel_host.h
index 960aa17..ccca8415 100644
--- a/chrome/browser/ui/panels/panel_host.h
+++ b/chrome/browser/ui/panels/panel_host.h
@@ -56,7 +56,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   void ActivateContents(content::WebContents* contents) override;
diff --git a/chrome/browser/ui/screen_capture_notification_ui_stub.cc b/chrome/browser/ui/screen_capture_notification_ui_stub.cc
index 18dafa2d..0eab3ee9 100644
--- a/chrome/browser/ui/screen_capture_notification_ui_stub.cc
+++ b/chrome/browser/ui/screen_capture_notification_ui_stub.cc
@@ -10,10 +10,9 @@
 class ScreenCaptureNotificationUIStub : public ScreenCaptureNotificationUI {
  public:
   ScreenCaptureNotificationUIStub() {}
-  virtual ~ScreenCaptureNotificationUIStub() {}
+  ~ScreenCaptureNotificationUIStub() override {}
 
-  virtual gfx::NativeViewId OnStarted(const base::Closure& stop_callback)
-      override {
+  gfx::NativeViewId OnStarted(const base::Closure& stop_callback) override {
     NOTIMPLEMENTED();
     return 0;
   }
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 238fdb5a..50e42fa 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -600,6 +600,11 @@
     silent_launch = true;
   }
 
+  // If --no-startup-window is specified and Chrome is already running then do
+  // not open a new window.
+  if (!process_startup && command_line.HasSwitch(switches::kNoStartupWindow))
+    silent_launch = true;
+
   // If we don't want to launch a new browser window or tab we are done here.
   if (silent_launch)
     return true;
diff --git a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc
index be34584..fcc3f7a 100644
--- a/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc
+++ b/chrome/browser/ui/views/extensions/extension_action_platform_delegate_views.cc
@@ -69,6 +69,10 @@
   DCHECK(!popup_);  // We should never have a visible popup at shutdown.
   if (context_menu_owner == this)
     context_menu_owner = nullptr;
+  // Since the popup close process is asynchronous, it might not be fully closed
+  // at shutdown. We still need to cleanup, though.
+  if (popup_)
+    CleanupPopup(true);
   UnregisterCommand(false);
 }
 
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index f511213..cd9b39d6 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -64,6 +64,7 @@
 #include "components/search_engines/template_url_service.h"
 #include "components/translate/core/browser/language_state.h"
 #include "components/ui/zoom/zoom_controller.h"
+#include "components/ui/zoom/zoom_event_manager.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
@@ -193,6 +194,9 @@
 
   if (browser_)
     browser_->search_model()->AddObserver(this);
+
+  ui_zoom::ZoomEventManager::GetForBrowserContext(profile)
+      ->AddZoomEventManagerObserver(this);
 }
 
 LocationBarView::~LocationBarView() {
@@ -200,6 +204,9 @@
     template_url_service_->RemoveObserver(this);
   if (browser_)
     browser_->search_model()->RemoveObserver(this);
+
+  ui_zoom::ZoomEventManager::GetForBrowserContext(profile())
+      ->RemoveZoomEventManagerObserver(this);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1153,6 +1160,10 @@
   return was_visible != zoom_view_->visible();
 }
 
+void LocationBarView::OnDefaultZoomLevelChanged() {
+  RefreshZoomView();
+}
+
 void LocationBarView::RefreshTranslateIcon() {
   if (!TranslateService::IsTranslateBubbleEnabled())
     return;
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 17385d9..38fa64d1 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/views/extensions/extension_popup.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_view_views.h"
 #include "components/search_engines/template_url_service_observer.h"
+#include "components/ui/zoom/zoom_event_manager_observer.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/geometry/rect.h"
@@ -83,7 +84,8 @@
                         public DropdownBarHostDelegate,
                         public gfx::AnimationDelegate,
                         public TemplateURLServiceObserver,
-                        public SearchModelObserver {
+                        public SearchModelObserver,
+                        public ui_zoom::ZoomEventManagerObserver {
  public:
   // The location bar view's class name.
   static const char kViewClassName[];
@@ -259,6 +261,10 @@
   ToolbarModel* GetToolbarModel() override;
   content::WebContents* GetWebContents() override;
 
+  // ZoomEventManagerObserver:
+  // Updates the view for the zoom icon when default zoom levels change.
+  void OnDefaultZoomLevelChanged() override;
+
   // Thickness of the edges of the omnibox background images, in normal mode.
   static const int kNormalEdgeThickness;
   // The same, but for popup mode.
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 86f0e2a..188dc8c7 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/profiles/profiles_state.h"
-#include "chrome/browser/signin/local_auth.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_header_helper.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
diff --git a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
index f27a5dd..10187367 100644
--- a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
+++ b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
@@ -119,6 +119,7 @@
       *accel = ui::Accelerator(ui::VKEY_R, ui::EF_CONTROL_DOWN);
       return true;
 
+    case IDC_CONTENT_CONTEXT_SAVEAVAS:
     case IDC_SAVE_PAGE:
       *accel = ui::Accelerator(ui::VKEY_S, ui::EF_CONTROL_DOWN);
       return true;
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
index ca1bec93..286863e4 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
@@ -22,8 +22,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/test/test_utils.h"
@@ -54,6 +52,7 @@
     file_selected_ = true;
     path_ = path;
     params_ = params;
+    QuitMessageLoop();
   }
   void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& selected_file_info,
                                  int index,
@@ -61,17 +60,31 @@
     FileSelected(selected_file_info.local_path, index, params);
   }
   void MultiFilesSelected(const std::vector<base::FilePath>& files,
-                          void* params) override {}
+                          void* params) override {
+    QuitMessageLoop();
+  }
   void FileSelectionCanceled(void* params) override {
     canceled_ = true;
     params_ = params;
+    QuitMessageLoop();
+  }
+
+  void WaitForCalled() {
+    message_loop_runner_ = new content::MessageLoopRunner();
+    message_loop_runner_->Run();
   }
 
  private:
+  void QuitMessageLoop() {
+    if (message_loop_runner_.get())
+      message_loop_runner_->Quit();
+  }
+
   bool file_selected_;
   bool canceled_;
   base::FilePath path_;
   void* params_;
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(MockSelectFileDialogListener);
 };
@@ -190,9 +203,6 @@
                    const gfx::NativeWindow& owning_window) {
     // Inject JavaScript to click the cancel button and wait for notification
     // that the window has closed.
-    content::WindowedNotificationObserver host_destroyed(
-        content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
-        content::NotificationService::AllSources());
     content::RenderViewHost* host = dialog_->GetRenderViewHost();
     std::string button_class =
         (button_type == DIALOG_BTN_OK) ? ".button-panel .ok" :
@@ -204,7 +214,7 @@
     // to JavaScript, so do not wait for return values.
     host->GetMainFrame()->ExecuteJavaScript(script);
     LOG(INFO) << "Waiting for window close notification.";
-    host_destroyed.Wait();
+    listener_->WaitForCalled();
 
     // Dialog no longer believes it is running.
     ASSERT_FALSE(dialog_->IsRunning(owning_window));
diff --git a/chrome/browser/ui/webui/app_list/OWNERS b/chrome/browser/ui/webui/app_list/OWNERS
new file mode 100644
index 0000000..2aebc091
--- /dev/null
+++ b/chrome/browser/ui/webui/app_list/OWNERS
@@ -0,0 +1,3 @@
+calamity@chromium.org
+mgiuca@chromium.org
+tapted@chromium.org
diff --git a/chrome/browser/ui/webui/app_list/start_page_browsertest.js b/chrome/browser/ui/webui/app_list/start_page_browsertest.js
index 9cdecbb..eb2099e 100644
--- a/chrome/browser/ui/webui/app_list/start_page_browsertest.js
+++ b/chrome/browser/ui/webui/app_list/start_page_browsertest.js
@@ -123,6 +123,43 @@
   assertEquals(this.browsePreload, document.location.href);
 });
 
+TEST_F('AppListStartPageWebUITest', 'LoadDoodle', function() {
+  var doodleData = {
+    'ddljson': {
+      'transparent_large_image': {
+        'url': 'doodle.png'
+      },
+      'alt_text': 'Doodle alt text',
+      'target_url': '/target.html'
+    }
+  };
+
+  assertEquals(null, $('doodle'));
+
+  // Load the doodle with a target url and alt text.
+  appList.startPage.onAppListDoodleUpdated(doodleData,
+                                           'http://example.com/x/');
+  assertNotEquals(null, $('doodle'));
+  assertEquals('http://example.com/x/doodle.png', $('doodle_image').src);
+  assertEquals(doodleData.ddljson.alt_text, $('doodle_image').title);
+  assertEquals('http://example.com/target.html', $('doodle_link').href);
+
+  // Reload the doodle without a target url and alt text.
+  doodleData.ddljson.alt_text = undefined;
+  doodleData.ddljson.target_url = undefined;
+  appList.startPage.onAppListDoodleUpdated(doodleData,
+                                           'http://example.com/x/');
+  assertNotEquals(null, $('doodle'));
+  assertEquals('http://example.com/x/doodle.png', $('doodle_image').src);
+  assertEquals('', $('doodle_image').title);
+  assertEquals(null, $('doodle_link'));
+
+
+  appList.startPage.onAppListDoodleUpdated({},
+                                           'http://example.com/');
+  assertEquals(null, $('doodle'));
+});
+
 TEST_F('AppListStartPageWebUITest', 'SpeechRecognitionState', function() {
   this.mockHandler.expects(once()).setSpeechRecognitionState('READY');
   appList.startPage.onAppListShown();
diff --git a/chrome/browser/ui/webui/chrome_web_contents_handler.cc b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
index c733afe..9b21e21 100644
--- a/chrome/browser/ui/webui/chrome_web_contents_handler.cc
+++ b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
@@ -72,15 +72,15 @@
 // Creates a new tab with |new_contents|. |context| is the browser context that
 // the browser should be owned by. |source| is the WebContent where the
 // operation originated. |disposition| controls how the new tab should be
-// opened. |initial_pos| is the position of the window if a new window is
-// created.  |user_gesture| is true if the operation was started by a user
+// opened. |initial_rect| is the position and size of the window if a new window
+// is created.  |user_gesture| is true if the operation was started by a user
 // gesture.
 void ChromeWebContentsHandler::AddNewContents(
     content::BrowserContext* context,
     WebContents* source,
     WebContents* new_contents,
     WindowOpenDisposition disposition,
-    const gfx::Rect& initial_pos,
+    const gfx::Rect& initial_rect,
     bool user_gesture) {
   if (!context)
     return;
@@ -102,7 +102,7 @@
   chrome::NavigateParams params(browser, new_contents);
   params.source_contents = source;
   params.disposition = disposition;
-  params.window_bounds = initial_pos;
+  params.window_bounds = initial_rect;
   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
   params.user_gesture = true;
   chrome::Navigate(&params);
diff --git a/chrome/browser/ui/webui/chrome_web_contents_handler.h b/chrome/browser/ui/webui/chrome_web_contents_handler.h
index c0a084b..2755a16 100644
--- a/chrome/browser/ui/webui/chrome_web_contents_handler.h
+++ b/chrome/browser/ui/webui/chrome_web_contents_handler.h
@@ -23,7 +23,7 @@
                       content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture) override;
 
  private:
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index f22a6906..a6678216 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
+#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/policy/consumer_management_service.h"
 #include "chrome/browser/chromeos/policy/consumer_management_stage.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -79,7 +80,7 @@
     message_id = IDS_CREATE_SUPERVISED_USER_CREATION_RESTRICTED_TEXT;
   }
   if (supervised_users_can_create &&
-      user_manager::UserManager::Get()
+      ChromeUserManager::Get()
           ->GetUsersAllowedForSupervisedUsersCreation()
           .empty()) {
     supervised_users_can_create = false;
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 7ad3e72..44de6a9 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -405,10 +405,6 @@
   return core_handler_;
 }
 
-UpdateScreenActor* OobeUI::GetUpdateScreenActor() {
-  return update_screen_handler_;
-}
-
 NetworkView* OobeUI::GetNetworkView() {
   return network_view_;
 }
@@ -417,6 +413,10 @@
   return eula_view_;
 }
 
+UpdateView* OobeUI::GetUpdateView() {
+  return update_screen_handler_;
+}
+
 EnableDebuggingScreenActor* OobeUI::GetEnableDebuggingScreenActor() {
   return debugging_screen_actor_;
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
index 02085325..888d9ca 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -100,9 +100,9 @@
 
   // OobeDisplay implementation:
   CoreOobeActor* GetCoreOobeActor() override;
-  UpdateScreenActor* GetUpdateScreenActor() override;
   NetworkView* GetNetworkView() override;
   EulaView* GetEulaView() override;
+  UpdateView* GetUpdateView() override;
   EnableDebuggingScreenActor* GetEnableDebuggingScreenActor() override;
   EnrollmentScreenActor* GetEnrollmentScreenActor() override;
   ResetScreenActor* GetResetScreenActor() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc b/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc
index 34925a6..2846abd 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/compiler_specific.h"
 #include "chrome/browser/chromeos/login/screens/user_selection_screen.h"
-#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller_delegate.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
@@ -35,9 +35,8 @@
       public MultiProfileUserControllerDelegate {
  public:
   SigninPrepareUserListTest()
-      : fake_user_manager_(new FakeUserManager()),
-        user_manager_enabler_(fake_user_manager_) {
-  }
+      : fake_user_manager_(new FakeChromeUserManager()),
+        user_manager_enabler_(fake_user_manager_) {}
 
   ~SigninPrepareUserListTest() override {}
 
@@ -66,7 +65,7 @@
   // MultiProfileUserControllerDelegate overrides:
   void OnUserNotAllowed(const std::string& user_email) override {}
 
-  FakeUserManager* fake_user_manager_;
+  FakeChromeUserManager* fake_user_manager_;
   ScopedUserManagerEnabler user_manager_enabler_;
   scoped_ptr<TestingProfileManager> profile_manager_;
   std::map<std::string,
diff --git a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
index 0bb7b32a..7f0ad01 100644
--- a/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/supervised_user_creation_screen_handler.cc
@@ -211,8 +211,7 @@
   scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
   scoped_ptr<base::ListValue> users_list(new base::ListValue());
   const user_manager::UserList& users =
-      user_manager::UserManager::Get()
-          ->GetUsersAllowedForSupervisedUsersCreation();
+      ChromeUserManager::Get()->GetUsersAllowedForSupervisedUsersCreation();
   std::string owner;
   chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
 
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
index be62834..1818dea 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/login/screens/update_model.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -20,14 +21,12 @@
 namespace chromeos {
 
 UpdateScreenHandler::UpdateScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      screen_(NULL),
-      show_on_init_(false) {
+    : BaseScreenHandler(kJsScreenPath), model_(nullptr), show_on_init_(false) {
 }
 
 UpdateScreenHandler::~UpdateScreenHandler() {
-  if (screen_)
-    screen_->OnActorDestroyed(this);
+  if (model_)
+    model_->OnViewDestroyed(this);
 }
 
 void UpdateScreenHandler::DeclareLocalizedValues(
@@ -62,8 +61,7 @@
   }
 }
 
-void UpdateScreenHandler::SetDelegate(UpdateScreenActor::Delegate* screen) {
-  screen_ = screen;
+void UpdateScreenHandler::PrepareToShow() {
 }
 
 void UpdateScreenHandler::Show() {
@@ -72,79 +70,24 @@
     return;
   }
   ShowScreen(OobeUI::kScreenOobeUpdate, NULL);
-#if !defined(OFFICIAL_BUILD)
-  CallJS("enableUpdateCancel");
-#endif
 }
 
 void UpdateScreenHandler::Hide() {
 }
 
-void UpdateScreenHandler::PrepareToShow() {
+void UpdateScreenHandler::Bind(UpdateModel& model) {
+  model_ = &model;
+  BaseScreenHandler::SetBaseScreen(model_);
 }
 
-void UpdateScreenHandler::ShowManualRebootInfo() {
-  CallJS("setUpdateMessage", l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED));
-}
-
-void UpdateScreenHandler::SetProgress(int progress) {
-  CallJS("setUpdateProgress", progress);
-}
-
-void UpdateScreenHandler::ShowEstimatedTimeLeft(bool visible) {
-  CallJS("showEstimatedTimeLeft", visible);
-}
-
-void UpdateScreenHandler::SetEstimatedTimeLeft(const base::TimeDelta& time) {
-  CallJS("setEstimatedTimeLeft", time.InSecondsF());
-}
-
-void UpdateScreenHandler::ShowProgressMessage(bool visible) {
-  CallJS("showProgressMessage", visible);
-}
-
-void UpdateScreenHandler::SetProgressMessage(ProgressMessage message) {
-  int ids = 0;
-  switch (message) {
-    case PROGRESS_MESSAGE_UPDATE_AVAILABLE:
-      ids = IDS_UPDATE_AVAILABLE;
-      break;
-    case PROGRESS_MESSAGE_INSTALLING_UPDATE:
-      ids = IDS_INSTALLING_UPDATE;
-      break;
-    case PROGRESS_MESSAGE_VERIFYING:
-      ids = IDS_UPDATE_VERIFYING;
-      break;
-    case PROGRESS_MESSAGE_FINALIZING:
-      ids = IDS_UPDATE_FINALIZING;
-      break;
-    default:
-      NOTREACHED();
-      return;
-  }
-
-  CallJS("setProgressMessage", l10n_util::GetStringUTF16(ids));
-}
-
-void UpdateScreenHandler::ShowCurtain(bool visible) {
-  CallJS("showUpdateCurtain", visible);
-}
-
-void UpdateScreenHandler::RegisterMessages() {
-#if !defined(OFFICIAL_BUILD)
-  AddCallback("cancelUpdate", &UpdateScreenHandler::HandleUpdateCancel);
-#endif
+void UpdateScreenHandler::Unbind() {
+  model_ = nullptr;
+  BaseScreenHandler::SetBaseScreen(nullptr);
 }
 
 void UpdateScreenHandler::OnConnectToNetworkRequested() {
-  if (screen_)
-    screen_->OnConnectToNetworkRequested();
+  if (model_)
+    model_->OnConnectToNetworkRequested();
 }
 
-#if !defined(OFFICIAL_BUILD)
-void UpdateScreenHandler::HandleUpdateCancel() {
-  screen_->CancelUpdate();
-}
-#endif
-
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
index 92f20b0..88c1454 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
@@ -8,49 +8,35 @@
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "chrome/browser/chromeos/login/screens/update_screen_actor.h"
+#include "chrome/browser/chromeos/login/screens/update_view.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_dropdown_handler.h"
 
 namespace chromeos {
 
-class UpdateScreenHandler : public UpdateScreenActor,
+class UpdateScreenHandler : public UpdateView,
                             public BaseScreenHandler,
                             public NetworkDropdownHandler::Observer {
  public:
   UpdateScreenHandler();
   ~UpdateScreenHandler() override;
 
-  // BaseScreenHandler implementation:
-  void DeclareLocalizedValues(LocalizedValuesBuilder* builder) override;
-  void Initialize() override;
-
-  // UpdateScreenActor implementation:
-  void SetDelegate(UpdateScreenActor::Delegate* screen) override;
+  // UpdateView:
+  void PrepareToShow() override;
   void Show() override;
   void Hide() override;
-  void PrepareToShow() override;
-  void ShowManualRebootInfo() override;
-  void SetProgress(int progress) override;
-  void ShowEstimatedTimeLeft(bool visible) override;
-  void SetEstimatedTimeLeft(const base::TimeDelta& time) override;
-  void ShowProgressMessage(bool visible) override;
-  void SetProgressMessage(ProgressMessage message) override;
-  void ShowCurtain(bool visible) override;
+  void Bind(UpdateModel& model) override;
+  void Unbind() override;
 
-  // WebUIMessageHandler implementation:
-  void RegisterMessages() override;
+  // BaseScreenHandler:
+  void DeclareLocalizedValues(LocalizedValuesBuilder* builder) override;
+  void Initialize() override;
 
  private:
   // NetworkDropdownHandler::Observer implementation:
   void OnConnectToNetworkRequested() override;
 
-#if !defined(OFFICIAL_BUILD)
-  // Called when user presses Escape to cancel update.
-  void HandleUpdateCancel();
-#endif
-
-  UpdateScreenActor::Delegate* screen_;
+  UpdateModel* model_;
 
   // Keeps whether screen should be shown right after initialization.
   bool show_on_init_;
diff --git a/chrome/browser/ui/webui/omnibox/omnibox.mojom b/chrome/browser/ui/webui/omnibox/omnibox.mojom
index 04a3d32..5e1d7b0 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox.mojom
+++ b/chrome/browser/ui/webui/omnibox/omnibox.mojom
@@ -47,13 +47,13 @@
   array<AutocompleteResultsForProviderMojo> results_by_provider;
 };
 
-[Client=OmniboxPage]
 interface OmniboxUIHandlerMojo {
   StartOmniboxQuery(string input_string,
                     int32 cursor_position,
                     bool prevent_inline_autocomplete,
                     bool prefer_keyword,
-                    int32 page_classification);
+                    int32 page_classification,
+                    OmniboxPage page);
 };
 
 interface OmniboxPage {
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
index 2301d87..644d4b2 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
+++ b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.cc
@@ -114,7 +114,8 @@
   ResetController();
 }
 
-OmniboxUIHandler::~OmniboxUIHandler() {}
+OmniboxUIHandler::~OmniboxUIHandler() {
+}
 
 void OmniboxUIHandler::OnResultChanged(bool default_match_changed) {
   OmniboxResultMojoPtr result(OmniboxResultMojo::New());
@@ -159,7 +160,7 @@
     }
   }
 
-  client()->HandleNewAutocompleteResult(result.Pass());
+  page_->HandleNewAutocompleteResult(result.Pass());
 }
 
 bool OmniboxUIHandler::LookupIsTypedHost(const base::string16& host,
@@ -179,13 +180,15 @@
                                          int32_t cursor_position,
                                          bool prevent_inline_autocomplete,
                                          bool prefer_keyword,
-                                         int32_t page_classification) {
+                                         int32_t page_classification,
+                                         OmniboxPagePtr page) {
   // Reset the controller.  If we don't do this, then the
   // AutocompleteController might inappropriately set its |minimal_changes|
   // variable (or something else) and some providers will short-circuit
   // important logic and return stale results.  In short, we want the
   // actual results to not depend on the state of the previous request.
   ResetController();
+  page_ = page.Pass();
   time_omnibox_started_ = base::Time::Now();
   input_ = AutocompleteInput(
       input_string.To<base::string16>(), cursor_position, std::string(), GURL(),
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h
index 81763a1..c60b7b27 100644
--- a/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h
+++ b/chrome/browser/ui/webui/omnibox/omnibox_ui_handler.h
@@ -42,7 +42,8 @@
                          int32_t cursor_position,
                          bool prevent_inline_autocomplete,
                          bool prefer_keyword,
-                         int32_t page_classification) override;
+                         int32_t page_classification,
+                         OmniboxPagePtr page) override;
 
  private:
   // Looks up whether the hostname is a typed host (i.e., has received
@@ -66,6 +67,9 @@
   // The input used when starting the AutocompleteController.
   AutocompleteInput input_;
 
+  // Handle back to the page by which we can pass results.
+  OmniboxPagePtr page_;
+
   // The Profile* handed to us in our constructor.
   Profile* profile_;
 
diff --git a/chrome/browser/ui/webui/options/autofill_options_handler.cc b/chrome/browser/ui/webui/options/autofill_options_handler.cc
index f564aa3..374337b 100644
--- a/chrome/browser/ui/webui/options/autofill_options_handler.cc
+++ b/chrome/browser/ui/webui/options/autofill_options_handler.cc
@@ -332,13 +332,16 @@
                 IDS_AUTOFILL_OPTIONS_TITLE);
 
   localized_strings->SetString("helpUrl", autofill::kHelpURL);
+
+  personal_data_ = autofill::PersonalDataManagerFactory::GetForProfile(
+      Profile::FromWebUI(web_ui()));
+
   SetAddressOverlayStrings(localized_strings);
   SetCreditCardOverlayStrings(localized_strings);
 
   localized_strings->SetBoolean(
       "enableAutofillWalletIntegration",
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          autofill::switches::kEnableWalletCardImport));
+      personal_data_->IsExperimentalWalletIntegrationEnabled());
   localized_strings->SetString(
       "manageWalletAddressesUrl",
       autofill::wallet::GetManageAddressesUrl(0).spec());
@@ -359,9 +362,6 @@
 }
 
 void AutofillOptionsHandler::RegisterMessages() {
-  personal_data_ = autofill::PersonalDataManagerFactory::GetForProfile(
-      Profile::FromWebUI(web_ui()));
-
 #if defined(OS_MACOSX) && !defined(OS_IOS)
   web_ui()->RegisterMessageCallback(
       "accessAddressBook",
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 72b1c38..d00be98 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -681,11 +681,11 @@
       "showWakeOnWifi",
       chromeos::WakeOnWifiManager::Get()->WakeOnWifiSupported() &&
       chromeos::switches::WakeOnWifiEnabled());
-  const bool have_enable_time_zone_tracking_option_switch =
+  const bool have_disable_time_zone_tracking_option_switch =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kEnableTimeZoneTrackingOption);
+          chromeos::switches::kDisableTimeZoneTrackingOption);
   values->SetBoolean("enableTimeZoneTrackingOption",
-                     have_enable_time_zone_tracking_option_switch &&
+                     !have_disable_time_zone_tracking_option_switch &&
                          !chromeos::system::HasSystemTimezonePolicy());
 #endif
 }
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 335e6083..b9cf3f3 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -89,6 +89,10 @@
 #include "chrome/browser/local_discovery/privet_constants.h"
 #endif
 
+#if defined(ENABLE_EXTENSIONS)
+#include "extensions/browser/api/printer_provider/printer_provider_api.h"
+#endif
+
 using content::BrowserThread;
 using content::RenderViewHost;
 using content::WebContents;
@@ -647,6 +651,14 @@
   web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
       base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getExtensionPrinters",
+      base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinters,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "getExtensionPrinterCapabilities",
+      base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinterCapabilities,
+                 base::Unretained(this)));
   RegisterForMergeSession();
 }
 
@@ -706,6 +718,42 @@
 #endif
 }
 
+void PrintPreviewHandler::HandleGetExtensionPrinters(
+    const base::ListValue* args) {
+#if defined(ENABLE_EXTENSIONS)
+  // TODO(tbarzic): Handle case where a new search is initiated before the
+  // previous one finishes. Currently, in this case Web UI layer may get
+  // multiple events with printer list from some extensions, and it may get
+  // fooled by |done| flag from the first search into marking the search
+  // complete.
+  extensions::PrinterProviderAPI::GetFactoryInstance()
+      ->Get(preview_web_contents()->GetBrowserContext())
+      ->DispatchGetPrintersRequested(
+          base::Bind(&PrintPreviewHandler::OnGotPrintersForExtension,
+                     weak_factory_.GetWeakPtr()));
+#else
+  OnGotPrintersForExtension(base::ListValue(), true /* done */);
+#endif
+}
+
+void PrintPreviewHandler::HandleGetExtensionPrinterCapabilities(
+    const base::ListValue* args) {
+  std::string printer_id;
+  bool ok = args->GetString(0, &printer_id);
+  DCHECK(ok);
+
+#if defined(ENABLE_EXTENSIONS)
+  extensions::PrinterProviderAPI::GetFactoryInstance()
+      ->Get(preview_web_contents()->GetBrowserContext())
+      ->DispatchGetCapabilityRequested(
+          printer_id,
+          base::Bind(&PrintPreviewHandler::OnGotExtensionPrinterCapabilities,
+                     weak_factory_.GetWeakPtr(), printer_id));
+#else
+  OnGotExtensionPrinterCapabilities(printer_id, base::DictionaryValue());
+#endif
+}
+
 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
   DCHECK_EQ(3U, args->GetSize());
   scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
@@ -1588,6 +1636,26 @@
 
 #endif  // defined(ENABLE_SERVICE_DISCOVERY)
 
+void PrintPreviewHandler::OnGotPrintersForExtension(
+    const base::ListValue& printers,
+    bool done) {
+  web_ui()->CallJavascriptFunction("onExtensionPrintersAdded", printers,
+                                   base::FundamentalValue(done));
+}
+
+void PrintPreviewHandler::OnGotExtensionPrinterCapabilities(
+    const std::string& printer_id,
+    const base::DictionaryValue& capabilities) {
+  if (capabilities.empty()) {
+    web_ui()->CallJavascriptFunction("failedToGetExtensionPrinterCapabilities",
+                                     base::StringValue(printer_id));
+    return;
+  }
+
+  web_ui()->CallJavascriptFunction("onExtensionCapabilitiesSet",
+                                   base::StringValue(printer_id), capabilities);
+}
+
 void PrintPreviewHandler::RegisterForMergeSession() {
   DCHECK(!reconcilor_);
   Profile* profile = Profile::FromWebUI(web_ui());
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index cbc6e1b..f6bf882 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -124,6 +124,9 @@
   // Starts getting all local privet printers. |arg| is unused.
   void HandleGetPrivetPrinters(const base::ListValue* args);
 
+  // Starts getting all local extension managed printers. |arg| is unused.
+  void HandleGetExtensionPrinters(const base::ListValue* args);
+
   // Stops getting all local privet printers. |arg| is unused.
   void HandleStopGetPrivetPrinters(const base::ListValue* args);
 
@@ -196,6 +199,10 @@
 
   void HandleGetPrivetPrinterCapabilities(const base::ListValue* arg);
 
+  // Requests an extension managed printer's capabilities.
+  // |arg| contains the ID of the printer whose capabilities are requested.
+  void HandleGetExtensionPrinterCapabilities(const base::ListValue* args);
+
   void SendInitialSettings(const std::string& default_printer);
 
   // Send OAuth2 access token.
@@ -282,6 +289,20 @@
       base::DictionaryValue* printer_value);
 #endif
 
+  // Called when a list of printers is reported by an extension.
+  // |printers|: The list of printers managed by the extension.
+  // |done|: Whether all the extensions have reported the list of printers
+  //     they manage.
+  void OnGotPrintersForExtension(const base::ListValue& printers, bool done);
+
+  // Called when an extension reports the set of print capabilites for a
+  // printer.
+  // |printer_id|: The id of the printer whose capabilities are reported.
+  // |capabilities|: The printer capabilities.
+  void OnGotExtensionPrinterCapabilities(
+      const std::string& printer_id,
+      const base::DictionaryValue& capabilities);
+
   // Register/unregister from notifications of changes done to the GAIA
   // cookie.
   void RegisterForMergeSession();
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 308460c..d9ed6882 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -140,7 +140,7 @@
       switches::IsNewProfileManagement() &&
       !password_.empty() &&
       profiles::IsLockAvailable(profile_)) {
-    chrome::SetLocalAuthCredentials(profile_, password_);
+    LocalAuth::SetLocalAuthCredentials(profile_, password_);
   }
 
   if (source == signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ||
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
index 0ba5513e..46ad3397 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -414,7 +414,7 @@
   }
 
   authenticating_profile_index_ = profile_index;
-  if (!chrome::ValidateLocalAuthCredentials(profile_index, password)) {
+  if (!LocalAuth::ValidateLocalAuthCredentials(profile_index, password)) {
     // Make a second attempt via an on-line authentication call.  This handles
     // profiles that are missing sign-in credentials and also cases where the
     // password has been changed externally.
@@ -525,8 +525,8 @@
 
 void UserManagerScreenHandler::OnClientLoginSuccess(
     const ClientLoginResult& result) {
-  chrome::SetLocalAuthCredentials(authenticating_profile_index_,
-                                  password_attempt_);
+  LocalAuth::SetLocalAuthCredentials(authenticating_profile_index_,
+                                     password_attempt_);
   ReportAuthenticationResult(true, ProfileMetrics::AUTH_ONLINE);
 }
 
@@ -547,8 +547,8 @@
   // profile was locked.  Save the password to streamline future unlocks.
   if (success) {
     DCHECK(!password_attempt_.empty());
-    chrome::SetLocalAuthCredentials(authenticating_profile_index_,
-                                    password_attempt_);
+    LocalAuth::SetLocalAuthCredentials(authenticating_profile_index_,
+                                       password_attempt_);
   }
 
   bool offline = (state == GoogleServiceAuthError::CONNECTION_FAILED ||
@@ -728,7 +728,7 @@
         kKeyProfilePath, base::CreateFilePathValue(profile_path));
     profile_value->SetBoolean(kKeyPublicAccount, false);
     profile_value->SetBoolean(
-        kKeySupervisedUser, info_cache.ProfileIsSupervisedAtIndex(i));
+        kKeySupervisedUser, info_cache.ProfileIsLegacySupervisedAtIndex(i));
     profile_value->SetBoolean(
         kKeyChildUser, info_cache.ProfileIsChildAtIndex(i));
     profile_value->SetBoolean(
diff --git a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc
index c063a6a..c389169 100644
--- a/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc
+++ b/chrome/browser/ui/zoom/chrome_zoom_level_prefs.cc
@@ -71,6 +71,8 @@
   // set this manually.
   host_zoom_map_->SetDefaultZoomLevel(level);
   default_zoom_changed_callbacks_.Notify();
+  if (zoom_event_manager_)
+    zoom_event_manager_->OnDefaultZoomLevelChanged();
 }
 
 double ChromeZoomLevelPrefs::GetDefaultZoomLevelPref() const {
diff --git a/chrome/browser/web_dev_style/css_checker.py b/chrome/browser/web_dev_style/css_checker.py
index 5707e1a..37f19a5 100644
--- a/chrome/browser/web_dev_style/css_checker.py
+++ b/chrome/browser/web_dev_style/css_checker.py
@@ -258,18 +258,18 @@
     def webkit_before_or_after(line):
       return webkit_before_or_after_reg.search(line)
 
-    def zero_length_values(contents):
+    def zero_width_lengths(contents):
       hsl_reg = re.compile(r"""
           hsl\([^\)]*       # hsl(<maybe stuff>
           (?:[, ]|(?<=\())  # a comma or space not followed by a (
           (?:0?\.?)?0%      # some equivalent to 0%""",
           re.VERBOSE)
       zeros_reg = re.compile(r"""
-          ^.*(?:^|[^0-9.])                                 # start/non-number
-          (?:\.0|0(?:\.0?                                  # .0, 0, or 0.0
-          |px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz))  # a length unit
-          (?:\D|$)                                         # non-number/end
-          (?=[^{}]+?}).*$                                  # only { rules }""",
+          ^.*(?:^|[^0-9.])              # start/non-number
+          (?:\.0|0(?:\.0?               # .0, 0, or 0.0
+          |px|em|%|in|cm|mm|pc|pt|ex))  # a length unit
+          (?:\D|$)                      # non-number/end
+          (?=[^{}]+?}).*$               # only { rules }""",
           re.MULTILINE | re.VERBOSE)
       errors = []
       for z in re.finditer(zeros_reg, contents):
@@ -336,9 +336,8 @@
           'test': webkit_before_or_after,
           'after': suggest_top_or_bottom,
         },
-        { 'desc': 'Make all zero length terms (i.e. 0px) 0 unless inside of '
-                  'hsl() or part of @keyframe.',
-          'test': zero_length_values,
+        { 'desc': 'Use "0" for zero-width lengths (i.e. 0px -> 0)',
+          'test': zero_width_lengths,
           'multiline': True,
         },
     ]
diff --git a/chrome/browser_tests.isolate b/chrome/browser_tests.isolate
index eaf72eb8..912fbca6 100644
--- a/chrome/browser_tests.isolate
+++ b/chrome/browser_tests.isolate
@@ -12,6 +12,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -174,6 +176,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/chrome/child/BUILD.gn b/chrome/child/BUILD.gn
new file mode 100644
index 0000000..1b268f1
--- /dev/null
+++ b/chrome/child/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("child") {
+  sources = [
+    "pdf_child_init.cc",
+    "pdf_child_init.h",
+  ]
+
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+
+  deps = [
+    "//base",
+    "//content/public/child",
+  ]
+}
diff --git a/chrome/child/DEPS b/chrome/child/DEPS
new file mode 100644
index 0000000..ad94e88
--- /dev/null
+++ b/chrome/child/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+content/public/child",
+]
diff --git a/chrome/child/pdf_child_init.cc b/chrome/child/pdf_child_init.cc
new file mode 100644
index 0000000..338403cc
--- /dev/null
+++ b/chrome/child/pdf_child_init.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 "chrome/child/pdf_child_init.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "content/public/child/child_thread.h"
+
+#if defined(OS_WIN)
+#include "base/win/iat_patch_function.h"
+#endif
+
+namespace chrome {
+namespace {
+#if defined(OS_WIN)
+static base::win::IATPatchFunction g_iat_patch_createdca;
+HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
+                          LPCSTR device_name,
+                          LPCSTR output,
+                          const void* init_data) {
+  DCHECK(std::string("DISPLAY") == std::string(driver_name));
+  DCHECK(!device_name);
+  DCHECK(!output);
+  DCHECK(!init_data);
+
+  // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
+  return CreateCompatibleDC(NULL);
+}
+
+static base::win::IATPatchFunction g_iat_patch_get_font_data;
+DWORD WINAPI GetFontDataPatch(HDC hdc,
+                              DWORD table,
+                              DWORD offset,
+                              LPVOID buffer,
+                              DWORD length) {
+  int rv = GetFontData(hdc, table, offset, buffer, length);
+  if (rv == GDI_ERROR && hdc) {
+    HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
+
+    LOGFONT logfont;
+    if (GetObject(font, sizeof(LOGFONT), &logfont)) {
+      std::vector<char> font_data;
+      content::ChildThread::Get()->PreCacheFont(logfont);
+      rv = GetFontData(hdc, table, offset, buffer, length);
+      content::ChildThread::Get()->ReleaseCachedFonts();
+    }
+  }
+  return rv;
+}
+#endif  // OS_WIN
+
+}  // namespace
+
+void InitializePDF() {
+#if defined(OS_WIN)
+  // Need to patch a few functions for font loading to work correctly. This can
+  // be removed once we switch PDF to use Skia.
+  HMODULE current_module = NULL;
+  wchar_t current_module_name[MAX_PATH];
+  CHECK(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                          reinterpret_cast<LPCWSTR>(InitializePDF),
+                          &current_module));
+  DWORD result = GetModuleFileNameW(current_module, current_module_name,
+                                    MAX_PATH);
+  if (!result || result == MAX_PATH)
+    return;
+  g_iat_patch_createdca.Patch(current_module_name, "gdi32.dll", "CreateDCA",
+                              CreateDCAPatch);
+  g_iat_patch_get_font_data.Patch(current_module_name, "gdi32.dll",
+                                  "GetFontData", GetFontDataPatch);
+#endif  // OS_WIN
+}
+
+}  // namespace chrome
diff --git a/chrome/child/pdf_child_init.h b/chrome/child/pdf_child_init.h
new file mode 100644
index 0000000..1aac5c6fb
--- /dev/null
+++ b/chrome/child/pdf_child_init.h
@@ -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.
+
+#ifndef CHROME_CHILD_PDF_CHILD_INIT_H_
+#define CHROME_CHILD_PDF_CHILD_INIT_H_
+
+namespace chrome {
+
+// Initializes child-process specific code for the PDF module.
+void InitializePDF();
+
+}  // namespace chrome
+
+#endif  // CHROME_CHILD_PDF_CHILD_INIT_H_
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index ce0b5ce..639f2c83 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -32,6 +32,7 @@
           '../ppapi/ppapi_internal.gyp:ppapi_host',
         ],
         'chromium_child_dependencies': [
+          'child',
           'plugin',
           'renderer',
           'utility',
@@ -122,6 +123,7 @@
       'includes': [
         '../apps/apps.gypi',
         'app_installer/app_installer.gypi',
+        'chrome_child.gypi',
         'chrome_debugger.gypi',
         'chrome_dll.gypi',
         'chrome_exe.gypi',
@@ -604,7 +606,6 @@
             'chrome_version_java',
             'document_tab_model_info_proto_java',
             'profile_account_management_metrics_java',
-            'add_web_contents_result_java',
             'content_setting_java',
             'content_settings_type_java',
             'page_info_connection_type_java',
diff --git a/chrome/chrome.isolate b/chrome/chrome.isolate
index 9ebce299..64ae230 100644
--- a/chrome/chrome.isolate
+++ b/chrome/chrome.isolate
@@ -8,7 +8,6 @@
         'files': [
           '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
-          '<(PRODUCT_DIR)/libpdf.so',
         ],
       },
     }],
@@ -88,7 +87,6 @@
           '<(PRODUCT_DIR)/ffmpegsumo.dll',
           '<(PRODUCT_DIR)/libexif.dll',
           '<(PRODUCT_DIR)/osmesa.dll',
-          '<(PRODUCT_DIR)/pdf.dll',
         ],
       },
     }],
diff --git a/chrome/chrome_android.gypi b/chrome/chrome_android.gypi
index 7ecfda0..3c62104a9 100644
--- a/chrome/chrome_android.gypi
+++ b/chrome/chrome_android.gypi
@@ -24,6 +24,7 @@
       'dependencies': [
         'chrome.gyp:browser',
         'chrome.gyp:browser_ui',
+        'chrome.gyp:child',
         'chrome.gyp:plugin',
         'chrome.gyp:renderer',
         'chrome.gyp:utility',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 1fb6f309..d111cba 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -109,6 +109,8 @@
       'browser/android/location_settings.h',
       'browser/android/location_settings_impl.cc',
       'browser/android/location_settings_impl.h',
+      'browser/android/manifest_icon_selector.cc',
+      'browser/android/manifest_icon_selector.h',
       'browser/android/most_visited_sites.cc',
       'browser/android/most_visited_sites.h',
       'browser/android/omnibox/answers_image_bridge.cc',
@@ -141,6 +143,8 @@
       'browser/android/resource_id.h',
       'browser/android/shortcut_helper.cc',
       'browser/android/shortcut_helper.h',
+      'browser/android/shortcut_info.cc',
+      'browser/android/shortcut_info.h',
       'browser/android/signin/account_management_screen_helper.cc',
       'browser/android/signin/account_management_screen_helper.h',
       'browser/android/signin/signin_manager_android.cc',
@@ -422,8 +426,8 @@
       'browser/internal_auth.h',
       'browser/interstitials/security_interstitial_page.cc',
       'browser/interstitials/security_interstitial_page.h',
-      'browser/interstitials/security_interstitial_uma_helper.cc',
-      'browser/interstitials/security_interstitial_uma_helper.h',
+      'browser/interstitials/security_interstitial_metrics_helper.cc',
+      'browser/interstitials/security_interstitial_metrics_helper.h',
       'browser/intranet_redirect_detector.cc',
       'browser/intranet_redirect_detector.h',
       'browser/invalidation/invalidation_service_factory_android.cc',
@@ -1472,8 +1476,6 @@
       'browser/google/google_brand.h',
       'browser/google/google_brand_chromeos.cc',
       'browser/google/google_brand_chromeos.h',
-      'browser/google/google_profile_helper.cc',
-      'browser/google/google_profile_helper.h',
       'browser/google/google_search_counter.cc',
       'browser/google/google_search_counter.h',
       'browser/google/google_search_counter_android.cc',
@@ -1609,6 +1611,7 @@
       'android/java/src/org/chromium/chrome/browser/VoiceSearchTabHelper.java',
       'android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java',
       'android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopupLegacy.java',
+      'android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegate.java',
       'android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java',
       'android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBarDelegate.java',
       'android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java',
@@ -2286,7 +2289,6 @@
       'browser/safe_browsing/download_feedback_service.h',
       'browser/safe_browsing/download_protection_service.cc',
       'browser/safe_browsing/download_protection_service.h',
-      'browser/safe_browsing/incident_reporting/add_incident_callback.h',
       'browser/safe_browsing/incident_reporting/binary_integrity_analyzer.cc',
       'browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h',
       'browser/safe_browsing/incident_reporting/binary_integrity_analyzer_win.cc',
@@ -2310,6 +2312,7 @@
       'browser/safe_browsing/incident_reporting/incident.h',
       'browser/safe_browsing/incident_reporting/incident_handler_util.cc',
       'browser/safe_browsing/incident_reporting/incident_handler_util.h',
+      'browser/safe_browsing/incident_reporting/incident_receiver.h',
       'browser/safe_browsing/incident_reporting/incident_report_uploader.cc',
       'browser/safe_browsing/incident_reporting/incident_report_uploader.h',
       'browser/safe_browsing/incident_reporting/incident_report_uploader_impl.cc',
@@ -3634,15 +3637,6 @@
           'includes': [ '../build/android/java_cpp_enum.gypi' ],
         },
         {
-         # GN: //chrome/android:chrome_android_java_enums_srcjar
-         'target_name': 'add_web_contents_result_java',
-         'type': 'none',
-         'variables': {
-           'source_file': 'browser/android/chrome_web_contents_delegate_android.h',
-          },
-          'includes': [ '../build/android/java_cpp_enum.gypi' ],
-        },
-        {
           # GN: //chrome/android:chrome_android_java_enums_srcjar
           'target_name': 'profile_sync_service_model_type_selection_java',
           'type': 'none',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 98971e87..a57b9cf 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -543,9 +543,10 @@
         'browser/chromeos/login/screens/terms_of_service_screen.cc',
         'browser/chromeos/login/screens/terms_of_service_screen.h',
         'browser/chromeos/login/screens/terms_of_service_screen_actor.h',
+        'browser/chromeos/login/screens/update_model.cc',
+        'browser/chromeos/login/screens/update_model.h',
         'browser/chromeos/login/screens/update_screen.cc',
         'browser/chromeos/login/screens/update_screen.h',
-        'browser/chromeos/login/screens/update_screen_actor.h',
         'browser/chromeos/login/screens/user_image_model.cc',
         'browser/chromeos/login/screens/user_image_model.h',
         'browser/chromeos/login/screens/user_image_screen.cc',
@@ -665,6 +666,7 @@
         'browser/chromeos/login/users/supervised_user_manager.h',
         'browser/chromeos/login/users/supervised_user_manager_impl.cc',
         'browser/chromeos/login/users/supervised_user_manager_impl.h',
+        'browser/chromeos/login/users/user_manager_interface.h',
         'browser/chromeos/login/users/wallpaper/wallpaper_manager.cc',
         'browser/chromeos/login/users/wallpaper/wallpaper_manager.h',
         'browser/chromeos/login/version_info_updater.cc',
@@ -727,8 +729,12 @@
         'browser/chromeos/platform_keys/platform_keys_service.h',
         'browser/chromeos/platform_keys/platform_keys_service_factory.cc',
         'browser/chromeos/platform_keys/platform_keys_service_factory.h',
+        'browser/chromeos/policy/affiliated_cloud_policy_invalidator.cc',
+        'browser/chromeos/policy/affiliated_cloud_policy_invalidator.h',
         'browser/chromeos/policy/affiliated_invalidation_service_provider.cc',
         'browser/chromeos/policy/affiliated_invalidation_service_provider.h',
+        'browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc',
+        'browser/chromeos/policy/affiliated_invalidation_service_provider_impl.h',
         'browser/chromeos/policy/auto_enrollment_client.cc',
         'browser/chromeos/policy/auto_enrollment_client.h',
         'browser/chromeos/policy/browser_policy_connector_chromeos.cc',
@@ -759,8 +765,6 @@
         'browser/chromeos/policy/consumer_unenrollment_handler_factory.h',
         'browser/chromeos/policy/device_cloud_policy_initializer.cc',
         'browser/chromeos/policy/device_cloud_policy_initializer.h',
-        'browser/chromeos/policy/device_cloud_policy_invalidator.cc',
-        'browser/chromeos/policy/device_cloud_policy_invalidator.h',
         'browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc',
         'browser/chromeos/policy/device_cloud_policy_manager_chromeos.h',
         'browser/chromeos/policy/device_cloud_policy_store_chromeos.cc',
@@ -1099,6 +1103,7 @@
         '../components/components.gyp:ownership',
         '../components/components.gyp:pairing',
         '../components/components.gyp:policy',
+        '../components/components.gyp:user_manager',
         # This depends directly on the variations target, rather than just
         # transitively via the common target because the proto sources need to
         # be generated before code in this target can start building.
@@ -1140,6 +1145,7 @@
         '../third_party/zlib/zlib.gyp:zlib',
         '../ui/base/ui_base.gyp:ui_base',
         '../ui/display/display.gyp:display',
+        '../ui/events/devices/events_devices.gyp:events_devices',
         '../ui/events/events.gyp:dom4_keycode_converter',
         '../ui/events/platform/events_platform.gyp:events_platform',
         '../ui/chromeos/ui_chromeos.gyp:ui_chromeos_resources',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 1f97eb8..67dedf5e 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -5,9 +5,6 @@
 {
   'variables': {
     'chrome_browser_extensions_chromeos_sources': [
-      'browser/extensions/api/diagnostics/diagnostics_api.cc',
-      'browser/extensions/api/diagnostics/diagnostics_api.h',
-      'browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc',
       'browser/extensions/api/document_scan/document_scan_interface_chromeos.cc',
       'browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc',
       'browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index dfda52e..16899e2 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -27,6 +27,8 @@
       'browser/ui/android/autofill/password_generation_popup_view_android.h',
       'browser/ui/android/content_settings/popup_blocked_infobar_delegate.cc',
       'browser/ui/android/content_settings/popup_blocked_infobar_delegate.h',
+      'browser/ui/android/infobars/app_banner_infobar.cc',
+      'browser/ui/android/infobars/app_banner_infobar.h',
       'browser/ui/android/infobars/confirm_infobar.cc',
       'browser/ui/android/infobars/confirm_infobar.h',
       'browser/ui/android/infobars/data_reduction_proxy_infobar.cc',
diff --git a/chrome/chrome_child.gypi b/chrome/chrome_child.gypi
new file mode 100644
index 0000000..6464a39
--- /dev/null
+++ b/chrome/chrome_child.gypi
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'child',
+      'type': 'static_library',
+      'variables': { 'enable_wexit_time_destructors': 1, },
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../content/content.gyp:content_child',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'child/pdf_child_init.cc',
+        'child/pdf_child_init.h',
+      ],
+    },
+  ],
+}
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi
index 024f34db..0885668 100644
--- a/chrome/chrome_dll.gypi
+++ b/chrome/chrome_dll.gypi
@@ -256,6 +256,11 @@
                 '../content/content.gyp:content_app_browser',
               ],
             }],
+            ['chrome_multiple_dll==0 and enable_plugins==1', {
+              'dependencies': [
+                '../pdf/pdf.gyp:pdf',
+              ],
+            }],
             ['cld_version==1', {
               'dependencies': [
                 '<(DEPTH)/third_party/cld/cld.gyp:cld',
@@ -278,9 +283,6 @@
                 # sets -order_file.
                 'ORDER_FILE': 'app/framework.order',
               },
-              'dependencies': [
-                '../pdf/pdf.gyp:pdf',
-              ],
               'include_dirs': [
                 '<(grit_out_dir)',
               ],
@@ -372,6 +374,11 @@
                 }],
               ]
             }],
+            ['enable_plugins==1', {
+              'dependencies': [
+                '../pdf/pdf.gyp:pdf',
+              ],
+            }],
           ],
         },  # target chrome_child_dll
       ],
diff --git a/chrome/chrome_dll_bundle.gypi b/chrome/chrome_dll_bundle.gypi
index c522f2f..dd01c01 100644
--- a/chrome/chrome_dll_bundle.gypi
+++ b/chrome/chrome_dll_bundle.gypi
@@ -76,7 +76,6 @@
     # Bring in pdfsqueeze and run it on all pdfs
     '../build/temp_gyp/pdfsqueeze.gyp:pdfsqueeze',
     '../crypto/crypto.gyp:crypto',
-    '../pdf/pdf.gyp:pdf',
     # On Mac, Flash gets put into the framework, so we need this
     # dependency here. flash_player.gyp will copy the Flash bundle
     # into PRODUCT_DIR.
@@ -147,9 +146,6 @@
     },
     {
       'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Internet Plug-Ins',
-      'files': [
-        '<(PRODUCT_DIR)/PDF.plugin',
-      ],
       'conditions': [
         ['disable_nacl!=1', {
           'conditions': [
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index e27baa8..2713e9b 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -62,6 +62,8 @@
         'app/chrome_exe_main_mac.cc',
         'app/chrome_exe_main_win.cc',
         'app/chrome_exe_resource.h',
+        'app/chrome_watcher_client_win.cc',
+        'app/chrome_watcher_client_win.h',
         'app/chrome_watcher_command_line_win.cc',
         'app/chrome_watcher_command_line_win.h',
         'app/client_util.cc',
@@ -188,6 +190,11 @@
                 '../build/linux/system.gyp:xext',
               ],
             }],
+            ['enable_plugins==1', {
+              'dependencies': [
+                '../pdf/pdf.gyp:pdf',
+              ],
+            }],
           ],
           'sources': [
             'app/chrome_dll_resource.h',
@@ -426,20 +433,6 @@
             # NOTE: chrome/app/theme/chromium/BRANDING and
             # chrome/app/theme/google_chrome/BRANDING have the short name
             # "chrome" etc.; should we try to extract from there instead?
-
-            # CrOS does this in a separate build step.
-            ['OS=="linux" and chromeos==0 and linux_dump_symbols==1', {
-              'dependencies': [
-                '../pdf/pdf.gyp:pdf_linux_symbols',
-              ],
-            }], # OS=="linux" and chromeos==0 and linux_dump_symbols==1
-            # Android doesn't use pdfium.
-            ['OS!="android"', {
-              'dependencies': [
-                # On Mac, this is done in chrome_dll.gypi.
-                '../pdf/pdf.gyp:pdf',
-              ],
-            }], # OS=="android"
           ],
           'dependencies': [
             '../components/components.gyp:startup_metric_utils',
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index c771597d..ed2bcd51 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -461,7 +461,6 @@
           '<(PRODUCT_DIR)/chrome',
           '<(PRODUCT_DIR)/chrome_sandbox',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
-          '<(PRODUCT_DIR)/libpdf.so',
           '<(PRODUCT_DIR)/xdg-mime',
           '<(PRODUCT_DIR)/xdg-settings',
           '<(PRODUCT_DIR)/locales/en-US.pak',
diff --git a/chrome/chrome_syzygy.gyp b/chrome/chrome_syzygy.gyp
index 7ffd1c6..47fa23b 100644
--- a/chrome/chrome_syzygy.gyp
+++ b/chrome/chrome_syzygy.gyp
@@ -9,14 +9,18 @@
     ['syzyasan==1', {
       'variables': {
         'syzygy_exe_dir': '<(DEPTH)/third_party/syzygy/binaries/exe',
+        'kasko_exe_dir': '<(DEPTH)/third_party/kasko',
       },
       # Copy the SyzyASan runtime and logger to the syzygy directory.
+      # TODO(erikwright): Decouple Kasko from SyzyASAN.
       'targets': [
         {
           'target_name': 'copy_syzyasan_binaries',
           'type': 'none',
           'outputs': [
             '<(dest_dir)/agent_logger.exe',
+            '<(dest_dir)/kasko.dll',
+            '<(dest_dir)/kasko.dll.pdb',
             '<(dest_dir)/syzyasan_rtl.dll',
             '<(dest_dir)/syzyasan_rtl.dll.pdb',
           ],
@@ -24,6 +28,8 @@
             {
               'destination': '<(dest_dir)',
               'files': [
+                '<(kasko_exe_dir)/kasko.dll',
+                '<(kasko_exe_dir)/kasko.dll.pdb',
                 '<(syzygy_exe_dir)/agent_logger.exe',
                 '<(syzygy_exe_dir)/syzyasan_rtl.dll',
                 '<(syzygy_exe_dir)/syzyasan_rtl.dll.pdb',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 4276759..4c72b47 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1449,7 +1449,6 @@
         '../net/net.gyp:net',
         '../net/net.gyp:net_resources',
         '../net/net.gyp:net_test_support',
-        '../pdf/pdf.gyp:pdf',
         '../ppapi/ppapi_internal.gyp:ppapi_tests',
         '../skia/skia.gyp:skia',
         '../sync/sync.gyp:sync',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index ddfc850..eaad070 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -15,12 +15,12 @@
       # All unittests in browser, common, renderer and service.
       'browser/about_flags_unittest.cc',
       'browser/android/bookmarks/partner_bookmarks_shim_unittest.cc',
+      'browser/android/manifest_icon_selector_unittest.cc',
       # TODO(newt): move this to test_support_unit?
       'browser/android/mock_location_settings.cc',
       'browser/android/mock_location_settings.h',
       'browser/android/preferences/pref_service_bridge_unittest.cc',
       'browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc',
-      'browser/android/shortcut_helper_unittest.cc',
       'browser/app_controller_mac_unittest.mm',
       'browser/autocomplete/autocomplete_provider_unittest.cc',
       'browser/autocomplete/bookmark_provider_unittest.cc',
@@ -627,12 +627,6 @@
       'browser/background/background_contents_service_unittest.cc',
       'browser/background/background_mode_manager_unittest.cc',
     ],
-    'chrome_unit_tests_nacl_sources': [
-      # TODO(yael): Move to //components/components_tests.gypi once
-      # nacl_defines is moved out of chrome.gyp into a common place.
-      '../components/nacl/loader/nacl_ipc_adapter_unittest.cc',
-      '../components/nacl/loader/nacl_validation_query_unittest.cc',
-    ],
     'chrome_unit_tests_extensions_sources': [
       '../apps/saved_files_service_unittest.cc',
       'browser/apps/app_shim/app_shim_host_mac_unittest.cc',
@@ -1009,6 +1003,8 @@
       'browser/safe_browsing/incident_reporting/incident_report_uploader_impl_unittest.cc',
       'browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc',
       'browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc',
+      'browser/safe_browsing/incident_reporting/mock_incident_receiver.cc',
+      'browser/safe_browsing/incident_reporting/mock_incident_receiver.h',
       'browser/safe_browsing/incident_reporting/module_integrity_unittest_util_win.cc',
       'browser/safe_browsing/incident_reporting/module_integrity_unittest_util_win.h',
       'browser/safe_browsing/incident_reporting/module_integrity_verifier_win_unittest.cc',
@@ -1235,7 +1231,8 @@
       'browser/chromeos/ownership/fake_owner_settings_service.cc',
       'browser/chromeos/ownership/fake_owner_settings_service.h',
       'browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc',
-      'browser/chromeos/policy/affiliated_invalidation_service_provider_unittest.cc',
+      'browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc',
+      'browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc',
       'browser/chromeos/policy/auto_enrollment_client_unittest.cc',
       'browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc',
       'browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc',
@@ -1248,11 +1245,12 @@
       'browser/chromeos/policy/consumer_management_service_unittest.cc',
       'browser/chromeos/policy/consumer_unenrollment_handler_unittest.cc',
       'browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc',
-      'browser/chromeos/policy/device_cloud_policy_invalidator_unittest.cc',
       'browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc',
       'browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc',
       'browser/chromeos/policy/device_local_account_policy_service_unittest.cc',
       'browser/chromeos/policy/enterprise_install_attributes_unittest.cc',
+      'browser/chromeos/policy/fake_affiliated_invalidation_service_provider.cc',
+      'browser/chromeos/policy/fake_affiliated_invalidation_service_provider.h',
       'browser/chromeos/policy/network_configuration_updater_unittest.cc',
       'browser/chromeos/policy/recommendation_restorer_unittest.cc',
       'browser/chromeos/policy/server_backed_state_keys_broker_unittest.cc',
@@ -1750,6 +1748,7 @@
       'conditions': [
         ['OS!="ios"', {
           'dependencies': [
+            'child',
             'plugin',
             'renderer',
             'utility',
@@ -1789,6 +1788,7 @@
           'dependencies': [
             '../build/linux/system.gyp:dbus',
             '../chromeos/chromeos.gyp:chromeos_test_support',
+            '../components/components.gyp:user_manager_test_support',
           ],
           'sources': [
             # Note: sources list duplicated in GN build.
@@ -1820,8 +1820,8 @@
             'browser/chromeos/login/users/avatar/mock_user_image_manager.h',
             'browser/chromeos/login/users/fake_supervised_user_manager.cc',
             'browser/chromeos/login/users/fake_supervised_user_manager.h',
-            'browser/chromeos/login/users/fake_user_manager.cc',
-            'browser/chromeos/login/users/fake_user_manager.h',
+            'browser/chromeos/login/users/fake_chrome_user_manager.cc',
+            'browser/chromeos/login/users/fake_chrome_user_manager.h',
             'browser/chromeos/login/users/mock_user_manager.cc',
             'browser/chromeos/login/users/mock_user_manager.h',
             'browser/chromeos/net/network_portal_detector_test_utils.cc',
@@ -1984,6 +1984,9 @@
             'test/ppapi/ppapi_test.cc',
             'test/ppapi/ppapi_test.h',
           ],
+          'dependencies': [
+            '../pdf/pdf.gyp:pdf',
+          ],
         }],
         ['enable_plugins==1 and disable_nacl==0', {
           'dependencies': [
@@ -2059,7 +2062,6 @@
         '../third_party/icu/icu.gyp:icui18n',
         '../third_party/icu/icu.gyp:icuuc',
         '../third_party/libxml/libxml.gyp:libxml',
-        '../ui/accelerometer/ui_accelerometer.gyp:ui_accelerometer',
         '../ui/base/ui_base.gyp:ui_base_test_support',
         '../ui/gfx/gfx.gyp:gfx_test_support',
         '../ui/resources/ui_resources.gyp:ui_resources',
@@ -2156,9 +2158,6 @@
             }],
           ],
         }],
-        ['disable_nacl==0', {
-          'sources':[ '<@(chrome_unit_tests_nacl_sources)' ],
-        }],
         ['enable_extensions==1', {
           'sources': [ '<@(chrome_unit_tests_extensions_sources)' ],
           'dependencies': [
@@ -2607,6 +2606,8 @@
         '..',
       ],
       'sources': [
+        'app/chrome_watcher_client_unittest_win.cc',
+        'app/chrome_watcher_client_win.cc',
         'app/chrome_watcher_command_line_unittest_win.cc',
         'app/chrome_watcher_command_line_win.cc',
         'app/delay_load_hook_win.cc',
diff --git a/chrome/chrome_watcher/chrome_watcher_main.cc b/chrome/chrome_watcher/chrome_watcher_main.cc
index 0b455418..4e294dc 100644
--- a/chrome/chrome_watcher/chrome_watcher_main.cc
+++ b/chrome/chrome_watcher/chrome_watcher_main.cc
@@ -34,23 +34,27 @@
         { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
 
 // Takes care of monitoring a browser. This class watches for a browser's exit
-// code, as well as listening for WM_ENDSESSION messages. Events are recorded
-// in an exit funnel, for reporting the next time Chrome runs.
+// code, as well as listening for WM_ENDSESSION messages. Events are recorded in
+// an exit funnel, for reporting the next time Chrome runs.
 class BrowserMonitor {
  public:
   BrowserMonitor(base::RunLoop* run_loop, const base::char16* registry_path);
   ~BrowserMonitor();
 
-  // Starts the monitor, returns true on success.
+  // Initiates the asynchronous monitoring process, returns true on success.
+  // |on_initialized_event| will be signaled immediately before blocking on the
+  // exit of |process|.
   bool StartWatching(const base::char16* registry_path,
-                     base::Process process);
+                     base::Process process,
+                     base::win::ScopedHandle on_initialized_event);
 
  private:
   // Called from EndSessionWatcherWindow on a end session messages.
   void OnEndSessionMessage(UINT message, LPARAM lparam);
 
-  // Blocking function that runs on |background_thread_|.
-  void Watch();
+  // Blocking function that runs on |background_thread_|. Signals
+  // |on_initialized_event| before waiting for the browser process to exit.
+  void Watch(base::win::ScopedHandle on_initialized_event);
 
   // Posted to main thread from Watch when browser exits.
   void BrowserExited();
@@ -89,8 +93,10 @@
 BrowserMonitor::~BrowserMonitor() {
 }
 
-bool BrowserMonitor::StartWatching(const base::char16* registry_path,
-                                   base::Process process) {
+bool BrowserMonitor::StartWatching(
+    const base::char16* registry_path,
+    base::Process process,
+    base::win::ScopedHandle on_initialized_event) {
   if (!exit_code_watcher_.Initialize(process.Pass()))
     return false;
 
@@ -104,8 +110,9 @@
     return false;
   }
 
-  if (!background_thread_.task_runner()->PostTask(FROM_HERE,
-        base::Bind(&BrowserMonitor::Watch, base::Unretained(this)))) {
+  if (!background_thread_.task_runner()->PostTask(
+          FROM_HERE, base::Bind(&BrowserMonitor::Watch, base::Unretained(this),
+                                base::Passed(on_initialized_event.Pass())))) {
     background_thread_.Stop();
     return false;
   }
@@ -137,10 +144,15 @@
     run_loop_->Quit();
 }
 
-void BrowserMonitor::Watch() {
+void BrowserMonitor::Watch(base::win::ScopedHandle on_initialized_event) {
   // This needs to run on an IO thread.
   DCHECK_NE(main_thread_, base::MessageLoopProxy::current());
 
+  // Signal our client now that the Kasko reporter is initialized and we have
+  // cleared all of the obstacles that might lead to an early exit.
+  ::SetEvent(on_initialized_event.Get());
+  on_initialized_event.Close();
+
   exit_code_watcher_.WaitForExit();
   exit_funnel_.RecordEvent(L"BrowserExit");
 
@@ -177,8 +189,10 @@
 // The main entry point to the watcher, declared as extern "C" to avoid name
 // mangling.
 extern "C" int WatcherMain(const base::char16* registry_path,
-                           HANDLE process_handle) {
+                           HANDLE process_handle,
+                           HANDLE on_initialized_event_handle) {
   base::Process process(process_handle);
+  base::win::ScopedHandle on_initialized_event(on_initialized_event_handle);
 
   // The exit manager is in charge of calling the dtors of singletons.
   base::AtExitManager exit_manager;
@@ -197,8 +211,10 @@
 
   base::RunLoop run_loop;
   BrowserMonitor monitor(&run_loop, registry_path);
-  if (!monitor.StartWatching(registry_path, process.Pass()))
+  if (!monitor.StartWatching(registry_path, process.Pass(),
+                             on_initialized_event.Pass())) {
     return 1;
+  }
 
   run_loop.Run();
 
diff --git a/chrome/chrome_watcher/chrome_watcher_main_api.h b/chrome/chrome_watcher/chrome_watcher_main_api.h
index 491b550..22dbf9b 100644
--- a/chrome/chrome_watcher/chrome_watcher_main_api.h
+++ b/chrome/chrome_watcher/chrome_watcher_main_api.h
@@ -16,8 +16,11 @@
 
 // The type of the watcher DLL's main entry point.
 // Watches |parent_process| and records its exit code under |registry_path| in
-// HKCU. Takes ownership of |parent_process|.
-typedef int (*ChromeWatcherMainFunction)(const base::char16* registry_path,
-                                         HANDLE parent_process);
+// HKCU. |on_initialized_event| will be signaled once the process is fully
+// initialized. Takes ownership of |parent_process| and |on_initialized_event|.
+typedef int (*ChromeWatcherMainFunction)(
+    const base::char16* registry_path,
+    HANDLE parent_process,
+    HANDLE on_initialized_event);
 
 #endif  // CHROME_CHROME_WATCHER_CHROME_WATCHER_MAIN_API_H_
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 587b2aa..21df9e0 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -64,11 +64,8 @@
 namespace {
 
 #if defined(ENABLE_PLUGINS)
-const char kPDFPluginMimeType[] = "application/pdf";
 const char kPDFPluginExtension[] = "pdf";
 const char kPDFPluginDescription[] = "Portable Document Format";
-const char kPDFPluginPrintPreviewMimeType[] =
-    "application/x-google-chrome-print-preview-pdf";
 const char kPDFPluginOutOfProcessMimeType[] =
     "application/x-google-chrome-pdf";
 const uint32 kPDFPluginPermissions = ppapi::PERMISSION_PRIVATE |
@@ -95,6 +92,10 @@
 const uint32 kGTalkPluginPermissions = ppapi::PERMISSION_PRIVATE |
                                        ppapi::PERMISSION_DEV;
 
+content::PepperPluginInfo::GetInterfaceFunc g_pdf_get_interface;
+content::PepperPluginInfo::PPP_InitializeModuleFunc g_pdf_initialize_module;
+content::PepperPluginInfo::PPP_ShutdownModuleFunc g_pdf_shutdown_module;
+
 #if defined(ENABLE_REMOTING)
 
 content::PepperPluginInfo::GetInterfaceFunc g_remoting_get_interface;
@@ -133,43 +134,25 @@
 // not marked internal, aside from being automatically registered, they're just
 // regular plugins).
 void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) {
-  // PDF.
-  //
-  // Once we're sandboxed, we can't know if the PDF plugin is available or not;
-  // but (on Linux) this function is always called once before we're sandboxed.
-  // So the first time through test if the file is available and then skip the
-  // check on subsequent calls if yes.
-  static bool skip_pdf_file_check = false;
-  base::FilePath path;
-  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path)) {
-    if (skip_pdf_file_check || base::PathExists(path)) {
-      content::PepperPluginInfo pdf;
-      pdf.path = path;
-      pdf.name = ChromeContentClient::kPDFPluginName;
-      if (switches::OutOfProcessPdfEnabled()) {
-        pdf.is_out_of_process = true;
-        content::WebPluginMimeType pdf_mime_type(kPDFPluginOutOfProcessMimeType,
-                                                 kPDFPluginExtension,
-                                                 kPDFPluginDescription);
-        pdf.mime_types.push_back(pdf_mime_type);
-        // TODO(raymes): Make print preview work with out of process PDF.
-      } else {
-        content::WebPluginMimeType pdf_mime_type(kPDFPluginMimeType,
-                                                 kPDFPluginExtension,
-                                                 kPDFPluginDescription);
-        content::WebPluginMimeType print_preview_pdf_mime_type(
-            kPDFPluginPrintPreviewMimeType,
-            kPDFPluginExtension,
-            kPDFPluginDescription);
-        pdf.mime_types.push_back(pdf_mime_type);
-        pdf.mime_types.push_back(print_preview_pdf_mime_type);
-      }
-      pdf.permissions = kPDFPluginPermissions;
-      plugins->push_back(pdf);
+  content::PepperPluginInfo pdf_info;
+  pdf_info.is_internal = true;
+  pdf_info.is_out_of_process = true;
+  pdf_info.name = ChromeContentClient::kPDFPluginName;
+  pdf_info.description = kPDFPluginDescription;
+  pdf_info.path = base::FilePath::FromUTF8Unsafe(
+      ChromeContentClient::kPDFPluginPath);
+  content::WebPluginMimeType pdf_mime_type(
+      kPDFPluginOutOfProcessMimeType,
+      kPDFPluginExtension,
+      kPDFPluginDescription);
+  pdf_info.mime_types.push_back(pdf_mime_type);
+  pdf_info.internal_entry_points.get_interface = g_pdf_get_interface;
+  pdf_info.internal_entry_points.initialize_module = g_pdf_initialize_module;
+  pdf_info.internal_entry_points.shutdown_module = g_pdf_shutdown_module;
+  pdf_info.permissions = kPDFPluginPermissions;
+  plugins->push_back(pdf_info);
 
-      skip_pdf_file_check = true;
-    }
-  }
+  base::FilePath path;
 
 #if !defined(DISABLE_NACL)
   // Handle Native Client just like the PDF plugin. This means that it is
@@ -454,6 +437,17 @@
 }
 #endif
 
+#if defined(ENABLE_PLUGINS)
+void ChromeContentClient::SetPDFEntryFunctions(
+    content::PepperPluginInfo::GetInterfaceFunc get_interface,
+    content::PepperPluginInfo::PPP_InitializeModuleFunc initialize_module,
+    content::PepperPluginInfo::PPP_ShutdownModuleFunc shutdown_module) {
+  g_pdf_get_interface = get_interface;
+  g_pdf_initialize_module = initialize_module;
+  g_pdf_shutdown_module = shutdown_module;
+}
+#endif
+
 void ChromeContentClient::SetActiveURL(const GURL& url) {
   base::debug::SetCrashKeyValue(crash_keys::kActiveURL,
                                 url.possibly_invalid_spec());
diff --git a/chrome/common/chrome_content_client.h b/chrome/common/chrome_content_client.h
index 968db7c..fd00d31 100644
--- a/chrome/common/chrome_content_client.h
+++ b/chrome/common/chrome_content_client.h
@@ -22,6 +22,7 @@
 class ChromeContentClient : public content::ContentClient {
  public:
   static const char* const kPDFPluginName;
+  static const char* const kPDFPluginPath;
   static const char* const kRemotingViewerPluginPath;
 
   // The methods below are called by child processes to set the function
@@ -42,6 +43,13 @@
       content::PepperPluginInfo::PPP_ShutdownModuleFunc shutdown_module);
 #endif
 
+#if defined(ENABLE_PLUGINS)
+  static void SetPDFEntryFunctions(
+      content::PepperPluginInfo::GetInterfaceFunc get_interface,
+      content::PepperPluginInfo::PPP_InitializeModuleFunc initialize_module,
+      content::PepperPluginInfo::PPP_ShutdownModuleFunc shutdown_module);
+#endif
+
   void SetActiveURL(const GURL& url) override;
   void SetGpuInfo(const gpu::GPUInfo& gpu_info) override;
   void AddPepperPlugins(
diff --git a/chrome/common/chrome_content_client_constants.cc b/chrome/common/chrome_content_client_constants.cc
index aeda5340..f0a59f8 100644
--- a/chrome/common/chrome_content_client_constants.cc
+++ b/chrome/common/chrome_content_client_constants.cc
@@ -4,6 +4,12 @@
 
 #include "chrome/common/chrome_content_client.h"
 
+#if defined(GOOGLE_CHROME_BUILD)
 const char* const ChromeContentClient::kPDFPluginName = "Chrome PDF Viewer";
+#else
+const char* const ChromeContentClient::kPDFPluginName = "Chromium PDF Viewer";
+#endif
+const char* const ChromeContentClient::kPDFPluginPath =
+    "internal-pdf-viewer";
 const char* const ChromeContentClient::kRemotingViewerPluginPath =
     "internal-remoting-viewer";
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index af56236..9537376 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -50,16 +50,6 @@
     FILE_PATH_LITERAL("Macromed\\Flash");
 #endif
 
-// File name of the internal PDF plugin on different platforms.
-const base::FilePath::CharType kInternalPDFPluginFileName[] =
-#if defined(OS_WIN)
-    FILE_PATH_LITERAL("pdf.dll");
-#elif defined(OS_MACOSX)
-    FILE_PATH_LITERAL("PDF.plugin");
-#else  // Linux and Chrome OS
-    FILE_PATH_LITERAL("libpdf.so");
-#endif
-
 const base::FilePath::CharType kInternalNaClPluginFileName[] =
     FILE_PATH_LITERAL("internal-nacl-plugin");
 
@@ -294,11 +284,6 @@
         return false;
       cur = cur.Append(chrome::kPepperFlashPluginFilename);
       break;
-    case chrome::FILE_PDF_PLUGIN:
-      if (!GetInternalPluginsDirectory(&cur))
-        return false;
-      cur = cur.Append(kInternalPDFPluginFileName);
-      break;
     case chrome::FILE_EFFECTS_PLUGIN:
       if (!GetInternalPluginsDirectory(&cur))
         return false;
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index a22600ed..34c85fb 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -83,7 +83,6 @@
                                 // matter the file exists or not.
   FILE_PEPPER_FLASH_PLUGIN,     // Full path to the bundled Pepper Flash plugin
                                 // file.
-  FILE_PDF_PLUGIN,              // Full path to the internal PDF plugin file.
 
   FILE_NACL_PLUGIN,             // Full path to the internal NaCl plugin file.
   DIR_PNACL_BASE,               // Full path to the base dir for PNaCl.
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 220bf60e..6986eee 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -451,6 +451,9 @@
 // Enables experimentation with launching ephemeral apps via hyperlinks.
 const char kEnableLinkableEphemeralApps[]   = "enable-linkable-ephemeral-apps";
 
+// Enables the material design Settings feature.
+const char kEnableMaterialDesignSettings[]  = "enable-md-settings";
+
 // Runs the Native Client inside the renderer process and enables GPU plugin
 // (internally adds lEnableGpuPlugin to the command line).
 const char kEnableNaCl[]                    = "enable-nacl";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index d39824a..d877231 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -132,6 +132,7 @@
 extern const char kEnableFastUnload[];
 extern const char kEnableIPv6[];
 extern const char kEnableLinkableEphemeralApps[];
+extern const char kEnableMaterialDesignSettings[];
 extern const char kEnableNaCl[];
 extern const char kEnableNetBenchmarking[];
 extern const char kEnableNewBookmarkApps[];
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index b68b8cb..65518e95 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -262,11 +262,6 @@
     "dependencies": ["manifest:devtools_page"],
     "contexts": ["blessed_extension"]
   },
-  "diagnostics": {
-    "dependencies": ["permission:diagnostics"],
-    "extension_types": ["platform_app"],
-    "contexts": ["blessed_extension"]
-  },
   "dial": {
     "dependencies": ["permission:dial"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index acc6795..aedc4e1 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -249,21 +249,6 @@
       "852290F2442EEE45EF673B8DA6090112079012A2"   // http://crbug.com/375484
     ]
   },
-  "diagnostics": [
-    {
-      "channel": "dev",
-      "extension_types": ["platform_app"]
-    },
-    {
-      "channel": "stable",
-      "extension_types": ["platform_app"],
-      "whitelist": [
-        "7AE714FFD394E073F0294CFA134C9F91DB5FBAA4",  // CCD Development
-        "C7DA3A55C2355F994D3FDDAD120B426A0DF63843",  // CCD Testing
-        "75E3CFFFC530582C583E4690EF97C70B9C8423B7"   // CCD Release
-      ]
-    }
-  ],
   "debugger": [
     {
       "channel": "stable",
diff --git a/chrome/common/extensions/api/content_settings.json b/chrome/common/extensions/api/content_settings.json
index 126e7ee..3d6e4ad4 100644
--- a/chrome/common/extensions/api/content_settings.json
+++ b/chrome/common/extensions/api/content_settings.json
@@ -229,6 +229,14 @@
           {"type":"string", "enum": ["allow", "block", "ask"]}
         ]
       },
+      "fullscreen": {
+        "$ref": "ContentSetting",
+        "description": "Whether to allow sites to toggle the fullscreen mode. One of<br><var>allow</var>: Allow sites to toggle the fullscreen mode,<br><var>ask</var>: Ask when a site wants to toggle the fullscreen mode. <br>Default is <var>ask</var>.<br>The primary URL is the URL of the document which requested to toggle the fullscreen mode. The secondary URL is the URL of the top-level frame (which may or may not differ from the requesting URL).",
+        "value": [
+          "fullscreen",
+          {"type":"string", "enum": ["allow", "ask"]}
+        ]
+      },
       "mouselock": {
         "$ref": "ContentSetting",
         "description": "Whether to allow sites to disable the mouse cursor. One of <br><var>allow</var>: Allow sites to disable the mouse cursor,<br><var>block</var>: Don't allow sites to disable the mouse cursor,<br><var>ask</var>: Ask when a site wants to disable the mouse cursor. <br>Default is <var>ask</var>.<br>The primary URL is the URL of the top-level frame. The secondary URL is not used.",
@@ -252,6 +260,22 @@
           "media-stream-camera",
           {"type":"string", "enum": ["allow", "block", "ask"]}
         ]
+      },
+      "unsandboxedPlugins": {
+        "$ref": "ContentSetting",
+        "description": "Whether to allow sites to run plug-ins unsandboxed. One of <br><var>allow</var>: Allow sites to run plug-ins unsandboxed,<br><var>block</var>: Don't allow sites to run plug-ins unsandboxed,<br><var>ask</var>: Ask when a site wants to run a plug-in unsandboxed. <br>Default is <var>ask</var>.<br>The primary URL is the URL of the top-level frame. The secondary URL is not used.",
+        "value": [
+          "ppapi-broker",
+          {"type":"string", "enum": ["allow", "block", "ask"]}
+        ]
+      },
+      "automaticDownloads": {
+        "$ref": "ContentSetting",
+        "description": "Whether to allow sites to download multiple files automatically. One of <br><var>allow</var>: Allow sites to download multiple files automatically,<br><var>block</var>: Don't allow sites to download multiple files automatically,<br><var>ask</var>: Ask when a site wants to download files automatically after the first file. <br>Default is <var>ask</var>.<br>The primary URL is the URL of the top-level frame. The secondary URL is not used.",
+        "value": [
+          "multiple-automatic-downloads",
+          {"type":"string", "enum": ["allow", "block", "ask"]}
+        ]
       }
     }
   }
diff --git a/chrome/common/extensions/api/document_scan.idl b/chrome/common/extensions/api/document_scan.idl
index 0428d4a1..97baa91c 100644
--- a/chrome/common/extensions/api/document_scan.idl
+++ b/chrome/common/extensions/api/document_scan.idl
@@ -18,18 +18,19 @@
     // an image tag.
     DOMString[] dataUrls;
 
-    // The MIME type of |dataUrls|.
+    // The MIME type of <code>dataUrls</code>.
     DOMString mimeType;
   };
 
-  // Callback from the <code>scan</code> method; on success
-  // the results from the scan is returned in |results|.
-  callback ScanCallback = void (ScanResults results);
+  // Callback from the <code>scan</code> method.
+  // |result| The results from the scan, if successful.
+  // Otherwise will return null and set runtime.lastError.
+  callback ScanCallback = void (ScanResults result);
 
   interface Functions {
     // Performs a document scan.  On success, the PNG data will be
     // sent to the callback.
-    // |options| : <code>Options</code> object containing scan parameters.
+    // |options| : Object containing scan parameters.
     // |callback| : Called with the result and data from the scan.
     static void scan(ScanOptions options, ScanCallback callback);
   };
diff --git a/chrome/common/extensions/api/notifications.idl b/chrome/common/extensions/api/notifications.idl
index fb1fe65..7b41605 100644
--- a/chrome/common/extensions/api/notifications.idl
+++ b/chrome/common/extensions/api/notifications.idl
@@ -124,31 +124,40 @@
 
   interface Functions {
     // Creates and displays a notification.
-    // |notificationId|: Identifier of the notification. If it is empty, this
-    // method generates an id. If it matches an existing notification, this
-    // method first clears that notification before proceeding with the create
-    // operation.
+    // |notificationId|: Identifier of the notification. If not set or empty, an
+    // ID will automatically be generated. If it matches an existing
+    // notification, this method first clears that notification before
+    // proceeding with the create operation.
+    //
+    // The <code>notificationId</code> parameter is required before Chrome 42.
     // |options|: Contents of the notification.
     // |callback|: Returns the notification id (either supplied or generated)
     // that represents the created notification.
-    static void create(DOMString notificationId,
+    //
+    // The callback is required before Chrome 42.
+    static void create(optional DOMString notificationId,
                        NotificationOptions options,
-                       CreateCallback callback);
+                       optional CreateCallback callback);
 
     // Updates an existing notification.
     // |notificationId|: The id of the notification to be updated. This is
     // returned by $(ref:notifications.create) method.
     // |options|: Contents of the notification to update to.
     // |callback|: Called to indicate whether a matching notification existed.
+    //
+    // The callback is required before Chrome 42.
     static void update(DOMString notificationId,
                        NotificationOptions options,
-                       UpdateCallback callback);
+                       optional UpdateCallback callback);
 
     // Clears the specified notification.
     // |notificationId|: The id of the notification to be cleared. This is
     // returned by $(ref:notifications.create) method.
     // |callback|: Called to indicate whether a matching notification existed.
-    static void clear(DOMString notificationId, ClearCallback callback);
+    //
+    // The callback is required before Chrome 42.
+    static void clear(DOMString notificationId,
+                      optional ClearCallback callback);
 
     // Retrieves all the notifications.
     // |callback|: Returns the set of notification_ids currently in the system.
diff --git a/chrome/common/extensions/api/schemas.gypi b/chrome/common/extensions/api/schemas.gypi
index 7b630c00..d02d0a1 100644
--- a/chrome/common/extensions/api/schemas.gypi
+++ b/chrome/common/extensions/api/schemas.gypi
@@ -107,7 +107,6 @@
     # ChromeOS-specific schemas.
     'chromeos_schema_files': [
       'accessibility_features.json',
-      'diagnostics.idl',
       'enterprise_platform_keys.idl',
       'enterprise_platform_keys_internal.idl',
       'file_browser_handler_internal.json',
diff --git a/chrome/common/extensions/docs/server2/admin_servlets.py b/chrome/common/extensions/docs/server2/admin_servlets.py
new file mode 100644
index 0000000..7990761
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/admin_servlets.py
@@ -0,0 +1,111 @@
+# Copyright 2014 The Chromium 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 appengine_wrappers import taskqueue
+from commit_tracker import CommitTracker
+from future import All
+from object_store_creator import ObjectStoreCreator
+from refresh_tracker import RefreshTracker
+from servlet import Servlet, Response
+
+
+class EnqueueServlet(Servlet):
+  '''This Servlet can be used to manually enqueue tasks on the default
+  taskqueue. Useful for when an admin wants to manually force a specific
+  DataSource refresh, but the refresh operation takes longer than the 60 sec
+  timeout of a non-taskqueue request. For example, you might query
+
+  /_enqueue/_refresh/content_providers/cr-native-client?commit=123ff65468dcafff0
+
+  which will enqueue a task (/_refresh/content_providers/cr-native-client) to
+  refresh the NaCl documentation cache for commit 123ff65468dcafff0.
+
+  Access to this servlet should always be restricted to administrative users.
+  '''
+  def __init__(self, request):
+    Servlet.__init__(self, request)
+
+  def Get(self):
+    queue = taskqueue.Queue()
+    queue.add(taskqueue.Task(url='/%s' % self._request.path,
+                             params=self._request.arguments))
+    return Response.Ok('Task enqueued.')
+
+
+class QueryCommitServlet(Servlet):
+  '''Provides read access to the commit ID cache within the server. For example:
+
+  /_query_commit/master
+
+  will return the commit ID stored under the commit key "master" within the
+  commit cache. Currently "master" is the only named commit we cache, and it
+  corresponds to the commit ID whose data currently populates the data cache
+  used by live instances.
+  '''
+  def __init__(self, request):
+    Servlet.__init__(self, request)
+
+  def Get(self):
+    object_store_creator = ObjectStoreCreator(start_empty=False)
+    commit_tracker = CommitTracker(object_store_creator)
+
+    def generate_response(result):
+      commit_id, history = result
+      history_log = ''.join('%s: %s<br>' % (entry.datetime, entry.commit_id)
+                            for entry in reversed(history))
+      response = 'Current commit: %s<br><br>Most recent commits:<br>%s' % (
+          commit_id, history_log)
+      return response
+
+    commit_name = self._request.path
+    id_future = commit_tracker.Get(commit_name)
+    history_future = commit_tracker.GetHistory(commit_name)
+    return Response.Ok(
+        All((id_future, history_future)).Then(generate_response).Get())
+
+
+class DumpRefreshServlet(Servlet):
+  def __init__(self, request):
+    Servlet.__init__(self, request)
+
+  def Get(self):
+    object_store_creator = ObjectStoreCreator(start_empty=False)
+    refresh_tracker = RefreshTracker(object_store_creator)
+    commit_id = self._request.path
+    work_order = refresh_tracker._GetWorkOrder(commit_id).Get()
+    task_names = ['%s@%s' % (commit_id, task) for task in work_order.tasks]
+    completions = refresh_tracker._task_completions.GetMulti(task_names).Get()
+    missing = []
+    for task in task_names:
+      if task not in completions:
+        missing.append(task)
+    response = 'Missing:<br>%s' % ''.join('%s<br>' % task for task in missing)
+    return Response.Ok(response)
+
+class ResetCommitServlet(Servlet):
+  '''Writes a new commit ID to the commit cache. For example:
+
+  /_reset_commit/master/123456
+
+  will reset the 'master' commit ID to '123456'. The provided commit MUST be
+  in the named commit's recent history or it will be ignored.
+  '''
+
+  class Delegate(object):
+    def CreateCommitTracker(self):
+      return CommitTracker(ObjectStoreCreator(start_empty=False))
+
+  def __init__(self, request, delegate=Delegate()):
+    Servlet.__init__(self, request)
+    self._delegate = delegate
+
+  def Get(self):
+    commit_tracker = self._delegate.CreateCommitTracker()
+    commit_name, commit_id = self._request.path.split('/', 1)
+    history = commit_tracker.GetHistory(commit_name).Get()
+    if not any(entry.commit_id == commit_id for entry in history):
+      return Response.BadRequest('Commit %s not cached.' % commit_id)
+    commit_tracker.Set(commit_name, commit_id).Get()
+    return Response.Ok('Commit "%s" updated to %s' % (commit_name, commit_id))
+
diff --git a/chrome/common/extensions/docs/server2/admin_servlets_test.py b/chrome/common/extensions/docs/server2/admin_servlets_test.py
new file mode 100755
index 0000000..3fe9535
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/admin_servlets_test.py
@@ -0,0 +1,89 @@
+#!/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 unittest
+
+from admin_servlets import ResetCommitServlet
+from commit_tracker import CommitTracker
+from object_store_creator import ObjectStoreCreator
+from servlet import Request
+
+
+_COMMIT_HISTORY_DATA = (
+  '1234556789abcdef1234556789abcdef12345567',
+  'f00f00f00f00f00f00f00f00f00f00f00f00f00f',
+  '1010101010101010101010101010101010101010',
+  'abcdefabcdefabcdefabcdefabcdefabcdefabcd',
+  '4242424242424242424242424242424242424242',
+)
+
+
+class _ResetCommitDelegate(ResetCommitServlet.Delegate):
+  def __init__(self, commit_tracker):
+    self._commit_tracker = commit_tracker
+
+  def CreateCommitTracker(self):
+    return self._commit_tracker
+
+
+class AdminServletsTest(unittest.TestCase):
+  def setUp(self):
+    object_store_creator = ObjectStoreCreator(start_empty=True)
+    self._commit_tracker = CommitTracker(object_store_creator)
+    for id in _COMMIT_HISTORY_DATA:
+      self._commit_tracker.Set('master', id).Get()
+
+  def _ResetCommit(self, commit_name, commit_id):
+    return ResetCommitServlet(
+        Request.ForTest('%s/%s' % (commit_name, commit_id)),
+        _ResetCommitDelegate(self._commit_tracker)).Get()
+
+  def _AssertBadRequest(self, commit_name, commit_id):
+    response = self._ResetCommit(commit_name, commit_id)
+    self.assertEqual(response.status, 400,
+        'Should have failed to reset to commit %s to %s.' %
+        (commit_name, commit_id))
+
+  def _AssertOk(self, commit_name, commit_id):
+    response = self._ResetCommit(commit_name, commit_id)
+    self.assertEqual(response.status, 200,
+        'Failed to reset commit %s to %s.' % (commit_name, commit_id))
+
+  def testResetCommitServlet(self):
+    # Make sure all the valid commits can be used for reset.
+    for id in _COMMIT_HISTORY_DATA:
+      self._AssertOk('master', id)
+
+    # Non-existent commit should fail to update
+    self._AssertBadRequest('master',
+                           'b000000000000000000000000000000000000000')
+
+    # Commit 'master' should still point to the last valid entry
+    self.assertEqual(self._commit_tracker.Get('master').Get(),
+                     _COMMIT_HISTORY_DATA[-1])
+
+    # Reset to a valid commit but older
+    self._AssertOk('master', _COMMIT_HISTORY_DATA[0])
+
+    # Commit 'master' should point to the first history entry
+    self.assertEqual(self._commit_tracker.Get('master').Get(),
+                     _COMMIT_HISTORY_DATA[0])
+
+    # Add a new entry to the history and validate that it can be used for reset.
+    _NEW_ENTRY = '9999999999999999999999999999999999999999'
+    self._commit_tracker.Set('master', _NEW_ENTRY).Get()
+    self._AssertOk('master', _NEW_ENTRY)
+
+    # Add a bunch (> 50) of entries to ensure that _NEW_ENTRY has been flushed
+    # out of the history.
+    for i in xrange(0, 20):
+      for id in _COMMIT_HISTORY_DATA:
+        self._commit_tracker.Set('master', id).Get()
+
+    # Verify that _NEW_ENTRY is no longer valid for reset.
+    self._AssertBadRequest('master', _NEW_ENTRY)
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index 698bd396..f8d6f30 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -22,6 +22,10 @@
   script: appengine_main.py
   secure: always
   login: admin
+- url: /_reset_commit/.*
+  script: appengine_main.py
+  secure: always
+  login: admin
 - url: /.*
   script: appengine_main.py
   secure: always
diff --git a/chrome/common/extensions/docs/server2/availability_finder.py b/chrome/common/extensions/docs/server2/availability_finder.py
index 69ecf356..bc470f5e 100644
--- a/chrome/common/extensions/docs/server2/availability_finder.py
+++ b/chrome/common/extensions/docs/server2/availability_finder.py
@@ -174,7 +174,7 @@
     schema_fs = self._CreateAPISchemaFileSystem(file_system)
     api_schemas = schema_fs.GetFromFile(api_filename).Get()
     matching_schemas = [api for api in api_schemas
-                        if api['namespace'] == api_name]
+                        if api and api['namespace'] == api_name]
     # There should only be a single matching schema per file, or zero in the
     # case of no API data being found in _EXTENSION_API.
     assert len(matching_schemas) <= 1
diff --git a/chrome/common/extensions/docs/server2/commit_tracker.py b/chrome/common/extensions/docs/server2/commit_tracker.py
index 53bb90c9..874c4b7b 100644
--- a/chrome/common/extensions/docs/server2/commit_tracker.py
+++ b/chrome/common/extensions/docs/server2/commit_tracker.py
@@ -2,20 +2,55 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import collections
+import datetime
+
 from object_store_creator import ObjectStoreCreator
 from future import Future
 
 
+# The maximum number of commit IDs to retain in a named commit's history deque.
+_MAX_COMMIT_HISTORY_LENGTH = 50
+
+
+class CachedCommit(object):
+  '''Object type which is stored for each entry in a named commit's history.
+  |datetime| is used as a timestamp for when the commit cache was completed,
+  and is only meant to provide a loose ordering of commits for administrative
+  servlets to display.'''
+  def __init__(self, commit_id, datetime):
+    self.commit_id = commit_id
+    self.datetime = datetime
+
+
 class CommitTracker(object):
   '''Utility class for managing and querying the storage of various named commit
   IDs.'''
   def __init__(self, object_store_creator):
-    # The object store should never be created empty since the sole purpose of
+    # The object stores should never be created empty since the sole purpose of
     # this tracker is to persist named commit data across requests.
     self._store = object_store_creator.Create(CommitTracker, start_empty=False)
+    self._history_store = object_store_creator.Create(CommitTracker,
+        category='history', start_empty=False)
 
   def Get(self, key):
     return self._store.Get(key)
 
   def Set(self, key, commit):
-    return self._store.Set(key, commit)
+    return (self._store.Set(key, commit)
+      .Then(lambda _: self._UpdateHistory(key, commit)))
+
+  def GetHistory(self, key):
+    '''Fetches the commit ID history for a named commit. If the commit has no
+    history, this will return an empty collection.'''
+    return (self._history_store.Get(key)
+        .Then(lambda history: () if history is None else history))
+
+  def _UpdateHistory(self, key, commit):
+    '''Appends a commit ID to a named commit's tracked history.'''
+    def create_or_amend_history(history):
+      if history is None:
+        history = collections.deque([], maxlen=50)
+      history.append(CachedCommit(commit, datetime.datetime.now()))
+      return self._history_store.Set(key, history)
+    return self._history_store.Get(key).Then(create_or_amend_history)
diff --git a/chrome/common/extensions/docs/server2/handler.py b/chrome/common/extensions/docs/server2/handler.py
index a0e044e..c6a2eed 100644
--- a/chrome/common/extensions/docs/server2/handler.py
+++ b/chrome/common/extensions/docs/server2/handler.py
@@ -4,11 +4,10 @@
 
 import time
 
-from appengine_wrappers import taskqueue
-from commit_tracker import CommitTracker
+from admin_servlets import (DumpRefreshServlet, EnqueueServlet,
+    QueryCommitServlet, ResetCommitServlet)
 from cron_servlet import CronServlet
 from instance_servlet import InstanceServlet
-from object_store_creator import ObjectStoreCreator
 from patch_servlet import PatchServlet
 from refresh_servlet import RefreshServlet
 from servlet import Servlet, Request, Response
@@ -18,55 +17,15 @@
 _DEFAULT_SERVLET = InstanceServlet.GetConstructor()
 
 
-class _EnqueueServlet(Servlet):
-  '''This Servlet can be used to manually enqueue tasks on the default
-  taskqueue. Useful for when an admin wants to manually force a specific
-  DataSource refresh, but the refresh operation takes longer than the 60 sec
-  timeout of a non-taskqueue request. For example, you might query
-
-  /_enqueue/_refresh/content_providers/cr-native-client?commit=123ff65468dcafff0
-
-  which will enqueue a task (/_refresh/content_providers/cr-native-client) to
-  refresh the NaCl documentation cache for commit 123ff65468dcafff0.
-
-  Access to this servlet should always be restricted to administrative users.
-  '''
-  def __init__(self, request):
-    Servlet.__init__(self, request)
-
-  def Get(self):
-    queue = taskqueue.Queue()
-    queue.add(taskqueue.Task(url='/%s' % self._request.path,
-                             params=self._request.arguments))
-    return Response.Ok('Task enqueued.')
-
-
-class _QueryCommitServlet(Servlet):
-  '''Provides read access to the commit ID cache within the server. For example:
-
-  /_query_commit/master
-
-  will return the commit ID stored under the commit key "master" within the
-  commit cache. Currently "master" is the only named commit we cache, and it
-  corresponds to the commit ID whose data currently populates the data cache
-  used by live instances.
-  '''
-  def __init__(self, request):
-    Servlet.__init__(self, request)
-
-  def Get(self):
-    object_store_creator = ObjectStoreCreator(start_empty=False)
-    commit_tracker = CommitTracker(object_store_creator)
-    return Response.Ok(commit_tracker.Get(self._request.path).Get())
-
-
 _SERVLETS = {
   'cron': CronServlet,
-  'enqueue': _EnqueueServlet,
+  'enqueue': EnqueueServlet,
   'patch': PatchServlet,
-  'query_commit': _QueryCommitServlet,
+  'query_commit': QueryCommitServlet,
   'refresh': RefreshServlet,
+  'reset_commit': ResetCommitServlet,
   'test': TestServlet,
+  'dump_refresh': DumpRefreshServlet,
 }
 
 
diff --git a/chrome/common/extensions/docs/server2/servlet.py b/chrome/common/extensions/docs/server2/servlet.py
index 5465d81..61917ff 100644
--- a/chrome/common/extensions/docs/server2/servlet.py
+++ b/chrome/common/extensions/docs/server2/servlet.py
@@ -96,6 +96,12 @@
     return Response(headers={'Location': url}, status=status)
 
   @staticmethod
+  def BadRequest(content, headers=None):
+    '''Returns a bad request (400) response.
+    '''
+    return Response(content=content, headers=headers, status=400)
+
+  @staticmethod
   def NotFound(content, headers=None):
     '''Returns a not found (404) response.
     '''
diff --git a/chrome/common/extensions/docs/templates/public/apps/copresenceEndpoints.html b/chrome/common/extensions/docs/templates/public/apps/copresenceEndpoints.html
deleted file mode 100644
index bf67990..0000000
--- a/chrome/common/extensions/docs/templates/public/apps/copresenceEndpoints.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_apps_api api:apis.apps.copresence_endpoints/}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/documentScan.html b/chrome/common/extensions/docs/templates/public/apps/documentScan.html
new file mode 100644
index 0000000..755908d
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/apps/documentScan.html
@@ -0,0 +1 @@
+{{+partials.standard_apps_api api:apis.apps.document_scan intro:intros.documentScan/}}
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index a40fe6a..4ca22c0 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -229,9 +229,6 @@
       {APIPermission::kDeveloperPrivate,
        "developerPrivate",
        APIPermissionInfo::kFlagCannotBeOptional},
-      {APIPermission::kDiagnostics,
-       "diagnostics",
-       APIPermissionInfo::kFlagCannotBeOptional},
       {APIPermission::kDial, "dial", APIPermissionInfo::kFlagCannotBeOptional},
       {APIPermission::kDownloadsInternal, "downloadsInternal"},
       {APIPermission::kExperienceSamplingPrivate,
diff --git a/chrome/common/extensions/update_manifest_unittest.cc b/chrome/common/extensions/update_manifest_unittest.cc
index 36ea5d5b..8915ab75 100644
--- a/chrome/common/extensions/update_manifest_unittest.cc
+++ b/chrome/common/extensions/update_manifest_unittest.cc
@@ -17,14 +17,14 @@
 "</gupdate>";
 
 static const char valid_xml_with_hash[] =
-"<?xml version='1.0' encoding='UTF-8'?>"
-"<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>"
-" <app appid='12345'>"
-"  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'"
-"               version='1.2.3.4' prodversionmin='2.0.143.0' "
-"               hash='1234'/>"
-" </app>"
-"</gupdate>";
+    "<?xml version='1.0' encoding='UTF-8'?>"
+    "<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>"
+    " <app appid='12345'>"
+    "  <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'"
+    "               version='1.2.3.4' prodversionmin='2.0.143.0' "
+    "               hash_sha256='1234'/>"
+    " </app>"
+    "</gupdate>";
 
 static const char kMissingAppId[] =
 "<?xml version='1.0'?>"
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include
index 81bb746..3ff0fd6 100644
--- a/chrome/installer/linux/common/installer.include
+++ b/chrome/installer/linux/common/installer.include
@@ -172,11 +172,6 @@
   install -m 644 "${PEPPERFLASH_SRCDIR}/manifest.json" \
     "${PEPPERFLASH_DESTDIR}/"
 
-  # pdf plugin
-  if [ -f "${BUILDDIR}/libpdf.so" ]; then
-    install -m 644 -s "${BUILDDIR}/libpdf.so" "${STAGEDIR}/${INSTALLDIR}/"
-  fi
-
   # peerconnection shared library
   if [ -f "${BUILDDIR}/lib/libpeerconnection.so" ]; then
     install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/lib/"
diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release
index 5b07489..0c92e6d 100644
--- a/chrome/installer/mini_installer/chrome.release
+++ b/chrome/installer/mini_installer/chrome.release
@@ -9,7 +9,7 @@
 chrome.exe: %(ChromeDir)s\
 wow_helper.exe: %(ChromeDir)s\
 #
-# Chrome version dir aseembly manifest.
+# Chrome version dir assembly manifest.
 # The name of this file must match the name of the version dir, so we cannot
 # hard-code it.
 # // TODO(caitkp): Find a way to do this without wildcards.
@@ -25,6 +25,7 @@
 chrome_watcher.dll: %(VersionDir)s\
 d3dcompiler_47.dll: %(VersionDir)s\
 ffmpegsumo.dll: %(VersionDir)s\
+kasko.dll: %(VersionDir)s\
 icudt.dll: %(VersionDir)s\
 icudtl.dat: %(VersionDir)s\
 libEGL.dll: %(VersionDir)s\
@@ -34,7 +35,6 @@
 nacl_irt_x86_32.nexe: %(VersionDir)s\
 nacl_irt_x86_64.nexe: %(VersionDir)s\
 natives_blob.bin: %(VersionDir)s\
-pdf.dll: %(VersionDir)s\
 resources.pak: %(VersionDir)s\
 snapshot_blob.bin: %(VersionDir)s\
 syzyasan_rtl.dll: %(VersionDir)s\
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 2372e9d3..5454e8d 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -170,15 +170,15 @@
   archive_helper->set_patch_source(patch_source);
 
   // Try courgette first. Failing that, try bspatch.
-  if ((installer_state.UpdateStage(installer::ENSEMBLE_PATCHING),
-       !archive_helper->EnsemblePatch()) &&
-      (installer_state.UpdateStage(installer::BINARY_PATCHING),
-       !archive_helper->BinaryPatch())) {
-    *install_status = installer::APPLY_DIFF_PATCH_FAILED;
-    installer_state.WriteInstallerResult(*install_status,
-                                         IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
-                                         NULL);
-    return false;
+  installer_state.UpdateStage(installer::ENSEMBLE_PATCHING);
+  if (!archive_helper->EnsemblePatch()) {
+    installer_state.UpdateStage(installer::BINARY_PATCHING);
+    if (!archive_helper->BinaryPatch()) {
+      *install_status = installer::APPLY_DIFF_PATCH_FAILED;
+      installer_state.WriteInstallerResult(
+          *install_status, IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL);
+      return false;
+    }
   }
 
   *archive_type = installer::INCREMENTAL_ARCHIVE_TYPE;
diff --git a/chrome/interactive_ui_tests.isolate b/chrome/interactive_ui_tests.isolate
index bef04953..d968a7d 100644
--- a/chrome/interactive_ui_tests.isolate
+++ b/chrome/interactive_ui_tests.isolate
@@ -12,6 +12,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -76,6 +78,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 9367b98..0987379 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -43,10 +43,6 @@
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
-#if defined(OS_WIN)
-#include "base/win/iat_patch_function.h"
-#endif
-
 #if defined(ENABLE_EXTENSIONS)
 #include "chrome/renderer/extensions/extension_localization_peer.h"
 #endif
@@ -112,43 +108,6 @@
   DISALLOW_COPY_AND_ASSIGN(RendererResourceDelegate);
 };
 
-#if defined(OS_WIN)
-static base::win::IATPatchFunction g_iat_patch_createdca;
-HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
-                          LPCSTR device_name,
-                          LPCSTR output,
-                          const void* init_data) {
-  DCHECK(std::string("DISPLAY") == std::string(driver_name));
-  DCHECK(!device_name);
-  DCHECK(!output);
-  DCHECK(!init_data);
-
-  // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
-  return CreateCompatibleDC(NULL);
-}
-
-static base::win::IATPatchFunction g_iat_patch_get_font_data;
-DWORD WINAPI GetFontDataPatch(HDC hdc,
-                              DWORD table,
-                              DWORD offset,
-                              LPVOID buffer,
-                              DWORD length) {
-  int rv = GetFontData(hdc, table, offset, buffer, length);
-  if (rv == GDI_ERROR && hdc) {
-    HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
-
-    LOGFONT logfont;
-    if (GetObject(font, sizeof(LOGFONT), &logfont)) {
-      std::vector<char> font_data;
-      RenderThread::Get()->PreCacheFont(logfont);
-      rv = GetFontData(hdc, table, offset, buffer, length);
-      RenderThread::Get()->ReleaseCachedFonts();
-    }
-  }
-  return rv;
-}
-#endif  // OS_WIN
-
 static const int kWaitForWorkersStatsTimeoutMS = 20;
 
 class HeapStatisticsCollector {
@@ -280,22 +239,6 @@
   // Configure modules that need access to resources.
   net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
 
-#if defined(OS_WIN)
-  // TODO(scottmg): http://crbug.com/448473. This code should be removed once
-  // PDF is always OOP and/or PDF is made to use Skia instead of GDI directly.
-  if (!command_line.HasSwitch(switches::kEnableOutOfProcessPdf)) {
-    // Need to patch a few functions for font loading to work correctly.
-    base::FilePath pdf;
-    if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
-        base::PathExists(pdf)) {
-      g_iat_patch_createdca.Patch(pdf.value().c_str(), "gdi32.dll", "CreateDCA",
-                                  CreateDCAPatch);
-      g_iat_patch_get_font_data.Patch(pdf.value().c_str(), "gdi32.dll",
-                                      "GetFontData", GetFontDataPatch);
-    }
-  }
-#endif
-
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS)
   // On platforms where we use system NSS shared libraries,
   // initialize NSS now because it won't be able to load the .so's
diff --git a/chrome/renderer/media/OWNERS b/chrome/renderer/media/OWNERS
index 43bd1e5..cbadb65a 100644
--- a/chrome/renderer/media/OWNERS
+++ b/chrome/renderer/media/OWNERS
@@ -5,7 +5,6 @@
 scherkus@chromium.org
 sergeyu@chromium.org
 tommi@chromium.org
-vrk@chromium.org
 xhwang@chromium.org
 
 per-file cast_*=hclam@chromium.org
diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js
index 9dcf6261..309edacb 100644
--- a/chrome/renderer/resources/extensions/automation/automation_node.js
+++ b/chrome/renderer/resources/extensions/automation/automation_node.js
@@ -728,7 +728,7 @@
 
     // TODO(dtseng): Make into set listing all hosting node roles.
     if (nodeData.role == schema.RoleType.webView) {
-      if (nodeImpl.pendingChildFrame === undefined)
+      if (nodeImpl.childTreeID !== nodeData.intAttributes.childTreeId)
         nodeImpl.pendingChildFrame = true;
 
       if (nodeImpl.pendingChildFrame) {
diff --git a/chrome/renderer/resources/extensions/notifications_custom_bindings.js b/chrome/renderer/resources/extensions/notifications_custom_bindings.js
index eebf290..fc6b4425 100644
--- a/chrome/renderer/resources/extensions/notifications_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/notifications_custom_bindings.js
@@ -7,6 +7,7 @@
 var binding = require('binding').Binding.create('notifications');
 
 var sendRequest = require('sendRequest').sendRequest;
+var exceptionHandler = require('uncaught_exception_handler');
 var imageUtil = require('imageUtil');
 var lastError = require('lastError');
 var notificationsPrivate = requireNative('notifications_private');
@@ -111,20 +112,21 @@
   return function(id, input_notification_details, callback) {
     // TODO(dewittj): Remove this hack. This is used as a way to deep
     // copy a complex JSON object.
-    var notification_details = JSON.parse(
-        JSON.stringify(input_notification_details));
+    var notification_details = $JSON.parse(
+        $JSON.stringify(input_notification_details));
     var that = this;
+    var stack = exceptionHandler.getExtensionStackTrace();
     replaceNotificationOptionURLs(notification_details, function(success) {
       if (success) {
         sendRequest(that.name,
             [id, notification_details, callback],
-            that.definition.parameters);
+            that.definition.parameters, {stack: stack});
         return;
       }
       lastError.run(name,
                     'Unable to download all specified images.',
-                    null,
-                    failure_function, [callback, id])
+                    stack,
+                    failure_function, [callback || function() {}, id]);
     });
   };
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 588a4b4..1c24f05 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -124,6 +124,7 @@
 
   if (!is_ios) {
     deps += [
+      "//chrome/child",
       "//chrome/plugin",
       "//chrome/renderer",
       "//chrome/utility",
@@ -136,6 +137,7 @@
       "//components/captive_portal:test_support",
       "//components/infobars/core",
       "//components/sessions:test_support",
+      "//components/user_manager:test_support",
       "//components/web_resource:test_support",
       "//google_apis:test_support",
       "//ipc:test_support",
@@ -174,6 +176,7 @@
       "ppapi/ppapi_test.cc",
       "ppapi/ppapi_test.h",
     ]
+    deps += [ "//pdf" ]
   }
 
   if (use_ash) {
@@ -245,7 +248,6 @@
       "//net",
       "//net:net_resources",
       "//net:test_support",
-      "//pdf",
 
       #"//ppapi:ppapi_tests",  # TODO(GYP) this doesn't exist yet.
       "//skia",
@@ -627,6 +629,7 @@
       "//components/resources",
       "//components/strings",
       "//components/translate/core/common",
+      "//components/user_manager:test_support",
       "//crypto:platform",
       "//crypto:test_support",
       "//device/bluetooth:mocks",
@@ -1211,7 +1214,6 @@
       "//third_party/cacheinvalidation",
       "//third_party/icu",
       "//third_party/libxml",
-      "//ui/accelerometer",
       "//ui/base:test_support",
       "//ui/gfx:test_support",
       "//ui/resources",
@@ -1670,7 +1672,7 @@
     }
     if (use_ozone) {
       # crbug.com/354036
-      sources -= [ "browser/chromeos/events/event_rewriter_unittest.cc" ]
+      sources -= [ "../browser/chromeos/events/event_rewriter_unittest.cc" ]
     }
     if (!enable_plugin_installation) {
       sources -= [ "../browser/plugins/plugin_installer_unittest.cc" ]
diff --git a/chrome/test/base/extension_js_browser_test.h b/chrome/test/base/extension_js_browser_test.h
index 34cecdd..439e169 100644
--- a/chrome/test/base/extension_js_browser_test.h
+++ b/chrome/test/base/extension_js_browser_test.h
@@ -17,7 +17,7 @@
  public:
   ExtensionJSBrowserTest();
 
-  virtual ~ExtensionJSBrowserTest();
+  ~ExtensionJSBrowserTest() override;
 
  protected:
   // Waits for an extension to load; returns immediately if already loaded.
diff --git a/chrome/test/base/extension_load_waiter_one_shot.h b/chrome/test/base/extension_load_waiter_one_shot.h
index 47d22d6..15cae65 100644
--- a/chrome/test/base/extension_load_waiter_one_shot.h
+++ b/chrome/test/base/extension_load_waiter_one_shot.h
@@ -19,16 +19,16 @@
 class ExtensionLoadWaiterOneShot : public content::NotificationObserver {
  public:
   ExtensionLoadWaiterOneShot();
-  virtual ~ExtensionLoadWaiterOneShot();
+  ~ExtensionLoadWaiterOneShot() override;
 
   // Waits for extension with |extension_id| to load. The id should be a pointer
   // to a static char array.
   void WaitForExtension(const char* extension_id, const base::Closure& load_cb);
 
   // content::NotificationObserver overrides.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) override;
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
 
   // Get the browser context associated with the loaded extension. Returns
   // NULL if |WaitForExtension| was not previously called.
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 7f49296f..3c2a90f 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -569,21 +569,15 @@
           this, BuildHistoryService));
   if (!history_service->Init(
           no_db, history::HistoryDatabaseParamsForPath(this->GetPath()))) {
-    HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse(this, NULL);
+    HistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr);
+    return false;
   }
   // Disable WebHistoryService by default, since it makes network requests.
-  WebHistoryServiceFactory::GetInstance()->SetTestingFactory(this, NULL);
+  WebHistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr);
   return true;
 }
 
 void TestingProfile::DestroyHistoryService() {
-  // TODO(sdefresne): remove this once ChromeHistoryClient is no longer an
-  // HistoryServiceObserver, http://crbug.com/373326
-  ChromeHistoryClient* history_client =
-      ChromeHistoryClientFactory::GetForProfileWithoutCreating(this);
-  if (history_client)
-    history_client->Shutdown();
-
   HistoryService* history_service =
       HistoryServiceFactory::GetForProfileWithoutCreating(this);
   if (!history_service)
diff --git a/chrome/test/data/extensions/api_test/content_settings/standard/test.js b/chrome/test/data/extensions/api_test/content_settings/standard/test.js
index c2237d3e..72dad15 100644
--- a/chrome/test/data/extensions/api_test/content_settings/standard/test.js
+++ b/chrome/test/data/extensions/api_test/content_settings/standard/test.js
@@ -14,9 +14,12 @@
   "popups": "block",
   "location": "ask",
   "notifications": "ask",
+  "fullscreen": "ask",
   "mouselock": "ask",
   "microphone": "ask",
   "camera": "ask",
+  "unsandboxedPlugins": "ask",
+  "automaticDownloads": "ask"
 };
 
 var settings = {
@@ -27,9 +30,12 @@
   "popups": "allow",
   "location": "block",
   "notifications": "block",
+  "fullscreen": "allow",
   "mouselock": "block",
   "microphone": "block",
-  "camera": "block"
+  "camera": "block",
+  "unsandboxedPlugins": "block",
+  "automaticDownloads": "block"
 };
 
 Object.prototype.forEach = function(f) {
diff --git a/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js b/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js
index e1d0106..001f6db 100644
--- a/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js
+++ b/chrome/test/data/extensions/api_test/notifications/api/basic_usage/background.js
@@ -325,7 +325,32 @@
   create("largeImage", options).then(succeed, fail);
 }
 
+function testOptionalParameters() {
+  var testName = "testOptionalParameters";
+  var succeed = succeedTest(testName);
+  var fail = failTest(testName);
+  function createCallback(notificationId) {
+    new Promise(function() {
+      chrome.test.assertNoLastError();
+      chrome.test.assertEq("string", typeof notificationId);
+      // Optional callback - should run without problems
+      chrome.notifications.clear(notificationId);
+      // Note: The point of the previous line is to show that a callback can be
+      // optional. Because .clear is asynchronous, we have to be careful with
+      // calling .clear again. Since .clear is processed in order, calling
+      // clear() synchronously is okay.
+      // If this assumption does not hold and leaks to flaky tests, file a bug
+      // report and/or put the following call in a setTimeout call.
+
+      // The notification should not exist any more, so clear() should fail.
+      clear(notificationId).then(fail, succeed);
+    }).then(null, fail);
+  }
+  // .create should succeed even when notificationId is omitted.
+  chrome.notifications.create(basicNotificationOptions, createCallback);
+}
+
 chrome.test.runTests([
     testIdUsage, testBaseFormat, testListItem, testGetAll, testProgress,
-    testLargeImage
+    testLargeImage, testOptionalParameters
 ]);
diff --git a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
index 91e7db8..763b63d 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
+++ b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
@@ -1421,16 +1421,14 @@
 // chrome URL is provided.
 function testLoadAbortIllegalChromeURL() {
   var webview = document.createElement('webview');
-  var onFirstLoadStop = function(e) {
-    webview.removeEventListener('loadstop', onFirstLoadStop);
-    webview.setAttribute('src', 'chrome://newtab');
-  };
-  webview.addEventListener('loadstop', onFirstLoadStop);
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
+  });
+  webview.addEventListener('loadstop', function(e)  {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
-  webview.setAttribute('src', 'about:blank');
+  webview.src = 'chrome://newtab';
   document.body.appendChild(webview);
 }
 
@@ -1438,9 +1436,12 @@
   var webview = document.createElement('webview');
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
-  webview.setAttribute('src', 'file://foo');
+  webview.src = 'file://foo';
   document.body.appendChild(webview);
 }
 
@@ -1448,6 +1449,9 @@
   var webview = document.createElement('webview');
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
   webview.setAttribute('src', 'javascript:void(document.bgColor="#0000FF")');
@@ -1457,17 +1461,19 @@
 // Verifies that navigating to invalid URL (e.g. 'http:') doesn't cause a crash.
 function testLoadAbortInvalidNavigation() {
   var webview = document.createElement('webview');
-  var validSchemeWithEmptyURL = 'http:';
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
     embedder.test.assertEq('', e.url);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
   webview.addEventListener('exit', function(e) {
     // We should not crash.
     embedder.test.fail();
   });
-  webview.setAttribute('src', validSchemeWithEmptyURL);
+  webview.src = 'http:';
   document.body.appendChild(webview);
 }
 
@@ -1475,17 +1481,20 @@
 // pseudo-scheme fires loadabort and doesn't cause a crash.
 function testLoadAbortNonWebSafeScheme() {
   var webview = document.createElement('webview');
-  var chromeGuestURL = 'chrome-guest://abc123';
+  var chromeGuestURL = 'chrome-guest://abc123/';
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
-    embedder.test.assertEq('chrome-guest://abc123/', e.url);
+    embedder.test.assertEq(chromeGuestURL, e.url);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
   webview.addEventListener('exit', function(e) {
     // We should not crash.
     embedder.test.fail();
   });
-  webview.setAttribute('src', chromeGuestURL);
+  webview.src = chromeGuestURL;
   document.body.appendChild(webview);
 };
 
diff --git a/chrome/test/data/frame_tree/page_with_two_frames_remote_and_local.html b/chrome/test/data/frame_tree/page_with_two_frames_remote_and_local.html
new file mode 100644
index 0000000..4e5f365
--- /dev/null
+++ b/chrome/test/data/frame_tree/page_with_two_frames_remote_and_local.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<html>
+<head></head>
+<body>
+  This page has two iframes: one is cross-site, the other is same-site.
+  <iframe src="/cross-site/bar.com/title1.html"></iframe>
+  <iframe src="/title1.html"></iframe>
+</body>
+</html>
diff --git a/chrome/test/data/webui/history_browsertest.js b/chrome/test/data/webui/history_browsertest.js
index 8aacf42..03350b7 100644
--- a/chrome/test/data/webui/history_browsertest.js
+++ b/chrome/test/data/webui/history_browsertest.js
@@ -787,7 +787,7 @@
 
 TEST_F('HistoryWebUIRealBackendTest', 'atLeastOneFocusable', function() {
   var results = document.querySelectorAll('#results-display [tabindex="0"]');
-  expectEquals(1, results.length);
+  expectGE(results.length, 1);
   testDone();
 });
 
@@ -1004,7 +1004,7 @@
 
 TEST_F('HistoryWebUIDeleteProhibitedTest', 'atLeastOneFocusable', function() {
   var results = document.querySelectorAll('#results-display [tabindex="0"]');
-  expectEquals(1, results.length);
+  expectGE(results.length, 1);
   testDone();
 });
 
diff --git a/chrome/test/data/webui/net_internals/chromeos_view.js b/chrome/test/data/webui/net_internals/chromeos_view.js
index 4420225..35454b1 100644
--- a/chrome/test/data/webui/net_internals/chromeos_view.js
+++ b/chrome/test/data/webui/net_internals/chromeos_view.js
@@ -47,10 +47,13 @@
 };
 
 TEST_F('NetInternalsTest',
-       'DISABLED_netInternalsChromeOSViewStoreDebugLogs',
+       'netInternalsChromeOSViewStoreDebugLogs',
        function() {
-  if (!cr.isChromeOS)
+  if (!cr.isChromeOS) {
     testDone();
+    return;
+  }
+
   // #chromeos-view-import-onc fails accessibility check.
   this.runAccessibilityChecks = false;
   NetInternalsTest.switchToView('chromeos');
diff --git a/chrome/tools/build/chromeos/FILES.cfg b/chrome/tools/build/chromeos/FILES.cfg
index 801a5a7..ee70795 100644
--- a/chrome/tools/build/chromeos/FILES.cfg
+++ b/chrome/tools/build/chromeos/FILES.cfg
@@ -113,11 +113,6 @@
     'buildtype': ['official'],
     'direct_archive': 1,
   },
-  # PDF Plugin files:
-  {
-    'filename': 'libpdf.so',
-    'buildtype': ['dev', 'official'],
-  },
   # Native Client plugin files:
   {
     'filename': 'nacl_irt_x86_32.nexe',
diff --git a/chrome/tools/build/linux/FILES.cfg b/chrome/tools/build/linux/FILES.cfg
index d406d7ae..0862176 100644
--- a/chrome/tools/build/linux/FILES.cfg
+++ b/chrome/tools/build/linux/FILES.cfg
@@ -130,11 +130,6 @@
     'filename': 'PepperFlash',
     'buildtype': ['official'],
   },
-  # PDF Plugin files:
-  {
-    'filename': 'libpdf.so',
-    'buildtype': ['dev', 'official'],
-  },
   # Native Client plugin files:
   {
     'filename': 'nacl_irt_x86_32.nexe',
@@ -195,18 +190,6 @@
     'archive': 'breakpad-info.zip',
   },
   {
-    'filename': 'libpdf.so.breakpad.ia32',
-    'arch': ['32bit'],
-    'buildtype': ['official'],
-    'archive': 'breakpad-info.zip',
-  },
-  {
-    'filename': 'libpdf.so.breakpad.x64',
-    'arch': ['64bit'],
-    'buildtype': ['official'],
-    'archive': 'breakpad-info.zip',
-  },
-  {
     'filename': 'nacl_irt_x86_32.nexe.debug',
     'arch': ['32bit'],
     'buildtype': ['official'],
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index bbdfa7e1..fb547cb 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -369,12 +369,6 @@
     'filename': 'widevinecdmadapter.dll',
     'buildtype': ['official'],
   },
-  # PDF Plugin files:
-  {
-    'filename': 'pdf.dll',
-    'buildtype': ['dev', 'official'],
-    'filegroup': ['default', 'symsrc'],
-  },
   # ANGLE files:
   {
     'filename': 'D3DCompiler_47.dll',
@@ -595,6 +589,14 @@
     'buildtype': ['dev', 'official'],
     'optional': ['dev', 'official'],
   },
+  {
+    'filename': 'syzygy/kasko.dll',
+    'arch': ['32bit'],
+    'buildtype': ['dev', 'official'],
+    'archive': 'syzygy/kasko.dll',
+    'filegroup': ['symsrc'],
+    'optional': ['dev', 'official'],
+  },
   # Test binaries for external QA:
   {
     'filename': 'interactive_ui_tests.exe',
@@ -709,11 +711,6 @@
     'archive': 'chrome-win32-syms.zip',
   },
   {
-    'filename': 'pdf.dll.pdb',
-    'buildtype': ['dev', 'official'],
-    'archive': 'chrome-win32-syms.zip',
-  },
-  {
     'filename': 'setup.exe.pdb',
     'buildtype': ['dev', 'official'],
     'archive': 'chrome-win32-syms.zip',
@@ -766,6 +763,13 @@
     'optional': ['dev', 'official'],
   },
   {
+    'filename': 'syzygy/kasko.dll.pdb',
+    'arch': ['32bit'],
+    'buildtype': ['dev', 'official'],
+    'archive': 'chrome-win32-syms.zip',
+    'optional': ['dev', 'official'],
+  },
+  {
     'filename': 'nacl_irt_x86_32.nexe.debug',
     'arch': ['32bit'],
     'buildtype': ['official'],
diff --git a/chrome/tools/crash_service/caps/caps.gyp b/chrome/tools/crash_service/caps/caps.gyp
index f18f84d..bcbe414 100644
--- a/chrome/tools/crash_service/caps/caps.gyp
+++ b/chrome/tools/crash_service/caps/caps.gyp
@@ -39,14 +39,21 @@
       'target_name': 'caps',
       'type': 'executable',
       'include_dirs': [
-        '../..',
+        '..',
       ],
       'sources': [
+        'exit_codes.h',
+        'logger_win.cc',
+        'logger_win.h',
         'main_win.cc',
+        'process_singleton_win.cc',
+        'process_singleton_win.h',
         '<(SHARED_INTERMEDIATE_DIR)/caps/caps_version.rc',
       ],
       'dependencies': [
         'caps_resources',
+        '../../../../base/base.gyp:base',
+        '../../../../chrome/chrome.gyp:common_version',
       ],
       'msvs_settings': {
         'VCLinkerTool': {
diff --git a/chrome/tools/crash_service/caps/exit_codes.h b/chrome/tools/crash_service/caps/exit_codes.h
new file mode 100644
index 0000000..583e0a5c
--- /dev/null
+++ b/chrome/tools/crash_service/caps/exit_codes.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 CHROME_TOOLS_CRASH_SERVICE_CAPS_EXIT_CODES_H_
+#define CHROME_TOOLS_CRASH_SERVICE_CAPS_EXIT_CODES_H_
+
+namespace caps {
+
+// Exit codes for CAPS. Don't reorder these values.
+enum ExitCodes {
+  EC_NORMAL_EXIT = 0,
+  EC_EXISTING_INSTANCE,
+  EC_INIT_ERROR,
+  EC_LAST_CODE
+};
+
+}  // namespace caps
+
+#endif  // CHROME_TOOLS_CRASH_SERVICE_CAPS_EXIT_CODES_H_
+
diff --git a/chrome/tools/crash_service/caps/logger_win.cc b/chrome/tools/crash_service/caps/logger_win.cc
new file mode 100644
index 0000000..2e4a1cf
--- /dev/null
+++ b/chrome/tools/crash_service/caps/logger_win.cc
@@ -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.
+
+#include <windows.h>
+#include <time.h>
+
+#include "base/files/file_path.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/chrome_version_info_values.h"
+#include "chrome/tools/crash_service/caps/logger_win.h"
+
+namespace {
+// Every message has this structure:
+// <index>~ <tick_count> <message> ~\n"
+const char kMessageHeader[] = "%03d~ %08x %s ~\n";
+
+// Do not re-order these messages. Only add at the end.
+const char* kMessages[] {
+  "start pid(%lu) version(%s) time(%s)",                    // 0
+  "exit pid(%lu) time(%s)",                                 // 1
+  "instance found",                                         // 2
+};
+
+bool WriteLogLine(HANDLE file, const std::string& txt) {
+  if (txt.empty())
+    return true;
+  DWORD written;
+  auto rc = ::WriteFile(file, txt.c_str(),
+                        static_cast<DWORD>(txt.size()),
+                        &written,
+                        nullptr);
+  return (rc == TRUE);
+}
+
+// Uses |kMessages| at |index| above to write to disk a formatted log line.
+bool WriteFormattedLogLine(HANDLE file, size_t index, ...) {
+  va_list ap;
+  va_start(ap, index);
+  auto fmt = base::StringPrintf(
+      kMessageHeader, index, ::GetTickCount(), kMessages[index]);
+  auto msg = base::StringPrintV(fmt.c_str(), ap);
+  auto rc = WriteLogLine(file, msg.c_str());
+  va_end(ap);
+  return rc;
+}
+
+// Returns the current time and date formatted in standard C style.
+std::string DateTime() {
+  time_t current_time = 0;
+  time(&current_time);
+  struct tm local_time = {0};
+  char time_buf[26] = {0};
+  localtime_s(&local_time, &current_time);
+  asctime_s(time_buf, &local_time);
+  time_buf[24] = '\0';
+  return time_buf;
+}
+
+}  // namespace
+
+namespace caps {
+
+Logger::Logger(const base::FilePath& path) : file_(INVALID_HANDLE_VALUE) {
+  auto logfile = path.Append(L"caps_log.txt");
+  // Opening a file like so allows atomic appends, but can't be used
+  // for anything else.
+  DWORD kShareAll = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+  file_ = ::CreateFile(logfile.value().c_str(),
+                       FILE_APPEND_DATA, kShareAll,
+                       nullptr,
+                       OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                       nullptr);
+  if (file_ == INVALID_HANDLE_VALUE)
+    return;
+  WriteFormattedLogLine(
+      file_, 0, ::GetCurrentProcessId(), PRODUCT_VERSION, DateTime().c_str());
+}
+
+Logger::~Logger() {
+  if (file_ != INVALID_HANDLE_VALUE) {
+    WriteFormattedLogLine(
+        file_, 1, ::GetCurrentProcessId(), DateTime().c_str());
+    ::CloseHandle(file_);
+  }
+}
+
+}  // namespace caps
+
diff --git a/chrome/tools/crash_service/caps/logger_win.h b/chrome/tools/crash_service/caps/logger_win.h
new file mode 100644
index 0000000..efa0b94
--- /dev/null
+++ b/chrome/tools/crash_service/caps/logger_win.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TOOLS_CRASH_SERVICE_CAPS_LOGGER_WIN_H_
+#define CHROME_TOOLS_CRASH_SERVICE_CAPS_LOGGER_WIN_H_
+
+#include <windows.h>
+
+#include "base/macros.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace caps {
+// Creates a human-readable activity log file.
+class Logger {
+public:
+  explicit Logger(const base::FilePath& path);
+  ~Logger();
+
+private:
+  HANDLE file_;
+
+  DISALLOW_COPY_AND_ASSIGN(Logger);
+};
+
+}  // namespace caps
+
+#endif  // CHROME_TOOLS_CRASH_SERVICE_CAPS_LOGGER_WIN_H_
+
diff --git a/chrome/tools/crash_service/caps/main_win.cc b/chrome/tools/crash_service/caps/main_win.cc
index b2c01745..61461652 100644
--- a/chrome/tools/crash_service/caps/main_win.cc
+++ b/chrome/tools/crash_service/caps/main_win.cc
@@ -4,6 +4,33 @@
 
 #include <windows.h>
 
+#include "base/at_exit.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/version.h"
+#include "chrome/tools/crash_service/caps/exit_codes.h"
+#include "chrome/tools/crash_service/caps/logger_win.h"
+#include "chrome/tools/crash_service/caps/process_singleton_win.h"
+
 int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
-  return 0;
+  base::AtExitManager at_exit_manager;
+  base::FilePath dir_exe;
+  if (!PathService::Get(base::DIR_EXE, &dir_exe))
+    return caps::EC_INIT_ERROR;
+
+  // What directory we write depends if we are being run from the actual
+  // location (a versioned directory) or from a build output directory.
+  base::Version version(dir_exe.BaseName().MaybeAsASCII());
+  auto data_path = version.IsValid() ? dir_exe.DirName() : dir_exe;
+
+  // Start logging.
+  caps::Logger logger(data_path);
+
+  // Check for an existing running instance.
+  caps::ProcessSingleton process_singleton;
+  if (process_singleton.other_instance())
+    return caps::EC_EXISTING_INSTANCE;
+
+  return caps::EC_NORMAL_EXIT;
 }
+
diff --git a/chrome/tools/crash_service/caps/process_singleton_win.cc b/chrome/tools/crash_service/caps/process_singleton_win.cc
new file mode 100644
index 0000000..f51accc
--- /dev/null
+++ b/chrome/tools/crash_service/caps/process_singleton_win.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 <windows.h>
+
+#include "chrome/tools/crash_service/caps/process_singleton_win.h"
+
+namespace caps {
+
+ProcessSingleton::ProcessSingleton() : mutex_(nullptr) {
+  auto mutex = ::CreateMutex(nullptr, TRUE, L"CHROME.CAPS.V1");
+  if (!mutex)
+    return;
+  if (::GetLastError() == ERROR_ALREADY_EXISTS) {
+    ::CloseHandle(mutex);
+    return;
+  }
+  // We are now the single instance.
+  mutex_ = mutex;
+}
+
+ProcessSingleton::~ProcessSingleton() {
+  if (mutex_)
+    ::CloseHandle(mutex_);
+}
+
+}  // namespace caps
+
diff --git a/chrome/tools/crash_service/caps/process_singleton_win.h b/chrome/tools/crash_service/caps/process_singleton_win.h
new file mode 100644
index 0000000..5440d9c
--- /dev/null
+++ b/chrome/tools/crash_service/caps/process_singleton_win.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TOOLS_CRASH_SERVICE_CAPS_PROCESS_SINGLETON_WIN_H_
+#define CHROME_TOOLS_CRASH_SERVICE_CAPS_PROCESS_SINGLETON_WIN_H_
+
+#include <windows.h>
+
+#include "base/macros.h"
+
+namespace caps {
+// Uses a named mutex to make sure that only one process of
+// with this particular version is launched.
+class ProcessSingleton {
+public:
+  ProcessSingleton();
+  ~ProcessSingleton();
+  bool other_instance() const { return mutex_ == NULL; }
+
+private:
+  HANDLE mutex_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
+};
+
+}  // namespace caps
+
+#endif  // CHROME_TOOLS_CRASH_SERVICE_CAPS_PROCESS_SINGLETON_WIN_H_
+
diff --git a/chrome/unit_tests.isolate b/chrome/unit_tests.isolate
index 446550b8..a03f8a5 100644
--- a/chrome/unit_tests.isolate
+++ b/chrome/unit_tests.isolate
@@ -49,6 +49,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -102,6 +104,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index e06aebc..843b1f3 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -166,10 +166,6 @@
   extensions::ExtensionsHandler::PreSandboxStartup();
 #endif
 
-#if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
-  PrintingHandler::PreSandboxStartup();
-#endif
-
 #if defined(ENABLE_MDNS)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kUtilityProcessEnableMDns)) {
diff --git a/chrome/utility/printing_handler.cc b/chrome/utility/printing_handler.cc
index b69d6ea..9e282ad 100644
--- a/chrome/utility/printing_handler.cc
+++ b/chrome/utility/printing_handler.cc
@@ -13,11 +13,11 @@
 #include "chrome/utility/cloud_print/bitmap_image.h"
 #include "chrome/utility/cloud_print/pwg_encoder.h"
 #include "content/public/utility/utility_thread.h"
+#include "pdf/pdf.h"
 #include "printing/page_range.h"
 #include "printing/pdf_render_settings.h"
 
 #if defined(OS_WIN)
-#include "base/win/iat_patch_function.h"
 #include "printing/emf_win.h"
 #include "ui/gfx/gdi_util.h"
 #endif
@@ -37,225 +37,12 @@
   content::UtilityThread::Get()->ReleaseProcessIfNeeded();
 }
 
-class PdfFunctionsBase {
- public:
-  PdfFunctionsBase() : render_pdf_to_bitmap_func_(NULL),
-                       get_pdf_doc_info_func_(NULL) {}
-
-  bool Init() {
-    base::FilePath pdf_module_path;
-    if (!PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_module_path) ||
-        !base::PathExists(pdf_module_path)) {
-      return false;
-    }
-
-    pdf_lib_.Reset(base::LoadNativeLibrary(pdf_module_path, NULL));
-    if (!pdf_lib_.is_valid()) {
-      LOG(WARNING) << "Couldn't load PDF plugin";
-      return false;
-    }
-
-    render_pdf_to_bitmap_func_ =
-        reinterpret_cast<RenderPDFPageToBitmapProc>(
-            pdf_lib_.GetFunctionPointer("RenderPDFPageToBitmap"));
-    LOG_IF(WARNING, !render_pdf_to_bitmap_func_) <<
-        "Missing RenderPDFPageToBitmap";
-
-    get_pdf_doc_info_func_ =
-        reinterpret_cast<GetPDFDocInfoProc>(
-            pdf_lib_.GetFunctionPointer("GetPDFDocInfo"));
-    LOG_IF(WARNING, !get_pdf_doc_info_func_) << "Missing GetPDFDocInfo";
-
-    if (!render_pdf_to_bitmap_func_ || !get_pdf_doc_info_func_ ||
-        !PlatformInit(pdf_module_path, pdf_lib_)) {
-      Reset();
-    }
-
-    return IsValid();
-  }
-
-  bool IsValid() const {
-    return pdf_lib_.is_valid();
-  }
-
-  void Reset() {
-    pdf_lib_.Reset(NULL);
-  }
-
-  bool RenderPDFPageToBitmap(const void* pdf_buffer,
-                             int pdf_buffer_size,
-                             int page_number,
-                             void* bitmap_buffer,
-                             int bitmap_width,
-                             int bitmap_height,
-                             int dpi_x,
-                             int dpi_y,
-                             bool autorotate) {
-    if (!render_pdf_to_bitmap_func_)
-      return false;
-    return render_pdf_to_bitmap_func_(pdf_buffer, pdf_buffer_size, page_number,
-                                      bitmap_buffer, bitmap_width,
-                                      bitmap_height, dpi_x, dpi_y, autorotate);
-  }
-
-  bool GetPDFDocInfo(const void* pdf_buffer,
-                     int buffer_size,
-                     int* page_count,
-                     double* max_page_width) {
-    if (!get_pdf_doc_info_func_)
-      return false;
-    return get_pdf_doc_info_func_(pdf_buffer, buffer_size, page_count,
-                                  max_page_width);
-  }
-
- protected:
-  virtual bool PlatformInit(
-      const base::FilePath& pdf_module_path,
-      const base::ScopedNativeLibrary& pdf_lib) {
-    return true;
-  }
-
- private:
-  // Exported by PDF plugin.
-  typedef bool (*RenderPDFPageToBitmapProc)(const void* pdf_buffer,
-                                            int pdf_buffer_size,
-                                            int page_number,
-                                            void* bitmap_buffer,
-                                            int bitmap_width,
-                                            int bitmap_height,
-                                            int dpi_x,
-                                            int dpi_y,
-                                            bool autorotate);
-  typedef bool (*GetPDFDocInfoProc)(const void* pdf_buffer,
-                                    int buffer_size, int* page_count,
-                                    double* max_page_width);
-
-  RenderPDFPageToBitmapProc render_pdf_to_bitmap_func_;
-  GetPDFDocInfoProc get_pdf_doc_info_func_;
-
-  base::ScopedNativeLibrary pdf_lib_;
-  DISALLOW_COPY_AND_ASSIGN(PdfFunctionsBase);
-};
-
-#if defined(OS_WIN)
-// The 2 below IAT patch functions are almost identical to the code in
-// render_process_impl.cc. This is needed to work around specific Windows APIs
-// used by the Chrome PDF plugin that will fail in the sandbox.
-static base::win::IATPatchFunction g_iat_patch_createdca;
-HDC WINAPI UtilityProcess_CreateDCAPatch(LPCSTR driver_name,
-                                         LPCSTR device_name,
-                                         LPCSTR output,
-                                         const DEVMODEA* init_data) {
-  if (driver_name && (std::string("DISPLAY") == driver_name)) {
-    // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
-    return CreateCompatibleDC(NULL);
-  }
-
-  NOTREACHED();
-  return CreateDCA(driver_name, device_name, output, init_data);
-}
-
-static base::win::IATPatchFunction g_iat_patch_get_font_data;
-DWORD WINAPI UtilityProcess_GetFontDataPatch(
-    HDC hdc, DWORD table, DWORD offset, LPVOID buffer, DWORD length) {
-  int rv = GetFontData(hdc, table, offset, buffer, length);
-  if (rv == GDI_ERROR && hdc) {
-    HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
-
-    LOGFONT logfont;
-    if (GetObject(font, sizeof(LOGFONT), &logfont)) {
-      content::UtilityThread::Get()->PreCacheFont(logfont);
-      rv = GetFontData(hdc, table, offset, buffer, length);
-      content::UtilityThread::Get()->ReleaseCachedFonts();
-    }
-  }
-  return rv;
-}
-
-class PdfFunctionsWin : public PdfFunctionsBase {
- public:
-  PdfFunctionsWin() : render_pdf_to_dc_func_(NULL) {
-  }
-
-  bool PlatformInit(
-      const base::FilePath& pdf_module_path,
-      const base::ScopedNativeLibrary& pdf_lib) override {
-    // Patch the IAT for handling specific APIs known to fail in the sandbox.
-    if (!g_iat_patch_createdca.is_patched()) {
-      g_iat_patch_createdca.Patch(pdf_module_path.value().c_str(),
-                                  "gdi32.dll", "CreateDCA",
-                                  UtilityProcess_CreateDCAPatch);
-    }
-
-    if (!g_iat_patch_get_font_data.is_patched()) {
-      g_iat_patch_get_font_data.Patch(pdf_module_path.value().c_str(),
-                                      "gdi32.dll", "GetFontData",
-                                      UtilityProcess_GetFontDataPatch);
-    }
-    render_pdf_to_dc_func_ =
-      reinterpret_cast<RenderPDFPageToDCProc>(
-          pdf_lib.GetFunctionPointer("RenderPDFPageToDC"));
-    LOG_IF(WARNING, !render_pdf_to_dc_func_) << "Missing RenderPDFPageToDC";
-
-    return render_pdf_to_dc_func_ != NULL;
-  }
-
-  bool RenderPDFPageToDC(const void* pdf_buffer,
-                         int buffer_size,
-                         int page_number,
-                         HDC dc,
-                         int dpi_x,
-                         int dpi_y,
-                         int bounds_origin_x,
-                         int bounds_origin_y,
-                         int bounds_width,
-                         int bounds_height,
-                         bool fit_to_bounds,
-                         bool stretch_to_bounds,
-                         bool keep_aspect_ratio,
-                         bool center_in_bounds,
-                         bool autorotate) {
-    if (!render_pdf_to_dc_func_)
-      return false;
-    return render_pdf_to_dc_func_(pdf_buffer, buffer_size, page_number,
-                                  dc, dpi_x, dpi_y, bounds_origin_x,
-                                  bounds_origin_y, bounds_width, bounds_height,
-                                  fit_to_bounds, stretch_to_bounds,
-                                  keep_aspect_ratio, center_in_bounds,
-                                  autorotate);
-  }
-
- private:
-  // Exported by PDF plugin.
-  typedef bool (*RenderPDFPageToDCProc)(
-      const void* pdf_buffer, int buffer_size, int page_number, HDC dc,
-      int dpi_x, int dpi_y, int bounds_origin_x, int bounds_origin_y,
-      int bounds_width, int bounds_height, bool fit_to_bounds,
-      bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds,
-      bool autorotate);
-  RenderPDFPageToDCProc render_pdf_to_dc_func_;
-
-  DISALLOW_COPY_AND_ASSIGN(PdfFunctionsWin);
-};
-
-typedef PdfFunctionsWin PdfFunctions;
-#else  // OS_WIN
-typedef PdfFunctionsBase PdfFunctions;
-#endif  // OS_WIN
-
-base::LazyInstance<PdfFunctions> g_pdf_lib = LAZY_INSTANCE_INITIALIZER;
-
 }  // namespace
 
 PrintingHandler::PrintingHandler() {}
 
 PrintingHandler::~PrintingHandler() {}
 
-// static
-void PrintingHandler::PreSandboxStartup() {
-  g_pdf_lib.Get().Init();
-}
-
 bool PrintingHandler::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(PrintingHandler, message)
@@ -328,9 +115,6 @@
 
 #if defined(OS_WIN)
 int PrintingHandler::LoadPDF(base::File pdf_file) {
-  if (!g_pdf_lib.Get().IsValid())
-    return 0;
-
   int64 length64 = pdf_file.GetLength();
   if (length64 <= 0 || length64 > std::numeric_limits<int>::max())
     return 0;
@@ -341,7 +125,7 @@
     return 0;
 
   int total_page_count = 0;
-  if (!g_pdf_lib.Get().GetPDFDocInfo(
+  if (!chrome_pdf::GetPDFDocInfo(
           &pdf_data_.front(), pdf_data_.size(), &total_page_count, NULL)) {
     return 0;
   }
@@ -370,13 +154,12 @@
   // The underlying metafile is of type Emf and ignores the arguments passed
   // to StartPage.
   metafile.StartPage(gfx::Size(), gfx::Rect(), 1);
-  if (!g_pdf_lib.Get().RenderPDFPageToDC(
+  if (!chrome_pdf::RenderPDFPageToDC(
           &pdf_data_.front(),
           pdf_data_.size(),
           page_number,
           metafile.context(),
           pdf_rendering_settings_.dpi(),
-          pdf_rendering_settings_.dpi(),
           pdf_rendering_settings_.area().x(),
           pdf_rendering_settings_.area().y(),
           pdf_rendering_settings_.area().width(),
@@ -402,9 +185,6 @@
     const printing::PwgRasterSettings& bitmap_settings,
     base::File bitmap_file) {
   bool autoupdate = true;
-  if (!g_pdf_lib.Get().IsValid())
-    return false;
-
   base::File::Info info;
   if (!pdf_file.GetInfo(&info) || info.size <= 0 ||
       info.size > std::numeric_limits<int>::max())
@@ -416,8 +196,8 @@
     return false;
 
   int total_page_count = 0;
-  if (!g_pdf_lib.Get().GetPDFDocInfo(data.data(), data_size,
-                                     &total_page_count, NULL)) {
+  if (!chrome_pdf::GetPDFDocInfo(data.data(), data_size,
+                                 &total_page_count, NULL)) {
     return false;
   }
 
@@ -438,15 +218,14 @@
       page_number = total_page_count - 1 - page_number;
     }
 
-    if (!g_pdf_lib.Get().RenderPDFPageToBitmap(data.data(),
-                                               data_size,
-                                               page_number,
-                                               image.pixel_data(),
-                                               image.size().width(),
-                                               image.size().height(),
-                                               settings.dpi(),
-                                               settings.dpi(),
-                                               autoupdate)) {
+    if (!chrome_pdf::RenderPDFPageToBitmap(data.data(),
+                                           data_size,
+                                           page_number,
+                                           image.pixel_data(),
+                                           image.size().width(),
+                                           image.size().height(),
+                                           settings.dpi(),
+                                           autoupdate)) {
       return false;
     }
 
diff --git a/chrome/utility/printing_handler.h b/chrome/utility/printing_handler.h
index cc490ba..341a358 100644
--- a/chrome/utility/printing_handler.h
+++ b/chrome/utility/printing_handler.h
@@ -27,8 +27,6 @@
   PrintingHandler();
   ~PrintingHandler() override;
 
-  static void PreSandboxStartup();
-
   // IPC::Listener:
   bool OnMessageReceived(const IPC::Message& message) override;
 
diff --git a/chromecast/browser/android/cast_window_android.cc b/chromecast/browser/android/cast_window_android.cc
index 8503fd6..eef789c 100644
--- a/chromecast/browser/android/cast_window_android.cc
+++ b/chromecast/browser/android/cast_window_android.cc
@@ -107,7 +107,7 @@
 void CastWindowAndroid::AddNewContents(content::WebContents* source,
                                        content::WebContents* new_contents,
                                        WindowOpenDisposition disposition,
-                                       const gfx::Rect& initial_pos,
+                                       const gfx::Rect& initial_rect,
                                        bool user_gesture,
                                        bool* was_blocked) {
   NOTIMPLEMENTED();
diff --git a/chromecast/browser/android/cast_window_android.h b/chromecast/browser/android/cast_window_android.h
index 281f140..b7073619 100644
--- a/chromecast/browser/android/cast_window_android.h
+++ b/chromecast/browser/android/cast_window_android.h
@@ -59,7 +59,7 @@
   virtual void AddNewContents(content::WebContents* source,
                               content::WebContents* new_contents,
                               WindowOpenDisposition disposition,
-                              const gfx::Rect& initial_pos,
+                              const gfx::Rect& initial_rect,
                               bool user_gesture,
                               bool* was_blocked) override;
   virtual void CloseContents(content::WebContents* source) override;
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index e7bcbc9..263d595 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -168,12 +168,21 @@
 }
 
 int CastBrowserMainParts::PreCreateThreads() {
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+  // GPU process is started immediately after threads are created, requiring
+  // CrashDumpManager to be initialized beforehand.
+  base::FilePath crash_dumps_dir;
+  if (!chromecast::CrashHandler::GetCrashDumpLocation(&crash_dumps_dir)) {
+    LOG(ERROR) << "Could not find crash dump location.";
+  }
+  cast_browser_process_->SetCrashDumpManager(
+      make_scoped_ptr(new breakpad::CrashDumpManager(crash_dumps_dir)));
+#else
   base::FilePath home_dir;
   CHECK(PathService::Get(DIR_CAST_HOME, &home_dir));
   if (!base::CreateDirectory(home_dir))
     return 1;
-#endif  // !defined(OS_ANDROID)
+#endif
   return 0;
 }
 
@@ -199,15 +208,6 @@
           cast_browser_process_->pref_service(),
           cast_browser_process_->browser_context()->GetRequestContext()));
 
-#if defined(OS_ANDROID)
-  base::FilePath crash_dumps_dir;
-  if (!chromecast::CrashHandler::GetCrashDumpLocation(&crash_dumps_dir)) {
-    LOG(ERROR) << "Could not find crash dump location.";
-  }
-  cast_browser_process_->SetCrashDumpManager(
-      make_scoped_ptr(new breakpad::CrashDumpManager(crash_dumps_dir)));
-#endif
-
   if (!PlatformClientAuth::Initialize())
     LOG(ERROR) << "PlatformClientAuth::Initialize failed.";
 
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp
index df70201..db35e6f 100644
--- a/chromecast/chromecast.gyp
+++ b/chromecast/chromecast.gyp
@@ -45,6 +45,29 @@
       ],
     },  # end of target 'cast_base'
     {
+      'target_name': 'cast_crash_client',
+      'type': '<(component)',
+      'dependencies': [
+        '../breakpad/breakpad.gyp:breakpad_client',
+        '../components/components.gyp:crash_component',
+      ],
+      'sources': [
+        'crash/cast_crash_reporter_client.cc',
+        'crash/cast_crash_reporter_client.h',
+      ],
+      'conditions': [
+        ['chromecast_branding=="Chrome"', {
+          'dependencies': [
+            '<(cast_internal_gyp):crash_internal',
+          ],
+        }, {
+          'sources': [
+            'crash/cast_crash_reporter_client_simple.cc',
+          ],
+        }],
+      ]
+    },  # end of target 'cast_crash_client'
+    {
       'target_name': 'cast_net',
       'type': '<(component)',
       'sources': [
@@ -113,6 +136,7 @@
       'type': '<(component)',
       'dependencies': [
         'cast_base',
+        'cast_crash_client',
         'cast_shell_pak',
         'cast_shell_resources',
         'cast_version_header',
@@ -423,29 +447,6 @@
     }, {  # OS != "android"
       'targets': [
         {
-          'target_name': 'cast_crash_client',
-          'type': '<(component)',
-          'dependencies': [
-            '../breakpad/breakpad.gyp:breakpad_client',
-            '../components/components.gyp:crash_component',
-          ],
-          'sources': [
-            'crash/cast_crash_reporter_client.cc',
-            'crash/cast_crash_reporter_client.h',
-          ],
-          'conditions': [
-            ['chromecast_branding=="Chrome"', {
-              'dependencies': [
-                '<(cast_internal_gyp):crash_internal',
-              ],
-            }, {
-              'sources': [
-                'crash/cast_crash_reporter_client_simple.cc',
-              ],
-            }],
-          ]
-        },  # end of target 'cast_crash_client'
-        {
           'target_name': 'cast_shell_media',
           'type': '<(component)',
           'dependencies': [
@@ -492,7 +493,6 @@
           'target_name': 'cast_shell_core',
           'type': '<(component)',
           'dependencies': [
-            'cast_crash_client',
             'cast_net',
             'cast_shell_media',
             'cast_shell_common',
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 947c0e7..6b7bad4e 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -34,7 +34,6 @@
     "//third_party/icu",
     "//third_party/libxml",
     "//third_party/protobuf:protobuf_lite",
-    "//ui/accelerometer",
     "//ui/gfx/geometry",
     "//url",
     ":cryptohome_proto",
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 1d221b46..89a4b21b 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-6750.0.0
\ No newline at end of file
+6752.0.0
\ No newline at end of file
diff --git a/chromeos/DEPS b/chromeos/DEPS
index a398cc6..8bc2f79 100644
--- a/chromeos/DEPS
+++ b/chromeos/DEPS
@@ -11,6 +11,4 @@
 
   # Some targets may not have any UI, so explictly exclude src/ui.
   "-ui",
-  # TODO(stevenjb/flackr): Remove these dependencies.
-  "+ui/accelerometer"
 ]
diff --git a/chromeos/accelerometer/accelerometer_reader.cc b/chromeos/accelerometer/accelerometer_reader.cc
index e2a5e79..4d68ebf0 100644
--- a/chromeos/accelerometer/accelerometer_reader.cc
+++ b/chromeos/accelerometer/accelerometer_reader.cc
@@ -41,8 +41,7 @@
 
 // The names of the accelerometers. Matches up with the enum AccelerometerSource
 // in ui/accelerometer/accelerometer_types.h.
-const char kAccelerometerNames[ui::ACCELEROMETER_SOURCE_COUNT][5] = {
-    "lid", "base"};
+const char kAccelerometerNames[ACCELEROMETER_SOURCE_COUNT][5] = {"lid", "base"};
 
 // The axes on each accelerometer.
 const char kAccelerometerAxes[][2] = {"y", "x", "z"};
@@ -59,10 +58,6 @@
 // The mean acceleration due to gravity on Earth in m/s^2.
 const float kMeanGravity = 9.80665f;
 
-// The maximum deviation from the acceleration expected due to gravity under
-// which to detect hinge angle and screen rotation in m/s^2
-const float kDeviationFromGravityThreshold = 1.0f;
-
 // Reads |path| to the unsigned int pointed to by |value|. Returns true on
 // success or false on failure.
 bool ReadFileToInt(const base::FilePath& path, int* value) {
@@ -126,14 +121,14 @@
 
   // Adjust the directions of accelerometers to match the AccelerometerUpdate
   // type specified in ui/accelerometer/accelerometer_types.h.
-  configuration->data.scale[ui::ACCELEROMETER_SOURCE_SCREEN][0] *= -1.0f;
+  configuration->data.scale[ACCELEROMETER_SOURCE_SCREEN][0] *= -1.0f;
   for (int i = 0; i < 3; ++i) {
-    configuration->data.scale[ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD][i] *=
+    configuration->data.scale[ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD][i] *=
         -1.0f;
   }
 
   // Verify indices are within bounds.
-  for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) {
+  for (int i = 0; i < ACCELEROMETER_SOURCE_COUNT; ++i) {
     if (!configuration->data.has[i])
       continue;
     for (int j = 0; j < 3; ++j) {
@@ -176,7 +171,7 @@
 
 AccelerometerReader::ConfigurationData::ConfigurationData()
     : count(0) {
-  for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) {
+  for (int i = 0; i < ACCELEROMETER_SOURCE_COUNT; ++i) {
     has[i] = false;
     for (int j = 0; j < 3; ++j) {
       scale[i][j] = 0;
@@ -215,13 +210,6 @@
   observers_.RemoveObserver(observer);
 }
 
-bool AccelerometerReader::IsReadingStable(const ui::AccelerometerUpdate& update,
-                                          ui::AccelerometerSource source) {
-  return update.has(source) &&
-         std::abs(update.get(source).Length() - kMeanGravity) <=
-             kDeviationFromGravityThreshold;
-}
-
 AccelerometerReader::AccelerometerReader()
     : configuration_(new AccelerometerReader::Configuration()),
       weak_factory_(this) {
@@ -257,12 +245,12 @@
   DCHECK(!task_runner_->RunsTasksOnCurrentThread());
 
   if (success) {
-    for (int i = 0; i < ui::ACCELEROMETER_SOURCE_COUNT; ++i) {
+    for (int i = 0; i < ACCELEROMETER_SOURCE_COUNT; ++i) {
       if (!configuration_->data.has[i])
         continue;
 
       int16* values = reinterpret_cast<int16*>(reading->data);
-      update_.Set(static_cast<ui::AccelerometerSource>(i),
+      update_.Set(static_cast<AccelerometerSource>(i),
                   values[configuration_->data.index[i][0]] *
                       configuration_->data.scale[i][0],
                   values[configuration_->data.index[i][1]] *
diff --git a/chromeos/accelerometer/accelerometer_reader.h b/chromeos/accelerometer/accelerometer_reader.h
index 15115da..c2adde8 100644
--- a/chromeos/accelerometer/accelerometer_reader.h
+++ b/chromeos/accelerometer/accelerometer_reader.h
@@ -8,8 +8,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
 #include "chromeos/chromeos_export.h"
-#include "ui/accelerometer/accelerometer_types.h"
 
 template <typename T>
 struct DefaultSingletonTraits;
@@ -36,13 +36,13 @@
     size_t length;
 
     // Which accelerometers are present on device.
-    bool has[ui::ACCELEROMETER_SOURCE_COUNT];
+    bool has[ACCELEROMETER_SOURCE_COUNT];
 
     // Scale of accelerometers (i.e. raw value * scale = m/s^2).
-    float scale[ui::ACCELEROMETER_SOURCE_COUNT][3];
+    float scale[ACCELEROMETER_SOURCE_COUNT][3];
 
     // Index of each accelerometer axis in data stream.
-    int index[ui::ACCELEROMETER_SOURCE_COUNT][3];
+    int index[ACCELEROMETER_SOURCE_COUNT][3];
   };
   typedef base::RefCountedData<ConfigurationData> Configuration;
   typedef base::RefCountedData<char[12]> Reading;
@@ -50,8 +50,7 @@
   // An interface to receive data from the AccelerometerReader.
   class Observer {
    public:
-    virtual void OnAccelerometerUpdated(
-        const ui::AccelerometerUpdate& update) = 0;
+    virtual void OnAccelerometerUpdated(const AccelerometerUpdate& update) = 0;
 
    protected:
     virtual ~Observer() {}
@@ -65,12 +64,6 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  // A reading is considered stable if its deviation from gravity is small. This
-  // returns false if the deviation is too higher, or if |source| is not present
-  // in the update.
-  static bool IsReadingStable(const ui::AccelerometerUpdate& update,
-                              ui::AccelerometerSource source);
-
  protected:
   AccelerometerReader();
   virtual ~AccelerometerReader();
@@ -95,7 +88,7 @@
   scoped_refptr<base::TaskRunner> task_runner_;
 
   // The last seen accelerometer data.
-  ui::AccelerometerUpdate update_;
+  AccelerometerUpdate update_;
 
   // The accelerometer configuration.
   scoped_refptr<Configuration> configuration_;
diff --git a/ui/accelerometer/accelerometer_types.cc b/chromeos/accelerometer/accelerometer_types.cc
similarity index 78%
rename from ui/accelerometer/accelerometer_types.cc
rename to chromeos/accelerometer/accelerometer_types.cc
index e5aa0ea..a08fbdd 100644
--- a/ui/accelerometer/accelerometer_types.cc
+++ b/chromeos/accelerometer/accelerometer_types.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/accelerometer/accelerometer_types.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
 
-namespace ui {
+namespace chromeos {
 
 AccelerometerReading::AccelerometerReading() : present(false) {
 }
@@ -18,4 +18,4 @@
 AccelerometerUpdate::~AccelerometerUpdate() {
 }
 
-}  // namespace ui
+}  // namespace chromeos
diff --git a/ui/accelerometer/accelerometer_types.h b/chromeos/accelerometer/accelerometer_types.h
similarity index 69%
rename from ui/accelerometer/accelerometer_types.h
rename to chromeos/accelerometer/accelerometer_types.h
index b3e513dd..f72e296 100644
--- a/ui/accelerometer/accelerometer_types.h
+++ b/chromeos/accelerometer/accelerometer_types.h
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_ACCELEROMETER_ACCELEROMETER_TYPES_H_
-#define UI_ACCELEROMETER_ACCELEROMETER_TYPES_H_
+#ifndef CHROMEOS_ACCELEROMETER_ACCELEROMETER_TYPES_H_
+#define CHROMEOS_ACCELEROMETER_ACCELEROMETER_TYPES_H_
 
 #include "base/macros.h"
-#include "ui/accelerometer/ui_accelerometer_export.h"
-#include "ui/gfx/geometry/vector3d_f.h"
+#include "chromeos/chromeos_export.h"
 
-namespace ui {
+namespace chromeos {
 
 enum AccelerometerSource {
   // Accelerometer is located in the device's screen. In the screen's natural
@@ -30,47 +29,48 @@
   ACCELEROMETER_SOURCE_COUNT
 };
 
-struct UI_ACCELEROMETER_EXPORT AccelerometerReading {
+struct CHROMEOS_EXPORT AccelerometerReading {
   AccelerometerReading();
   ~AccelerometerReading();
 
   // If true, this accelerometer is being updated.
   bool present;
 
-  // The reading from this accelerometer measured in m/s^2.
-  gfx::Vector3dF reading;
+  // The readings from this accelerometer measured in m/s^2.
+  float x;
+  float y;
+  float z;
 };
 
 // An accelerometer update contains the last known value for each of the
 // accelerometers present on the device.
-class UI_ACCELEROMETER_EXPORT AccelerometerUpdate {
+class CHROMEOS_EXPORT AccelerometerUpdate {
  public:
   AccelerometerUpdate();
   ~AccelerometerUpdate();
 
   // Returns true if |source| has a valid value in this update.
-  bool has(AccelerometerSource source)  const {
-    return data_[source].present;
-  }
+  bool has(AccelerometerSource source) const { return data_[source].present; }
 
   // Returns the last known value for |source|.
-  const gfx::Vector3dF& get(AccelerometerSource source) const {
-    return data_[source].reading;
+  const AccelerometerReading& get(AccelerometerSource source) const {
+    return data_[source];
   }
 
   void Set(AccelerometerSource source, float x, float y, float z) {
     data_[source].present = true;
-    data_[source].reading.set_x(x);
-    data_[source].reading.set_y(y);
-    data_[source].reading.set_z(z);
+    data_[source].x = x;
+    data_[source].y = y;
+    data_[source].z = z;
   }
 
  protected:
   AccelerometerReading data_[ACCELEROMETER_SOURCE_COUNT];
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(AccelerometerUpdate);
 };
 
-}  // namespace ui
+}  // namespace chromeos
 
-#endif  // UI_ACCELEROMETER_ACCELEROMETER_TYPES_H_
+#endif  // CHROMEOS_ACCELEROMETER_ACCELEROMETER_TYPES_H_
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index 7d89d07..7175ebf 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -9,6 +9,8 @@
     'chromeos_sources': [
       'accelerometer/accelerometer_reader.cc',
       'accelerometer/accelerometer_reader.h',
+      'accelerometer/accelerometer_types.cc',
+      'accelerometer/accelerometer_types.h',
       'app_mode/kiosk_oem_manifest_parser.cc',
       'app_mode/kiosk_oem_manifest_parser.h',
       'audio/audio_device.cc',
@@ -521,7 +523,6 @@
         '../third_party/libxml/libxml.gyp:libxml',
         '../third_party/protobuf/protobuf.gyp:protobuf_lite',
         '../ui/gfx/gfx.gyp:gfx_geometry',
-        '../ui/accelerometer/ui_accelerometer.gyp:ui_accelerometer',
         '../url/url.gyp:url_lib',
         'cryptohome_proto',
         'ime/input_method.gyp:gencode',
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 20c55c80..5c019c9b 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -304,8 +304,9 @@
 const char kEnableCaptivePortalBypassProxy[] =
     "enable-captive-portal-bypass-proxy";
 
-// Enable automatic timezone update.
-const char kEnableTimeZoneTrackingOption[] = "enable-timezone-tracking-option";
+// Disable automatic timezone update.
+const char kDisableTimeZoneTrackingOption[] =
+    "disable-timezone-tracking-option";
 
 bool WakeOnWifiEnabled() {
   return !base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableWakeOnWifi);
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 1ddddeb..23cb788 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -99,7 +99,7 @@
 CHROMEOS_EXPORT extern const char kTestAutoUpdateUI[];
 CHROMEOS_EXPORT extern const char kWakeOnPackets[];
 CHROMEOS_EXPORT extern const char kEnableCaptivePortalBypassProxy[];
-CHROMEOS_EXPORT extern const char kEnableTimeZoneTrackingOption[];
+CHROMEOS_EXPORT extern const char kDisableTimeZoneTrackingOption[];
 
 CHROMEOS_EXPORT bool WakeOnWifiEnabled();
 
diff --git a/chromeos/dbus/fake_privet_daemon_client.cc b/chromeos/dbus/fake_privet_daemon_client.cc
index 9f9bfa0..bc252f0 100644
--- a/chromeos/dbus/fake_privet_daemon_client.cc
+++ b/chromeos/dbus/fake_privet_daemon_client.cc
@@ -4,6 +4,8 @@
 
 #include "chromeos/dbus/fake_privet_daemon_client.h"
 
+#include <string>
+
 #include "base/callback.h"
 
 namespace chromeos {
@@ -17,6 +19,17 @@
 void FakePrivetDaemonClient::Init(dbus::Bus* bus) {
 }
 
+void FakePrivetDaemonClient::AddObserver(Observer* observer) {
+}
+
+void FakePrivetDaemonClient::RemoveObserver(Observer* observer) {
+}
+
+std::string FakePrivetDaemonClient::GetWifiBootstrapState() {
+  // Simulate Wi-Fi being configured already.
+  return privetd::kWiFiBootstrapStateMonitoring;
+}
+
 void FakePrivetDaemonClient::Ping(const PingCallback& callback) {
   callback.Run(true /* success */);
 }
diff --git a/chromeos/dbus/fake_privet_daemon_client.h b/chromeos/dbus/fake_privet_daemon_client.h
index e15ea95..1b86e41 100644
--- a/chromeos/dbus/fake_privet_daemon_client.h
+++ b/chromeos/dbus/fake_privet_daemon_client.h
@@ -20,6 +20,9 @@
   void Init(dbus::Bus* bus) override;
 
   // PrivetClient overrides:
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  std::string GetWifiBootstrapState() override;
   void Ping(const PingCallback& callback) override;
 
  private:
diff --git a/chromeos/dbus/privet_daemon_client.cc b/chromeos/dbus/privet_daemon_client.cc
index 21b0980..cd75d67c 100644
--- a/chromeos/dbus/privet_daemon_client.cc
+++ b/chromeos/dbus/privet_daemon_client.cc
@@ -9,9 +9,12 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
+#include "dbus/object_manager.h"
 #include "dbus/object_proxy.h"
+#include "dbus/property.h"
 
 namespace chromeos {
 namespace {
@@ -19,57 +22,206 @@
 // The expected response to the Ping D-Bus method.
 const char kPingResponse[] = "Hello world!";
 
-// The PrivetClient implementation used in production.
-class PrivetClientImpl : public PrivetDaemonClient {
+// The PrivetDaemonClient implementation used in production. Note that privetd
+// is not available on all devices. If privetd is not running this object
+// returns empty property values and logs errors for attempted method calls but
+// will not crash.
+class PrivetDaemonClientImpl : public PrivetDaemonClient,
+                               public dbus::ObjectManager::Interface {
  public:
-  PrivetClientImpl();
-  ~PrivetClientImpl() override;
+  // Setup state properties. The object manager reads the initial values.
+  struct Properties : public dbus::PropertySet {
+    // Network bootstrap state. Read-only.
+    dbus::Property<std::string> wifi_bootstrap_state;
+
+    Properties(dbus::ObjectProxy* object_proxy,
+               const std::string& interface_name,
+               const PropertyChangedCallback& callback);
+    ~Properties() override;
+  };
+
+  PrivetDaemonClientImpl();
+  ~PrivetDaemonClientImpl() override;
 
   // DBusClient overrides:
   void Init(dbus::Bus* bus) override;
 
-  // PrivetClient overrides:
+  // PrivetDaemonClient overrides:
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  std::string GetWifiBootstrapState() override;
   void Ping(const PingCallback& callback) override;
 
  private:
-  // Callback for the Ping DBus method.
+  // dbus::ObjectManager::Interface overrides:
+  dbus::PropertySet* CreateProperties(
+      dbus::ObjectProxy* object_proxy,
+      const dbus::ObjectPath& object_path,
+      const std::string& interface_name) override;
+
+  // Called with the owner of the privetd service at startup and again if the
+  // owner changes.
+  void OnServiceOwnerChanged(const std::string& service_owner);
+
+  // Cleans up |object_manager_|.
+  void CleanUpObjectManager();
+
+  // Returns the instance of the property set or null if privetd is not running.
+  Properties* GetProperties();
+
+  // Called by dbus::PropertySet when a property value is changed, either by
+  // result of a signal or response to a GetAll() or Get() call. Informs
+  // observers.
+  void OnPropertyChanged(const std::string& property_name);
+
+  // Callback for the Ping D-Bus method.
   void OnPing(const PingCallback& callback, dbus::Response* response);
 
-  // Called when the object is connected to the signal.
-  void OnSignalConnected(const std::string& interface_name,
-                         const std::string& signal_name,
-                         bool success);
+  // The current bus, usually the system bus. Not owned.
+  dbus::Bus* bus_;
 
-  dbus::ObjectProxy* privetd_proxy_;
-  base::WeakPtrFactory<PrivetClientImpl> weak_ptr_factory_;
+  // Object manager used to read D-Bus properties. Null if privetd is not
+  // running. Not owned.
+  dbus::ObjectManager* object_manager_;
 
-  DISALLOW_COPY_AND_ASSIGN(PrivetClientImpl);
+  // Callback that monitors for service owner changes.
+  dbus::Bus::GetServiceOwnerCallback service_owner_callback_;
+
+  // The current service owner or the empty string is privetd is not running.
+  std::string service_owner_;
+
+  ObserverList<Observer> observers_;
+  base::WeakPtrFactory<PrivetDaemonClientImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrivetDaemonClientImpl);
 };
 
-PrivetClientImpl::PrivetClientImpl()
-    : privetd_proxy_(nullptr), weak_ptr_factory_(this) {
+///////////////////////////////////////////////////////////////////////////////
+
+PrivetDaemonClientImpl::Properties::Properties(
+    dbus::ObjectProxy* object_proxy,
+    const std::string& interface_name,
+    const PropertyChangedCallback& callback)
+    : dbus::PropertySet(object_proxy, interface_name, callback) {
+  RegisterProperty(privetd::kWiFiBootstrapStateProperty, &wifi_bootstrap_state);
 }
 
-PrivetClientImpl::~PrivetClientImpl() {
+PrivetDaemonClientImpl::Properties::~Properties() {
 }
 
-void PrivetClientImpl::Ping(const PingCallback& callback) {
+///////////////////////////////////////////////////////////////////////////////
+
+PrivetDaemonClientImpl::PrivetDaemonClientImpl()
+    : bus_(nullptr), object_manager_(nullptr), weak_ptr_factory_(this) {
+}
+
+PrivetDaemonClientImpl::~PrivetDaemonClientImpl() {
+  CleanUpObjectManager();
+  if (bus_) {
+    bus_->UnlistenForServiceOwnerChange(privetd::kPrivetdServiceName,
+                                        service_owner_callback_);
+  }
+}
+
+void PrivetDaemonClientImpl::Init(dbus::Bus* bus) {
+  bus_ = bus;
+  // privetd may not be running. Watch for it starting up later.
+  service_owner_callback_ =
+      base::Bind(&PrivetDaemonClientImpl::OnServiceOwnerChanged,
+                 weak_ptr_factory_.GetWeakPtr());
+  bus_->ListenForServiceOwnerChange(privetd::kPrivetdServiceName,
+                                    service_owner_callback_);
+  // Also explicitly check for its existence on startup.
+  bus_->GetServiceOwner(privetd::kPrivetdServiceName, service_owner_callback_);
+}
+
+void PrivetDaemonClientImpl::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void PrivetDaemonClientImpl::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+std::string PrivetDaemonClientImpl::GetWifiBootstrapState() {
+  Properties* properties = GetProperties();
+  if (!properties)
+    return "";
+  return properties->wifi_bootstrap_state.value();
+}
+
+dbus::PropertySet* PrivetDaemonClientImpl::CreateProperties(
+    dbus::ObjectProxy* object_proxy,
+    const dbus::ObjectPath& object_path,
+    const std::string& interface_name) {
+  return new Properties(object_proxy, interface_name,
+                        base::Bind(&PrivetDaemonClientImpl::OnPropertyChanged,
+                                   weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PrivetDaemonClientImpl::Ping(const PingCallback& callback) {
+  if (!object_manager_) {
+    LOG(ERROR) << "privetd not available.";
+    return;
+  }
+  dbus::ObjectProxy* proxy = object_manager_->GetObjectProxy(
+      dbus::ObjectPath(privetd::kPrivetdManagerServicePath));
+  if (!proxy) {
+    LOG(ERROR) << "Object not available.";
+    return;
+  }
   dbus::MethodCall method_call(privetd::kPrivetdManagerInterface,
                                privetd::kPingMethod);
-  privetd_proxy_->CallMethod(
-      &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-      base::Bind(&PrivetClientImpl::OnPing, weak_ptr_factory_.GetWeakPtr(),
-                 callback));
+  proxy->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                    base::Bind(&PrivetDaemonClientImpl::OnPing,
+                               weak_ptr_factory_.GetWeakPtr(), callback));
 }
 
-void PrivetClientImpl::Init(dbus::Bus* bus) {
-  privetd_proxy_ = bus->GetObjectProxy(
-      privetd::kPrivetdServiceName,
-      dbus::ObjectPath(privetd::kPrivetdManagerServicePath));
+void PrivetDaemonClientImpl::OnServiceOwnerChanged(
+    const std::string& service_owner) {
+  // If |service_owner| and |service_owner_| are both empty then the service
+  // hasn't started yet. If they match the owner hasn't changed.
+  if (service_owner == service_owner_)
+    return;
+
+  service_owner_ = service_owner;
+  if (service_owner_.empty()) {
+    LOG(ERROR) << "Lost privetd service.";
+    CleanUpObjectManager();
+    return;
+  }
+
+  // Finish initialization (or re-initialize if privetd restarted).
+  object_manager_ =
+      bus_->GetObjectManager(privetd::kPrivetdServiceName,
+                             dbus::ObjectPath(privetd::kPrivetdServicePath));
+  object_manager_->RegisterInterface(privetd::kPrivetdManagerInterface, this);
 }
 
-void PrivetClientImpl::OnPing(const PingCallback& callback,
-                              dbus::Response* response) {
+void PrivetDaemonClientImpl::CleanUpObjectManager() {
+  if (object_manager_) {
+    object_manager_->UnregisterInterface(privetd::kPrivetdManagerInterface);
+    object_manager_ = nullptr;
+  }
+}
+
+PrivetDaemonClientImpl::Properties* PrivetDaemonClientImpl::GetProperties() {
+  if (!object_manager_)
+    return nullptr;
+
+  return static_cast<Properties*>(object_manager_->GetProperties(
+      dbus::ObjectPath(privetd::kPrivetdManagerServicePath),
+      privetd::kPrivetdManagerInterface));
+}
+
+void PrivetDaemonClientImpl::OnPropertyChanged(
+    const std::string& property_name) {
+  FOR_EACH_OBSERVER(PrivetDaemonClient::Observer, observers_,
+                    OnPrivetDaemonPropertyChanged(property_name));
+}
+
+void PrivetDaemonClientImpl::OnPing(const PingCallback& callback,
+                                    dbus::Response* response) {
   if (!response) {
     LOG(ERROR) << "Error calling " << privetd::kPingMethod;
     callback.Run(false);
@@ -85,12 +237,6 @@
   callback.Run(value == kPingResponse);
 }
 
-void PrivetClientImpl::OnSignalConnected(const std::string& interface_name,
-                                         const std::string& signal_name,
-                                         bool success) {
-  LOG_IF(ERROR, !success) << "Failed to connect to " << signal_name;
-}
-
 }  // namespace
 
 //////////////////////////////////////////////////////////////////////////////
@@ -103,7 +249,7 @@
 
 // static
 PrivetDaemonClient* PrivetDaemonClient::Create() {
-  return new PrivetClientImpl();
+  return new PrivetDaemonClientImpl();
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/privet_daemon_client.h b/chromeos/dbus/privet_daemon_client.h
index 61f55e50..04e9df7 100644
--- a/chromeos/dbus/privet_daemon_client.h
+++ b/chromeos/dbus/privet_daemon_client.h
@@ -17,8 +17,19 @@
 // interface is finalized.
 namespace privetd {
 const char kPrivetdServiceName[] = "org.chromium.privetd";
-const char kPrivetdManagerServicePath[] = "/org/chromium/privetd/Manager";
+const char kPrivetdServicePath[] = "/org/chromium/privetd";
 const char kPrivetdManagerInterface[] = "org.chromium.privetd.Manager";
+const char kPrivetdManagerServicePath[] = "/org/chromium/privetd/Manager";
+
+// Properties.
+const char kWiFiBootstrapStateProperty[] = "WiFiBootstrapState";
+
+// Property values.
+const char kWiFiBootstrapStateDisabled[] = "disabled";
+const char kWiFiBootstrapStateWaiting[] = "waiting";
+const char kWiFiBootstrapStateConnecting[] = "connecting";
+const char kWiFiBootstrapStateMonitoring[] = "monitoring";
+
 // Methods.
 const char kPingMethod[] = "Ping";
 }  // namespace privetd
@@ -30,11 +41,27 @@
 // embedded Chrome OS Core device.
 class CHROMEOS_EXPORT PrivetDaemonClient : public DBusClient {
  public:
-  ~PrivetDaemonClient() override;
-
   // Returns true if privetd correctly responded to Ping().
   using PingCallback = base::Callback<void(bool success)>;
 
+  // Interface for observing changes in setup state.
+  class Observer {
+   public:
+    virtual ~Observer() {}
+
+    // Notifies the observer when a named |property| changes.
+    virtual void OnPrivetDaemonPropertyChanged(const std::string& property) = 0;
+  };
+
+  ~PrivetDaemonClient() override;
+
+  // The usual observer interface.
+  virtual void AddObserver(Observer* observer) = 0;
+  virtual void RemoveObserver(Observer* observer) = 0;
+
+  // Returns the current properties.
+  virtual std::string GetWifiBootstrapState() = 0;
+
   // Asynchronously pings the daemon.
   virtual void Ping(const PingCallback& callback) = 0;
 
@@ -46,8 +73,6 @@
   PrivetDaemonClient();
 
  private:
-  friend class PrivetDaemonClientTest;
-
   DISALLOW_COPY_AND_ASSIGN(PrivetDaemonClient);
 };
 
diff --git a/components/BUILD.gn b/components/BUILD.gn
index b7ecabd..10d0d89 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -28,7 +28,6 @@
     "//components/component_updater",
     "//components/content_settings/core/browser",
     "//components/content_settings/core/common",
-    "//components/copresence_endpoints",
     "//components/crash/app",
     "//components/crash/browser",
     "//components/crx_file",
@@ -126,7 +125,6 @@
   }
   if (is_ios) {
     deps -= [
-      "//components/copresence_endpoints",
       "//components/history/content/browser",
       "//components/keyed_service/content",
     ]
diff --git a/components/OWNERS b/components/OWNERS
index e40e825..8216783 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -43,6 +43,7 @@
 per-file data_reduction_proxy*=bengr@chromium.org
 per-file data_reduction_proxy*=marq@chromium.org
 per-file data_reduction_proxy*=bolian@chromium.org
+per-file data_reduction_proxy*=sclittle@chromium.org
 
 per-file devtools_bridge.gyp=mnaganov@chromium.org
 per-file devtools_bridge.gyp=serya@chromium.org
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 0d0ac39..ee889cff 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -175,6 +175,11 @@
       true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterBooleanPref(
+      prefs::kAutofillWalletSyncExperimentEnabled,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  // TODO(estade): Should this be syncable?
+  registry->RegisterBooleanPref(
       prefs::kAutofillWalletImportEnabled,
       true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
@@ -561,8 +566,7 @@
       unmasking_query_id_ = query_id;
       unmasking_form_ = form;
       unmasking_field_ = field;
-      // TODO(estade): uncomment this after the demo.
-      // real_pan_client_.Prepare();
+      real_pan_client_.Prepare();
       client()->ShowUnmaskPrompt(unmasking_card_,
                                  weak_ptr_factory_.GetWeakPtr());
       return;
@@ -690,23 +694,9 @@
 void AutofillManager::OnUnmaskResponse(const base::string16& cvc,
                                        const base::string16& exp_month,
                                        const base::string16& exp_year) {
-  // Most of this function is demo code. The real code should look something
-  // like:
-  //   real_pan_client_.UnmaskCard(unmasking_card_, cvc, exp_month, exp_year);
-
   unmasking_cvc_ = cvc;
-  // TODO(estade): fake verification: assume 123/1234 is the correct cvc.
-  if (StartsWithASCII(base::UTF16ToASCII(cvc), "123", true)) {
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE, base::Bind(&AutofillManager::OnUnmaskVerificationResult,
-                              base::Unretained(this), true),
-        base::TimeDelta::FromSeconds(2));
-  } else {
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE, base::Bind(&AutofillManager::OnUnmaskVerificationResult,
-                              base::Unretained(this), false),
-        base::TimeDelta::FromSeconds(2));
-  }
+  // TODO(estade): use month/year.
+  real_pan_client_.UnmaskCard(unmasking_card_, base::UTF16ToASCII(cvc));
 }
 
 void AutofillManager::OnUnmaskPromptClosed() {
@@ -721,25 +711,15 @@
 }
 
 void AutofillManager::OnDidGetRealPan(const std::string& real_pan) {
-  NOTIMPLEMENTED();
-}
-
-void AutofillManager::OnUnmaskVerificationResult(bool success) {
-  if (success) {
+  if (!real_pan.empty()) {
     unmasking_card_.set_record_type(CreditCard::FULL_SERVER_CARD);
-    if (unmasking_card_.type() == kAmericanExpressCard) {
-      unmasking_card_.SetNumber(base::ASCIIToUTF16("371449635398431"));
-    } else if (unmasking_card_.type() == kVisaCard) {
-      unmasking_card_.SetNumber(base::ASCIIToUTF16("4012888888881881"));
-    } else {
-      DCHECK_EQ(kDiscoverCard, unmasking_card_.type());
-      unmasking_card_.SetNumber(base::ASCIIToUTF16("6011000990139424"));
-    }
+    unmasking_card_.SetNumber(base::UTF8ToUTF16(real_pan));
     personal_data_->UpdateServerCreditCard(unmasking_card_);
     FillCreditCardForm(unmasking_query_id_, unmasking_form_, unmasking_field_,
                        unmasking_card_);
   }
-  client()->OnUnmaskVerificationResult(success);
+
+  client()->OnUnmaskVerificationResult(!real_pan.empty());
 }
 
 void AutofillManager::OnDidEndTextFieldEditing() {
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 7e29820a..eb61b56 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -238,9 +238,6 @@
   IdentityProvider* GetIdentityProvider() override;
   void OnDidGetRealPan(const std::string& real_pan) override;
 
-  // A toy method called when the (fake) unmasking process has finished.
-  void OnUnmaskVerificationResult(bool success);
-
   // Returns false if Autofill is disabled or if no Autofill data is available.
   bool RefreshDataModels() const;
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 911d07b..fcc36877 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -675,8 +675,7 @@
   credit_cards_.clear();
   credit_cards_.insert(credit_cards_.end(), local_credit_cards_.begin(),
                        local_credit_cards_.end());
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableWalletCardImport) &&
+  if (IsExperimentalWalletIntegrationEnabled() &&
       pref_service_->GetBoolean(prefs::kAutofillWalletImportEnabled)) {
     credit_cards_.insert(credit_cards_.end(), server_credit_cards_.begin(),
                          server_credit_cards_.end());
@@ -960,6 +959,13 @@
   return default_country_code_;
 }
 
+bool PersonalDataManager::IsExperimentalWalletIntegrationEnabled() const {
+  // The feature can be enabled by sync experiment *or* command line flag.
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kEnableWalletCardImport) ||
+         pref_service_->GetBoolean(prefs::kAutofillWalletSyncExperimentEnabled);
+}
+
 void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) {
   if (is_off_the_record_)
     return;
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index ef66ce6..4ac72bb 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -219,6 +219,10 @@
   void BinaryChanging();
 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 
+  // Returns true if the wallet integration feature is enabled. Note that the
+  // feature can still disabled by a user pref.
+  bool IsExperimentalWalletIntegrationEnabled() const;
+
  protected:
   // Only PersonalDataManagerFactory and certain tests can create instances of
   // PersonalDataManager.
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
index 35c6cbd..41ce19a2 100644
--- a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
+++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
@@ -4,6 +4,7 @@
 
 #include "components/autofill/core/browser/wallet/real_pan_wallet_client.h"
 
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
@@ -23,12 +24,11 @@
 namespace {
 
 const char kUnmaskCardRequestFormat[] =
-    "request_content_type=application/json&request=%s&cvc=%s";
+    "requestContentType=application/json; charset=utf-8&request=%s&cvc=%s";
 
-// TODO(estade): use a sandbox server on dev builds?
 const char kUnmaskCardRequestUrl[] =
-    "https://wallet.google.com/payments/apis-secure/creditcardservice"
-    "/GetRealPan?s7e=cvc";
+    "https://sandbox.google.com/payments/apis-secure/creditcardservice"
+    "/getrealpan?s7e=cvc";
 
 const char kTokenServiceConsumerId[] = "real_pan_wallet_client";
 const char kWalletOAuth2Scope[] =
@@ -64,8 +64,13 @@
 
   base::DictionaryValue request_dict;
   request_dict.SetString("encrypted_cvc", "__param:cvc");
-  // TODO(estade): is this the correct "token"?
   request_dict.SetString("credit_card_token", card.server_id());
+
+  // TODO(estade): add real risk data.
+  std::string base64_risk;
+  base::Base64Encode("{}", &base64_risk);
+  request_dict.SetString("risk_data_base64", base64_risk);
+
   std::string json_request;
   base::JSONWriter::Write(&request_dict, &json_request);
   std::string post_body = base::StringPrintf(kUnmaskCardRequestFormat,
@@ -91,6 +96,8 @@
   scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
   scoped_ptr<base::DictionaryValue> response_dict;
   int response_code = source->GetResponseCode();
+  std::string data;
+  source->GetResponseAsString(&data);
 
   // TODO(estade): OAuth2 may fail due to an expired access token, in which case
   // we should invalidate the token and try again. How is that failure reported?
@@ -98,41 +105,40 @@
   switch (response_code) {
     // Valid response.
     case net::HTTP_OK: {
-      std::string data;
-      source->GetResponseAsString(&data);
       scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
       if (message_value.get() &&
           message_value->IsType(base::Value::TYPE_DICTIONARY)) {
         response_dict.reset(
             static_cast<base::DictionaryValue*>(message_value.release()));
-      } else {
-        NOTIMPLEMENTED();
       }
       break;
     }
 
     // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
     case net::HTTP_BAD_REQUEST: {
-      NOTIMPLEMENTED();
       break;
     }
 
     // Response contains an error to show the user.
     case net::HTTP_FORBIDDEN:
     case net::HTTP_INTERNAL_SERVER_ERROR: {
-      NOTIMPLEMENTED();
       break;
     }
 
     // Handle anything else as a generic error.
     default:
-      NOTIMPLEMENTED();
       break;
   }
 
   std::string real_pan;
   if (response_dict)
     response_dict->GetString("pan", &real_pan);
+
+  if (real_pan.empty()) {
+    NOTIMPLEMENTED() << "Unhandled error: " << response_code <<
+        " with data: " << data;
+  }
+
   delegate_->OnDidGetRealPan(real_pan);
 }
 
@@ -157,7 +163,7 @@
     delegate_->OnDidGetRealPan(std::string());
   }
   // TODO(estade): what do we do in the failure case?
-  NOTIMPLEMENTED();
+  NOTIMPLEMENTED() << "Unhandled OAuth2 error: " << error.ToString();
 
   access_token_request_.reset();
 }
@@ -178,7 +184,7 @@
 }
 
 void RealPanWalletClient::SetOAuth2TokenAndStartRequest() {
-  request_->AddExtraRequestHeader("Authorization: " + access_token_);
+  request_->AddExtraRequestHeader("Authorization: Bearer " + access_token_);
   request_->Start();
 }
 
diff --git a/components/autofill/core/common/autofill_pref_names.cc b/components/autofill/core/common/autofill_pref_names.cc
index 62fe49b..b272a62 100644
--- a/components/autofill/core/common/autofill_pref_names.cc
+++ b/components/autofill/core/common/autofill_pref_names.cc
@@ -38,8 +38,16 @@
 // true, then kAutofillMacAddressBookQueried is expected to also be true.
 const char kAutofillUseMacAddressBook[] = "autofill.use_mac_address_book";
 
-// Boolean that's true when Wallet card and address import is enabled.
+// Boolean that's true when Wallet card and address import is enabled by the
+// user. This will only be available to the user if the overall feature is
+// enabled.
 const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled";
 
+// Enables/disables the Wallet card and address feature. Set via sync
+// experiment. Even if this is false, the feature can still be enabled via the
+// command line flag flags::kEnableWalletCardImport.
+const char kAutofillWalletSyncExperimentEnabled[] =
+    "autofill.wallet_import_sync_experiment_enabled";
+
 }  // namespace prefs
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_pref_names.h b/components/autofill/core/common/autofill_pref_names.h
index 087780e..fffafd9 100644
--- a/components/autofill/core/common/autofill_pref_names.h
+++ b/components/autofill/core/common/autofill_pref_names.h
@@ -18,6 +18,7 @@
 extern const char kAutofillPositiveUploadRate[];
 extern const char kAutofillUseMacAddressBook[];
 extern const char kAutofillWalletImportEnabled[];
+extern const char kAutofillWalletSyncExperimentEnabled[];
 
 }  // namespace prefs
 }  // namespace autofill
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc
index 73a2fd5..2b62766 100644
--- a/components/autofill/core/common/password_form.cc
+++ b/components/autofill/core/common/password_form.cc
@@ -20,7 +20,7 @@
       blacklisted_by_user(false),
       type(TYPE_MANUAL),
       times_used(0),
-      is_zero_click(false) {
+      skip_zero_click(false) {
 }
 
 PasswordForm::~PasswordForm() {
@@ -55,7 +55,7 @@
       display_name == form.display_name &&
       avatar_url == form.avatar_url &&
       federation_url == form.federation_url &&
-      is_zero_click == form.is_zero_click;
+      skip_zero_click == form.skip_zero_click;
 }
 
 bool PasswordForm::operator!=(const PasswordForm& form) const {
@@ -91,7 +91,7 @@
             << " display_name: " << base::UTF16ToUTF8(form.display_name)
             << " avatar_url: " << form.avatar_url
             << " federation_url: " << form.federation_url
-            << " is_zero_click: " << form.is_zero_click;
+            << " skip_next_zero_click: " << form.skip_zero_click;
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/common/password_form.h b/components/autofill/core/common/password_form.h
index be85cd3e..29d369a7 100644
--- a/components/autofill/core/common/password_form.h
+++ b/components/autofill/core/common/password_form.h
@@ -218,9 +218,10 @@
   // The URL of identity provider used for federated login.
   GURL federation_url;
 
-  // If true, Chrome will sign the user in automatically using the credentials.
-  // This field isn't synced deliberately.
-  bool is_zero_click;
+  // If true, Chrome will not return this credential to a site in response to
+  // 'navigator.credentials.request()' without user interaction.
+  // Once user selects this credential the flag is reseted.
+  bool skip_zero_click;
 
   // Returns true if this match was found using public suffix matching.
   bool IsPublicSuffixMatch() const;
diff --git a/components/browser_watcher/watcher_client_win.cc b/components/browser_watcher/watcher_client_win.cc
index e055278..dd6182a 100644
--- a/components/browser_watcher/watcher_client_win.cc
+++ b/components/browser_watcher/watcher_client_win.cc
@@ -48,6 +48,8 @@
     // Launch the child process inheriting only |self| on
     // Vista and better.
     to_inherit.push_back(self.Handle());
+    to_inherit.insert(to_inherit.end(), inherited_handles_.begin(),
+                      inherited_handles_.end());
     options.handles_to_inherit = &to_inherit;
   }
 
@@ -56,4 +58,8 @@
     LOG(ERROR) << "Failed to launch browser watcher.";
 }
 
+void WatcherClient::AddInheritedHandle(HANDLE handle) {
+  inherited_handles_.push_back(handle);
+}
+
 }  // namespace browser_watcher
diff --git a/components/browser_watcher/watcher_client_win.h b/components/browser_watcher/watcher_client_win.h
index 5ae3c96..9e8810799 100644
--- a/components/browser_watcher/watcher_client_win.h
+++ b/components/browser_watcher/watcher_client_win.h
@@ -32,12 +32,19 @@
   // a non-threadsafe legacy launch mode that's compatible with Windows XP.
   void LaunchWatcher();
 
+  // Ensures that |handle| may be inherited by the watcher process. |handle|
+  // must still be inheritable, and it's the client's responsibility to
+  // communicate the value of |handle| to the launched process.
+  void AddInheritedHandle(HANDLE handle);
+
+  // Returns the launched process.
+  const base::Process& process() const { return process_; }
+
   // Accessors, exposed only for testing.
   bool use_legacy_launch() const { return use_legacy_launch_; }
   void set_use_legacy_launch(bool use_legacy_launch) {
       use_legacy_launch_ = use_legacy_launch;
   }
-  base::ProcessHandle process() const { return process_.Handle(); }
 
  private:
   // If true, the watcher process will be launched with XP legacy handle
@@ -52,6 +59,8 @@
   // LaunchWatcher() call.
   base::Process process_;
 
+  std::vector<HANDLE> inherited_handles_;
+
   DISALLOW_COPY_AND_ASSIGN(WatcherClient);
 };
 
diff --git a/components/browser_watcher/watcher_client_win_unittest.cc b/components/browser_watcher/watcher_client_win_unittest.cc
index 2e19f42..ca24e81 100644
--- a/components/browser_watcher/watcher_client_win_unittest.cc
+++ b/components/browser_watcher/watcher_client_win_unittest.cc
@@ -137,25 +137,11 @@
                       base::Unretained(this), handle_policy);
   }
 
-  void AssertSuccessfulExitCode(base::ProcessHandle handle) {
-    ASSERT_NE(base::kNullProcessHandle, handle);
-
-    // Duplicate the process handle to work around the fact that
-    // WaitForExitCode closes it(!!!).
-    base::ProcessHandle dupe = NULL;
-    ASSERT_TRUE(::DuplicateHandle(base::GetCurrentProcessHandle(),
-                                  handle,
-                                  base::GetCurrentProcessHandle(),
-                                  &dupe,
-                                  SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
-                                  FALSE,
-                                  0));
-    ASSERT_NE(base::kNullProcessHandle, dupe);
+  void AssertSuccessfulExitCode(base::Process process) {
+    ASSERT_TRUE(process.IsValid());
     int exit_code = 0;
-    if (!base::WaitForExitCode(dupe, &exit_code)) {
-      base::CloseProcessHandle(dupe);
-      FAIL() << "WaitForExitCode failed.";
-    }
+    if (!process.WaitForExit(&exit_code))
+      FAIL() << "Process::WaitForExit failed.";
     ASSERT_EQ(0, exit_code);
   }
 
@@ -177,7 +163,8 @@
 
   client.LaunchWatcher();
 
-  ASSERT_NO_FATAL_FAILURE(AssertSuccessfulExitCode(client.process()));
+  ASSERT_NO_FATAL_FAILURE(
+      AssertSuccessfulExitCode(client.process().Duplicate()));
 }
 
 TEST_F(WatcherClientTest, LaunchWatcherLegacyModeSucceeds) {
@@ -190,7 +177,8 @@
 
   client.LaunchWatcher();
 
-  ASSERT_NO_FATAL_FAILURE(AssertSuccessfulExitCode(client.process()));
+  ASSERT_NO_FATAL_FAILURE(
+      AssertSuccessfulExitCode(client.process().Duplicate()));
 }
 
 TEST_F(WatcherClientTest, LegacyModeDetectedOnXP) {
@@ -205,7 +193,8 @@
 
   client.LaunchWatcher();
 
-  ASSERT_NO_FATAL_FAILURE(AssertSuccessfulExitCode(client.process()));
+  ASSERT_NO_FATAL_FAILURE(
+      AssertSuccessfulExitCode(client.process().Duplicate()));
 }
 
 }  // namespace browser_watcher
diff --git a/components/components.gyp b/components/components.gyp
index e5714dd..c8b1e35 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -72,7 +72,6 @@
       'includes': [
         'app_modal.gypi',
         'cdm.gypi',
-        'copresence_endpoints.gypi',
         'navigation_interception.gypi',
         'plugins.gypi',
         'power.gypi',
diff --git a/components/components_browsertests.isolate b/components/components_browsertests.isolate
index cb5b41c..aaa6d190 100644
--- a/components/components_browsertests.isolate
+++ b/components/components_browsertests.isolate
@@ -28,6 +28,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -51,6 +53,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index c4ee483..23261b15 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -723,6 +723,7 @@
                 'components.gyp:wifi_sync',
 
                 'components.gyp:pairing',
+                'components.gyp:user_manager_test_support',
                 '../chromeos/chromeos.gyp:chromeos_test_support',
               ],
             }],
diff --git a/components/components_unittests.isolate b/components/components_unittests.isolate
index 84d0fd137..d94c567 100644
--- a/components/components_unittests.isolate
+++ b/components/components_unittests.isolate
@@ -29,6 +29,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -47,6 +49,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '<(PRODUCT_DIR)/ffmpegsumo.so',
@@ -63,6 +67,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../chrome/test/data/policy/',
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc
index 715df59..386de0c 100644
--- a/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -518,6 +518,7 @@
              setting == CONTENT_SETTING_DETECT_IMPORTANT_CONTENT;
     case CONTENT_SETTINGS_TYPE_GEOLOCATION:
     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+    case CONTENT_SETTINGS_TYPE_FULLSCREEN:
     case CONTENT_SETTINGS_TYPE_MOUSELOCK:
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
diff --git a/components/copresence_endpoints.gypi b/components/copresence_endpoints.gypi
deleted file mode 100644
index 5cd7cc2..0000000
--- a/components/copresence_endpoints.gypi
+++ /dev/null
@@ -1,28 +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.
-
-{
-  'targets': [
-    {
-      'target_name': 'copresence_endpoints',
-      'type': 'static_library',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../device/bluetooth/bluetooth.gyp:device_bluetooth',
-        '../net/net.gyp:net',
-      ],
-      'include_dirs': [
-        '..',
-      ],
-      'sources': [
-        # GN version: //components/copresence_endpoints
-        'copresence_endpoints/copresence_endpoint.cc',
-        'copresence_endpoints/copresence_socket.h',
-        'copresence_endpoints/public/copresence_endpoint.h',
-        'copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.cc',
-        'copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.h',
-      ],
-    },
-  ],
-}
diff --git a/components/copresence_endpoints/BUILD.gn b/components/copresence_endpoints/BUILD.gn
deleted file mode 100644
index 7d4ee0a7..0000000
--- a/components/copresence_endpoints/BUILD.gn
+++ /dev/null
@@ -1,19 +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.
-
-static_library("copresence_endpoints") {
-  sources = [
-    "copresence_endpoint.cc",
-    "copresence_socket.h",
-    "public/copresence_endpoint.h",
-    "transports/bluetooth/copresence_socket_bluetooth.cc",
-    "transports/bluetooth/copresence_socket_bluetooth.h",
-  ]
-
-  deps = [
-    "//base",
-    "//device/bluetooth",
-    "//net",
-  ]
-}
diff --git a/components/copresence_endpoints/DEPS b/components/copresence_endpoints/DEPS
deleted file mode 100644
index 338b701a..0000000
--- a/components/copresence_endpoints/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
-  "+base",
-  "+device/bluetooth",
-  "+net",
-]
diff --git a/components/copresence_endpoints/OWNERS b/components/copresence_endpoints/OWNERS
deleted file mode 100644
index 6a2cb03..0000000
--- a/components/copresence_endpoints/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-rkc@chromium.org
diff --git a/components/copresence_endpoints/copresence_endpoint.cc b/components/copresence_endpoints/copresence_endpoint.cc
deleted file mode 100644
index c13fd33..0000000
--- a/components/copresence_endpoints/copresence_endpoint.cc
+++ /dev/null
@@ -1,162 +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.
-
-#include "components/copresence_endpoints/public/copresence_endpoint.h"
-
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/format_macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/bluetooth_device.h"
-#include "device/bluetooth/bluetooth_socket.h"
-#include "device/bluetooth/bluetooth_uuid.h"
-
-namespace {
-
-const char kAdapterError[] = "NOADAPTER";
-const char kSocketServiceUuid[] = "2491fb14-0077-4d4d-bd41-b18e9a570f56";
-
-// This class will confirm pairing for a device that is expecting a pairing
-// confirmation.
-class DefaultApprovalDelegate
-    : public device::BluetoothDevice::PairingDelegate {
- public:
-  DefaultApprovalDelegate() {}
-  ~DefaultApprovalDelegate() override {}
-
-  // device::BluetoothDevice::PairingDelegate overrides:
-  void RequestPinCode(device::BluetoothDevice* device) override {}
-  void RequestPasskey(device::BluetoothDevice* device) override {}
-  void DisplayPinCode(device::BluetoothDevice* device,
-                      const std::string& pincode) override {}
-  void DisplayPasskey(device::BluetoothDevice* device,
-                      uint32 passkey) override {}
-  void KeysEntered(device::BluetoothDevice* device, uint32 entered) override {}
-  void ConfirmPasskey(device::BluetoothDevice* device,
-                      uint32 passkey) override {}
-  void AuthorizePairing(device::BluetoothDevice* device) override {
-    if (device->ExpectingConfirmation())
-      device->ConfirmPairing();
-  }
-};
-
-}  // namespace
-
-namespace copresence_endpoints {
-
-CopresenceEndpoint::CopresenceEndpoint(
-    int endpoint_id,
-    const CreateEndpointCallback& create_callback,
-    const base::Closure& accept_callback,
-    const CopresenceSocket::ReceiveCallback& receive_callback)
-    : endpoint_id_(endpoint_id),
-      create_callback_(create_callback),
-      accept_callback_(accept_callback),
-      receive_callback_(receive_callback),
-      delegate_(nullptr),
-      weak_ptr_factory_(this) {
-  CHECK(!create_callback.is_null());
-  CHECK(!accept_callback.is_null());
-  CHECK(!receive_callback.is_null());
-
-  if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
-    create_callback_.Run(std::string());
-    return;
-  }
-
-  device::BluetoothAdapterFactory::GetAdapter(base::Bind(
-      &CopresenceEndpoint::OnGetAdapter, weak_ptr_factory_.GetWeakPtr()));
-}
-
-CopresenceEndpoint::~CopresenceEndpoint() {
-  server_socket_->Disconnect(base::Bind(&base::DoNothing));
-  server_socket_->Close();
-  if (delegate_)
-    adapter_->RemovePairingDelegate(delegate_.get());
-}
-
-std::string CopresenceEndpoint::GetLocator() {
-  if (!adapter_.get())
-    return kAdapterError;
-  return base::IntToString(endpoint_id_) + "." + adapter_->GetAddress() + "." +
-         kSocketServiceUuid;
-}
-
-bool CopresenceEndpoint::Send(const scoped_refptr<net::IOBuffer>& buffer,
-                              int buffer_size) {
-  if (!client_socket_)
-    return false;
-
-  return client_socket_->Send(buffer, buffer_size);
-}
-
-// Private methods.
-
-void CopresenceEndpoint::OnGetAdapter(
-    scoped_refptr<device::BluetoothAdapter> adapter) {
-  if (!adapter.get() || !adapter->IsPresent() || !adapter->IsPowered()) {
-    LOG(WARNING) << "Unable to use BT adapter";
-    create_callback_.Run(std::string());
-    return;
-  }
-
-  adapter_ = adapter;
-  delegate_ = make_scoped_ptr(new DefaultApprovalDelegate());
-  VLOG(2) << "Got Adapter, creating service with UUID: " << kSocketServiceUuid;
-  adapter_->AddPairingDelegate(
-      delegate_.get(),
-      device::BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH);
-  adapter_->CreateRfcommService(
-      device::BluetoothUUID(kSocketServiceUuid),
-      device::BluetoothAdapter::ServiceOptions(),
-      base::Bind(&CopresenceEndpoint::OnCreateService,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::Bind(&CopresenceEndpoint::OnCreateServiceError,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CopresenceEndpoint::OnCreateService(
-    scoped_refptr<device::BluetoothSocket> socket) {
-  if (!socket.get()) {
-    LOG(WARNING) << "Couldn't create service!";
-    create_callback_.Run(std::string());
-    return;
-  }
-
-  VLOG(3) << "Starting Accept Socket.";
-  server_socket_ = socket;
-  create_callback_.Run(GetLocator());
-  server_socket_->Accept(
-      base::Bind(&CopresenceEndpoint::OnAccept, weak_ptr_factory_.GetWeakPtr()),
-      base::Bind(&CopresenceEndpoint::OnAcceptError,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CopresenceEndpoint::OnCreateServiceError(const std::string& message) {
-  LOG(WARNING) << "Couldn't create Bluetooth service: " << message;
-  create_callback_.Run(std::string());
-}
-
-void CopresenceEndpoint::OnAccept(
-    const device::BluetoothDevice* device,
-    scoped_refptr<device::BluetoothSocket> socket) {
-  if (!socket.get())
-    return;
-  VLOG(3) << "Accepted Socket.";
-  client_socket_.reset(new CopresenceSocketBluetooth(socket));
-  accept_callback_.Run();
-  client_socket_->Receive(receive_callback_);
-}
-
-void CopresenceEndpoint::OnAcceptError(const std::string& message) {
-  LOG(WARNING) << "Couldn't accept Bluetooth connection: " << message;
-}
-
-}  // namespace copresence_endpoints
diff --git a/components/copresence_endpoints/copresence_socket.h b/components/copresence_endpoints/copresence_socket.h
deleted file mode 100644
index 115300e1..0000000
--- a/components/copresence_endpoints/copresence_socket.h
+++ /dev/null
@@ -1,44 +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.
-
-#ifndef COMPONENTS_COPRESENCE_ENDPOINTS_COPRESENCE_SOCKET_H_
-#define COMPONENTS_COPRESENCE_ENDPOINTS_COPRESENCE_SOCKET_H_
-
-#include <string>
-
-#include "base/macros.h"
-
-namespace net {
-class IOBuffer;
-}
-
-namespace copresence_endpoints {
-
-// A CopresenceSocket is an object that is used to send receive data to and
-// from CopresencePeers.
-// TODO(rkc): Add the ability to connect to a remote CopresencePeer.
-class CopresenceSocket {
- public:
-  typedef base::Callback<void(const scoped_refptr<net::IOBuffer>& buffer,
-                              int buffer_size)> ReceiveCallback;
-
-  CopresenceSocket() {}
-  virtual ~CopresenceSocket() {}
-
-  // Send data on this socket. If unable to send the data, return false. This
-  // operation only guarantees that if the return value is a success, the send
-  // was started. It does not make any guarantees about the completion of the
-  // operation.
-  // TODO(rkc): Expand the bool into more a more detailed failures enum.
-  virtual bool Send(const scoped_refptr<net::IOBuffer>& buffer,
-                    int buffer_size) = 0;
-  virtual void Receive(const ReceiveCallback& callback) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CopresenceSocket);
-};
-
-}  // namespace copresence_endpoints
-
-#endif  // COMPONENTS_COPRESENCE_ENDPOINTS_COPRESENCE_SOCKET_H_
diff --git a/components/copresence_endpoints/public/copresence_endpoint.h b/components/copresence_endpoints/public/copresence_endpoint.h
deleted file mode 100644
index c0b7bc55..0000000
--- a/components/copresence_endpoints/public/copresence_endpoint.h
+++ /dev/null
@@ -1,89 +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.
-
-#ifndef COMPONENTS_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINT_H_
-#define COMPONENTS_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINT_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "components/copresence_endpoints/copresence_socket.h"
-#include "device/bluetooth/bluetooth_device.h"
-#include "device/bluetooth/bluetooth_uuid.h"
-
-namespace device {
-class BluetoothAdapter;
-class BluetoothSocket;
-}
-
-namespace copresence_endpoints {
-
-// A CopresenceEndpoint is an object that can be used for communication with
-// remote endpoints. Creating this object will create a server that will listen
-// on Bluetooth (currently) and accept connections. Once a connection is
-// accepted, the endpoint continuously listens for data on the accepted
-// connection(s).
-class CopresenceEndpoint {
- public:
-  // Callback with the locator data for the created peer. On a failed create,
-  // the locator string will be empty.
-  typedef base::Callback<void(const std::string&)> CreateEndpointCallback;
-
-  // Create a CopresenceEndpoint and start listening for connections. Once the
-  // endpoint object is created, the locator data for the object is returned via
-  // create_callback. This locator data can be used to connect to this peer by
-  // a remote endpoint.
-  // endpoint_id is the id that this endpoint will use to identify itself.
-  // create_callback is called when the endpoint creation is complete.
-  // accept_callback is called when we receive an incoming connection.
-  // receive_callback is called when we receive data on this endpoint.
-  CopresenceEndpoint(int endpoint_id,
-                     const CreateEndpointCallback& create_callback,
-                     const base::Closure& accept_callback,
-                     const CopresenceSocket::ReceiveCallback& receive_callback);
-
-  virtual ~CopresenceEndpoint();
-
-  // Send's data to the remote device connected to this endpoint.
-  bool Send(const scoped_refptr<net::IOBuffer>& buffer, int buffer_size);
-
-  // This will return a string containing the data needed for a remote endpoint
-  // to connect to this endpoint.
-  std::string GetLocator();
-
- private:
-  void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
-  void OnCreateService(scoped_refptr<device::BluetoothSocket> socket);
-  void OnCreateServiceError(const std::string& message);
-
-  void OnAccept(const device::BluetoothDevice* device,
-                scoped_refptr<device::BluetoothSocket> socket);
-  void OnAcceptError(const std::string& message);
-
-  scoped_refptr<device::BluetoothAdapter> adapter_;
-  scoped_refptr<device::BluetoothSocket> server_socket_;
-  // TODO(rkc): Eventually an endpoint will be able to accept multiple
-  // connections. Whenever the API supports one-to-many connections, fix this
-  // code to do so too.
-  scoped_ptr<CopresenceSocket> client_socket_;
-
-  int endpoint_id_;
-  CreateEndpointCallback create_callback_;
-  base::Closure accept_callback_;
-  CopresenceSocket::ReceiveCallback receive_callback_;
-
-  scoped_ptr<device::BluetoothDevice::PairingDelegate> delegate_;
-
-  base::WeakPtrFactory<CopresenceEndpoint> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(CopresenceEndpoint);
-};
-
-}  // namespace copresence_endpoints
-
-#endif  // COMPONENTS_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINT_H_
diff --git a/components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.cc b/components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.cc
deleted file mode 100644
index bfee046a..0000000
--- a/components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.cc
+++ /dev/null
@@ -1,94 +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.
-
-#include "components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_piece.h"
-#include "device/bluetooth/bluetooth_socket.h"
-#include "net/base/io_buffer.h"
-
-namespace {
-
-// TODO(rkc): This number is totally arbitrary. Figure out what this should be.
-const int kMaxReceiveBytes = 4096;
-
-}  // namespace
-
-namespace copresence_endpoints {
-
-CopresenceSocketBluetooth::CopresenceSocketBluetooth(
-    const scoped_refptr<device::BluetoothSocket>& socket)
-    : socket_(socket), receiving_(false), weak_ptr_factory_(this) {
-}
-
-CopresenceSocketBluetooth::~CopresenceSocketBluetooth() {
-  receiving_ = false;
-}
-
-bool CopresenceSocketBluetooth::Send(const scoped_refptr<net::IOBuffer>& buffer,
-                                     int buffer_size) {
-  VLOG(3) << "Starting sending of data with size = " << buffer_size;
-  socket_->Send(buffer, buffer_size,
-                base::Bind(&CopresenceSocketBluetooth::OnSendComplete,
-                           weak_ptr_factory_.GetWeakPtr()),
-                base::Bind(&CopresenceSocketBluetooth::OnSendError,
-                           weak_ptr_factory_.GetWeakPtr()));
-  return true;
-}
-
-void CopresenceSocketBluetooth::Receive(const ReceiveCallback& callback) {
-  VLOG(3) << "Starting Receive.";
-  receiving_ = true;
-  receive_callback_ = callback;
-  socket_->Receive(kMaxReceiveBytes,
-                   base::Bind(&CopresenceSocketBluetooth::OnReceive,
-                              weak_ptr_factory_.GetWeakPtr()),
-                   base::Bind(&CopresenceSocketBluetooth::OnReceiveError,
-                              weak_ptr_factory_.GetWeakPtr()));
-}
-
-void CopresenceSocketBluetooth::OnSendComplete(int status) {
-  VLOG(3) << "Send Completed. Status = " << status;
-}
-
-void CopresenceSocketBluetooth::OnSendError(const std::string& message) {
-  LOG(ERROR) << "Bluetooth send error: " << message;
-}
-
-void CopresenceSocketBluetooth::OnReceive(
-    int size,
-    scoped_refptr<net::IOBuffer> io_buffer) {
-  VLOG(3) << "Data received with size = " << size
-          << " and receiving_ = " << receiving_;
-  // Dispatch the data to the callback and go back to listening for more data.
-  receive_callback_.Run(io_buffer, size);
-
-  // We cancelled receiving due to an error. Don't post more receive tasks.
-  if (!receiving_)
-    return;
-
-  // Post a task to delay the read until the socket is available, as
-  // calling Receive again at this point would error with ERR_IO_PENDING.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&device::BluetoothSocket::Receive, socket_, kMaxReceiveBytes,
-                 base::Bind(&CopresenceSocketBluetooth::OnReceive,
-                            weak_ptr_factory_.GetWeakPtr()),
-                 base::Bind(&CopresenceSocketBluetooth::OnReceiveError,
-                            weak_ptr_factory_.GetWeakPtr())));
-}
-
-void CopresenceSocketBluetooth::OnReceiveError(
-    device::BluetoothSocket::ErrorReason reason,
-    const std::string& message) {
-  LOG(ERROR) << "Bluetooth receive error: " << message;
-  if (reason == device::BluetoothSocket::kIOPending)
-    return;
-
-  receiving_ = false;
-}
-
-}  // namespace copresence_endpoints
diff --git a/components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.h b/components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.h
deleted file mode 100644
index 5af5557d..0000000
--- a/components/copresence_endpoints/transports/bluetooth/copresence_socket_bluetooth.h
+++ /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.
-
-#ifndef COMPONENTS_COPRESENCE_SOCKETS_TRANSPORTS_COPRESENCE_SOCKET_BLUETOOTH_H_
-#define COMPONENTS_COPRESENCE_SOCKETS_TRANSPORTS_COPRESENCE_SOCKET_BLUETOOTH_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "components/copresence_endpoints/copresence_socket.h"
-#include "device/bluetooth/bluetooth_socket.h"
-
-namespace net {
-class IOBuffer;
-}
-
-namespace copresence_endpoints {
-
-// A CopresenceSocketBluetooth is the Bluetooth implementation of a
-// CopresenceSocket. This is currently a thin wrapper around BluetoothSocket.
-class CopresenceSocketBluetooth : public CopresenceSocket {
- public:
-  explicit CopresenceSocketBluetooth(
-      const scoped_refptr<device::BluetoothSocket>& socket);
-  ~CopresenceSocketBluetooth() override;
-
-  // CopresenceSocket overrides:
-  bool Send(const scoped_refptr<net::IOBuffer>& buffer,
-            int buffer_size) override;
-  void Receive(const ReceiveCallback& callback) override;
-
- private:
-  void OnSendComplete(int status);
-  void OnSendError(const std::string& message);
-
-  void OnReceive(int size, scoped_refptr<net::IOBuffer> io_buffer);
-  void OnReceiveError(device::BluetoothSocket::ErrorReason reason,
-                      const std::string& message);
-
-  scoped_refptr<device::BluetoothSocket> socket_;
-  ReceiveCallback receive_callback_;
-
-  bool receiving_;
-
-  base::WeakPtrFactory<CopresenceSocketBluetooth> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(CopresenceSocketBluetooth);
-};
-
-}  // namespace copresence_endpoints
-
-#endif  // COMPONENTS_COPRESENCE_SOCKETS_TRANSPORTS_COPRESENCE_SOCKET_BLUETOOTH_H_
diff --git a/components/data_reduction_proxy/OWNERS b/components/data_reduction_proxy/OWNERS
index 6a63b53..6fe062f7 100644
--- a/components/data_reduction_proxy/OWNERS
+++ b/components/data_reduction_proxy/OWNERS
@@ -1,3 +1,4 @@
 bengr@chromium.org
 bolian@chromium.org
 marq@chromium.org
+sclittle@chromium.org
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats.cc
index 7c1293b..f603265 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats.cc
@@ -128,8 +128,13 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   DataReductionProxyTypeInfo proxy_info;
+  // Ignore requests that did not use the data reduction proxy. The check for
+  // LOAD_BYPASS_PROXY is necessary because the proxy_server() in the |request|
+  // might still be set to the data reduction proxy if |request| was retried
+  // over direct and a network error occurred while retrying it.
   if (data_reduction_proxy_params_->WasDataReductionProxyUsed(request,
-                                                              &proxy_info)) {
+                                                              &proxy_info) &&
+      (request->load_flags() & net::LOAD_BYPASS_PROXY) == 0) {
     if (request->status().status() == net::URLRequestStatus::SUCCESS) {
       successful_requests_through_proxy_count_++;
       NotifyUnavailabilityIfChanged();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc
index 7867884..dbd85d4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats_unittest.cc
@@ -448,22 +448,25 @@
 
   struct TestCase {
     bool was_proxy_used;
+    bool is_load_bypass_proxy;
     bool is_fallback;
     bool is_main_frame;
     net::Error net_error;
   };
 
   const TestCase test_cases[] = {
-    {false, false, true, net::OK},
-    {false, false, false, net::ERR_TOO_MANY_REDIRECTS},
-    {true, false, true, net::OK},
-    {true, false, true, net::ERR_TOO_MANY_REDIRECTS},
-    {true, false, false, net::OK},
-    {true, false, false, net::ERR_TOO_MANY_REDIRECTS},
-    {true, true, true, net::OK},
-    {true, true, true, net::ERR_TOO_MANY_REDIRECTS},
-    {true, true, false, net::OK},
-    {true, true, false, net::ERR_TOO_MANY_REDIRECTS}
+    {false, true, false, true, net::OK},
+    {false, true, false, false, net::ERR_TOO_MANY_REDIRECTS},
+    {false, false, false, true, net::OK},
+    {false, false, false, false, net::ERR_TOO_MANY_REDIRECTS},
+    {true, false, false, true, net::OK},
+    {true, false, false, true, net::ERR_TOO_MANY_REDIRECTS},
+    {true, false, false, false, net::OK},
+    {true, false, false, false, net::ERR_TOO_MANY_REDIRECTS},
+    {true, false, true, true, net::OK},
+    {true, false, true, true, net::ERR_TOO_MANY_REDIRECTS},
+    {true, false, true, false, net::OK},
+    {true, false, true, false, net::ERR_TOO_MANY_REDIRECTS}
   };
 
   for (size_t i = 0; i < arraysize(test_cases); ++i) {
@@ -478,6 +481,10 @@
     scoped_ptr<net::URLRequest> fake_request(
         CreateURLRequestWithResponseHeaders(GURL("http://www.google.com/"),
                                             raw_headers));
+    if (test_cases[i].is_load_bypass_proxy) {
+      fake_request->SetLoadFlags(fake_request->load_flags() |
+                                 net::LOAD_BYPASS_PROXY);
+    }
     if (test_cases[i].is_main_frame) {
       fake_request->SetLoadFlags(fake_request->load_flags() |
                                  net::LOAD_MAIN_FRAME);
@@ -497,27 +504,29 @@
 
     usage_stats->OnUrlRequestCompleted(fake_request.get(), false);
 
-    if (test_cases[i].was_proxy_used && !test_cases[i].is_fallback) {
+    if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy &&
+        !test_cases[i].is_fallback) {
       histogram_tester.ExpectUniqueSample(
           kPrimaryHistogramName, -net_error_int, 1);
     } else {
       histogram_tester.ExpectTotalCount(kPrimaryHistogramName, 0);
     }
-    if (test_cases[i].was_proxy_used && test_cases[i].is_fallback) {
+    if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy &&
+        test_cases[i].is_fallback) {
       histogram_tester.ExpectUniqueSample(
           kFallbackHistogramName, -net_error_int, 1);
     } else {
       histogram_tester.ExpectTotalCount(kFallbackHistogramName, 0);
     }
-    if (test_cases[i].was_proxy_used && !test_cases[i].is_fallback &&
-        test_cases[i].is_main_frame) {
+    if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy &&
+        !test_cases[i].is_fallback && test_cases[i].is_main_frame) {
       histogram_tester.ExpectUniqueSample(
           kPrimaryMainFrameHistogramName, -net_error_int, 1);
     } else {
       histogram_tester.ExpectTotalCount(kPrimaryMainFrameHistogramName, 0);
     }
-    if (test_cases[i].was_proxy_used && test_cases[i].is_fallback &&
-        test_cases[i].is_main_frame) {
+    if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy &&
+        test_cases[i].is_fallback && test_cases[i].is_main_frame) {
       histogram_tester.ExpectUniqueSample(
           kFallbackMainFrameHistogramName, -net_error_int, 1);
     } else {
diff --git a/components/enhanced_bookmarks/enhanced_bookmark_model.cc b/components/enhanced_bookmarks/enhanced_bookmark_model.cc
index f9d34782..f114c5a 100644
--- a/components/enhanced_bookmarks/enhanced_bookmark_model.cc
+++ b/components/enhanced_bookmarks/enhanced_bookmark_model.cc
@@ -226,6 +226,16 @@
   return true;
 }
 
+void EnhancedBookmarkModel::RemoveImageData(const BookmarkNode* node) {
+  DCHECK(node->is_url());
+  image::collections::ImageData data;
+  data.set_user_removed_image(true);
+
+  std::string encoded_data;
+  base::Base64Encode(data.SerializeAsString(), &encoded_data);
+  SetMetaInfo(node, kImageDataKey, encoded_data);
+}
+
 bool EnhancedBookmarkModel::GetOriginalImage(const BookmarkNode* node,
                                              GURL* url,
                                              int* width,
diff --git a/components/enhanced_bookmarks/enhanced_bookmark_model.h b/components/enhanced_bookmarks/enhanced_bookmark_model.h
index 7eab266..1660237 100644
--- a/components/enhanced_bookmarks/enhanced_bookmark_model.h
+++ b/components/enhanced_bookmarks/enhanced_bookmark_model.h
@@ -86,6 +86,10 @@
                         int width,
                         int height);
 
+  // Removes all image data for the node and sets the user_removed_image flag
+  // so the server won't try to fetch a new image for the node.
+  void RemoveImageData(const BookmarkNode* node);
+
   // Returns the url and dimensions of the original scraped image of a
   // bookmark |node|.
   // Returns true if the out variables are populated, false otherwise.
diff --git a/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc b/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc
index db2c54f0..f760d0c 100644
--- a/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc
+++ b/components/enhanced_bookmarks/enhanced_bookmark_model_unittest.cc
@@ -25,6 +25,7 @@
 
 namespace {
 const std::string BOOKMARK_URL("http://example.com/index.html");
+const std::string IMAGE_URL("http://example.com/image.jpg");
 }  // namespace
 
 class EnhancedBookmarkModelTest
@@ -773,3 +774,24 @@
       bookmark_model_->non_cloned_keys();
   EXPECT_TRUE(non_cloned_keys.find("stars.id") != non_cloned_keys.end());
 }
+
+TEST_F(EnhancedBookmarkModelTest, RemoveImageData) {
+  const BookmarkNode* node = AddBookmark();
+  model_->SetAllImages(node, GURL(IMAGE_URL), 64, 64, GURL(IMAGE_URL), 16, 16);
+
+  GURL url;
+  int width, height;
+  EXPECT_TRUE(model_->GetOriginalImage(node, &url, &width, &height));
+  EXPECT_TRUE(model_->GetThumbnailImage(node, &url, &width, &height));
+
+  model_->RemoveImageData(node);
+  EXPECT_FALSE(model_->GetOriginalImage(node, &url, &width, &height));
+  EXPECT_FALSE(model_->GetThumbnailImage(node, &url, &width, &height));
+
+  std::string meta_info = GetMetaInfoField(node, "stars.imageData");
+  std::string decoded;
+  ASSERT_TRUE(base::Base64Decode(meta_info, &decoded));
+  image::collections::ImageData data;
+  ASSERT_TRUE(data.ParseFromString(decoded));
+  EXPECT_TRUE(data.user_removed_image());
+}
diff --git a/components/enhanced_bookmarks/proto/metadata.proto b/components/enhanced_bookmarks/proto/metadata.proto
index bf4f18c..4a5f2ecd 100644
--- a/components/enhanced_bookmarks/proto/metadata.proto
+++ b/components/enhanced_bookmarks/proto/metadata.proto
@@ -26,6 +26,17 @@
 
   // Information about the server hosted thumbnail.
   optional ImageInfo thumbnail_info = 3;
+
+  // The expiration timestamp of the served thumbnail, in microseconds since
+  // epoch. The thumbnail is only guaranteed until this time, afterwards the
+  // URL may be broken.
+  // If expiration_timestamp is not present, then whoever set the thumbnail_info
+  // should guarantee that the thumbnail will not expire.
+  optional int64 expiration_timestamp = 5;
+
+  // Represents an explicit user action to remove an image. This will prevent
+  // any additional backfilling once this is set.
+  optional bool user_removed_image = 6;
 }
 
 message PageData {
diff --git a/components/nacl.gyp b/components/nacl.gyp
index f6d7e26..9d543d8 100644
--- a/components/nacl.gyp
+++ b/components/nacl.gyp
@@ -77,11 +77,12 @@
           'dependencies': [
             '../base/base.gyp:base',
             '../base/base.gyp:base_static',
+            '../crypto/crypto.gyp:crypto',
             '../ipc/ipc.gyp:ipc',
             '../mojo/mojo_nacl.gyp:monacl_syscall',
-            '../ppapi/ppapi_internal.gyp:ppapi_shared',
-            '../ppapi/ppapi_internal.gyp:ppapi_ipc',
             '../native_client/src/trusted/service_runtime/service_runtime.gyp:sel_main_chrome',
+            '../ppapi/ppapi_internal.gyp:ppapi_ipc',
+            '../ppapi/ppapi_internal.gyp:ppapi_shared',
             '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
           ],
           'conditions': [
@@ -202,11 +203,14 @@
           'target_name': 'nacl_loader_unittests',
           'type': '<(gtest_target_type)',
           'sources': [
+            'nacl/loader/nacl_ipc_adapter_unittest.cc',
+            'nacl/loader/nacl_validation_query_unittest.cc',
             'nacl/loader/run_all_unittests.cc',
           ],
           'dependencies': [
             'nacl',
             '../base/base.gyp:test_support_base',
+            '../ipc/ipc.gyp:test_support_ipc',
             '../testing/gtest.gyp:gtest',
           ],
           'conditions': [
@@ -218,8 +222,8 @@
                 'nacl/loader/nonsfi/irt_icache_unittest.cc',
                 # TODO(hamaji): Currently, we build them twice. Stop building
                 # them for components_unittests. See crbug.com/364751
-                'nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc',
                 'nacl/loader/nonsfi/nonsfi_sandbox_sigsys_unittest.cc',
+                'nacl/loader/nonsfi/nonsfi_sandbox_unittest.cc',
               ],
               'dependencies': [
                 'nacl_linux',
diff --git a/components/password_manager/core/browser/affiliation_utils.cc b/components/password_manager/core/browser/affiliation_utils.cc
index 23de0888..4f57b861 100644
--- a/components/password_manager/core/browser/affiliation_utils.cc
+++ b/components/password_manager/core/browser/affiliation_utils.cc
@@ -8,8 +8,11 @@
 #include <ostream>
 
 #include "base/base64.h"
+#include "base/command_line.h"
+#include "base/metrics/field_trial.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "components/password_manager/core/common/password_manager_switches.h"
 #include "net/base/escape.h"
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_canon_stdstring.h"
@@ -285,4 +288,17 @@
   return std::equal(a_sorted.begin(), a_sorted.end(), b_sorted.begin());
 }
 
+bool IsAffiliationBasedMatchingEnabled(const base::CommandLine& command_line) {
+  // Note: It is important to always query the field trial state, to ensure that
+  // UMA reports the correct group.
+  const std::string group_name =
+      base::FieldTrialList::FindFullName("AffiliationBasedMatching");
+
+  if (command_line.HasSwitch(switches::kDisableAffiliationBasedMatching))
+    return false;
+  if (command_line.HasSwitch(switches::kEnableAffiliationBasedMatching))
+    return true;
+  return StartsWithASCII(group_name, "Enabled", /*case_sensitive=*/false);
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_utils.h b/components/password_manager/core/browser/affiliation_utils.h
index 5a25b53e..8054346 100644
--- a/components/password_manager/core/browser/affiliation_utils.h
+++ b/components/password_manager/core/browser/affiliation_utils.h
@@ -53,6 +53,10 @@
 #include "base/time/time.h"
 #include "url/url_parse.h"
 
+namespace base {
+class CommandLine;
+}  // namespace base
+
 namespace password_manager {
 
 // Encapsulates a facet URI in canonical form.
@@ -161,6 +165,11 @@
 bool AreEquivalenceClassesEqual(const AffiliatedFacets& a,
                                 const AffiliatedFacets& b);
 
+// Returns whether or not affiliation based matching is enabled, either via
+// command line flags or field trials. The command line flag, if present, always
+// takes precedence.
+bool IsAffiliationBasedMatchingEnabled(const base::CommandLine& command_line);
+
 // For logging use only.
 std::ostream& operator<<(std::ostream& os, const FacetURI& facet_uri);
 
diff --git a/components/password_manager/core/browser/affiliation_utils_unittest.cc b/components/password_manager/core/browser/affiliation_utils_unittest.cc
index 540963d..c67ac8be 100644
--- a/components/password_manager/core/browser/affiliation_utils_unittest.cc
+++ b/components/password_manager/core/browser/affiliation_utils_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "components/password_manager/core/browser/affiliation_utils.h"
 
+#include "base/command_line.h"
+#include "base/metrics/field_trial.h"
+#include "components/password_manager/core/common/password_manager_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/url_constants.h"
 
@@ -192,4 +195,44 @@
   EXPECT_FALSE(AreEquivalenceClassesEqual(c, b));
 }
 
+TEST(AffiliationUtilsTest, IsAffiliationBasedMatchingEnabled) {
+  const char kFieldTrialName[] = "AffiliationBasedMatching";
+
+  struct {
+    const char* field_trial_group;
+    const char* command_line_switch;
+    bool expected_enabled;
+  } kTestCases[] = {
+      {"", "", false},
+      {"", switches::kEnableAffiliationBasedMatching, true},
+      {"", switches::kDisableAffiliationBasedMatching, false},
+      {"garbage value", "", false},
+      {"disabled", "", false},
+      {"disabled2", "", false},
+      {"Disabled", "", false},
+      {"Disabled", switches::kDisableAffiliationBasedMatching, false},
+      {"Disabled", switches::kEnableAffiliationBasedMatching, true},
+      {"enabled", "", true},
+      {"enabled2", "", true},
+      {"Enabled", "", true},
+      {"Enabled", switches::kDisableAffiliationBasedMatching, false},
+      {"Enabled", switches::kEnableAffiliationBasedMatching, true}};
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(testing::Message("Command line = ")
+                 << test_case.command_line_switch);
+    SCOPED_TRACE(testing::Message("Group name = ")
+                 << test_case.field_trial_group);
+
+    base::FieldTrialList field_trials(NULL);
+    base::FieldTrialList::CreateFieldTrial(kFieldTrialName,
+                                           test_case.field_trial_group);
+
+    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+    command_line.AppendSwitch(test_case.command_line_switch);
+    EXPECT_EQ(test_case.expected_enabled,
+              IsAffiliationBasedMatchingEnabled(command_line));
+  }
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index 31cbb61..44dff2a 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -27,7 +27,7 @@
 
 namespace password_manager {
 
-const int kCurrentVersionNumber = 10;
+const int kCurrentVersionNumber = 11;
 static const int kCompatibleVersionNumber = 1;
 
 Pickle SerializeVector(const std::vector<base::string16>& vec) {
@@ -74,7 +74,7 @@
   COLUMN_DISPLAY_NAME,
   COLUMN_AVATAR_URL,
   COLUMN_FEDERATION_URL,
-  COLUMN_IS_ZERO_CLICK,
+  COLUMN_SKIP_ZERO_CLICK,
 };
 
 void BindAddStatement(const PasswordForm& form,
@@ -109,7 +109,7 @@
   s->BindString16(COLUMN_DISPLAY_NAME, form.display_name);
   s->BindString(COLUMN_AVATAR_URL, form.avatar_url.spec());
   s->BindString(COLUMN_FEDERATION_URL, form.federation_url.spec());
-  s->BindInt(COLUMN_IS_ZERO_CLICK, form.is_zero_click);
+  s->BindInt(COLUMN_SKIP_ZERO_CLICK, form.skip_zero_click);
 }
 
 void AddCallback(int err, sql::Statement* /*stmt*/) {
@@ -150,6 +150,43 @@
   LogDynamicUMAStat(name, sample, 0, 100, 10);
 }
 
+// Creates a table named |table_name| using our current schema.
+bool CreateNewTable(sql::Connection* db, const char* table_name) {
+  std::string query = base::StringPrintf(
+      "CREATE TABLE %s ("
+      "origin_url VARCHAR NOT NULL, "
+      "action_url VARCHAR, "
+      "username_element VARCHAR, "
+      "username_value VARCHAR, "
+      "password_element VARCHAR, "
+      "password_value BLOB, "
+      "submit_element VARCHAR, "
+      "signon_realm VARCHAR NOT NULL,"
+      "ssl_valid INTEGER NOT NULL,"
+      "preferred INTEGER NOT NULL,"
+      "date_created INTEGER NOT NULL,"
+      "blacklisted_by_user INTEGER NOT NULL,"
+      "scheme INTEGER NOT NULL,"
+      "password_type INTEGER,"
+      "possible_usernames BLOB,"
+      "times_used INTEGER,"
+      "form_data BLOB,"
+      "date_synced INTEGER,"
+      "display_name VARCHAR,"
+      "avatar_url VARCHAR,"
+      "federation_url VARCHAR,"
+      "skip_zero_click INTEGER,"
+      "UNIQUE (origin_url, username_element, username_value, "
+      "password_element, signon_realm))", table_name);
+  return db->Execute(query.c_str());
+}
+
+bool CreateIndexOnSignonRealm(sql::Connection* db, const char* table_name) {
+  std::string query = base::StringPrintf(
+      "CREATE INDEX logins_signon ON %s (signon_realm)", table_name);
+  return db->Execute(query.c_str());
+}
+
 }  // namespace
 
 LoginDatabase::LoginDatabase(const base::FilePath& db_path)
@@ -300,11 +337,30 @@
               ("CREATE TABLE logins(" + fields_to_copy + ")").c_str()) ||
           !db_.Execute(copy_data_query("logins_data", "logins").c_str()) ||
           !db_.Execute("DROP TABLE logins_data") ||
-          !db_.Execute("CREATE INDEX logins_signon ON logins (signon_realm)"))
+          !CreateIndexOnSignonRealm(&db_, "logins"))
         return false;
 
       meta_table_.SetVersionNumber(10);
     }
+    case 10: {
+      // rename is_zero_click -> skip_zero_click and restore the unique key
+      // (origin_url, username_element, username_value, password_element,
+      // signon_realm).
+      const char copy_query[] = "INSERT OR REPLACE INTO logins_new SELECT "
+          "origin_url, action_url, username_element, username_value, "
+          "password_element, password_value, submit_element, signon_realm, "
+          "ssl_valid, preferred, date_created, blacklisted_by_user, scheme, "
+          "password_type, possible_usernames, times_used, form_data, "
+          "date_synced, display_name, avatar_url, federation_url, is_zero_click"
+          " FROM logins";
+      if (!CreateNewTable(&db_, "logins_new") ||
+          !db_.Execute(copy_query) ||
+          !db_.Execute("DROP TABLE logins") ||
+          !db_.Execute("ALTER TABLE logins_new RENAME TO logins") ||
+          !CreateIndexOnSignonRealm(&db_, "logins"))
+        return false;
+      meta_table_.SetVersionNumber(11);
+    }
     case kCurrentVersionNumber:
       // Already up to date
       return true;
@@ -316,39 +372,11 @@
 
 bool LoginDatabase::InitLoginsTable() {
   if (!db_.DoesTableExist("logins")) {
-    if (!db_.Execute(
-            "CREATE TABLE logins ("
-            "origin_url VARCHAR NOT NULL, "
-            "action_url VARCHAR, "
-            "username_element VARCHAR, "
-            "username_value VARCHAR, "
-            "password_element VARCHAR, "
-            "password_value BLOB, "
-            "submit_element VARCHAR, "
-            "signon_realm VARCHAR NOT NULL,"
-            "ssl_valid INTEGER NOT NULL,"
-            "preferred INTEGER NOT NULL,"
-            "date_created INTEGER NOT NULL,"
-            "blacklisted_by_user INTEGER NOT NULL,"
-            "scheme INTEGER NOT NULL,"
-            "password_type INTEGER,"
-            "possible_usernames BLOB,"
-            "times_used INTEGER,"
-            "form_data BLOB,"
-            "date_synced INTEGER,"
-            "display_name VARCHAR,"
-            "avatar_url VARCHAR,"
-            "federation_url VARCHAR,"
-            "is_zero_click INTEGER,"
-            "UNIQUE "
-            "(origin_url, username_element, "
-            "username_value, password_element, "
-            "submit_element, signon_realm))")) {
+    if (!CreateNewTable(&db_, "logins")) {
       NOTREACHED();
       return false;
     }
-    if (!db_.Execute("CREATE INDEX logins_signon ON "
-                     "logins (signon_realm)")) {
+    if (!CreateIndexOnSignonRealm(&db_, "logins")) {
       NOTREACHED();
       return false;
     }
@@ -483,7 +511,7 @@
       " signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
       " scheme, password_type, possible_usernames, times_used, form_data, "
       " date_synced, display_name, avatar_url,"
-      " federation_url, is_zero_click) VALUES "
+      " federation_url, skip_zero_click) VALUES "
       "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
   BindAddStatement(form, encrypted_password, &s);
   db_.set_error_callback(base::Bind(&AddCallback));
@@ -502,7 +530,7 @@
       " signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
       " scheme, password_type, possible_usernames, times_used, form_data, "
       " date_synced, display_name, avatar_url,"
-      " federation_url, is_zero_click) VALUES "
+      " federation_url, skip_zero_click) VALUES "
       "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
   BindAddStatement(form, encrypted_password, &s);
   if (s.Run()) {
@@ -537,7 +565,7 @@
                                           "display_name = ?, "
                                           "avatar_url = ?, "
                                           "federation_url = ?, "
-                                          "is_zero_click = ? "
+                                          "skip_zero_click = ? "
                                           "WHERE origin_url = ? AND "
                                           "username_element = ? AND "
                                           "username_value = ? AND "
@@ -560,7 +588,7 @@
   s.BindString16(12, form.display_name);
   s.BindString(13, form.avatar_url.spec());
   s.BindString(14, form.federation_url.spec());
-  s.BindInt(15, form.is_zero_click);
+  s.BindInt(15, form.skip_zero_click);
 
   // WHERE starts here.
   s.BindString(16, form.origin.spec());
@@ -681,7 +709,7 @@
   form->display_name = s.ColumnString16(COLUMN_DISPLAY_NAME);
   form->avatar_url = GURL(s.ColumnString(COLUMN_AVATAR_URL));
   form->federation_url = GURL(s.ColumnString(COLUMN_FEDERATION_URL));
-  form->is_zero_click = (s.ColumnInt(COLUMN_IS_ZERO_CLICK) > 0);
+  form->skip_zero_click = (s.ColumnInt(COLUMN_SKIP_ZERO_CLICK) > 0);
   return ENCRYPTION_RESULT_SUCCESS;
 }
 
@@ -697,7 +725,8 @@
       "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
       "scheme, password_type, possible_usernames, times_used, form_data, "
       "date_synced, display_name, avatar_url, "
-      "federation_url, is_zero_click FROM logins WHERE signon_realm == ? ";
+      "federation_url, skip_zero_click "
+      "FROM logins WHERE signon_realm == ? ";
   sql::Statement s;
   const GURL signon_realm(form.signon_realm);
   std::string registered_domain = GetRegistryControlledDomain(signon_realm);
@@ -794,7 +823,7 @@
       "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
       "scheme, password_type, possible_usernames, times_used, form_data, "
       "date_synced, display_name, avatar_url, "
-      "federation_url, is_zero_click FROM logins "
+      "federation_url, skip_zero_click FROM logins "
       "WHERE date_created >= ? AND date_created < ?"
       "ORDER BY origin_url"));
   s.BindInt64(0, begin.ToInternalValue());
@@ -826,7 +855,7 @@
       "ssl_valid, preferred, date_created, blacklisted_by_user, "
       "scheme, password_type, possible_usernames, times_used, form_data, "
       "date_synced, display_name, avatar_url, "
-      "federation_url, is_zero_click FROM logins "
+      "federation_url, skip_zero_click FROM logins "
       "WHERE date_synced >= ? AND date_synced < ?"
       "ORDER BY origin_url"));
   s.BindInt64(0, begin.ToInternalValue());
@@ -870,7 +899,7 @@
       "signon_realm, ssl_valid, preferred, date_created, blacklisted_by_user, "
       "scheme, password_type, possible_usernames, times_used, form_data, "
       "date_synced, display_name, avatar_url, "
-      "federation_url, is_zero_click FROM logins "
+      "federation_url, skip_zero_click FROM logins "
       "WHERE blacklisted_by_user == ? ORDER BY origin_url"));
   s.BindInt(0, blacklisted ? 1 : 0);
 
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index 97c566c..e9b87329 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
 #include "base/time/time.h"
@@ -65,7 +66,7 @@
   form->display_name = ASCIIToUTF16("Mr. Smith");
   form->avatar_url = GURL("https://accounts.google.com/Avatar");
   form->federation_url = GURL("https://accounts.google.com/federation");
-  form->is_zero_click = true;
+  form->skip_zero_click = true;
 }
 
 }  // namespace
@@ -617,7 +618,7 @@
   form.display_name = ASCIIToUTF16(unique_string);
   form.avatar_url = GURL("https://accounts.google.com/Avatar");
   form.federation_url = GURL("https://accounts.google.com/federation");
-  form.is_zero_click = true;
+  form.skip_zero_click = true;
 
   if (date_is_creation)
     form.date_created = time;
@@ -741,7 +742,7 @@
   form.display_name = ASCIIToUTF16("Mr. Smith");
   form.avatar_url = GURL("https://accounts.google.com/Avatar");
   form.federation_url = GURL("https://accounts.google.com/federation");
-  form.is_zero_click = true;
+  form.skip_zero_click = true;
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
 
   // Get all non-blacklisted logins (should be none).
@@ -980,7 +981,7 @@
   form.display_name = ASCIIToUTF16("Mr. Smith");
   form.avatar_url = GURL("https://accounts.google.com/Avatar");
   form.federation_url = GURL("https://accounts.google.com/federation");
-  form.is_zero_click = true;
+  form.skip_zero_click = true;
   EXPECT_EQ(UpdateChangeForForm(form), db().UpdateLogin(form));
 
   ScopedVector<autofill::PasswordForm> result;
@@ -1116,7 +1117,8 @@
 }
 #endif  // defined(OS_POSIX)
 
-class LoginDatabaseMigrationTest : public testing::Test {
+// Test the migration from GetParam() version to kCurrentVersionNumber.
+class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
  protected:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -1127,12 +1129,12 @@
     database_path_ = temp_dir_.path().AppendASCII("test.db");
   }
 
-  // Creates database of specific |version|.
-  void CreateDatabase(std::string version) {
+  // Creates the databse from |sql_file|.
+  void CreateDatabase(base::StringPiece sql_file) {
     base::FilePath database_dump;
-    PathService::Get(base::DIR_SOURCE_ROOT, &database_dump);
-    database_dump = database_dump.Append(database_dump_location_)
-                        .AppendASCII("login_db_v" + version + ".sql");
+    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &database_dump));
+    database_dump =
+        database_dump.Append(database_dump_location_).AppendASCII(sql_file);
     ASSERT_TRUE(
         sql::test::CreateDatabaseFromSQL(database_path_, database_dump));
   }
@@ -1152,8 +1154,8 @@
       return results;
 
     sql::Statement s(db.GetCachedStatement(
-        SQL_FROM_HERE,
-        "SELECT date_created from logins order by username_value"));
+        SQL_FROM_HERE, "SELECT date_created FROM logins "
+                       "ORDER BY username_value, date_created DESC"));
     if (!s.is_valid()) {
       db.Close();
       return results;
@@ -1167,6 +1169,12 @@
     return results;
   }
 
+  // Returns the database version for the test.
+  int version() const { return GetParam(); }
+
+  // Actual test body.
+  void MigrationToVCurrent(base::StringPiece sql_file);
+
   base::FilePath database_path_;
 
  private:
@@ -1174,63 +1182,85 @@
   base::ScopedTempDir temp_dir_;
 };
 
-// Tests the migration of the login database from version 1 to version
-// kCurrentVersionNumber. This test will fail when kCurrentVersionNumber
-// will be changed to 10, because file login_db_v10.sql doesn't exist.
-// It has to be added in order to fix test.
-TEST_F(LoginDatabaseMigrationTest, MigrationV1ToVCurrent) {
-  std::vector<std::string> versions;
-  for (int version = 1; version < kCurrentVersionNumber; ++version)
-    versions.push_back(base::IntToString(version));
-  versions.push_back("9_without_use_additional_auth_field");
+void LoginDatabaseMigrationTest::MigrationToVCurrent(
+    base::StringPiece sql_file) {
+  SCOPED_TRACE(testing::Message("Version file = ") << sql_file);
+  CreateDatabase(sql_file);
+  // Original date, in seconds since UTC epoch.
+  std::vector<int64_t> date_created(GetDateCreated());
+  ASSERT_EQ(2U, date_created.size());
+  // Migration to version 8 performs changes dates to the new format.
+  // So for versions less of equal to 8 create date should be in old
+  // format before migration and in new format after.
+  if (version() <= 8) {
+    ASSERT_EQ(1402955745, date_created[0]);
+    ASSERT_EQ(1402950000, date_created[1]);
+  } else {
+    ASSERT_EQ(13047429345000000, date_created[0]);
+    ASSERT_EQ(13047423600000000, date_created[1]);
+  }
 
-  for (const auto& version : versions) {
-    CreateDatabase(version);
-    SCOPED_TRACE(testing::Message("Version = ") << version);
-    // Original date, in seconds since UTC epoch.
-    std::vector<int64_t> date_created(GetDateCreated());
-    int table_version;
-    base::StringToInt(version, &table_version);
-    // Migration to version 8 performs changes dates to the new format.
-    // So for versions less of equal to 8 create date should be in old
-    // format before migration and in new format after.
-    if (table_version <= 8) {
-      ASSERT_EQ(1402955745, date_created[0]);
-      ASSERT_EQ(1402950000, date_created[1]);
-    } else {
-      ASSERT_EQ(13047429345000000, date_created[0]);
-      ASSERT_EQ(13047423600000000, date_created[1]);
-    }
+  {
+    // Assert that the database was successfully opened and updated
+    // to current version.
+    LoginDatabase db(database_path_);
+    ASSERT_TRUE(db.Init());
+    // Verifies that the final version can save all the appropriate fields.
+    PasswordForm form;
+    GenerateExamplePasswordForm(&form);
+    // Add the same form twice to test the constraints in the database.
+    EXPECT_EQ(AddChangeForForm(form), db.AddLogin(form));
+    PasswordStoreChangeList list;
+    list.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
+    list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form));
+    EXPECT_EQ(list, db.AddLogin(form));
 
-    {
-      // Assert that the database was successfully opened and updated
-      // to current version.
-      LoginDatabase db(database_path_);
-      ASSERT_TRUE(db.Init());
-      // Verifies that the final version can save all the appropriate fields.
-      ScopedVector<autofill::PasswordForm> result;
-      PasswordForm form;
-      GenerateExamplePasswordForm(&form);
-      db.AddLogin(form);
-      EXPECT_TRUE(db.GetLogins(form, &result));
-      ASSERT_EQ(1U, result.size());
-      FormsAreEqual(form, *result[0]);
-      EXPECT_TRUE(db.RemoveLogin(form));
-      result.clear();
+    ScopedVector<autofill::PasswordForm> result;
+    EXPECT_TRUE(db.GetLogins(form, &result));
+    ASSERT_EQ(1U, result.size());
+    FormsAreEqual(form, *result[0]);
+    EXPECT_TRUE(db.RemoveLogin(form));
+  }
+  // New date, in microseconds since platform independent epoch.
+  std::vector<int64_t> new_date_created(GetDateCreated());
+  if (version() <= 8) {
+    ASSERT_EQ(2U, new_date_created.size());
+    // Check that the two dates match up.
+    for (size_t i = 0; i < date_created.size(); ++i) {
+      EXPECT_EQ(base::Time::FromInternalValue(new_date_created[i]),
+                base::Time::FromTimeT(date_created[i]));
     }
-    // New date, in microseconds since platform independent epoch.
-    std::vector<int64_t> new_date_created(GetDateCreated());
+  } else if (version() == 10) {
+    // The test data is setup on this version to cause a unique key collision.
+    EXPECT_EQ(1U, new_date_created.size());
+  } else {
+    ASSERT_EQ(2U, new_date_created.size());
     ASSERT_EQ(13047429345000000, new_date_created[0]);
     ASSERT_EQ(13047423600000000, new_date_created[1]);
-    if (table_version <= 8) {
-      // Check that the two dates match up.
-      for (size_t i = 0; i < date_created.size(); ++i) {
-        EXPECT_EQ(base::Time::FromInternalValue(new_date_created[i]),
-                  base::Time::FromTimeT(date_created[i]));
-      }
-    }
-    DestroyDatabase();
   }
+  DestroyDatabase();
 }
 
+// Tests the migration of the login database from version() to
+// kCurrentVersionNumber.
+TEST_P(LoginDatabaseMigrationTest, MigrationToVCurrent) {
+  MigrationToVCurrent(base::StringPrintf("login_db_v%d.sql", version()));
+}
+
+class LoginDatabaseMigrationTestV9 : public LoginDatabaseMigrationTest {
+};
+
+// Tests migration from the alternative version #9, see crbug.com/423716.
+TEST_P(LoginDatabaseMigrationTestV9, V9WithoutUseAdditionalAuthField) {
+  ASSERT_EQ(9, version());
+  MigrationToVCurrent("login_db_v9_without_use_additional_auth_field.sql");
+}
+
+INSTANTIATE_TEST_CASE_P(MigrationToVCurrent,
+                        LoginDatabaseMigrationTest,
+                        testing::Range(1, kCurrentVersionNumber));
+INSTANTIATE_TEST_CASE_P(MigrationToVCurrent,
+                        LoginDatabaseMigrationTestV9,
+                        testing::Values(9));
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 276090a..164db452 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -160,10 +160,15 @@
 
 void PasswordStore::ReportMetrics(const std::string& sync_username,
                                   bool custom_passphrase_sync_enabled) {
-  ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl,
-                          this,
-                          sync_username,
-                          custom_passphrase_sync_enabled));
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner(
+      GetBackgroundTaskRunner());
+  if (task_runner) {
+    base::Closure task =
+        base::Bind(&PasswordStore::ReportMetricsImpl, this, sync_username,
+                   custom_passphrase_sync_enabled);
+    task_runner->PostDelayedTask(FROM_HERE, task,
+                                 base::TimeDelta::FromSeconds(30));
+  }
 }
 
 void PasswordStore::AddObserver(Observer* observer) {
diff --git a/components/password_manager/core/common/password_manager_switches.cc b/components/password_manager/core/common/password_manager_switches.cc
index 3b71d82..f230891 100644
--- a/components/password_manager/core/common/password_manager_switches.cc
+++ b/components/password_manager/core/common/password_manager_switches.cc
@@ -11,6 +11,12 @@
 // Force the password manager to allow sync credentials to be autofilled.
 const char kAllowAutofillSyncCredential[] = "allow-autofill-sync-credential";
 
+// Disable affiliation based matching, so that credentials stored for an Android
+// application will not be considered matches for, and will not be filled into
+// corresponding Web applications.
+const char kDisableAffiliationBasedMatching[] =
+    "disable-affiliation-based-matching";
+
 // Disable dropping the credential used to sync passwords.
 const char kDisableDropSyncCredential[] = "disable-drop-sync-credential";
 
@@ -30,6 +36,12 @@
 const char kDisallowAutofillSyncCredentialForReauth[] =
     "disallow-autofill-sync-credential-for-reauth";
 
+// Enable affiliation based matching, so that credentials stored for an Android
+// application will also be considered matches for, and be filled into
+// corresponding Web applications.
+const char kEnableAffiliationBasedMatching[] =
+    "enable-affiliation-based-matching";
+
 // Disables the save-password prompt. Passwords are then saved automatically,
 // without asking the user.
 const char kEnableAutomaticPasswordSaving[] =
diff --git a/components/password_manager/core/common/password_manager_switches.h b/components/password_manager/core/common/password_manager_switches.h
index abd8628..9b09685 100644
--- a/components/password_manager/core/common/password_manager_switches.h
+++ b/components/password_manager/core/common/password_manager_switches.h
@@ -13,11 +13,13 @@
 // alongside the definition of their values in the .cc file.
 
 extern const char kAllowAutofillSyncCredential[];
+extern const char kDisableAffiliationBasedMatching[];
 extern const char kDisableDropSyncCredential[];
 extern const char kDisableManagerForSyncSignin[];
 extern const char kDisablePasswordLink[];
 extern const char kDisallowAutofillSyncCredential[];
 extern const char kDisallowAutofillSyncCredentialForReauth[];
+extern const char kEnableAffiliationBasedMatching[];
 extern const char kEnableAutomaticPasswordSaving[];
 extern const char kEnableDropSyncCredential[];
 extern const char kEnableManagerForSyncSignin[];
diff --git a/components/policy/core/common/cloud/mock_cloud_policy_client.cc b/components/policy/core/common/cloud/mock_cloud_policy_client.cc
index 9a1b5a4..df3a2c1 100644
--- a/components/policy/core/common/cloud/mock_cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/mock_cloud_policy_client.cc
@@ -35,6 +35,11 @@
   response = new enterprise_management::PolicyFetchResponse(policy);
 }
 
+void MockCloudPolicyClient::SetFetchedInvalidationVersion(
+    int64_t fetched_invalidation_version) {
+  fetched_invalidation_version_ = fetched_invalidation_version;
+}
+
 void MockCloudPolicyClient::SetStatus(DeviceManagementStatus status) {
   status_ = status;
 }
diff --git a/components/policy/core/common/cloud/mock_cloud_policy_client.h b/components/policy/core/common/cloud/mock_cloud_policy_client.h
index 14aaaae..f297221 100644
--- a/components/policy/core/common/cloud/mock_cloud_policy_client.h
+++ b/components/policy/core/common/cloud/mock_cloud_policy_client.h
@@ -43,6 +43,10 @@
                  const std::string& settings_entity_id,
                  const enterprise_management::PolicyFetchResponse& policy);
 
+  // Inject invalidation version.
+  void SetFetchedInvalidationVersion(
+      int64_t fetched_invalidation_version);
+
   // Sets the status field.
   void SetStatus(DeviceManagementStatus status);
 
diff --git a/components/rappor/rappor_service.cc b/components/rappor/rappor_service.cc
index 5b7b7537..7fc4fce 100644
--- a/components/rappor/rappor_service.cc
+++ b/components/rappor/rappor_service.cc
@@ -126,7 +126,8 @@
     }
   }
 
-  DVLOG(1) << "RapporService may_upload=" << may_upload;
+  DVLOG(1) << "RapporService recording_level=" << recording_level_
+           << " may_upload=" << may_upload;
   if (may_upload) {
     uploader_->Start();
   } else {
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index 3103479..b39062b 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -65,6 +65,7 @@
                             NULL),
       registered_with_token_service_(false),
       registered_with_merge_session_helper_(false),
+      registered_with_content_settings_(false),
       is_reconcile_started_(false),
       first_execution_(true),
       are_gaia_accounts_set_(false),
@@ -144,11 +145,24 @@
 }
 
 void AccountReconcilor::RegisterWithContentSettings() {
+  VLOG(1) << "AccountReconcilor::RegisterWithContentSettings";
+  // During re-auth, the reconcilor will get a callback about successful signin
+  // even when the profile is already connected.  Avoid re-registering
+  // with the token service since this will DCHECK.
+  if (registered_with_content_settings_)
+    return;
+
   client_->AddContentSettingsObserver(this);
+  registered_with_content_settings_ = true;
 }
 
 void AccountReconcilor::UnregisterWithContentSettings() {
+  VLOG(1) << "AccountReconcilor::UnregisterWithContentSettings";
+  if (!registered_with_content_settings_)
+    return;
+
   client_->RemoveContentSettingsObserver(this);
+  registered_with_content_settings_ = false;
 }
 
 void AccountReconcilor::RegisterWithTokenService() {
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 1b903aa1..1d7adcf 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -193,6 +193,7 @@
   scoped_ptr<GaiaAuthFetcher> gaia_fetcher_;
   bool registered_with_token_service_;
   bool registered_with_merge_session_helper_;
+  bool registered_with_content_settings_;
 
   // True while the reconcilor is busy checking or managing the accounts in
   // this profile.
diff --git a/components/test/data/data_reduction_proxy/OWNERS b/components/test/data/data_reduction_proxy/OWNERS
index f74e102..a33576ac 100644
--- a/components/test/data/data_reduction_proxy/OWNERS
+++ b/components/test/data/data_reduction_proxy/OWNERS
@@ -1,3 +1,4 @@
 bengr@chromium.org
 marq@chromium.org
 bolian@chromium.org
+sclittle@chromium.org
diff --git a/components/test/data/password_manager/login_db_v10.sql b/components/test/data/password_manager/login_db_v10.sql
new file mode 100644
index 0000000..33e464c3
--- /dev/null
+++ b/components/test/data/password_manager/login_db_v10.sql
@@ -0,0 +1,79 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+INSERT INTO "meta" VALUES('last_compatible_version','1');
+INSERT INTO "meta" VALUES('version','9');
+CREATE TABLE logins (
+origin_url VARCHAR NOT NULL,
+action_url VARCHAR,
+username_element VARCHAR,
+username_value VARCHAR,
+password_element VARCHAR,
+password_value BLOB,
+submit_element VARCHAR,
+signon_realm VARCHAR NOT NULL,
+ssl_valid INTEGER NOT NULL,
+preferred INTEGER NOT NULL,
+date_created INTEGER NOT NULL,
+blacklisted_by_user INTEGER NOT NULL,
+scheme INTEGER NOT NULL,
+password_type INTEGER,
+possible_usernames BLOB,
+times_used INTEGER,
+form_data BLOB,
+date_synced INTEGER,
+display_name VARCHAR,
+avatar_url VARCHAR,
+federation_url VARCHAR,
+is_zero_click INTEGER,
+UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
+INSERT INTO "logins" VALUES(
+'https://accounts.google.com/ServiceLogin', /* origin_url */
+'https://accounts.google.com/ServiceLoginAuth', /* action_url */
+'Email', /* username_element */
+'theerikchen', /* username_value */
+'Passwd', /* password_element */
+X'', /* password_value */
+'', /* submit_element */
+'https://accounts.google.com/', /* signon_realm */
+1, /* ssl_valid */
+1, /* preferred */
+13047429345000000, /* date_created */
+0, /* blacklisted_by_user */
+0, /* scheme */
+0, /* password_type */
+X'00000000', /* possible_usernames */
+1, /* times_used */
+X'18000000020000000000000000000000000000000000000000000000', /* form_data */
+0, /* date_synced */
+'', /* display_name */
+'', /* avatar_url */
+'', /* federation_url */
+0  /* is_zero_click */
+);
+INSERT INTO "logins" VALUES(
+'https://accounts.google.com/ServiceLogin', /* origin_url */
+'https://accounts.google.com/ServiceLoginAuth', /* action_url */
+'Email', /* username_element */
+'theerikchen', /* username_value */
+'Passwd', /* password_element */
+X'', /* password_value */
+'non-empty', /* submit_element */
+'https://accounts.google.com/', /* signon_realm */
+1, /* ssl_valid */
+1, /* preferred */
+13047423600000000, /* date_created */
+0, /* blacklisted_by_user */
+0, /* scheme */
+0, /* password_type */
+X'00000000', /* possible_usernames */
+1, /* times_used */
+X'18000000020000000000000000000000000000000000000000000000', /* form_data */
+0, /* date_synced */
+'', /* display_name */
+'', /* avatar_url */
+'', /* federation_url */
+0  /* is_zero_click */
+);
+CREATE INDEX logins_signon ON logins (signon_realm);
+COMMIT;
diff --git a/components/ui/zoom/BUILD.gn b/components/ui/zoom/BUILD.gn
index a3958b8..8774b0d 100644
--- a/components/ui/zoom/BUILD.gn
+++ b/components/ui/zoom/BUILD.gn
@@ -12,6 +12,7 @@
     "zoom_controller.h",
     "zoom_event_manager.cc",
     "zoom_event_manager.h",
+    "zoom_event_manager_observer.h",
     "zoom_observer.h",
   ]
 
diff --git a/components/ui/zoom/zoom_event_manager.cc b/components/ui/zoom/zoom_event_manager.cc
index 72906271..f841123 100644
--- a/components/ui/zoom/zoom_event_manager.cc
+++ b/components/ui/zoom/zoom_event_manager.cc
@@ -4,6 +4,7 @@
 
 #include "components/ui/zoom/zoom_event_manager.h"
 
+#include "components/ui/zoom/zoom_event_manager_observer.h"
 #include "content/public/browser/browser_context.h"
 
 namespace {
@@ -37,4 +38,19 @@
   return zoom_level_changed_callbacks_.Add(callback);
 }
 
+void ZoomEventManager::OnDefaultZoomLevelChanged() {
+  FOR_EACH_OBSERVER(ZoomEventManagerObserver, observers_,
+                    OnDefaultZoomLevelChanged());
+}
+
+void ZoomEventManager::AddZoomEventManagerObserver(
+    ZoomEventManagerObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ZoomEventManager::RemoveZoomEventManagerObserver(
+    ZoomEventManagerObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 }  // namespace ui_zoom
diff --git a/components/ui/zoom/zoom_event_manager.h b/components/ui/zoom/zoom_event_manager.h
index 3f0fcf0..72d335d 100644
--- a/components/ui/zoom/zoom_event_manager.h
+++ b/components/ui/zoom/zoom_event_manager.h
@@ -7,6 +7,7 @@
 
 #include "base/callback_list.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "base/supports_user_data.h"
 #include "content/public/browser/host_zoom_map.h"
 
@@ -16,6 +17,8 @@
 
 namespace ui_zoom {
 
+class ZoomEventManagerObserver;
+
 // This class serves as a target for event notifications from all ZoomController
 // objects. Classes that need to know about browser-specific zoom events (e.g.
 // manual-mode zoom) should subscribe here.
@@ -34,9 +37,19 @@
   void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change);
 
   // Add and remove zoom level changed callbacks.
+  // TODO(wjmaclean): Convert this callback mechanism to use
+  // ZoomEventManagerObserver instead.
   scoped_ptr<content::HostZoomMap::Subscription> AddZoomLevelChangedCallback(
       const content::HostZoomMap::ZoomLevelChangedCallback& callback);
 
+  // Called by ZoomLevelDelegates when changes are made to the default zoom
+  // level for their associated HostZoomMap.
+  void OnDefaultZoomLevelChanged();
+
+  // Add and remove observers.
+  void AddZoomEventManagerObserver(ZoomEventManagerObserver* observer);
+  void RemoveZoomEventManagerObserver(ZoomEventManagerObserver* observer);
+
   // Get a weak ptr to be used by clients who may themselves be UserData for
   // the context, since the order of destruction is undefined between the client
   // and this class.
@@ -47,6 +60,7 @@
  private:
   base::CallbackList<void(const content::HostZoomMap::ZoomLevelChange&)>
       zoom_level_changed_callbacks_;
+  ObserverList<ZoomEventManagerObserver> observers_;
   base::WeakPtrFactory<ZoomEventManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ZoomEventManager);
diff --git a/components/ui/zoom/zoom_event_manager_observer.h b/components/ui/zoom/zoom_event_manager_observer.h
new file mode 100644
index 0000000..f3afedc
--- /dev/null
+++ b/components/ui/zoom/zoom_event_manager_observer.h
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_UI_ZOOM_ZOOM_EVENT_MANAGER_OBSERVER_H_
+#define COMPONENTS_UI_ZOOM_ZOOM_EVENT_MANAGER_OBSERVER_H_
+
+namespace ui_zoom {
+
+class ZoomEventManagerObserver {
+ public:
+  // TODO(wjmaclean): convert existing ZoomLevelChangedCallbacks to be
+  // observers.
+  virtual void OnZoomLevelChanged() {}
+  virtual void OnDefaultZoomLevelChanged() {}
+
+ protected:
+  virtual ~ZoomEventManagerObserver() {}
+};
+
+}  // namespace ui_zoom
+
+#endif  // COMPONENTS_UI_ZOOM_ZOOM_EVENT_MANAGER_OBSERVER_H_
diff --git a/components/ui_zoom.gypi b/components/ui_zoom.gypi
index fc3ed76..15e988d 100644
--- a/components/ui_zoom.gypi
+++ b/components/ui_zoom.gypi
@@ -27,6 +27,7 @@
         'ui/zoom/zoom_controller.h',
         'ui/zoom/zoom_event_manager.cc',
         'ui/zoom/zoom_event_manager.h',
+        'ui/zoom/zoom_event_manager_observer.h',
         'ui/zoom/zoom_observer.h'
       ],
     }
diff --git a/components/user_manager.gypi b/components/user_manager.gypi
index 03aba1e..dac32c3b 100644
--- a/components/user_manager.gypi
+++ b/components/user_manager.gypi
@@ -62,5 +62,25 @@
         'sources': [ '<@(user_manager_chromeos_sources)' ],
       }],
     ],
-  }],
+  },
+  {
+    # GN version: //components/user_manager:test_support
+    'target_name': 'user_manager_test_support',
+    'type': 'static_library',
+    'conditions': [
+      ['chromeos == 1', {
+        'dependencies': [
+          '<(DEPTH)/base/base.gyp:base',
+          '<(DEPTH)/base/base.gyp:test_support_base',
+          '<(DEPTH)/testing/gmock.gyp:gmock',
+          '<(DEPTH)/testing/gtest.gyp:gtest',
+          'user_manager',
+        ],
+        'sources': [
+          'user_manager/fake_user_manager.cc',
+          'user_manager/fake_user_manager.h',
+        ],
+      }],
+     ]
+  },],
 }
diff --git a/components/user_manager/BUILD.gn b/components/user_manager/BUILD.gn
index 0150e27..b0755a6 100644
--- a/components/user_manager/BUILD.gn
+++ b/components/user_manager/BUILD.gn
@@ -47,3 +47,18 @@
     ]
   }
 }
+
+source_set("test_support") {
+  testonly = true
+  if (is_chromeos) {
+    sources = [
+      "fake_user_manager.cc",
+      "fake_user_manager.h",
+    ]
+    deps = [
+      ":user_manager",
+      "//base",
+      "//skia",
+    ]
+  }
+}
diff --git a/components/user_manager/fake_user_manager.cc b/components/user_manager/fake_user_manager.cc
new file mode 100644
index 0000000..5e8d561
--- /dev/null
+++ b/components/user_manager/fake_user_manager.cc
@@ -0,0 +1,273 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/user_manager/fake_user_manager.h"
+
+#include "base/callback.h"
+#include "base/task_runner.h"
+#include "components/user_manager/user_type.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+class FakeTaskRunner : public base::TaskRunner {
+ public:
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override {
+    task.Run();
+    return true;
+  }
+  bool RunsTasksOnCurrentThread() const override { return true; }
+
+ protected:
+  ~FakeTaskRunner() override {}
+};
+
+}  // namespace
+
+namespace user_manager {
+
+FakeUserManager::FakeUserManager()
+    : UserManagerBase(new FakeTaskRunner(), new FakeTaskRunner()),
+      primary_user_(NULL),
+      owner_email_(std::string()) {
+}
+
+FakeUserManager::~FakeUserManager() {
+}
+
+const user_manager::User* FakeUserManager::AddUser(const std::string& email) {
+  user_manager::User* user = user_manager::User::CreateRegularUser(email);
+  users_.push_back(user);
+  return user;
+}
+
+void FakeUserManager::RemoveUserFromList(const std::string& email) {
+  user_manager::UserList::iterator it = users_.begin();
+  while (it != users_.end() && (*it)->email() != email)
+    ++it;
+  if (it != users_.end()) {
+    delete *it;
+    users_.erase(it);
+  }
+}
+
+const user_manager::UserList& FakeUserManager::GetUsers() const {
+  return users_;
+}
+
+user_manager::UserList FakeUserManager::GetUsersAllowedForMultiProfile() const {
+  user_manager::UserList result;
+  for (user_manager::UserList::const_iterator it = users_.begin();
+       it != users_.end(); ++it) {
+    if ((*it)->GetType() == user_manager::USER_TYPE_REGULAR &&
+        !(*it)->is_logged_in())
+      result.push_back(*it);
+  }
+  return result;
+}
+
+const user_manager::UserList& FakeUserManager::GetLoggedInUsers() const {
+  return logged_in_users_;
+}
+
+void FakeUserManager::UserLoggedIn(const std::string& email,
+                                   const std::string& username_hash,
+                                   bool browser_restart) {
+  for (user_manager::UserList::const_iterator it = users_.begin();
+       it != users_.end(); ++it) {
+    if ((*it)->username_hash() == username_hash) {
+      (*it)->set_is_logged_in(true);
+      (*it)->set_profile_is_created();
+      logged_in_users_.push_back(*it);
+
+      if (!primary_user_)
+        primary_user_ = *it;
+      break;
+    }
+  }
+}
+
+user_manager::User* FakeUserManager::GetActiveUserInternal() const {
+  if (users_.size()) {
+    if (!active_user_id_.empty()) {
+      for (user_manager::UserList::const_iterator it = users_.begin();
+           it != users_.end(); ++it) {
+        if ((*it)->email() == active_user_id_)
+          return *it;
+      }
+    }
+    return users_[0];
+  }
+  return NULL;
+}
+
+const user_manager::User* FakeUserManager::GetActiveUser() const {
+  return GetActiveUserInternal();
+}
+
+user_manager::User* FakeUserManager::GetActiveUser() {
+  return GetActiveUserInternal();
+}
+
+void FakeUserManager::SwitchActiveUser(const std::string& email) {
+}
+
+void FakeUserManager::SaveUserDisplayName(const std::string& username,
+                                          const base::string16& display_name) {
+  for (user_manager::UserList::iterator it = users_.begin(); it != users_.end();
+       ++it) {
+    if ((*it)->email() == username) {
+      (*it)->set_display_name(display_name);
+      return;
+    }
+  }
+}
+
+const user_manager::UserList& FakeUserManager::GetLRULoggedInUsers() const {
+  return users_;
+}
+
+user_manager::UserList FakeUserManager::GetUnlockUsers() const {
+  return users_;
+}
+
+const std::string& FakeUserManager::GetOwnerEmail() const {
+  return owner_email_;
+}
+
+bool FakeUserManager::IsKnownUser(const std::string& email) const {
+  return true;
+}
+
+const user_manager::User* FakeUserManager::FindUser(
+    const std::string& email) const {
+  const user_manager::UserList& users = GetUsers();
+  for (user_manager::UserList::const_iterator it = users.begin();
+       it != users.end(); ++it) {
+    if ((*it)->email() == email)
+      return *it;
+  }
+  return NULL;
+}
+
+user_manager::User* FakeUserManager::FindUserAndModify(
+    const std::string& email) {
+  return NULL;
+}
+
+const user_manager::User* FakeUserManager::GetLoggedInUser() const {
+  return NULL;
+}
+
+user_manager::User* FakeUserManager::GetLoggedInUser() {
+  return NULL;
+}
+
+const user_manager::User* FakeUserManager::GetPrimaryUser() const {
+  return primary_user_;
+}
+
+base::string16 FakeUserManager::GetUserDisplayName(
+    const std::string& username) const {
+  return base::string16();
+}
+
+std::string FakeUserManager::GetUserDisplayEmail(
+    const std::string& username) const {
+  return std::string();
+}
+
+bool FakeUserManager::IsCurrentUserOwner() const {
+  return false;
+}
+
+bool FakeUserManager::IsCurrentUserNew() const {
+  return false;
+}
+
+bool FakeUserManager::IsCurrentUserNonCryptohomeDataEphemeral() const {
+  return false;
+}
+
+bool FakeUserManager::CanCurrentUserLock() const {
+  return false;
+}
+
+bool FakeUserManager::IsUserLoggedIn() const {
+  return logged_in_users_.size() > 0;
+}
+
+bool FakeUserManager::IsLoggedInAsUserWithGaiaAccount() const {
+  return true;
+}
+
+bool FakeUserManager::IsLoggedInAsPublicAccount() const {
+  return false;
+}
+
+bool FakeUserManager::IsLoggedInAsGuest() const {
+  return false;
+}
+
+bool FakeUserManager::IsLoggedInAsSupervisedUser() const {
+  return false;
+}
+
+bool FakeUserManager::IsLoggedInAsKioskApp() const {
+  const user_manager::User* active_user = GetActiveUser();
+  return active_user
+             ? active_user->GetType() == user_manager::USER_TYPE_KIOSK_APP
+             : false;
+}
+
+bool FakeUserManager::IsLoggedInAsStub() const {
+  return false;
+}
+
+bool FakeUserManager::IsSessionStarted() const {
+  return false;
+}
+
+bool FakeUserManager::IsUserNonCryptohomeDataEphemeral(
+    const std::string& email) const {
+  return false;
+}
+
+bool FakeUserManager::AreSupervisedUsersAllowed() const {
+  return true;
+}
+
+bool FakeUserManager::AreEphemeralUsersEnabled() const {
+  return false;
+}
+
+const std::string& FakeUserManager::GetApplicationLocale() const {
+  static const std::string default_locale("en-US");
+  return default_locale;
+}
+
+PrefService* FakeUserManager::GetLocalState() const {
+  return NULL;
+}
+
+bool FakeUserManager::IsEnterpriseManaged() const {
+  return false;
+}
+
+bool FakeUserManager::IsDemoApp(const std::string& user_id) const {
+  return false;
+}
+
+bool FakeUserManager::IsKioskApp(const std::string& user_id) const {
+  return false;
+}
+
+bool FakeUserManager::IsPublicAccountMarkedForRemoval(
+    const std::string& user_id) const {
+  return false;
+}
+
+}  // namespace user_manager
diff --git a/chrome/browser/chromeos/login/users/fake_user_manager.h b/components/user_manager/fake_user_manager.h
similarity index 74%
rename from chrome/browser/chromeos/login/users/fake_user_manager.h
rename to components/user_manager/fake_user_manager.h
index c8397d4..c71df24e 100644
--- a/chrome/browser/chromeos/login/users/fake_user_manager.h
+++ b/components/user_manager/fake_user_manager.h
@@ -2,55 +2,34 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USERS_FAKE_USER_MANAGER_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_USERS_FAKE_USER_MANAGER_H_
+#ifndef COMPONENTS_USER_MANAGER_FAKE_USER_MANAGER_H_
+#define COMPONENTS_USER_MANAGER_FAKE_USER_MANAGER_H_
 
 #include <map>
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/chromeos/login/user_flow.h"
-#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "components/user_manager/user.h"
-#include "components/user_manager/user_image/user_image.h"
+#include "components/user_manager/user_manager_base.h"
 
-namespace chromeos {
-
-class FakeSupervisedUserManager;
+namespace user_manager {
 
 // Fake user manager with a barebones implementation. Users can be added
 // and set as logged in, and those users can be returned.
-class FakeUserManager : public ChromeUserManager {
+class USER_MANAGER_EXPORT FakeUserManager : public UserManagerBase {
  public:
   FakeUserManager();
   ~FakeUserManager() override;
 
   // Create and add a new user.
-  const user_manager::User* AddUser(const std::string& email);
-
-  // Create and add a kiosk app user.
-  void AddKioskAppUser(const std::string& kiosk_app_username);
-
-  // Create and add a public account user.
-  const user_manager::User* AddPublicAccountUser(const std::string& email);
+  virtual const user_manager::User* AddUser(const std::string& email);
 
   // Calculates the user name hash and calls UserLoggedIn to login a user.
   void LoginUser(const std::string& email);
 
-  // ChromeUserManager overrides.
-  MultiProfileUserController* GetMultiProfileUserController() override;
-  UserImageManager* GetUserImageManager(const std::string& user_id) override;
-  SupervisedUserManager* GetSupervisedUserManager() override;
-  void SetUserFlow(const std::string& email, UserFlow* flow) override {}
-  UserFlow* GetCurrentUserFlow() const override;
-  UserFlow* GetUserFlow(const std::string& email) const override;
-  void ResetUserFlow(const std::string& email) override {}
-
   // UserManager overrides.
   const user_manager::UserList& GetUsers() const override;
   user_manager::UserList GetUsersAllowedForMultiProfile() const override;
-  user_manager::UserList GetUsersAllowedForSupervisedUsersCreation()
-      const override;
   const user_manager::UserList& GetLoggedInUsers() const override;
 
   // Set the user as logged in.
@@ -133,33 +112,23 @@
   void PublicAccountUserLoggedIn(user_manager::User* user) override {}
   void SupervisedUserLoggedIn(const std::string& user_id) override {}
 
-  void set_owner_email(const std::string& owner_email) {
-    owner_email_ = owner_email;
-  }
-
-  void set_multi_profile_user_controller(
-      MultiProfileUserController* controller) {
-    multi_profile_user_controller_ = controller;
-  }
-
- private:
-  // We use this internal function for const-correctness.
-  user_manager::User* GetActiveUserInternal() const;
-
-  scoped_ptr<FakeSupervisedUserManager> supervised_user_manager_;
-  user_manager::UserList user_list_;
-  user_manager::UserList logged_in_users_;
-  std::string owner_email_;
+ protected:
   user_manager::User* primary_user_;
 
   // If set this is the active user. If empty, the first created user is the
   // active user.
   std::string active_user_id_;
-  MultiProfileUserController* multi_profile_user_controller_;
+
+ private:
+  // We use this internal function for const-correctness.
+  user_manager::User* GetActiveUserInternal() const;
+
+  // stub, always empty string.
+  std::string owner_email_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeUserManager);
 };
 
-}  // namespace chromeos
+}  // namespace user_manager
 
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_USERS_FAKE_USER_MANAGER_H_
+#endif  // COMPONENTS_USER_MANAGER_FAKE_USER_MANAGER_H_
diff --git a/components/user_manager/user.h b/components/user_manager/user.h
index e5a45f3..684a0035 100644
--- a/components/user_manager/user.h
+++ b/components/user_manager/user.h
@@ -20,7 +20,7 @@
 namespace chromeos {
 class ChromeUserManagerImpl;
 class FakeLoginUtils;
-class FakeUserManager;
+class FakeChromeUserManager;
 class MockUserManager;
 class SupervisedUserManagerImpl;
 class UserAddingScreenTest;
@@ -31,6 +31,7 @@
 namespace user_manager {
 
 class UserManagerBase;
+class FakeUserManager;
 
 // A class representing information about a previously logged in user.
 // Each user has a canonical email (username), returned by |email()| and
@@ -169,9 +170,10 @@
   friend class chromeos::UserSessionManager;
 
   // For testing:
+  friend class FakeUserManager;
+  friend class chromeos::FakeChromeUserManager;
   friend class chromeos::MockUserManager;
   friend class chromeos::FakeLoginUtils;
-  friend class chromeos::FakeUserManager;
   friend class chromeos::UserAddingScreenTest;
 
   // Do not allow anyone else to create new User instances.
diff --git a/components/user_manager/user_manager.h b/components/user_manager/user_manager.h
index 4253992..1ac1a7f 100644
--- a/components/user_manager/user_manager.h
+++ b/components/user_manager/user_manager.h
@@ -117,11 +117,6 @@
   // has a policy that prohibits it to be part of multi-profile session.
   virtual UserList GetUsersAllowedForMultiProfile() const = 0;
 
-  // Returns list of users allowed for supervised user creation.
-  // Returns an empty list in cases when supervised user creation or adding new
-  // users is restricted.
-  virtual UserList GetUsersAllowedForSupervisedUsersCreation() const = 0;
-
   // Returns a list of users who are currently logged in.
   virtual const UserList& GetLoggedInUsers() const = 0;
 
diff --git a/components/user_manager/user_manager_base.h b/components/user_manager/user_manager_base.h
index ba7cd793..9dc1c9ab 100644
--- a/components/user_manager/user_manager_base.h
+++ b/components/user_manager/user_manager_base.h
@@ -136,7 +136,7 @@
 
   // Loads |users_| from Local State if the list has not been loaded yet.
   // Subsequent calls have no effect. Must be called on the UI thread.
-  void EnsureUsersLoaded();
+  virtual void EnsureUsersLoaded();
 
   // Handle OAuth token |status| change for |user_id|.
   virtual void HandleUserOAuthTokenStatusChange(
@@ -260,6 +260,15 @@
   // |UpdateAndCleanUpPublicAccounts|.
   UserList users_;
 
+  // List of all users that are logged in current session. These point to User
+  // instances in |users_|. Only one of them could be marked as active.
+  UserList logged_in_users_;
+
+  // A list of all users that are logged in the current session. In contrast to
+  // |logged_in_users|, the order of this list is least recently used so that
+  // the active user should always be the first one in the list.
+  UserList lru_logged_in_users_;
+
  private:
   // Stages of loading user list from preferences. Some methods can have
   // different behavior depending on stage.
@@ -316,15 +325,6 @@
   // Indicates stage of loading user from prefs.
   UserLoadStage user_loading_stage_;
 
-  // List of all users that are logged in current session. These point to User
-  // instances in |users_|. Only one of them could be marked as active.
-  UserList logged_in_users_;
-
-  // A list of all users that are logged in the current session. In contrast to
-  // |logged_in_users|, the order of this list is least recently used so that
-  // the active user should always be the first one in the list.
-  UserList lru_logged_in_users_;
-
   // True if SessionStarted() has been called.
   bool session_started_;
 
diff --git a/components/web_resource/web_resource_service.cc b/components/web_resource/web_resource_service.cc
index 6e9c589f..40225b8c 100644
--- a/components/web_resource/web_resource_service.cc
+++ b/components/web_resource/web_resource_service.cc
@@ -107,9 +107,9 @@
 
   GURL web_resource_server =
       application_locale_.empty()
-          ? google_util::AppendGoogleLocaleParam(web_resource_server_,
-                                                 application_locale_)
-          : web_resource_server_;
+          ? web_resource_server_
+          : google_util::AppendGoogleLocaleParam(web_resource_server_,
+                                                 application_locale_);
 
   DVLOG(1) << "WebResourceService StartFetch " << web_resource_server;
   url_fetcher_.reset(
diff --git a/content/app/android/child_process_service.cc b/content/app/android/child_process_service.cc
index 9d46e080..93c622ef 100644
--- a/content/app/android/child_process_service.cc
+++ b/content/app/android/child_process_service.cc
@@ -12,7 +12,7 @@
 #include "base/android/memory_pressure_listener_android.h"
 #include "base/logging.h"
 #include "base/posix/global_descriptors.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/android/surface_texture_manager.h"
 #include "content/common/android/surface_texture_peer.h"
 #include "content/common/gpu/gpu_surface_lookup.h"
@@ -188,7 +188,7 @@
 }
 
 void ShutdownMainThread(JNIEnv* env, jobject obj) {
-  ChildThread::ShutdownThread();
+  ChildThreadImpl::ShutdownThread();
 }
 
 }  // namespace content
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 3e794f8..8bebd15d 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -350,6 +350,7 @@
   }
 
   if (is_chromeos) {
+    sources -= [ "device_sensors/data_fetcher_shared_memory_default.cc" ]
     deps += [
       "//chromeos",
       "//chromeos:power_manager_proto",
diff --git a/content/browser/accessibility/android_granularity_movement_browsertest.cc b/content/browser/accessibility/android_granularity_movement_browsertest.cc
index 975da4c..b24fa757 100644
--- a/content/browser/accessibility/android_granularity_movement_browsertest.cc
+++ b/content/browser/accessibility/android_granularity_movement_browsertest.cc
@@ -33,7 +33,7 @@
 class AndroidGranularityMovementBrowserTest : public ContentBrowserTest {
  public:
   AndroidGranularityMovementBrowserTest() {}
-  virtual ~AndroidGranularityMovementBrowserTest() {}
+  ~AndroidGranularityMovementBrowserTest() override {}
 
   BrowserAccessibility* LoadUrlAndGetAccessibilityRoot(const GURL& url) {
     NavigateToURL(shell(), GURL(url::kAboutBlankURL));
diff --git a/content/browser/accessibility/android_hit_testing_browsertest.cc b/content/browser/accessibility/android_hit_testing_browsertest.cc
index f483286..12817d1 100644
--- a/content/browser/accessibility/android_hit_testing_browsertest.cc
+++ b/content/browser/accessibility/android_hit_testing_browsertest.cc
@@ -32,7 +32,7 @@
 class AndroidHitTestingBrowserTest : public ContentBrowserTest {
  public:
   AndroidHitTestingBrowserTest() {}
-  virtual ~AndroidHitTestingBrowserTest() {}
+  ~AndroidHitTestingBrowserTest() override {}
 };
 
 IN_PROC_BROWSER_TEST_F(AndroidHitTestingBrowserTest,
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 65d805b..13402f5 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -186,43 +186,7 @@
 
 gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const {
   gfx::Rect bounds = GetLocation();
-
-  // Walk up the parent chain. Every time we encounter a Web Area, offset
-  // based on the scroll bars and then offset based on the origin of that
-  // nested web area.
-  BrowserAccessibility* parent = GetParentForBoundsCalculation();
-  bool need_to_offset_web_area =
-      (GetRole() == ui::AX_ROLE_WEB_AREA ||
-       GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
-  while (parent) {
-    if (need_to_offset_web_area &&
-        parent->GetLocation().width() > 0 &&
-        parent->GetLocation().height() > 0) {
-      bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
-      need_to_offset_web_area = false;
-    }
-
-    // On some platforms, we don't want to take the root scroll offsets
-    // into account.
-    if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
-        !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
-      break;
-    }
-
-    if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
-        parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
-      int sx = 0;
-      int sy = 0;
-      if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
-          parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
-        bounds.Offset(-sx, -sy);
-      }
-      need_to_offset_web_area = true;
-    }
-    parent = parent->GetParentForBoundsCalculation();
-  }
-
-  return bounds;
+  return ElementBoundsToLocalBounds(bounds);
 }
 
 gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const {
@@ -252,7 +216,7 @@
       }
       start -= child_len;
     }
-    return bounds;
+    return ElementBoundsToLocalBounds(bounds);
   }
 
   int end = start + len;
@@ -329,7 +293,7 @@
       bounds.Union(child_overlap_rect);
   }
 
-  return bounds;
+  return ElementBoundsToLocalBounds(bounds);
 }
 
 gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len)
@@ -711,4 +675,44 @@
   return manager_->delegate()->AccessibilityGetParentFrame();
 }
 
+gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds)
+    const {
+  // Walk up the parent chain. Every time we encounter a Web Area, offset
+  // based on the scroll bars and then offset based on the origin of that
+  // nested web area.
+  BrowserAccessibility* parent = GetParentForBoundsCalculation();
+  bool need_to_offset_web_area =
+      (GetRole() == ui::AX_ROLE_WEB_AREA ||
+       GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
+  while (parent) {
+    if (need_to_offset_web_area &&
+        parent->GetLocation().width() > 0 &&
+        parent->GetLocation().height() > 0) {
+      bounds.Offset(parent->GetLocation().x(), parent->GetLocation().y());
+      need_to_offset_web_area = false;
+    }
+
+    // On some platforms, we don't want to take the root scroll offsets
+    // into account.
+    if (parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA &&
+        !manager()->UseRootScrollOffsetsWhenComputingBounds()) {
+      break;
+    }
+
+    if (parent->GetRole() == ui::AX_ROLE_WEB_AREA ||
+        parent->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
+      int sx = 0;
+      int sy = 0;
+      if (parent->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) &&
+          parent->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) {
+        bounds.Offset(-sx, -sy);
+      }
+      need_to_offset_web_area = true;
+    }
+    parent = parent->GetParentForBoundsCalculation();
+  }
+
+  return bounds;
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 47f19b7c..844d3cc2 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -267,6 +267,11 @@
   // bounds offsets.
   BrowserAccessibility* GetParentForBoundsCalculation() const;
 
+  // Convert the bounding rectangle of an element (which is relative to
+  // its nearest scrollable ancestor) to local bounds (which are relative
+  // to the top of the web accessibility tree).
+  gfx::Rect ElementBoundsToLocalBounds(gfx::Rect bounds) const;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibility);
 };
 
diff --git a/content/browser/accessibility/browser_accessibility_android.h b/content/browser/accessibility/browser_accessibility_android.h
index 70579ab..8ab81a3 100644
--- a/content/browser/accessibility/browser_accessibility_android.h
+++ b/content/browser/accessibility/browser_accessibility_android.h
@@ -13,11 +13,11 @@
 class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
  public:
   // Overrides from BrowserAccessibility.
-  virtual void OnDataChanged() override;
-  virtual bool IsNative() const override;
-  virtual void OnLocationChanged() override;
+  void OnDataChanged() override;
+  bool IsNative() const override;
+  void OnLocationChanged() override;
 
-  virtual bool PlatformIsLeaf() const override;
+  bool PlatformIsLeaf() const override;
 
   bool CanScrollForward() const;
   bool CanScrollBackward() const;
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.h b/content/browser/accessibility/browser_accessibility_manager_android.h
index 3d96d5d4..6ab9ae8 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.h
+++ b/content/browser/accessibility/browser_accessibility_manager_android.h
@@ -41,7 +41,7 @@
       BrowserAccessibilityDelegate* delegate,
       BrowserAccessibilityFactory* factory = new BrowserAccessibilityFactory());
 
-  virtual ~BrowserAccessibilityManagerAndroid();
+  ~BrowserAccessibilityManagerAndroid() override;
 
   static ui::AXTreeUpdate GetEmptyDocument();
 
@@ -49,8 +49,8 @@
       base::android::ScopedJavaLocalRef<jobject> content_view_core);
 
   // Implementation of BrowserAccessibilityManager.
-  virtual void NotifyAccessibilityEvent(
-      ui::AXEvent event_type, BrowserAccessibility* node) override;
+  void NotifyAccessibilityEvent(ui::AXEvent event_type,
+                                BrowserAccessibility* node) override;
 
   // --------------------------------------------------------------------------
   // Methods called from Java via JNI
@@ -127,7 +127,7 @@
       bool root_changed,
       const std::vector<ui::AXTreeDelegate::Change>& changes) override;
 
-  virtual bool UseRootScrollOffsetsWhenComputingBounds() override;
+  bool UseRootScrollOffsetsWhenComputingBounds() override;
 
  private:
   // This gives BrowserAccessibilityManager::Create access to the class
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index d0ca4bb..1b831615 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -798,6 +798,54 @@
             static_text_accessible->GetLocalBoundsForRange(2, 2).ToString());
 }
 
+TEST(BrowserAccessibilityManagerTest, BoundsForRangeScrolledWindow) {
+  ui::AXNodeData root;
+  root.id = 1;
+  root.role = ui::AX_ROLE_ROOT_WEB_AREA;
+  root.AddIntAttribute(ui::AX_ATTR_SCROLL_X, 25);
+  root.AddIntAttribute(ui::AX_ATTR_SCROLL_Y, 50);
+
+  ui::AXNodeData static_text;
+  static_text.id = 2;
+  static_text.SetValue("ABC");
+  static_text.role = ui::AX_ROLE_STATIC_TEXT;
+  static_text.location = gfx::Rect(100, 100, 16, 9);
+  root.child_ids.push_back(2);
+
+  ui::AXNodeData inline_text;
+  inline_text.id = 3;
+  inline_text.SetValue("ABC");
+  inline_text.role = ui::AX_ROLE_INLINE_TEXT_BOX;
+  inline_text.location = gfx::Rect(100, 100, 16, 9);
+  inline_text.AddIntAttribute(ui::AX_ATTR_TEXT_DIRECTION,
+                              ui::AX_TEXT_DIRECTION_LR);
+  std::vector<int32> character_offsets1;
+  character_offsets1.push_back(6);   // 0
+  character_offsets1.push_back(11);  // 1
+  character_offsets1.push_back(16);  // 2
+  inline_text.AddIntListAttribute(
+      ui::AX_ATTR_CHARACTER_OFFSETS, character_offsets1);
+  static_text.child_ids.push_back(3);
+
+  scoped_ptr<BrowserAccessibilityManager> manager(
+      BrowserAccessibilityManager::Create(
+          MakeAXTreeUpdate(root, static_text, inline_text),
+          NULL,
+          new CountedBrowserAccessibilityFactory()));
+
+  BrowserAccessibility* root_accessible = manager->GetRoot();
+  BrowserAccessibility* static_text_accessible =
+      root_accessible->PlatformGetChild(0);
+
+  if (manager->UseRootScrollOffsetsWhenComputingBounds()) {
+    EXPECT_EQ(gfx::Rect(75, 50, 16, 9).ToString(),
+              static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+  } else {
+    EXPECT_EQ(gfx::Rect(100, 100, 16, 9).ToString(),
+              static_text_accessible->GetLocalBoundsForRange(0, 3).ToString());
+  }
+}
+
 #if defined(OS_WIN)
 #define MAYBE_BoundsForRangeOnParentElement \
   DISABLED_BoundsForRangeOnParentElement
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.cc b/content/browser/accessibility/browser_accessibility_state_impl.cc
index 597b13a..5d68c2c 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -31,7 +31,8 @@
 
 BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl()
     : BrowserAccessibilityState(),
-      accessibility_mode_(AccessibilityModeOff) {
+      accessibility_mode_(AccessibilityModeOff),
+      disable_hot_tracking_(false) {
   ResetAccessibilityModeValue();
 #if defined(OS_WIN)
   // On Windows, UpdateHistograms calls some system functions with unknown
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.h b/content/browser/accessibility/browser_accessibility_state_impl.h
index 4c888437..7724916 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.h
+++ b/content/browser/accessibility/browser_accessibility_state_impl.h
@@ -60,6 +60,18 @@
   // removed.
   void RemoveAccessibilityMode(AccessibilityMode mode);
 
+  // Accessibility objects can have the "hot tracked" state set when
+  // the mouse is hovering over them, but this makes tests flaky because
+  // the test behaves differently when the mouse happens to be over an
+  // element.  This is a global switch to not use the "hot tracked" state
+  // in a test.
+  void set_disable_hot_tracking_for_testing(bool disable_hot_tracking) {
+    disable_hot_tracking_ = disable_hot_tracking;
+  }
+  bool disable_hot_tracking_for_testing() const {
+    return disable_hot_tracking_;
+  }
+
  private:
   friend class base::RefCountedThreadSafe<BrowserAccessibilityStateImpl>;
   friend struct DefaultSingletonTraits<BrowserAccessibilityStateImpl>;
@@ -84,6 +96,8 @@
 
   std::vector<base::Closure> histogram_callbacks_;
 
+  bool disable_hot_tracking_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityStateImpl);
 };
 
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index e4d2f379..a550159 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -3568,8 +3568,6 @@
     ia_state |= STATE_SYSTEM_FOCUSABLE;
   if (HasState(ui::AX_STATE_HASPOPUP))
     ia_state |= STATE_SYSTEM_HASPOPUP;
-  if (HasState(ui::AX_STATE_HOVERED))
-    ia_state |= STATE_SYSTEM_HOTTRACKED;
   if (HasState(ui::AX_STATE_INDETERMINATE))
     ia_state |= STATE_SYSTEM_INDETERMINATE;
   if (HasIntAttribute(ui::AX_ATTR_INVALID_STATE) &&
@@ -3607,6 +3605,16 @@
   if (HasState(ui::AX_STATE_VISITED))
     ia_state |= STATE_SYSTEM_TRAVERSED;
 
+  // Expose whether or not the mouse is over an element, but suppress
+  // this for tests because it can make the test results flaky depending
+  // on the position of the mouse.
+  BrowserAccessibilityStateImpl* accessibility_state =
+      BrowserAccessibilityStateImpl::GetInstance();
+  if (!accessibility_state->disable_hot_tracking_for_testing()) {
+    if (HasState(ui::AX_STATE_HOVERED))
+      ia_state |= STATE_SYSTEM_HOTTRACKED;
+  }
+
   // WebKit marks everything as readonly unless it's editable text, so if it's
   // not readonly, mark it as editable now. The final computation of the
   // READONLY state for MSAA is below, after the switch.
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index c30c2bb..d09b852 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -16,6 +16,7 @@
 #include "content/browser/accessibility/accessibility_tree_formatter.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_paths.h"
@@ -121,6 +122,11 @@
 
 void DumpAccessibilityTestBase::RunTest(
     const base::FilePath file_path, const char* file_dir) {
+  // Disable the "hot tracked" state (set when the mouse is hovering over
+  // an object) because it makes test output change based on the mouse position.
+  BrowserAccessibilityStateImpl::GetInstance()->
+      set_disable_hot_tracking_for_testing(true);
+
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
   // Output the test path to help anyone who encounters a failure and needs
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 621d710..6f83a6f 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -267,6 +267,18 @@
   RunAriaTest(FILE_PATH_LITERAL("aria-grabbed.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaGrid) {
+  RunAriaTest(FILE_PATH_LITERAL("aria-grid.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaGridCell) {
+  RunAriaTest(FILE_PATH_LITERAL("aria-gridcell.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaGroup) {
+  RunAriaTest(FILE_PATH_LITERAL("aria-group.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaImg) {
   RunAriaTest(FILE_PATH_LITERAL("aria-img.html"));
 }
@@ -502,6 +514,10 @@
   RunAriaTest(FILE_PATH_LITERAL("aria-tablist.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTabPanel) {
+  RunAriaTest(FILE_PATH_LITERAL("aria-tabpanel.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTextbox) {
   RunAriaTest(FILE_PATH_LITERAL("aria-textbox.html"));
 }
@@ -563,6 +579,14 @@
   RunHtmlTest(FILE_PATH_LITERAL("a-with-img.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityB) {
+  RunHtmlTest(FILE_PATH_LITERAL("b.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBase) {
+  RunHtmlTest(FILE_PATH_LITERAL("base.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityBdo) {
   RunHtmlTest(FILE_PATH_LITERAL("bdo.html"));
 }
@@ -783,6 +807,10 @@
   RunHtmlTest(FILE_PATH_LITERAL("input-file.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputHidden) {
+  RunHtmlTest(FILE_PATH_LITERAL("input-hidden.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputImage) {
   RunHtmlTest(FILE_PATH_LITERAL("input-image.html"));
 }
@@ -804,6 +832,10 @@
 }
 #endif
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputPassword) {
+  RunHtmlTest(FILE_PATH_LITERAL("input-password.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputRadio) {
   RunHtmlTest(FILE_PATH_LITERAL("input-radio.html"));
 }
@@ -825,6 +857,10 @@
   RunHtmlTest(FILE_PATH_LITERAL("input-search.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilitySmall) {
+  RunHtmlTest(FILE_PATH_LITERAL("small.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputSubmit) {
   RunHtmlTest(FILE_PATH_LITERAL("input-submit.html"));
 }
diff --git a/content/browser/accessibility/site_per_process_accessibility_browsertest.cc b/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
index a10959e1..1893e0d 100644
--- a/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
+++ b/content/browser/accessibility/site_per_process_accessibility_browsertest.cc
@@ -47,13 +47,11 @@
           root->GetStringAttribute(ui::AX_ATTR_DOC_URL) != url::kAboutBlankURL);
 }
 
-// TODO(nasko): try enabling this test on more platforms once
-// SitePerProcessBrowserTest.CrossSiteIframe is enabled everywhere.
-// http://crbug.com/399775
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#define MAYBE_CrossSiteIframeAccessibility CrossSiteIframeAccessibility
-#else
+// Times out on Android, not clear if it's an actual bug or just slow.
+#if defined(OS_ANDROID)
 #define MAYBE_CrossSiteIframeAccessibility DISABLED_CrossSiteIframeAccessibility
+#else
+#define MAYBE_CrossSiteIframeAccessibility CrossSiteIframeAccessibility
 #endif
 IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest,
                        MAYBE_CrossSiteIframeAccessibility) {
diff --git a/content/browser/android/in_process/DEPS b/content/browser/android/in_process/DEPS
index a8ba3f4c..6954b5f 100644
--- a/content/browser/android/in_process/DEPS
+++ b/content/browser/android/in_process/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+cc/blink",
   # Required for SynchronousCompositor (in --single-process mode only).
   "+content/public/renderer/android",
   "+content/renderer",
diff --git a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
index 4767b83..e3148ec 100644
--- a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
@@ -18,9 +18,9 @@
 #include "ui/gl/gl_surface_stub.h"
 #include "webkit/common/gpu/context_provider_in_process.h"
 
+using cc_blink::ContextProviderWebContext;
 using gpu_blink::WebGraphicsContext3DImpl;
 using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl;
-using webkit::gpu::ContextProviderWebContext;
 
 namespace content {
 
diff --git a/content/browser/android/in_process/synchronous_compositor_factory_impl.h b/content/browser/android/in_process/synchronous_compositor_factory_impl.h
index a3739bdb..169381c 100644
--- a/content/browser/android/in_process/synchronous_compositor_factory_impl.h
+++ b/content/browser/android/in_process/synchronous_compositor_factory_impl.h
@@ -6,11 +6,11 @@
 #define CONTENT_BROWSER_ANDROID_IN_PROCESS_SYNCHRONOUS_COMPOSITOR_FACTORY_IMPL_H_
 
 #include "base/synchronization/lock.h"
+#include "cc/blink/context_provider_web_context.h"
 #include "content/browser/android/in_process/synchronous_input_event_filter.h"
 #include "content/renderer/android/synchronous_compositor_factory.h"
 #include "content/renderer/media/android/stream_texture_factory_synchronous_impl.h"
 #include "gpu/command_buffer/service/in_process_command_buffer.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
 
 namespace gpu {
 class GLInProcessContext;
@@ -38,10 +38,10 @@
   virtual InputHandlerManagerClient* GetInputHandlerManagerClient() override;
   virtual scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
       int routing_id) override;
-  virtual scoped_refptr<webkit::gpu::ContextProviderWebContext>
-      CreateOffscreenContextProvider(
-          const blink::WebGraphicsContext3D::Attributes& attributes,
-          const std::string& debug_name) override;
+  virtual scoped_refptr<cc_blink::ContextProviderWebContext>
+  CreateOffscreenContextProvider(
+      const blink::WebGraphicsContext3D::Attributes& attributes,
+      const std::string& debug_name) override;
   virtual scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory(
       int view_id) override;
   virtual gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*
diff --git a/content/browser/browser_plugin/browser_plugin_embedder.cc b/content/browser/browser_plugin/browser_plugin_embedder.cc
index 39881a0..8159b0d 100644
--- a/content/browser/browser_plugin/browser_plugin_embedder.cc
+++ b/content/browser/browser_plugin/browser_plugin_embedder.cc
@@ -124,7 +124,8 @@
   // to the guest that initiated the drag/drop operation. This will ensure that
   // the guest's RVH state is reset properly.
   if (guest_started_drag_)
-    guest_started_drag_->EndSystemDrag();
+    guest_started_drag_->EmbedderSystemDragEnded();
+
   guest_dragging_over_.reset();
   ClearGuestDragStateIfApplicable();
 }
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index 543a63c7..3c412a0 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -91,6 +91,9 @@
       last_input_flags_(0),
       last_can_compose_inline_(true),
       guest_proxy_routing_id_(MSG_ROUTING_NONE),
+      last_drag_status_(blink::WebDragStatusUnknown),
+      seen_embedder_system_drag_ended_(false),
+      seen_embedder_drag_source_ended_at_(false),
       delegate_(delegate),
       weak_ptr_factory_(this) {
   DCHECK(web_contents);
@@ -417,12 +420,45 @@
     int screen_x, int screen_y, blink::WebDragOperation operation) {
   web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
       screen_x, screen_y, operation);
+  seen_embedder_drag_source_ended_at_ = true;
+  EndSystemDragIfApplicable();
 }
 
-void BrowserPluginGuest::EndSystemDrag() {
-  RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
-      GetWebContents()->GetRenderViewHost());
-  guest_rvh->DragSourceSystemDragEnded();
+void BrowserPluginGuest::EndSystemDragIfApplicable() {
+  // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
+  // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
+  // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
+  // means we call it in all cases and also make sure we only call it once.
+  // This ensures that the input state of the guest stays correct, otherwise
+  // it will go stale and won't accept any further input events.
+  //
+  // The strategy used here to call DragSourceSystemDragEnded() on the RVH
+  // is when the following conditions are met:
+  //   a. Embedder has seen SystemDragEnded()
+  //   b. Embedder has seen DragSourceEndedAt()
+  //   c. The guest has seen some drag status update other than
+  //      WebDragStatusUnknown. Note that this step should ideally be done
+  //      differently: The guest has seen at least one of
+  //      {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
+  //      a source quickly outside of <webview> bounds, then the
+  //      BrowserPluginGuest never sees any of these drag status updates,
+  //      there we just check whether we've seen any drag status update or
+  //      not.
+  if (last_drag_status_ != blink::WebDragStatusOver &&
+      seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
+    RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
+        GetWebContents()->GetRenderViewHost());
+    guest_rvh->DragSourceSystemDragEnded();
+
+    last_drag_status_ = blink::WebDragStatusUnknown;
+    seen_embedder_system_drag_ended_ = false;
+    seen_embedder_drag_source_ended_at_ = false;
+  }
+}
+
+void BrowserPluginGuest::EmbedderSystemDragEnded() {
+  seen_embedder_system_drag_ended_ = true;
+  EndSystemDragIfApplicable();
 }
 
 void BrowserPluginGuest::SendQueuedMessages() {
@@ -649,11 +685,12 @@
       break;
     case blink::WebDragStatusDrop:
       host->DragTargetDrop(location, location, 0);
-      EndSystemDrag();
       break;
     case blink::WebDragStatusUnknown:
       NOTREACHED();
   }
+  last_drag_status_ = drag_status;
+  EndSystemDragIfApplicable();
 }
 
 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
@@ -830,8 +867,8 @@
 #endif
 
 void BrowserPluginGuest::OnShowWidget(int route_id,
-                                      const gfx::Rect& initial_pos) {
-  GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
+                                      const gfx::Rect& initial_rect) {
+  GetWebContents()->ShowCreatedWidget(route_id, initial_rect);
 }
 
 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index 09417820..fd859e7 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -198,7 +198,8 @@
       int screen_y, blink::WebDragOperation operation);
 
   // Called when the drag started by this guest ends at an OS-level.
-  void EndSystemDrag();
+  void EmbedderSystemDragEnded();
+  void EndSystemDragIfApplicable();
 
   void RespondToPermissionRequest(int request_id,
                                   bool should_allow,
@@ -330,7 +331,7 @@
   void OnShowPopup(RenderFrameHost* render_frame_host,
                    const FrameHostMsg_ShowPopup_Params& params);
 #endif
-  void OnShowWidget(int route_id, const gfx::Rect& initial_pos);
+  void OnShowWidget(int route_id, const gfx::Rect& initial_rect);
   void OnTakeFocus(bool reverse);
   void OnUpdateFrameName(int frame_id,
                          bool is_top_level,
@@ -387,6 +388,12 @@
   // The is the routing ID for a swapped out RenderView for the guest
   // WebContents in the embedder's process.
   int guest_proxy_routing_id_;
+  // Last seen state of drag status update.
+  blink::WebDragStatus last_drag_status_;
+  // Whether or not our embedder has seen a SystemDragEnded() call.
+  bool seen_embedder_system_drag_ended_;
+  // Whether or not our embedder has seen a DragSourceEndedAt() call.
+  bool seen_embedder_drag_source_ended_at_;
 
   // Guests generate frames and send a CompositorFrameSwapped (CFS) message
   // indicating the next frame is ready to be positioned and composited.
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory.h b/content/browser/device_sensors/data_fetcher_shared_memory.h
index a5d1f82..a0d9828 100644
--- a/content/browser/device_sensors/data_fetcher_shared_memory.h
+++ b/content/browser/device_sensors/data_fetcher_shared_memory.h
@@ -22,7 +22,9 @@
 
 namespace content {
 
-#if defined(OS_MACOSX)
+#if defined(OS_CHROMEOS)
+class SensorManagerChromeOS;
+#elif defined(OS_MACOSX)
 class AmbientLightSensor;
 #endif
 
@@ -42,7 +44,10 @@
   DeviceOrientationHardwareBuffer* orientation_buffer_;
   DeviceLightHardwareBuffer* light_buffer_;
 #endif
-#if defined(OS_MACOSX)
+
+#if defined(OS_CHROMEOS)
+  scoped_ptr<SensorManagerChromeOS> sensor_manager_;
+#elif defined(OS_MACOSX)
   void Fetch(unsigned consumer_bitmask) override;
   FetcherType GetType() const override;
 
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory_chromeos.cc b/content/browser/device_sensors/data_fetcher_shared_memory_chromeos.cc
new file mode 100644
index 0000000..6dc0336
--- /dev/null
+++ b/content/browser/device_sensors/data_fetcher_shared_memory_chromeos.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/device_sensors/data_fetcher_shared_memory.h"
+
+#include "content/browser/device_sensors/sensor_manager_chromeos.h"
+
+namespace content {
+
+DataFetcherSharedMemory::DataFetcherSharedMemory() {
+}
+
+DataFetcherSharedMemory::~DataFetcherSharedMemory() {
+}
+
+bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
+  DCHECK(buffer);
+  if (!sensor_manager_)
+    sensor_manager_.reset(new SensorManagerChromeOS);
+
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      // TODO(jonross): Implement Device Motion API. (crbug.com/427662)
+      NOTIMPLEMENTED();
+      return false;
+    case CONSUMER_TYPE_ORIENTATION:
+      return sensor_manager_->StartFetchingDeviceOrientationData(
+          static_cast<DeviceOrientationHardwareBuffer*>(buffer));
+    case CONSUMER_TYPE_LIGHT:
+      NOTIMPLEMENTED();
+      return false;
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      NOTIMPLEMENTED();
+      return false;
+    case CONSUMER_TYPE_ORIENTATION:
+      return sensor_manager_->StopFetchingDeviceOrientationData();
+    case CONSUMER_TYPE_LIGHT:
+      NOTIMPLEMENTED();
+      return false;
+  }
+  NOTREACHED();
+  return false;
+}
+
+}  // namespace content
diff --git a/content/browser/device_sensors/sensor_manager_android_unittest.cc b/content/browser/device_sensors/sensor_manager_android_unittest.cc
index b5f0c5fb9..5ce25fb 100644
--- a/content/browser/device_sensors/sensor_manager_android_unittest.cc
+++ b/content/browser/device_sensors/sensor_manager_android_unittest.cc
@@ -17,9 +17,9 @@
 class FakeSensorManagerAndroid : public SensorManagerAndroid {
  public:
   FakeSensorManagerAndroid() { }
-  virtual ~FakeSensorManagerAndroid() { }
+  ~FakeSensorManagerAndroid() override {}
 
-  virtual int GetNumberActiveDeviceMotionSensors() override {
+  int GetNumberActiveDeviceMotionSensors() override {
     return number_active_sensors_;
   }
 
@@ -28,12 +28,9 @@
   }
 
  protected:
-  virtual bool Start(EventType event_type) override {
-    return true;
-  }
+  bool Start(EventType event_type) override { return true; }
 
-  virtual void Stop(EventType event_type) override {
-  }
+  void Stop(EventType event_type) override {}
 
  private:
   int number_active_sensors_;
diff --git a/content/browser/device_sensors/sensor_manager_chromeos.cc b/content/browser/device_sensors/sensor_manager_chromeos.cc
new file mode 100644
index 0000000..2952ab63
--- /dev/null
+++ b/content/browser/device_sensors/sensor_manager_chromeos.cc
@@ -0,0 +1,119 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/device_sensors/sensor_manager_chromeos.h"
+
+#include "base/logging.h"
+#include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace {
+// Conversion ratio from radians to degrees.
+const double kRad2deg = 180.0 / M_PI;
+}
+
+namespace content {
+
+SensorManagerChromeOS::SensorManagerChromeOS() : orientation_buffer_(nullptr) {
+}
+
+SensorManagerChromeOS::~SensorManagerChromeOS() {
+}
+
+bool SensorManagerChromeOS::StartFetchingDeviceOrientationData(
+    DeviceOrientationHardwareBuffer* buffer) {
+  DCHECK(buffer);
+  {
+    base::AutoLock autolock(orientation_buffer_lock_);
+    if (orientation_buffer_)
+      return false;
+    orientation_buffer_ = buffer;
+
+    // No compass information, so we cannot provide absolute orientation.
+    orientation_buffer_->seqlock.WriteBegin();
+    orientation_buffer_->data.absolute = false;
+    orientation_buffer_->data.hasAbsolute = true;
+    orientation_buffer_->seqlock.WriteEnd();
+  }
+
+  StartObservingAccelerometer();
+  return true;
+}
+
+bool SensorManagerChromeOS::StopFetchingDeviceOrientationData() {
+  {
+    base::AutoLock autolock(orientation_buffer_lock_);
+    if (!orientation_buffer_)
+      return false;
+    // Make sure to indicate that the sensor data is no longer available.
+    orientation_buffer_->seqlock.WriteBegin();
+    orientation_buffer_->data.allAvailableSensorsAreActive = false;
+    orientation_buffer_->seqlock.WriteEnd();
+    orientation_buffer_ = nullptr;
+  }
+
+  StopObservingAccelerometer();
+  return true;
+}
+
+void SensorManagerChromeOS::OnAccelerometerUpdated(
+    const chromeos::AccelerometerUpdate& update) {
+  base::AutoLock autolock(orientation_buffer_lock_);
+  if (!orientation_buffer_)
+    return;
+
+  chromeos::AccelerometerSource source;
+  if (update.has(chromeos::ACCELEROMETER_SOURCE_SCREEN)) {
+    source = chromeos::ACCELEROMETER_SOURCE_SCREEN;
+  } else if (update.has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)) {
+    source = chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD;
+  } else {
+    return;
+  }
+
+  double x = update.get(source).x;
+  double y = update.get(source).y;
+  double z = update.get(source).z;
+
+  // Create a unit vector for trigonometry
+  // TODO(jonross): Stop reversing signs for vector components once
+  // accelerometer values have been fixed. crbug.com/431391
+  // Ternaries are to remove -0.0f which gives incorrect trigonometrical
+  // results.
+  gfx::Vector3dF data(x, y ? -y : 0.0f, z ? -z : 0.0f);
+  data.Scale(1.0f / data.Length());
+
+  // Transform accelerometer to W3C angles, using the Z-X-Y Eulerangles matrix.
+  // x = sin(gamma)
+  // y = -cos(gamma) * sin(beta)
+  // z = cos(beta) * cos(gamma)
+  // With only accelerometer alpha cannot be provided.
+  double beta = kRad2deg * atan2(data.y(), data.z());
+  double gamma = kRad2deg * asin(data.x());
+
+  // Convert beta and gamma to fit the intervals in the specification. Beta is
+  // [-180, 180) and gamma is [-90, 90).
+  if (beta >= 180.0f)
+    beta = -180.0f;
+  if (gamma >= 90.0f)
+    gamma = -90.0f;
+  orientation_buffer_->seqlock.WriteBegin();
+  orientation_buffer_->data.beta = beta;
+  orientation_buffer_->data.hasBeta = true;
+  orientation_buffer_->data.gamma = gamma;
+  orientation_buffer_->data.hasGamma = true;
+  orientation_buffer_->data.allAvailableSensorsAreActive = true;
+  orientation_buffer_->seqlock.WriteEnd();
+}
+
+void SensorManagerChromeOS::StartObservingAccelerometer() {
+  chromeos::AccelerometerReader::GetInstance()->AddObserver(this);
+}
+
+void SensorManagerChromeOS::StopObservingAccelerometer() {
+  chromeos::AccelerometerReader::GetInstance()->RemoveObserver(this);
+}
+
+}  // namespace content
diff --git a/content/browser/device_sensors/sensor_manager_chromeos.h b/content/browser/device_sensors/sensor_manager_chromeos.h
new file mode 100644
index 0000000..faeabeb7
--- /dev/null
+++ b/content/browser/device_sensors/sensor_manager_chromeos.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 CONTENT_BROWSER_DEVICE_SENSORS_SENSOR_MANAGER_CHROMEOS_H_
+#define CONTENT_BROWSER_DEVICE_SENSORS_SENSOR_MANAGER_CHROMEOS_H_
+
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "chromeos/accelerometer/accelerometer_reader.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
+#include "content/common/content_export.h"
+#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
+
+namespace content {
+
+// Observes Chrome OS accelerometer sensors, and provides updated device
+// orientation information.
+class CONTENT_EXPORT SensorManagerChromeOS
+    : public chromeos::AccelerometerReader::Observer {
+ public:
+  SensorManagerChromeOS();
+  ~SensorManagerChromeOS() override;
+
+  // Begins monitoring of orientation events, the shared memory of |buffer| will
+  // be updated upon subsequent events.
+  bool StartFetchingDeviceOrientationData(
+      DeviceOrientationHardwareBuffer* buffer);
+
+  // Stops monitoring orientation events. Returns true if there is an active
+  // |orientation_buffer_| and fetching stops. Otherwise returns false.
+  bool StopFetchingDeviceOrientationData();
+
+  // chromeos::AccelerometerReader::Observer:
+  void OnAccelerometerUpdated(
+      const chromeos::AccelerometerUpdate& update) override;
+
+ protected:
+  // Begins/ends the observation of accelerometer events.
+  virtual void StartObservingAccelerometer();
+  virtual void StopObservingAccelerometer();
+
+ private:
+  // Shared memory to update.
+  DeviceOrientationHardwareBuffer* orientation_buffer_;
+
+  // Synchronize orientation_buffer_ across threads.
+  base::Lock orientation_buffer_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(SensorManagerChromeOS);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVICE_SENSORS_SENSOR_MANAGER_CHROMEOS_H_
diff --git a/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc b/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc
new file mode 100644
index 0000000..3e71839
--- /dev/null
+++ b/content/browser/device_sensors/sensor_manager_chromeos_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/device_sensors/sensor_manager_chromeos.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "chromeos/accelerometer/accelerometer_types.h"
+#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const double kMeanGravity = 9.80665;
+
+// Isolated content::SensorManagerChromeOS from the active
+// chromeos::AccelerometerReader. This allows for direct control over which
+// accelerometer events are provided to the sensor manager.
+class TestSensorManagerChromeOS : public content::SensorManagerChromeOS {
+ public:
+  TestSensorManagerChromeOS() {}
+  ~TestSensorManagerChromeOS() override {};
+
+ protected:
+  void StartObservingAccelerometer() override {}
+  void StopObservingAccelerometer() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestSensorManagerChromeOS);
+};
+
+}  // namespace
+
+namespace content {
+
+class SensorManagerChromeOSTest : public testing::Test {
+ public:
+  SensorManagerChromeOSTest() {
+    orientation_buffer_.reset(new DeviceOrientationHardwareBuffer);
+  }
+
+  ~SensorManagerChromeOSTest() override {}
+
+  void OnAccelerationIncludingGravity(double x, double y, double z) {
+    chromeos::AccelerometerUpdate update;
+    update.Set(chromeos::ACCELEROMETER_SOURCE_SCREEN, x, y, z);
+    sensor_manager_->OnAccelerometerUpdated(update);
+  }
+
+  DeviceOrientationHardwareBuffer* orientation_buffer() {
+    return orientation_buffer_.get();
+  }
+
+  SensorManagerChromeOS* sensor_manager() { return sensor_manager_.get(); }
+
+  // testing::Test:
+  void SetUp() override {
+    testing::Test::SetUp();
+    sensor_manager_.reset(new TestSensorManagerChromeOS);
+    sensor_manager_->StartFetchingDeviceOrientationData(
+        orientation_buffer_.get());
+  }
+
+  void TearDown() override {
+    sensor_manager_->StopFetchingDeviceOrientationData();
+    testing::Test::TearDown();
+  }
+
+ private:
+  scoped_ptr<TestSensorManagerChromeOS> sensor_manager_;
+
+  scoped_ptr<DeviceOrientationHardwareBuffer> orientation_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(SensorManagerChromeOSTest);
+};
+
+// Tests that starting to process orientation data will update the associated
+// buffer.
+TEST_F(SensorManagerChromeOSTest, OrientationBuffer) {
+  DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+  EXPECT_TRUE(buffer->data.hasAbsolute);
+  EXPECT_FALSE(buffer->data.hasAlpha);
+  EXPECT_FALSE(buffer->data.hasBeta);
+  EXPECT_FALSE(buffer->data.hasGamma);
+  EXPECT_FALSE(buffer->data.allAvailableSensorsAreActive);
+
+  OnAccelerationIncludingGravity(0.0f, 0.0f, 1.0f);
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.alpha);
+  EXPECT_FALSE(buffer->data.hasAlpha);
+  EXPECT_TRUE(buffer->data.hasBeta);
+  EXPECT_TRUE(buffer->data.hasGamma);
+  EXPECT_TRUE(buffer->data.allAvailableSensorsAreActive);
+
+  sensor_manager()->StopFetchingDeviceOrientationData();
+  EXPECT_FALSE(buffer->data.allAvailableSensorsAreActive);
+}
+
+// Tests a device resting flat.
+TEST_F(SensorManagerChromeOSTest, NeutralOrientation) {
+  OnAccelerationIncludingGravity(0.0f, 0.0f, -kMeanGravity);
+  DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.beta);
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.gamma);
+}
+
+// Tests an upside-down device, such that the W3C boundary [-180,180) causes the
+// beta value to become negative.
+TEST_F(SensorManagerChromeOSTest, UpsideDown) {
+  OnAccelerationIncludingGravity(0.0f, 0.0f, kMeanGravity);
+  DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+  EXPECT_FLOAT_EQ(-180.0f, buffer->data.beta);
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.gamma);
+}
+
+// Tests for positive beta value before the device is completely upside-down
+TEST_F(SensorManagerChromeOSTest, BeforeUpsideDownBoundary) {
+  OnAccelerationIncludingGravity(0.0f, -kMeanGravity / 2.0f,
+                                 kMeanGravity / 2.0f);
+  DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+  EXPECT_FLOAT_EQ(135.0f, buffer->data.beta);
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.gamma);
+}
+
+// Tests a device lying on its left-edge.
+TEST_F(SensorManagerChromeOSTest, LeftEdge) {
+  OnAccelerationIncludingGravity(-kMeanGravity, 0.0f, 0.0f);
+  DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.beta);
+  EXPECT_FLOAT_EQ(-90.0f, buffer->data.gamma);
+}
+
+// Tests a device lying on its right-edge, such that the W3C boundary [-90,90)
+// causes the gamma value to become negative.
+TEST_F(SensorManagerChromeOSTest, RightEdge) {
+  OnAccelerationIncludingGravity(kMeanGravity, 0.0f, 0.0f);
+  DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.beta);
+  EXPECT_FLOAT_EQ(-90.0f, buffer->data.gamma);
+}
+
+// Tests for positive gamma value before the device is completely on its right
+// side.
+TEST_F(SensorManagerChromeOSTest, BeforeRightEdgeBoundary) {
+  OnAccelerationIncludingGravity(kMeanGravity / 2.0f, 0.0f,
+                                 -kMeanGravity / 2.0f);
+  DeviceOrientationHardwareBuffer* buffer = orientation_buffer();
+  EXPECT_FLOAT_EQ(0.0f, buffer->data.beta);
+  EXPECT_FLOAT_EQ(45.0f, buffer->data.gamma);
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/frame_accessibility.cc b/content/browser/frame_host/frame_accessibility.cc
index c0e86b29..39b1e0e6 100644
--- a/content/browser/frame_host/frame_accessibility.cc
+++ b/content/browser/frame_host/frame_accessibility.cc
@@ -161,9 +161,15 @@
           FrameTree::GloballyFindByID(iter->child_frame_tree_node_id);
       if (child_node &&
           child_node->current_frame_host() == child_frame_host) {
-        // We should have gotten a *direct* child of the parent frame.
-        if (child_node->parent() !=
-            iter->parent_frame_host->frame_tree_node()) {
+        // Assert that the child node is a descendant of the parent frame in
+        // the frame tree. It may not be a direct descendant because the
+        // parent frame's accessibility tree may span multiple frames from the
+        // same origin.
+        FrameTreeNode* parent_node = iter->parent_frame_host->frame_tree_node();
+        FrameTreeNode* child_node_ancestor = child_node->parent();
+        while (child_node_ancestor && child_node_ancestor != parent_node)
+          child_node_ancestor = child_node_ancestor->parent();
+        if (child_node_ancestor != parent_node) {
           NOTREACHED();
           return false;
         }
@@ -201,8 +207,15 @@
   if (!child_node)
     return nullptr;
 
-  // We should have gotten a *direct* child of the parent frame.
-  if (child_node->parent() != parent_frame_host->frame_tree_node()) {
+  // Assert that the child node is a descendant of the parent frame in
+  // the frame tree. It may not be a direct descendant because the
+  // parent frame's accessibility tree may span multiple frames from the
+  // same origin.
+  FrameTreeNode* parent_node = parent_frame_host->frame_tree_node();
+  FrameTreeNode* child_node_ancestor = child_node->parent();
+  while (child_node_ancestor && child_node_ancestor != parent_node)
+    child_node_ancestor = child_node_ancestor->parent();
+  if (child_node_ancestor != parent_node) {
     NOTREACHED();
     return nullptr;
   }
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index 96890f0..af15b99 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -208,6 +208,9 @@
       root()->render_manager()->CreateRenderFrame(
           site_instance, nullptr, MSG_ROUTING_NONE,
           CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
+    } else {
+      root()->render_manager()->EnsureRenderViewInitialized(
+          source, render_view_host, site_instance);
     }
   }
 
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index 57cd7fd..c59075c5 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -740,13 +740,13 @@
 
 void InterstitialPageImpl::ShowCreatedWindow(int route_id,
                                              WindowOpenDisposition disposition,
-                                             const gfx::Rect& initial_pos,
+                                             const gfx::Rect& initial_rect,
                                              bool user_gesture) {
   NOTREACHED() << "InterstitialPage does not support showing popups yet.";
 }
 
 void InterstitialPageImpl::ShowCreatedWidget(int route_id,
-                                             const gfx::Rect& initial_pos) {
+                                             const gfx::Rect& initial_rect) {
   NOTREACHED() << "InterstitialPage does not support showing drop-downs yet.";
 }
 
diff --git a/content/browser/frame_host/interstitial_page_impl.h b/content/browser/frame_host/interstitial_page_impl.h
index 9a99b47..ae41f77 100644
--- a/content/browser/frame_host/interstitial_page_impl.h
+++ b/content/browser/frame_host/interstitial_page_impl.h
@@ -130,9 +130,9 @@
   void CreateNewFullscreenWidget(int render_process_id, int route_id) override;
   void ShowCreatedWindow(int route_id,
                          WindowOpenDisposition disposition,
-                         const gfx::Rect& initial_pos,
+                         const gfx::Rect& initial_rect,
                          bool user_gesture) override;
-  void ShowCreatedWidget(int route_id, const gfx::Rect& initial_pos) override;
+  void ShowCreatedWidget(int route_id, const gfx::Rect& initial_rect) override;
   void ShowCreatedFullscreenWidget(int route_id) override;
 
   SessionStorageNamespace* GetSessionStorageNamespace(
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 3eca788..d9bdc38c 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -4,17 +4,29 @@
 
 #include "base/bind.h"
 #include "base/strings/stringprintf.h"
+#include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/navigation_controller_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace content {
 
 class NavigationControllerBrowserTest : public ContentBrowserTest {
+ protected:
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, LoadDataWithBaseURL) {
@@ -76,5 +88,111 @@
             controller.GetLastCommittedEntry()->GetURL());
 }
 
-}  // namespace content
+struct FrameNavigateParamsCapturer : public WebContentsObserver {
+ public:
+  explicit FrameNavigateParamsCapturer(FrameTreeNode* node)
+      : WebContentsObserver(
+            node->current_frame_host()->delegate()->GetAsWebContents()),
+        frame_tree_node_id_(node->frame_tree_node_id()),
+        message_loop_runner_(new MessageLoopRunner) {}
 
+  void Wait() {
+    message_loop_runner_->Run();
+  }
+
+  const FrameNavigateParams& params() const {
+    return params_;
+  }
+
+  const LoadCommittedDetails& details() const {
+    return details_;
+  }
+
+ private:
+  void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+                           const LoadCommittedDetails& details,
+                           const FrameNavigateParams& params) override {
+    RenderFrameHostImpl* rfh =
+        static_cast<RenderFrameHostImpl*>(render_frame_host);
+    if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
+      return;
+
+    params_ = params;
+    details_ = details;
+    message_loop_runner_->Quit();
+  }
+
+  // The id of the FrameTreeNode whose navigations to observe.
+  int frame_tree_node_id_;
+
+  // The params of the last navigation.
+  FrameNavigateParams params_;
+
+  // The details of the last navigation.
+  LoadCommittedDetails details_;
+
+  // The MessageLoopRunner used to spin the message loop.
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
+};
+
+// Verify that the distinction between manual and auto subframes is properly set
+// for subframe navigations. TODO(avi): It's rather bogus that the same info is
+// in two different enums; http://crbug.com/453555.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       ManualAndAutoSubframeNavigationClassification) {
+  GURL main_url(
+      embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
+  NavigateToURL(shell(), main_url);
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root =
+      static_cast<WebContentsImpl*>(shell()->web_contents())->
+          GetFrameTree()->root();
+
+  ASSERT_EQ(1U, root->child_count());
+  ASSERT_NE(nullptr, root->child_at(0));
+
+  {
+    // Navigate the iframe to a new URL; expect a manual subframe transition.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    GURL frame_url(
+        embedded_test_server()->GetURL("/frame_tree/2-1.html"));
+    NavigateFrameToURL(root->child_at(0), frame_url);
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+              capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+  }
+
+  {
+    // History navigations should result in an auto subframe transition.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    shell()->web_contents()->GetController().GoBack();
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
+  }
+
+  {
+    // History navigations should result in an auto subframe transition.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    shell()->web_contents()->GetController().GoForward();
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
+  }
+
+  {
+    // Navigate the iframe to a new URL; expect a manual subframe transition.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    GURL frame_url(
+        embedded_test_server()->GetURL("/frame_tree/2-3.html"));
+    NavigateFrameToURL(root->child_at(0), frame_url);
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+              capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 34647b9..f359f51 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -108,7 +108,12 @@
   DCHECK(state_ == STARTED);
   state_ = FAILED;
   // TODO(davidben): Network failures should display a network error page.
-  NOTIMPLEMENTED();
+  NOTIMPLEMENTED() << " where net_error=" << net_error;
+}
+
+void NavigationRequest::OnRequestStarted(base::TimeTicks timestamp) {
+  frame_tree_node_->navigator()->LogResourceRequestTime(timestamp,
+                                                        common_params_.url);
 }
 
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 649e6288..8e1d303 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -110,6 +110,7 @@
   void OnResponseStarted(const scoped_refptr<ResourceResponse>& response,
                          scoped_ptr<StreamHandle> body) override;
   void OnRequestFailed(int net_error) override;
+  void OnRequestStarted(base::TimeTicks timestamp) override;
 
   FrameTreeNode* frame_tree_node_;
 
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index 191a5836..e56335a 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -138,8 +138,12 @@
   // |frame_tree_node| is destroyed.
   virtual void CancelNavigation(FrameTreeNode* frame_tree_node) {}
 
-  // Called when the first resource request for a given navigation is executed
-  // so that it can be tracked into an histogram.
+  // Called when the network stack started handling the navigation request
+  // so that the |timestamp| when it happened can be recorded into an histogram.
+  // The |url| is used to verify we're tracking the correct navigation.
+  // TODO(carlosk): once PlzNavigate is the only navigation implementation
+  // remove the URL parameter and rename this method to better suit its naming
+  // conventions.
   virtual void LogResourceRequestTime(
     base::TimeTicks timestamp, const GURL& url) {};
 
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index ebd10e97..8617d7e6 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -504,21 +504,6 @@
   bool use_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kSitePerProcess);
 
-  if (use_site_per_process) {
-    // TODO(creis): Until we mirror the frame tree in the subframe's process,
-    // cross-process subframe navigations happen in a renderer's main frame.
-    // Correct the transition type here if we know it is for a subframe.
-    NavigationEntryImpl* pending_entry =
-        NavigationEntryImpl::FromNavigationEntry(
-            controller_->GetPendingEntry());
-    if (!render_frame_host->frame_tree_node()->IsMainFrame() &&
-        pending_entry &&
-        pending_entry->frame_tree_node_id() ==
-            render_frame_host->frame_tree_node()->frame_tree_node_id()) {
-      params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
-    }
-  }
-
   if (ui::PageTransitionIsMainFrame(params.transition)) {
     if (delegate_) {
       // When overscroll navigation gesture is enabled, a screenshot of the page
@@ -772,6 +757,9 @@
     navigation_request = scoped_request.get();
     navigation_request_map_.set(
         frame_tree_node->frame_tree_node_id(), scoped_request.Pass());
+
+    if (frame_tree_node->IsMainFrame())
+      navigation_data_.reset();
   }
   DCHECK(navigation_request);
 
@@ -833,6 +821,8 @@
   CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnableBrowserSideNavigation));
   navigation_request_map_.erase(frame_tree_node->frame_tree_node_id());
+  if (frame_tree_node->IsMainFrame())
+    navigation_data_.reset();
   // TODO(carlosk): move this cleanup into the NavigationRequest destructor once
   // we properly cancel ongoing navigations.
   frame_tree_node->render_manager()->CleanUpNavigation();
@@ -944,6 +934,7 @@
     RecordAction(base::UserMetricsAction("FrameLoad"));
 
   if (!details.is_main_frame || !navigation_data_ ||
+      navigation_data_->url_job_start_time_.is_null() ||
       navigation_data_->url_ != params.original_request_url) {
     return;
   }
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 5878180..420275f0 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -278,6 +278,8 @@
 }
 
 blink::WebPageVisibilityState RenderFrameHostImpl::GetVisibilityState() {
+  // TODO(mlamouri,kenrb): call GetRenderWidgetHost() directly when it stops
+  // returning nullptr in some cases. See https://crbug.com/455245.
   blink::WebPageVisibilityState visibility_state =
       RenderWidgetHostImpl::From(GetView()->GetRenderWidgetHost())->is_hidden()
           ? blink::WebPageVisibilityStateHidden
@@ -568,6 +570,14 @@
     rwhv->Hide();
   }
 
+  if (proxy_routing_id != MSG_ROUTING_NONE) {
+    RenderFrameProxyHost* proxy = RenderFrameProxyHost::FromID(
+        GetProcess()->GetID(), proxy_routing_id);
+    // We have also created a RenderFrameProxy in FrameMsg_NewFrame above, so
+    // remember that.
+    proxy->set_render_frame_proxy_created(true);
+  }
+
   // The renderer now has a RenderFrame for this RenderFrameHost.  Note that
   // this path is only used for out-of-process iframes.  Main frame RenderFrames
   // are created with their RenderView, and same-site iframes are created at the
@@ -1594,7 +1604,10 @@
 }
 
 bool RenderFrameHostImpl::IsFocused() {
-  return GetView()->HasFocus() &&
+  // TODO(mlamouri,kenrb): call GetRenderWidgetHost() directly when it stops
+  // returning nullptr in some cases. See https://crbug.com/455245.
+  return RenderWidgetHostImpl::From(
+            GetView()->GetRenderWidgetHost())->is_focused() &&
          frame_tree_->GetFocusedFrame() &&
          (frame_tree_->GetFocusedFrame() == frame_tree_node() ||
           frame_tree_->GetFocusedFrame()->IsDescendantOf(frame_tree_node()));
@@ -1610,7 +1623,8 @@
 
     FrameTree* frame_tree = frame_tree_node()->frame_tree();
     FrameTreeNode* child_frame_tree_node = frame_tree->FindByRoutingID(
-        GetProcess()->GetID(), frame_routing_id);
+        frame_routing_id, GetProcess()->GetID());
+
     if (child_frame_tree_node) {
       FrameAccessibility::GetInstance()->AddChildFrame(
           this, node_id, child_frame_tree_node->frame_tree_node_id());
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index f66411d2..e7f1de5 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -408,7 +408,7 @@
 
   // Returns whether the frame is focused. A frame is considered focused when it
   // is the parent chain of the focused frame within the frame tree. In
-  // addition, its associated RenderWidgetHostView has to be focused.
+  // addition, its associated RenderWidgetHost has to be focused.
   bool IsFocused();
 
  protected:
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index baefe87f..4a9034b5 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -502,11 +502,22 @@
   // swap them back in while the process is exiting.  Start by finding them,
   // since there could be more than one.
   std::list<int> ids_to_remove;
+  // Do not remove proxies in the dead process that still have active frame
+  // count though, we just reset them to be uninitialized.
+  std::list<int> ids_to_keep;
   for (RenderFrameProxyHostMap::iterator iter = proxy_hosts_.begin();
        iter != proxy_hosts_.end();
        ++iter) {
-    if (iter->second->GetProcess() == render_process_host)
+    RenderFrameProxyHost* proxy = iter->second;
+    if (proxy->GetProcess() != render_process_host)
+      continue;
+
+    if (static_cast<SiteInstanceImpl*>(proxy->GetSiteInstance())
+            ->active_frame_count() >= 1U) {
+      ids_to_keep.push_back(iter->first);
+    } else {
       ids_to_remove.push_back(iter->first);
+    }
   }
 
   // Now delete them.
@@ -515,6 +526,14 @@
     proxy_hosts_.erase(ids_to_remove.back());
     ids_to_remove.pop_back();
   }
+
+  while (!ids_to_keep.empty()) {
+    frame_tree_node_->frame_tree()->ForEach(
+        base::Bind(
+            &RenderFrameHostManager::ResetProxiesInSiteInstance,
+            ids_to_keep.back()));
+    ids_to_keep.pop_back();
+  }
 }
 
 void RenderFrameHostManager::SwapOutOldFrame(
@@ -570,6 +589,9 @@
   // Tell the old RenderFrameHost to swap out and be replaced by the proxy.
   old_render_frame_host->SwapOut(proxy, true);
 
+  // SwapOut creates a RenderFrameProxy, so set the proxy to be initialized.
+  proxy->set_render_frame_proxy_created(true);
+
   bool is_main_frame = frame_tree_node_->IsMainFrame();
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kSitePerProcess) &&
@@ -694,17 +716,6 @@
     CleanUpNavigation();
     navigation_rfh = render_frame_host_.get();
   } else {
-    // If the current render_frame_host_ isn't live, we should create it so
-    // that we don't show a sad tab while the navigation is ongoing.
-    // (Bug 1145340)
-    if (!render_frame_host_->IsRenderFrameLive()) {
-      // Note: we don't call InitRenderView here because we are navigating away
-      // soon anyway, and we don't have the NavigationEntry for this host.
-      delegate_->CreateRenderViewForRenderManager(
-          render_frame_host_->render_view_host(), MSG_ROUTING_NONE,
-          MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame());
-    }
-
     // If the SiteInstance for the final URL doesn't match the one from the
     // speculatively created RenderFrameHost, create a new RenderFrameHost using
     // this new SiteInstance.
@@ -719,6 +730,16 @@
     }
     DCHECK(speculative_render_frame_host_);
     navigation_rfh = speculative_render_frame_host_.get();
+
+    // Check if our current RFH is live.
+    if (!render_frame_host_->IsRenderFrameLive()) {
+      // The current RFH is not live.  There's no reason to sit around with a
+      // sad tab or a newly created RFH while we wait for the navigation to
+      // complete. Just switch to the speculative RFH now and go back to non
+      // cross-navigating (Note that we don't care about on{before}unload
+      // handlers if the current RFH isn't live.)
+      CommitPending();
+    }
   }
   DCHECK(navigation_rfh &&
          (navigation_rfh == render_frame_host_.get() ||
@@ -811,6 +832,17 @@
   return true;
 }
 
+// static.
+bool RenderFrameHostManager::ResetProxiesInSiteInstance(int32 site_instance_id,
+                                                        FrameTreeNode* node) {
+  RenderFrameProxyHostMap::iterator iter =
+      node->render_manager()->proxy_hosts_.find(site_instance_id);
+  if (iter != node->render_manager()->proxy_hosts_.end())
+    iter->second->set_render_frame_proxy_created(false);
+
+  return true;
+}
+
 bool RenderFrameHostManager::ShouldTransitionCrossSite() {
   // False in the single-process mode, as it makes RVHs to accumulate
   // in swapped_out_hosts_.
@@ -1393,6 +1425,23 @@
   return proxy->GetRoutingID();
 }
 
+void RenderFrameHostManager::EnsureRenderViewInitialized(
+    FrameTreeNode* source,
+    RenderViewHostImpl* render_view_host,
+    SiteInstance* instance) {
+  DCHECK(frame_tree_node_->IsMainFrame());
+
+  if (render_view_host->IsRenderViewLive())
+    return;
+
+  // Recreate the opener chain.
+  int opener_route_id =
+      delegate_->CreateOpenerRenderViewsForRenderManager(instance);
+  RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
+  InitRenderView(render_view_host, opener_route_id, proxy->GetRoutingID(),
+                 source->IsMainFrame());
+}
+
 bool RenderFrameHostManager::InitRenderView(
     RenderViewHostImpl* render_view_host,
     int opener_route_id,
@@ -1454,6 +1503,8 @@
   if (existing_proxy) {
     proxy_routing_id = existing_proxy->GetRoutingID();
     CHECK_NE(proxy_routing_id, MSG_ROUTING_NONE);
+    if (!existing_proxy->is_render_frame_proxy_live())
+      existing_proxy->InitRenderFrameProxy();
   }
   return delegate_->CreateRenderFrameForRenderManager(render_frame_host,
                                                       parent_routing_id,
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index cc2e2d840..59b4d77 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -234,6 +234,13 @@
                                    pending_and_current_web_ui_.get();
   }
 
+  // PlzNavigate
+  // Returns the speculative WebUI for the navigation (a newly created one or
+  // the current one if it should be reused). If none is set returns nullptr.
+  WebUIImpl* speculative_web_ui_for_testing() const {
+    return should_reuse_web_ui_ ? web_ui_.get() : speculative_web_ui_.get();
+  }
+
   // Called when we want to instruct the renderer to navigate to the given
   // navigation entry. It may create a new RenderFrameHost or re-use an existing
   // one. The RenderFrameHost to navigate will be returned. Returns NULL if one
@@ -397,6 +404,10 @@
   void OnDidStartLoading();
   void OnDidStopLoading();
 
+  void EnsureRenderViewInitialized(FrameTreeNode* source,
+                                   RenderViewHostImpl* render_view_host,
+                                   SiteInstance* instance);
+
  private:
   friend class NavigatorTestWithBrowserSideNavigation;
   friend class RenderFrameHostManagerTest;
@@ -409,6 +420,10 @@
   // FrameTreeNode's RenderFrameHostManager.
   static bool ClearProxiesInSiteInstance(int32 site_instance_id,
                                          FrameTreeNode* node);
+  // Used with FrameTree::ForEach to reset initialized state of
+  // RenderFrameProxyHosts from a FrameTreeNode's RenderFrameHostManager.
+  static bool ResetProxiesInSiteInstance(int32 site_instance_id,
+                                         FrameTreeNode* node);
 
   // Returns whether this tab should transition to a new renderer for
   // cross-site URLs.  Enabled unless we see the --process-per-tab command line
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 079c6c4a..52d99af 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -941,8 +941,11 @@
   scoped_ptr<TestWebContents> web_contents(
       TestWebContents::Create(browser_context(), instance));
   RenderFrameHostManager* manager = web_contents->GetRenderManagerForTesting();
+  RenderFrameHostImpl* initial_rfh = manager->current_frame_host();
 
   EXPECT_FALSE(manager->current_host()->IsRenderViewLive());
+  EXPECT_FALSE(manager->web_ui());
+  EXPECT_TRUE(initial_rfh);
 
   const GURL kUrl("chrome://foo");
   NavigationEntryImpl entry(NULL /* instance */, -1 /* page_id */, kUrl,
@@ -955,6 +958,7 @@
   // RenderFrameHost was not live.  We test a case where it is live in
   // WebUIInNewTab.
   EXPECT_TRUE(host);
+  EXPECT_NE(initial_rfh, host);
   EXPECT_EQ(host, manager->current_frame_host());
   EXPECT_FALSE(GetPendingFrameHost(manager));
 
@@ -967,7 +971,12 @@
 
   // The Web UI is committed immediately because the RenderViewHost has not been
   // used yet. UpdateStateForNavigate() took the short cut path.
-  EXPECT_FALSE(manager->pending_web_ui());
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBrowserSideNavigation)) {
+    EXPECT_FALSE(manager->speculative_web_ui_for_testing());
+  } else {
+    EXPECT_FALSE(manager->pending_web_ui());
+  }
   EXPECT_TRUE(manager->web_ui());
 
   // Commit.
@@ -1410,15 +1419,25 @@
   RenderProcessHost::RendererClosedDetails details(
       base::TERMINATION_STATUS_PROCESS_CRASHED,
       0);
+  // TODO(nasko): Investigate whether this test can be made more realistic by
+  // not faking the notification and just doing the RenderProcessGone. This
+  // should also get rid of faking |set_render_view_created()| call below.
   NotificationService::current()->Notify(
       NOTIFICATION_RENDERER_PROCESS_CLOSED,
       Source<RenderProcessHost>(rvh1->GetProcess()),
       Details<RenderProcessHost::RendererClosedDetails>(&details));
   rvh1->set_render_view_created(false);
 
-  // Ensure that the swapped out RenderViewHost has been deleted.
-  EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
-      rvh1->GetSiteInstance()));
+  // Ensure that the RenderFrameProxyHost stays around and the RenderFrameProxy
+  // is deleted.
+  RenderFrameProxyHost* render_frame_proxy_host =
+      opener1_manager->GetRenderFrameProxyHost(rvh1->GetSiteInstance());
+  EXPECT_TRUE(render_frame_proxy_host);
+  EXPECT_FALSE(render_frame_proxy_host->is_render_frame_proxy_live());
+
+  // Expect the swapped out RVH to exist.
+  EXPECT_TRUE(opener1_manager->GetSwappedOutRenderViewHost(
+                  rvh1->GetSiteInstance()));
 
   // Reload the initial tab. This should recreate the opener's swapped out RVH
   // in the original SiteInstance.
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index 7366da77..5b74b1e 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -44,7 +44,9 @@
                                            FrameTreeNode* frame_tree_node)
     : routing_id_(site_instance->GetProcess()->GetNextRoutingID()),
       site_instance_(site_instance),
-      frame_tree_node_(frame_tree_node) {
+      process_(site_instance->GetProcess()),
+      frame_tree_node_(frame_tree_node),
+      render_frame_proxy_created_(false) {
   GetProcess()->AddRoute(routing_id_, this);
   CHECK(g_routing_id_frame_proxy_map.Get().insert(
       std::make_pair(
@@ -121,11 +123,12 @@
 }
 
 bool RenderFrameProxyHost::InitRenderFrameProxy() {
+  DCHECK(!render_frame_proxy_created_);
   // The process may (if we're sharing a process with another host that already
   // initialized it) or may not (we have our own process or the old process
   // crashed) have been initialized. Calling Init multiple times will be
   // ignored, so this is safe.
-  if (!site_instance_->GetProcess()->Init())
+  if (!GetProcess()->Init())
     return false;
 
   DCHECK(GetProcess()->HasConnection());
@@ -146,6 +149,7 @@
                                   frame_tree_node_
                                       ->current_replication_state()));
 
+  render_frame_proxy_created_ = true;
   return true;
 }
 
diff --git a/content/browser/frame_host/render_frame_proxy_host.h b/content/browser/frame_host/render_frame_proxy_host.h
index ed3235c..9647506 100644
--- a/content/browser/frame_host/render_frame_proxy_host.h
+++ b/content/browser/frame_host/render_frame_proxy_host.h
@@ -62,7 +62,7 @@
   ~RenderFrameProxyHost() override;
 
   RenderProcessHost* GetProcess() {
-    return site_instance_->GetProcess();
+    return process_;
   }
 
   // Initializes the object and creates the RenderFrameProxy in the process
@@ -106,6 +106,13 @@
   // action in another renderer process.
   void DisownOpener();
 
+  void set_render_frame_proxy_created(bool created) {
+    render_frame_proxy_created_ = created;
+  }
+
+  // Returns if the RenderFrameProxy for this host is alive.
+  bool is_render_frame_proxy_live() { return render_frame_proxy_created_; }
+
  private:
   // IPC Message handlers.
   void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
@@ -116,9 +123,18 @@
   // The SiteInstance this proxy is associated with.
   scoped_refptr<SiteInstance> site_instance_;
 
+  // The renderer process this RenderFrameHostProxy is associated with. It is
+  // equivalent to the result of site_instance_->GetProcess(), but that
+  // method has the side effect of creating the process if it doesn't exist.
+  // Cache a pointer to avoid unnecessary process creation.
+  RenderProcessHost* process_;
+
   // The node in the frame tree where this proxy is located.
   FrameTreeNode* frame_tree_node_;
 
+  // True if we have a live RenderFrameProxy for this host.
+  bool render_frame_proxy_created_;
+
   // When a RenderFrameHost is in a different process from its parent in the
   // frame tree, this class connects its associated RenderWidgetHostView
   // to this RenderFrameProxyHost, which corresponds to the same frame in the
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 04d6663..ebbea17c 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -107,7 +107,7 @@
 
 void RenderWidgetHostViewChildFrame::InitAsPopup(
     RenderWidgetHostView* parent_host_view,
-    const gfx::Rect& pos) {
+    const gfx::Rect& bounds) {
   NOTREACHED();
 }
 
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h
index e063eb9..84835a8 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -57,7 +57,7 @@
 
   // RenderWidgetHostViewBase implementation.
   void InitAsPopup(RenderWidgetHostView* parent_host_view,
-                   const gfx::Rect& pos) override;
+                   const gfx::Rect& bounds) override;
   void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
   void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
   void Blur() override;
@@ -120,8 +120,8 @@
 
   // RenderWidgetHostViewBase implementation.
 #if defined(OS_ANDROID)
-  virtual void LockCompositingSurface() override;
-  virtual void UnlockCompositingSurface() override;
+  void LockCompositingSurface() override;
+  void UnlockCompositingSurface() override;
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_WIN)
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index 075d4ff..17d22b6 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -218,7 +218,7 @@
 }
 
 void RenderWidgetHostViewGuest::InitAsPopup(
-    RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
+    RenderWidgetHostView* parent_host_view, const gfx::Rect& bounds) {
   // This should never get called.
   NOTREACHED();
 }
diff --git a/content/browser/frame_host/render_widget_host_view_guest.h b/content/browser/frame_host/render_widget_host_view_guest.h
index be07e97b..c5a6e72 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.h
+++ b/content/browser/frame_host/render_widget_host_view_guest.h
@@ -67,7 +67,7 @@
 
   // RenderWidgetHostViewBase implementation.
   void InitAsPopup(RenderWidgetHostView* parent_host_view,
-                   const gfx::Rect& pos) override;
+                   const gfx::Rect& bounds) override;
   void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
   void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
   void UpdateCursor(const WebCursor& cursor) override;
@@ -124,8 +124,8 @@
 #endif  // defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
 
 #if defined(OS_ANDROID)
-  virtual void LockCompositingSurface() override;
-  virtual void UnlockCompositingSurface() override;
+  void LockCompositingSurface() override;
+  void UnlockCompositingSurface() override;
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_WIN)
diff --git a/content/browser/gamepad/gamepad_platform_data_fetcher_android.h b/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
index 989a467..4acdfb3b 100644
--- a/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
+++ b/content/browser/gamepad/gamepad_platform_data_fetcher_android.h
@@ -21,12 +21,12 @@
 class GamepadPlatformDataFetcherAndroid : public GamepadDataFetcher {
  public:
   GamepadPlatformDataFetcherAndroid();
-  virtual ~GamepadPlatformDataFetcherAndroid();
+  ~GamepadPlatformDataFetcherAndroid() override;
 
-  virtual void PauseHint(bool paused) override;
+  void PauseHint(bool paused) override;
 
-  virtual void GetGamepadData(blink::WebGamepads* pads,
-                              bool devices_changed_hint) override;
+  void GetGamepadData(blink::WebGamepads* pads,
+                      bool devices_changed_hint) override;
 
   // Registers the JNI methods for GamepadsReader.
   static bool RegisterGamepadPlatformDataFetcherAndroid(JNIEnv* env);
diff --git a/content/browser/geolocation/location_provider_android.h b/content/browser/geolocation/location_provider_android.h
index e24f67c..9e0ad5f 100644
--- a/content/browser/geolocation/location_provider_android.h
+++ b/content/browser/geolocation/location_provider_android.h
@@ -17,17 +17,17 @@
 class LocationProviderAndroid : public LocationProviderBase {
  public:
   LocationProviderAndroid();
-  virtual ~LocationProviderAndroid();
+  ~LocationProviderAndroid() override;
 
   // Called by the AndroidLocationApiAdapter.
   void NotifyNewGeoposition(const Geoposition& position);
 
   // LocationProvider.
-  virtual bool StartProvider(bool high_accuracy) override;
-  virtual void StopProvider() override;
-  virtual void GetPosition(Geoposition* position) override;
-  virtual void RequestRefresh() override;
-  virtual void OnPermissionGranted() override;
+  bool StartProvider(bool high_accuracy) override;
+  void StopProvider() override;
+  void GetPosition(Geoposition* position) override;
+  void RequestRefresh() override;
+  void OnPermissionGranted() override;
 
  private:
   Geoposition last_position_;
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 0f01ec8..9606eb5 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -292,6 +292,21 @@
   return command_line.HasSwitch(switches::kForceGpuRasterization);
 }
 
+bool IsThreadedGpuRasterizationEnabled() {
+  if (!IsImplSidePaintingEnabled())
+    return false;
+
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+
+  if (command_line.HasSwitch(switches::kDisableThreadedGpuRasterization))
+    return false;
+  if (command_line.HasSwitch(switches::kEnableThreadedGpuRasterization))
+    return true;
+
+  return false;
+}
+
 bool UseSurfacesEnabled() {
 #if defined(OS_ANDROID)
   return false;
diff --git a/content/browser/gpu/compositor_util.h b/content/browser/gpu/compositor_util.h
index 6266f36e..16dca45c 100644
--- a/content/browser/gpu/compositor_util.h
+++ b/content/browser/gpu/compositor_util.h
@@ -42,6 +42,10 @@
 // Returns true if force-gpu-rasterization is on (via flags) for the renderer.
 CONTENT_EXPORT bool IsForceGpuRasterizationEnabled();
 
+// Returns true if threaded GPU rasterization is on (via flags) for the
+// renderer.
+CONTENT_EXPORT bool IsThreadedGpuRasterizationEnabled();
+
 // Returns the number of raster threads to use for compositing.
 CONTENT_EXPORT int NumberOfRendererRasterThreads();
 
diff --git a/content/browser/loader/navigation_url_loader_delegate.h b/content/browser/loader/navigation_url_loader_delegate.h
index 199f48a..f558c754 100644
--- a/content/browser/loader/navigation_url_loader_delegate.h
+++ b/content/browser/loader/navigation_url_loader_delegate.h
@@ -39,6 +39,12 @@
   // network error code for the failure.
   virtual void OnRequestFailed(int net_error) = 0;
 
+  // Called after the network request has begun on the IO thread at time
+  // |timestamp|. This is just a thread hop but is used to compare timing
+  // against the pre-PlzNavigate codepath which didn't start the network request
+  // until after the renderer was initialized.
+  virtual void OnRequestStarted(base::TimeTicks timestamp) = 0;
+
  protected:
   NavigationURLLoaderDelegate() {}
   virtual ~NavigationURLLoaderDelegate() {}
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index b6dbed0..949d630 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -73,4 +73,10 @@
   delegate_->OnRequestFailed(net_error);
 }
 
+void NavigationURLLoaderImpl::NotifyRequestStarted(base::TimeTicks timestamp) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  delegate_->OnRequestStarted(timestamp);
+}
+
 }  // namespace content
diff --git a/content/browser/loader/navigation_url_loader_impl.h b/content/browser/loader/navigation_url_loader_impl.h
index ecfd238..7dba1185 100644
--- a/content/browser/loader/navigation_url_loader_impl.h
+++ b/content/browser/loader/navigation_url_loader_impl.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "content/browser/loader/navigation_url_loader.h"
 
 namespace net {
@@ -50,6 +51,10 @@
   // Notifies the delegate the request failed to return a response.
   void NotifyRequestFailed(int net_error);
 
+  // Notifies the delegate the begin navigation request was handled and a
+  // potential first network request is about to be made.
+  void NotifyRequestStarted(base::TimeTicks timestamp);
+
   NavigationURLLoaderDelegate* delegate_;
 
   // |core_| is deleted on the IO thread in a subsequent task when the
diff --git a/content/browser/loader/navigation_url_loader_impl_core.cc b/content/browser/loader/navigation_url_loader_impl_core.cc
index 48845e8..c8e681e 100644
--- a/content/browser/loader/navigation_url_loader_impl_core.cc
+++ b/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/time/time.h"
 #include "content/browser/frame_host/navigation_request_info.h"
 #include "content/browser/loader/navigation_resource_handler.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -42,6 +43,11 @@
     ResourceRequestBody* request_body) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&NavigationURLLoaderImpl::NotifyRequestStarted, loader_,
+                 base::TimeTicks::Now()));
+
   ResourceDispatcherHostImpl::Get()->BeginNavigationRequest(
       resource_context, frame_tree_node_id,
       common_params, *request_info, request_body,
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index 097035c..745afe82 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -62,8 +62,7 @@
 class TestNavigationURLLoaderDelegate : public NavigationURLLoaderDelegate {
  public:
   TestNavigationURLLoaderDelegate()
-      : net_error_(0) {
-  }
+      : net_error_(0), on_request_handled_counter_(0) {}
 
   const net::RedirectInfo& redirect_info() const { return redirect_info_; }
   ResourceResponse* redirect_response() const {
@@ -72,6 +71,7 @@
   ResourceResponse* response() const { return response_.get(); }
   StreamHandle* body() const { return body_.get(); }
   int net_error() const { return net_error_; }
+  int on_request_handled_counter() const { return on_request_handled_counter_; }
 
   void WaitForRequestRedirected() {
     request_redirected_.reset(new base::RunLoop);
@@ -119,12 +119,18 @@
     request_failed_->Quit();
   }
 
+  void OnRequestStarted(base::TimeTicks timestamp) override {
+    ASSERT_FALSE(timestamp.is_null());
+    ++on_request_handled_counter_;
+  }
+
  private:
   net::RedirectInfo redirect_info_;
   scoped_refptr<ResourceResponse> redirect_response_;
   scoped_refptr<ResourceResponse> response_;
   scoped_ptr<StreamHandle> body_;
   int net_error_;
+  int on_request_handled_counter_;
 
   scoped_ptr<base::RunLoop> request_redirected_;
   scoped_ptr<base::RunLoop> response_started_;
@@ -222,6 +228,8 @@
   // Check the body is correct.
   EXPECT_EQ(net::URLRequestTestJob::test_data_1(),
             FetchURL(delegate.body()->GetURL()));
+
+  EXPECT_EQ(1, delegate.on_request_handled_counter());
 }
 
 // Tests that request failures are propagated correctly.
@@ -233,6 +241,7 @@
   // Wait for the request to fail as expected.
   delegate.WaitForRequestFailed();
   EXPECT_EQ(net::ERR_UNKNOWN_URL_SCHEME, delegate.net_error());
+  EXPECT_EQ(1, delegate.on_request_handled_counter());
 }
 
 // Test that redirects are sent to the delegate.
@@ -252,6 +261,7 @@
   EXPECT_EQ(net::URLRequestTestJob::test_url_2(),
             delegate.redirect_info().new_first_party_for_cookies);
   EXPECT_EQ(302, delegate.redirect_response()->head.headers->response_code());
+  EXPECT_EQ(1, delegate.on_request_handled_counter());
 
   // Wait for the response to complete.
   loader->FollowRedirect();
@@ -265,6 +275,8 @@
   EXPECT_TRUE(net::URLRequestTestJob::ProcessOnePendingMessage());
   EXPECT_EQ(net::URLRequestTestJob::test_data_2(),
             FetchURL(delegate.body()->GetURL()));
+
+  EXPECT_EQ(1, delegate.on_request_handled_counter());
 }
 
 // Tests that the destroying the loader cancels the request.
@@ -325,6 +337,7 @@
   // Wait for the request to now be aborted.
   delegate.WaitForRequestFailed();
   EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
+  EXPECT_EQ(1, delegate.on_request_handled_counter());
 }
 
 // Tests that, if the request is blocked by the ResourceDispatcherHostDelegate,
@@ -340,6 +353,7 @@
   // Wait for the request to fail as expected.
   delegate.WaitForRequestFailed();
   EXPECT_EQ(net::ERR_ABORTED, delegate.net_error());
+  EXPECT_EQ(1, delegate.on_request_handled_counter());
 
   host_.SetDelegate(nullptr);
 }
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 332b7ec..ddb8a09 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -979,7 +979,9 @@
   // When logging time-to-network only care about main frame and non-transfer
   // navigations.
   if (request_data.resource_type == RESOURCE_TYPE_MAIN_FRAME &&
-      request_data.transferred_request_request_id == -1) {
+      request_data.transferred_request_request_id == -1 &&
+      !base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBrowserSideNavigation)) {
     BrowserThread::PostTask(
         BrowserThread::UI,
         FROM_HERE,
diff --git a/content/browser/manifest/manifest_browsertest.cc b/content/browser/manifest/manifest_browsertest.cc
index 404831dd..b31d26a 100644
--- a/content/browser/manifest/manifest_browsertest.cc
+++ b/content/browser/manifest/manifest_browsertest.cc
@@ -281,4 +281,32 @@
   EXPECT_EQ(6u, console_error_count());
 }
 
+// If a page has a manifest and the page is navigated to a page without a
+// manifest, the page's manifest should be updated.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, Navigation) {
+  {
+    GURL test_url = GetTestUrl("manifest", "dummy-manifest.html");
+
+    TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+    shell()->LoadURL(test_url);
+    navigation_observer.Wait();
+
+    GetManifestAndWait();
+    EXPECT_FALSE(manifest().IsEmpty());
+    EXPECT_EQ(0u, console_error_count());
+  }
+
+  {
+    GURL test_url = GetTestUrl("manifest", "no-manifest.html");
+
+    TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
+    shell()->LoadURL(test_url);
+    navigation_observer.Wait();
+
+    GetManifestAndWait();
+    EXPECT_TRUE(manifest().IsEmpty());
+    EXPECT_EQ(0u, console_error_count());
+  }
+}
+
 } // namespace content
diff --git a/content/browser/media/OWNERS b/content/browser/media/OWNERS
index 00fcbc6..c64283a 100644
--- a/content/browser/media/OWNERS
+++ b/content/browser/media/OWNERS
@@ -1,11 +1,12 @@
 dalecurtis@chromium.org
 ddorwin@chromium.org
-perkj@chromium.org
 scherkus@chromium.org
-tommi@chromium.org
-vrk@chromium.org
 xhwang@chromium.org
 
+# WebRTC OWNERS.
+perkj@chromium.org
+tommi@chromium.org
+
 per-file midi_*=toyoshim@chromium.org
 
 # For changes related to the tab media indicators.
diff --git a/content/browser/media/android/browser_demuxer_android.cc b/content/browser/media/android/browser_demuxer_android.cc
index a0cf7f7d..ed46203 100644
--- a/content/browser/media/android/browser_demuxer_android.cc
+++ b/content/browser/media/android/browser_demuxer_android.cc
@@ -15,26 +15,25 @@
       : demuxer_(demuxer),
         demuxer_client_id_(demuxer_client_id) {}
 
-  virtual ~Internal() {
+  ~Internal() override {
     DCHECK(ClientIDExists()) << demuxer_client_id_;
     demuxer_->RemoveDemuxerClient(demuxer_client_id_);
   }
 
   // media::DemuxerAndroid implementation.
-  virtual void Initialize(media::DemuxerAndroidClient* client) override {
+  void Initialize(media::DemuxerAndroidClient* client) override {
     DCHECK(!ClientIDExists()) << demuxer_client_id_;
     demuxer_->AddDemuxerClient(demuxer_client_id_, client);
   }
 
-  virtual void RequestDemuxerData(media::DemuxerStream::Type type) override {
+  void RequestDemuxerData(media::DemuxerStream::Type type) override {
     DCHECK(ClientIDExists()) << demuxer_client_id_;
     demuxer_->Send(new MediaPlayerMsg_ReadFromDemuxer(
         demuxer_client_id_, type));
   }
 
-  virtual void RequestDemuxerSeek(
-      const base::TimeDelta& time_to_seek,
-      bool is_browser_seek) override {
+  void RequestDemuxerSeek(const base::TimeDelta& time_to_seek,
+                          bool is_browser_seek) override {
     DCHECK(ClientIDExists()) << demuxer_client_id_;
     demuxer_->Send(new MediaPlayerMsg_DemuxerSeekRequest(
         demuxer_client_id_, time_to_seek, is_browser_seek));
diff --git a/content/browser/media/android/browser_demuxer_android.h b/content/browser/media/android/browser_demuxer_android.h
index 1e7f799..407e0b3 100644
--- a/content/browser/media/android/browser_demuxer_android.h
+++ b/content/browser/media/android/browser_demuxer_android.h
@@ -21,9 +21,9 @@
   BrowserDemuxerAndroid();
 
   // BrowserMessageFilter overrides.
-  virtual void OverrideThreadForMessage(const IPC::Message& message,
-                                        BrowserThread::ID* thread) override;
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
+  void OverrideThreadForMessage(const IPC::Message& message,
+                                BrowserThread::ID* thread) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
 
   // Returns an uninitialized demuxer implementation associated with
   // |demuxer_client_id|, which can be used to communicate with the real demuxer
@@ -32,7 +32,7 @@
 
  protected:
   friend class base::RefCountedThreadSafe<BrowserDemuxerAndroid>;
-  virtual ~BrowserDemuxerAndroid();
+  ~BrowserDemuxerAndroid() override;
 
  private:
   class Internal;
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index 7f00e6a..55fbf55 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -149,6 +149,12 @@
   fullscreen_player_id_ = kInvalidMediaPlayerId;
   if (!player)
     return;
+
+#if defined(VIDEO_HOLE)
+  if (external_video_surface_container_)
+    external_video_surface_container_->OnFrameInfoUpdated();
+#endif  // defined(VIDEO_HOLE)
+
   if (release_media_player)
     ReleaseFullscreenPlayer(player);
   else
@@ -318,6 +324,9 @@
 }
 
 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
+  if (fullscreen_player_id_ != kInvalidMediaPlayerId)
+    return;
+
   if (external_video_surface_container_)
     external_video_surface_container_->OnFrameInfoUpdated();
 }
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h
index 3925eeb..e0a40132 100644
--- a/content/browser/media/android/browser_media_player_manager.h
+++ b/content/browser/media/android/browser_media_player_manager.h
@@ -54,7 +54,7 @@
 
   ContentViewCoreImpl* GetContentViewCore() const;
 
-  virtual ~BrowserMediaPlayerManager();
+  ~BrowserMediaPlayerManager() override;
 
   // Fullscreen video playback controls.
   virtual void ExitFullscreen(bool release_media_player);
@@ -68,32 +68,28 @@
   void ReleaseAllMediaPlayers();
 
   // media::MediaPlayerManager overrides.
-  virtual void OnTimeUpdate(
-      int player_id,
-      base::TimeDelta current_timestamp,
-      base::TimeTicks current_time_ticks) override;
-  virtual void OnMediaMetadataChanged(
-      int player_id,
-      base::TimeDelta duration,
-      int width,
-      int height,
-      bool success) override;
-  virtual void OnPlaybackComplete(int player_id) override;
-  virtual void OnMediaInterrupted(int player_id) override;
-  virtual void OnBufferingUpdate(int player_id, int percentage) override;
-  virtual void OnSeekComplete(
-      int player_id,
-      const base::TimeDelta& current_time) override;
-  virtual void OnError(int player_id, int error) override;
-  virtual void OnVideoSizeChanged(
-      int player_id, int width, int height) override;
-  virtual media::MediaResourceGetter* GetMediaResourceGetter() override;
-  virtual media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
-  virtual media::MediaPlayerAndroid* GetFullscreenPlayer() override;
-  virtual media::MediaPlayerAndroid* GetPlayer(int player_id) override;
-  virtual void RequestFullScreen(int player_id) override;
+  void OnTimeUpdate(int player_id,
+                    base::TimeDelta current_timestamp,
+                    base::TimeTicks current_time_ticks) override;
+  void OnMediaMetadataChanged(int player_id,
+                              base::TimeDelta duration,
+                              int width,
+                              int height,
+                              bool success) override;
+  void OnPlaybackComplete(int player_id) override;
+  void OnMediaInterrupted(int player_id) override;
+  void OnBufferingUpdate(int player_id, int percentage) override;
+  void OnSeekComplete(int player_id,
+                      const base::TimeDelta& current_time) override;
+  void OnError(int player_id, int error) override;
+  void OnVideoSizeChanged(int player_id, int width, int height) override;
+  media::MediaResourceGetter* GetMediaResourceGetter() override;
+  media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
+  media::MediaPlayerAndroid* GetFullscreenPlayer() override;
+  media::MediaPlayerAndroid* GetPlayer(int player_id) override;
+  void RequestFullScreen(int player_id) override;
 #if defined(VIDEO_HOLE)
-  virtual bool ShouldUseVideoOverlayForEmbeddedEncryptedVideo() override;
+  bool ShouldUseVideoOverlayForEmbeddedEncryptedVideo() override;
 
   void AttachExternalVideoSurface(int player_id, jobject surface);
   void DetachExternalVideoSurface(int player_id);
diff --git a/content/browser/media/android/media_resource_getter_impl.h b/content/browser/media/android/media_resource_getter_impl.h
index 4f0d2e8..9a55fcb7 100644
--- a/content/browser/media/android/media_resource_getter_impl.h
+++ b/content/browser/media/android/media_resource_getter_impl.h
@@ -40,30 +40,25 @@
                           storage::FileSystemContext* file_system_context,
                           int render_process_id,
                           int render_frame_id);
-  virtual ~MediaResourceGetterImpl();
+  ~MediaResourceGetterImpl() override;
 
   // media::MediaResourceGetter implementation.
   // Must be called on the UI thread.
-  virtual void GetAuthCredentials(
-      const GURL& url,
-      const GetAuthCredentialsCB& callback) override;
-  virtual void GetCookies(
-      const GURL& url,
-      const GURL& first_party_for_cookies,
-      const GetCookieCB& callback) override;
-  virtual void GetPlatformPathFromURL(
-      const GURL& url,
-      const GetPlatformPathCB& callback) override;
-  virtual void ExtractMediaMetadata(
-      const std::string& url,
-      const std::string& cookies,
-      const std::string& user_agent,
-      const ExtractMediaMetadataCB& callback) override;
-  virtual void ExtractMediaMetadata(
-      const int fd,
-      const int64 offset,
-      const int64 size,
-      const ExtractMediaMetadataCB& callback) override;
+  void GetAuthCredentials(const GURL& url,
+                          const GetAuthCredentialsCB& callback) override;
+  void GetCookies(const GURL& url,
+                  const GURL& first_party_for_cookies,
+                  const GetCookieCB& callback) override;
+  void GetPlatformPathFromURL(const GURL& url,
+                              const GetPlatformPathCB& callback) override;
+  void ExtractMediaMetadata(const std::string& url,
+                            const std::string& cookies,
+                            const std::string& user_agent,
+                            const ExtractMediaMetadataCB& callback) override;
+  void ExtractMediaMetadata(const int fd,
+                            const int64 offset,
+                            const int64 size,
+                            const ExtractMediaMetadataCB& callback) override;
 
   static bool RegisterMediaResourceGetter(JNIEnv* env);
 
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index 0ddcf269..bb546c2 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -451,7 +451,7 @@
 void DesktopCaptureDevice::AllocateAndStart(
     const media::VideoCaptureParams& params,
     scoped_ptr<Client> client) {
-  thread_.message_loop_proxy()->PostTask(
+  thread_.task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&Core::AllocateAndStart, base::Unretained(core_.get()), params,
                  base::Passed(&client)));
@@ -459,16 +459,20 @@
 
 void DesktopCaptureDevice::StopAndDeAllocate() {
   if (core_) {
-    thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, core_.release());
+    thread_.task_runner()->DeleteSoon(FROM_HERE, core_.release());
     thread_.Stop();
   }
 }
 
 void DesktopCaptureDevice::SetNotificationWindowId(
     gfx::NativeViewId window_id) {
-  thread_.message_loop_proxy()->PostTask(
+  // This may be called after the capturer has been stopped.
+  if (!core_)
+    return;
+  thread_.task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&Core::SetNotificationWindowId, base::Unretained(core_.get()),
+      base::Bind(&Core::SetNotificationWindowId,
+                 base::Unretained(core_.get()),
                  window_id));
 }
 
@@ -485,7 +489,7 @@
 
   thread_.StartWithOptions(base::Thread::Options(thread_type, 0));
 
-  core_.reset(new Core(thread_.message_loop_proxy(), capturer.Pass(), type));
+  core_.reset(new Core(thread_.task_runner(), capturer.Pass(), type));
 }
 
 }  // namespace content
diff --git a/content/browser/media/encrypted_media_browsertest.cc b/content/browser/media/encrypted_media_browsertest.cc
index 9e02339..7d58aca 100644
--- a/content/browser/media/encrypted_media_browsertest.cc
+++ b/content/browser/media/encrypted_media_browsertest.cc
@@ -129,7 +129,7 @@
   }
 
 #if defined(OS_ANDROID)
-  virtual void SetUpCommandLine(base::CommandLine* command_line) override {
+  void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(
         switches::kDisableGestureRequirementForMediaPlayback);
   }
diff --git a/content/browser/media/media_source_browsertest.cc b/content/browser/media/media_source_browsertest.cc
index 54c80d5..191ff66 100644
--- a/content/browser/media/media_source_browsertest.cc
+++ b/content/browser/media/media_source_browsertest.cc
@@ -49,7 +49,7 @@
   }
 
 #if defined(OS_ANDROID)
-  virtual void SetUpCommandLine(base::CommandLine* command_line) override {
+  void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(
         switches::kDisableGestureRequirementForMediaPlayback);
   }
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index 617c66b..91e013b 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -46,6 +46,7 @@
     case SERVICE_WORKER_ERROR_IPC_FAILED:
     case SERVICE_WORKER_ERROR_NETWORK:
     case SERVICE_WORKER_ERROR_SECURITY:
+    case SERVICE_WORKER_ERROR_STATE:
       status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
       break;
   }
@@ -93,6 +94,7 @@
     case SERVICE_WORKER_ERROR_NETWORK:
     case SERVICE_WORKER_ERROR_SECURITY:
     case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+    case SERVICE_WORKER_ERROR_STATE:
       status = PERSISTENT_NOTIFICATION_STATUS_SERVICE_WORKER_ERROR;
       break;
     case SERVICE_WORKER_OK:
diff --git a/content/browser/push_messaging/push_messaging_message_filter.cc b/content/browser/push_messaging/push_messaging_message_filter.cc
index 8d69c5ce..bec7730 100644
--- a/content/browser/push_messaging/push_messaging_message_filter.cc
+++ b/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -412,6 +412,7 @@
     case SERVICE_WORKER_ERROR_NETWORK:
     case SERVICE_WORKER_ERROR_SECURITY:
     case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+    case SERVICE_WORKER_ERROR_STATE:
       NOTREACHED() << "Got unexpected error code: " << service_worker_status
                    << " " << ServiceWorkerStatusToString(service_worker_status);
       DidUnregister(request_id, PUSH_UNREGISTRATION_STATUS_UNKNOWN_ERROR);
@@ -527,6 +528,7 @@
     case SERVICE_WORKER_ERROR_NETWORK:
     case SERVICE_WORKER_ERROR_SECURITY:
     case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+    case SERVICE_WORKER_ERROR_STATE:
       NOTREACHED() << "Got unexpected error code: " << service_worker_status
                    << " " << ServiceWorkerStatusToString(service_worker_status);
       get_status = PUSH_GETREGISTRATION_STATUS_SERVICE_WORKER_ERROR;
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc
index 2fe0538..085ee7d21 100644
--- a/content/browser/push_messaging/push_messaging_router.cc
+++ b/content/browser/push_messaging/push_messaging_router.cc
@@ -114,6 +114,7 @@
     case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
     case SERVICE_WORKER_ERROR_NETWORK:
     case SERVICE_WORKER_ERROR_SECURITY:
+    case SERVICE_WORKER_ERROR_STATE:
       NOTREACHED() << "Got unexpected error code: " << service_worker_status
                    << " " << ServiceWorkerStatusToString(service_worker_status);
       delivery_status = PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR;
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index c32fc32..8b2f7b9 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -80,7 +80,7 @@
     main_thread_ = base::MessageLoopProxy::current();
   }
 
-  virtual void SwapBuffers(cc::CompositorFrame* frame) override {
+  void SwapBuffers(cc::CompositorFrame* frame) override {
     GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info);
     DCHECK(frame->gl_frame_data->sub_buffer_rect ==
            gfx::Rect(frame->gl_frame_data->size));
@@ -88,7 +88,7 @@
     client_->DidSwapBuffers();
   }
 
-  virtual bool BindToClient(cc::OutputSurfaceClient* client) override {
+  bool BindToClient(cc::OutputSurfaceClient* client) override {
     if (!OutputSurface::BindToClient(client))
       return false;
 
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 09c8b8a..dbcdc66 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -44,7 +44,7 @@
       public ui::WindowAndroidCompositor {
  public:
   CompositorImpl(CompositorClient* client, gfx::NativeWindow root_window);
-  virtual ~CompositorImpl();
+  ~CompositorImpl() override;
 
   static bool IsInitialized();
 
@@ -52,53 +52,51 @@
 
  private:
   // Compositor implementation.
-  virtual void SetRootLayer(scoped_refptr<cc::Layer> root) override;
-  virtual void SetSurface(jobject surface) override;
-  virtual void SetVisible(bool visible) override;
-  virtual void setDeviceScaleFactor(float factor) override;
-  virtual void SetWindowBounds(const gfx::Size& size) override;
-  virtual void SetHasTransparentBackground(bool flag) override;
-  virtual void SetNeedsComposite() override;
-  virtual ui::UIResourceProvider& GetUIResourceProvider() override;
-  virtual ui::ResourceManager& GetResourceManager() override;
+  void SetRootLayer(scoped_refptr<cc::Layer> root) override;
+  void SetSurface(jobject surface) override;
+  void SetVisible(bool visible) override;
+  void setDeviceScaleFactor(float factor) override;
+  void SetWindowBounds(const gfx::Size& size) override;
+  void SetHasTransparentBackground(bool flag) override;
+  void SetNeedsComposite() override;
+  ui::UIResourceProvider& GetUIResourceProvider() override;
+  ui::ResourceManager& GetResourceManager() override;
 
   // LayerTreeHostClient implementation.
-  virtual void WillBeginMainFrame(int frame_id) override {}
-  virtual void DidBeginMainFrame() override {}
-  virtual void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
-  virtual void Layout() override;
-  virtual void ApplyViewportDeltas(
-      const gfx::Vector2d& inner_delta,
-      const gfx::Vector2d& outer_delta,
-      const gfx::Vector2dF& elastic_overscroll_delta,
-      float page_scale,
-      float top_controls_delta) override {}
-  virtual void ApplyViewportDeltas(
-      const gfx::Vector2d& scroll_delta,
-      float page_scale,
-      float top_controls_delta) override {}
-  virtual void RequestNewOutputSurface() override;
-  virtual void DidInitializeOutputSurface() override {}
-  virtual void DidFailToInitializeOutputSurface() override;
-  virtual void WillCommit() override {}
-  virtual void DidCommit() override;
-  virtual void DidCommitAndDrawFrame() override {}
-  virtual void DidCompleteSwapBuffers() override;
-  virtual void DidCompletePageScaleAnimation() override {}
+  void WillBeginMainFrame() override {}
+  void DidBeginMainFrame() override {}
+  void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
+  void Layout() override;
+  void ApplyViewportDeltas(const gfx::Vector2d& inner_delta,
+                           const gfx::Vector2d& outer_delta,
+                           const gfx::Vector2dF& elastic_overscroll_delta,
+                           float page_scale,
+                           float top_controls_delta) override {}
+  void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
+                           float page_scale,
+                           float top_controls_delta) override {}
+  void RequestNewOutputSurface() override;
+  void DidInitializeOutputSurface() override {}
+  void DidFailToInitializeOutputSurface() override;
+  void WillCommit() override {}
+  void DidCommit() override;
+  void DidCommitAndDrawFrame() override {}
+  void DidCompleteSwapBuffers() override;
+  void DidCompletePageScaleAnimation() override {}
 
   // LayerTreeHostSingleThreadClient implementation.
-  virtual void ScheduleComposite() override;
-  virtual void ScheduleAnimation() override;
-  virtual void DidPostSwapBuffers() override;
-  virtual void DidAbortSwapBuffers() override;
+  void ScheduleComposite() override;
+  void ScheduleAnimation() override;
+  void DidPostSwapBuffers() override;
+  void DidAbortSwapBuffers() override;
 
   // WindowAndroidCompositor implementation.
-  virtual void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) override;
-  virtual void RequestCopyOfOutputOnRootLayer(
+  void AttachLayerForReadback(scoped_refptr<cc::Layer> layer) override;
+  void RequestCopyOfOutputOnRootLayer(
       scoped_ptr<cc::CopyOutputRequest> request) override;
-  virtual void OnVSync(base::TimeTicks frame_time,
-                       base::TimeDelta vsync_period) override;
-  virtual void SetNeedsAnimate() override;
+  void OnVSync(base::TimeTicks frame_time,
+               base::TimeDelta vsync_period) override;
+  void SetNeedsAnimate() override;
 
   void SetWindowSurface(ANativeWindow* window);
 
diff --git a/content/browser/renderer_host/input/input_router_config_helper.cc b/content/browser/renderer_host/input/input_router_config_helper.cc
index 57ad49e..3ed530f 100644
--- a/content/browser/renderer_host/input/input_router_config_helper.cc
+++ b/content/browser/renderer_host/input/input_router_config_helper.cc
@@ -95,28 +95,12 @@
 
 #endif
 
-TouchEventQueue::TouchScrollingMode GetTouchScrollingMode() {
-  std::string modeString =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kTouchScrollingMode);
-  if (modeString == switches::kTouchScrollingModeAsyncTouchmove)
-    return TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE;
-  if (modeString == switches::kTouchScrollingModeSyncTouchmove)
-    return TouchEventQueue::TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE;
-  if (modeString == switches::kTouchScrollingModeTouchcancel)
-    return TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL;
-  if (!modeString.empty())
-    LOG(ERROR) << "Invalid --touch-scrolling-mode option: " << modeString;
-  return TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT;
-}
-
 }  // namespace
 
 InputRouterImpl::Config GetInputRouterConfigForPlatform() {
   InputRouterImpl::Config config;
   config.gesture_config = GetGestureEventQueueConfig();
   config.touch_config = GetTouchEventQueueConfig();
-  config.touch_config.touch_scrolling_mode = GetTouchScrollingMode();
   return config;
 }
 
diff --git a/content/browser/renderer_host/input/motion_event_android.h b/content/browser/renderer_host/input/motion_event_android.h
index 4af9f72..f4e8c94 100644
--- a/content/browser/renderer_host/input/motion_event_android.h
+++ b/content/browser/renderer_host/input/motion_event_android.h
@@ -55,35 +55,35 @@
                      jfloat raw_offset_y_pixels,
                      const Pointer& pointer0,
                      const Pointer& pointer1);
-  virtual ~MotionEventAndroid();
+  ~MotionEventAndroid() override;
 
   // ui::MotionEvent methods.
-  virtual int GetId() const override;
-  virtual Action GetAction() const override;
-  virtual int GetActionIndex() const override;
-  virtual size_t GetPointerCount() const override;
-  virtual int GetPointerId(size_t pointer_index) const override;
-  virtual float GetX(size_t pointer_index) const override;
-  virtual float GetY(size_t pointer_index) const override;
-  virtual float GetRawX(size_t pointer_index) const override;
-  virtual float GetRawY(size_t pointer_index) const override;
-  virtual float GetTouchMajor(size_t pointer_index) const override;
-  virtual float GetTouchMinor(size_t pointer_index) const override;
-  virtual float GetOrientation(size_t pointer_index) const override;
-  virtual float GetPressure(size_t pointer_index) const override;
-  virtual base::TimeTicks GetEventTime() const override;
-  virtual size_t GetHistorySize() const override;
-  virtual base::TimeTicks GetHistoricalEventTime(
+  int GetId() const override;
+  Action GetAction() const override;
+  int GetActionIndex() const override;
+  size_t GetPointerCount() const override;
+  int GetPointerId(size_t pointer_index) const override;
+  float GetX(size_t pointer_index) const override;
+  float GetY(size_t pointer_index) const override;
+  float GetRawX(size_t pointer_index) const override;
+  float GetRawY(size_t pointer_index) const override;
+  float GetTouchMajor(size_t pointer_index) const override;
+  float GetTouchMinor(size_t pointer_index) const override;
+  float GetOrientation(size_t pointer_index) const override;
+  float GetPressure(size_t pointer_index) const override;
+  base::TimeTicks GetEventTime() const override;
+  size_t GetHistorySize() const override;
+  base::TimeTicks GetHistoricalEventTime(
       size_t historical_index) const override;
-  virtual float GetHistoricalTouchMajor(size_t pointer_index,
-                                        size_t historical_index) const override;
-  virtual float GetHistoricalX(size_t pointer_index,
-                               size_t historical_index) const override;
-  virtual float GetHistoricalY(size_t pointer_index,
-                               size_t historical_index) const override;
-  virtual ToolType GetToolType(size_t pointer_index) const override;
-  virtual int GetButtonState() const override;
-  virtual int GetFlags() const override;
+  float GetHistoricalTouchMajor(size_t pointer_index,
+                                size_t historical_index) const override;
+  float GetHistoricalX(size_t pointer_index,
+                       size_t historical_index) const override;
+  float GetHistoricalY(size_t pointer_index,
+                       size_t historical_index) const override;
+  ToolType GetToolType(size_t pointer_index) const override;
+  int GetButtonState() const override;
+  int GetFlags() const override;
 
   static bool RegisterMotionEventAndroid(JNIEnv* env);
 
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_android.h b/content/browser/renderer_host/input/synthetic_gesture_target_android.h
index 571fcbd..afd124e5 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_android.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_android.h
@@ -18,28 +18,28 @@
   SyntheticGestureTargetAndroid(
       RenderWidgetHostImpl* host,
       base::android::ScopedJavaLocalRef<jobject> touch_event_synthesizer);
-  virtual ~SyntheticGestureTargetAndroid();
+  ~SyntheticGestureTargetAndroid() override;
 
   static bool RegisterTouchEventSynthesizer(JNIEnv* env);
 
   // SyntheticGestureTargetBase:
-  virtual void DispatchWebTouchEventToPlatform(
+  void DispatchWebTouchEventToPlatform(
       const blink::WebTouchEvent& web_touch,
       const ui::LatencyInfo& latency_info) override;
-  virtual void DispatchWebMouseWheelEventToPlatform(
+  void DispatchWebMouseWheelEventToPlatform(
       const blink::WebMouseWheelEvent& web_wheel,
       const ui::LatencyInfo& latency_info) override;
-  virtual void DispatchWebMouseEventToPlatform(
+  void DispatchWebMouseEventToPlatform(
       const blink::WebMouseEvent& web_mouse,
       const ui::LatencyInfo& latency_info) override;
 
   // SyntheticGestureTarget:
-  virtual SyntheticGestureParams::GestureSourceType
-      GetDefaultSyntheticGestureSourceType() const override;
+  SyntheticGestureParams::GestureSourceType
+  GetDefaultSyntheticGestureSourceType() const override;
 
-  virtual float GetTouchSlopInDips() const override;
+  float GetTouchSlopInDips() const override;
 
-  virtual float GetMinScalingSpanInDips() const override;
+  float GetMinScalingSpanInDips() const override;
 
  private:
   // Enum values below need to be kept in sync with TouchEventSynthesizer.java
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index ea4649e..38718b3f 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -179,14 +179,8 @@
 
   EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchstart"));
   EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchmove"));
-  if (TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT ==
-      TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL) {
-    EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchend"));
-    EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchcancel"));
-  } else {
-    EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchend"));
-    EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchcancel"));
-  }
+  EXPECT_EQ(1, ExecuteScriptAndExtractInt("eventCounts.touchend"));
+  EXPECT_EQ(0, ExecuteScriptAndExtractInt("eventCounts.touchcancel"));
 }
 
 // Verify that touching a touch-action: none region disables scrolling and
diff --git a/content/browser/renderer_host/input/touch_event_queue.cc b/content/browser/renderer_host/input/touch_event_queue.cc
index 013ddd0..6ac63ce 100644
--- a/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/content/browser/renderer_host/input/touch_event_queue.cc
@@ -357,8 +357,7 @@
 };
 
 TouchEventQueue::Config::Config()
-    : touch_scrolling_mode(TOUCH_SCROLLING_MODE_DEFAULT),
-      touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
+    : touch_ack_timeout_delay(base::TimeDelta::FromMilliseconds(200)),
       touch_ack_timeout_supported(false) {
 }
 
@@ -371,8 +370,7 @@
       drop_remaining_touches_in_sequence_(false),
       touchmove_slop_suppressor_(new TouchMoveSlopSuppressor),
       send_touch_events_async_(false),
-      last_sent_touch_timestamp_sec_(0),
-      touch_scrolling_mode_(config.touch_scrolling_mode) {
+      last_sent_touch_timestamp_sec_(0) {
   DCHECK(client);
   if (config.touch_ack_timeout_supported) {
     timeout_handler_.reset(
@@ -541,8 +539,7 @@
       DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
           <<  "A touch handler should be offered a touchmove before scrolling.";
     }
-    if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE &&
-        !drop_remaining_touches_in_sequence_ &&
+    if (!drop_remaining_touches_in_sequence_ &&
         touch_consumer_states_.is_empty()) {
       // If no touch points have a consumer, prevent all subsequent touch events
       // received during the scroll from reaching the renderer. This ensures
@@ -552,60 +549,26 @@
       drop_remaining_touches_in_sequence_ = true;
     }
 
-    if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
-      pending_async_touchmove_.reset();
+    pending_async_touchmove_.reset();
 
     return;
   }
 
-  if (gesture_event.event.type != blink::WebInputEvent::GestureScrollUpdate)
-    return;
-
-  if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
+  if (gesture_event.event.type == blink::WebInputEvent::GestureScrollUpdate)
     send_touch_events_async_ = true;
-
-  if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL)
-    return;
-
-  // We assume that scroll events are generated synchronously from
-  // dispatching a touch event ack. This allows us to generate a synthetic
-  // cancel event that has the same touch ids as the touch event that
-  // is being acked. Otherwise, we don't perform the touch-cancel optimization.
-  if (!dispatching_touch_ack_)
-    return;
-
-  if (drop_remaining_touches_in_sequence_)
-    return;
-
-  drop_remaining_touches_in_sequence_ = true;
-
-  // Fake a TouchCancel to cancel the touch points of the touch event
-  // that is currently being acked.
-  // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we
-  // are in the scope of PopTouchEventToClient() and that no touch event
-  // in the queue is waiting for ack from renderer. So we can just insert
-  // the touch cancel at the beginning of the queue.
-  touch_queue_.push_front(new CoalescedWebTouchEvent(
-      ObtainCancelEventForTouchEvent(
-          dispatching_touch_ack_->coalesced_event()), true));
 }
 
 void TouchEventQueue::OnGestureEventAck(
     const GestureEventWithLatencyInfo& event,
     InputEventAckState ack_result) {
-  if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
-    return;
-
-  if (event.event.type != blink::WebInputEvent::GestureScrollUpdate)
-    return;
-
   // Throttle sending touchmove events as long as the scroll events are handled.
   // Note that there's no guarantee that this ACK is for the most recent
   // gesture event (or even part of the current sequence).  Worst case, the
   // delay in updating the absorption state will result in minor UI glitches.
   // A valid |pending_async_touchmove_| will be flushed when the next event is
   // forwarded.
-  send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
+  if (event.event.type == blink::WebInputEvent::GestureScrollUpdate)
+    send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
 }
 
 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
@@ -774,10 +737,9 @@
         touch_consumer_states_.clear_bit(point.id);
     }
   } else if (event.type == WebInputEvent::TouchStart) {
-    if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE &&
-        ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
+    if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
       send_touch_events_async_ = false;
-    }
+
     for (unsigned i = 0; i < event.touchesLength; ++i) {
       const WebTouchPoint& point = event.touches[i];
       if (point.state == WebTouchPoint::StatePressed) {
diff --git a/content/browser/renderer_host/input/touch_event_queue.h b/content/browser/renderer_host/input/touch_event_queue.h
index cdd5d29..584935f 100644
--- a/content/browser/renderer_host/input/touch_event_queue.h
+++ b/content/browser/renderer_host/input/touch_event_queue.h
@@ -38,31 +38,9 @@
 // A queue for throttling and coalescing touch-events.
 class CONTENT_EXPORT TouchEventQueue {
  public:
-  // Different ways of dealing with touch events during scrolling.
-  // TODO(rbyers): Remove this once we're confident that touch move absorption
-  // is OK. http://crbug.com/350430
-  enum TouchScrollingMode {
-    // Send a touchcancel on scroll start and no further touch events for the
-    // duration of the scroll.  Chrome Android's traditional behavior.
-    TOUCH_SCROLLING_MODE_TOUCHCANCEL,
-    // Send touchmove events throughout a scroll, blocking on each ACK and
-    // using the disposition to determine whether a scroll update should be
-    // sent.  Mobile Safari's default overflow scroll behavior.
-    TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE,
-    // Send touchmove events throughout a scroll, but throttle sending and
-    // ignore the ACK as long as scrolling remains possible.  Unconsumed scroll
-    // events return touchmove events to being dispatched synchronously.
-    TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE,
-    TOUCH_SCROLLING_MODE_DEFAULT = TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE
-  };
-
   struct CONTENT_EXPORT Config {
     Config();
 
-    // Determines the type of touch scrolling.
-    // Defaults to TouchEventQueue:::TOUCH_SCROLLING_MODE_DEFAULT.
-    TouchEventQueue::TouchScrollingMode touch_scrolling_mode;
-
     // Controls whether touch ack timeouts will trigger touch cancellation.
     // Defaults to 200ms.
     base::TimeDelta touch_ack_timeout_delay;
@@ -212,8 +190,7 @@
   // this is a stricter condition than an empty |touch_consumer_states_|, as it
   // also prevents forwarding of touchstart events for new pointers in the
   // current sequence. This is only used when the event is synthetically
-  // cancelled after a touch timeout, or after a scroll event when the
-  // mode is TOUCH_SCROLLING_MODE_TOUCHCANCEL.
+  // cancelled after a touch timeout.
   bool drop_remaining_touches_in_sequence_;
 
   // Optional handler for timed-out touch event acks.
@@ -232,11 +209,6 @@
   scoped_ptr<TouchEventWithLatencyInfo> pending_async_touchmove_;
   double last_sent_touch_timestamp_sec_;
 
-  // How touch events are handled during scrolling.  For now this is a global
-  // setting for experimentation, but we may evolve it into an app-controlled
-  // mode.
-  const TouchScrollingMode touch_scrolling_mode_;
-
   // Event is saved to compare pointer positions for new touchmove events.
   scoped_ptr<blink::WebTouchEvent> last_sent_touchevent_;
 
diff --git a/content/browser/renderer_host/input/touch_event_queue_unittest.cc b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
index afdc436..5af6743 100644
--- a/content/browser/renderer_host/input/touch_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
@@ -37,13 +37,14 @@
       : sent_event_count_(0),
         acked_event_count_(0),
         last_acked_event_state_(INPUT_EVENT_ACK_STATE_UNKNOWN),
-        slop_length_dips_(0),
-        touch_scrolling_mode_(TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT) {}
+        slop_length_dips_(0) {}
 
   ~TouchEventQueueTest() override {}
 
   // testing::Test
-  void SetUp() override { ResetQueueWithConfig(CreateConfig()); }
+  void SetUp() override {
+    ResetQueueWithConfig(TouchEventQueue::Config());
+  }
 
   void TearDown() override { queue_.reset(); }
 
@@ -78,23 +79,12 @@
   }
 
  protected:
-  TouchEventQueue::Config CreateConfig() {
-    TouchEventQueue::Config config;
-    config.touch_scrolling_mode = touch_scrolling_mode_;
-    return config;
-  }
-
-  void SetTouchScrollingMode(TouchEventQueue::TouchScrollingMode mode) {
-    touch_scrolling_mode_ = mode;
-    ResetQueueWithConfig(CreateConfig());
-  }
-
   void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
     slop_length_dips_ = slop_length_dips;
   }
 
   void SetUpForTimeoutTesting(base::TimeDelta timeout_delay) {
-    TouchEventQueue::Config config = CreateConfig();
+    TouchEventQueue::Config config;
     config.touch_ack_timeout_delay = timeout_delay;
     config.touch_ack_timeout_supported = true;
     ResetQueueWithConfig(config);
@@ -304,7 +294,6 @@
   scoped_ptr<InputEventAckState> sync_ack_result_;
   double slop_length_dips_;
   gfx::PointF anchor_;
-  TouchEventQueue::TouchScrollingMode touch_scrolling_mode_;
   base::MessageLoopForUI message_loop_;
 };
 
@@ -988,140 +977,6 @@
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
 }
 
-// Tests that no TouchEvents are sent to renderer during scrolling.
-TEST_F(TouchEventQueueTest, TouchCancelOnScroll) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL);
-  // Queue a TouchStart.
-  PressTouchPoint(0, 1);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
-  MoveTouchPoint(0, 20, 5);
-  EXPECT_EQ(1U, queued_event_count());
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-
-  MoveTouchPoint(0, 30, 15);
-  EXPECT_EQ(2U, queued_event_count());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-
-  // Queue another TouchStart.
-  PressTouchPoint(20, 20);
-  EXPECT_EQ(3U, queued_event_count());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type);
-
-  WebGestureEvent followup_scroll;
-  followup_scroll.type = WebInputEvent::GestureScrollBegin;
-  SetFollowupEvent(followup_scroll);
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(2U, queued_event_count());
-  EXPECT_TRUE(sent_event().cancelable);
-  EXPECT_EQ(WebInputEvent::TouchMove, sent_event().type);
-
-  // GestureScrollUpdate inserts a synthetic TouchCancel before the TouchStart.
-  followup_scroll.type = WebInputEvent::GestureScrollUpdate;
-  SetFollowupEvent(followup_scroll);
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(2U, queued_event_count());
-  EXPECT_EQ(WebInputEvent::TouchCancel, sent_event().type);
-  EXPECT_FALSE(sent_event().cancelable);
-  EXPECT_EQ(WebInputEvent::TouchStart, latest_event().type);
-
-  // Acking the TouchCancel will result in dispatch of the next TouchStart.
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  // The synthetic TouchCancel should not reach client, only the TouchStart.
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(WebInputEvent::TouchStart, acked_event().type);
-
-  // TouchMove should not be sent to the renderer.
-  MoveTouchPoint(0, 30, 5);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
-  // GestureScrollUpdates should not change affect touch forwarding.
-  SendGestureEvent(WebInputEvent::GestureScrollUpdate);
-
-  // TouchEnd should not be sent to the renderer.
-  ReleaseTouchPoint(0);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
-  ReleaseTouchPoint(0);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
-  // Touch events from a new gesture sequence should be forwarded normally.
-  PressTouchPoint(80, 10);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
-  MoveTouchPoint(0, 80, 20);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
-  ReleaseTouchPoint(0);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-}
-
-// Tests that a scroll event will not insert a synthetic TouchCancel if there
-// was no consumer for the current touch sequence.
-TEST_F(TouchEventQueueTest, NoTouchCancelOnScrollIfNoConsumer) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL);
-
-  // Queue a TouchStart.
-  PressTouchPoint(0, 1);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
-
-  // Queue a TouchMove that turns into a GestureScrollBegin.
-  WebGestureEvent followup_scroll;
-  followup_scroll.type = WebInputEvent::GestureScrollBegin;
-  SetFollowupEvent(followup_scroll);
-  MoveTouchPoint(0, 20, 5);
-
-  // The TouchMove has no consumer, and should be ack'ed immediately. However,
-  // *no* synthetic TouchCancel should be inserted as the touch sequence
-  // had no consumer.
-  EXPECT_EQ(0U, queued_event_count());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(0U, queued_event_count());
-  EXPECT_EQ(WebInputEvent::TouchStart, sent_event().type);
-
-  // Subsequent TouchMove's should not be sent to the renderer.
-  MoveTouchPoint(0, 30, 5);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
-  // TouchEnd should not be sent to the renderer.
-  ReleaseTouchPoint(0);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_EQ(0U, GetAndResetSentEventCount());
-  EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
-
-  // Touch events from a new gesture sequence should be forwarded normally.
-  PressTouchPoint(80, 10);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetAckedEventCount());
-}
-
 // Tests that IsTouchStartPendingAck works correctly.
 TEST_F(TouchEventQueueTest, PendingStart) {
 
@@ -1714,31 +1569,7 @@
   EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state());
 }
 
-TEST_F(TouchEventQueueTest, SyncTouchMoveDoesntCancelTouchOnScroll) {
- SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE);
- // Queue a TouchStart.
- PressTouchPoint(0, 1);
- EXPECT_EQ(1U, GetAndResetSentEventCount());
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
-
- MoveTouchPoint(0, 20, 5);
- EXPECT_EQ(1U, queued_event_count());
- EXPECT_EQ(1U, GetAndResetSentEventCount());
-
- // GestureScrollBegin doesn't insert a synthetic TouchCancel.
- WebGestureEvent followup_scroll;
- followup_scroll.type = WebInputEvent::GestureScrollBegin;
- SetFollowupEvent(followup_scroll);
- SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- EXPECT_EQ(0U, GetAndResetSentEventCount());
- EXPECT_EQ(1U, GetAndResetAckedEventCount());
- EXPECT_EQ(0U, queued_event_count());
-}
-
 TEST_F(TouchEventQueueTest, AsyncTouch) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
   // Queue a TouchStart.
   PressTouchPoint(0, 1);
   EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1770,8 +1601,6 @@
 // Ensure that touchmove's are appropriately throttled during a typical
 // scroll sequences that transitions between scrolls consumed and unconsumed.
 TEST_F(TouchEventQueueTest, AsyncTouchThrottledAfterScroll) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
   // Process a TouchStart
   PressTouchPoint(0, 1);
   EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -1967,8 +1796,6 @@
 }
 
 TEST_F(TouchEventQueueTest, AsyncTouchFlushedByTouchEnd) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
   PressTouchPoint(0, 0);
   SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
   EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -2024,7 +1851,6 @@
 // Ensure that async touch dispatch and touch ack timeout interactions work
 // appropriately.
 TEST_F(TouchEventQueueTest, AsyncTouchWithAckTimeout) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
   SetUpForTimeoutTesting(DefaultTouchTimeoutDelay());
 
   // The touchstart should start the timeout.
@@ -2107,8 +1933,6 @@
 // Ensure that if the touch ack for an async touchmove triggers a follow-up
 // touch event, that follow-up touch will be forwarded appropriately.
 TEST_F(TouchEventQueueTest, AsyncTouchWithTouchCancelAfterAck) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
   PressTouchPoint(0, 0);
   EXPECT_EQ(1U, GetAndResetSentEventCount());
   SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -2162,8 +1986,6 @@
 // Ensure that the async touch is fully reset if the touch sequence restarts
 // without properly terminating.
 TEST_F(TouchEventQueueTest, AsyncTouchWithHardTouchStartReset) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
   PressTouchPoint(0, 0);
   EXPECT_EQ(1U, GetAndResetSentEventCount());
   SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -2201,8 +2023,6 @@
 }
 
 TEST_F(TouchEventQueueTest, TouchAbsorptionWithConsumedFirstMove) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
   // Queue a TouchStart.
   PressTouchPoint(0, 1);
   SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
@@ -2242,8 +2062,6 @@
 }
 
 TEST_F(TouchEventQueueTest, TouchStartCancelableDuringScroll) {
-  SetTouchScrollingMode(TouchEventQueue::TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE);
-
   // Queue a touchstart and touchmove that go unconsumed, transitioning to an
   // active scroll sequence.
   PressTouchPoint(0, 1);
diff --git a/content/browser/renderer_host/media/OWNERS b/content/browser/renderer_host/media/OWNERS
index 9fd1d61..848d5a5 100644
--- a/content/browser/renderer_host/media/OWNERS
+++ b/content/browser/renderer_host/media/OWNERS
@@ -1,7 +1,8 @@
 dalecurtis@chromium.org
 ddorwin@chromium.org
-perkj@chromium.org
 scherkus@chromium.org
-tommi@chromium.org
-vrk@chromium.org
 xhwang@chromium.org
+
+# WebRTC OWNERS.
+perkj@chromium.org
+tommi@chromium.org
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index f35ea575..8ff97bdf 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -469,23 +469,29 @@
       NOTREACHED();
   }
 
-  libyuv::ConvertToI420(data,
-                        length,
-                        yplane,
-                        yplane_stride,
-                        uplane,
-                        uv_plane_stride,
-                        vplane,
-                        uv_plane_stride,
-                        crop_x,
-                        crop_y,
-                        frame_format.frame_size.width(),
-                        (flip ? -frame_format.frame_size.height() :
+  if (libyuv::ConvertToI420(data,
+                            length,
+                            yplane,
+                            yplane_stride,
+                            uplane,
+                            uv_plane_stride,
+                            vplane,
+                            uv_plane_stride,
+                            crop_x,
+                            crop_y,
+                            frame_format.frame_size.width(),
+                            (flip ? -frame_format.frame_size.height() :
                                 frame_format.frame_size.height()),
-                        new_unrotated_width,
-                        new_unrotated_height,
-                        rotation_mode,
-                        origin_colorspace);
+                            new_unrotated_width,
+                            new_unrotated_height,
+                            rotation_mode,
+                            origin_colorspace) != 0) {
+    DLOG(WARNING) << "Failed to convert buffer from"
+                  << media::VideoCaptureFormat::PixelFormatToString(
+                         frame_format.pixel_format)
+                  << "to I420.";
+    return;
+  }
   scoped_refptr<media::VideoFrame> frame =
       media::VideoFrame::WrapExternalPackedMemory(
           media::VideoFrame::I420,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 37d745e3..3223ecb 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1075,6 +1075,9 @@
   if (IsGpuRasterizationEnabled())
     command_line->AppendSwitch(switches::kEnableGpuRasterization);
 
+  if (IsThreadedGpuRasterizationEnabled())
+    command_line->AppendSwitch(switches::kEnableThreadedGpuRasterization);
+
   int msaa_sample_count = GpuRasterizationMSAASampleCount();
   if (msaa_sample_count > 0) {
     command_line->AppendSwitchASCII(
@@ -2065,6 +2068,10 @@
 #endif
   RemoveUserData(kSessionStorageHolderKey);
 
+  // RenderProcessGone handlers might navigate or perform other actions that
+  // require a connection. Ensure that there is one before calling them.
+  mojo_application_host_.reset(new MojoApplicationHost);
+
   IDMap<IPC::Listener>::iterator iter(&listeners_);
   while (!iter.IsAtEnd()) {
     iter.GetCurrentValue()->OnMessageReceived(
@@ -2074,8 +2081,6 @@
     iter.Advance();
   }
 
-  mojo_application_host_.reset(new MojoApplicationHost);
-
   // It's possible that one of the calls out to the observers might have caused
   // this object to be no longer needed.
   if (delayed_cleanup_needed_)
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 634cc81..e07f318 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -250,13 +250,13 @@
   // the Windows function which is actually a #define.
   virtual void ShowCreatedWindow(int route_id,
                                  WindowOpenDisposition disposition,
-                                 const gfx::Rect& initial_pos,
+                                 const gfx::Rect& initial_rect,
                                  bool user_gesture) {}
 
   // Show the newly created widget with the specified bounds.
   // The widget is identified by the route_id passed to CreateNewWidget.
   virtual void ShowCreatedWidget(int route_id,
-                                 const gfx::Rect& initial_pos) {}
+                                 const gfx::Rect& initial_rect) {}
 
   // Show the newly created full screen widget. Similar to above.
   virtual void ShowCreatedFullscreenWidget(int route_id) {}
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 1626be711..2be0fc0 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -1001,19 +1001,19 @@
 
 void RenderViewHostImpl::OnShowView(int route_id,
                                     WindowOpenDisposition disposition,
-                                    const gfx::Rect& initial_pos,
+                                    const gfx::Rect& initial_rect,
                                     bool user_gesture) {
   if (is_active_) {
     delegate_->ShowCreatedWindow(
-        route_id, disposition, initial_pos, user_gesture);
+        route_id, disposition, initial_rect, user_gesture);
   }
   Send(new ViewMsg_Move_ACK(route_id));
 }
 
 void RenderViewHostImpl::OnShowWidget(int route_id,
-                                      const gfx::Rect& initial_pos) {
+                                      const gfx::Rect& initial_rect) {
   if (is_active_)
-    delegate_->ShowCreatedWidget(route_id, initial_pos);
+    delegate_->ShowCreatedWidget(route_id, initial_rect);
   Send(new ViewMsg_Move_ACK(route_id));
 }
 
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index cc07184..430e34ad 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -171,10 +171,8 @@
   void SelectWordAroundCaret() override;
 
 #if defined(OS_ANDROID)
-  virtual void ActivateNearestFindResult(int request_id,
-                                         float x,
-                                         float y) override;
-  virtual void RequestFindMatchRects(int current_version) override;
+  void ActivateNearestFindResult(int request_id, float x, float y) override;
+  void RequestFindMatchRects(int current_version) override;
 #endif
 
   void set_delegate(RenderViewHostDelegate* d) {
@@ -334,9 +332,9 @@
   // IPC message handlers.
   void OnShowView(int route_id,
                   WindowOpenDisposition disposition,
-                  const gfx::Rect& initial_pos,
+                  const gfx::Rect& initial_rect,
                   bool user_gesture);
-  void OnShowWidget(int route_id, const gfx::Rect& initial_pos);
+  void OnShowWidget(int route_id, const gfx::Rect& initial_rect);
   void OnShowFullscreenWidget(int route_id);
   void OnRunModal(int opener_id, IPC::Message* reply_msg);
   void OnRenderViewReady();
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 05ad072..5272547 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -186,6 +186,7 @@
       has_touch_handler_(false),
       next_browser_snapshot_id_(1),
       owned_by_render_frame_host_(false),
+      is_focused_(false),
       weak_factory_(this) {
   CHECK(delegate_);
   if (routing_id_ == MSG_ROUTING_NONE) {
@@ -663,10 +664,14 @@
 }
 
 void RenderWidgetHostImpl::Focus() {
+  is_focused_ = true;
+
   Send(new InputMsg_SetFocus(routing_id_, true));
 }
 
 void RenderWidgetHostImpl::Blur() {
+  is_focused_ = false;
+
   // If there is a pending mouse lock request, we don't want to reject it at
   // this point. The user can switch focus back to this view and approve the
   // request later.
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 99f2aa3..a5136ce 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -140,8 +140,8 @@
                             const SkColorType color_type) override;
   bool CanCopyFromBackingStore() override;
 #if defined(OS_ANDROID)
-  virtual void LockBackingStore() override;
-  virtual void UnlockBackingStore() override;
+  void LockBackingStore() override;
+  void UnlockBackingStore() override;
 #endif
   void ForwardMouseEvent(const blink::WebMouseEvent& mouse_event) override;
   void ForwardWheelEvent(const blink::WebMouseWheelEvent& wheel_event) override;
@@ -228,6 +228,15 @@
   virtual void GotFocus();
   virtual void LostCapture();
 
+  // Indicates whether the RenderWidgetHost thinks it is focused.
+  // This is different from RenderWidgetHostView::HasFocus() in the sense that
+  // it reflects what the renderer process knows: it saves the state that is
+  // sent/received.
+  // RenderWidgetHostView::HasFocus() is checking whether the view is focused so
+  // it is possible in some edge cases that a view was requested to be focused
+  // but it failed, thus HasFocus() returns false.
+  bool is_focused() const { return is_focused_; }
+
   // Called to notify the RenderWidget that it has lost the mouse lock.
   virtual void LostMouseLock();
 
@@ -841,6 +850,12 @@
   // object does not self destroy.
   bool owned_by_render_frame_host_;
 
+  // Indicates whether this RenderWidgetHost thinks is focused. This is trying
+  // to match what the renderer process knows. It is different from
+  // RenderWidgetHostView::HasFocus in that in that the focus request may fail,
+  // causing HasFocus to return false when is_focused_ is true.
+  bool is_focused_;
+
   base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostImpl);
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 11d2113a..0c6a5fc 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -89,115 +89,110 @@
  public:
   RenderWidgetHostViewAndroid(RenderWidgetHostImpl* widget,
                               ContentViewCoreImpl* content_view_core);
-  virtual ~RenderWidgetHostViewAndroid();
+  ~RenderWidgetHostViewAndroid() override;
 
   // RenderWidgetHostView implementation.
-  virtual bool OnMessageReceived(const IPC::Message& msg) override;
-  virtual void InitAsChild(gfx::NativeView parent_view) override;
-  virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
-                           const gfx::Rect& pos) override;
-  virtual void InitAsFullscreen(
-      RenderWidgetHostView* reference_host_view) override;
-  virtual RenderWidgetHost* GetRenderWidgetHost() const override;
-  virtual void SetSize(const gfx::Size& size) override;
-  virtual void SetBounds(const gfx::Rect& rect) override;
-  virtual gfx::Vector2dF GetLastScrollOffset() const override;
-  virtual gfx::NativeView GetNativeView() const override;
-  virtual gfx::NativeViewId GetNativeViewId() const override;
-  virtual gfx::NativeViewAccessible GetNativeViewAccessible() override;
-  virtual void MovePluginWindows(
-      const std::vector<WebPluginGeometry>& moves) override;
-  virtual void Focus() override;
-  virtual void Blur() override;
-  virtual bool HasFocus() const override;
-  virtual bool IsSurfaceAvailableForCopy() const override;
-  virtual void Show() override;
-  virtual void Hide() override;
-  virtual bool IsShowing() override;
-  virtual gfx::Rect GetViewBounds() const override;
-  virtual gfx::Size GetPhysicalBackingSize() const override;
-  virtual bool DoTopControlsShrinkBlinkSize() const override;
-  virtual float GetTopControlsHeight() const override;
-  virtual void UpdateCursor(const WebCursor& cursor) override;
-  virtual void SetIsLoading(bool is_loading) override;
-  virtual void TextInputTypeChanged(ui::TextInputType type,
-                                    ui::TextInputMode input_mode,
-                                    bool can_compose_inline,
-                                    int flags) override;
-  virtual void ImeCancelComposition() override;
-  virtual void ImeCompositionRangeChanged(
+  bool OnMessageReceived(const IPC::Message& msg) override;
+  void InitAsChild(gfx::NativeView parent_view) override;
+  void InitAsPopup(RenderWidgetHostView* parent_host_view,
+                   const gfx::Rect& pos) override;
+  void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override;
+  RenderWidgetHost* GetRenderWidgetHost() const override;
+  void SetSize(const gfx::Size& size) override;
+  void SetBounds(const gfx::Rect& rect) override;
+  gfx::Vector2dF GetLastScrollOffset() const override;
+  gfx::NativeView GetNativeView() const override;
+  gfx::NativeViewId GetNativeViewId() const override;
+  gfx::NativeViewAccessible GetNativeViewAccessible() override;
+  void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override;
+  void Focus() override;
+  void Blur() override;
+  bool HasFocus() const override;
+  bool IsSurfaceAvailableForCopy() const override;
+  void Show() override;
+  void Hide() override;
+  bool IsShowing() override;
+  gfx::Rect GetViewBounds() const override;
+  gfx::Size GetPhysicalBackingSize() const override;
+  bool DoTopControlsShrinkBlinkSize() const override;
+  float GetTopControlsHeight() const override;
+  void UpdateCursor(const WebCursor& cursor) override;
+  void SetIsLoading(bool is_loading) override;
+  void TextInputTypeChanged(ui::TextInputType type,
+                            ui::TextInputMode input_mode,
+                            bool can_compose_inline,
+                            int flags) override;
+  void ImeCancelComposition() override;
+  void ImeCompositionRangeChanged(
       const gfx::Range& range,
       const std::vector<gfx::Rect>& character_bounds) override;
-  virtual void FocusedNodeChanged(bool is_editable_node) override;
-  virtual void RenderProcessGone(base::TerminationStatus status,
-                                 int error_code) override;
-  virtual void Destroy() override;
-  virtual void SetTooltipText(const base::string16& tooltip_text) override;
-  virtual void SelectionChanged(const base::string16& text,
-                                size_t offset,
-                                const gfx::Range& range) override;
-  virtual void SelectionBoundsChanged(
+  void FocusedNodeChanged(bool is_editable_node) override;
+  void RenderProcessGone(base::TerminationStatus status,
+                         int error_code) override;
+  void Destroy() override;
+  void SetTooltipText(const base::string16& tooltip_text) override;
+  void SelectionChanged(const base::string16& text,
+                        size_t offset,
+                        const gfx::Range& range) override;
+  void SelectionBoundsChanged(
       const ViewHostMsg_SelectionBounds_Params& params) override;
-  virtual void AcceleratedSurfaceInitialized(int route_id) override;
-  virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
-  virtual void SetBackgroundColor(SkColor color) override;
-  virtual void CopyFromCompositingSurface(
-      const gfx::Rect& src_subrect,
-      const gfx::Size& dst_size,
-      ReadbackRequestCallback& callback,
-      const SkColorType color_type) override;
-  virtual void CopyFromCompositingSurfaceToVideoFrame(
+  void AcceleratedSurfaceInitialized(int route_id) override;
+  bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
+  void SetBackgroundColor(SkColor color) override;
+  void CopyFromCompositingSurface(const gfx::Rect& src_subrect,
+                                  const gfx::Size& dst_size,
+                                  ReadbackRequestCallback& callback,
+                                  const SkColorType color_type) override;
+  void CopyFromCompositingSurfaceToVideoFrame(
       const gfx::Rect& src_subrect,
       const scoped_refptr<media::VideoFrame>& target,
       const base::Callback<void(bool)>& callback) override;
-  virtual bool CanCopyToVideoFrame() const override;
-  virtual void GetScreenInfo(blink::WebScreenInfo* results) override;
-  virtual gfx::Rect GetBoundsInRootWindow() override;
-  virtual gfx::GLSurfaceHandle GetCompositingSurface() override;
-  virtual void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
-                                      InputEventAckState ack_result) override;
-  virtual InputEventAckState FilterInputEvent(
+  bool CanCopyToVideoFrame() const override;
+  void GetScreenInfo(blink::WebScreenInfo* results) override;
+  gfx::Rect GetBoundsInRootWindow() override;
+  gfx::GLSurfaceHandle GetCompositingSurface() override;
+  void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
+                              InputEventAckState ack_result) override;
+  InputEventAckState FilterInputEvent(
       const blink::WebInputEvent& input_event) override;
-  virtual void OnSetNeedsFlushInput() override;
-  virtual void GestureEventAck(const blink::WebGestureEvent& event,
-                               InputEventAckState ack_result) override;
-  virtual BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
+  void OnSetNeedsFlushInput() override;
+  void GestureEventAck(const blink::WebGestureEvent& event,
+                       InputEventAckState ack_result) override;
+  BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
       BrowserAccessibilityDelegate* delegate) override;
-  virtual bool LockMouse() override;
-  virtual void UnlockMouse() override;
-  virtual void OnSwapCompositorFrame(
-      uint32 output_surface_id,
-      scoped_ptr<cc::CompositorFrame> frame) override;
-  virtual void DidOverscroll(const DidOverscrollParams& params) override;
-  virtual void DidStopFlinging() override;
-  virtual void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
-                                       const SkBitmap& zoomed_bitmap) override;
-  virtual scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
-      override;
-  virtual void LockCompositingSurface() override;
-  virtual void UnlockCompositingSurface() override;
-  virtual void OnTextSurroundingSelectionResponse(const base::string16& content,
-                                                  size_t start_offset,
-                                                  size_t end_offset) override;
+  bool LockMouse() override;
+  void UnlockMouse() override;
+  void OnSwapCompositorFrame(uint32 output_surface_id,
+                             scoped_ptr<cc::CompositorFrame> frame) override;
+  void DidOverscroll(const DidOverscrollParams& params) override;
+  void DidStopFlinging() override;
+  void ShowDisambiguationPopup(const gfx::Rect& rect_pixels,
+                               const SkBitmap& zoomed_bitmap) override;
+  scoped_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget() override;
+  void LockCompositingSurface() override;
+  void UnlockCompositingSurface() override;
+  void OnTextSurroundingSelectionResponse(const base::string16& content,
+                                          size_t start_offset,
+                                          size_t end_offset) override;
 
   // cc::DelegatedFrameResourceCollectionClient implementation.
-  virtual void UnusedResourcesAreAvailable() override;
+  void UnusedResourcesAreAvailable() override;
 
   // ui::GestureProviderClient implementation.
-  virtual void OnGestureEvent(const ui::GestureEventData& gesture) override;
+  void OnGestureEvent(const ui::GestureEventData& gesture) override;
 
   // ui::WindowAndroidObserver implementation.
-  virtual void OnCompositingDidCommit() override;
-  virtual void OnAttachCompositor() override;
-  virtual void OnDetachCompositor() override;
-  virtual void OnVSync(base::TimeTicks frame_time,
-                       base::TimeDelta vsync_period) override;
-  virtual void OnAnimate(base::TimeTicks begin_frame_time) override;
+  void OnCompositingDidCommit() override;
+  void OnAttachCompositor() override;
+  void OnDetachCompositor() override;
+  void OnVSync(base::TimeTicks frame_time,
+               base::TimeDelta vsync_period) override;
+  void OnAnimate(base::TimeTicks begin_frame_time) override;
 
   // DelegatedFrameEvictor implementation
-  virtual void EvictDelegatedFrame() override;
+  void EvictDelegatedFrame() override;
 
-  virtual SkColorType PreferredReadbackFormat() override;
+  SkColorType PreferredReadbackFormat() override;
 
   // StylusTextSelectorClient implementation.
   void OnStylusSelectBegin(float x0, float y0, float x1, float y1) override;
@@ -206,15 +201,15 @@
   void OnStylusSelectTap(base::TimeTicks time, float x, float y) override;
 
   // ui::TouchSelectionControllerClient implementation.
-  virtual bool SupportsAnimation() const override;
-  virtual void SetNeedsAnimate() override;
-  virtual void MoveCaret(const gfx::PointF& position) override;
-  virtual void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
-  virtual void SelectBetweenCoordinates(const gfx::PointF& base,
-                                        const gfx::PointF& extent) override;
-  virtual void OnSelectionEvent(ui::SelectionEventType event,
-                                const gfx::PointF& anchor_position) override;
-  virtual scoped_ptr<ui::TouchHandleDrawable> CreateDrawable() override;
+  bool SupportsAnimation() const override;
+  void SetNeedsAnimate() override;
+  void MoveCaret(const gfx::PointF& position) override;
+  void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
+  void SelectBetweenCoordinates(const gfx::PointF& base,
+                                const gfx::PointF& extent) override;
+  void OnSelectionEvent(ui::SelectionEventType event,
+                        const gfx::PointF& anchor_position) override;
+  scoped_ptr<ui::TouchHandleDrawable> CreateDrawable() override;
 
   // Non-virtual methods
   void SetContentViewCore(ContentViewCoreImpl* content_view_core);
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index 3189f94..9f1450b 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -193,7 +193,7 @@
   // Perform all the initialization steps necessary for this object to represent
   // a popup (such as a <select> dropdown), then shows the popup at |pos|.
   virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
-                           const gfx::Rect& pos) = 0;
+                           const gfx::Rect& bounds) = 0;
 
   // Perform all the initialization steps necessary for this object to represent
   // a full screen window.
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 57c9369..d1be2b8 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -148,6 +148,18 @@
   // Event monitor for scroll wheel end event.
   id endWheelMonitor_;
 
+  // When a gesture starts, the system does not inform the view of which type
+  // of gesture is happening (magnify, rotate, etc), rather, it just informs
+  // the view that some as-yet-undefined gesture is starting. Capture the
+  // information about the gesture's beginning event here. It will be used to
+  // create a specific gesture begin event later.
+  scoped_ptr<blink::WebGestureEvent> gestureBeginEvent_;
+
+  // This is set if a GesturePinchBegin event has been sent in the lifetime of
+  // |gestureBeginEvent_|. If set, a GesturePinchEnd will be sent when the
+  // gesture ends.
+  BOOL gestureBeginPinchSent_;
+
   // If true then escape key down events are suppressed until the first escape
   // key up event. (The up event is suppressed as well). This is used by the
   // flash fullscreen code to avoid sending a key up event without a matching
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 01e60c5..b0150f8 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -2239,19 +2239,37 @@
 
 - (void)beginGestureWithEvent:(NSEvent*)event {
   [responderDelegate_ beginGestureWithEvent:event];
+  gestureBeginEvent_.reset(
+      new WebGestureEvent(WebInputEventFactory::gestureEvent(event, self)));
 }
+
 - (void)endGestureWithEvent:(NSEvent*)event {
   [responderDelegate_ endGestureWithEvent:event];
+  gestureBeginEvent_.reset();
+
+  if (!renderWidgetHostView_->render_widget_host_)
+    return;
+
+  if (gestureBeginPinchSent_) {
+    WebGestureEvent endEvent(WebInputEventFactory::gestureEvent(event, self));
+    endEvent.type = WebInputEvent::GesturePinchEnd;
+    renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(endEvent);
+    gestureBeginPinchSent_ = NO;
+  }
 }
+
 - (void)touchesMovedWithEvent:(NSEvent*)event {
   [responderDelegate_ touchesMovedWithEvent:event];
 }
+
 - (void)touchesBeganWithEvent:(NSEvent*)event {
   [responderDelegate_ touchesBeganWithEvent:event];
 }
+
 - (void)touchesCancelledWithEvent:(NSEvent*)event {
   [responderDelegate_ touchesCancelledWithEvent:event];
 }
+
 - (void)touchesEndedWithEvent:(NSEvent*)event {
   [responderDelegate_ touchesEndedWithEvent:event];
 }
@@ -2330,16 +2348,27 @@
 
 // Called repeatedly during a pinch gesture, with incremental change values.
 - (void)magnifyWithEvent:(NSEvent*)event {
-  if (renderWidgetHostView_->render_widget_host_) {
-    // Send a GesturePinchUpdate event.
-    // Note that we don't attempt to bracket these by GesturePinchBegin/End (or
-    // GestureSrollBegin/End) as is done for touchscreen.  Keeping track of when
-    // a pinch is active would take a little more work here, and we don't need
-    // it for anything yet.
-    const WebGestureEvent& webEvent =
-        WebInputEventFactory::gestureEvent(event, self);
-    renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(webEvent);
+  if (!renderWidgetHostView_->render_widget_host_)
+    return;
+
+  // If, due to nesting of multiple gestures (e.g, from multiple touch
+  // devices), the beginning of the gesture has been lost, skip the remainder
+  // of the gesture.
+  if (!gestureBeginEvent_)
+    return;
+
+  // Send a GesturePinchBegin event if none has been sent yet.
+  if (!gestureBeginPinchSent_) {
+    WebGestureEvent beginEvent(*gestureBeginEvent_);
+    beginEvent.type = WebInputEvent::GesturePinchBegin;
+    renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(beginEvent);
+    gestureBeginPinchSent_ = YES;
   }
+
+  // Send a GesturePinchUpdate event.
+  const WebGestureEvent& updateEvent =
+      WebInputEventFactory::gestureEvent(event, self);
+  renderWidgetHostView_->render_widget_host_->ForwardGestureEvent(updateEvent);
 }
 
 - (void)viewWillMoveToWindow:(NSWindow*)newWindow {
diff --git a/content/browser/resources/media/OWNERS b/content/browser/resources/media/OWNERS
index a55b92f..ae057213 100644
--- a/content/browser/resources/media/OWNERS
+++ b/content/browser/resources/media/OWNERS
@@ -2,5 +2,4 @@
 ddorwin@chromium.org
 scherkus@chromium.org
 tommi@chromium.org
-vrk@chromium.org
 xhwang@chromium.org
diff --git a/content/browser/screen_orientation/screen_orientation_delegate_android.h b/content/browser/screen_orientation/screen_orientation_delegate_android.h
index efcdafe..063a569 100644
--- a/content/browser/screen_orientation/screen_orientation_delegate_android.h
+++ b/content/browser/screen_orientation/screen_orientation_delegate_android.h
@@ -20,7 +20,7 @@
 class ScreenOrientationDelegateAndroid : public ScreenOrientationDelegate {
  public:
   ScreenOrientationDelegateAndroid();
-  virtual ~ScreenOrientationDelegateAndroid();
+  ~ScreenOrientationDelegateAndroid() override;
 
   static bool Register(JNIEnv* env);
 
diff --git a/content/browser/screen_orientation/screen_orientation_message_filter_android.h b/content/browser/screen_orientation/screen_orientation_message_filter_android.h
index 9a01ed4..9d85fe6 100644
--- a/content/browser/screen_orientation/screen_orientation_message_filter_android.h
+++ b/content/browser/screen_orientation/screen_orientation_message_filter_android.h
@@ -14,10 +14,10 @@
   ScreenOrientationMessageFilterAndroid();
 
   // BrowserMessageFilter implementation.
-  virtual bool OnMessageReceived(const IPC::Message& message) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
 
  private:
-  virtual ~ScreenOrientationMessageFilterAndroid();
+  ~ScreenOrientationMessageFilterAndroid() override;
 
   void OnStartListening();
   void OnStopListening();
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 4e357443..443c87d 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -21,11 +21,14 @@
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/security_style.h"
+#include "content/public/common/ssl_status.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -766,45 +769,110 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, Reload) {
-  const std::string kPageUrl = "/service_worker/reload.html";
-  const std::string kWorkerUrl = "/service_worker/fetch_event_reload.js";
-  {
-    scoped_refptr<WorkerActivatedObserver> observer =
-        new WorkerActivatedObserver(wrapper());
-    observer->Init();
-    public_context()->RegisterServiceWorker(
-        embedded_test_server()->GetURL(kPageUrl),
-        embedded_test_server()->GetURL(kWorkerUrl),
-        base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
-    observer->Wait();
-  }
-  {
-    const base::string16 title = base::ASCIIToUTF16("reload=false");
-    TitleWatcher title_watcher(shell()->web_contents(), title);
-    NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
-    EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
-  }
-  {
-    const base::string16 title = base::ASCIIToUTF16("reload=true");
-    TitleWatcher title_watcher(shell()->web_contents(), title);
-    ReloadBlockUntilNavigationsComplete(shell(), 1);
-    EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
-  }
+  const char kPageUrl[] = "/service_worker/reload.html";
+  const char kWorkerUrl[] = "/service_worker/fetch_event_reload.js";
+  scoped_refptr<WorkerActivatedObserver> observer =
+      new WorkerActivatedObserver(wrapper());
+  observer->Init();
+  public_context()->RegisterServiceWorker(
+      embedded_test_server()->GetURL(kPageUrl),
+      embedded_test_server()->GetURL(kWorkerUrl),
+      base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+  observer->Wait();
+
+  const base::string16 title1 = base::ASCIIToUTF16("reload=false");
+  TitleWatcher title_watcher1(shell()->web_contents(), title1);
+  NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+  EXPECT_EQ(title1, title_watcher1.WaitAndGetTitle());
+
+  const base::string16 title2 = base::ASCIIToUTF16("reload=true");
+  TitleWatcher title_watcher2(shell()->web_contents(), title2);
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  EXPECT_EQ(title2, title_watcher2.WaitAndGetTitle());
+
   shell()->Close();
-  {
-    base::RunLoop run_loop;
-    public_context()->UnregisterServiceWorker(
-        embedded_test_server()->GetURL(kPageUrl),
-        base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
-    run_loop.Run();
-  }
+
+  base::RunLoop run_loop;
+  public_context()->UnregisterServiceWorker(
+      embedded_test_server()->GetURL(kPageUrl),
+      base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
+                       ResponseFromHTTPSServiceWorkerIsMarkedAsSecure) {
+  const char kPageUrl[] = "files/service_worker/fetch_event_blob.html";
+  const char kWorkerUrl[] = "files/service_worker/fetch_event_blob.js";
+  net::SpawnedTestServer https_server(
+      net::SpawnedTestServer::TYPE_HTTPS,
+      net::BaseTestServer::SSLOptions(
+          net::BaseTestServer::SSLOptions::CERT_OK),
+      base::FilePath(FILE_PATH_LITERAL("content/test/data/")));
+  ASSERT_TRUE(https_server.Start());
+
+  scoped_refptr<WorkerActivatedObserver> observer =
+      new WorkerActivatedObserver(wrapper());
+  observer->Init();
+  public_context()->RegisterServiceWorker(
+      https_server.GetURL(kPageUrl),
+      https_server.GetURL(kWorkerUrl),
+      base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+  observer->Wait();
+
+  const base::string16 title = base::ASCIIToUTF16("Title");
+  TitleWatcher title_watcher(shell()->web_contents(), title);
+  NavigateToURL(shell(), https_server.GetURL(kPageUrl));
+  EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+  EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
+  NavigationEntry* entry =
+      shell()->web_contents()->GetController().GetVisibleEntry();
+  EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, entry->GetSSL().security_style);
+
+  shell()->Close();
+
+  base::RunLoop run_loop;
+  public_context()->UnregisterServiceWorker(
+      https_server.GetURL(kPageUrl),
+      base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest,
+                       ResponseFromHTTPServiceWorkerIsNotMarkedAsSecure) {
+  const char kPageUrl[] = "/service_worker/fetch_event_blob.html";
+  const char kWorkerUrl[] = "/service_worker/fetch_event_blob.js";
+  scoped_refptr<WorkerActivatedObserver> observer =
+      new WorkerActivatedObserver(wrapper());
+  observer->Init();
+  public_context()->RegisterServiceWorker(
+      embedded_test_server()->GetURL(kPageUrl),
+      embedded_test_server()->GetURL(kWorkerUrl),
+      base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+  observer->Wait();
+
+  const base::string16 title = base::ASCIIToUTF16("Title");
+  TitleWatcher title_watcher(shell()->web_contents(), title);
+  NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+  EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+  EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent());
+  NavigationEntry* entry =
+      shell()->web_contents()->GetController().GetVisibleEntry();
+  EXPECT_EQ(SECURITY_STYLE_UNAUTHENTICATED, entry->GetSSL().security_style);
+
+  shell()->Close();
+
+  base::RunLoop run_loop;
+  public_context()->UnregisterServiceWorker(
+      embedded_test_server()->GetURL(kPageUrl),
+      base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+  run_loop.Run();
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
-  const std::string kScopeUrl = "/service_worker/imports_bust_memcache_scope/";
-  const std::string kPageUrl = "/service_worker/imports_bust_memcache.html";
-  const std::string kScriptUrl = "/service_worker/worker_with_one_import.js";
-  const std::string kImportUrl = "/service_worker/long_lived_import.js";
+  const char kScopeUrl[] = "/service_worker/imports_bust_memcache_scope/";
+  const char kPageUrl[] = "/service_worker/imports_bust_memcache.html";
+  const char kScriptUrl[] = "/service_worker/worker_with_one_import.js";
+  const char kImportUrl[] = "/service_worker/long_lived_import.js";
   const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
   const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
 
@@ -878,8 +946,8 @@
   shell()->Close();
   EXPECT_EQ(0, CountRenderProcessHosts());
 
-  const std::string kWorkerUrl = "/service_worker/fetch_event.js";
-  const std::string kScope = "/service_worker/";
+  const char kWorkerUrl[] = "/service_worker/fetch_event.js";
+  const char kScope[] = "/service_worker/";
 
   // Unregistering nothing should return false.
   {
@@ -953,7 +1021,7 @@
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, CrossSiteTransfer) {
   // The first page registers a service worker.
-  const std::string kRegisterPageUrl = "/service_worker/cross_site_xfer.html";
+  const char kRegisterPageUrl[] = "/service_worker/cross_site_xfer.html";
   const base::string16 kOKTitle1(base::ASCIIToUTF16("OK_1"));
   const base::string16 kFailTitle1(base::ASCIIToUTF16("FAIL_1"));
   content::TitleWatcher title_watcher1(shell()->web_contents(), kOKTitle1);
@@ -966,7 +1034,7 @@
   ShellContentBrowserClient::SetSwapProcessesForRedirect(true);
 
   // The second pages loads via the serviceworker including a subresource.
-  const std::string kConfirmPageUrl =
+  const char kConfirmPageUrl[] =
       "/service_worker/cross_site_xfer_scope/"
       "cross_site_xfer_confirm_via_serviceworker.html";
   const base::string16 kOKTitle2(base::ASCIIToUTF16("OK_2"));
diff --git a/content/browser/service_worker/service_worker_context_request_handler.cc b/content/browser/service_worker/service_worker_context_request_handler.cc
index 3bd8418..dad2c75 100644
--- a/content/browser/service_worker/service_worker_context_request_handler.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler.cc
@@ -83,7 +83,7 @@
   int64 response_id = kInvalidServiceWorkerResponseId;
   if (ShouldReadFromScriptCache(request->url(), &response_id)) {
     return new ServiceWorkerReadFromCacheJob(
-        request, network_delegate, context_, response_id);
+        request, network_delegate, context_, version_, response_id);
   }
 
   // NULL means use the network.
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index c5f9b16..46f9074 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -57,7 +57,8 @@
       provider_id_(provider_id),
       context_(context),
       dispatcher_host_(dispatcher_host),
-      allow_association_(true) {
+      allow_association_(true),
+      is_claiming_(false) {
   DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_);
   if (render_frame_id == MSG_ROUTING_NONE) {
     // Actual thread id is set when the worker context gets started.
@@ -124,7 +125,7 @@
     return;  // Could be NULL in some tests.
 
   bool should_notify_controllerchange =
-      previous_version && version && version->skip_waiting();
+      is_claiming_ || (previous_version && version && version->skip_waiting());
 
   // SetController message should be sent only for the document context.
   DCHECK_EQ(kDocumentMainThreadId, render_thread_id_);
@@ -159,10 +160,7 @@
 void ServiceWorkerProviderHost::AssociateRegistration(
     ServiceWorkerRegistration* registration) {
   DCHECK(CanAssociateRegistration(registration));
-  if (associated_registration_.get())
-    DecreaseProcessReference(associated_registration_->pattern());
   IncreaseProcessReference(registration->pattern());
-
   associated_registration_ = registration;
   associated_registration_->AddListener(this);
   SendAssociateRegistrationMessage();
@@ -282,6 +280,19 @@
   IncreaseProcessReference(pattern);
 }
 
+void ServiceWorkerProviderHost::ClaimedByRegistration(
+    ServiceWorkerRegistration* registration) {
+  DCHECK(registration->active_version());
+  is_claiming_ = true;
+  if (registration == associated_registration_) {
+    SetControllerVersionAttribute(registration->active_version());
+  } else if (allow_association_) {
+    DisassociateRegistration();
+    AssociateRegistration(registration);
+  }
+  is_claiming_ = false;
+}
+
 void ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() {
   DCHECK_NE(ChildProcessHost::kInvalidUniqueID, render_process_id_);
   DCHECK_NE(MSG_ROUTING_NONE, render_frame_id_);
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 99898a9..b3e60c1 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -152,6 +152,9 @@
   // be removed in destructor.
   void AddScopedProcessReferenceToPattern(const GURL& pattern);
 
+  // |registration| claims the document to be controlled.
+  void ClaimedByRegistration(ServiceWorkerRegistration* registration);
+
   // Methods to support cross site navigations.
   void PrepareForCrossSiteTransfer();
   void CompleteCrossSiteTransfer(
@@ -220,6 +223,7 @@
   base::WeakPtr<ServiceWorkerContextCore> context_;
   ServiceWorkerDispatcherHost* dispatcher_host_;
   bool allow_association_;
+  bool is_claiming_;
 
   std::vector<base::Closure> queued_events_;
 
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job.cc b/content/browser/service_worker/service_worker_read_from_cache_job.cc
index 84b7988..135c5898 100644
--- a/content/browser/service_worker/service_worker_read_from_cache_job.cc
+++ b/content/browser/service_worker/service_worker_read_from_cache_job.cc
@@ -26,9 +26,11 @@
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate,
     base::WeakPtr<ServiceWorkerContextCore> context,
+    const scoped_refptr<ServiceWorkerVersion>& version,
     int64 response_id)
     : net::URLRequestJob(request, network_delegate),
       context_(context),
+      version_(version),
       response_id_(response_id),
       has_been_killed_(false),
       weak_factory_(this) {
@@ -164,6 +166,8 @@
   if (is_range_request())
     SetupRangeResponse(http_info_io_buffer_->response_data_size);
   http_info_io_buffer_ = NULL;
+  if (request_->url() == version_->script_url())
+    version_->SetMainScriptHttpResponseInfo(*http_info_);
   TRACE_EVENT_ASYNC_END1("ServiceWorker",
                          "ServiceWorkerReadFromCacheJob::ReadInfo",
                          this,
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job.h b/content/browser/service_worker/service_worker_read_from_cache_job.h
index 2a290d3..48c2aa5 100644
--- a/content/browser/service_worker/service_worker_read_from_cache_job.h
+++ b/content/browser/service_worker/service_worker_read_from_cache_job.h
@@ -18,6 +18,7 @@
 
 class ServiceWorkerContextCore;
 class ServiceWorkerResponseReader;
+class ServiceWorkerVersion;
 
 // A URLRequestJob derivative used to retrieve script resources
 // from the service workers script cache. It uses a response reader
@@ -29,6 +30,7 @@
       net::URLRequest* request,
       net::NetworkDelegate* network_delegate,
       base::WeakPtr<ServiceWorkerContextCore> context,
+      const scoped_refptr<ServiceWorkerVersion>& version,
       int64 response_id);
 
  private:
@@ -55,6 +57,7 @@
   void SetupRangeResponse(int response_data_size);
 
   base::WeakPtr<ServiceWorkerContextCore> context_;
+  scoped_refptr<ServiceWorkerVersion> version_;
   int64 response_id_;
   scoped_ptr<ServiceWorkerResponseReader> reader_;
   scoped_refptr<HttpResponseInfoIOBuffer> http_info_io_buffer_;
diff --git a/content/browser/service_worker/service_worker_registration.cc b/content/browser/service_worker/service_worker_registration.cc
index a4fac5c..2640e5e 100644
--- a/content/browser/service_worker/service_worker_registration.cc
+++ b/content/browser/service_worker/service_worker_registration.cc
@@ -161,6 +161,16 @@
     ActivateWaitingVersion();
 }
 
+void ServiceWorkerRegistration::ClaimClients(const StatusCallback& callback) {
+  DCHECK(context_);
+  DCHECK(active_version());
+  // TODO(xiang): Should better not hit the database http://crbug.com/454250.
+  context_->storage()->GetRegistrationsForOrigin(
+      pattern_.GetOrigin(),
+      base::Bind(&ServiceWorkerRegistration::DidGetRegistrationsForClaimClients,
+                 this, callback, active_version_));
+}
+
 void ServiceWorkerRegistration::ClearWhenReady() {
   DCHECK(context_);
   if (is_uninstalling_)
@@ -360,4 +370,48 @@
   callback.Run(status);
 }
 
+void ServiceWorkerRegistration::DidGetRegistrationsForClaimClients(
+    const StatusCallback& callback,
+    scoped_refptr<ServiceWorkerVersion> version,
+    const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+  if (!context_) {
+    callback.Run(SERVICE_WORKER_ERROR_ABORT);
+    return;
+  }
+  if (!active_version() || version != active_version()) {
+    callback.Run(SERVICE_WORKER_ERROR_STATE);
+    return;
+  }
+
+  for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
+           context_->GetProviderHostIterator();
+       !it->IsAtEnd(); it->Advance()) {
+    ServiceWorkerProviderHost* host = it->GetProviderHost();
+    if (ShouldClaim(host, registrations))
+      host->ClaimedByRegistration(this);
+  }
+  callback.Run(SERVICE_WORKER_OK);
+}
+
+bool ServiceWorkerRegistration::ShouldClaim(
+    ServiceWorkerProviderHost* provider_host,
+    const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
+  if (provider_host->controlling_version() == active_version())
+    return false;
+
+  LongestScopeMatcher matcher(provider_host->document_url());
+  if (!matcher.MatchLongest(pattern_))
+    return false;
+  for (const ServiceWorkerRegistrationInfo& info : registrations) {
+    ServiceWorkerRegistration* registration =
+        context_->GetLiveRegistration(info.registration_id);
+    if (registration &&
+        (registration->is_uninstalling() || registration->is_uninstalled()))
+      continue;
+    if (matcher.MatchLongest(info.pattern))
+      return false;
+  }
+  return true;
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_registration.h b/content/browser/service_worker/service_worker_registration.h
index 6a8d11fc..2618483 100644
--- a/content/browser/service_worker/service_worker_registration.h
+++ b/content/browser/service_worker/service_worker_registration.h
@@ -109,6 +109,10 @@
   // initiated immediately.
   void ActivateWaitingVersionWhenReady();
 
+  // Takes over control of provider hosts which are currently not controlled or
+  // controlled by other registrations.
+  void ClaimClients(const StatusCallback& callback);
+
   // Triggers the [[ClearRegistration]] algorithm when the currently
   // active version has no controllees. Deletes this registration
   // from storage immediately.
@@ -163,6 +167,14 @@
                          scoped_refptr<ServiceWorkerVersion> version,
                          ServiceWorkerStatusCode status);
 
+  void DidGetRegistrationsForClaimClients(
+      const StatusCallback& callback,
+      scoped_refptr<ServiceWorkerVersion> version,
+      const std::vector<ServiceWorkerRegistrationInfo>& registrations);
+  bool ShouldClaim(
+      ServiceWorkerProviderHost* provider_host,
+      const std::vector<ServiceWorkerRegistrationInfo>& registration_infos);
+
   const GURL pattern_;
   const int64 registration_id_;
   bool is_deleted_;
diff --git a/content/browser/service_worker/service_worker_registration_status.cc b/content/browser/service_worker/service_worker_registration_status.cc
index 548ec5f3..84f293e 100644
--- a/content/browser/service_worker/service_worker_registration_status.cc
+++ b/content/browser/service_worker/service_worker_registration_status.cc
@@ -53,6 +53,7 @@
     case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
     case SERVICE_WORKER_ERROR_EXISTS:
     case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
+    case SERVICE_WORKER_ERROR_STATE:
       // Unexpected, or should have bailed out before calling this, or we don't
       // have a corresponding blink error code yet.
       break;  // Fall through to NOTREACHED().
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index ecac9528..4c6c59d 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -112,7 +112,9 @@
 void ServiceWorkerURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
   if (!http_info())
     return;
+  const base::Time request_time = info->request_time;
   *info = *http_info();
+  info->request_time = request_time;
   info->response_time = response_time_;
 }
 
@@ -538,6 +540,16 @@
   fetch_end_time_ = base::TimeTicks::Now();
   load_timing_info_.send_end = fetch_end_time_;
 
+  // Creates a new HttpResponseInfo using the the ServiceWorker script's
+  // HttpResponseInfo to show HTTPS padlock.
+  // TODO(horo): When we support mixed-content (HTTP) no-cors requests from a
+  // ServiceWorker, we have to check the security level of the responses.
+  DCHECK(!http_response_info_);
+  const net::HttpResponseInfo* main_script_http_info =
+      provider_host_->active_version()->GetMainScriptHttpResponseInfo();
+  DCHECK(main_script_http_info);
+  http_response_info_.reset(new net::HttpResponseInfo(*main_script_http_info));
+
   // Set up a request for reading the stream.
   if (response.stream_url.is_valid()) {
     DCHECK(response.blob_uuid.empty());
@@ -610,8 +622,11 @@
 }
 
 void ServiceWorkerURLRequestJob::CommitResponseHeader() {
-  http_response_info_.reset(new net::HttpResponseInfo());
+  if (!http_response_info_)
+    http_response_info_.reset(new net::HttpResponseInfo());
   http_response_info_->headers.swap(http_response_headers_);
+  http_response_info_->vary_data = net::HttpVaryData();
+  http_response_info_->metadata = nullptr;
   NotifyHeadersComplete();
 }
 
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index 7ce8007..0081740 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -108,8 +108,6 @@
   // StreamRegisterObserver override:
   void OnStreamRegistered(Stream* stream) override;
 
-  const net::HttpResponseInfo* http_info() const;
-
   void GetExtraResponseInfo(
       bool* was_fetched_via_service_worker,
       bool* was_fallback_required_by_service_worker,
@@ -163,6 +161,8 @@
   // Releases the resources for streaming.
   void ClearStream();
 
+  const net::HttpResponseInfo* http_info() const;
+
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
 
   // Timing info to show on the popup in Devtools' Network tab.
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 28986de..8103b8f4 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -31,8 +31,11 @@
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/io_buffer.h"
+#include "net/base/test_data_directory.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
+#include "net/ssl/ssl_info.h"
+#include "net/test/cert_test_util.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_job_factory_impl.h"
@@ -125,6 +128,15 @@
         GURL("http://example.com/service_worker.js"),
         1L,
         helper_->context()->AsWeakPtr());
+    net::HttpResponseInfo http_info;
+    http_info.ssl_info.cert =
+        net::ImportCertFromFile(net::GetTestCertsDirectory(),
+                                "ok_cert.pem");
+    EXPECT_TRUE(http_info.ssl_info.is_valid());
+    http_info.ssl_info.security_bits = 0x100;
+    // SSL3 TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    http_info.ssl_info.connection_status = 0x300039;
+    version_->SetMainScriptHttpResponseInfo(http_info);
 
     scoped_ptr<ServiceWorkerProviderHost> provider_host(
         new ServiceWorkerProviderHost(
@@ -180,6 +192,10 @@
     EXPECT_EQ(expected_status_text,
               request_->response_headers()->GetStatusText());
     EXPECT_EQ(expected_response, url_request_delegate_.response_data());
+    const net::SSLInfo& ssl_info = request_->response_info().ssl_info;
+    EXPECT_TRUE(ssl_info.is_valid());
+    EXPECT_EQ(ssl_info.security_bits, 0x100);
+    EXPECT_EQ(ssl_info.connection_status, 0x300039);
   }
 
   bool HasInflightRequests() {
diff --git a/content/browser/service_worker/service_worker_utils_unittest.cc b/content/browser/service_worker/service_worker_utils_unittest.cc
index 766b59c..d7895a43b 100644
--- a/content/browser/service_worker/service_worker_utils_unittest.cc
+++ b/content/browser/service_worker/service_worker_utils_unittest.cc
@@ -102,6 +102,9 @@
   // "/xxx" should be matched longer than "/xx".
   ASSERT_TRUE(matcher.MatchLongest(GURL("http://www.example.com/xxx")));
 
+  // The second call with the same URL should return false.
+  ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/xxx")));
+
   ASSERT_FALSE(matcher.MatchLongest(GURL("http://www.example.com/xxxx")));
 }
 
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 94dce9a..8776f0e 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -8,6 +8,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
 #include "content/browser/message_port_message_filter.h"
 #include "content/browser/message_port_service.h"
 #include "content/browser/service_worker/embedded_worker_instance.h"
@@ -18,6 +19,7 @@
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
+#include "net/http/http_response_info.h"
 
 namespace content {
 
@@ -71,6 +73,12 @@
 // Default delay for scheduled update.
 const int kUpdateDelaySeconds = 1;
 
+const char kClaimClientsStateErrorMesage[] =
+    "Only the active worker can claim clients.";
+
+const char kClaimClientsShutdownErrorMesage[] =
+    "Failed to claim clients due to Service Worker system shutdown.";
+
 void RunSoon(const base::Closure& callback) {
   if (!callback.is_null())
     base::MessageLoop::current()->PostTask(FROM_HERE, callback);
@@ -669,6 +677,16 @@
   }
 }
 
+void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
+    const net::HttpResponseInfo& http_info) {
+  main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
+}
+
+const net::HttpResponseInfo*
+ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
+  return main_script_http_info_.get();
+}
+
 void ServiceWorkerVersion::OnStarted() {
   DCHECK_EQ(RUNNING, running_status());
   DCHECK(cache_listener_.get());
@@ -800,6 +818,8 @@
                         OnGetClientInfoError)
     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
                         OnSkipWaiting)
+    IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
+                        OnClaimClients)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -1105,6 +1125,45 @@
     embedded_worker_->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id));
 }
 
+void ServiceWorkerVersion::OnClaimClients(int request_id) {
+  StatusCallback callback = base::Bind(&ServiceWorkerVersion::DidClaimClients,
+                                       weak_factory_.GetWeakPtr(), request_id);
+  if (status_ != ACTIVATING && status_ != ACTIVATED) {
+    callback.Run(SERVICE_WORKER_ERROR_STATE);
+    return;
+  }
+  if (!context_) {
+    callback.Run(SERVICE_WORKER_ERROR_ABORT);
+    return;
+  }
+
+  ServiceWorkerRegistration* registration =
+      context_->GetLiveRegistration(registration_id_);
+  if (!registration) {
+    callback.Run(SERVICE_WORKER_ERROR_ABORT);
+    return;
+  }
+  registration->ClaimClients(callback);
+}
+
+void ServiceWorkerVersion::DidClaimClients(
+    int request_id, ServiceWorkerStatusCode status) {
+  if (status == SERVICE_WORKER_ERROR_STATE) {
+    embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
+        request_id, blink::WebServiceWorkerError::ErrorTypeState,
+        base::ASCIIToUTF16(kClaimClientsStateErrorMesage)));
+    return;
+  }
+  if (status == SERVICE_WORKER_ERROR_ABORT) {
+    embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
+        request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
+        base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage)));
+    return;
+  }
+  DCHECK(status == SERVICE_WORKER_OK);
+  embedded_worker_->SendMessage(ServiceWorkerMsg_DidClaimClients(request_id));
+}
+
 void ServiceWorkerVersion::DidGetClientInfo(
     int client_id,
     scoped_refptr<GetClientDocumentsCallback> callback,
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 6954a420..015fc9d 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -33,6 +33,10 @@
 struct WebCircularGeofencingRegion;
 }
 
+namespace net {
+class HttpResponseInfo;
+}
+
 namespace content {
 
 class EmbeddedWorkerRegistry;
@@ -292,6 +296,13 @@
 
   void SetDevToolsAttached(bool attached);
 
+  // Sets the HttpResponseInfo used to load the main script.
+  // This HttpResponseInfo will be used for all responses sent back from the
+  // service worker, as the effective security of these responses is equivalent
+  // to that of the ServiceWorker.
+  void SetMainScriptHttpResponseInfo(const net::HttpResponseInfo& http_info);
+  const net::HttpResponseInfo* GetMainScriptHttpResponseInfo();
+
  private:
   class GetClientDocumentsCallback;
 
@@ -357,9 +368,11 @@
                                const std::vector<int>& sent_message_port_ids);
   void OnFocusClient(int request_id, int client_id);
   void OnSkipWaiting(int request_id);
+  void OnClaimClients(int request_id);
 
   void OnFocusClientFinished(int request_id, bool result);
   void DidSkipWaiting(int request_id);
+  void DidClaimClients(int request_id, ServiceWorkerStatusCode status);
   void DidGetClientInfo(int client_id,
                         scoped_refptr<GetClientDocumentsCallback> callback,
                         ServiceWorkerStatusCode status,
@@ -409,6 +422,7 @@
   bool is_doomed_;
   std::vector<int> pending_skip_waiting_requests_;
   bool skip_waiting_;
+  scoped_ptr<net::HttpResponseInfo> main_script_http_info_;
 
   base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_;
 
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.cc b/content/browser/service_worker/service_worker_write_to_cache_job.cc
index a6a8cfb..0138c90 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.cc
@@ -418,6 +418,8 @@
 
     if (!CheckPathRestriction(request))
       return;
+
+    version_->SetMainScriptHttpResponseInfo(net_request_->response_info());
   }
 
   WriteHeadersToCache();
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 61b8111..f5b509a 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -337,25 +337,79 @@
             child->current_frame_host()->GetSiteInstance());
 }
 
-// In A-embed-B-embed-C scenario, verify that killing process B clears proxies
-// of C from the tree.
+// This test checks that killing a renderer process of a remote frame
+// and then navigating some other frame to the same SiteInstance of the killed
+// process works properly.
+// This can be illustrated as follows,
+// where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
+// B process:
 //
-//     1          A                  A
-//    / \        / \                / \    .
-//   2   3 ->   B   A -> Kill B -> B*  A
+//     1        A                  A                           A
+//    / \  ->  / \  -> Kill B ->  / \  -> Navigate 3 to B ->  / \  .
+//   2   3    B   A              B*  A                       B*  B
+//
+// Initially, node1.proxy_hosts_ = {B}
+// After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
+// 3 to B and we expect that to complete normally.
+// See http://crbug.com/432107.
+//
+// Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
+// site B and stays in not rendered state.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+                       NavigateRemoteFrameToKilledProcess) {
+  GURL main_url(embedded_test_server()->GetURL(
+                    "/frame_tree/page_with_two_frames.html"));
+  NavigateToURL(shell(), main_url);
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root =
+      static_cast<WebContentsImpl*>(shell()->web_contents())->
+          GetFrameTree()->root();
+
+  TestNavigationObserver observer(shell()->web_contents());
+  ASSERT_EQ(2U, root->child_count());
+
+  // Make sure node2 points to the correct cross-site page.
+  GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
+  FrameTreeNode* node2 = root->child_at(0);
+  EXPECT_EQ(site_b_url, node2->current_url());
+
+  // Kill that cross-site renderer.
+  RenderProcessHost* child_process =
+      node2->current_frame_host()->GetProcess();
+  RenderProcessHostWatcher crash_observer(
+      child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  child_process->Shutdown(0, false);
+  crash_observer.Wait();
+
+  // Now navigate the second iframe (node3) to the same site as the node2.
+  FrameTreeNode* node3 = root->child_at(1);
+  NavigateFrameToURL(node3, site_b_url);
+  EXPECT_TRUE(observer.last_navigation_succeeded());
+  EXPECT_EQ(site_b_url, observer.last_navigation_url());
+}
+
+// This test is similar to
+// SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
+// addition that node2 also has a cross-origin frame to site C.
+//
+//     1          A                  A                       A
+//    / \        / \                / \                     / \  .
+//   2   3 ->   B   A -> Kill B -> B*   A -> Navigate 3 -> B*  B
 //  /          /
 // 4          C
 //
-// node1 is the root.
-// Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
-// After we kill B, make sure proxies for C are cleared.
+// Initially, node1.proxy_hosts_ = {B, C}
+// After we kill B, we make sure B stays in node1.proxy_hosts_, but
+// C gets cleared from node1.proxy_hosts_.
 //
-// TODO(lazyboy): Once http://crbug.com/432107 is fixed, we should also make
-// sure that proxies for B are not cleared when we kill B.
+// Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
+// site B and stays in not rendered state.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       KillingRendererClearsDescendantProxies) {
+                       NavigateRemoteFrameToKilledProcessWithSubtree) {
   GURL main_url(
-      embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
+      embedded_test_server()->GetURL(
+          "/frame_tree/page_with_two_frames_nested.html"));
   NavigateToURL(shell(), main_url);
 
   // It is safe to obtain the root frame tree node here, as it doesn't change.
@@ -366,24 +420,9 @@
 
   ASSERT_EQ(2U, root->child_count());
 
-  // Navigate the second subframe (node3) to a local frame.
-  GURL site_a_url(embedded_test_server()->GetURL("/title1.html"));
-  NavigateFrameToURL(root->child_at(1), site_a_url);
-
-  // Navigate the first subframe (node2) to a cross-site page with two
-  // subframes.
-  // NavigateFrameToURL can't be used here because it doesn't guarantee that
-  // FrameTreeNodes will have been created for child frames when it returns.
-  RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
   GURL site_b_url(
       embedded_test_server()->GetURL(
           "bar.com", "/frame_tree/page_with_one_frame.html"));
-  NavigationController::LoadURLParams params_b(site_b_url);
-  params_b.transition_type = ui::PAGE_TRANSITION_LINK;
-  params_b.frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
-  root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params_b);
-  frame_observer.Wait();
-
   // We can't use a TestNavigationObserver to verify the URL here,
   // since the frame has children that may have clobbered it in the observer.
   EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
@@ -397,12 +436,107 @@
 
   ASSERT_EQ(1U, root->child_at(0)->child_count());
 
-  // Navigate node4 to cross-site-page.
+  // Make sure node4 points to the correct cross-site page.
   FrameTreeNode* node4 = root->child_at(0)->child_at(0);
-  GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
-  NavigateFrameToURL(node4, site_c_url);
+  GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_c_url, node4->current_url());
+
+  // |site_instance_c| is expected to go away once we kill |child_process_b|
+  // below, so create a local scope so we can extend the lifetime of
+  // |site_instance_c| with a refptr.
+  {
+    SiteInstance* site_instance_b =
+        root->child_at(0)->current_frame_host()->GetSiteInstance();
+    // |site_c| will go away, so extend its lifetime with a refptr.
+    scoped_refptr<SiteInstanceImpl> site_instance_c =
+        node4->current_frame_host()->GetSiteInstance();
+
+    // Initially proxies for both B and C will be present in the root and node3.
+    EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_b));
+    EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_c.get()));
+    FrameTreeNode* node3 = root->child_at(1);
+    EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_b));
+    EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_c.get()));
+
+    // Kill that cross-site renderer/process B.
+    RenderProcessHost* child_process_b =
+        root->child_at(0)->current_frame_host()->GetProcess();
+    RenderProcessHostWatcher crash_observer(
+        child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+    child_process_b->Shutdown(0, false);
+    crash_observer.Wait();
+
+    // Make sure proxy B stays around in root and node3.
+    EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_b));
+    EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_b));
+    // Make sure proxy C goes away from root and node3.
+    EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(
+                     site_instance_c.get()));
+    EXPECT_FALSE(node3->render_manager()->GetRenderFrameProxyHost(
+                     site_instance_c.get()));
+  }
+
+  // Now navigate the second iframe (node3) to the same site as the node2.
+  FrameTreeNode* node3 = root->child_at(1);
+  GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
+  NavigateFrameToURL(node3, url);
   EXPECT_TRUE(observer.last_navigation_succeeded());
-  EXPECT_EQ(site_c_url, observer.last_navigation_url());
+  EXPECT_EQ(url, observer.last_navigation_url());
+}
+
+// In A-embed-B-embed-C scenario, verify that killing process B clears proxies
+// of C from the tree.
+//
+//     1          A                  A
+//    / \        / \                / \    .
+//   2   3 ->   B   A -> Kill B -> B*  A
+//  /          /
+// 4          C
+//
+// node1 is the root.
+// Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
+// After we kill B, make sure proxies for C are cleared.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+                       KillingRendererClearsDescendantProxies) {
+  GURL main_url(
+      embedded_test_server()->GetURL(
+          "/frame_tree/page_with_two_frames_nested.html"));
+  NavigateToURL(shell(), main_url);
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root =
+      static_cast<WebContentsImpl*>(shell()->web_contents())->
+          GetFrameTree()->root();
+  TestNavigationObserver observer(shell()->web_contents());
+
+  ASSERT_EQ(2U, root->child_count());
+
+  GURL site_b_url(
+      embedded_test_server()->GetURL(
+          "bar.com", "/frame_tree/page_with_one_frame.html"));
+  // We can't use a TestNavigationObserver to verify the URL here,
+  // since the frame has children that may have clobbered it in the observer.
+  EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
+
+  // Ensure that a new process is created for node2.
+  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
+            root->child_at(0)->current_frame_host()->GetSiteInstance());
+  // Ensure that a new process is *not* created for node3.
+  EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
+            root->child_at(1)->current_frame_host()->GetSiteInstance());
+
+  ASSERT_EQ(1U, root->child_at(0)->child_count());
+
+  // Make sure node4 points to the correct cross-site-page.
+  FrameTreeNode* node4 = root->child_at(0)->child_at(0);
+  GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_c_url, node4->current_url());
 
   // |site_instance_c| is expected to go away once we kill |child_process_b|
   // below, so create a local scope so we can extend the lifetime of
@@ -433,8 +567,11 @@
     // Make sure proxy C has gone from node3 as well.
     EXPECT_FALSE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost(
                      site_instance_c.get()));
-    // TODO(lazyboy): Once http://crbug.com/432107 is fixed, we should also
-    // check that proxy B exists in both root and node3.
+    // Make sure proxy B stays around in root and node3.
+    EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_b));
+    EXPECT_TRUE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost(
+                    site_instance_b));
   }
 }
 
diff --git a/content/browser/speech/speech_recognizer_impl_android.h b/content/browser/speech/speech_recognizer_impl_android.h
index cdf0b4db..11895c4 100644
--- a/content/browser/speech/speech_recognizer_impl_android.h
+++ b/content/browser/speech/speech_recognizer_impl_android.h
@@ -24,11 +24,11 @@
                               int session_id);
 
   // SpeechRecognizer methods.
-  virtual void StartRecognition(const std::string& device_id) override;
-  virtual void AbortRecognition() override;
-  virtual void StopAudioCapture() override;
-  virtual bool IsActive() const override;
-  virtual bool IsCapturingAudio() const override;
+  void StartRecognition(const std::string& device_id) override;
+  void AbortRecognition() override;
+  void StopAudioCapture() override;
+  bool IsActive() const override;
+  bool IsCapturingAudio() const override;
 
   // Called from Java methods via JNI.
   void OnAudioStart(JNIEnv* env, jobject obj);
@@ -53,7 +53,7 @@
       std::string language, bool continuous, bool interim_results);
   void OnRecognitionResultsOnIOThread(SpeechRecognitionResults const &results);
 
-  virtual ~SpeechRecognizerImplAndroid();
+  ~SpeechRecognizerImplAndroid() override;
 
   base::android::ScopedJavaGlobalRef<jobject> j_recognition_;
   State state_;
diff --git a/content/browser/time_zone_monitor_android.h b/content/browser/time_zone_monitor_android.h
index a462eb5..cb3cb9f21 100644
--- a/content/browser/time_zone_monitor_android.h
+++ b/content/browser/time_zone_monitor_android.h
@@ -17,7 +17,7 @@
 class TimeZoneMonitorAndroid : public TimeZoneMonitor {
  public:
   TimeZoneMonitorAndroid();
-  virtual ~TimeZoneMonitorAndroid();
+  ~TimeZoneMonitorAndroid() override;
 
   // Must be called at startup.
   static bool Register(JNIEnv* env);
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 12bb8da..5e2b128 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -480,19 +480,4 @@
       ConvertJavaStringToUTF8(env, message)));
 }
 
-void WebContentsAndroid::OpenURL(JNIEnv* env,
-                                 jobject obj,
-                                 jstring url,
-                                 jboolean user_gesture,
-                                 jboolean is_renderer_initiated) {
-  GURL gurl(base::android::ConvertJavaStringToUTF8(env, url));
-  OpenURLParams open_params(gurl,
-                            Referrer(),
-                            CURRENT_TAB,
-                            ui::PAGE_TRANSITION_LINK,
-                            is_renderer_initiated);
-  open_params.user_gesture = user_gesture;
-  web_contents_->OpenURL(open_params);
-}
-
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index 219872b..4379e3d 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -32,7 +32,7 @@
   static bool Register(JNIEnv* env);
 
   explicit WebContentsAndroid(WebContents* web_contents);
-  virtual ~WebContentsAndroid();
+  ~WebContentsAndroid() override;
 
   WebContents* web_contents() const { return web_contents_; }
 
@@ -109,12 +109,6 @@
                                    jint level,
                                    jstring message);
 
-  void OpenURL(JNIEnv* env,
-               jobject jobj,
-               jstring url,
-               jboolean user_gesture,
-               jboolean is_renderer_initiated);
-
  private:
   RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 507ebbe..094361d 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1644,9 +1644,9 @@
     // new window.  As a result, we need to show and navigate the window here.
     bool was_blocked = false;
     if (delegate_) {
-      gfx::Rect initial_pos;
+      gfx::Rect initial_rect;
       delegate_->AddNewContents(
-          this, new_contents, params.disposition, initial_pos,
+          this, new_contents, params.disposition, initial_rect,
           params.user_gesture, &was_blocked);
     }
     if (!was_blocked) {
@@ -1716,21 +1716,21 @@
 
 void WebContentsImpl::ShowCreatedWindow(int route_id,
                                         WindowOpenDisposition disposition,
-                                        const gfx::Rect& initial_pos,
+                                        const gfx::Rect& initial_rect,
                                         bool user_gesture) {
   WebContentsImpl* contents = GetCreatedWindow(route_id);
   if (contents) {
     WebContentsDelegate* delegate = GetDelegate();
     if (delegate) {
       delegate->AddNewContents(
-          this, contents, disposition, initial_pos, user_gesture, NULL);
+          this, contents, disposition, initial_rect, user_gesture, NULL);
     }
   }
 }
 
 void WebContentsImpl::ShowCreatedWidget(int route_id,
-                                        const gfx::Rect& initial_pos) {
-  ShowCreatedWidget(route_id, false, initial_pos);
+                                        const gfx::Rect& initial_rect) {
+  ShowCreatedWidget(route_id, false, initial_rect);
 }
 
 void WebContentsImpl::ShowCreatedFullscreenWidget(int route_id) {
@@ -1739,7 +1739,7 @@
 
 void WebContentsImpl::ShowCreatedWidget(int route_id,
                                         bool is_fullscreen,
-                                        const gfx::Rect& initial_pos) {
+                                        const gfx::Rect& initial_rect) {
   RenderWidgetHostViewBase* widget_host_view =
       static_cast<RenderWidgetHostViewBase*>(GetCreatedWidget(route_id));
   if (!widget_host_view)
@@ -1769,7 +1769,7 @@
     if (!widget_host_view->HasFocus())
       widget_host_view->Focus();
   } else {
-    widget_host_view->InitAsPopup(view, initial_pos);
+    widget_host_view->InitAsPopup(view, initial_rect);
   }
 
   RenderWidgetHostImpl* render_widget_host_impl =
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index afec265..c76a40a79 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -341,8 +341,7 @@
   void GetManifest(const GetManifestCallback&) override;
   void ExitFullscreen() override;
 #if defined(OS_ANDROID)
-  virtual base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents()
-      override;
+  base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents() override;
   virtual WebContentsAndroid* GetWebContentsAndroid();
 #elif defined(OS_MACOSX)
   void SetAllowOtherViews(bool allow) override;
@@ -473,9 +472,9 @@
   void CreateNewFullscreenWidget(int render_process_id, int route_id) override;
   void ShowCreatedWindow(int route_id,
                          WindowOpenDisposition disposition,
-                         const gfx::Rect& initial_pos,
+                         const gfx::Rect& initial_rect,
                          bool user_gesture) override;
-  void ShowCreatedWidget(int route_id, const gfx::Rect& initial_pos) override;
+  void ShowCreatedWidget(int route_id, const gfx::Rect& initial_rect) override;
   void ShowCreatedFullscreenWidget(int route_id) override;
   void RequestMediaAccessPermission(
       const MediaStreamRequest& request,
@@ -887,7 +886,7 @@
   // Helper for ShowCreatedWidget/ShowCreatedFullscreenWidget.
   void ShowCreatedWidget(int route_id,
                          bool is_fullscreen,
-                         const gfx::Rect& initial_pos);
+                         const gfx::Rect& initial_rect);
 
   // Finds the new RenderWidgetHost and returns it. Note that this can only be
   // called once as this call also removes it from the internal map.
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index e82a5daa..ded5a4b 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -2909,7 +2909,7 @@
     // Commit the navigation in the child frame and send the DidStopLoading
     // message.
     contents()->TestDidNavigate(
-        subframe, 3, bar_url, ui::PAGE_TRANSITION_TYPED);
+        subframe, 3, bar_url, ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
     subframe->OnMessageReceived(
         FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
   }
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h
index a63bb88..9f7216f 100644
--- a/content/browser/web_contents/web_contents_view_android.h
+++ b/content/browser/web_contents/web_contents_view_android.h
@@ -22,7 +22,7 @@
  public:
   WebContentsViewAndroid(WebContentsImpl* web_contents,
                          WebContentsViewDelegate* delegate);
-  virtual ~WebContentsViewAndroid();
+  ~WebContentsViewAndroid() override;
 
   // Sets the interface to the view system. ContentViewCoreImpl is owned
   // by its Java ContentViewCore counterpart, whose lifetime is managed
@@ -30,48 +30,49 @@
   void SetContentViewCore(ContentViewCoreImpl* content_view_core);
 
   // WebContentsView implementation --------------------------------------------
-  virtual gfx::NativeView GetNativeView() const override;
-  virtual gfx::NativeView GetContentNativeView() const override;
-  virtual gfx::NativeWindow GetTopLevelNativeWindow() const override;
-  virtual void GetContainerBounds(gfx::Rect* out) const override;
-  virtual void SizeContents(const gfx::Size& size) override;
-  virtual void Focus() override;
-  virtual void SetInitialFocus() override;
-  virtual void StoreFocus() override;
-  virtual void RestoreFocus() override;
-  virtual DropData* GetDropData() const override;
-  virtual gfx::Rect GetViewBounds() const override;
-  virtual void CreateView(
-      const gfx::Size& initial_size, gfx::NativeView context) override;
-  virtual RenderWidgetHostViewBase* CreateViewForWidget(
-      RenderWidgetHost* render_widget_host, bool is_guest_view_hack) override;
-  virtual RenderWidgetHostViewBase* CreateViewForPopupWidget(
+  gfx::NativeView GetNativeView() const override;
+  gfx::NativeView GetContentNativeView() const override;
+  gfx::NativeWindow GetTopLevelNativeWindow() const override;
+  void GetContainerBounds(gfx::Rect* out) const override;
+  void SizeContents(const gfx::Size& size) override;
+  void Focus() override;
+  void SetInitialFocus() override;
+  void StoreFocus() override;
+  void RestoreFocus() override;
+  DropData* GetDropData() const override;
+  gfx::Rect GetViewBounds() const override;
+  void CreateView(const gfx::Size& initial_size,
+                  gfx::NativeView context) override;
+  RenderWidgetHostViewBase* CreateViewForWidget(
+      RenderWidgetHost* render_widget_host,
+      bool is_guest_view_hack) override;
+  RenderWidgetHostViewBase* CreateViewForPopupWidget(
       RenderWidgetHost* render_widget_host) override;
-  virtual void SetPageTitle(const base::string16& title) override;
-  virtual void RenderViewCreated(RenderViewHost* host) override;
-  virtual void RenderViewSwappedIn(RenderViewHost* host) override;
-  virtual void SetOverscrollControllerEnabled(bool enabled) override;
+  void SetPageTitle(const base::string16& title) override;
+  void RenderViewCreated(RenderViewHost* host) override;
+  void RenderViewSwappedIn(RenderViewHost* host) override;
+  void SetOverscrollControllerEnabled(bool enabled) override;
 
   // Backend implementation of RenderViewHostDelegateView.
-  virtual void ShowContextMenu(RenderFrameHost* render_frame_host,
-                               const ContextMenuParams& params) override;
-  virtual void ShowPopupMenu(RenderFrameHost* render_frame_host,
-                             const gfx::Rect& bounds,
-                             int item_height,
-                             double item_font_size,
-                             int selected_item,
-                             const std::vector<MenuItem>& items,
-                             bool right_aligned,
-                             bool allow_multiple_selection) override;
-  virtual void HidePopupMenu() override;
-  virtual void StartDragging(const DropData& drop_data,
-                             blink::WebDragOperationsMask allowed_ops,
-                             const gfx::ImageSkia& image,
-                             const gfx::Vector2d& image_offset,
-                             const DragEventSourceInfo& event_info) override;
-  virtual void UpdateDragCursor(blink::WebDragOperation operation) override;
-  virtual void GotFocus() override;
-  virtual void TakeFocus(bool reverse) override;
+  void ShowContextMenu(RenderFrameHost* render_frame_host,
+                       const ContextMenuParams& params) override;
+  void ShowPopupMenu(RenderFrameHost* render_frame_host,
+                     const gfx::Rect& bounds,
+                     int item_height,
+                     double item_font_size,
+                     int selected_item,
+                     const std::vector<MenuItem>& items,
+                     bool right_aligned,
+                     bool allow_multiple_selection) override;
+  void HidePopupMenu() override;
+  void StartDragging(const DropData& drop_data,
+                     blink::WebDragOperationsMask allowed_ops,
+                     const gfx::ImageSkia& image,
+                     const gfx::Vector2d& image_offset,
+                     const DragEventSourceInfo& event_info) override;
+  void UpdateDragCursor(blink::WebDragOperation operation) override;
+  void GotFocus() override;
+  void TakeFocus(bool reverse) override;
 
  private:
   // The WebContents whose contents we display.
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index d5b5367..a8d488a 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -31,7 +31,7 @@
 #include "content/app/resources/grit/content_resources.h"
 #include "content/app/strings/grit/content_strings.h"
 #include "content/child/bluetooth/web_bluetooth_impl.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/content_child_helpers.h"
 #include "content/child/geofencing/web_geofencing_provider_impl.h"
 #include "content/child/navigator_connect/navigator_connect_provider.h"
@@ -436,15 +436,15 @@
 
 void BlinkPlatformImpl::InternalInit() {
   // ChildThread may not exist in some tests.
-  if (ChildThread::current()) {
+  if (ChildThreadImpl::current()) {
     geofencing_provider_.reset(new WebGeofencingProviderImpl(
-        ChildThread::current()->thread_safe_sender()));
+        ChildThreadImpl::current()->thread_safe_sender()));
     bluetooth_.reset(
-        new WebBluetoothImpl(ChildThread::current()->thread_safe_sender()));
-    thread_safe_sender_ = ChildThread::current()->thread_safe_sender();
+        new WebBluetoothImpl(ChildThreadImpl::current()->thread_safe_sender()));
+    thread_safe_sender_ = ChildThreadImpl::current()->thread_safe_sender();
     notification_dispatcher_ =
-        ChildThread::current()->notification_dispatcher();
-    push_dispatcher_ = ChildThread::current()->push_dispatcher();
+        ChildThreadImpl::current()->notification_dispatcher();
+    push_dispatcher_ = ChildThreadImpl::current()->push_dispatcher();
   }
 
   if (main_thread_task_runner_.get()) {
@@ -456,7 +456,7 @@
 }
 
 WebURLLoader* BlinkPlatformImpl::createURLLoader() {
-  ChildThread* child_thread = ChildThread::current();
+  ChildThreadImpl* child_thread = ChildThreadImpl::current();
   // There may be no child thread in RenderViewTests.  These tests can still use
   // data URLs to bypass the ResourceDispatcher.
   return new WebURLLoaderImpl(
diff --git a/content/child/bluetooth/bluetooth_message_filter.cc b/content/child/bluetooth/bluetooth_message_filter.cc
index b339674..554e3c3 100644
--- a/content/child/bluetooth/bluetooth_message_filter.cc
+++ b/content/child/bluetooth/bluetooth_message_filter.cc
@@ -4,40 +4,34 @@
 
 #include "content/child/bluetooth/bluetooth_message_filter.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/child/bluetooth/bluetooth_dispatcher.h"
 #include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "ipc/ipc_message_macros.h"
 
 namespace content {
 
 BluetoothMessageFilter::BluetoothMessageFilter(ThreadSafeSender* sender)
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(sender) {
+    : WorkerThreadMessageFilter(sender) {
 }
 
 BluetoothMessageFilter::~BluetoothMessageFilter() {
 }
 
-base::TaskRunner* BluetoothMessageFilter::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != BluetoothMsgStart)
-    return NULL;
-  int ipc_thread_id = 0;
-  const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
-  DCHECK(success);
-  if (!ipc_thread_id)
-    return main_thread_loop_proxy_.get();
-  return new WorkerThreadTaskRunner(ipc_thread_id);
+bool BluetoothMessageFilter::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == BluetoothMsgStart;
 }
 
-bool BluetoothMessageFilter::OnMessageReceived(const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != BluetoothMsgStart)
-    return false;
-  BluetoothDispatcher::GetOrCreateThreadSpecificInstance(
-      thread_safe_sender_.get())->OnMessageReceived(msg);
-  return true;
+void BluetoothMessageFilter::OnFilteredMessageReceived(
+    const IPC::Message& msg) {
+  BluetoothDispatcher::GetOrCreateThreadSpecificInstance(thread_safe_sender())
+      ->OnMessageReceived(msg);
+}
+
+bool BluetoothMessageFilter::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  return PickleIterator(msg).ReadInt(ipc_thread_id);
 }
 
 }  // namespace content
diff --git a/content/child/bluetooth/bluetooth_message_filter.h b/content/child/bluetooth/bluetooth_message_filter.h
index db183806..5692dcce 100644
--- a/content/child/bluetooth/bluetooth_message_filter.h
+++ b/content/child/bluetooth/bluetooth_message_filter.h
@@ -5,30 +5,22 @@
 #ifndef CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_
 #define CONTENT_CHILD_BLUETOOTH_BLUETOOTH_MESSAGE_FILTER_H_
 
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
 
 namespace content {
 
-class ThreadSafeSender;
-
-class BluetoothMessageFilter : public ChildMessageFilter {
+class BluetoothMessageFilter : public WorkerThreadMessageFilter {
  public:
   explicit BluetoothMessageFilter(ThreadSafeSender* thread_safe_sender);
 
  private:
   ~BluetoothMessageFilter() override;
 
-  // ChildMessageFilter implementation:
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
-
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
 
   DISALLOW_COPY_AND_ASSIGN(BluetoothMessageFilter);
 };
diff --git a/content/child/child_discardable_shared_memory_manager.cc b/content/child/child_discardable_shared_memory_manager.cc
index 7d07e327..83d29d6 100644
--- a/content/child/child_discardable_shared_memory_manager.cc
+++ b/content/child/child_discardable_shared_memory_manager.cc
@@ -6,7 +6,6 @@
 
 #include "base/memory/discardable_shared_memory.h"
 #include "base/process/process_metrics.h"
-#include "content/child/child_thread.h"
 #include "content/common/child_process_messages.h"
 
 namespace content {
diff --git a/content/child/child_gpu_memory_buffer_manager.cc b/content/child/child_gpu_memory_buffer_manager.cc
index 7cb793d..0e1c312ad 100644
--- a/content/child/child_gpu_memory_buffer_manager.cc
+++ b/content/child/child_gpu_memory_buffer_manager.cc
@@ -4,7 +4,6 @@
 
 #include "content/child/child_gpu_memory_buffer_manager.h"
 
-#include "content/child/child_thread.h"
 #include "content/common/child_process_messages.h"
 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
 
diff --git a/content/child/child_histogram_message_filter.cc b/content/child/child_histogram_message_filter.cc
index 3e895fc..3e778d5 100644
--- a/content/child/child_histogram_message_filter.cc
+++ b/content/child/child_histogram_message_filter.cc
@@ -10,7 +10,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_delta_serialization.h"
 #include "content/child/child_process.h"
-#include "content/child/child_thread.h"
 #include "content/common/child_process_messages.h"
 #include "ipc/ipc_sender.h"
 
diff --git a/content/child/child_message_filter.cc b/content/child/child_message_filter.cc
index 9e5ff63..66b7555 100644
--- a/content/child/child_message_filter.cc
+++ b/content/child/child_message_filter.cc
@@ -8,7 +8,7 @@
 #include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/task_runner.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/thread_safe_sender.h"
 #include "ipc/message_filter.h"
 
@@ -52,7 +52,7 @@
 
 ChildMessageFilter::ChildMessageFilter()
     : internal_(NULL),
-      thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
+      thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()) {}
 
 ChildMessageFilter::~ChildMessageFilter() {}
 
diff --git a/content/child/child_message_filter.h b/content/child/child_message_filter.h
index a79ceec..e3dbdf8 100644
--- a/content/child/child_message_filter.h
+++ b/content/child/child_message_filter.h
@@ -51,7 +51,7 @@
 
  private:
   class Internal;
-  friend class ChildThread;
+  friend class ChildThreadImpl;
   friend class RenderThreadImpl;
   friend class WorkerThread;
 
diff --git a/content/child/child_process.cc b/content/child/child_process.cc
index 42eff930..db73ea3 100644
--- a/content/child/child_process.cc
+++ b/content/child/child_process.cc
@@ -16,7 +16,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_local.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 
 #if defined(OS_ANDROID)
 #include "base/debug/debugger.h"
@@ -72,11 +72,11 @@
   io_thread_.Stop();
 }
 
-ChildThread* ChildProcess::main_thread() {
+ChildThreadImpl* ChildProcess::main_thread() {
   return main_thread_.get();
 }
 
-void ChildProcess::set_main_thread(ChildThread* thread) {
+void ChildProcess::set_main_thread(ChildThreadImpl* thread) {
   main_thread_.reset(thread);
 }
 
diff --git a/content/child/child_process.h b/content/child/child_process.h
index 1aedcb6..cf3173f7 100644
--- a/content/child/child_process.h
+++ b/content/child/child_process.h
@@ -12,7 +12,7 @@
 #include "content/common/content_export.h"
 
 namespace content {
-class ChildThread;
+class ChildThreadImpl;
 
 // Base class for child processes of the browser process (i.e. renderer and
 // plugin host). This is a singleton object for each child process.
@@ -22,12 +22,12 @@
 //
 // 1. ChildProcess::~ChildProcess() is called.
 //   2. Shutdown event is fired. Background threads should stop.
-//   3. ChildThread::Shutdown() is called. ChildThread is also deleted.
+//   3. ChildThreadImpl::Shutdown() is called. ChildThread is also deleted.
 //   4. IO thread is stopped.
 // 5. Main message loop exits.
 // 6. Child process is now fully stopped.
 //
-// Note: IO thread outlives the ChildThread object.
+// Note: IO thread outlives the ChildThreadImpl object.
 class CONTENT_EXPORT ChildProcess {
  public:
   // Child processes should have an object that derives from this class.
@@ -36,11 +36,11 @@
   virtual ~ChildProcess();
 
   // May be NULL if the main thread hasn't been set explicitly.
-  ChildThread* main_thread();
+  ChildThreadImpl* main_thread();
 
   // Sets the object associated with the main thread of this process.
   // Takes ownership of the pointer.
-  void set_main_thread(ChildThread* thread);
+  void set_main_thread(ChildThreadImpl* thread);
 
   base::MessageLoop* io_message_loop() { return io_thread_.message_loop(); }
   base::MessageLoopProxy* io_message_loop_proxy() {
@@ -81,7 +81,7 @@
   // NOTE: make sure that main_thread_ is listed after shutdown_event_, since
   // it depends on it (indirectly through IPC::SyncChannel).  Same for
   // io_thread_.
-  scoped_ptr<ChildThread> main_thread_;
+  scoped_ptr<ChildThreadImpl> main_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(ChildProcess);
 };
diff --git a/content/child/child_shared_bitmap_manager.cc b/content/child/child_shared_bitmap_manager.cc
index 5cccb6d36..73395da 100644
--- a/content/child/child_shared_bitmap_manager.cc
+++ b/content/child/child_shared_bitmap_manager.cc
@@ -6,7 +6,7 @@
 
 #include "base/debug/alias.h"
 #include "base/process/process_metrics.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/child_process_messages.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -111,7 +111,7 @@
   if (!memory->Map(memory_size))
     CHECK(false);
 #else
-  memory = ChildThread::AllocateSharedMemory(memory_size, sender_.get());
+  memory = ChildThreadImpl::AllocateSharedMemory(memory_size, sender_.get());
 #if defined(OS_WIN)
   if (!memory)
     CollectMemoryUsageAndDie(size);
diff --git a/content/child/child_thread.cc b/content/child/child_thread_impl.cc
similarity index 89%
rename from content/child/child_thread.cc
rename to content/child/child_thread_impl.cc
index 82caa77..4db2e27c 100644
--- a/content/child/child_thread.cc
+++ b/content/child/child_thread_impl.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 "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 
 #include <signal.h>
 
@@ -71,7 +71,7 @@
 // How long to wait for a connection to the browser process before giving up.
 const int kConnectionTimeoutS = 15;
 
-base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls =
+base::LazyInstance<base::ThreadLocalPointer<ChildThreadImpl> > g_lazy_tls =
     LAZY_INSTANCE_INITIALIZER;
 
 // This isn't needed on Windows because there the sandbox's job object
@@ -162,7 +162,7 @@
 #endif  // OS(POSIX)
 
 #if defined(OS_ANDROID)
-ChildThread* g_child_thread = NULL;
+ChildThreadImpl* g_child_thread = NULL;
 
 // A lock protects g_child_thread.
 base::LazyInstance<base::Lock> g_lazy_child_thread_lock =
@@ -199,50 +199,54 @@
 
 }  // namespace
 
-ChildThread::Options::Options()
+ChildThread* ChildThread::Get() {
+  return ChildThreadImpl::current();
+}
+
+ChildThreadImpl::Options::Options()
     : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kProcessChannelID)),
       use_mojo_channel(false),
       in_browser_process(false) {
 }
 
-ChildThread::Options::Options(bool mojo)
+ChildThreadImpl::Options::Options(bool mojo)
     : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kProcessChannelID)),
       use_mojo_channel(mojo),
       in_browser_process(true) {
 }
 
-ChildThread::Options::Options(std::string name, bool mojo)
+ChildThreadImpl::Options::Options(std::string name, bool mojo)
     : channel_name(name), use_mojo_channel(mojo), in_browser_process(true) {
 }
 
-ChildThread::Options::~Options() {
+ChildThreadImpl::Options::~Options() {
 }
 
-ChildThread::ChildThreadMessageRouter::ChildThreadMessageRouter(
+ChildThreadImpl::ChildThreadMessageRouter::ChildThreadMessageRouter(
     IPC::Sender* sender)
     : sender_(sender) {}
 
-bool ChildThread::ChildThreadMessageRouter::Send(IPC::Message* msg) {
+bool ChildThreadImpl::ChildThreadMessageRouter::Send(IPC::Message* msg) {
   return sender_->Send(msg);
 }
 
-ChildThread::ChildThread()
+ChildThreadImpl::ChildThreadImpl()
     : router_(this),
       in_browser_process_(false),
       channel_connected_factory_(this) {
   Init(Options());
 }
 
-ChildThread::ChildThread(const Options& options)
+ChildThreadImpl::ChildThreadImpl(const Options& options)
     : router_(this),
       in_browser_process_(options.in_browser_process),
       channel_connected_factory_(this) {
   Init(options);
 }
 
-void ChildThread::ConnectChannel(bool use_mojo_channel) {
+void ChildThreadImpl::ConnectChannel(bool use_mojo_channel) {
   bool create_pipe_now = true;
   if (use_mojo_channel) {
     VLOG(1) << "Mojo is enabled on child";
@@ -255,7 +259,7 @@
   channel_->Init(channel_name_, IPC::Channel::MODE_CLIENT, create_pipe_now);
 }
 
-void ChildThread::Init(const Options& options) {
+void ChildThreadImpl::Init(const Options& options) {
   channel_name_ = options.channel_name;
 
   g_lazy_tls.Pointer()->Set(this);
@@ -363,7 +367,7 @@
 
   base::MessageLoop::current()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&ChildThread::EnsureConnected,
+      base::Bind(&ChildThreadImpl::EnsureConnected,
                  channel_connected_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(connection_timeout));
 
@@ -395,7 +399,7 @@
       new ChildDiscardableSharedMemoryManager(thread_safe_sender()));
 }
 
-ChildThread::~ChildThread() {
+ChildThreadImpl::~ChildThreadImpl() {
 #ifdef IPC_MESSAGE_LOG_ENABLED
   IPC::Logging::GetInstance()->SetIPCSender(NULL);
 #endif
@@ -415,7 +419,7 @@
   g_lazy_tls.Pointer()->Set(NULL);
 }
 
-void ChildThread::Shutdown() {
+void ChildThreadImpl::Shutdown() {
   // Delete objects that hold references to blink so derived classes can
   // safely shutdown blink in their Shutdown implementation.
   file_system_dispatcher_.reset();
@@ -423,16 +427,16 @@
   WebFileSystemImpl::DeleteThreadSpecificInstance();
 }
 
-void ChildThread::OnChannelConnected(int32 peer_pid) {
+void ChildThreadImpl::OnChannelConnected(int32 peer_pid) {
   channel_connected_factory_.InvalidateWeakPtrs();
 }
 
-void ChildThread::OnChannelError() {
+void ChildThreadImpl::OnChannelError() {
   set_on_channel_error_called(true);
   base::MessageLoop::current()->Quit();
 }
 
-bool ChildThread::Send(IPC::Message* msg) {
+bool ChildThreadImpl::Send(IPC::Message* msg) {
   DCHECK(base::MessageLoop::current() == message_loop());
   if (!channel_) {
     delete msg;
@@ -442,19 +446,29 @@
   return channel_->Send(msg);
 }
 
-MessageRouter* ChildThread::GetRouter() {
+#if defined(OS_WIN)
+void ChildThreadImpl::PreCacheFont(const LOGFONT& log_font) {
+  Send(new ChildProcessHostMsg_PreCacheFont(log_font));
+}
+
+void ChildThreadImpl::ReleaseCachedFonts() {
+  Send(new ChildProcessHostMsg_ReleaseCachedFonts());
+}
+#endif
+
+MessageRouter* ChildThreadImpl::GetRouter() {
   DCHECK(base::MessageLoop::current() == message_loop());
   return &router_;
 }
 
-scoped_ptr<base::SharedMemory> ChildThread::AllocateSharedMemory(
+scoped_ptr<base::SharedMemory> ChildThreadImpl::AllocateSharedMemory(
     size_t buf_size) {
   DCHECK(base::MessageLoop::current() == message_loop());
   return AllocateSharedMemory(buf_size, this);
 }
 
 // static
-scoped_ptr<base::SharedMemory> ChildThread::AllocateSharedMemory(
+scoped_ptr<base::SharedMemory> ChildThreadImpl::AllocateSharedMemory(
     size_t buf_size,
     IPC::Sender* sender) {
   scoped_ptr<base::SharedMemory> shared_buf;
@@ -484,7 +498,7 @@
   return shared_buf;
 }
 
-bool ChildThread::OnMessageReceived(const IPC::Message& msg) {
+bool ChildThreadImpl::OnMessageReceived(const IPC::Message& msg) {
   if (mojo_application_->OnMessageReceived(msg))
     return true;
 
@@ -497,7 +511,7 @@
     return true;
 
   bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(ChildThread, msg)
+  IPC_BEGIN_MESSAGE_MAP(ChildThreadImpl, msg)
     IPC_MESSAGE_HANDLER(ChildProcessMsg_Shutdown, OnShutdown)
 #if defined(IPC_MESSAGE_LOG_ENABLED)
     IPC_MESSAGE_HANDLER(ChildProcessMsg_SetIPCLoggingEnabled,
@@ -525,16 +539,16 @@
   return router_.OnMessageReceived(msg);
 }
 
-bool ChildThread::OnControlMessageReceived(const IPC::Message& msg) {
+bool ChildThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
   return false;
 }
 
-void ChildThread::OnShutdown() {
+void ChildThreadImpl::OnShutdown() {
   base::MessageLoop::current()->Quit();
 }
 
 #if defined(IPC_MESSAGE_LOG_ENABLED)
-void ChildThread::OnSetIPCLoggingEnabled(bool enable) {
+void ChildThreadImpl::OnSetIPCLoggingEnabled(bool enable) {
   if (enable)
     IPC::Logging::GetInstance()->Enable();
   else
@@ -542,11 +556,11 @@
 }
 #endif  //  IPC_MESSAGE_LOG_ENABLED
 
-void ChildThread::OnSetProfilerStatus(ThreadData::Status status) {
+void ChildThreadImpl::OnSetProfilerStatus(ThreadData::Status status) {
   ThreadData::InitializeAndSetTrackingStatus(status);
 }
 
-void ChildThread::OnGetChildProfilerData(int sequence_number) {
+void ChildThreadImpl::OnGetChildProfilerData(int sequence_number) {
   tracked_objects::ProcessDataSnapshot process_data;
   ThreadData::Snapshot(false, &process_data);
 
@@ -554,7 +568,7 @@
                                                  process_data));
 }
 
-void ChildThread::OnDumpHandles() {
+void ChildThreadImpl::OnDumpHandles() {
 #if defined(OS_WIN)
   scoped_refptr<HandleEnumerator> handle_enum(
       new HandleEnumerator(
@@ -568,7 +582,7 @@
 }
 
 #if defined(USE_TCMALLOC)
-void ChildThread::OnGetTcmallocStats() {
+void ChildThreadImpl::OnGetTcmallocStats() {
   std::string result;
   char buffer[1024 * 32];
   base::allocator::GetStats(buffer, sizeof(buffer));
@@ -577,15 +591,15 @@
 }
 #endif
 
-ChildThread* ChildThread::current() {
+ChildThreadImpl* ChildThreadImpl::current() {
   return g_lazy_tls.Pointer()->Get();
 }
 
 #if defined(OS_ANDROID)
 // The method must NOT be called on the child thread itself.
 // It may block the child thread if so.
-void ChildThread::ShutdownThread() {
-  DCHECK(!ChildThread::current()) <<
+void ChildThreadImpl::ShutdownThread() {
+  DCHECK(!ChildThreadImpl::current()) <<
       "this method should NOT be called from child thread itself";
   {
     base::AutoLock lock(g_lazy_child_thread_lock.Get());
@@ -598,7 +612,7 @@
 }
 #endif
 
-void ChildThread::OnProcessFinalRelease() {
+void ChildThreadImpl::OnProcessFinalRelease() {
   if (on_channel_error_called_) {
     base::MessageLoop::current()->Quit();
     return;
@@ -613,12 +627,12 @@
   Send(new ChildProcessHostMsg_ShutdownRequest);
 }
 
-void ChildThread::EnsureConnected() {
-  VLOG(0) << "ChildThread::EnsureConnected()";
+void ChildThreadImpl::EnsureConnected() {
+  VLOG(0) << "ChildThreadImpl::EnsureConnected()";
   base::KillProcess(base::GetCurrentProcessHandle(), 0, false);
 }
 
-void ChildThread::OnProcessBackgrounded(bool background) {
+void ChildThreadImpl::OnProcessBackgrounded(bool background) {
   // Set timer slack to maximum on main thread when in background.
   base::TimerSlack timer_slack = base::TIMER_SLACK_NONE;
   if (background)
diff --git a/content/child/child_thread.h b/content/child/child_thread_impl.h
similarity index 90%
rename from content/child/child_thread.h
rename to content/child/child_thread_impl.h
index 24cfc61..20decd40 100644
--- a/content/child/child_thread.h
+++ b/content/child/child_thread_impl.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 CONTENT_CHILD_CHILD_THREAD_H_
-#define CONTENT_CHILD_CHILD_THREAD_H_
+#ifndef CONTENT_CHILD_CHILD_THREAD_IMPL_H_
+#define CONTENT_CHILD_CHILD_THREAD_IMPL_H_
 
 #include <string>
 
@@ -16,6 +16,7 @@
 #include "content/child/mojo/mojo_application.h"
 #include "content/common/content_export.h"
 #include "content/common/message_router.h"
+#include "content/public/child/child_thread.h"
 #include "ipc/ipc_message.h"  // For IPC_MESSAGE_LOG_ENABLED.
 
 namespace base {
@@ -37,14 +38,13 @@
 }  // namespace blink
 
 namespace content {
-class BluetoothMessageFilter;
+class ChildMessageFilter;
 class ChildDiscardableSharedMemoryManager;
 class ChildGpuMemoryBufferManager;
 class ChildHistogramMessageFilter;
 class ChildResourceMessageFilter;
 class ChildSharedBitmapManager;
 class FileSystemDispatcher;
-class GeofencingMessageFilter;
 class NavigatorConnectDispatcher;
 class NotificationDispatcher;
 class PushDispatcher;
@@ -57,7 +57,9 @@
 struct RequestInfo;
 
 // The main thread of a child process derives from this class.
-class CONTENT_EXPORT ChildThread : public IPC::Listener, public IPC::Sender {
+class CONTENT_EXPORT ChildThreadImpl
+    : public IPC::Listener,
+      virtual public ChildThread {
  public:
   struct CONTENT_EXPORT Options {
     Options();
@@ -72,21 +74,27 @@
   };
 
   // Creates the thread.
-  ChildThread();
+  ChildThreadImpl();
   // Allow to be used for single-process mode and for in process gpu mode via
   // options.
-  explicit ChildThread(const Options& options);
+  explicit ChildThreadImpl(const Options& options);
   // ChildProcess::main_thread() is reset after Shutdown(), and before the
   // destructor, so any subsystem that relies on ChildProcess::main_thread()
   // must be terminated before Shutdown returns. In particular, if a subsystem
   // has a thread that post tasks to ChildProcess::main_thread(), that thread
   // should be joined in Shutdown().
-  ~ChildThread() override;
+  ~ChildThreadImpl() override;
   virtual void Shutdown();
 
   // IPC::Sender implementation:
   bool Send(IPC::Message* msg) override;
 
+  // ChildThread implementation:
+#if defined(OS_WIN)
+  void PreCacheFont(const LOGFONT& log_font) override;
+  void ReleaseCachedFonts() override;
+#endif
+
   IPC::SyncChannel* channel() { return channel_.get(); }
 
   MessageRouter* GetRouter();
@@ -170,7 +178,7 @@
   base::MessageLoop* message_loop() const { return message_loop_; }
 
   // Returns the one child thread. Can only be called on the main thread.
-  static ChildThread* current();
+  static ChildThreadImpl* current();
 
 #if defined(OS_ANDROID)
   // Called on Android's service thread to shutdown the main thread of this
@@ -241,7 +249,8 @@
 
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
 
-  // Implements message routing functionality to the consumers of ChildThread.
+  // Implements message routing functionality to the consumers of
+  // ChildThreadImpl.
   ChildThreadMessageRouter router_;
 
   // Handles resource loads for this process.
@@ -284,19 +293,18 @@
 
   scoped_ptr<base::PowerMonitor> power_monitor_;
 
-  scoped_refptr<GeofencingMessageFilter> geofencing_message_filter_;
-
-  scoped_refptr<BluetoothMessageFilter> bluetooth_message_filter_;
+  scoped_refptr<ChildMessageFilter> geofencing_message_filter_;
+  scoped_refptr<ChildMessageFilter> bluetooth_message_filter_;
 
   scoped_refptr<NavigatorConnectDispatcher> navigator_connect_dispatcher_;
 
   bool in_browser_process_;
 
-  base::WeakPtrFactory<ChildThread> channel_connected_factory_;
+  base::WeakPtrFactory<ChildThreadImpl> channel_connected_factory_;
 
-  DISALLOW_COPY_AND_ASSIGN(ChildThread);
+  DISALLOW_COPY_AND_ASSIGN(ChildThreadImpl);
 };
 
 }  // namespace content
 
-#endif  // CONTENT_CHILD_CHILD_THREAD_H_
+#endif  // CONTENT_CHILD_CHILD_THREAD_IMPL_H_
diff --git a/content/child/fileapi/file_system_dispatcher.cc b/content/child/fileapi/file_system_dispatcher.cc
index 8ba8764e..1a742db2 100644
--- a/content/child/fileapi/file_system_dispatcher.cc
+++ b/content/child/fileapi/file_system_dispatcher.cc
@@ -8,7 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/process/process.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/fileapi/file_system_messages.h"
 #include "storage/common/fileapi/file_system_info.h"
 
@@ -171,7 +171,7 @@
     const StatusCallback& error_callback) {
   int request_id = dispatchers_.Add(
       CallbackDispatcher::Create(success_callback, error_callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_OpenFileSystem(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_OpenFileSystem(
       request_id, origin_url, type));
 }
 
@@ -181,7 +181,7 @@
     const StatusCallback& error_callback) {
   int request_id = dispatchers_.Add(
       CallbackDispatcher::Create(success_callback, error_callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_ResolveURL(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_ResolveURL(
           request_id, filesystem_url));
 }
 
@@ -189,7 +189,7 @@
                                             storage::FileSystemType type,
                                             const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_DeleteFileSystem(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_DeleteFileSystem(
           request_id, origin_url, type));
 }
 
@@ -198,7 +198,7 @@
     const GURL& dest_path,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_Move(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_Move(
           request_id, src_path, dest_path));
 }
 
@@ -207,7 +207,7 @@
     const GURL& dest_path,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_Copy(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_Copy(
       request_id, src_path, dest_path));
 }
 
@@ -216,7 +216,7 @@
     bool recursive,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_Remove(request_id, path, recursive));
 }
 
@@ -226,7 +226,7 @@
     const StatusCallback& error_callback) {
   int request_id = dispatchers_.Add(
       CallbackDispatcher::Create(success_callback, error_callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_ReadMetadata(request_id, path));
 }
 
@@ -235,7 +235,7 @@
     bool exclusive,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_Create(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_Create(
       request_id, path, exclusive,
       false /* is_directory */, false /* recursive */));
 }
@@ -246,7 +246,7 @@
     bool recursive,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_Create(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_Create(
       request_id, path, exclusive, true /* is_directory */, recursive));
 }
 
@@ -255,7 +255,7 @@
     bool is_directory,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_Exists(request_id, path, is_directory));
 }
 
@@ -265,7 +265,7 @@
     const StatusCallback& error_callback) {
   int request_id = dispatchers_.Add(
       CallbackDispatcher::Create(success_callback, error_callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_ReadDirectory(request_id, path));
 }
 
@@ -275,7 +275,7 @@
     int* request_id_out,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_Truncate(request_id, path, offset));
 
   if (request_id_out)
@@ -291,7 +291,7 @@
     const StatusCallback& error_callback) {
   int request_id = dispatchers_.Add(
       CallbackDispatcher::Create(success_callback, error_callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_Write(request_id, path, blob_id, offset));
 
   if (request_id_out)
@@ -302,7 +302,7 @@
     int request_id_to_cancel,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(new FileSystemHostMsg_CancelWrite(
+  ChildThreadImpl::current()->Send(new FileSystemHostMsg_CancelWrite(
       request_id, request_id_to_cancel));
 }
 
@@ -312,7 +312,7 @@
     const base::Time& last_modified_time,
     const StatusCallback& callback) {
   int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_TouchFile(
           request_id, path, last_access_time, last_modified_time));
 }
@@ -323,7 +323,7 @@
     const StatusCallback& error_callback) {
   int request_id = dispatchers_.Add(
       CallbackDispatcher::Create(success_callback, error_callback));
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new FileSystemHostMsg_CreateSnapshotFile(
           request_id, file_path));
 }
diff --git a/content/child/fileapi/webfilesystem_impl.cc b/content/child/fileapi/webfilesystem_impl.cc
index 8fe0243..c791e8d 100644
--- a/content/child/fileapi/webfilesystem_impl.cc
+++ b/content/child/fileapi/webfilesystem_impl.cc
@@ -10,12 +10,12 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_local.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/file_info_util.h"
 #include "content/child/fileapi/file_system_dispatcher.h"
 #include "content/child/fileapi/webfilewriter_impl.h"
-#include "content/child/worker_task_runner.h"
 #include "content/common/fileapi/file_system_messages.h"
 #include "storage/common/fileapi/directory_entry.h"
 #include "storage/common/fileapi/file_system_util.h"
@@ -86,15 +86,11 @@
     g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER;
 
 void DidReceiveSnapshotFile(int request_id) {
-  if (ChildThread::current())
-    ChildThread::current()->Send(
+  if (ChildThreadImpl::current())
+    ChildThreadImpl::current()->Send(
         new FileSystemHostMsg_DidReceiveSnapshotFile(request_id));
 }
 
-int CurrentWorkerId() {
-  return WorkerTaskRunner::Instance()->CurrentWorkerId();
-}
-
 template <typename Method, typename Params>
 void CallDispatcherOnMainThread(
     const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
@@ -110,12 +106,12 @@
       return;
     waitable_results->WaitAndRun();
   }
-  if (!ChildThread::current() ||
-      !ChildThread::current()->file_system_dispatcher())
+  if (!ChildThreadImpl::current() ||
+      !ChildThreadImpl::current()->file_system_dispatcher())
     return;
 
   DCHECK(!waitable_results);
-  DispatchToMethod(ChildThread::current()->file_system_dispatcher(),
+  DispatchToMethod(ChildThreadImpl::current()->file_system_dispatcher(),
                    method, params);
 }
 
@@ -191,35 +187,37 @@
   callback.Run(&callbacks);
 }
 
-void DispatchResultsClosure(int thread_id, int callbacks_id,
-                            WaitableCallbackResults* waitable_results,
-                            const base::Closure& results_closure) {
-  if (thread_id != CurrentWorkerId()) {
-    if (waitable_results) {
-      // If someone is waiting, this should result in running the closure.
-      waitable_results->AddResultsAndSignal(results_closure);
-      // In case no one is waiting, post a task to run the closure.
-      WorkerTaskRunner::Instance()->PostTask(
-          thread_id,
-          base::Bind(&WaitableCallbackResults::Run,
-                     make_scoped_refptr(waitable_results)));
-      return;
-    }
-    WorkerTaskRunner::Instance()->PostTask(thread_id, results_closure);
+void DispatchResultsClosure(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
+    WaitableCallbackResults* waitable_results,
+    const base::Closure& results_closure) {
+  if (task_runner->BelongsToCurrentThread()) {
+    results_closure.Run();
     return;
   }
-  results_closure.Run();
+
+  if (waitable_results) {
+    // If someone is waiting, this should result in running the closure.
+    waitable_results->AddResultsAndSignal(results_closure);
+    // In case no one is waiting, post a task to run the closure.
+    task_runner->PostTask(FROM_HERE,
+                          base::Bind(&WaitableCallbackResults::Run,
+                                     make_scoped_refptr(waitable_results)));
+    return;
+  }
+  task_runner->PostTask(FROM_HERE, results_closure);
 }
 
 void CallbackFileSystemCallbacks(
-    int thread_id, int callbacks_id,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
     WaitableCallbackResults* waitable_results,
     const base::Callback<void(WebFileSystemCallbacks*)>& callback,
     CallbacksUnregisterMode callbacksunregister_mode) {
-  DispatchResultsClosure(
-      thread_id, callbacks_id, waitable_results,
-      base::Bind(&RunCallbacks, callbacks_id, callback,
-                 callbacksunregister_mode));
+  DispatchResultsClosure(task_runner, callbacks_id, waitable_results,
+                         base::Bind(&RunCallbacks, callbacks_id, callback,
+                                    callbacksunregister_mode));
 }
 
 //-----------------------------------------------------------------------------
@@ -228,64 +226,67 @@
 // if necessary.
 
 void OpenFileSystemCallbackAdapter(
-    int thread_id, int callbacks_id,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
     WaitableCallbackResults* waitable_results,
-    const std::string& name, const GURL& root) {
+    const std::string& name,
+    const GURL& root) {
   CallbackFileSystemCallbacks(
-      thread_id, callbacks_id, waitable_results,
+      task_runner, callbacks_id, waitable_results,
       base::Bind(&DidOpenFileSystem, base::UTF8ToUTF16(name), root),
       UNREGISTER_CALLBACKS);
 }
 
-void ResolveURLCallbackAdapter(int thread_id,
-                               int callbacks_id,
-                               WaitableCallbackResults* waitable_results,
-                               const storage::FileSystemInfo& info,
-                               const base::FilePath& file_path,
-                               bool is_directory) {
+void ResolveURLCallbackAdapter(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
+    WaitableCallbackResults* waitable_results,
+    const storage::FileSystemInfo& info,
+    const base::FilePath& file_path,
+    bool is_directory) {
   base::FilePath normalized_path(
       storage::VirtualPath::GetNormalizedFilePath(file_path));
   CallbackFileSystemCallbacks(
-      thread_id, callbacks_id, waitable_results,
+      task_runner, callbacks_id, waitable_results,
       base::Bind(&DidResolveURL, base::UTF8ToUTF16(info.name), info.root_url,
-                 info.mount_type,
-                 normalized_path.AsUTF16Unsafe(), is_directory),
+                 info.mount_type, normalized_path.AsUTF16Unsafe(),
+                 is_directory),
       UNREGISTER_CALLBACKS);
 }
 
-void StatusCallbackAdapter(int thread_id, int callbacks_id,
-                           WaitableCallbackResults* waitable_results,
-                           base::File::Error error) {
+void StatusCallbackAdapter(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
+    WaitableCallbackResults* waitable_results,
+    base::File::Error error) {
   if (error == base::File::FILE_OK) {
-    CallbackFileSystemCallbacks(
-        thread_id, callbacks_id, waitable_results,
-        base::Bind(&DidSucceed),
-        UNREGISTER_CALLBACKS);
+    CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
+                                base::Bind(&DidSucceed), UNREGISTER_CALLBACKS);
   } else {
-    CallbackFileSystemCallbacks(
-        thread_id, callbacks_id, waitable_results,
-        base::Bind(&DidFail, error),
-        UNREGISTER_CALLBACKS);
+    CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
+                                base::Bind(&DidFail, error),
+                                UNREGISTER_CALLBACKS);
   }
 }
 
-void ReadMetadataCallbackAdapter(int thread_id, int callbacks_id,
-                                 WaitableCallbackResults* waitable_results,
-                                 const base::File::Info& file_info) {
-  CallbackFileSystemCallbacks(
-      thread_id, callbacks_id, waitable_results,
-      base::Bind(&DidReadMetadata, file_info),
-      UNREGISTER_CALLBACKS);
+void ReadMetadataCallbackAdapter(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
+    WaitableCallbackResults* waitable_results,
+    const base::File::Info& file_info) {
+  CallbackFileSystemCallbacks(task_runner, callbacks_id, waitable_results,
+                              base::Bind(&DidReadMetadata, file_info),
+                              UNREGISTER_CALLBACKS);
 }
 
 void ReadDirectoryCallbackAdapter(
-    int thread_id,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     int callbacks_id,
     WaitableCallbackResults* waitable_results,
     const std::vector<storage::DirectoryEntry>& entries,
     bool has_more) {
   CallbackFileSystemCallbacks(
-      thread_id, callbacks_id, waitable_results,
+      task_runner, callbacks_id, waitable_results,
       base::Bind(&DidReadDirectory, entries, has_more),
       has_more ? DO_NOT_UNREGISTER_CALLBACKS : UNREGISTER_CALLBACKS);
 }
@@ -317,14 +318,15 @@
 }
 
 void CreateFileWriterCallbackAdapter(
-    int thread_id, int callbacks_id,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
     WaitableCallbackResults* waitable_results,
     const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
     const GURL& path,
     blink::WebFileWriterClient* client,
     const base::File::Info& file_info) {
   DispatchResultsClosure(
-      thread_id, callbacks_id, waitable_results,
+      task_runner, callbacks_id, waitable_results,
       base::Bind(&DidCreateFileWriter, callbacks_id, path, client,
                  main_thread_task_runner, file_info));
 }
@@ -355,14 +357,15 @@
 }
 
 void CreateSnapshotFileCallbackAdapter(
-    int thread_id, int callbacks_id,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    int callbacks_id,
     WaitableCallbackResults* waitable_results,
     const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner,
     const base::File::Info& file_info,
     const base::FilePath& platform_path,
     int request_id) {
   DispatchResultsClosure(
-      thread_id, callbacks_id, waitable_results,
+      task_runner, callbacks_id, waitable_results,
       base::Bind(&DidCreateSnapshotFile, callbacks_id, main_thread_task_runner,
                  file_info, platform_path, request_id));
 }
@@ -413,17 +416,14 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::OpenFileSystem,
+      main_thread_task_runner_, &FileSystemDispatcher::OpenFileSystem,
       MakeTuple(GURL(storage_partition),
                 static_cast<storage::FileSystemType>(type),
                 base::Bind(&OpenFileSystemCallbackAdapter,
-                           CurrentWorkerId(),
-                           callbacks_id,
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
                            waitable_results),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(),
-                           callbacks_id,
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
                            waitable_results)),
       waitable_results.get());
 }
@@ -435,13 +435,14 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::ResolveURL,
+      main_thread_task_runner_, &FileSystemDispatcher::ResolveURL,
       MakeTuple(GURL(filesystem_url),
                 base::Bind(&ResolveURLCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -453,13 +454,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::DeleteFileSystem,
+      main_thread_task_runner_, &FileSystemDispatcher::DeleteFileSystem,
       MakeTuple(GURL(storage_partition),
                 static_cast<storage::FileSystemType>(type),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(),
-                           callbacks_id,
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
                            waitable_results)),
       waitable_results.get());
 }
@@ -472,11 +471,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::Move,
+      main_thread_task_runner_, &FileSystemDispatcher::Move,
       MakeTuple(GURL(src_path), GURL(dest_path),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -488,11 +487,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::Copy,
+      main_thread_task_runner_, &FileSystemDispatcher::Copy,
       MakeTuple(GURL(src_path), GURL(dest_path),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -503,11 +502,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::Remove,
+      main_thread_task_runner_, &FileSystemDispatcher::Remove,
       MakeTuple(GURL(path), false /* recursive */,
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -518,11 +517,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::Remove,
+      main_thread_task_runner_, &FileSystemDispatcher::Remove,
       MakeTuple(GURL(path), true /* recursive */,
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -533,13 +532,13 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::ReadMetadata,
-      MakeTuple(GURL(path),
-                base::Bind(&ReadMetadataCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results),
+      main_thread_task_runner_, &FileSystemDispatcher::ReadMetadata,
+      MakeTuple(GURL(path), base::Bind(&ReadMetadataCallbackAdapter,
+                                       base::ThreadTaskRunnerHandle::Get(),
+                                       callbacks_id, waitable_results),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -551,11 +550,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::CreateFile,
+      main_thread_task_runner_, &FileSystemDispatcher::CreateFile,
       MakeTuple(GURL(path), exclusive,
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -567,11 +566,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::CreateDirectory,
+      main_thread_task_runner_, &FileSystemDispatcher::CreateDirectory,
       MakeTuple(GURL(path), exclusive, false /* recursive */,
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -582,11 +581,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::Exists,
+      main_thread_task_runner_, &FileSystemDispatcher::Exists,
       MakeTuple(GURL(path), false /* directory */,
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -597,11 +596,11 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::Exists,
+      main_thread_task_runner_, &FileSystemDispatcher::Exists,
       MakeTuple(GURL(path), true /* directory */,
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -612,13 +611,13 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::ReadDirectory,
-      MakeTuple(GURL(path),
-                base::Bind(&ReadDirectoryCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results),
+      main_thread_task_runner_, &FileSystemDispatcher::ReadDirectory,
+      MakeTuple(GURL(path), base::Bind(&ReadDirectoryCallbackAdapter,
+                                       base::ThreadTaskRunnerHandle::Get(),
+                                       callbacks_id, waitable_results),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
   return callbacks_id;
 }
@@ -631,14 +630,15 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::ReadMetadata,
+      main_thread_task_runner_, &FileSystemDispatcher::ReadMetadata,
       MakeTuple(GURL(path),
                 base::Bind(&CreateFileWriterCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results,
-                           main_thread_task_runner_, GURL(path), client),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results, main_thread_task_runner_,
+                           GURL(path), client),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
@@ -649,14 +649,14 @@
   scoped_refptr<WaitableCallbackResults> waitable_results =
       MaybeCreateWaitableResults(callbacks, callbacks_id);
   CallDispatcherOnMainThread(
-      main_thread_task_runner_,
-      &FileSystemDispatcher::CreateSnapshotFile,
+      main_thread_task_runner_, &FileSystemDispatcher::CreateSnapshotFile,
       MakeTuple(GURL(path),
                 base::Bind(&CreateSnapshotFileCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results,
-                           main_thread_task_runner_),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results, main_thread_task_runner_),
                 base::Bind(&StatusCallbackAdapter,
-                           CurrentWorkerId(), callbacks_id, waitable_results)),
+                           base::ThreadTaskRunnerHandle::Get(), callbacks_id,
+                           waitable_results)),
       waitable_results.get());
 }
 
diff --git a/content/child/fileapi/webfilewriter_impl.cc b/content/child/fileapi/webfilewriter_impl.cc
index a8fd3ea..ef16def1 100644
--- a/content/child/fileapi/webfilewriter_impl.cc
+++ b/content/child/fileapi/webfilewriter_impl.cc
@@ -6,7 +6,8 @@
 
 #include "base/bind.h"
 #include "base/synchronization/waitable_event.h"
-#include "content/child/child_thread.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/fileapi/file_system_dispatcher.h"
 #include "content/child/worker_task_runner.h"
 
@@ -15,8 +16,8 @@
 namespace {
 
 FileSystemDispatcher* GetFileSystemDispatcher() {
-  return ChildThread::current() ?
-      ChildThread::current()->file_system_dispatcher() : NULL;
+  return ChildThreadImpl::current() ?
+      ChildThreadImpl::current()->file_system_dispatcher() : NULL;
 }
 
 }  // namespace
@@ -31,7 +32,9 @@
  public:
   WriterBridge(WebFileWriterImpl::Type type)
       : request_id_(0),
-        thread_id_(WorkerTaskRunner::Instance()->CurrentWorkerId()),
+        running_on_worker_(WorkerTaskRunner::Instance()->CurrentWorkerId() > 0),
+        task_runner_(running_on_worker_ ? base::ThreadTaskRunnerHandle::Get()
+                                        : nullptr),
         written_bytes_(0) {
     if (type == WebFileWriterImpl::TYPE_SYNC)
       waitable_event_.reset(new base::WaitableEvent(false, false));
@@ -42,7 +45,7 @@
     status_callback_ = status_callback;
     if (!GetFileSystemDispatcher())
       return;
-    ChildThread::current()->file_system_dispatcher()->Truncate(
+    ChildThreadImpl::current()->file_system_dispatcher()->Truncate(
         path, offset, &request_id_,
         base::Bind(&WriterBridge::DidFinish, this));
   }
@@ -54,7 +57,7 @@
     status_callback_ = error_callback;
     if (!GetFileSystemDispatcher())
       return;
-    ChildThread::current()->file_system_dispatcher()->Write(
+    ChildThreadImpl::current()->file_system_dispatcher()->Write(
         path, id, offset, &request_id_,
         base::Bind(&WriterBridge::DidWrite, this),
         base::Bind(&WriterBridge::DidFinish, this));
@@ -64,7 +67,7 @@
     status_callback_ = status_callback;
     if (!GetFileSystemDispatcher())
       return;
-    ChildThread::current()->file_system_dispatcher()->Cancel(
+    ChildThreadImpl::current()->file_system_dispatcher()->Cancel(
         request_id_,
         base::Bind(&WriterBridge::DidFinish, this));
   }
@@ -96,23 +99,25 @@
 
   void PostTaskToWorker(const base::Closure& closure) {
     written_bytes_ = 0;
-    if (!thread_id_) {
+    if (!running_on_worker_) {
       DCHECK(!waitable_event_);
       closure.Run();
       return;
     }
+    DCHECK(task_runner_);
     if (waitable_event_) {
       results_closure_ = closure;
       waitable_event_->Signal();
       return;
     }
-    WorkerTaskRunner::Instance()->PostTask(thread_id_, closure);
+    task_runner_->PostTask(FROM_HERE, closure);
   }
 
   StatusCallback status_callback_;
   WriteCallback write_callback_;
   int request_id_;
-  int thread_id_;
+  const bool running_on_worker_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   int written_bytes_;
   scoped_ptr<base::WaitableEvent> waitable_event_;
   base::Closure results_closure_;
diff --git a/content/child/geofencing/geofencing_message_filter.cc b/content/child/geofencing/geofencing_message_filter.cc
index a833457..a866b37 100644
--- a/content/child/geofencing/geofencing_message_filter.cc
+++ b/content/child/geofencing/geofencing_message_filter.cc
@@ -4,40 +4,33 @@
 
 #include "content/child/geofencing/geofencing_message_filter.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/child/geofencing/geofencing_dispatcher.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "ipc/ipc_message_macros.h"
 
 namespace content {
 
 GeofencingMessageFilter::GeofencingMessageFilter(ThreadSafeSender* sender)
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(sender) {
+    : WorkerThreadMessageFilter(sender) {
 }
 
 GeofencingMessageFilter::~GeofencingMessageFilter() {
 }
 
-base::TaskRunner* GeofencingMessageFilter::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != GeofencingMsgStart)
-    return NULL;
-  int ipc_thread_id = 0;
-  const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
-  DCHECK(success);
-  if (!ipc_thread_id)
-    return main_thread_loop_proxy_.get();
-  return new WorkerThreadTaskRunner(ipc_thread_id);
+bool GeofencingMessageFilter::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == GeofencingMsgStart;
 }
 
-bool GeofencingMessageFilter::OnMessageReceived(const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != GeofencingMsgStart)
-    return false;
-  GeofencingDispatcher::GetOrCreateThreadSpecificInstance(
-      thread_safe_sender_.get())->OnMessageReceived(msg);
-  return true;
+void GeofencingMessageFilter::OnFilteredMessageReceived(
+    const IPC::Message& msg) {
+  GeofencingDispatcher::GetOrCreateThreadSpecificInstance(thread_safe_sender())
+      ->OnMessageReceived(msg);
+}
+
+bool GeofencingMessageFilter::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  return PickleIterator(msg).ReadInt(ipc_thread_id);
 }
 
 }  // namespace content
diff --git a/content/child/geofencing/geofencing_message_filter.h b/content/child/geofencing/geofencing_message_filter.h
index 3a95d42..34a05c2 100644
--- a/content/child/geofencing/geofencing_message_filter.h
+++ b/content/child/geofencing/geofencing_message_filter.h
@@ -5,30 +5,22 @@
 #ifndef CONTENT_CHILD_GEOFENCING_GEOFENCING_MESSAGE_FILTER_H_
 #define CONTENT_CHILD_GEOFENCING_GEOFENCING_MESSAGE_FILTER_H_
 
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
 
 namespace content {
 
-class ThreadSafeSender;
-
-class GeofencingMessageFilter : public ChildMessageFilter {
+class GeofencingMessageFilter : public WorkerThreadMessageFilter {
  public:
   explicit GeofencingMessageFilter(ThreadSafeSender* thread_safe_sender);
 
  private:
   ~GeofencingMessageFilter() override;
 
-  // ChildMessageFilter implementation:
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
-
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
 
   DISALLOW_COPY_AND_ASSIGN(GeofencingMessageFilter);
 };
diff --git a/content/child/indexed_db/indexed_db_message_filter.cc b/content/child/indexed_db/indexed_db_message_filter.cc
index bce3817..60c1bea 100644
--- a/content/child/indexed_db/indexed_db_message_filter.cc
+++ b/content/child/indexed_db/indexed_db_message_filter.cc
@@ -4,10 +4,8 @@
 
 #include "content/child/indexed_db/indexed_db_message_filter.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/child/indexed_db/indexed_db_dispatcher.h"
 #include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "content/common/indexed_db/indexed_db_constants.h"
 #include "content/common/indexed_db/indexed_db_messages.h"
 
@@ -15,29 +13,26 @@
 
 IndexedDBMessageFilter::IndexedDBMessageFilter(
     ThreadSafeSender* thread_safe_sender)
-    : main_thread_loop_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(thread_safe_sender) {}
+    : WorkerThreadMessageFilter(thread_safe_sender) {
+}
 
 IndexedDBMessageFilter::~IndexedDBMessageFilter() {}
 
-base::TaskRunner* IndexedDBMessageFilter::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
-    return NULL;
-  int ipc_thread_id = 0;
-  const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
-  DCHECK(success);
-  if (!ipc_thread_id)
-    return main_thread_loop_.get();
-  return new WorkerThreadTaskRunner(ipc_thread_id);
+bool IndexedDBMessageFilter::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == IndexedDBMsgStart;
 }
 
-bool IndexedDBMessageFilter::OnMessageReceived(const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
-    return false;
-  IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get())
+void IndexedDBMessageFilter::OnFilteredMessageReceived(
+    const IPC::Message& msg) {
+  IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender())
       ->OnMessageReceived(msg);
-  return true;
+}
+
+bool IndexedDBMessageFilter::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  return PickleIterator(msg).ReadInt(ipc_thread_id);
 }
 
 void IndexedDBMessageFilter::OnStaleMessageReceived(const IPC::Message& msg) {
@@ -57,13 +52,13 @@
     const IndexedDBDatabaseMetadata& idb_metadata) {
   if (ipc_database_id == kNoDatabase)
     return;
-  thread_safe_sender_->Send(
+  thread_safe_sender()->Send(
       new IndexedDBHostMsg_DatabaseClose(ipc_database_id));
 }
 
 void IndexedDBMessageFilter::OnStaleUpgradeNeeded(
     const IndexedDBMsg_CallbacksUpgradeNeeded_Params& p) {
-  thread_safe_sender_->Send(
+  thread_safe_sender()->Send(
       new IndexedDBHostMsg_DatabaseClose(p.ipc_database_id));
 }
 
diff --git a/content/child/indexed_db/indexed_db_message_filter.h b/content/child/indexed_db/indexed_db_message_filter.h
index e2d1ed5..08e39982 100644
--- a/content/child/indexed_db/indexed_db_message_filter.h
+++ b/content/child/indexed_db/indexed_db_message_filter.h
@@ -6,7 +6,7 @@
 #define CONTENT_CHILD_INDEXED_DB_INDEXED_DB_MESSAGE_FILTER_H_
 
 #include "base/memory/ref_counted.h"
-#include "content/child/child_message_filter.h"
+#include "content/child/worker_thread_message_filter.h"
 
 struct IndexedDBDatabaseMetadata;
 struct IndexedDBMsg_CallbacksUpgradeNeeded_Params;
@@ -15,15 +15,9 @@
 class MessageLoopProxy;
 }
 
-namespace IPC {
-class Message;
-}
-
 namespace content {
 
-class ThreadSafeSender;
-
-class IndexedDBMessageFilter : public ChildMessageFilter {
+class IndexedDBMessageFilter : public WorkerThreadMessageFilter {
  public:
   explicit IndexedDBMessageFilter(ThreadSafeSender* thread_safe_sender);
 
@@ -31,10 +25,13 @@
   ~IndexedDBMessageFilter() override;
 
  private:
-  // ChildMessageFilter implementation:
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
+
+  // ChildMessageFilter:
   void OnStaleMessageReceived(const IPC::Message& msg) override;
 
   void OnStaleSuccessIDBDatabase(int32 ipc_thread_id,
@@ -44,9 +41,6 @@
                                  const IndexedDBDatabaseMetadata&);
   void OnStaleUpgradeNeeded(const IndexedDBMsg_CallbacksUpgradeNeeded_Params&);
 
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
   DISALLOW_COPY_AND_ASSIGN(IndexedDBMessageFilter);
 };
 
diff --git a/content/child/navigator_connect/navigator_connect_dispatcher.cc b/content/child/navigator_connect/navigator_connect_dispatcher.cc
index d2f7119a..1a30433 100644
--- a/content/child/navigator_connect/navigator_connect_dispatcher.cc
+++ b/content/child/navigator_connect/navigator_connect_dispatcher.cc
@@ -4,41 +4,33 @@
 
 #include "content/child/navigator_connect/navigator_connect_dispatcher.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/child/navigator_connect/navigator_connect_provider.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "content/common/navigator_connect_messages.h"
 
 namespace content {
 
 NavigatorConnectDispatcher::NavigatorConnectDispatcher(ThreadSafeSender* sender)
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(sender) {
+    : WorkerThreadMessageFilter(sender) {
 }
 
 NavigatorConnectDispatcher::~NavigatorConnectDispatcher() {
 }
 
-base::TaskRunner* NavigatorConnectDispatcher::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != NavigatorConnectMsgStart)
-    return NULL;
-  int ipc_thread_id = 0;
-  const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
-  DCHECK(success);
-  if (!ipc_thread_id)
-    return main_thread_loop_proxy_.get();
-  return new WorkerThreadTaskRunner(ipc_thread_id);
+bool NavigatorConnectDispatcher::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == NavigatorConnectMsgStart;
 }
 
-bool NavigatorConnectDispatcher::OnMessageReceived(const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != NavigatorConnectMsgStart)
-    return false;
-  NavigatorConnectProvider::ThreadSpecificInstance(thread_safe_sender_.get(),
-                                                   main_thread_loop_proxy_)
-      ->OnMessageReceived(msg);
-  return true;
+void NavigatorConnectDispatcher::OnFilteredMessageReceived(
+    const IPC::Message& msg) {
+  NavigatorConnectProvider::ThreadSpecificInstance(
+      thread_safe_sender(), main_thread_task_runner())->OnMessageReceived(msg);
+}
+
+bool NavigatorConnectDispatcher::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  return PickleIterator(msg).ReadInt(ipc_thread_id);
 }
 
 }  // namespace content
diff --git a/content/child/navigator_connect/navigator_connect_dispatcher.h b/content/child/navigator_connect/navigator_connect_dispatcher.h
index 3455912..0044b51 100644
--- a/content/child/navigator_connect/navigator_connect_dispatcher.h
+++ b/content/child/navigator_connect/navigator_connect_dispatcher.h
@@ -5,32 +5,24 @@
 #ifndef CONTENT_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_H_
 #define CONTENT_CHILD_NAVIGATOR_CONNECT_NAVIGATOR_CONNECT_DISPATCHER_H_
 
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
 
 namespace content {
 
-class ThreadSafeSender;
-
 // Receives IPC messages from the browser process and dispatches them to the
 // correct thread specific NavigatorConnectProvider.
-class NavigatorConnectDispatcher : public ChildMessageFilter {
+class NavigatorConnectDispatcher : public WorkerThreadMessageFilter {
  public:
   explicit NavigatorConnectDispatcher(ThreadSafeSender* thread_safe_sender);
 
  private:
   ~NavigatorConnectDispatcher() override;
 
-  // ChildMessageFilter implementation:
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
-
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
 
   DISALLOW_COPY_AND_ASSIGN(NavigatorConnectDispatcher);
 };
diff --git a/content/child/notifications/notification_dispatcher.cc b/content/child/notifications/notification_dispatcher.cc
index a9a5daa..5949972 100644
--- a/content/child/notifications/notification_dispatcher.cc
+++ b/content/child/notifications/notification_dispatcher.cc
@@ -4,19 +4,14 @@
 
 #include "content/child/notifications/notification_dispatcher.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/child/notifications/notification_manager.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "content/common/platform_notification_messages.h"
 
 namespace content {
 
 NotificationDispatcher::NotificationDispatcher(
     ThreadSafeSender* thread_safe_sender)
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(thread_safe_sender),
-      next_notification_id_(0) {
+    : WorkerThreadMessageFilter(thread_safe_sender), next_notification_id_(0) {
 }
 
 NotificationDispatcher::~NotificationDispatcher() {}
@@ -27,43 +22,32 @@
   return next_notification_id_++;
 }
 
-base::TaskRunner* NotificationDispatcher::OverrideTaskRunnerForMessage(
+bool NotificationDispatcher::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == PlatformNotificationMsgStart;
+}
+
+void NotificationDispatcher::OnFilteredMessageReceived(
     const IPC::Message& msg) {
-  if (!ShouldHandleMessage(msg))
-    return NULL;
+  NotificationManager::ThreadSpecificInstance(thread_safe_sender(),
+                                              main_thread_task_runner(),
+                                              this)->OnMessageReceived(msg);
+}
 
-  int notification_id = -1,
-      thread_id = 0;
-
+bool NotificationDispatcher::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  int notification_id = -1;
   const bool success = PickleIterator(msg).ReadInt(&notification_id);
   DCHECK(success);
 
-  {
-    base::AutoLock lock(notification_id_map_lock_);
-    auto iterator = notification_id_map_.find(notification_id);
-    if (iterator != notification_id_map_.end())
-      thread_id = iterator->second;
+  base::AutoLock lock(notification_id_map_lock_);
+  auto iterator = notification_id_map_.find(notification_id);
+  if (iterator != notification_id_map_.end()) {
+    *ipc_thread_id = iterator->second;
+    return true;
   }
-
-  if (!thread_id)
-    return main_thread_loop_proxy_.get();
-
-  return new WorkerThreadTaskRunner(thread_id);
-}
-
-bool NotificationDispatcher::OnMessageReceived(const IPC::Message& msg) {
-  if (!ShouldHandleMessage(msg))
-    return false;
-
-  NotificationManager::ThreadSpecificInstance(
-      thread_safe_sender_.get(),
-      main_thread_loop_proxy_.get(),
-      this)->OnMessageReceived(msg);
-  return true;
-}
-
-bool NotificationDispatcher::ShouldHandleMessage(const IPC::Message& msg) {
-  return IPC_MESSAGE_CLASS(msg) == PlatformNotificationMsgStart;
+  return false;
 }
 
 }  // namespace content
diff --git a/content/child/notifications/notification_dispatcher.h b/content/child/notifications/notification_dispatcher.h
index be4ada9..824cde3b 100644
--- a/content/child/notifications/notification_dispatcher.h
+++ b/content/child/notifications/notification_dispatcher.h
@@ -7,19 +7,12 @@
 
 #include <map>
 
-#include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
 
 namespace content {
 
-class ThreadSafeSender;
-
-class NotificationDispatcher : public ChildMessageFilter {
+class NotificationDispatcher : public WorkerThreadMessageFilter {
  public:
   explicit NotificationDispatcher(ThreadSafeSender* thread_safe_sender);
 
@@ -31,15 +24,11 @@
   ~NotificationDispatcher() override;
 
  private:
-  bool ShouldHandleMessage(const IPC::Message& msg);
-
-  // ChildMessageFilter implementation.
-  base::TaskRunner* OverrideTaskRunnerForMessage(const IPC::Message& msg)
-      override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
-
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
 
   using NotificationIdToThreadId = std::map<int, int>;
 
diff --git a/content/child/notifications/notification_image_loader.cc b/content/child/notifications/notification_image_loader.cc
index b2eb23eb..c194b024 100644
--- a/content/child/notifications/notification_image_loader.cc
+++ b/content/child/notifications/notification_image_loader.cc
@@ -5,7 +5,7 @@
 #include "content/child/notifications/notification_image_loader.h"
 
 #include "base/logging.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/image_decoder.h"
 #include "content/child/worker_task_runner.h"
 #include "third_party/WebKit/public/platform/Platform.h"
@@ -29,7 +29,7 @@
 
 void NotificationImageLoader::StartOnMainThread(const WebURL& image_url,
                                                 int worker_thread_id) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   DCHECK(!url_loader_);
 
   worker_thread_id_ = worker_thread_id;
diff --git a/content/child/npapi/plugin_url_fetcher.cc b/content/child/npapi/plugin_url_fetcher.cc
index c7db56c..15bd602 100644
--- a/content/child/npapi/plugin_url_fetcher.cc
+++ b/content/child/npapi/plugin_url_fetcher.cc
@@ -5,7 +5,7 @@
 #include "content/child/npapi/plugin_url_fetcher.h"
 
 #include "base/memory/scoped_ptr.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/multipart_response_delegate.h"
 #include "content/child/npapi/plugin_host.h"
 #include "content/child/npapi/plugin_instance.h"
@@ -146,7 +146,7 @@
       request_info.headers = std::string("Range: ") + range;
   }
 
-  bridge_.reset(ChildThread::current()->resource_dispatcher()->CreateBridge(
+  bridge_.reset(ChildThreadImpl::current()->resource_dispatcher()->CreateBridge(
       request_info));
   if (!body.empty()) {
     scoped_refptr<ResourceRequestBody> request_body =
diff --git a/content/child/push_messaging/push_dispatcher.cc b/content/child/push_messaging/push_dispatcher.cc
index 4bd1705..8cc33fc0 100644
--- a/content/child/push_messaging/push_dispatcher.cc
+++ b/content/child/push_messaging/push_dispatcher.cc
@@ -4,19 +4,13 @@
 
 #include "content/child/push_messaging/push_dispatcher.h"
 
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/pickle.h"
 #include "content/child/push_messaging/push_provider.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "content/common/push_messaging_messages.h"
 
 namespace content {
 
 PushDispatcher::PushDispatcher(ThreadSafeSender* thread_safe_sender)
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(thread_safe_sender),
-      next_request_id_(0) {
+    : WorkerThreadMessageFilter(thread_safe_sender), next_request_id_(0) {
 }
 
 PushDispatcher::~PushDispatcher() {
@@ -28,43 +22,7 @@
   return next_request_id_++;
 }
 
-base::TaskRunner* PushDispatcher::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (!ShouldHandleMessage(msg))
-    return nullptr;
-
-  int request_id = -1;
-  int thread_id = 0;
-
-  const bool success = PickleIterator(msg).ReadInt(&request_id);
-  DCHECK(success);
-
-  {
-    base::AutoLock lock(request_id_map_lock_);
-    auto it = request_id_map_.find(request_id);
-    if (it != request_id_map_.end()) {
-      thread_id = it->second;
-      request_id_map_.erase(it);
-    }
-  }
-
-  if (!thread_id)
-    return main_thread_loop_proxy_.get();
-
-  return new WorkerThreadTaskRunner(thread_id);
-}
-
-bool PushDispatcher::OnMessageReceived(const IPC::Message& msg) {
-  if (!ShouldHandleMessage(msg))
-    return false;
-
-  bool handled = PushProvider::ThreadSpecificInstance(
-                     thread_safe_sender_.get(), this)->OnMessageReceived(msg);
-  DCHECK(handled);
-  return handled;
-}
-
-bool PushDispatcher::ShouldHandleMessage(const IPC::Message& msg) {
+bool PushDispatcher::ShouldHandleMessage(const IPC::Message& msg) const {
   // Note that not all Push API IPC messages flow through this class. A subset
   // of the API functionality requires a direct association with a document and
   // a frame, and for those cases the IPC messages are handled by a
@@ -79,4 +37,27 @@
          msg.type() == PushMessagingMsg_UnregisterError::ID;
 }
 
+void PushDispatcher::OnFilteredMessageReceived(const IPC::Message& msg) {
+  bool handled = PushProvider::ThreadSpecificInstance(
+                     thread_safe_sender(), this)->OnMessageReceived(msg);
+  DCHECK(handled);
+}
+
+bool PushDispatcher::GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                                 int* ipc_thread_id) {
+  int request_id = -1;
+
+  const bool success = PickleIterator(msg).ReadInt(&request_id);
+  DCHECK(success);
+
+  base::AutoLock lock(request_id_map_lock_);
+  auto it = request_id_map_.find(request_id);
+  if (it != request_id_map_.end()) {
+    *ipc_thread_id = it->second;
+    request_id_map_.erase(it);
+    return true;
+  }
+  return false;
+}
+
 }  // namespace content
diff --git a/content/child/push_messaging/push_dispatcher.h b/content/child/push_messaging/push_dispatcher.h
index db598fb..5eaf550 100644
--- a/content/child/push_messaging/push_dispatcher.h
+++ b/content/child/push_messaging/push_dispatcher.h
@@ -7,20 +7,12 @@
 
 #include <map>
 
-#include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
-#include "content/child/child_message_filter.h"
-#include "content/public/common/push_messaging_status.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
 
 namespace content {
 
-class ThreadSafeSender;
-
-class PushDispatcher : public ChildMessageFilter {
+class PushDispatcher : public WorkerThreadMessageFilter {
  public:
   explicit PushDispatcher(ThreadSafeSender* thread_safe_sender);
 
@@ -34,15 +26,11 @@
   ~PushDispatcher() override;
 
  private:
-  bool ShouldHandleMessage(const IPC::Message& msg);
-
-  // ChildMessageFilter implementation.
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
-
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
 
   base::Lock request_id_map_lock_;
   std::map<int, int> request_id_map_;  // Maps request id to thread id.
diff --git a/content/child/push_messaging/push_provider.h b/content/child/push_messaging/push_provider.h
index 3a0eec9..3a243c78 100644
--- a/content/child/push_messaging/push_provider.h
+++ b/content/child/push_messaging/push_provider.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "content/child/push_messaging/push_dispatcher.h"
 #include "content/child/worker_task_runner.h"
+#include "content/public/common/push_messaging_status.h"
 #include "third_party/WebKit/public/platform/WebPushError.h"
 #include "third_party/WebKit/public/platform/WebPushProvider.h"
 
diff --git a/content/child/quota_dispatcher.cc b/content/child/quota_dispatcher.cc
index 1a1577a..fa766dba 100644
--- a/content/child/quota_dispatcher.cc
+++ b/content/child/quota_dispatcher.cc
@@ -7,7 +7,6 @@
 #include "base/basictypes.h"
 #include "base/lazy_instance.h"
 #include "base/threading/thread_local.h"
-#include "content/child/child_thread.h"
 #include "content/child/quota_message_filter.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/common/quota_messages.h"
diff --git a/content/child/quota_message_filter.cc b/content/child/quota_message_filter.cc
index 139be25..e9290e48 100644
--- a/content/child/quota_message_filter.cc
+++ b/content/child/quota_message_filter.cc
@@ -4,19 +4,13 @@
 
 #include "content/child/quota_message_filter.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/child/quota_dispatcher.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "content/common/quota_messages.h"
 
 namespace content {
 
-QuotaMessageFilter::QuotaMessageFilter(
-    ThreadSafeSender* thread_safe_sender)
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(thread_safe_sender),
-      next_request_id_(0) {
+QuotaMessageFilter::QuotaMessageFilter(ThreadSafeSender* thread_safe_sender)
+    : WorkerThreadMessageFilter(thread_safe_sender), next_request_id_(0) {
 }
 
 QuotaMessageFilter::~QuotaMessageFilter() {}
@@ -38,35 +32,29 @@
   }
 }
 
-base::TaskRunner* QuotaMessageFilter::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != QuotaMsgStart)
-    return NULL;
+bool QuotaMessageFilter::ShouldHandleMessage(const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == QuotaMsgStart;
+}
 
-  int request_id = -1, thread_id = 0;
+void QuotaMessageFilter::OnFilteredMessageReceived(const IPC::Message& msg) {
+  QuotaDispatcher::ThreadSpecificInstance(thread_safe_sender(), this)
+      ->OnMessageReceived(msg);
+}
+
+bool QuotaMessageFilter::GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                                     int* ipc_thread_id) {
+  int request_id = -1;
   const bool success = PickleIterator(msg).ReadInt(&request_id);
   DCHECK(success);
 
-  {
-    base::AutoLock lock(request_id_map_lock_);
-    RequestIdToThreadId::iterator found = request_id_map_.find(request_id);
-    if (found != request_id_map_.end()) {
-      thread_id = found->second;
-      request_id_map_.erase(found);
-    }
+  base::AutoLock lock(request_id_map_lock_);
+  RequestIdToThreadId::iterator found = request_id_map_.find(request_id);
+  if (found != request_id_map_.end()) {
+    *ipc_thread_id = found->second;
+    request_id_map_.erase(found);
+    return true;
   }
-
-  if (!thread_id)
-    return main_thread_loop_proxy_.get();
-  return new WorkerThreadTaskRunner(thread_id);
-}
-
-bool QuotaMessageFilter::OnMessageReceived(const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != QuotaMsgStart)
-    return false;
-  QuotaDispatcher::ThreadSpecificInstance(thread_safe_sender_.get(), this)
-      ->OnMessageReceived(msg);
-  return true;
+  return false;
 }
 
 }  // namespace content
diff --git a/content/child/quota_message_filter.h b/content/child/quota_message_filter.h
index b13e705..d6135849 100644
--- a/content/child/quota_message_filter.h
+++ b/content/child/quota_message_filter.h
@@ -7,19 +7,12 @@
 
 #include <map>
 
-#include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
 
 namespace content {
 
-class ThreadSafeSender;
-
-class QuotaMessageFilter : public ChildMessageFilter {
+class QuotaMessageFilter : public WorkerThreadMessageFilter {
  public:
   explicit QuotaMessageFilter(ThreadSafeSender* thread_safe_sender);
 
@@ -35,16 +28,14 @@
   ~QuotaMessageFilter() override;
 
  private:
-  // ChildMessageFilter implementation:
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
 
   typedef std::map<int, int> RequestIdToThreadId;
 
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
   base::Lock request_id_map_lock_;
   RequestIdToThreadId request_id_map_;
   int next_request_id_;
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index ba7fe6f..bccff3b 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -16,7 +16,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
-#include "content/child/child_thread.h"
 #include "content/child/request_extra_data.h"
 #include "content/child/request_info.h"
 #include "content/child/resource_loader_bridge.h"
diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc
index fce8783..73b9a29 100644
--- a/content/child/service_worker/service_worker_dispatcher.cc
+++ b/content/child/service_worker/service_worker_dispatcher.cc
@@ -8,7 +8,7 @@
 #include "base/stl_util.h"
 #include "base/threading/thread_local.h"
 #include "base/trace_event/trace_event.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
 #include "content/child/service_worker/service_worker_provider_context.h"
 #include "content/child/service_worker/service_worker_registration_handle_reference.h"
@@ -346,11 +346,11 @@
   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
   if (provider == provider_contexts_.end())
     return;
-  provider->second->OnDisassociateRegistration();
   worker_to_provider_.erase(provider->second->installing_handle_id());
   worker_to_provider_.erase(provider->second->waiting_handle_id());
   worker_to_provider_.erase(provider->second->active_handle_id());
   worker_to_provider_.erase(provider->second->controller_handle_id());
+  provider->second->OnDisassociateRegistration();
 }
 
 void ServiceWorkerDispatcher::OnRegistered(
@@ -638,7 +638,7 @@
     const std::vector<int>& new_routing_ids) {
   // Make sure we're on the main document thread. (That must be the only
   // thread we get this message)
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   TRACE_EVENT1("ServiceWorker",
                "ServiceWorkerDispatcher::OnPostMessage",
                "Thread ID", thread_id);
diff --git a/content/child/service_worker/service_worker_message_filter.cc b/content/child/service_worker/service_worker_message_filter.cc
index b0554c0..3568ad7 100644
--- a/content/child/service_worker/service_worker_message_filter.cc
+++ b/content/child/service_worker/service_worker_message_filter.cc
@@ -4,10 +4,8 @@
 
 #include "content/child/service_worker/service_worker_message_filter.h"
 
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "content/common/service_worker/service_worker_messages.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "ipc/ipc_message_macros.h"
@@ -39,29 +37,26 @@
 }  // namespace
 
 ServiceWorkerMessageFilter::ServiceWorkerMessageFilter(ThreadSafeSender* sender)
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(sender) {}
+    : WorkerThreadMessageFilter(sender) {
+}
 
 ServiceWorkerMessageFilter::~ServiceWorkerMessageFilter() {}
 
-base::TaskRunner* ServiceWorkerMessageFilter::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != ServiceWorkerMsgStart)
-    return NULL;
-  int ipc_thread_id = 0;
-  const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
-  DCHECK(success);
-  if (!ipc_thread_id)
-    return main_thread_loop_proxy_.get();
-  return new WorkerThreadTaskRunner(ipc_thread_id);
+bool ServiceWorkerMessageFilter::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == ServiceWorkerMsgStart;
 }
 
-bool ServiceWorkerMessageFilter::OnMessageReceived(const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != ServiceWorkerMsgStart)
-    return false;
+void ServiceWorkerMessageFilter::OnFilteredMessageReceived(
+    const IPC::Message& msg) {
   ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
-      thread_safe_sender_.get())->OnMessageReceived(msg);
-  return true;
+      thread_safe_sender())->OnMessageReceived(msg);
+}
+
+bool ServiceWorkerMessageFilter::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  return PickleIterator(msg).ReadInt(ipc_thread_id);
 }
 
 void ServiceWorkerMessageFilter::OnStaleMessageReceived(
@@ -83,13 +78,13 @@
     int request_id,
     const ServiceWorkerRegistrationObjectInfo& info,
     const ServiceWorkerVersionAttributes& attrs) {
-  SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
                                    attrs.installing.handle_id);
-  SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
                                    attrs.waiting.handle_id);
-  SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
                                    attrs.active.handle_id);
-  SendRegistrationObjectDestroyed(thread_safe_sender_.get(), info.handle_id);
+  SendRegistrationObjectDestroyed(thread_safe_sender(), info.handle_id);
 }
 
 void ServiceWorkerMessageFilter::OnStaleSetVersionAttributes(
@@ -98,11 +93,11 @@
     int registration_handle_id,
     int changed_mask,
     const ServiceWorkerVersionAttributes& attrs) {
-  SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
                                    attrs.installing.handle_id);
-  SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
                                    attrs.waiting.handle_id);
-  SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(),
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(),
                                    attrs.active.handle_id);
   // Don't have to decrement registration refcount because the sender of the
   // SetVersionAttributes message doesn't increment it.
@@ -113,7 +108,7 @@
     int provider_id,
     const ServiceWorkerObjectInfo& info,
     bool should_notify_controllerchange) {
-  SendServiceWorkerObjectDestroyed(thread_safe_sender_.get(), info.handle_id);
+  SendServiceWorkerObjectDestroyed(thread_safe_sender(), info.handle_id);
 }
 
 }  // namespace content
diff --git a/content/child/service_worker/service_worker_message_filter.h b/content/child/service_worker/service_worker_message_filter.h
index dca7e7d..d6fdeb9 100644
--- a/content/child/service_worker/service_worker_message_filter.h
+++ b/content/child/service_worker/service_worker_message_filter.h
@@ -5,22 +5,17 @@
 #ifndef CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
 #define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
 
-#include "content/child/child_message_filter.h"
+#include "content/child/worker_thread_message_filter.h"
 #include "content/common/content_export.h"
 
-namespace base {
-class MessageLoopProxy;
-}
-
 namespace content {
 
-class ThreadSafeSender;
 struct ServiceWorkerObjectInfo;
 struct ServiceWorkerRegistrationObjectInfo;
 struct ServiceWorkerVersionAttributes;
 
 class CONTENT_EXPORT ServiceWorkerMessageFilter
-    : public NON_EXPORTED_BASE(ChildMessageFilter) {
+    : public NON_EXPORTED_BASE(WorkerThreadMessageFilter) {
  public:
   explicit ServiceWorkerMessageFilter(ThreadSafeSender* thread_safe_sender);
 
@@ -28,10 +23,13 @@
   ~ServiceWorkerMessageFilter() override;
 
  private:
-  // ChildMessageFilter implementation:
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
+
+  // ChildMessageFilter:
   void OnStaleMessageReceived(const IPC::Message& msg) override;
 
   // Message handlers for stale messages.
@@ -52,9 +50,6 @@
       const ServiceWorkerObjectInfo& info,
       bool should_notify_controllerchange);
 
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerMessageFilter);
 };
 
diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc
index db09351..915a1c96 100644
--- a/content/child/service_worker/service_worker_network_provider.cc
+++ b/content/child/service_worker/service_worker_network_provider.cc
@@ -5,7 +5,7 @@
 #include "content/child/service_worker/service_worker_network_provider.h"
 
 #include "base/atomic_sequence_num.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/service_worker/service_worker_provider_context.h"
 #include "content/common/service_worker/service_worker_messages.h"
 
@@ -38,24 +38,24 @@
 ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider(int render_frame_id)
     : provider_id_(GetNextProviderId()),
       context_(new ServiceWorkerProviderContext(provider_id_)) {
-  if (!ChildThread::current())
+  if (!ChildThreadImpl::current())
     return;  // May be null in some tests.
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new ServiceWorkerHostMsg_ProviderCreated(provider_id_, render_frame_id));
 }
 
 ServiceWorkerNetworkProvider::~ServiceWorkerNetworkProvider() {
-  if (!ChildThread::current())
+  if (!ChildThreadImpl::current())
     return;  // May be null in some tests.
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new ServiceWorkerHostMsg_ProviderDestroyed(provider_id_));
 }
 
 void ServiceWorkerNetworkProvider::SetServiceWorkerVersionId(
     int64 version_id) {
-  if (!ChildThread::current())
+  if (!ChildThreadImpl::current())
     return;  // May be null in some tests.
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new ServiceWorkerHostMsg_SetVersionId(provider_id_, version_id));
 }
 
diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc
index 129d557..d8273aa 100644
--- a/content/child/service_worker/service_worker_provider_context.cc
+++ b/content/child/service_worker/service_worker_provider_context.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/stl_util.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
 #include "content/child/service_worker/service_worker_registration_handle_reference.h"
@@ -20,9 +20,9 @@
 ServiceWorkerProviderContext::ServiceWorkerProviderContext(int provider_id)
     : provider_id_(provider_id),
       main_thread_loop_proxy_(base::MessageLoopProxy::current()) {
-  if (!ChildThread::current())
+  if (!ChildThreadImpl::current())
     return;  // May be null in some tests.
-  thread_safe_sender_ = ChildThread::current()->thread_safe_sender();
+  thread_safe_sender_ = ChildThreadImpl::current()->thread_safe_sender();
   ServiceWorkerDispatcher* dispatcher =
       ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
           thread_safe_sender_.get());
diff --git a/content/child/service_worker/web_service_worker_provider_impl.cc b/content/child/service_worker/web_service_worker_provider_impl.cc
index 52b6656..5b7d7406c 100644
--- a/content/child/service_worker/web_service_worker_provider_impl.cc
+++ b/content/child/service_worker/web_service_worker_provider_impl.cc
@@ -6,7 +6,6 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/logging.h"
-#include "content/child/child_thread.h"
 #include "content/child/service_worker/service_worker_dispatcher.h"
 #include "content/child/service_worker/service_worker_handle_reference.h"
 #include "content/child/service_worker/service_worker_provider_context.h"
diff --git a/content/child/shared_worker_devtools_agent.cc b/content/child/shared_worker_devtools_agent.cc
index 3a9b3509..26a51ed 100644
--- a/content/child/shared_worker_devtools_agent.cc
+++ b/content/child/shared_worker_devtools_agent.cc
@@ -4,7 +4,7 @@
 
 #include "content/child/shared_worker_devtools_agent.h"
 
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/devtools_messages.h"
 #include "ipc/ipc_channel.h"
 #include "third_party/WebKit/public/platform/WebCString.h"
@@ -95,7 +95,7 @@
 }
 
 bool SharedWorkerDevToolsAgent::Send(IPC::Message* message) {
-  return ChildThread::current()->Send(message);
+  return ChildThreadImpl::current()->Send(message);
 }
 
 }  // namespace content
diff --git a/content/child/thread_safe_sender.cc b/content/child/thread_safe_sender.cc
index d9ecfd1c..b8aef12 100644
--- a/content/child/thread_safe_sender.cc
+++ b/content/child/thread_safe_sender.cc
@@ -5,7 +5,7 @@
 #include "content/child/thread_safe_sender.h"
 
 #include "base/message_loop/message_loop_proxy.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "ipc/ipc_sync_message_filter.h"
 
 namespace content {
@@ -21,7 +21,7 @@
 
 bool ThreadSafeSender::Send(IPC::Message* msg) {
   if (main_loop_->BelongsToCurrentThread())
-    return ChildThread::current()->Send(msg);
+    return ChildThreadImpl::current()->Send(msg);
   return sync_filter_->Send(msg);
 }
 
diff --git a/content/child/thread_safe_sender.h b/content/child/thread_safe_sender.h
index 443e20a..37ad96b 100644
--- a/content/child/thread_safe_sender.h
+++ b/content/child/thread_safe_sender.h
@@ -19,9 +19,9 @@
 }
 
 namespace content {
-class ChildThread;
+class ChildThreadImpl;
 
-// The class of Sender returned by ChildThread::thread_safe_sender().
+// The class of Sender returned by ChildThreadImpl::thread_safe_sender().
 class CONTENT_EXPORT ThreadSafeSender
     : public IPC::Sender,
       public base::RefCountedThreadSafe<ThreadSafeSender> {
@@ -29,7 +29,7 @@
   bool Send(IPC::Message* msg) override;
 
  private:
-  friend class ChildThread;  // for construction
+  friend class ChildThreadImpl;  // for construction
   friend class IndexedDBDispatcherTest;
   friend class WebIDBCursorImplTest;
   friend class base::RefCountedThreadSafe<ThreadSafeSender>;
diff --git a/content/child/threaded_data_provider.cc b/content/child/threaded_data_provider.cc
index ccfe891..69ed34b 100644
--- a/content/child/threaded_data_provider.cc
+++ b/content/child/threaded_data_provider.cc
@@ -5,7 +5,7 @@
 #include "content/child/threaded_data_provider.h"
 
 #include "content/child/child_process.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/resource_dispatcher.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/child/webthread_impl.h"
@@ -127,12 +127,12 @@
       shm_size_(shm_size),
       background_thread_(static_cast<WebThreadImpl&>(
           *threaded_data_receiver->backgroundThread())),
-      ipc_channel_(ChildThread::current()->channel()),
+      ipc_channel_(ChildThreadImpl::current()->channel()),
       threaded_data_receiver_(threaded_data_receiver),
       resource_filter_active_(false),
       main_thread_task_runner_(main_thread_task_runner),
       main_thread_weak_factory_(this) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   DCHECK(ipc_channel_);
   DCHECK(threaded_data_receiver_);
   DCHECK(main_thread_task_runner_.get());
@@ -146,19 +146,19 @@
       background_thread_weak_factory_->GetWeakPtr(),
       main_thread_weak_factory_.GetWeakPtr(), request_id);
 
-  ChildThread::current()->channel()->AddFilter(filter_.get());
+  ChildThreadImpl::current()->channel()->AddFilter(filter_.get());
 }
 
 ThreadedDataProvider::~ThreadedDataProvider() {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
 
-  ChildThread::current()->channel()->RemoveFilter(filter_.get());
+  ChildThreadImpl::current()->channel()->RemoveFilter(filter_.get());
 
   delete threaded_data_receiver_;
 }
 
 void DestructOnMainThread(ThreadedDataProvider* data_provider) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
 
   // The ThreadedDataProvider must be destructed on the main thread to
   // be threadsafe when removing the message filter and releasing the shared
@@ -167,7 +167,7 @@
 }
 
 void ThreadedDataProvider::Stop() {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
 
   // Make sure we don't get called by on the main thread anymore via weak
   // pointers we've passed to the filter.
@@ -207,7 +207,7 @@
 }
 
 void ThreadedDataProvider::OnResourceMessageFilterAddedMainThread() {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   DCHECK(background_thread_weak_factory_);
 
   // We bounce this message from the I/O thread via the main thread and then
@@ -264,7 +264,7 @@
 
 void ThreadedDataProvider::OnReceivedDataOnForegroundThread(
     const char* data, int data_length, int encoded_data_length) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
 
   background_thread_.message_loop()->PostTask(FROM_HERE,
       base::Bind(&ThreadedDataProvider::ForwardAndACKData,
diff --git a/content/child/webblobregistry_impl.cc b/content/child/webblobregistry_impl.cc
index 81a1f4b6..7b4ec42 100644
--- a/content/child/webblobregistry_impl.cc
+++ b/content/child/webblobregistry_impl.cc
@@ -9,7 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/shared_memory.h"
 #include "base/message_loop/message_loop.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/thread_safe_sender.h"
 #include "content/common/fileapi/webblob_messages.h"
 #include "storage/common/data_element.h"
@@ -158,7 +158,7 @@
   // writing it directly to the IPC channel.
   size_t shared_memory_size = std::min(data.size(), kMaxSharedMemoryBytes);
   scoped_ptr<base::SharedMemory> shared_memory(
-      ChildThread::AllocateSharedMemory(shared_memory_size, sender_.get()));
+      ChildThreadImpl::AllocateSharedMemory(shared_memory_size, sender_.get()));
   CHECK(shared_memory.get());
   if (!shared_memory->Map(shared_memory_size))
     CHECK(false);
@@ -179,19 +179,19 @@
 
 void WebBlobRegistryImpl::registerStreamURL(
     const WebURL& url, const WebString& content_type) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   sender_->Send(new StreamHostMsg_StartBuilding(url, content_type.utf8()));
 }
 
 void WebBlobRegistryImpl::registerStreamURL(
     const WebURL& url, const WebURL& src_url) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   sender_->Send(new StreamHostMsg_Clone(url, src_url));
 }
 
 void WebBlobRegistryImpl::addDataToStream(const WebURL& url,
                                           const char* data, size_t length) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   if (length == 0)
     return;
   if (length < kLargeThresholdBytes) {
@@ -204,8 +204,8 @@
     size_t shared_memory_size = std::min(
         length, kMaxSharedMemoryBytes);
     scoped_ptr<base::SharedMemory> shared_memory(
-        ChildThread::AllocateSharedMemory(shared_memory_size,
-                                          sender_.get()));
+        ChildThreadImpl::AllocateSharedMemory(shared_memory_size,
+                                              sender_.get()));
     CHECK(shared_memory.get());
     if (!shared_memory->Map(shared_memory_size))
       CHECK(false);
@@ -224,22 +224,22 @@
 }
 
 void WebBlobRegistryImpl::flushStream(const WebURL& url) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   sender_->Send(new StreamHostMsg_Flush(url));
 }
 
 void WebBlobRegistryImpl::finalizeStream(const WebURL& url) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   sender_->Send(new StreamHostMsg_FinishBuilding(url));
 }
 
 void WebBlobRegistryImpl::abortStream(const WebURL& url) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   sender_->Send(new StreamHostMsg_AbortBuilding(url));
 }
 
 void WebBlobRegistryImpl::unregisterStreamURL(const WebURL& url) {
-  DCHECK(ChildThread::current());
+  DCHECK(ChildThreadImpl::current());
   sender_->Send(new StreamHostMsg_Remove(url));
 }
 
diff --git a/content/child/webcrypto/webcrypto_impl.cc b/content/child/webcrypto/webcrypto_impl.cc
index 9a3924b..3270fbc0 100644
--- a/content/child/webcrypto/webcrypto_impl.cc
+++ b/content/child/webcrypto/webcrypto_impl.cc
@@ -20,7 +20,6 @@
 #include "content/child/webcrypto/generate_key_result.h"
 #include "content/child/webcrypto/status.h"
 #include "content/child/webcrypto/webcrypto_util.h"
-#include "content/child/worker_thread_task_runner.h"
 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 
@@ -135,19 +134,10 @@
   }
 }
 
-// Gets a task runner for the current thread. The current thread is either:
-//
-//   * The main Blink thread
-//   * A Blink web worker thread
-//
-// A different mechanism is needed for posting to these threads. The main
-// thread has an associated message loop and can simply use
-// base::ThreadTaskRunnerHandle. Whereas the web worker threads are managed by
-// Blink and need to be indirected through WorkerThreadTaskRunner.
+// Gets a task runner for the current thread.
 scoped_refptr<base::TaskRunner> GetCurrentBlinkThread() {
-  if (base::ThreadTaskRunnerHandle::IsSet())
-    return base::ThreadTaskRunnerHandle::Get();
-  return WorkerThreadTaskRunner::current();
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
+  return base::ThreadTaskRunnerHandle::Get();
 }
 
 // --------------------------------------------------------------------
diff --git a/content/child/webmessageportchannel_impl.cc b/content/child/webmessageportchannel_impl.cc
index c3de36fb..725e5956 100644
--- a/content/child/webmessageportchannel_impl.cc
+++ b/content/child/webmessageportchannel_impl.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "content/child/child_process.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/message_port_messages.h"
 #include "third_party/WebKit/public/platform/WebMessagePortChannelClient.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -56,7 +56,7 @@
     Send(new MessagePortHostMsg_DestroyMessagePort(message_port_id_));
 
   if (route_id_ != MSG_ROUTING_NONE)
-    ChildThread::current()->GetRouter()->RemoveRoute(route_id_);
+    ChildThreadImpl::current()->GetRouter()->RemoveRoute(route_id_);
 }
 
 // static
@@ -169,7 +169,7 @@
     Send(new MessagePortHostMsg_ReleaseMessages(message_port_id_));
   }
 
-  ChildThread::current()->GetRouter()->AddRoute(route_id_, this);
+  ChildThreadImpl::current()->GetRouter()->AddRoute(route_id_, this);
 }
 
 void WebMessagePortChannelImpl::Entangle(
@@ -216,7 +216,7 @@
     return;
   }
 
-  ChildThread::current()->GetRouter()->Send(message);
+  ChildThreadImpl::current()->GetRouter()->Send(message);
 }
 
 bool WebMessagePortChannelImpl::OnMessageReceived(const IPC::Message& message) {
diff --git a/content/child/websocket_bridge.cc b/content/child/websocket_bridge.cc
index 5b32702..e091023 100644
--- a/content/child/websocket_bridge.cc
+++ b/content/child/websocket_bridge.cc
@@ -11,7 +11,7 @@
 
 #include "base/logging.h"
 #include "base/strings/string_util.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/websocket_dispatcher.h"
 #include "content/common/websocket.h"
 #include "content/common/websocket_messages.h"
@@ -52,7 +52,7 @@
   if (channel_id_ != kInvalidChannelId) {
     // The connection is abruptly disconnected by the renderer without
     // closing handshake.
-    ChildThread::current()->Send(
+    ChildThreadImpl::current()->Send(
         new WebSocketMsg_DropChannel(channel_id_,
                                      false,
                                      kAbnormalShutdownOpCode,
@@ -214,7 +214,7 @@
     WebSocketHandleClient* client) {
   DCHECK_EQ(kInvalidChannelId, channel_id_);
   WebSocketDispatcher* dispatcher =
-      ChildThread::current()->websocket_dispatcher();
+      ChildThreadImpl::current()->websocket_dispatcher();
   channel_id_ = dispatcher->AddBridge(this);
   client_ = client;
 
@@ -227,7 +227,7 @@
            << JoinString(protocols_to_pass, ", ") << "), "
            << origin_to_pass.string() << ")";
 
-  ChildThread::current()->Send(new WebSocketHostMsg_AddChannelRequest(
+  ChildThreadImpl::current()->Send(new WebSocketHostMsg_AddChannelRequest(
       channel_id_, url, protocols_to_pass, origin_to_pass, render_frame_id_));
 }
 
@@ -255,7 +255,7 @@
            << fin << ", " << type_to_pass << ", "
            << "(data size = "  << size << "))";
 
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new WebSocketMsg_SendFrame(channel_id_,
                                  fin,
                                  type_to_pass,
@@ -268,7 +268,7 @@
 
   DVLOG(1) << "Bridge #" << channel_id_ << " FlowControl(" << quota << ")";
 
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new WebSocketMsg_FlowControl(channel_id_, quota));
 }
 
@@ -281,7 +281,7 @@
   DVLOG(1) << "Bridge #" << channel_id_ << " Close("
            << code << ", " << reason_to_pass << ")";
   // This method is for closing handshake and hence |was_clean| shall be true.
-  ChildThread::current()->Send(
+  ChildThreadImpl::current()->Send(
       new WebSocketMsg_DropChannel(channel_id_, true, code, reason_to_pass));
 }
 
@@ -289,7 +289,7 @@
   if (channel_id_ == kInvalidChannelId)
     return;
   WebSocketDispatcher* dispatcher =
-      ChildThread::current()->websocket_dispatcher();
+      ChildThreadImpl::current()->websocket_dispatcher();
   dispatcher->RemoveBridge(channel_id_);
 
   channel_id_ = kInvalidChannelId;
diff --git a/content/child/worker_task_runner.cc b/content/child/worker_task_runner.cc
index 45b3619..4fc5bde 100644
--- a/content/child/worker_task_runner.cc
+++ b/content/child/worker_task_runner.cc
@@ -30,8 +30,7 @@
 } // namespace
 
 struct WorkerTaskRunner::ThreadLocalState {
-  explicit ThreadLocalState(int id) : id_(id) {}
-  int id_;
+  ThreadLocalState() {}
   ObserverList<WorkerTaskRunner::Observer> stop_observers_;
 };
 
@@ -59,7 +58,7 @@
 int WorkerTaskRunner::CurrentWorkerId() {
   if (!current_tls_.Get())
     return 0;
-  return current_tls_.Get()->id_;
+  return base::PlatformThread::CurrentId();
 }
 
 WorkerTaskRunner* WorkerTaskRunner::Instance() {
@@ -84,9 +83,9 @@
 void WorkerTaskRunner::OnWorkerRunLoopStarted(const WebWorkerRunLoop& loop) {
   DCHECK(!current_tls_.Get());
   DCHECK(!base::PlatformThread::CurrentRef().is_null());
-  int id = base::PlatformThread::CurrentId();
-  current_tls_.Set(new ThreadLocalState(id));
+  current_tls_.Set(new ThreadLocalState());
 
+  int id = base::PlatformThread::CurrentId();
   base::AutoLock locker_(loop_map_lock_);
   loop_map_[id] = loop;
 }
diff --git a/content/child/worker_thread_message_filter.cc b/content/child/worker_thread_message_filter.cc
new file mode 100644
index 0000000..ac11a3dbd
--- /dev/null
+++ b/content/child/worker_thread_message_filter.cc
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/worker_thread_message_filter.h"
+
+#include "base/thread_task_runner_handle.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/child/worker_thread_task_runner.h"
+#include "ipc/ipc_message_macros.h"
+
+namespace content {
+
+WorkerThreadMessageFilter::WorkerThreadMessageFilter(
+    ThreadSafeSender* thread_safe_sender)
+    : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      thread_safe_sender_(thread_safe_sender) {
+}
+
+WorkerThreadMessageFilter::~WorkerThreadMessageFilter() {
+}
+
+base::TaskRunner* WorkerThreadMessageFilter::OverrideTaskRunnerForMessage(
+    const IPC::Message& msg) {
+  if (!ShouldHandleMessage(msg))
+    return nullptr;
+  int ipc_thread_id = 0;
+  const bool success = GetWorkerThreadIdForMessage(msg, &ipc_thread_id);
+  DCHECK(success);
+  if (!ipc_thread_id)
+    return main_thread_task_runner_.get();
+  return new WorkerThreadTaskRunner(ipc_thread_id);
+}
+
+bool WorkerThreadMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+  if (!ShouldHandleMessage(msg))
+    return false;
+  OnFilteredMessageReceived(msg);
+  return true;
+}
+
+}  // namespace content
diff --git a/content/child/worker_thread_message_filter.h b/content/child/worker_thread_message_filter.h
new file mode 100644
index 0000000..56db521b
--- /dev/null
+++ b/content/child/worker_thread_message_filter.h
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_WORKER_THREAD_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_WORKER_THREAD_MESSAGE_FILTER_H_
+
+#include "content/child/child_message_filter.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace content {
+
+class ThreadSafeSender;
+
+// A base class for filtering IPC messages targeted for worker threads.
+class WorkerThreadMessageFilter : public ChildMessageFilter {
+ public:
+  explicit WorkerThreadMessageFilter(ThreadSafeSender* thread_safe_sender);
+
+ protected:
+  ~WorkerThreadMessageFilter() override;
+
+  base::SingleThreadTaskRunner* main_thread_task_runner() {
+    return main_thread_task_runner_.get();
+  }
+  ThreadSafeSender* thread_safe_sender() { return thread_safe_sender_.get(); }
+
+ private:
+  // Returns whether this filter should process |msg|.
+  virtual bool ShouldHandleMessage(const IPC::Message& msg) const = 0;
+
+  // Processes the IPC message in the worker thread, if the filter could extract
+  // its thread id. Otherwise, runs in the main thread. It only receives a
+  // message if ShouldHandleMessage() returns true for it.
+  virtual void OnFilteredMessageReceived(const IPC::Message& msg) = 0;
+
+  // Attempts to extract the thread-id of the worker-thread that should process
+  // the IPC message. Returns whether the thread-id could be determined and set
+  // in |ipc_thread_id|.
+  virtual bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                           int* ipc_thread_id) = 0;
+
+  // ChildMessageFilter implementation:
+  base::TaskRunner* OverrideTaskRunnerForMessage(const IPC::Message& msg) final;
+  bool OnMessageReceived(const IPC::Message& msg) final;
+
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkerThreadMessageFilter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_WORKER_THREAD_MESSAGE_FILTER_H_
diff --git a/content/child/worker_thread_task_runner.cc b/content/child/worker_thread_task_runner.cc
index 8e5b2e7..da7bc91 100644
--- a/content/child/worker_thread_task_runner.cc
+++ b/content/child/worker_thread_task_runner.cc
@@ -13,13 +13,6 @@
     : worker_thread_id_(worker_thread_id) {
 }
 
-scoped_refptr<WorkerThreadTaskRunner> WorkerThreadTaskRunner::current() {
-  int worker_thread_id = WorkerTaskRunner::Instance()->CurrentWorkerId();
-  if (!worker_thread_id)
-    return scoped_refptr<WorkerThreadTaskRunner>();
-  return make_scoped_refptr(new WorkerThreadTaskRunner(worker_thread_id));
-}
-
 bool WorkerThreadTaskRunner::PostDelayedTask(
     const tracked_objects::Location& /* from_here */,
     const base::Closure& task,
diff --git a/content/child/worker_thread_task_runner.h b/content/child/worker_thread_task_runner.h
index 5acafbd8..8e70128 100644
--- a/content/child/worker_thread_task_runner.h
+++ b/content/child/worker_thread_task_runner.h
@@ -17,10 +17,6 @@
  public:
   explicit WorkerThreadTaskRunner(int worker_thread_id);
 
-  // Gets the WorkerThreadTaskRunner for the current worker thread.
-  // This returns non-null value only when it is called on a worker thread.
-  static scoped_refptr<WorkerThreadTaskRunner> current();
-
   // TaskRunner overrides.
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const base::Closure& task,
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index baf65ce..1760a33 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -49,6 +49,42 @@
   }
 }
 
+if (is_chromeos && use_v4lplugin) {
+  action("libv4l2_generate_stubs") {
+    extra_header = "gpu/media/v4l2_stub_header.fragment"
+
+    script = "../../tools/generate_stubs/generate_stubs.py"
+    sources = [
+      "gpu/media/v4l2.sig",
+    ]
+    inputs = [
+      extra_header,
+    ]
+    stubs_filename_root = "v4l2_stubs"
+
+    outputs = [
+      "$target_gen_dir/gpu/media/$stubs_filename_root.cc",
+      "$target_gen_dir/gpu/media/$stubs_filename_root.h",
+    ]
+    args = [
+      "-i",
+      rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+      "-o",
+      rebase_path("$target_gen_dir/gpu/media", root_build_dir),
+      "-t",
+      "posix_stubs",
+      "-e",
+      rebase_path(extra_header, root_build_dir),
+      "-s",
+      stubs_filename_root,
+      "-p",
+      "content/common/gpu/media",
+    ]
+
+    args += rebase_path(sources, root_build_dir)
+  }
+}
+
 if (is_mac) {
   action("libvt_generate_stubs") {
     extra_header = "gpu/media/vt_stubs_header.fragment"
@@ -280,32 +316,46 @@
   }
 
   if (is_chromeos) {
+    if (use_v4lplugin) {
+      defines += [ "USE_LIBV4L2" ]
+      sources += get_target_outputs(":libv4l2_generate_stubs")
+      deps += [ ":libv4l2_generate_stubs" ]
+    }
     if (use_v4l2_codec) {
       defines += [ "USE_V4L2_CODEC" ]
-    }
-    if (cpu_arch == "arm" || (use_ozone && use_v4l2_codec)) {
       sources += [
+        "gpu/media/accelerated_video_decoder.h",
         "gpu/media/generic_v4l2_video_device.cc",
         "gpu/media/generic_v4l2_video_device.h",
+        "gpu/media/h264_decoder.cc",
+        "gpu/media/h264_decoder.h",
+        "gpu/media/h264_dpb.cc",
+        "gpu/media/h264_dpb.h",
         "gpu/media/v4l2_image_processor.cc",
         "gpu/media/v4l2_image_processor.h",
+        "gpu/media/v4l2_slice_video_decode_accelerator.cc",
+        "gpu/media/v4l2_slice_video_decode_accelerator.h",
         "gpu/media/v4l2_video_decode_accelerator.cc",
         "gpu/media/v4l2_video_decode_accelerator.h",
         "gpu/media/v4l2_video_device.cc",
         "gpu/media/v4l2_video_device.h",
         "gpu/media/v4l2_video_encode_accelerator.cc",
         "gpu/media/v4l2_video_encode_accelerator.h",
+        "gpu/media/vp8_decoder.cc",
+        "gpu/media/vp8_decoder.h",
+        "gpu/media/vp8_picture.cc",
+        "gpu/media/vp8_picture.h",
       ]
       libs = [
         "EGL",
         "GLESv2",
       ]
-      if (cpu_arch == "arm") {
-        sources += [
-          "gpu/media/tegra_v4l2_video_device.cc",
-          "gpu/media/tegra_v4l2_video_device.h",
-        ]
-      }
+    }
+    if (cpu_arch == "arm") {
+      sources += [
+        "gpu/media/tegra_v4l2_video_device.cc",
+        "gpu/media/tegra_v4l2_video_device.h",
+      ]
     }
     if (cpu_arch != "arm") {
       sources += [
diff --git a/content/common/common.gni b/content/common/common.gni
index e192ae2..597cd1b5 100644
--- a/content/common/common.gni
+++ b/content/common/common.gni
@@ -13,9 +13,10 @@
                 [ "../content_common.gypi" ])
 
 declare_args() {
-  # TODO(henryhsu): This flag should be removed after the linux header of
-  # trybot is updated.
-  # Indicates if Video4Linux2 codec is used. This is used for x86 CrOS
-  # platform which has v4l2 hardware encoder / decoder.
+  # Indicates if V4L plugin is used.
+  use_v4lplugin = false
+
+  # Indicates if Video4Linux2 codec is used. This is used for all CrOS
+  # platforms which have v4l2 hardware encoder / decoder.
   use_v4l2_codec = false
 }
diff --git a/content/common/gpu/client/DEPS b/content/common/gpu/client/DEPS
index 2e15de34..1aea663 100644
--- a/content/common/gpu/client/DEPS
+++ b/content/common/gpu/client/DEPS
@@ -1,3 +1,7 @@
+include_rules = [
+  "+cc/blink",
+]
+
 specific_include_rules = {
   # Tests can make use of content/browser/ infrastructure.
   ".*browsertest\.cc": [
diff --git a/content/common/gpu/client/context_provider_command_buffer.h b/content/common/gpu/client/context_provider_command_buffer.h
index 39c7fef..5be1e423 100644
--- a/content/common/gpu/client/context_provider_command_buffer.h
+++ b/content/common/gpu/client/context_provider_command_buffer.h
@@ -9,10 +9,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
+#include "cc/blink/context_provider_web_context.h"
 #include "cc/output/context_provider.h"
 #include "content/common/content_export.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
 
 namespace webkit {
 namespace gpu {
@@ -25,7 +25,7 @@
 // Implementation of cc::ContextProvider that provides a
 // WebGraphicsContext3DCommandBufferImpl context and a GrContext.
 class CONTENT_EXPORT ContextProviderCommandBuffer
-    : NON_EXPORTED_BASE(public webkit::gpu::ContextProviderWebContext) {
+    : NON_EXPORTED_BASE(public cc_blink::ContextProviderWebContext) {
  public:
   static scoped_refptr<ContextProviderCommandBuffer> Create(
       scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
@@ -33,7 +33,7 @@
 
   CommandBufferProxyImpl* GetCommandBufferProxy();
 
-  // ContextProviderWebContext implementation.
+  // cc_blink::ContextProviderWebContext implementation.
   WebGraphicsContext3DCommandBufferImpl* WebContext3D() override;
 
   // cc::ContextProvider implementation.
diff --git a/content/common/gpu/media/OWNERS b/content/common/gpu/media/OWNERS
index dbb1145..29eb0cd 100644
--- a/content/common/gpu/media/OWNERS
+++ b/content/common/gpu/media/OWNERS
@@ -2,5 +2,4 @@
 posciak@chromium.org
 sandersd@chromium.org
 scherkus@chromium.org
-vrk@chromium.org
 wuchengli@chromium.org
diff --git a/content/common/gpu/media/fake_video_decode_accelerator.cc b/content/common/gpu/media/fake_video_decode_accelerator.cc
new file mode 100644
index 0000000..84a40eb
--- /dev/null
+++ b/content/common/gpu/media/fake_video_decode_accelerator.cc
@@ -0,0 +1,178 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/media/fake_video_decode_accelerator.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "media/base/bitstream_buffer.h"
+#include "media/base/limits.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_surface_glx.h"
+
+namespace content {
+
+static const uint32 kDefaultTextureTarget = GL_TEXTURE_2D;
+// Must be at least 2 since the rendering helper will switch between textures
+// and if there is only one, it will wait for the next one that will never come.
+// Must also be an even number as otherwise there won't be the same amount of
+// white and black frames.
+static const unsigned int kNumBuffers = media::limits::kMaxVideoFrames +
+    (media::limits::kMaxVideoFrames & 1u);
+
+FakeVideoDecodeAccelerator::FakeVideoDecodeAccelerator(
+    gfx::GLContext* gl,
+    gfx::Size size,
+    const base::Callback<bool(void)>& make_context_current)
+    : child_message_loop_proxy_(base::MessageLoopProxy::current()),
+      client_(NULL),
+      make_context_current_(make_context_current),
+      gl_(gl),
+      frame_buffer_size_(size),
+      flushing_(false),
+      weak_this_factory_(this) {
+}
+
+FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() {
+}
+
+bool FakeVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile,
+                                            Client* client) {
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  if (profile == media::VIDEO_CODEC_PROFILE_UNKNOWN) {
+    LOG(ERROR) << "unknown codec profile";
+    return false;
+  }
+  // V4L2VideoDecodeAccelerator waits until first decode call to ask for buffers
+  // This class asks for it on initialization instead.
+  client_ = client;
+  client_->ProvidePictureBuffers(kNumBuffers,
+                                 frame_buffer_size_,
+                                 kDefaultTextureTarget);
+  return true;
+}
+
+void FakeVideoDecodeAccelerator::Decode(
+    const media::BitstreamBuffer& bitstream_buffer) {
+  int bitstream_buffer_id = bitstream_buffer.id();
+  queued_bitstream_ids_.push(bitstream_buffer_id);
+  child_message_loop_proxy_->PostTask(
+      FROM_HERE,
+      base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+                 weak_this_factory_.GetWeakPtr()));
+}
+
+// Similar to UseOutputBitstreamBuffer for the encode accelerator.
+void FakeVideoDecodeAccelerator::AssignPictureBuffers(
+    const std::vector<media::PictureBuffer>& buffers) {
+  DCHECK(buffers.size() == kNumBuffers);
+  DCHECK(!(buffers.size()%2));
+
+  // Save buffers and mark all buffers as ready for use.
+  scoped_ptr<uint8[]> white_data(
+      new uint8[frame_buffer_size_.width() * frame_buffer_size_.height() * 4]);
+  memset(white_data.get(),
+         UINT8_MAX,
+         frame_buffer_size_.width() * frame_buffer_size_.height() * 4);
+  scoped_ptr<uint8[]> black_data(
+      new uint8[frame_buffer_size_.width() * frame_buffer_size_.height() * 4]);
+  memset(black_data.get(),
+         0,
+         frame_buffer_size_.width() * frame_buffer_size_.height() * 4);
+  if (!make_context_current_.Run()) {
+    LOG(ERROR) << "ReusePictureBuffer(): could not make context current";
+    return;
+  }
+  for (size_t index = 0; index < buffers.size(); ++index) {
+    glBindTexture(GL_TEXTURE_2D, buffers[index].texture_id());
+    // Every other frame white and the rest black.
+    uint8* data = index%2 ? white_data.get():black_data.get();
+    glTexImage2D(GL_TEXTURE_2D,
+                 0,
+                 GL_RGBA,
+                 frame_buffer_size_.width(),
+                 frame_buffer_size_.height(),
+                 0,
+                 GL_RGBA,
+                 GL_UNSIGNED_BYTE,
+                 data);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glBindTexture(GL_TEXTURE_2D, 0);
+    free_output_buffers_.push(buffers[index].id());
+  }
+  child_message_loop_proxy_->PostTask(
+      FROM_HERE,
+      base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+                 weak_this_factory_.GetWeakPtr()));
+}
+
+void FakeVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
+  free_output_buffers_.push(picture_buffer_id);
+  child_message_loop_proxy_->PostTask(
+      FROM_HERE,
+      base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+                 weak_this_factory_.GetWeakPtr()));
+}
+
+void FakeVideoDecodeAccelerator::Flush() {
+  flushing_ = true;
+  child_message_loop_proxy_->PostTask(
+      FROM_HERE,
+      base::Bind(&FakeVideoDecodeAccelerator::DoPictureReady,
+                 weak_this_factory_.GetWeakPtr()));
+}
+
+void FakeVideoDecodeAccelerator::Reset() {
+  while (!queued_bitstream_ids_.empty()) {
+    client_->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_.front());
+    queued_bitstream_ids_.pop();
+  }
+  client_->NotifyResetDone();
+}
+
+void FakeVideoDecodeAccelerator::Destroy() {
+  while (!queued_bitstream_ids_.empty()) {
+    client_->NotifyEndOfBitstreamBuffer(queued_bitstream_ids_.front());
+    queued_bitstream_ids_.pop();
+  }
+  delete this;
+}
+
+bool FakeVideoDecodeAccelerator::CanDecodeOnIOThread() {
+  return true;
+}
+
+void FakeVideoDecodeAccelerator::DoPictureReady() {
+  if (flushing_ && queued_bitstream_ids_.empty()) {
+    flushing_ = false;
+    client_->NotifyFlushDone();
+  }
+  while (!free_output_buffers_.empty() && !queued_bitstream_ids_.empty()) {
+    int bitstream_id = queued_bitstream_ids_.front();
+    queued_bitstream_ids_.pop();
+    int buffer_id = free_output_buffers_.front();
+    free_output_buffers_.pop();
+
+    const media::Picture picture =
+        media::Picture(buffer_id,
+                       bitstream_id,
+                       gfx::Rect(frame_buffer_size_),
+                       false);
+    client_->PictureReady(picture);
+    // Bitstream no longer needed.
+    client_->NotifyEndOfBitstreamBuffer(bitstream_id);
+    if (flushing_ && queued_bitstream_ids_.empty()) {
+      flushing_ = false;
+      client_->NotifyFlushDone();
+    }
+  }
+}
+
+}  // namespace content
diff --git a/content/common/gpu/media/fake_video_decode_accelerator.h b/content/common/gpu/media/fake_video_decode_accelerator.h
new file mode 100644
index 0000000..de7df4ae
--- /dev/null
+++ b/content/common/gpu/media/fake_video_decode_accelerator.h
@@ -0,0 +1,72 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_FAKE_VIDEO_DECODE_ACCELERATOR_H_
+#define CONTENT_COMMON_GPU_MEDIA_FAKE_VIDEO_DECODE_ACCELERATOR_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/common/content_export.h"
+#include "media/video/video_decode_accelerator.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gl/gl_context.h"
+
+namespace content {
+
+class CONTENT_EXPORT FakeVideoDecodeAccelerator
+    : public media::VideoDecodeAccelerator {
+ public:
+  FakeVideoDecodeAccelerator(
+      gfx::GLContext* gl,
+      gfx::Size size,
+      const base::Callback<bool(void)>& make_context_current);
+  ~FakeVideoDecodeAccelerator() override;
+
+  bool Initialize(media::VideoCodecProfile profile,
+                  Client* client) override;
+  void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
+  void AssignPictureBuffers(
+      const std::vector<media::PictureBuffer>& buffers) override;
+  void ReusePictureBuffer(int32 picture_buffer_id) override;
+  void Flush() override;
+  void Reset() override;
+  void Destroy() override;
+  bool CanDecodeOnIOThread() override;
+
+ private:
+  void DoPictureReady();
+
+  // The message loop that created the class. Used for all callbacks. This
+  // class expects all calls to this class to be on this message loop (not
+  // checked).
+  const scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
+
+  Client* client_;
+
+  // Make our context current before running any GL entry points.
+  base::Callback<bool(void)> make_context_current_;
+  gfx::GLContext* gl_;
+
+  // Output picture size.
+  gfx::Size frame_buffer_size_;
+
+  // Picture buffer ids that are available for putting fake frames in.
+  std::queue<int> free_output_buffers_;
+  // BitstreamBuffer ids for buffers that contain new data to decode.
+  std::queue<int> queued_bitstream_ids_;
+
+  bool flushing_;
+
+  // The WeakPtrFactory for |weak_this_|.
+  base::WeakPtrFactory<FakeVideoDecodeAccelerator> weak_this_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeVideoDecodeAccelerator);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_GPU_MEDIA_FAKE_VIDEO_DECODE_ACCELERATOR_H_
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
index 8042690..4ab02c0 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
@@ -22,6 +22,7 @@
 #include "ipc/message_filter.h"
 #include "media/base/limits.h"
 #include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image.h"
 #include "ui/gl/gl_surface_egl.h"
 
 #if defined(OS_WIN)
@@ -30,18 +31,15 @@
 #elif defined(OS_MACOSX)
 #include "content/common/gpu/media/vt_video_decode_accelerator.h"
 #elif defined(OS_CHROMEOS)
-#if defined(ARCH_CPU_ARMEL) && defined(USE_LIBV4L2)
+#if defined(USE_V4L2_CODEC)
 #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h"
-#endif  // defined(ARCH_CPU_ARMEL)
-#if defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC))
 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
 #include "content/common/gpu/media/v4l2_video_device.h"
-// defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC))
 #endif
 #if defined(ARCH_CPU_X86_FAMILY)
 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
 #include "ui/gl/gl_implementation.h"
-#endif  // defined(ARCH_CPU_X86_FAMILY)
+#endif
 #elif defined(USE_OZONE)
 #include "media/ozone/media_ozone_platform.h"
 #elif defined(OS_ANDROID)
@@ -302,8 +300,7 @@
 scoped_ptr<media::VideoDecodeAccelerator>
 GpuVideoDecodeAccelerator::CreateV4L2VDA() {
   scoped_ptr<media::VideoDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && (defined(ARCH_CPU_ARMEL) || \
-    (defined(USE_OZONE) && defined(USE_V4L2_CODEC)))
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
   scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
   if (device.get()) {
     decoder.reset(new V4L2VideoDecodeAccelerator(
@@ -321,7 +318,7 @@
 scoped_ptr<media::VideoDecodeAccelerator>
 GpuVideoDecodeAccelerator::CreateV4L2SliceVDA() {
   scoped_ptr<media::VideoDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_LIBV4L2)
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
   scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
   if (device.get()) {
     decoder.reset(new V4L2SliceVideoDecodeAccelerator(
@@ -336,11 +333,24 @@
   return decoder.Pass();
 }
 
+void GpuVideoDecodeAccelerator::BindImage(uint32 client_texture_id,
+                                          uint32 texture_target,
+                                          scoped_refptr<gfx::GLImage> image) {
+  gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder();
+  gpu::gles2::TextureManager* texture_manager =
+      command_decoder->GetContextGroup()->texture_manager();
+  gpu::gles2::TextureRef* ref = texture_manager->GetTexture(client_texture_id);
+  if (ref)
+    texture_manager->SetLevelImage(ref, texture_target, 0, image.get());
+}
+
 scoped_ptr<media::VideoDecodeAccelerator>
 GpuVideoDecodeAccelerator::CreateVaapiVDA() {
   scoped_ptr<media::VideoDecodeAccelerator> decoder;
 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
-  decoder.reset(new VaapiVideoDecodeAccelerator(make_context_current_));
+  decoder.reset(new VaapiVideoDecodeAccelerator(
+      make_context_current_, base::Bind(&GpuVideoDecodeAccelerator::BindImage,
+                                        base::Unretained(this))));
 #endif
   return decoder.Pass();
 }
@@ -467,15 +477,9 @@
                                       width, height, 1, 0, format, 0, false);
       }
     }
-    uint32 service_texture_id;
-    if (!command_decoder->GetServiceTextureId(
-            texture_ids[i], &service_texture_id)) {
-      DLOG(ERROR) << "Failed to translate texture!";
-      NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
-      return;
-    }
-    buffers.push_back(media::PictureBuffer(
-        buffer_ids[i], texture_dimensions_, service_texture_id));
+    buffers.push_back(media::PictureBuffer(buffer_ids[i], texture_dimensions_,
+                                           texture_ref->service_id(),
+                                           texture_ids[i]));
     textures.push_back(texture_ref);
   }
   video_decode_accelerator_->AssignPictureBuffers(buffers);
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h
index 562b4c0..f147138c 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.h
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.h
@@ -104,6 +104,11 @@
   // Helper for replying to the creation request.
   void SendCreateDecoderReply(IPC::Message* message, bool succeeded);
 
+  // Helper to bind |image| to the texture specified by |client_texture_id|.
+  void BindImage(uint32 client_texture_id,
+                 uint32 texture_target,
+                 scoped_refptr<gfx::GLImage> image);
+
   // Route ID to communicate with the host.
   int32 host_route_id_;
 
diff --git a/content/common/gpu/media/gpu_video_encode_accelerator.cc b/content/common/gpu/media/gpu_video_encode_accelerator.cc
index df16d97..a2c3365c 100644
--- a/content/common/gpu/media/gpu_video_encode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_encode_accelerator.cc
@@ -18,13 +18,12 @@
 #include "media/base/video_frame.h"
 
 #if defined(OS_CHROMEOS)
-#if defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC))
+#if defined(USE_V4L2_CODEC)
 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
-// defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC))
 #endif
 #if defined(ARCH_CPU_X86_FAMILY)
 #include "content/common/gpu/media/vaapi_video_encode_accelerator.h"
-#endif  // defined(ARCH_CPU_X86_FAMILY)
+#endif
 #elif defined(OS_ANDROID) && defined(ENABLE_WEBRTC)
 #include "content/common/gpu/media/android_video_encode_accelerator.h"
 #endif
@@ -212,8 +211,7 @@
 scoped_ptr<media::VideoEncodeAccelerator>
 GpuVideoEncodeAccelerator::CreateV4L2VEA() {
   scoped_ptr<media::VideoEncodeAccelerator> encoder;
-#if defined(OS_CHROMEOS) && (defined(ARCH_CPU_ARMEL) || \
-    (defined(USE_OZONE) && defined(USE_V4L2_CODEC)))
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
   scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kEncoder);
   if (device)
     encoder.reset(new V4L2VideoEncodeAccelerator(device));
diff --git a/content/common/gpu/media/vaapi_drm_picture.cc b/content/common/gpu/media/vaapi_drm_picture.cc
index 82e16ec..628b4c8 100644
--- a/content/common/gpu/media/vaapi_drm_picture.cc
+++ b/content/common/gpu/media/vaapi_drm_picture.cc
@@ -13,6 +13,7 @@
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_image_linux_dma_buffer.h"
 #include "ui/gl/scoped_binders.h"
+#include "ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
 #include "ui/ozone/public/native_pixmap.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
@@ -101,17 +102,14 @@
   if (!make_context_current_.Run())
     return false;
 
-  // Create an EGLImage out of the same buffer.
-  gl_image_ = new gfx::GLImageLinuxDMABuffer(size(), GL_RGBA);
-  if (!gl_image_->Initialize(base::FileDescriptor(dmabuf_fd, false),
-                             gfx::GpuMemoryBuffer::BGRA_8888, dmabuf_pitch)) {
-    LOG(ERROR) << "Failed to create a GLImageLinuxDMABuffer for a NativePixmap";
-    return false;
-  }
-
-  // Bind the EGLImage to the given GL texture.
   gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES,
                                           texture_id());
+  gl_image_ = ui::GpuMemoryBufferFactoryOzoneNativeBuffer::CreateImageForPixmap(
+      pixmap_, size(), gfx::GpuMemoryBuffer::RGBA_8888, GL_RGBA);
+  if (!gl_image_) {
+    LOG(ERROR) << "Failed to create GLImage";
+    return false;
+  }
   if (!gl_image_->BindTexImage(GL_TEXTURE_EXTERNAL_OES)) {
     LOG(ERROR) << "Failed to bind texture to GLImage";
     return false;
@@ -126,4 +124,12 @@
                                      va_surface_->id(), va_surface_->size());
 }
 
+scoped_refptr<gfx::GLImage> VaapiDrmPicture::GetImageToBind() {
+  return gl_image_;
+}
+
+bool VaapiDrmPicture::AllowOverlay() const {
+  return true;
+}
+
 }  // namespace
diff --git a/content/common/gpu/media/vaapi_drm_picture.h b/content/common/gpu/media/vaapi_drm_picture.h
index 46c7304..e982b59 100644
--- a/content/common/gpu/media/vaapi_drm_picture.h
+++ b/content/common/gpu/media/vaapi_drm_picture.h
@@ -15,7 +15,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace gfx {
-class GLImageLinuxDMABuffer;
+class GLImage;
 }
 
 namespace ui {
@@ -41,6 +41,10 @@
 
   bool DownloadFromSurface(const scoped_refptr<VASurface>& va_surface) override;
 
+  scoped_refptr<gfx::GLImage> GetImageToBind() override;
+
+  bool AllowOverlay() const override;
+
  private:
   VaapiWrapper* vaapi_wrapper_;  // Not owned.
   base::Callback<bool(void)> make_context_current_;
@@ -49,7 +53,7 @@
   scoped_refptr<ui::NativePixmap> pixmap_;
 
   // EGLImage bound to the GL textures used by the VDA client.
-  scoped_refptr<gfx::GLImageLinuxDMABuffer> gl_image_;
+  scoped_refptr<gfx::GLImage> gl_image_;
 
   // VASurface used to transfer from the decoder's pixel format.
   scoped_refptr<VASurface> va_surface_;
diff --git a/content/common/gpu/media/vaapi_picture.cc b/content/common/gpu/media/vaapi_picture.cc
index 782971c6..cd886c06 100644
--- a/content/common/gpu/media/vaapi_picture.cc
+++ b/content/common/gpu/media/vaapi_picture.cc
@@ -37,6 +37,10 @@
   return picture;
 }
 
+bool VaapiPicture::AllowOverlay() const {
+  return false;
+}
+
 // static
 uint32 VaapiPicture::GetGLTextureTarget() {
 #if defined(USE_OZONE)
diff --git a/content/common/gpu/media/vaapi_picture.h b/content/common/gpu/media/vaapi_picture.h
index 44d9db7..ad43dfa3 100644
--- a/content/common/gpu/media/vaapi_picture.h
+++ b/content/common/gpu/media/vaapi_picture.h
@@ -16,6 +16,10 @@
 #include "base/threading/non_thread_safe.h"
 #include "ui/gfx/geometry/size.h"
 
+namespace gfx {
+class GLImage;
+}
+
 namespace content {
 
 class VASurface;
@@ -33,6 +37,11 @@
   uint32 texture_id() const { return texture_id_; }
   const gfx::Size& size() const { return size_; }
 
+  virtual bool AllowOverlay() const;
+
+  // Returns the |GLImage|, if any, to bind to the texture.
+  virtual scoped_refptr<gfx::GLImage> GetImageToBind() = 0;
+
   // Downloads the |va_surface| into the picture, potentially scaling
   // it if needed.
   virtual bool DownloadFromSurface(
diff --git a/content/common/gpu/media/vaapi_tfp_picture.cc b/content/common/gpu/media/vaapi_tfp_picture.cc
index 7f0122f..ee03742 100644
--- a/content/common/gpu/media/vaapi_tfp_picture.cc
+++ b/content/common/gpu/media/vaapi_tfp_picture.cc
@@ -74,4 +74,8 @@
                                               va_surface->size());
 }
 
+scoped_refptr<gfx::GLImage> VaapiTFPPicture::GetImageToBind() {
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/common/gpu/media/vaapi_tfp_picture.h b/content/common/gpu/media/vaapi_tfp_picture.h
index 02a1a23..3261791 100644
--- a/content/common/gpu/media/vaapi_tfp_picture.h
+++ b/content/common/gpu/media/vaapi_tfp_picture.h
@@ -39,6 +39,8 @@
 
   bool DownloadFromSurface(const scoped_refptr<VASurface>& va_surface) override;
 
+  scoped_refptr<gfx::GLImage> GetImageToBind() override;
+
  private:
   VaapiWrapper* vaapi_wrapper_;  // Not owned.
 
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
index 90c0cdda7..d24744d71 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
@@ -15,6 +15,7 @@
 #include "media/base/bind_to_current_loop.h"
 #include "media/video/picture.h"
 #include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_image.h"
 
 static void ReportToUMA(
     content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) {
@@ -72,7 +73,9 @@
 }
 
 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator(
-    const base::Callback<bool(void)>& make_context_current)
+    const base::Callback<bool(void)>& make_context_current,
+    const base::Callback<void(uint32, uint32, scoped_refptr<gfx::GLImage>)>&
+        bind_image)
     : make_context_current_(make_context_current),
       state_(kUninitialized),
       input_ready_(&lock_),
@@ -84,6 +87,7 @@
       finish_flush_pending_(false),
       awaiting_va_surfaces_recycle_(false),
       requested_num_pics_(0),
+      bind_image_(bind_image),
       weak_this_factory_(this) {
   weak_this_ = weak_this_factory_.GetWeakPtr();
   va_surface_release_cb_ = media::BindToCurrentLoop(
@@ -186,8 +190,9 @@
   // TODO(posciak): Use visible size from decoder here instead
   // (crbug.com/402760).
   if (client_)
-    client_->PictureReady(
-        media::Picture(output_id, input_id, gfx::Rect(picture->size()), false));
+    client_->PictureReady(media::Picture(output_id, input_id,
+                                         gfx::Rect(picture->size()),
+                                         picture->AllowOverlay()));
 }
 
 void VaapiVideoDecodeAccelerator::TryOutputSurface() {
@@ -525,6 +530,12 @@
         vaapi_wrapper_.get(), make_context_current_, buffers[i].id(),
         buffers[i].texture_id(), requested_pic_size_));
 
+    scoped_refptr<gfx::GLImage> image = picture->GetImageToBind();
+    if (image) {
+      bind_image_.Run(buffers[i].internal_texture_id(),
+                      VaapiPicture::GetGLTextureTarget(), image);
+    }
+
     RETURN_AND_NOTIFY_ON_FAILURE(
         picture.get(), "Failed assigning picture buffer to a texture.",
         PLATFORM_FAILURE, );
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.h b/content/common/gpu/media/vaapi_video_decode_accelerator.h
index 9e98a6b7..0ef25c55 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.h
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.h
@@ -28,6 +28,10 @@
 #include "media/video/picture.h"
 #include "media/video/video_decode_accelerator.h"
 
+namespace gfx {
+class GLImage;
+}
+
 namespace content {
 
 class VaapiPicture;
@@ -44,7 +48,9 @@
     : public media::VideoDecodeAccelerator {
  public:
   VaapiVideoDecodeAccelerator(
-      const base::Callback<bool(void)>& make_context_current);
+      const base::Callback<bool(void)>& make_context_current,
+      const base::Callback<void(uint32, uint32, scoped_refptr<gfx::GLImage>)>&
+          bind_image);
   ~VaapiVideoDecodeAccelerator() override;
 
   // media::VideoDecodeAccelerator implementation.
@@ -264,6 +270,10 @@
   size_t requested_num_pics_;
   gfx::Size requested_pic_size_;
 
+  // Binds the provided GLImage to a givenr client texture ID & texture target
+  // combination in GLES.
+  base::Callback<void(uint32, uint32, scoped_refptr<gfx::GLImage>)> bind_image_;
+
   // The WeakPtrFactory for |weak_this_|.
   base::WeakPtrFactory<VaapiVideoDecodeAccelerator> weak_this_factory_;
 
diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc
index a028f98..6c8d68c2 100644
--- a/content/common/gpu/media/video_decode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc
@@ -47,20 +47,20 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
+#include "content/common/gpu/media/fake_video_decode_accelerator.h"
 #include "content/common/gpu/media/rendering_helper.h"
 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h"
 #include "content/public/common/content_switches.h"
 #include "media/filters/h264_parser.h"
 #include "ui/gfx/codec/png_codec.h"
+#include "ui/gl/gl_image.h"
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
 #include "content/common/gpu/media/dxva_video_decode_accelerator.h"
 #elif defined(OS_CHROMEOS)
-#if defined(ARCH_CPU_ARMEL) && defined(USE_LIBV4L2)
+#if defined(USE_V4L2_CODEC)
 #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h"
-#endif  // defined(ARCH_CPU_ARMEL)
-#if defined(ARCH_CPU_ARMEL) || (defined(USE_OZONE) && defined(USE_V4L2_CODEC))
 #include "content/common/gpu/media/v4l2_video_decode_accelerator.h"
 #include "content/common/gpu/media/v4l2_video_device.h"
 #endif
@@ -118,6 +118,8 @@
 // values for |num_play_throughs|. This setting will override the value. A
 // special value "0" means no override.
 int g_num_play_throughs = 0;
+// Fake decode
+int g_fake_decoder = 0;
 
 // Environment to store rendering thread.
 class VideoDecodeAcceleratorTestEnvironment;
@@ -294,6 +296,7 @@
                        int frame_width,
                        int frame_height,
                        media::VideoCodecProfile profile,
+                       int fake_decoder,
                        bool suppress_rendering,
                        int delay_reuse_after_frame_num,
                        int decode_calls_per_second,
@@ -329,11 +332,16 @@
  private:
   typedef std::map<int32, scoped_refptr<TextureRef>> TextureRefMap;
 
+  scoped_ptr<media::VideoDecodeAccelerator> CreateFakeVDA();
   scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA();
   scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA();
   scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SliceVDA();
   scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA();
 
+  void BindImage(uint32 client_texture_id,
+                 uint32 texture_target,
+                 scoped_refptr<gfx::GLImage> image);
+
   void SetState(ClientState new_state);
   void FinishInitialization();
   void ReturnPicture(int32 picture_buffer_id);
@@ -378,6 +386,7 @@
   int num_done_bitstream_buffers_;
   base::TimeTicks initialize_done_ticks_;
   media::VideoCodecProfile profile_;
+  int fake_decoder_;
   GLenum texture_target_;
   bool suppress_rendering_;
   std::vector<base::TimeTicks> frame_delivery_times_;
@@ -419,6 +428,7 @@
     int frame_width,
     int frame_height,
     media::VideoCodecProfile profile,
+    int fake_decoder,
     bool suppress_rendering,
     int delay_reuse_after_frame_num,
     int decode_calls_per_second,
@@ -440,6 +450,7 @@
       num_queued_fragments_(0),
       num_decoded_frames_(0),
       num_done_bitstream_buffers_(0),
+      fake_decoder_(fake_decoder),
       texture_target_(0),
       suppress_rendering_(suppress_rendering),
       delay_reuse_after_frame_num_(delay_reuse_after_frame_num),
@@ -467,6 +478,18 @@
 static bool DoNothingReturnTrue() { return true; }
 
 scoped_ptr<media::VideoDecodeAccelerator>
+GLRenderingVDAClient::CreateFakeVDA() {
+  scoped_ptr<media::VideoDecodeAccelerator> decoder;
+  if (fake_decoder_) {
+    decoder.reset(new FakeVideoDecodeAccelerator(
+        static_cast<gfx::GLContext*> (rendering_helper_->GetGLContextHandle()),
+        frame_size_,
+        base::Bind(&DoNothingReturnTrue)));
+  }
+  return decoder.Pass();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
 GLRenderingVDAClient::CreateDXVAVDA() {
   scoped_ptr<media::VideoDecodeAccelerator> decoder;
 #if defined(OS_WIN)
@@ -480,8 +503,7 @@
 scoped_ptr<media::VideoDecodeAccelerator>
 GLRenderingVDAClient::CreateV4L2VDA() {
   scoped_ptr<media::VideoDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && (defined(ARCH_CPU_ARMEL) || \
-    (defined(USE_OZONE) && defined(USE_V4L2_CODEC)))
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
   scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
   if (device.get()) {
     base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr();
@@ -500,7 +522,7 @@
 scoped_ptr<media::VideoDecodeAccelerator>
 GLRenderingVDAClient::CreateV4L2SliceVDA() {
   scoped_ptr<media::VideoDecodeAccelerator> decoder;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_LIBV4L2)
+#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
   scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder);
   if (device.get()) {
     base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr();
@@ -515,16 +537,23 @@
 #endif
   return decoder.Pass();
 }
+
 scoped_ptr<media::VideoDecodeAccelerator>
 GLRenderingVDAClient::CreateVaapiVDA() {
   scoped_ptr<media::VideoDecodeAccelerator> decoder;
 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
-  decoder.reset(
-      new VaapiVideoDecodeAccelerator(base::Bind(&DoNothingReturnTrue)));
+  decoder.reset(new VaapiVideoDecodeAccelerator(
+      base::Bind(&DoNothingReturnTrue),
+      base::Bind(&GLRenderingVDAClient::BindImage, base::Unretained(this))));
 #endif
   return decoder.Pass();
 }
 
+void GLRenderingVDAClient::BindImage(uint32 client_texture_id,
+                                     uint32 texture_target,
+                                     scoped_refptr<gfx::GLImage> image) {
+}
+
 void GLRenderingVDAClient::CreateAndStartDecoder() {
   CHECK(decoder_deleted());
   CHECK(!decoder_.get());
@@ -532,6 +561,7 @@
   VideoDecodeAccelerator::Client* client = this;
 
   scoped_ptr<media::VideoDecodeAccelerator> decoders[] = {
+    CreateFakeVDA(),
     CreateDXVAVDA(),
     CreateV4L2VDA(),
     CreateV4L2SliceVDA(),
@@ -1222,6 +1252,7 @@
                                  video_file->width,
                                  video_file->height,
                                  video_file->profile,
+                                 g_fake_decoder,
                                  suppress_rendering,
                                  delay_after_frame_num,
                                  0,
@@ -1475,6 +1506,7 @@
                                test_video_files_[0]->width,
                                test_video_files_[0]->height,
                                test_video_files_[0]->profile,
+                               g_fake_decoder,
                                true,
                                std::numeric_limits<int>::max(),
                                kWebRtcDecodeCallsPerSecond,
@@ -1553,6 +1585,9 @@
     if (it->first == "num_play_throughs") {
       std::string input(it->second.begin(), it->second.end());
       CHECK(base::StringToInt(input, &content::g_num_play_throughs));
+    }
+    if (it->first == "fake_decoder") {
+      content::g_fake_decoder = 1;
       continue;
     }
     if (it->first == "v" || it->first == "vmodule")
diff --git a/content/common/media/OWNERS b/content/common/media/OWNERS
index bbbdeff..2ba40a0 100644
--- a/content/common/media/OWNERS
+++ b/content/common/media/OWNERS
@@ -4,7 +4,6 @@
 sandersd@chromium.org
 scherkus@chromium.org
 tommi@chromium.org
-vrk@chromium.org
 xhwang@chromium.org
 
 # For security review of IPC message files.
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc
index d89679bd..c401d873 100644
--- a/content/common/sandbox_win.cc
+++ b/content/common/sandbox_win.cc
@@ -343,7 +343,8 @@
   return true;
 }
 
-bool AddPolicyForSandboxedProcess(sandbox::TargetPolicy* policy) {
+bool AddPolicyForSandboxedProcess(sandbox::TargetPolicy* policy,
+                                  std::string& type_str) {
   sandbox::ResultCode result;
   // Renderers need to share events with plugins.
   result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
@@ -353,8 +354,11 @@
     return false;
 
   // Win8+ adds a device DeviceApi that we don't need.
-  if (base::win::GetVersion() > base::win::VERSION_WIN7)
+  // Only close this handle on renderer processes.  See crbug.com/452613.
+  if (base::win::GetVersion() > base::win::VERSION_WIN7 &&
+      type_str == switches::kRendererProcess) {
     result = policy->AddKernelObjectToClose(L"File", L"\\Device\\DeviceApi");
+  }
   if (result != sandbox::SBOX_ALL_OK)
     return false;
 
@@ -649,7 +653,8 @@
   if (delegate)
     delegate->PreSandbox(&disable_default_policy, &exposed_dir);
 
-  if (!disable_default_policy && !AddPolicyForSandboxedProcess(policy))
+  if (!disable_default_policy &&
+      !AddPolicyForSandboxedProcess(policy, type_str))
     return base::Process();
 
   if (type_str == switches::kRendererProcess) {
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index 20b13ec..5aee688 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -240,6 +240,11 @@
 IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_SkipWaiting,
                     int /* request_id */)
 
+// Asks the browser to have this worker take control of pages that match
+// its scope.
+IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_ClaimClients,
+                    int /* request_id */)
+
 // CacheStorage operations in the browser.
 IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_CacheStorageHas,
                     int /* request_id */,
@@ -442,6 +447,12 @@
                      std::vector<int> /* new_routing_ids */)
 IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_DidSkipWaiting,
                      int /* request_id */)
+IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_DidClaimClients,
+                     int /* request_id */)
+IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_ClaimClientsError,
+                     int /* request_id */,
+                     blink::WebServiceWorkerError::ErrorType /* code */,
+                     base::string16 /* message */)
 
 // Sent via EmbeddedWorker as a response of GetClientDocuments.
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidGetClientDocuments,
diff --git a/content/common/service_worker/service_worker_status_code.cc b/content/common/service_worker/service_worker_status_code.cc
index f5c1e02..35aaa86 100644
--- a/content/common/service_worker/service_worker_status_code.cc
+++ b/content/common/service_worker/service_worker_status_code.cc
@@ -37,6 +37,8 @@
     case SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED:
       return "ServiceWorker failed to handle event (event.waitUntil "
              "Promise rejected)";
+    case SERVICE_WORKER_ERROR_STATE:
+      return "The ServiceWorker state was not valid";
   }
   NOTREACHED();
   return "";
diff --git a/content/common/service_worker/service_worker_status_code.h b/content/common/service_worker/service_worker_status_code.h
index e87e5c3..1e9cdd5 100644
--- a/content/common/service_worker/service_worker_status_code.h
+++ b/content/common/service_worker/service_worker_status_code.h
@@ -51,6 +51,9 @@
 
   // Event handling failed (event.waitUntil Promise rejected).
   SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED,
+
+  // An error triggered by invalid worker state.
+  SERVICE_WORKER_ERROR_STATE,
 };
 
 CONTENT_EXPORT const char* ServiceWorkerStatusToString(
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index e0914db0..968c228e 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -1043,19 +1043,19 @@
 // page/widget that was created by
 // CreateWindow/CreateWidget/CreateFullscreenWidget. routing_id
 // refers to the id that was returned from the Create message above.
-// The initial_position parameter is a rectangle in screen coordinates.
+// The initial_rect parameter is in screen coordinates.
 //
 // FUTURE: there will probably be flags here to control if the result is
 // in a new window.
 IPC_MESSAGE_ROUTED4(ViewHostMsg_ShowView,
                     int /* route_id */,
                     WindowOpenDisposition /* disposition */,
-                    gfx::Rect /* initial_pos */,
+                    gfx::Rect /* initial_rect */,
                     bool /* opened_by_user_gesture */)
 
 IPC_MESSAGE_ROUTED2(ViewHostMsg_ShowWidget,
                     int /* route_id */,
-                    gfx::Rect /* initial_pos */)
+                    gfx::Rect /* initial_rect */)
 
 // Message to show a full screen widget.
 IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowFullscreenWidget,
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 21f668d..071dce7 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -514,6 +514,7 @@
       'browser/device_sensors/data_fetcher_shared_memory_android.cc',
       'browser/device_sensors/data_fetcher_shared_memory_base.cc',
       'browser/device_sensors/data_fetcher_shared_memory_base.h',
+      'browser/device_sensors/data_fetcher_shared_memory_chromeos.cc',
       'browser/device_sensors/data_fetcher_shared_memory_default.cc',
       'browser/device_sensors/data_fetcher_shared_memory_mac.cc',
       'browser/device_sensors/data_fetcher_shared_memory_win.cc',
@@ -528,6 +529,8 @@
       'browser/device_sensors/inertial_sensor_consts.h',
       'browser/device_sensors/sensor_manager_android.cc',
       'browser/device_sensors/sensor_manager_android.h',
+      'browser/device_sensors/sensor_manager_chromeos.cc',
+      'browser/device_sensors/sensor_manager_chromeos.h',
       'browser/dom_storage/dom_storage_area.cc',
       'browser/dom_storage/dom_storage_area.h',
       'browser/dom_storage/dom_storage_context_impl.cc',
@@ -1891,6 +1894,7 @@
         '../chromeos/chromeos.gyp:power_manager_proto',
       ],
       'sources!': [
+        'browser/device_sensors/data_fetcher_shared_memory_default.cc',
         'browser/geolocation/wifi_data_provider_linux.cc',
         'browser/power_save_blocker_ozone.cc',
         'browser/power_save_blocker_x11.cc',
diff --git a/content/content_browsertests.isolate b/content/content_browsertests.isolate
index 53a53fc..9701675 100644
--- a/content/content_browsertests.isolate
+++ b/content/content_browsertests.isolate
@@ -42,6 +42,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -92,6 +94,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/content/content_child.gypi b/content/content_child.gypi
index 013d2e5..fedf374a 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -23,6 +23,7 @@
   ],
   'variables': {
     'public_child_sources': [
+      'public/child/child_thread.h',
       'public/child/image_decoder_utils.h',
       'public/child/request_peer.h',
       'public/child/resource_dispatcher_delegate.h',
@@ -61,8 +62,8 @@
       'child/child_resource_message_filter.h',
       'child/child_shared_bitmap_manager.cc',
       'child/child_shared_bitmap_manager.h',
-      'child/child_thread.cc',
-      'child/child_thread.h',
+      'child/child_thread_impl.cc',
+      'child/child_thread_impl.h',
       'child/content_child_helpers.cc',
       'child/content_child_helpers.h',
       'child/database_util.cc',
@@ -272,6 +273,8 @@
       'child/weburlresponse_extradata_impl.h',
       'child/worker_task_runner.cc',
       'child/worker_task_runner.h',
+      'child/worker_thread_message_filter.cc',
+      'child/worker_thread_message_filter.h',
       'child/worker_thread_task_runner.cc',
       'child/worker_thread_task_runner.h',
     ],
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 8a8dea2..31f3ea7 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -330,6 +330,8 @@
       'common/gpu/image_transport_surface_linux.cc',
       'common/gpu/image_transport_surface_mac.mm',
       'common/gpu/image_transport_surface_win.cc',
+      'common/gpu/media/fake_video_decode_accelerator.cc',
+      'common/gpu/media/fake_video_decode_accelerator.h',
       'common/gpu/media/gpu_video_decode_accelerator.cc',
       'common/gpu/media/gpu_video_decode_accelerator.h',
       'common/gpu/media/gpu_video_encode_accelerator.cc',
@@ -766,7 +768,7 @@
     }],
     ['use_v4lplugin==1 and chromeos==1', {
       'defines': [
-        'USE_LIBV4L2',
+        'USE_LIBV4L2'
       ],
       'variables': {
         'generate_stubs_script': '../tools/generate_stubs/generate_stubs.py',
@@ -817,50 +819,40 @@
       'defines': [
         'USE_V4L2_CODEC'
       ],
-    }],
-    ['chromeos==1 and (target_arch=="arm" or (use_ozone==1 and use_v4l2_codec==1))', {
       'dependencies': [
         '../media/media.gyp:media',
       ],
       'sources': [
+        'common/gpu/media/accelerated_video_decoder.h',
         'common/gpu/media/generic_v4l2_video_device.cc',
         'common/gpu/media/generic_v4l2_video_device.h',
+        'common/gpu/media/h264_decoder.cc',
+        'common/gpu/media/h264_decoder.h',
+        'common/gpu/media/h264_dpb.cc',
+        'common/gpu/media/h264_dpb.h',
         'common/gpu/media/v4l2_image_processor.cc',
         'common/gpu/media/v4l2_image_processor.h',
+        'common/gpu/media/v4l2_slice_video_decode_accelerator.cc',
+        'common/gpu/media/v4l2_slice_video_decode_accelerator.h',
         'common/gpu/media/v4l2_video_decode_accelerator.cc',
         'common/gpu/media/v4l2_video_decode_accelerator.h',
         'common/gpu/media/v4l2_video_device.cc',
         'common/gpu/media/v4l2_video_device.h',
         'common/gpu/media/v4l2_video_encode_accelerator.cc',
         'common/gpu/media/v4l2_video_encode_accelerator.h',
+        'common/gpu/media/vp8_decoder.cc',
+        'common/gpu/media/vp8_decoder.h',
+        'common/gpu/media/vp8_picture.cc',
+        'common/gpu/media/vp8_picture.h',
       ],
       'include_dirs': [
         '<(DEPTH)/third_party/khronos',
       ],
-      'conditions': [
-        ['target_arch == "arm"', {
-          'sources': [
-            'common/gpu/media/tegra_v4l2_video_device.cc',
-            'common/gpu/media/tegra_v4l2_video_device.h',
-          ],
-          'conditions': [
-            ['use_v4lplugin==1', {
-              'sources': [
-                'common/gpu/media/accelerated_video_decoder.h',
-                'common/gpu/media/h264_decoder.cc',
-                'common/gpu/media/h264_decoder.h',
-                'common/gpu/media/h264_dpb.cc',
-                'common/gpu/media/h264_dpb.h',
-                'common/gpu/media/v4l2_slice_video_decode_accelerator.cc',
-                'common/gpu/media/v4l2_slice_video_decode_accelerator.h',
-                'common/gpu/media/vp8_decoder.cc',
-                'common/gpu/media/vp8_decoder.h',
-                'common/gpu/media/vp8_picture.cc',
-                'common/gpu/media/vp8_picture.h',
-              ],
-            }],
-          ],
-        }],
+    }],
+    ['target_arch == "arm" and chromeos == 1', {
+      'sources': [
+        'common/gpu/media/tegra_v4l2_video_device.cc',
+        'common/gpu/media/tegra_v4l2_video_device.h',
       ],
     }],
     ['target_arch != "arm" and chromeos == 1', {
@@ -1031,6 +1023,7 @@
     ['use_ozone==1', {
       'dependencies': [
         '../ui/ozone/ozone.gyp:ozone',
+        '../ui/ozone/ozone.gyp:ozone_base',
         '../ui/ozone/gpu/ozone_gpu.gyp:ozone_gpu',
       ],
       'sources!': [
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 13ac6c02..6cdd46b 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -4,7 +4,6 @@
 
 {
   'variables': {
-    'use_v4lplugin%': 0,
     'layouttest_support_content_sources': [
       'public/test/layouttest_support.h',
       'public/test/nested_message_pump_android.cc',
@@ -346,6 +345,7 @@
       'browser/database_util_unittest.cc',
       'browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc',
       'browser/device_sensors/sensor_manager_android_unittest.cc',
+      'browser/device_sensors/sensor_manager_chromeos_unittest.cc',
       'browser/devtools/devtools_http_handler_unittest.cc',
       'browser/devtools/devtools_manager_unittest.cc',
       'browser/devtools/shared_worker_devtools_manager_unittest.cc',
@@ -1617,9 +1617,6 @@
                   '../ui/ozone/ozone.gyp:ozone',       # Used by rendering_helper.cc
                 ],
               }],
-              ['use_v4lplugin==1', {
-                'defines': ['USE_LIBV4L2'],
-              }],
             ],
             # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
             'msvs_disabled_warnings': [ 4267, ],
diff --git a/content/content_unittests.isolate b/content/content_unittests.isolate
index bc982e2..b72dcee 100644
--- a/content/content_unittests.isolate
+++ b/content/content_unittests.isolate
@@ -6,6 +6,7 @@
     ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
       'variables': {
         'files': [
+          '../net/data/ssl/certificates/',
           '../media/test/data/',
           'test/data/',
         ],
@@ -43,6 +44,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -67,6 +70,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '<(PRODUCT_DIR)/ffmpegsumo.so',
@@ -83,6 +88,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '<(PRODUCT_DIR)/ffmpegsumo.dll',
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index b7846f4..1064a70 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -44,8 +44,8 @@
   return false;
 }
 
-ChildThread::Options GetOptions() {
-  ChildThread::Options options;
+ChildThreadImpl::Options GetOptions() {
+  ChildThreadImpl::Options options;
 
 #if defined(USE_OZONE)
   IPC::MessageFilter* message_filter = ui::OzonePlatform::GetInstance()
@@ -64,7 +64,7 @@
                                bool dead_on_arrival,
                                const gpu::GPUInfo& gpu_info,
                                const DeferredMessages& deferred_messages)
-    : ChildThread(GetOptions()),
+    : ChildThreadImpl(GetOptions()),
       dead_on_arrival_(dead_on_arrival),
       gpu_info_(gpu_info),
       deferred_messages_(deferred_messages),
@@ -77,7 +77,7 @@
 }
 
 GpuChildThread::GpuChildThread(const std::string& channel_id)
-    : ChildThread(Options(channel_id, false)),
+    : ChildThreadImpl(Options(channel_id, false)),
       dead_on_arrival_(false),
       in_browser_process_(true) {
 #if defined(OS_WIN)
@@ -102,7 +102,7 @@
 }
 
 void GpuChildThread::Shutdown() {
-  ChildThread::Shutdown();
+  ChildThreadImpl::Shutdown();
   logging::SetLogMessageHandler(NULL);
 }
 
@@ -115,7 +115,7 @@
   // process. This could result in deadlock.
   DCHECK(!msg->is_sync());
 
-  return ChildThread::Send(msg);
+  return ChildThreadImpl::Send(msg);
 }
 
 bool GpuChildThread::OnControlMessageReceived(const IPC::Message& msg) {
diff --git a/content/gpu/gpu_child_thread.h b/content/gpu/gpu_child_thread.h
index b5c312d..7103cd3 100644
--- a/content/gpu/gpu_child_thread.h
+++ b/content/gpu/gpu_child_thread.h
@@ -14,7 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/gpu/gpu_channel.h"
 #include "content/common/gpu/gpu_channel_manager.h"
 #include "content/common/gpu/gpu_config.h"
@@ -33,7 +33,7 @@
 // these per process. It does process initialization and shutdown. It forwards
 // IPC messages to GpuChannelManager, which is responsible for issuing rendering
 // commands to the GPU.
-class GpuChildThread : public ChildThread {
+class GpuChildThread : public ChildThreadImpl {
  public:
   typedef std::queue<IPC::Message*> DeferredMessages;
 
diff --git a/content/plugin/plugin_thread.cc b/content/plugin/plugin_thread.cc
index 720a77b..a688902 100644
--- a/content/plugin/plugin_thread.cc
+++ b/content/plugin/plugin_thread.cc
@@ -106,7 +106,7 @@
 }
 
 void PluginThread::Shutdown() {
-  ChildThread::Shutdown();
+  ChildThreadImpl::Shutdown();
 
   if (preloaded_plugin_module_) {
     base::UnloadNativeLibrary(preloaded_plugin_module_);
diff --git a/content/plugin/plugin_thread.h b/content/plugin/plugin_thread.h
index 11acafc7..8ad115e2 100644
--- a/content/plugin/plugin_thread.h
+++ b/content/plugin/plugin_thread.h
@@ -8,7 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/native_library.h"
 #include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/npapi/plugin_lib.h"
 #include "content/plugin/plugin_channel.h"
 
@@ -22,7 +22,7 @@
 // The PluginThread class represents a background thread where plugin instances
 // live.  Communication occurs between WebPluginDelegateProxy in the renderer
 // process and WebPluginDelegateStub in this thread through IPC messages.
-class PluginThread : public ChildThread {
+class PluginThread : public ChildThreadImpl {
  public:
   PluginThread();
   ~PluginThread() override;
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
index ad84196..793f6d6 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.cc
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -10,7 +10,7 @@
 #include "base/strings/string16.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/child_process_messages.h"
 #include "ppapi/proxy/plugin_globals.h"
 #include "ppapi/shared_impl/proxy_lock.h"
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index 6d77afe..103a7b8 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -42,12 +42,10 @@
 #include "ppapi/proxy/plugin_message_filter.h"
 #include "ppapi/proxy/ppapi_messages.h"
 #include "ppapi/proxy/resource_reply_thread_registrar.h"
-#include "ppapi/shared_impl/proxy_lock.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "ui/base/ui_base_switches.h"
 
 #if defined(OS_WIN)
-#include "base/win/iat_patch_function.h"
 #include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/sandbox.h"
@@ -94,54 +92,6 @@
   }
 }
 
-// TODO(scottmg): http://crbug.com/448473. This code should be removed from the
-// renderer once PDF is always OOP and/or PDF is made to use Skia instead of GDI
-// directly.
-const wchar_t kPdfFileName[] = L"pdf.dll";
-
-static base::win::IATPatchFunction g_iat_patch_createdca;
-HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
-                          LPCSTR device_name,
-                          LPCSTR output,
-                          const void* init_data) {
-  DCHECK(std::string("DISPLAY") == std::string(driver_name));
-  DCHECK(!device_name);
-  DCHECK(!output);
-  DCHECK(!init_data);
-
-  // CreateDC fails behind the sandbox, but not CreateCompatibleDC.
-  return CreateCompatibleDC(NULL);
-}
-
-static base::win::IATPatchFunction g_iat_patch_get_font_data;
-DWORD WINAPI GetFontDataPatch(HDC hdc,
-                              DWORD table,
-                              DWORD offset,
-                              LPVOID buffer,
-                              DWORD length) {
-  int rv = GetFontData(hdc, table, offset, buffer, length);
-  if (rv == GDI_ERROR && hdc) {
-    HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
-
-    LOGFONT logfont;
-    if (GetObject(font, sizeof(LOGFONT), &logfont)) {
-      std::vector<char> font_data;
-      {
-        ppapi::ProxyAutoLock lock;
-        // In the sandbox, font loading will fail. We ask the browser to load it
-        // which causes it to be loaded by the kernel, which then makes the
-        // subsequent call succeed.
-        ppapi::proxy::PluginGlobals::Get()->PreCacheFontForFlash(
-            reinterpret_cast<const void*>(&logfont));
-      }
-      rv = GetFontData(hdc, table, offset, buffer, length);
-    }
-  }
-  return rv;
-}
-
-#else
-extern void* g_target_services;
 #endif
 
 namespace content {
@@ -173,7 +123,7 @@
 }
 
 void PpapiThread::Shutdown() {
-  ChildThread::Shutdown();
+  ChildThreadImpl::Shutdown();
 
   ppapi::proxy::PluginGlobals::Get()->ResetPluginProxyDelegate();
   if (plugin_entry_points_.shutdown_module)
@@ -185,7 +135,7 @@
 bool PpapiThread::Send(IPC::Message* msg) {
   // Allow access from multiple threads.
   if (base::MessageLoop::current() == message_loop())
-    return ChildThread::Send(msg);
+    return ChildThreadImpl::Send(msg);
 
   return sync_message_filter()->Send(msg);
 }
@@ -207,7 +157,7 @@
 }
 
 void PpapiThread::OnChannelConnected(int32 peer_pid) {
-  ChildThread::OnChannelConnected(peer_pid);
+  ChildThreadImpl::OnChannelConnected(peer_pid);
 #if defined(OS_WIN)
   if (is_broker_)
     peer_handle_.Set(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, peer_pid));
@@ -253,8 +203,7 @@
 
 void PpapiThread::PreCacheFont(const void* logfontw) {
 #if defined(OS_WIN)
-  Send(new ChildProcessHostMsg_PreCacheFont(
-      *static_cast<const LOGFONTW*>(logfontw)));
+  ChildThreadImpl::PreCacheFont(*static_cast<const LOGFONTW*>(logfontw));
 #endif
 }
 
@@ -374,15 +323,6 @@
   // otherwise these would be silent terminations and fly under the radar).
   base::win::SetAbortBehaviorForCrashReporting();
 
-  // Need to patch a few functions for font loading to work correctly. This can
-  // be removed once we switch PDF to use Skia.
-  if (GetModuleHandle(kPdfFileName)) {
-    g_iat_patch_createdca.Patch(kPdfFileName, "gdi32.dll", "CreateDCA",
-                                CreateDCAPatch);
-    g_iat_patch_get_font_data.Patch(kPdfFileName, "gdi32.dll", "GetFontData",
-                                    GetFontDataPatch);
-  }
-
   // Once we lower the token the sandbox is locked down and no new modules
   // can be loaded. TODO(cpu): consider changing to the loading style of
   // regular plugins.
diff --git a/content/ppapi_plugin/ppapi_thread.h b/content/ppapi_plugin/ppapi_thread.h
index 3d80e49..8b4f522 100644
--- a/content/ppapi_plugin/ppapi_thread.h
+++ b/content/ppapi_plugin/ppapi_thread.h
@@ -14,7 +14,7 @@
 #include "base/process/process.h"
 #include "base/scoped_native_library.h"
 #include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/public/common/pepper_plugin_info.h"
 #include "ppapi/c/pp_module.h"
 #include "ppapi/c/trusted/ppp_broker.h"
@@ -40,7 +40,13 @@
 
 class PpapiBlinkPlatformImpl;
 
-class PpapiThread : public ChildThread,
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
+
+class PpapiThread : public ChildThreadImpl,
                     public ppapi::proxy::PluginDispatcher::PluginDelegate,
                     public ppapi::proxy::PluginProxyDelegate {
  public:
@@ -158,6 +164,10 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(PpapiThread);
 };
 
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
 }  // namespace content
 
 #endif  // CONTENT_PPAPI_PLUGIN_PPAPI_THREAD_H_
diff --git a/content/public/android/java/res/drawable-hdpi/ic_menu_search_holo_light.png b/content/public/android/java/res/drawable-hdpi/ic_search.png
similarity index 100%
rename from content/public/android/java/res/drawable-hdpi/ic_menu_search_holo_light.png
rename to content/public/android/java/res/drawable-hdpi/ic_search.png
Binary files differ
diff --git a/content/public/android/java/res/drawable-mdpi/ic_menu_search_holo_light.png b/content/public/android/java/res/drawable-mdpi/ic_search.png
similarity index 100%
rename from content/public/android/java/res/drawable-mdpi/ic_menu_search_holo_light.png
rename to content/public/android/java/res/drawable-mdpi/ic_search.png
Binary files differ
diff --git a/content/public/android/java/res/drawable-xhdpi/ic_menu_search_holo_light.png b/content/public/android/java/res/drawable-xhdpi/ic_search.png
similarity index 100%
rename from content/public/android/java/res/drawable-xhdpi/ic_menu_search_holo_light.png
rename to content/public/android/java/res/drawable-xhdpi/ic_search.png
Binary files differ
diff --git a/content/public/android/java/res/drawable-xxhdpi/ic_menu_search_holo_light.png b/content/public/android/java/res/drawable-xxhdpi/ic_search.png
similarity index 100%
rename from content/public/android/java/res/drawable-xxhdpi/ic_menu_search_holo_light.png
rename to content/public/android/java/res/drawable-xxhdpi/ic_search.png
Binary files differ
diff --git a/content/public/android/java/res/drawable-xxxhdpi/ic_menu_search_holo_light.png b/content/public/android/java/res/drawable-xxxhdpi/ic_search.png
similarity index 100%
rename from content/public/android/java/res/drawable-xxxhdpi/ic_menu_search_holo_light.png
rename to content/public/android/java/res/drawable-xxxhdpi/ic_search.png
Binary files differ
diff --git a/content/public/android/java/res/values-v17/styles.xml b/content/public/android/java/res/values-v17/styles.xml
index dbdc8b1..58d8ed4 100644
--- a/content/public/android/java/res/values-v17/styles.xml
+++ b/content/public/android/java/res/values-v17/styles.xml
@@ -14,6 +14,6 @@
         <item name="android:icon">@drawable/ic_menu_share_holo_light</item>
     </style>
     <style name="SelectActionMenuWebSearch">
-        <item name="android:icon">@drawable/ic_menu_search_holo_light</item>
+        <item name="android:icon">@drawable/ic_search</item>
     </style>
 </resources>
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 00f974a6..d6cb714 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -296,11 +296,6 @@
         nativeAddMessageToDevToolsConsole(mNativeWebContentsAndroid, level, message);
     }
 
-    @Override
-    public void openUrl(String url, boolean userGesture, boolean isRendererInitiated) {
-        nativeOpenURL(mNativeWebContentsAndroid, url, userGesture, isRendererInitiated);
-    }
-
     @CalledByNative
     private static void onEvaluateJavaScriptResult(
             String jsonResult, JavaScriptCallback callback) {
@@ -352,6 +347,4 @@
             String script, JavaScriptCallback callback);
     private native void nativeAddMessageToDevToolsConsole(
             long nativeWebContentsAndroid, int level, String message);
-    private native void nativeOpenURL(long nativeWebContentsAndroid, String url,
-            boolean userGesture, boolean isRendererInitiated);
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index 3e56e61f..1902161 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -213,13 +213,4 @@
      * org.chromium.content_public.common.ConsoleMessageLevel.
      */
     public void addMessageToDevToolsConsole(int level, String message);
-
-    /**
-     * Opens a URL on web contents.
-     * @param url The URL to open.
-     * @param userGesture Whether navigation is triggered during a user gesture.
-     * @param isRendererInitiated Whether the navigation was started in the renderer (e.g.
-     *        clicking on a link).
-     */
-    public void openUrl(String url, boolean userGesture, boolean isRendererInitiated);
 }
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 13d1c1d..33450ac 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -94,14 +94,14 @@
 
   // Creates a new tab with the already-created WebContents 'new_contents'.
   // The window for the added contents should be reparented correctly when this
-  // method returns.  If |disposition| is NEW_POPUP, |initial_pos| should hold
-  // the initial position. If |was_blocked| is non-nullptr, then |*was_blocked|
-  // will be set to true if the popup gets blocked, and left unchanged
-  // otherwise.
+  // method returns.  If |disposition| is NEW_POPUP, |initial_rect| should hold
+  // the initial position and size. If |was_blocked| is non-nullptr, then
+  // |*was_blocked| will be set to true if the popup gets blocked, and left
+  // unchanged otherwise.
   virtual void AddNewContents(WebContents* source,
                               WebContents* new_contents,
                               WindowOpenDisposition disposition,
-                              const gfx::Rect& initial_pos,
+                              const gfx::Rect& initial_rect,
                               bool user_gesture,
                               bool* was_blocked) {}
 
diff --git a/content/public/child/child_thread.h b/content/public/child/child_thread.h
new file mode 100644
index 0000000..e3df72ca
--- /dev/null
+++ b/content/public/child/child_thread.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 CONTENT_PUBLIC_CHILD_THREAD_H_
+#define CONTENT_PUBLIC_CHILD_THREAD_H_
+
+#include "content/common/content_export.h"
+#include "ipc/ipc_sender.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace content {
+
+class CONTENT_EXPORT ChildThread : public IPC::Sender {
+ public:
+  // Returns the one child thread for this process.  Note that this can only be
+  // accessed when running on the child thread itself.
+  static ChildThread* Get();
+
+  ~ChildThread() override {}
+
+#if defined(OS_WIN)
+  // Request that the given font be loaded by the browser so it's cached by the
+  // OS. Please see ChildProcessHost::PreCacheFont for details.
+  virtual void PreCacheFont(const LOGFONT& log_font) = 0;
+
+  // Release cached font.
+  virtual void ReleaseCachedFonts() = 0;
+#endif
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_CHILD_THREAD_H_
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index de9eb49d..85083ae 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -494,6 +494,14 @@
 const char kGpuRasterizationMSAASampleCount[] =
     "gpu-rasterization-msaa-sample-count";
 
+// Enable threaded GPU rasterization.
+const char kEnableThreadedGpuRasterization[] =
+    "enable-threaded-gpu-rasterization";
+
+// Disable threaded GPU rasterization.  Overrides enable.
+const char kDisableThreadedGpuRasterization[] =
+    "disable-threaded-gpu-rasterization";
+
 // Force renderer accessibility to be on instead of enabling it on demand when
 // a screen reader is detected. The disable-renderer-accessibility switch
 // overrides this if present.
@@ -744,11 +752,6 @@
 // Type of the current test harness ("browser" or "ui").
 const char kTestType[]                      = "test-type";
 
-const char kTouchScrollingMode[]            = "touch-scrolling-mode";
-const char kTouchScrollingModeAsyncTouchmove[] = "async-touchmove";
-const char kTouchScrollingModeSyncTouchmove[] = "sync-touchmove";
-const char kTouchScrollingModeTouchcancel[] = "touchcancel";
-
 // Causes TRACE_EVENT flags to be recorded beginning with shutdown. Optionally,
 // can specify the specific trace categories to include (e.g.
 // --trace-shutdown=base,net) otherwise, all events are recorded.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index a8ad442..fd66188 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -144,6 +144,8 @@
 CONTENT_EXPORT extern const char kForceDisplayList2dCanvas[];
 CONTENT_EXPORT extern const char kForceFieldTrials[];
 CONTENT_EXPORT extern const char kForceGpuRasterization[];
+CONTENT_EXPORT extern const char kEnableThreadedGpuRasterization[];
+CONTENT_EXPORT extern const char kDisableThreadedGpuRasterization[];
 CONTENT_EXPORT extern const char kForceRendererAccessibility[];
 CONTENT_EXPORT extern const char kForceTextBlobs[];
 extern const char kGpuDeviceID[];
@@ -210,10 +212,6 @@
 CONTENT_EXPORT extern const char kTestingFixedHttpPort[];
 CONTENT_EXPORT extern const char kTestingFixedHttpsPort[];
 CONTENT_EXPORT extern const char kTestType[];
-CONTENT_EXPORT extern const char kTouchScrollingMode[];
-CONTENT_EXPORT extern const char kTouchScrollingModeAsyncTouchmove[];
-CONTENT_EXPORT extern const char kTouchScrollingModeSyncTouchmove[];
-CONTENT_EXPORT extern const char kTouchScrollingModeTouchcancel[];
 CONTENT_EXPORT extern const char kTraceShutdown[];
 extern const char kTraceShutdownFile[];
 extern const char kTraceStartup[];
diff --git a/content/public/renderer/DEPS b/content/public/renderer/DEPS
index 36c27b9..f78d4a39 100644
--- a/content/public/renderer/DEPS
+++ b/content/public/renderer/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+content/public/child",
   "+media/base",
   "+media/filters",
   "+media/video",
diff --git a/content/public/renderer/render_thread.h b/content/public/renderer/render_thread.h
index 002f45d..407128b 100644
--- a/content/public/renderer/render_thread.h
+++ b/content/public/renderer/render_thread.h
@@ -10,12 +10,8 @@
 #include "base/memory/shared_memory.h"
 #include "base/metrics/user_metrics_action.h"
 #include "content/common/content_export.h"
+#include "content/public/child/child_thread.h"
 #include "ipc/ipc_channel_proxy.h"
-#include "ipc/ipc_sender.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
 
 class GURL;
 
@@ -45,7 +41,7 @@
 class ResourceDispatcherDelegate;
 class ServiceRegistry;
 
-class CONTENT_EXPORT RenderThread : public IPC::Sender {
+class CONTENT_EXPORT RenderThread : virtual public ChildThread {
  public:
   // Returns the one render thread for this process.  Note that this can only
   // be accessed when running on the render thread itself.
@@ -135,15 +131,6 @@
   // Gets the shutdown event for the process.
   virtual base::WaitableEvent* GetShutdownEvent() = 0;
 
-#if defined(OS_WIN)
-  // Request that the given font be loaded by the browser so it's cached by the
-  // OS. Please see ChildProcessHost::PreCacheFont for details.
-  virtual void PreCacheFont(const LOGFONT& log_font) = 0;
-
-  // Release cached font.
-  virtual void ReleaseCachedFonts() = 0;
-#endif
-
   // Returns the ServiceRegistry for this thread.
   virtual ServiceRegistry* GetServiceRegistry() = 0;
 };
diff --git a/content/public/utility/DEPS b/content/public/utility/DEPS
new file mode 100644
index 0000000..ad94e88
--- /dev/null
+++ b/content/public/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+content/public/child",
+]
diff --git a/content/public/utility/utility_thread.h b/content/public/utility/utility_thread.h
index 6e7cbd10..42bf10c 100644
--- a/content/public/utility/utility_thread.h
+++ b/content/public/utility/utility_thread.h
@@ -6,16 +6,11 @@
 #define CONTENT_PUBLIC_UTILITY_UTILITY_THREAD_H_
 
 #include "base/basictypes.h"
-#include "content/common/content_export.h"
-#include "ipc/ipc_sender.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
+#include "content/public/child/child_thread.h"
 
 namespace content {
 
-class CONTENT_EXPORT UtilityThread : public IPC::Sender {
+class CONTENT_EXPORT UtilityThread : virtual public ChildThread {
  public:
   // Returns the one utility thread for this process.  Note that this can only
   // be accessed when running on the utility thread itself.
@@ -26,15 +21,6 @@
 
   // Releases the process if we are not (or no longer) in batch mode.
   virtual void ReleaseProcessIfNeeded() = 0;
-
-#if defined(OS_WIN)
-  // Request that the given font be loaded by the browser so it's cached by the
-  // OS. Please see ChildProcessHost::PreCacheFont for details.
-  virtual void PreCacheFont(const LOGFONT& log_font) = 0;
-
-  // Release cached font.
-  virtual void ReleaseCachedFonts() = 0;
-#endif
 };
 
 }  // namespace content
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index b6b93c6..44616e5 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -438,8 +438,7 @@
                            src.minValueForRange());
   }
 
-  if (dst->role == ui::AX_ROLE_DOCUMENT ||
-      dst->role == ui::AX_ROLE_WEB_AREA) {
+  if (dst->role == ui::AX_ROLE_WEB_AREA) {
     dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document");
     const WebDocument& document = src.document();
     if (name.empty())
diff --git a/content/renderer/android/synchronous_compositor_factory.h b/content/renderer/android/synchronous_compositor_factory.h
index 3ee74a09..7906f5f 100644
--- a/content/renderer/android/synchronous_compositor_factory.h
+++ b/content/renderer/android/synchronous_compositor_factory.h
@@ -19,14 +19,12 @@
 class OutputSurface;
 }
 
-namespace gpu_blink {
-class WebGraphicsContext3DInProcessCommandBufferImpl;
-}
-
-namespace webkit {
-namespace gpu {
+namespace cc_blink {
 class ContextProviderWebContext;
 }
+
+namespace gpu_blink {
+class WebGraphicsContext3DInProcessCommandBufferImpl;
 }
 
 namespace content {
@@ -59,10 +57,10 @@
   virtual scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
       int routing_id) = 0;
 
-  virtual scoped_refptr<webkit::gpu::ContextProviderWebContext>
-      CreateOffscreenContextProvider(
-          const blink::WebGraphicsContext3D::Attributes& attributes,
-          const std::string& debug_name) = 0;
+  virtual scoped_refptr<cc_blink::ContextProviderWebContext>
+  CreateOffscreenContextProvider(
+      const blink::WebGraphicsContext3D::Attributes& attributes,
+      const std::string& debug_name) = 0;
   virtual scoped_refptr<StreamTextureFactory> CreateStreamTextureFactory(
       int frame_id) = 0;
   virtual gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc
index 410e20b..08293fd 100644
--- a/content/renderer/child_frame_compositing_helper.cc
+++ b/content/renderer/child_frame_compositing_helper.cc
@@ -61,7 +61,10 @@
       render_frame_proxy_(render_frame_proxy),
       frame_(frame) {}
 
-ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
+ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {
+  if (resource_collection_.get())
+    resource_collection_->SetClient(NULL);
+}
 
 BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
   if (!browser_plugin_)
diff --git a/content/renderer/device_sensors/device_motion_event_pump_unittest.cc b/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
index 5b88d66..9b66ea0 100644
--- a/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
+++ b/content/renderer/device_sensors/device_motion_event_pump_unittest.cc
@@ -16,7 +16,8 @@
 
 class MockDeviceMotionListener : public blink::WebDeviceMotionListener {
  public:
-  MockDeviceMotionListener() : did_change_device_motion_(false) {
+  MockDeviceMotionListener()
+      : did_change_device_motion_(false), number_of_events_(0) {
     memset(&data_, 0, sizeof(data_));
   }
   virtual ~MockDeviceMotionListener() { }
@@ -25,17 +26,22 @@
       const blink::WebDeviceMotionData& data) override {
     memcpy(&data_, &data, sizeof(data));
     did_change_device_motion_ = true;
+    ++number_of_events_;
   }
 
   bool did_change_device_motion() const {
     return did_change_device_motion_;
   }
+
+  int number_of_events() const { return number_of_events_; }
+
   const blink::WebDeviceMotionData& data() const {
     return data_;
   }
 
  private:
   bool did_change_device_motion_;
+  int number_of_events_;
   blink::WebDeviceMotionData data_;
 
   DISALLOW_COPY_AND_ASSIGN(MockDeviceMotionListener);
@@ -44,9 +50,17 @@
 class DeviceMotionEventPumpForTesting : public DeviceMotionEventPump {
  public:
   DeviceMotionEventPumpForTesting()
-      : DeviceMotionEventPump(0) { }
+      : DeviceMotionEventPump(0), stop_on_fire_event_(true) {}
   ~DeviceMotionEventPumpForTesting() override {}
 
+  void set_stop_on_fire_event(bool stop_on_fire_event) {
+    stop_on_fire_event_ = stop_on_fire_event;
+  }
+
+  bool stop_on_fire_event() { return stop_on_fire_event_; }
+
+  int pump_delay_microseconds() const { return pump_delay_microseconds_; }
+
   void OnDidStart(base::SharedMemoryHandle renderer_handle) {
     DeviceMotionEventPump::OnDidStart(renderer_handle);
   }
@@ -54,11 +68,15 @@
   void SendStopMessage() override {}
   void FireEvent() override {
     DeviceMotionEventPump::FireEvent();
-    Stop();
-    base::MessageLoop::current()->QuitWhenIdle();
+    if (stop_on_fire_event_) {
+      Stop();
+      base::MessageLoop::current()->QuitWhenIdle();
+    }
   }
 
  private:
+  bool stop_on_fire_event_;
+
   DISALLOW_COPY_AND_ASSIGN(DeviceMotionEventPumpForTesting);
 };
 
@@ -158,4 +176,31 @@
   EXPECT_FALSE(received_data.hasRotationRateGamma);
 }
 
+// Confirm that the frequency of pumping events is not greater than 60Hz. A rate
+// above 60Hz would allow for the detection of keystrokes (crbug.com/421691)
+TEST_F(DeviceMotionEventPumpTest, PumpThrottlesEventRate) {
+  // Confirm that the delay for pumping events is 60 Hz.
+  EXPECT_GE(60, base::Time::kMicrosecondsPerSecond /
+      motion_pump()->pump_delay_microseconds());
+
+  base::MessageLoopForUI loop;
+
+  InitBuffer(true);
+
+  motion_pump()->set_stop_on_fire_event(false);
+  motion_pump()->Start(listener());
+  motion_pump()->OnDidStart(handle());
+
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
+      base::TimeDelta::FromMilliseconds(100));
+  base::MessageLoop::current()->Run();
+  motion_pump()->Stop();
+
+  // Check that the blink::WebDeviceMotionListener does not receive excess
+  // events.
+  EXPECT_TRUE(listener()->did_change_device_motion());
+  EXPECT_GE(6, listener()->number_of_events());
+}
+
 }  // namespace content
diff --git a/content/renderer/geolocation_dispatcher.cc b/content/renderer/geolocation_dispatcher.cc
index ce56f8e..65b85a1 100644
--- a/content/renderer/geolocation_dispatcher.cc
+++ b/content/renderer/geolocation_dispatcher.cc
@@ -4,7 +4,6 @@
 
 #include "content/renderer/geolocation_dispatcher.h"
 
-#include "content/child/child_thread.h"
 #include "content/public/common/geoposition.h"
 #include "content/renderer/render_view_impl.h"
 #include "third_party/WebKit/public/platform/WebString.h"
diff --git a/content/renderer/gpu/compositor_dependencies.h b/content/renderer/gpu/compositor_dependencies.h
index 26dff9d8..9aae19f 100644
--- a/content/renderer/gpu/compositor_dependencies.h
+++ b/content/renderer/gpu/compositor_dependencies.h
@@ -30,6 +30,7 @@
   virtual bool IsImplSidePaintingEnabled() = 0;
   virtual bool IsGpuRasterizationForced() = 0;
   virtual bool IsGpuRasterizationEnabled() = 0;
+  virtual bool IsThreadedGpuRasterizationEnabled() = 0;
   virtual int GetGpuRasterizationMSAASampleCount() = 0;
   virtual bool IsLcdTextEnabled() = 0;
   virtual bool IsDistanceFieldTextEnabled() = 0;
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index f623cb1..a4e8627 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -239,6 +239,8 @@
       compositor_deps_->IsGpuRasterizationForced();
   settings.gpu_rasterization_enabled =
       compositor_deps_->IsGpuRasterizationEnabled();
+  settings.threaded_gpu_rasterization_enabled =
+      compositor_deps_->IsThreadedGpuRasterizationEnabled();
   settings.can_use_lcd_text = compositor_deps_->IsLcdTextEnabled();
   settings.use_distance_field_text =
       compositor_deps_->IsDistanceFieldTextEnabled();
@@ -751,13 +753,11 @@
   layer_tree_host_->SetTopControlsContentOffset(offset);
 }
 
-void RenderWidgetCompositor::WillBeginMainFrame(int frame_id) {
-  widget_->InstrumentWillBeginFrame(frame_id);
+void RenderWidgetCompositor::WillBeginMainFrame() {
   widget_->willBeginCompositorFrame();
 }
 
 void RenderWidgetCompositor::DidBeginMainFrame() {
-  widget_->InstrumentDidBeginFrame();
 }
 
 void RenderWidgetCompositor::BeginMainFrame(const cc::BeginFrameArgs& args) {
@@ -840,7 +840,6 @@
 }
 
 void RenderWidgetCompositor::WillCommit() {
-  widget_->InstrumentWillComposite();
 }
 
 void RenderWidgetCompositor::DidCommit() {
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index 20ce38e..117cffaa 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -132,7 +132,7 @@
   virtual void setTopControlsContentOffset(float);
 
   // cc::LayerTreeHostClient implementation.
-  void WillBeginMainFrame(int frame_id) override;
+  void WillBeginMainFrame() override;
   void DidBeginMainFrame() override;
   void BeginMainFrame(const cc::BeginFrameArgs& args) override;
   void Layout() override;
diff --git a/content/renderer/manifest/manifest_manager.cc b/content/renderer/manifest/manifest_manager.cc
index 5c620c0d..a5ee94cf 100644
--- a/content/renderer/manifest/manifest_manager.cc
+++ b/content/renderer/manifest/manifest_manager.cc
@@ -101,6 +101,11 @@
   manifest_dirty_ = true;
 }
 
+void ManifestManager::DidCommitProvisionalLoad(bool is_new_navigation) {
+  may_have_manifest_ = false;
+  manifest_dirty_ = true;
+}
+
 void ManifestManager::FetchManifest() {
   GURL url(render_frame()->GetWebFrame()->document().manifestURL());
 
diff --git a/content/renderer/manifest/manifest_manager.h b/content/renderer/manifest/manifest_manager.h
index 5874724..e6529f2 100644
--- a/content/renderer/manifest/manifest_manager.h
+++ b/content/renderer/manifest/manifest_manager.h
@@ -42,6 +42,7 @@
   // RenderFrameObserver implementation.
   bool OnMessageReceived(const IPC::Message& message) override;
   void DidChangeManifest() override;
+  void DidCommitProvisionalLoad(bool is_new_navigation) override;
 
  private:
   enum ResolveState {
diff --git a/content/renderer/media/OWNERS b/content/renderer/media/OWNERS
index b5ef0db..dbaad20 100644
--- a/content/renderer/media/OWNERS
+++ b/content/renderer/media/OWNERS
@@ -1,14 +1,15 @@
 dalecurtis@chromium.org
 ddorwin@chromium.org
 jrummell@chromium.org
-perkj@chromium.org
 sandersd@chromium.org
 scherkus@chromium.org
-tommi@chromium.org
-vrk@chromium.org
 wolenetz@chromium.org
 xhwang@chromium.org
 
+# WebRTC OWNERS.
+perkj@chromium.org
+tommi@chromium.org
+
 per-file cast_*=hclam@chromium.org
 per-file cast_*=hubbe@chromium.org
 per-file cast_*=mikhal@chromium.org
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
index 9c24682..66f3d28 100644
--- a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -8,7 +8,7 @@
 #include <GLES2/gl2ext.h>
 
 #include "base/bind.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/gl_helper.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
@@ -48,7 +48,7 @@
     : task_runner_(task_runner),
       gpu_channel_host_(gpu_channel_host),
       context_provider_(context_provider),
-      thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
+      thread_safe_sender_(ChildThreadImpl::current()->thread_safe_sender()) {}
 
 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
 
@@ -239,7 +239,7 @@
 RendererGpuVideoAcceleratorFactories::CreateSharedMemory(size_t size) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   scoped_ptr<base::SharedMemory> mem(
-      ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()));
+      ChildThreadImpl::AllocateSharedMemory(size, thread_safe_sender_.get()));
   if (mem && !mem->Map(size))
     return nullptr;
   return mem;
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index ffa2536c..0bfc9d87 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -13,7 +13,6 @@
 #include "base/stl_util.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task_runner_util.h"
-#include "content/child/child_thread.h"
 #include "content/renderer/media/native_handle_impl.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "media/base/bind_to_current_loop.h"
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index 3b739eb..4c689d6d 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "cc/blink/context_provider_web_context.h"
 #include "cc/blink/web_layer_impl.h"
 #include "cc/layers/video_layer.h"
 #include "content/public/renderer/render_view.h"
@@ -32,7 +33,6 @@
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
 
 using blink::WebCanvas;
 using blink::WebMediaPlayer;
diff --git a/content/renderer/npapi/webplugin_delegate_proxy.cc b/content/renderer/npapi/webplugin_delegate_proxy.cc
index 32cac5d..66bc3627 100644
--- a/content/renderer/npapi/webplugin_delegate_proxy.cc
+++ b/content/renderer/npapi/webplugin_delegate_proxy.cc
@@ -640,7 +640,7 @@
 bool WebPluginDelegateProxy::CreateSharedBitmap(
     scoped_ptr<SharedMemoryBitmap>* memory,
     scoped_ptr<skia::PlatformCanvas>* canvas) {
-  *memory = ChildThread::current()
+  *memory = ChildThreadImpl::current()
                 ->shared_bitmap_manager()
                 ->AllocateSharedMemoryBitmap(plugin_rect_.size());
   if (!memory->get())
diff --git a/content/renderer/pepper/pepper_compositor_host.cc b/content/renderer/pepper/pepper_compositor_host.cc
index c5f5e98..eec292a 100644
--- a/content/renderer/pepper/pepper_compositor_host.cc
+++ b/content/renderer/pepper/pepper_compositor_host.cc
@@ -12,7 +12,7 @@
 #include "cc/resources/texture_mailbox.h"
 #include "cc/trees/layer_tree_host.h"
 #include "content/child/child_shared_bitmap_manager.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/public/renderer/renderer_ppapi_host.h"
 #include "content/renderer/pepper/gfx_conversion.h"
 #include "content/renderer/pepper/host_globals.h"
@@ -288,7 +288,7 @@
       DCHECK_EQ(desc.stride, desc.size.width * 4);
       DCHECK_EQ(desc.format, PP_IMAGEDATAFORMAT_RGBA_PREMUL);
       scoped_ptr<cc::SharedBitmap> bitmap =
-          ChildThread::current()
+          ChildThreadImpl::current()
               ->shared_bitmap_manager()
               ->GetBitmapForSharedMemory(image_shm.get());
 
diff --git a/content/renderer/pepper/pepper_file_system_host.cc b/content/renderer/pepper/pepper_file_system_host.cc
index 69945341..bce63a2 100644
--- a/content/renderer/pepper/pepper_file_system_host.cc
+++ b/content/renderer/pepper/pepper_file_system_host.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/child/fileapi/file_system_dispatcher.h"
 #include "content/common/pepper_file_util.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
@@ -102,7 +102,7 @@
     return PP_ERROR_FAILED;
 
   FileSystemDispatcher* file_system_dispatcher =
-      ChildThread::current()->file_system_dispatcher();
+      ChildThreadImpl::current()->file_system_dispatcher();
   reply_context_ = context->MakeReplyMessageContext();
   file_system_dispatcher->OpenFileSystem(
       document_url.GetOrigin(),
diff --git a/content/renderer/pepper/ppb_broker_impl.cc b/content/renderer/pepper/ppb_broker_impl.cc
index 33181a25..ead54a0 100644
--- a/content/renderer/pepper/ppb_broker_impl.cc
+++ b/content/renderer/pepper/ppb_broker_impl.cc
@@ -32,7 +32,7 @@
       connect_callback_(),
       pipe_handle_(PlatformFileToInt(base::SyncSocket::kInvalidHandle)),
       routing_id_(RenderThreadImpl::current()->GenerateRoutingID()) {
-  ChildThread::current()->GetRouter()->AddRoute(routing_id_, this);
+  ChildThreadImpl::current()->GetRouter()->AddRoute(routing_id_, this);
 }
 
 PPB_Broker_Impl::~PPB_Broker_Impl() {
@@ -43,7 +43,7 @@
 
   // The plugin owns the handle.
   pipe_handle_ = PlatformFileToInt(base::SyncSocket::kInvalidHandle);
-  ChildThread::current()->GetRouter()->RemoveRoute(routing_id_);
+  ChildThreadImpl::current()->GetRouter()->RemoveRoute(routing_id_);
 }
 
 PPB_Broker_API* PPB_Broker_Impl::AsPPB_Broker_API() { return this; }
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index 14123ac..da84db9 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/single_thread_task_runner.h"
+#include "cc/blink/context_provider_web_context.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/renderer/pepper/pepper_video_decoder_host.h"
 #include "content/renderer/render_thread_impl.h"
@@ -24,7 +25,6 @@
 #include "media/video/picture.h"
 #include "media/video/video_decode_accelerator.h"
 #include "ppapi/c/pp_errors.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
 
 namespace content {
 
diff --git a/content/renderer/pepper/video_decoder_shim.h b/content/renderer/pepper/video_decoder_shim.h
index 42335c1f..3a0f32a 100644
--- a/content/renderer/pepper/video_decoder_shim.h
+++ b/content/renderer/pepper/video_decoder_shim.h
@@ -23,6 +23,10 @@
 class SingleThreadTaskRunner;
 }
 
+namespace cc_blink {
+class ContextProviderWebContext;
+}
+
 namespace gpu {
 namespace gles2 {
 class GLES2Interface;
@@ -33,12 +37,6 @@
 class DecoderBuffer;
 }
 
-namespace webkit {
-namespace gpu {
-class ContextProviderWebContext;
-}
-}
-
 namespace content {
 
 class PepperVideoDecoderHost;
@@ -92,7 +90,7 @@
 
   PepperVideoDecoderHost* host_;
   scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
-  scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider_;
+  scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_;
 
   // The current decoded frame size.
   gfx::Size texture_size_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 876e8ae..b9c3fc7 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -157,7 +157,7 @@
 #include "content/renderer/media/android/stream_texture_factory_impl.h"
 #include "content/renderer/media/android/webmediaplayer_android.h"
 #else
-#include "webkit/common/gpu/context_provider_web_context.h"
+#include "cc/blink/context_provider_web_context.h"
 #endif
 
 #if defined(ENABLE_PEPPER_CDMS)
@@ -2041,13 +2041,13 @@
   DCHECK(!frame_ || frame_ == frame);
   // At this point we should have non-null data source.
   DCHECK(frame->dataSource());
-  if (!ChildThread::current())
+  if (!ChildThreadImpl::current())
     return NULL;  // May be null in some tests.
   ServiceWorkerNetworkProvider* provider =
       ServiceWorkerNetworkProvider::FromDocumentState(
           DocumentState::FromDataSource(frame->dataSource()));
   return new WebServiceWorkerProviderImpl(
-      ChildThread::current()->thread_safe_sender(),
+      ChildThreadImpl::current()->thread_safe_sender(),
       provider ? provider->context() : NULL);
 }
 
@@ -2587,7 +2587,7 @@
   // new navigation.
   navigation_state->set_request_committed(true);
 
-  SendDidCommitProvisionalLoad(frame);
+  SendDidCommitProvisionalLoad(frame, commit_type);
 
   // Check whether we have new encoding name.
   UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
@@ -3362,7 +3362,7 @@
     callbacks.didFail(blink::WebStorageQuotaErrorAbort);
     return;
   }
-  ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
+  ChildThreadImpl::current()->quota_dispatcher()->RequestStorageQuota(
       render_view_->GetRoutingID(),
       GURL(origin.toString()),
       static_cast<storage::StorageType>(type),
@@ -3661,7 +3661,9 @@
 }
 
 // Tell the embedding application that the URL of the active page has changed.
-void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) {
+void RenderFrameImpl::SendDidCommitProvisionalLoad(
+      blink::WebFrame* frame,
+      blink::WebHistoryCommitType commit_type) {
   DCHECK(!frame_ || frame_ == frame);
   WebDataSource* ds = frame->dataSource();
   DCHECK(ds);
@@ -3724,7 +3726,7 @@
   render_view_->navigation_gesture_ = NavigationGestureUnknown;
 
   // Make navigation state a part of the DidCommitProvisionalLoad message so
-  // that commited entry has it at all times.
+  // that committed entry has it at all times.
   HistoryEntry* entry = render_view_->history_controller()->GetCurrentEntry();
   if (entry)
     params.page_state = HistoryEntryToPageState(entry);
@@ -3829,13 +3831,12 @@
     // Subframe navigation: the type depends on whether this navigation
     // generated a new session history entry. When they do generate a session
     // history entry, it means the user initiated the navigation and we should
-    // mark it as such. This test checks if this is the first time
-    // SendDidCommitProvisionalLoad has been called since WillNavigateToURL was
-    // called to initiate the load.
-    if (render_view_->page_id_ > render_view_->last_page_id_sent_to_browser_)
-      params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
-    else
+    // mark it as such.
+    bool is_history_navigation = commit_type == blink::WebBackForwardCommit;
+    if (is_history_navigation || ds->replacesCurrentHistoryItem())
       params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
+    else
+      params.transition = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
 
     DCHECK(!navigation_state->history_list_was_cleared());
     params.history_list_was_cleared = false;
@@ -3846,10 +3847,6 @@
       Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params));
   }
 
-  render_view_->last_page_id_sent_to_browser_ =
-      std::max(render_view_->last_page_id_sent_to_browser_,
-               render_view_->page_id_);
-
   // If we end up reusing this WebRequest (for example, due to a #ref click),
   // we don't want the transition type to persist.  Just clear it.
   navigation_state->set_transition_type(ui::PAGE_TRANSITION_LINK);
@@ -4442,7 +4439,7 @@
           SynchronousCompositorFactory::GetInstance()) {
     stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_);
   } else {
-    scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider =
+    scoped_refptr<cc_blink::ContextProviderWebContext> context_provider =
         RenderThreadImpl::current()->SharedMainThreadContextProvider();
 
     if (!context_provider.get()) {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index f387e4f..f6784e7 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -571,7 +571,8 @@
   void RemoveObserver(RenderFrameObserver* observer);
 
   // Builds and sends DidCommitProvisionalLoad to the host.
-  void SendDidCommitProvisionalLoad(blink::WebFrame* frame);
+  void SendDidCommitProvisionalLoad(blink::WebFrame* frame,
+                                    blink::WebHistoryCommitType commit_type);
 
   // IPC message handlers ------------------------------------------------------
   //
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 2914c9c..2044f81 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -282,8 +282,8 @@
 
 scoped_ptr<cc::SharedBitmap> AllocateSharedBitmapFunction(
     const gfx::Size& size) {
-  return ChildThread::current()->shared_bitmap_manager()->AllocateSharedBitmap(
-      size);
+  return ChildThreadImpl::current()->shared_bitmap_manager()->
+      AllocateSharedBitmap(size);
 }
 
 void EnableBlinkPlatformLogChannels(const std::string& channels) {
@@ -423,18 +423,18 @@
 // When we run plugins in process, we actually run them on the render thread,
 // which means that we need to make the render thread pump UI events.
 RenderThreadImpl::RenderThreadImpl()
-    : ChildThread(Options(ShouldUseMojoChannel())) {
+    : ChildThreadImpl(Options(ShouldUseMojoChannel())) {
   Init();
 }
 
 RenderThreadImpl::RenderThreadImpl(const std::string& channel_name)
-    : ChildThread(Options(channel_name, ShouldUseMojoChannel())) {
+    : ChildThreadImpl(Options(channel_name, ShouldUseMojoChannel())) {
   Init();
 }
 
 RenderThreadImpl::RenderThreadImpl(
     scoped_ptr<base::MessageLoop> main_message_loop)
-    : ChildThread(Options(ShouldUseMojoChannel())),
+    : ChildThreadImpl(Options(ShouldUseMojoChannel())),
       main_message_loop_(main_message_loop.Pass()) {
   Init();
 }
@@ -593,6 +593,8 @@
   } else {
     gpu_rasterization_msaa_sample_count_ = 0;
   }
+  is_threaded_gpu_rasterization_enabled_ =
+      command_line.HasSwitch(switches::kEnableThreadedGpuRasterization);
 
   if (command_line.HasSwitch(switches::kDisableDistanceFieldText)) {
     is_distance_field_text_enabled_ = false;
@@ -655,7 +657,7 @@
   }
 
   base::DiscardableMemoryShmemAllocator::SetInstance(
-      ChildThread::discardable_shared_memory_manager());
+      ChildThreadImpl::discardable_shared_memory_manager());
 
   service_registry()->AddService<RenderFrameSetup>(
       base::Bind(CreateRenderFrameSetup));
@@ -670,7 +672,7 @@
   FOR_EACH_OBSERVER(
       RenderProcessObserver, observers_, OnRenderProcessShutdown());
 
-  ChildThread::Shutdown();
+  ChildThreadImpl::Shutdown();
 
   if (memory_observer_) {
     message_loop()->RemoveTaskObserver(memory_observer_.get());
@@ -811,7 +813,7 @@
 #endif
   }
 
-  bool rv = ChildThread::Send(msg);
+  bool rv = ChildThreadImpl::Send(msg);
 
   if (pumping_events) {
 #if defined(ENABLE_PLUGINS)
@@ -860,7 +862,7 @@
 }
 
 void RenderThreadImpl::AddRoute(int32 routing_id, IPC::Listener* listener) {
-  ChildThread::GetRouter()->AddRoute(routing_id, listener);
+  ChildThreadImpl::GetRouter()->AddRoute(routing_id, listener);
   PendingRenderFrameConnectMap::iterator it =
       pending_render_frame_connects_.find(routing_id);
   if (it == pending_render_frame_connects_.end())
@@ -881,7 +883,7 @@
 }
 
 void RenderThreadImpl::RemoveRoute(int32 routing_id) {
-  ChildThread::GetRouter()->RemoveRoute(routing_id);
+  ChildThreadImpl::GetRouter()->RemoveRoute(routing_id);
 }
 
 void RenderThreadImpl::AddEmbeddedWorkerRoute(int32 routing_id,
@@ -1112,7 +1114,7 @@
 
 scoped_ptr<base::SharedMemory>
     RenderThreadImpl::HostAllocateSharedMemoryBuffer(size_t size) {
-  return ChildThread::AllocateSharedMemory(size, thread_safe_sender());
+  return ChildThreadImpl::AllocateSharedMemory(size, thread_safe_sender());
 }
 
 cc::SharedBitmapManager* RenderThreadImpl::GetSharedBitmapManager() {
@@ -1268,7 +1270,7 @@
           NULL));
 }
 
-scoped_refptr<webkit::gpu::ContextProviderWebContext>
+scoped_refptr<cc_blink::ContextProviderWebContext>
 RenderThreadImpl::SharedMainThreadContextProvider() {
   DCHECK(IsMainThread());
   if (!shared_main_thread_contexts_.get() ||
@@ -1326,14 +1328,6 @@
   Send(new ViewHostMsg_PreCacheFontCharacters(log_font, str));
 }
 
-void RenderThreadImpl::PreCacheFont(const LOGFONT& log_font) {
-  Send(new ChildProcessHostMsg_PreCacheFont(log_font));
-}
-
-void RenderThreadImpl::ReleaseCachedFonts() {
-  Send(new ChildProcessHostMsg_ReleaseCachedFonts());
-}
-
 #endif  // OS_WIN
 
 ServiceRegistry* RenderThreadImpl::GetServiceRegistry() {
@@ -1352,6 +1346,10 @@
   return is_gpu_rasterization_enabled_;
 }
 
+bool RenderThreadImpl::IsThreadedGpuRasterizationEnabled() {
+  return is_threaded_gpu_rasterization_enabled_;
+}
+
 int RenderThreadImpl::GetGpuRasterizationMSAASampleCount() {
   return gpu_rasterization_msaa_sample_count_;
 }
@@ -1384,6 +1382,7 @@
 uint32 RenderThreadImpl::GetImageTextureTarget() {
   return use_image_texture_target_;
 }
+
 scoped_refptr<base::SingleThreadTaskRunner>
 RenderThreadImpl::GetCompositorMainThreadTaskRunner() {
   return main_thread_compositor_task_runner_;
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index e204c63d..288f4ffd 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -18,7 +18,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/content_export.h"
 #include "content/common/frame_replication_state.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
@@ -56,6 +56,10 @@
 class ContextProvider;
 }
 
+namespace cc_blink {
+class ContextProviderWebContext;
+}
+
 namespace IPC {
 class MessageFilter;
 }
@@ -69,13 +73,6 @@
 class Extension;
 }
 
-namespace webkit {
-namespace gpu {
-class ContextProviderWebContext;
-class GrContextForWebGraphicsContext3D;
-}
-}
-
 namespace content {
 
 class AppCacheDispatcher;
@@ -110,6 +107,12 @@
 class WebGraphicsContext3DCommandBufferImpl;
 class WebRTCIdentityService;
 
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
+
 // The RenderThreadImpl class represents a background thread where RenderView
 // instances live.  The RenderThread supports an API that is used by its
 // consumer to talk indirectly to the RenderViews and supporting objects.
@@ -121,7 +124,7 @@
 // The routing IDs correspond to RenderView instances.
 class CONTENT_EXPORT RenderThreadImpl
     : public RenderThread,
-      public ChildThread,
+      public ChildThreadImpl,
       public GpuChannelHostFactory,
       NON_EXPORTED_BASE(public CompositorDependencies) {
  public:
@@ -175,16 +178,13 @@
   int PostTaskToAllWebWorkers(const base::Closure& closure) override;
   bool ResolveProxy(const GURL& url, std::string* proxy_list) override;
   base::WaitableEvent* GetShutdownEvent() override;
-#if defined(OS_WIN)
-  virtual void PreCacheFont(const LOGFONT& log_font) override;
-  virtual void ReleaseCachedFonts() override;
-#endif
   ServiceRegistry* GetServiceRegistry() override;
 
   // CompositorDependencies implementation.
   bool IsImplSidePaintingEnabled() override;
   bool IsGpuRasterizationForced() override;
   bool IsGpuRasterizationEnabled() override;
+  bool IsThreadedGpuRasterizationEnabled() override;
   int GetGpuRasterizationMSAASampleCount() override;
   bool IsLcdTextEnabled() override;
   bool IsDistanceFieldTextEnabled() override;
@@ -324,8 +324,8 @@
 
   scoped_refptr<media::GpuVideoAcceleratorFactories> GetGpuFactories();
 
-  scoped_refptr<webkit::gpu::ContextProviderWebContext>
-      SharedMainThreadContextProvider();
+  scoped_refptr<cc_blink::ContextProviderWebContext>
+  SharedMainThreadContextProvider();
 
   // AudioRendererMixerManager instance which manages renderer side mixer
   // instances shared based on configured audio parameters.  Lazily created on
@@ -566,7 +566,7 @@
   scoped_ptr<InputHandlerManager> input_handler_manager_;
   scoped_refptr<CompositorForwardingMessageFilter> compositor_message_filter_;
 
-  scoped_refptr<webkit::gpu::ContextProviderWebContext>
+  scoped_refptr<cc_blink::ContextProviderWebContext>
       shared_main_thread_contexts_;
 
   ObserverList<RenderProcessObserver> observers_;
@@ -595,6 +595,7 @@
   bool is_gpu_rasterization_enabled_;
   bool is_gpu_rasterization_forced_;
   int gpu_rasterization_msaa_sample_count_;
+  bool is_threaded_gpu_rasterization_enabled_;
   bool is_impl_side_painting_enabled_;
   bool is_lcd_text_enabled_;
   bool is_distance_field_text_enabled_;
@@ -625,6 +626,10 @@
   DISALLOW_COPY_AND_ASSIGN(RenderThreadImpl);
 };
 
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
 }  // namespace content
 
 #endif  // CONTENT_RENDERER_RENDER_THREAD_IMPL_H_
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index 3e4a795..39bf764 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -77,6 +77,12 @@
   int count_;
 };
 
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
+
 class RenderThreadImplForTest : public RenderThreadImpl {
  public:
   RenderThreadImplForTest(const std::string& channel_id,
@@ -91,12 +97,16 @@
     RenderThreadImpl::SetResourceDispatchTaskQueue(test_task_counter_);
   }
 
-  using ChildThread::OnMessageReceived;
+  using ChildThreadImpl::OnMessageReceived;
 
  private:
   scoped_refptr<TestTaskCounter> test_task_counter_;
 };
 
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
 void QuitTask(base::MessageLoop* message_loop) {
   message_loop->QuitWhenIdle();
 }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 3be3eb3d..4bd9146e 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -35,7 +35,6 @@
 #include "content/child/appcache/appcache_dispatcher.h"
 #include "content/child/appcache/web_application_cache_host_impl.h"
 #include "content/child/child_shared_bitmap_manager.h"
-#include "content/child/child_thread.h"
 #include "content/child/npapi/webplugin_delegate_impl.h"
 #include "content/child/request_extra_data.h"
 #include "content/child/webmessageportchannel_impl.h"
@@ -642,7 +641,6 @@
       opener_suppressed_(false),
       suppress_dialogs_until_swap_out_(false),
       page_id_(-1),
-      last_page_id_sent_to_browser_(-1),
       next_page_id_(params.next_page_id),
       history_list_offset_(-1),
       history_list_length_(0),
@@ -3671,39 +3669,6 @@
   return true;
 }
 
-void RenderViewImpl::InstrumentWillBeginFrame(int frame_id) {
-  if (!webview())
-    return;
-  if (!webview()->devToolsAgent())
-    return;
-  webview()->devToolsAgent()->didBeginFrame(frame_id);
-}
-
-void RenderViewImpl::InstrumentDidBeginFrame() {
-  if (!webview())
-    return;
-  if (!webview()->devToolsAgent())
-    return;
-  // TODO(jamesr/caseq): Decide if this needs to be renamed.
-  webview()->devToolsAgent()->didComposite();
-}
-
-void RenderViewImpl::InstrumentDidCancelFrame() {
-  if (!webview())
-    return;
-  if (!webview()->devToolsAgent())
-    return;
-  webview()->devToolsAgent()->didCancelFrame();
-}
-
-void RenderViewImpl::InstrumentWillComposite() {
-  if (!webview())
-    return;
-  if (!webview()->devToolsAgent())
-    return;
-  webview()->devToolsAgent()->willComposite();
-}
-
 void RenderViewImpl::DidCompletePageScaleAnimation() {
   FocusChangeComplete();
 }
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index db5540b..e6f99ae 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -501,10 +501,6 @@
   void GetCompositionRange(gfx::Range* range) override;
   bool CanComposeInline() override;
   void DidCommitCompositorFrame() override;
-  void InstrumentWillBeginFrame(int frame_id) override;
-  void InstrumentDidBeginFrame() override;
-  void InstrumentDidCancelFrame() override;
-  void InstrumentWillComposite() override;
   void DidCompletePageScaleAnimation() override;
 
  protected:
@@ -856,13 +852,6 @@
   // See documentation in RenderView.
   int32 page_id_;
 
-  // Indicates the ID of the last page that we sent a FrameNavigate to the
-  // browser for. This is used to determine if the most recent transition
-  // generated a history entry (less than page_id_), or not (equal to or
-  // greater than). Note that this will be greater than page_id_ if the user
-  // goes back.
-  int32 last_page_id_sent_to_browser_;
-
   // The next available page ID to use for this RenderView.  These IDs are
   // specific to a given RenderView and the frames within it.
   int32 next_page_id_;
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 0712b77..a149616 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -255,11 +255,6 @@
   // Returns whether we currently should handle an IME event.
   bool ShouldHandleImeEvent();
 
-  virtual void InstrumentWillBeginFrame(int frame_id) {}
-  virtual void InstrumentDidBeginFrame() {}
-  virtual void InstrumentDidCancelFrame() {}
-  virtual void InstrumentWillComposite() {}
-
   // Called by the compositor when page scale animation completed.
   virtual void DidCompletePageScaleAnimation() {}
 
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 2894dc6..d0c1d88 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -14,6 +14,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "cc/blink/context_provider_web_context.h"
 #include "content/child/database_util.h"
 #include "content/child/file_info_util.h"
 #include "content/child/fileapi/webfilesystem_impl.h"
@@ -79,7 +80,6 @@
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "ui/gfx/color_profile.h"
 #include "url/gurl.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
 
 #if defined(OS_ANDROID)
 #include "content/renderer/android/synchronous_compositor_factory.h"
@@ -245,10 +245,10 @@
   }
 
   // ChildThread may not exist in some tests.
-  if (ChildThread::current()) {
-    sync_message_filter_ = ChildThread::current()->sync_message_filter();
-    thread_safe_sender_ = ChildThread::current()->thread_safe_sender();
-    quota_message_filter_ = ChildThread::current()->quota_message_filter();
+  if (ChildThreadImpl::current()) {
+    sync_message_filter_ = ChildThreadImpl::current()->sync_message_filter();
+    thread_safe_sender_ = ChildThreadImpl::current()->thread_safe_sender();
+    quota_message_filter_ = ChildThreadImpl::current()->quota_message_filter();
     blob_registry_.reset(new WebBlobRegistryImpl(thread_safe_sender_.get()));
     web_idb_factory_.reset(new WebIDBFactoryImpl(thread_safe_sender_.get()));
     web_database_observer_impl_.reset(
@@ -1009,7 +1009,7 @@
 
 blink::WebGraphicsContext3DProvider*
 RendererBlinkPlatformImpl::createSharedOffscreenGraphicsContext3DProvider() {
-  scoped_refptr<webkit::gpu::ContextProviderWebContext> provider =
+  scoped_refptr<cc_blink::ContextProviderWebContext> provider =
       RenderThreadImpl::current()->SharedMainThreadContextProvider();
   if (!provider.get())
     return NULL;
diff --git a/content/renderer/renderer_clipboard_delegate.cc b/content/renderer/renderer_clipboard_delegate.cc
index b8d0b0c..0ed03f6 100644
--- a/content/renderer/renderer_clipboard_delegate.cc
+++ b/content/renderer/renderer_clipboard_delegate.cc
@@ -143,7 +143,7 @@
 
     // Allocate a shared memory buffer to hold the bitmap bits.
     uint32 buf_size = checked_buf_size.ValueOrDie();
-    shared_buf = ChildThread::current()->AllocateSharedMemory(buf_size);
+    shared_buf = ChildThreadImpl::current()->AllocateSharedMemory(buf_size);
     if (!shared_buf)
       return false;
     if (!shared_buf->Map(buf_size))
diff --git a/content/renderer/scheduler/renderer_scheduler_impl.cc b/content/renderer/scheduler/renderer_scheduler_impl.cc
index 7f006144..fbd8cbe6 100644
--- a/content/renderer/scheduler/renderer_scheduler_impl.cc
+++ b/content/renderer/scheduler/renderer_scheduler_impl.cc
@@ -45,6 +45,8 @@
       CONTROL_TASK_QUEUE, RendererTaskQueueSelector::CONTROL_PRIORITY);
   renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
   task_queue_manager_->SetAutoPump(IDLE_TASK_QUEUE, false);
+  // TODO(skyostil): Increase this to 4 (crbug.com/444764).
+  task_queue_manager_->SetWorkBatchSize(1);
 
   for (size_t i = 0; i < TASK_QUEUE_COUNT; i++) {
     task_queue_manager_->SetQueueName(
@@ -255,8 +257,15 @@
   renderer_task_queue_selector_->DisableQueue(IDLE_TASK_QUEUE);
 }
 
+void RendererSchedulerImpl::SetTimeSourceForTesting(
+    scoped_refptr<cc::TestNowSource> time_source) {
+  main_thread_checker_.CalledOnValidThread();
+  time_source_ = time_source;
+  task_queue_manager_->SetTimeSourceForTesting(time_source);
+}
+
 base::TimeTicks RendererSchedulerImpl::Now() const {
-  return gfx::FrameTime::Now();
+  return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now();
 }
 
 RendererSchedulerImpl::PollableNeedsUpdateFlag::PollableNeedsUpdateFlag(
diff --git a/content/renderer/scheduler/renderer_scheduler_impl.h b/content/renderer/scheduler/renderer_scheduler_impl.h
index ccf5881c..9b4fdcf 100644
--- a/content/renderer/scheduler/renderer_scheduler_impl.h
+++ b/content/renderer/scheduler/renderer_scheduler_impl.h
@@ -8,6 +8,7 @@
 #include "base/atomicops.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
+#include "cc/test/test_now_source.h"
 #include "content/renderer/scheduler/cancelable_closure_holder.h"
 #include "content/renderer/scheduler/renderer_scheduler.h"
 #include "content/renderer/scheduler/single_thread_idle_task_runner.h"
@@ -42,9 +43,7 @@
   bool ShouldYieldForHighPriorityWork() override;
   void Shutdown() override;
 
- protected:
-  // Virtual for testing.
-  virtual base::TimeTicks Now() const;
+  void SetTimeSourceForTesting(scoped_refptr<cc::TestNowSource> time_source);
 
  private:
   friend class RendererSchedulerImplTest;
@@ -116,6 +115,8 @@
   void StartIdlePeriod();
   void EndIdlePeriod();
 
+  base::TimeTicks Now() const;
+
   base::ThreadChecker main_thread_checker_;
   scoped_ptr<RendererTaskQueueSelector> renderer_task_queue_selector_;
   scoped_ptr<TaskQueueManager> task_queue_manager_;
@@ -139,6 +140,8 @@
   base::TimeTicks last_input_time_;
   PollableNeedsUpdateFlag policy_may_need_update_;
 
+  scoped_refptr<cc::TestNowSource> time_source_;
+
   base::WeakPtr<RendererSchedulerImpl> weak_renderer_scheduler_ptr_;
   base::WeakPtrFactory<RendererSchedulerImpl> weak_factory_;
 
diff --git a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
index 36c85d3..ee16d04 100644
--- a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
+++ b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
@@ -12,31 +12,18 @@
 
 namespace content {
 
-class RendererSchedulerImplForTest : public RendererSchedulerImpl {
- public:
-  RendererSchedulerImplForTest(
-      scoped_refptr<cc::OrderedSimpleTaskRunner> task_runner,
-      scoped_refptr<cc::TestNowSource> clock)
-      : RendererSchedulerImpl(task_runner), clock_(clock) {}
-  ~RendererSchedulerImplForTest() override {}
-
- protected:
-  base::TimeTicks Now() const override { return clock_->Now(); }
-
- private:
-  scoped_refptr<cc::TestNowSource> clock_;
-};
-
 class RendererSchedulerImplTest : public testing::Test {
  public:
   RendererSchedulerImplTest()
       : clock_(cc::TestNowSource::Create(5000)),
         mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_, false)),
-        scheduler_(new RendererSchedulerImplForTest(mock_task_runner_, clock_)),
+        scheduler_(new RendererSchedulerImpl(mock_task_runner_)),
         default_task_runner_(scheduler_->DefaultTaskRunner()),
         compositor_task_runner_(scheduler_->CompositorTaskRunner()),
         loading_task_runner_(scheduler_->LoadingTaskRunner()),
-        idle_task_runner_(scheduler_->IdleTaskRunner()) {}
+        idle_task_runner_(scheduler_->IdleTaskRunner()) {
+    scheduler_->SetTimeSourceForTesting(clock_);
+  }
   ~RendererSchedulerImplTest() override {}
 
   void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); }
diff --git a/content/renderer/scheduler/task_queue_manager.cc b/content/renderer/scheduler/task_queue_manager.cc
index 07d5e66..083c773 100644
--- a/content/renderer/scheduler/task_queue_manager.cc
+++ b/content/renderer/scheduler/task_queue_manager.cc
@@ -4,13 +4,18 @@
 
 #include "content/renderer/scheduler/task_queue_manager.h"
 
+#include <queue>
+
 #include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "cc/test/test_now_source.h"
 #include "content/renderer/scheduler/task_queue_selector.h"
 
+namespace {
+const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max();
+}
+
 namespace content {
 namespace internal {
 
@@ -42,7 +47,7 @@
   void SetAutoPump(bool auto_pump);
   void PumpQueue();
 
-  bool UpdateWorkQueue();
+  bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task);
   base::PendingTask TakeTaskFromWorkQueue();
 
   void WillDeleteTaskQueueManager();
@@ -76,6 +81,9 @@
   base::TaskQueue incoming_queue_;
   bool auto_pump_;
   const char* name_;
+  std::priority_queue<base::TimeTicks,
+                      std::vector<base::TimeTicks>,
+                      std::greater<base::TimeTicks>> delayed_task_run_times_;
 
   base::TaskQueue work_queue_;
 
@@ -115,6 +123,8 @@
   task_queue_manager_->DidQueueTask(&pending_task);
 
   if (delay > base::TimeDelta()) {
+    pending_task.delayed_run_time = task_queue_manager_->Now() + delay;
+    delayed_task_run_times_.push(pending_task.delayed_run_time);
     return task_queue_manager_->PostDelayedTask(
         from_here, Bind(&TaskQueue::EnqueueTask, this, pending_task), delay);
   }
@@ -132,12 +142,16 @@
   }
 }
 
-bool TaskQueue::UpdateWorkQueue() {
+bool TaskQueue::UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task) {
   if (!work_queue_.empty())
     return true;
 
   {
     base::AutoLock lock(lock_);
+    if (!delayed_task_run_times_.empty()) {
+      *next_pending_delayed_task =
+          std::min(*next_pending_delayed_task, delayed_task_run_times_.top());
+    }
     if (!auto_pump_ || incoming_queue_.empty())
       return false;
     work_queue_.Swap(&incoming_queue_);
@@ -172,6 +186,17 @@
   if (auto_pump_ && incoming_queue_.empty())
     task_queue_manager_->MaybePostDoWorkOnMainRunner();
   incoming_queue_.push(pending_task);
+
+  if (!pending_task.delayed_run_time.is_null()) {
+    // Update the time of the next pending delayed task.
+    while (!delayed_task_run_times_.empty() &&
+           delayed_task_run_times_.top() <= pending_task.delayed_run_time) {
+      delayed_task_run_times_.pop();
+    }
+    // Clear the delayed run time because we've already applied the delay
+    // before getting here.
+    incoming_queue_.back().delayed_run_time = base::TimeTicks();
+  }
 }
 
 void TaskQueue::SetAutoPump(bool auto_pump) {
@@ -247,6 +272,8 @@
     : main_task_runner_(main_task_runner),
       selector_(selector),
       pending_dowork_count_(0),
+      work_batch_size_(1),
+      time_source_(nullptr),
       weak_factory_(this) {
   DCHECK(main_task_runner->RunsTasksOnCurrentThread());
   TRACE_EVENT_OBJECT_CREATED_WITH_ID(
@@ -301,14 +328,21 @@
   queue->PumpQueue();
 }
 
-bool TaskQueueManager::UpdateWorkQueues() {
+bool TaskQueueManager::UpdateWorkQueues(
+    base::TimeTicks* next_pending_delayed_task) {
   // TODO(skyostil): This is not efficient when the number of queues grows very
   // large due to the number of locks taken. Consider optimizing when we get
   // there.
   main_thread_checker_.CalledOnValidThread();
   bool has_work = false;
-  for (auto& queue : queues_)
-    has_work |= queue->UpdateWorkQueue();
+  for (auto& queue : queues_) {
+    has_work |= queue->UpdateWorkQueue(next_pending_delayed_task);
+    if (!queue->work_queue().empty()) {
+      // Currently we should not be getting tasks with delayed run times in any
+      // of the work queues.
+      DCHECK(queue->work_queue().front().delayed_run_time.is_null());
+    }
+  }
   return has_work;
 }
 
@@ -334,14 +368,26 @@
     DCHECK_GE(pending_dowork_count_, 0);
   }
   main_thread_checker_.CalledOnValidThread();
-  if (!UpdateWorkQueues())
-    return;
 
-  size_t queue_index;
-  if (!SelectWorkQueueToService(&queue_index))
-    return;
-  MaybePostDoWorkOnMainRunner();
-  ProcessTaskFromWorkQueue(queue_index);
+  base::TimeTicks next_pending_delayed_task(
+      base::TimeTicks::FromInternalValue(kMaxTimeTicks));
+  for (int i = 0; i < work_batch_size_; i++) {
+    if (!UpdateWorkQueues(&next_pending_delayed_task))
+      return;
+
+    // Interrupt the work batch if we should run the next delayed task.
+    if (i > 0 && next_pending_delayed_task.ToInternalValue() != kMaxTimeTicks &&
+        Now() >= next_pending_delayed_task)
+      return;
+
+    size_t queue_index;
+    if (!SelectWorkQueueToService(&queue_index))
+      return;
+    // Note that this function won't post another call to DoWork if one is
+    // already pending, so it is safe to call it in a loop.
+    MaybePostDoWorkOnMainRunner();
+    ProcessTaskFromWorkQueue(queue_index);
+  }
 }
 
 bool TaskQueueManager::SelectWorkQueueToService(size_t* out_queue_index) {
@@ -390,6 +436,22 @@
   queue->set_name(name);
 }
 
+void TaskQueueManager::SetWorkBatchSize(int work_batch_size) {
+  main_thread_checker_.CalledOnValidThread();
+  DCHECK_GE(work_batch_size, 1);
+  work_batch_size_ = work_batch_size;
+}
+
+void TaskQueueManager::SetTimeSourceForTesting(
+    scoped_refptr<cc::TestNowSource> time_source) {
+  main_thread_checker_.CalledOnValidThread();
+  time_source_ = time_source;
+}
+
+base::TimeTicks TaskQueueManager::Now() const {
+  return UNLIKELY(time_source_) ? time_source_->Now() : base::TimeTicks::Now();
+}
+
 scoped_refptr<base::debug::ConvertableToTraceFormat>
 TaskQueueManager::AsValueWithSelectorResult(bool should_run,
                                             size_t selected_queue) const {
diff --git a/content/renderer/scheduler/task_queue_manager.h b/content/renderer/scheduler/task_queue_manager.h
index 100c6d570..a0a1a44 100644
--- a/content/renderer/scheduler/task_queue_manager.h
+++ b/content/renderer/scheduler/task_queue_manager.h
@@ -22,6 +22,10 @@
 }
 }
 
+namespace cc {
+class TestNowSource;
+}
+
 namespace content {
 namespace internal {
 class TaskQueue;
@@ -80,6 +84,14 @@
   // to a static string.
   void SetQueueName(size_t queue_index, const char* name);
 
+  // Set the number of tasks executed in a single invocation of the task queue
+  // manager. Increasing the batch size can reduce the overhead of yielding
+  // back to the main message loop -- at the cost of potentially delaying other
+  // tasks posted to the main loop. The batch size is 1 by default.
+  void SetWorkBatchSize(int work_batch_size);
+
+  void SetTimeSourceForTesting(scoped_refptr<cc::TestNowSource> time_source);
+
  private:
   friend class internal::TaskQueue;
 
@@ -97,7 +109,9 @@
 
   // Reloads any empty work queues which have automatic pumping enabled.
   // Returns true if any work queue has tasks after doing this.
-  bool UpdateWorkQueues();
+  // |next_pending_delayed_task| should be the time of the next known delayed
+  // task. It is updated if any task is found which should run earlier.
+  bool UpdateWorkQueues(base::TimeTicks* next_pending_delayed_task);
 
   // Chooses the next work queue to service. Returns true if |out_queue_index|
   // indicates the queue from which the next task should be run, false to
@@ -118,6 +132,8 @@
                                   base::TimeDelta delay);
   internal::TaskQueue* Queue(size_t queue_index) const;
 
+  base::TimeTicks Now() const;
+
   scoped_refptr<base::debug::ConvertableToTraceFormat>
   AsValueWithSelectorResult(bool should_run, size_t selected_queue) const;
 
@@ -135,6 +151,10 @@
   // where re-entrant problems happen.
   int pending_dowork_count_;
 
+  int work_batch_size_;
+
+  scoped_refptr<cc::TestNowSource> time_source_;
+
   base::WeakPtrFactory<TaskQueueManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TaskQueueManager);
diff --git a/content/renderer/scheduler/task_queue_manager_unittest.cc b/content/renderer/scheduler/task_queue_manager_unittest.cc
index a6c1347..6d4d26b 100644
--- a/content/renderer/scheduler/task_queue_manager_unittest.cc
+++ b/content/renderer/scheduler/task_queue_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread.h"
+#include "cc/test/test_now_source.h"
 #include "content/renderer/scheduler/task_queue_selector.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -256,6 +257,31 @@
   EXPECT_THAT(run_order, ElementsAre(1));
 }
 
+TEST_F(TaskQueueManagerTest, DelayedTaskDoesNotStayDelayed) {
+  Initialize(1u);
+
+  std::vector<int> run_order;
+  scoped_refptr<base::SingleThreadTaskRunner> runner =
+      manager_->TaskRunnerForQueue(0);
+
+  selector_->AppendQueueToService(0);
+
+  base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10));
+  runner->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
+                          delay);
+  test_task_runner_->RunPendingTasks();
+
+  // Reload the work queue so we see the next pending task. It should no longer
+  // be marked as delayed.
+  manager_->PumpQueue(0);
+  EXPECT_TRUE(selector_->work_queues()[0]->front().delayed_run_time.is_null());
+
+  // Let the task run normally.
+  selector_->AppendQueueToService(0);
+  test_task_runner_->RunUntilIdle();
+  EXPECT_THAT(run_order, ElementsAre(1));
+}
+
 TEST_F(TaskQueueManagerTest, ManualPumping) {
   Initialize(1u);
   manager_->SetAutoPump(0, false);
@@ -480,5 +506,81 @@
   EXPECT_THAT(run_order, ElementsAre(0, 2, 1));
 }
 
+TEST_F(TaskQueueManagerTest, WorkBatching) {
+  Initialize(1u);
+
+  manager_->SetWorkBatchSize(2);
+
+  std::vector<int> run_order;
+  scoped_refptr<base::SingleThreadTaskRunner> runner =
+      manager_->TaskRunnerForQueue(0);
+
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+
+  runner->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
+  runner->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
+  runner->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
+  runner->PostTask(FROM_HERE, base::Bind(&TestTask, 4, &run_order));
+
+  // Running one task in the host message loop should cause two posted tasks to
+  // get executed.
+  EXPECT_EQ(test_task_runner_->GetPendingTasks().size(), 1u);
+  test_task_runner_->RunPendingTasks();
+  EXPECT_THAT(run_order, ElementsAre(1, 2));
+
+  // The second task runs the remaining two posted tasks.
+  EXPECT_EQ(test_task_runner_->GetPendingTasks().size(), 1u);
+  test_task_runner_->RunPendingTasks();
+  EXPECT_THAT(run_order, ElementsAre(1, 2, 3, 4));
+}
+
+void AdvanceNowTestTask(int value,
+                        std::vector<int>* out_result,
+                        scoped_refptr<cc::TestNowSource> time_source,
+                        base::TimeDelta delta) {
+  TestTask(value, out_result);
+  time_source->AdvanceNow(delta);
+}
+
+TEST_F(TaskQueueManagerTest, InterruptWorkBatchForDelayedTask) {
+  scoped_refptr<cc::TestNowSource> clock(cc::TestNowSource::Create());
+  Initialize(1u);
+
+  manager_->SetWorkBatchSize(2);
+  manager_->SetTimeSourceForTesting(clock);
+
+  std::vector<int> run_order;
+  scoped_refptr<base::SingleThreadTaskRunner> runner =
+      manager_->TaskRunnerForQueue(0);
+
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+
+  base::TimeDelta delta(base::TimeDelta::FromMilliseconds(10));
+  runner->PostTask(
+      FROM_HERE, base::Bind(&AdvanceNowTestTask, 2, &run_order, clock, delta));
+  runner->PostTask(
+      FROM_HERE, base::Bind(&AdvanceNowTestTask, 3, &run_order, clock, delta));
+
+  base::TimeDelta delay(base::TimeDelta::FromMilliseconds(5));
+  runner->PostDelayedTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order),
+                          delay);
+
+  // At this point we have two posted tasks: one for DoWork and one of the
+  // delayed task. Only the first non-delayed task should get executed because
+  // the work batch is interrupted by the pending delayed task.
+  EXPECT_EQ(test_task_runner_->GetPendingTasks().size(), 2u);
+  test_task_runner_->RunPendingTasks();
+  EXPECT_THAT(run_order, ElementsAre(2));
+
+  // Running all remaining tasks should execute both pending tasks.
+  test_task_runner_->RunUntilIdle();
+  EXPECT_THAT(run_order, ElementsAre(2, 3, 1));
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_context_client.cc b/content/renderer/service_worker/embedded_worker_context_client.cc
index d04fc06a..958e8f1 100644
--- a/content/renderer/service_worker/embedded_worker_context_client.cc
+++ b/content/renderer/service_worker/embedded_worker_context_client.cc
@@ -103,7 +103,7 @@
       service_worker_scope_(service_worker_scope),
       script_url_(script_url),
       worker_devtools_agent_route_id_(worker_devtools_agent_route_id),
-      sender_(ChildThread::current()->thread_safe_sender()),
+      sender_(ChildThreadImpl::current()->thread_safe_sender()),
       main_thread_proxy_(base::MessageLoopProxy::current()),
       weak_factory_(this) {
   TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
@@ -392,6 +392,12 @@
   script_context_->SkipWaiting(callbacks);
 }
 
+void EmbeddedWorkerContextClient::claim(
+    blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
+  DCHECK(script_context_);
+  script_context_->ClaimClients(callbacks);
+}
+
 void EmbeddedWorkerContextClient::OnMessageToWorker(
     int thread_id,
     int embedded_worker_id,
diff --git a/content/renderer/service_worker/embedded_worker_context_client.h b/content/renderer/service_worker/embedded_worker_context_client.h
index 9bdbeca..9cf8595 100644
--- a/content/renderer/service_worker/embedded_worker_context_client.h
+++ b/content/renderer/service_worker/embedded_worker_context_client.h
@@ -10,11 +10,6 @@
 #include "base/strings/string16.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "ipc/ipc_listener.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerClientFocusCallback.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerClientsInfo.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerSkipWaitingCallbacks.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
 #include "url/gurl.h"
 
@@ -117,6 +112,7 @@
                      blink::WebServiceWorkerClientFocusCallback*);
   virtual void skipWaiting(
       blink::WebServiceWorkerSkipWaitingCallbacks* callbacks);
+  virtual void claim(blink::WebServiceWorkerClientsClaimCallbacks* callbacks);
 
   // TODO: Implement DevTools related method overrides.
 
diff --git a/content/renderer/service_worker/embedded_worker_context_message_filter.cc b/content/renderer/service_worker/embedded_worker_context_message_filter.cc
index cbc141df..4ecaa17 100644
--- a/content/renderer/service_worker/embedded_worker_context_message_filter.cc
+++ b/content/renderer/service_worker/embedded_worker_context_message_filter.cc
@@ -4,45 +4,38 @@
 
 #include "content/renderer/service_worker/embedded_worker_context_message_filter.h"
 
-#include "base/message_loop/message_loop_proxy.h"
-#include "content/child/child_thread.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/child/worker_thread_task_runner.h"
+#include "content/child/child_thread_impl.h"
 #include "content/renderer/service_worker/embedded_worker_context_client.h"
 #include "ipc/ipc_message_macros.h"
 
 namespace content {
 
 EmbeddedWorkerContextMessageFilter::EmbeddedWorkerContextMessageFilter()
-    : main_thread_loop_proxy_(base::MessageLoopProxy::current()),
-      thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
+    : WorkerThreadMessageFilter(
+          ChildThreadImpl::current()->thread_safe_sender()) {
+}
 
 EmbeddedWorkerContextMessageFilter::~EmbeddedWorkerContextMessageFilter() {}
 
-base::TaskRunner*
-EmbeddedWorkerContextMessageFilter::OverrideTaskRunnerForMessage(
-    const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != EmbeddedWorkerContextMsgStart)
-    return NULL;
-  int ipc_thread_id = 0;
-  const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
-  DCHECK(success);
-  if (!ipc_thread_id)
-    return main_thread_loop_proxy_.get();
-  return new WorkerThreadTaskRunner(ipc_thread_id);
+bool EmbeddedWorkerContextMessageFilter::ShouldHandleMessage(
+    const IPC::Message& msg) const {
+  return IPC_MESSAGE_CLASS(msg) == EmbeddedWorkerContextMsgStart;
 }
 
-bool EmbeddedWorkerContextMessageFilter::OnMessageReceived(
+void EmbeddedWorkerContextMessageFilter::OnFilteredMessageReceived(
     const IPC::Message& msg) {
-  if (IPC_MESSAGE_CLASS(msg) != EmbeddedWorkerContextMsgStart)
-    return false;
   EmbeddedWorkerContextClient* client =
       EmbeddedWorkerContextClient::ThreadSpecificInstance();
-  if (!client) {
+  if (!client)
     LOG(ERROR) << "Stray message is sent to nonexistent worker";
-    return true;
-  }
-  return client->OnMessageReceived(msg);
+  else
+    client->OnMessageReceived(msg);
+}
+
+bool EmbeddedWorkerContextMessageFilter::GetWorkerThreadIdForMessage(
+    const IPC::Message& msg,
+    int* ipc_thread_id) {
+  return PickleIterator(msg).ReadInt(ipc_thread_id);
 }
 
 }  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_context_message_filter.h b/content/renderer/service_worker/embedded_worker_context_message_filter.h
index 366c39f..cefdc58 100644
--- a/content/renderer/service_worker/embedded_worker_context_message_filter.h
+++ b/content/renderer/service_worker/embedded_worker_context_message_filter.h
@@ -5,30 +5,24 @@
 #ifndef CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_MESSAGE_FILTER_H_
 #define CONTENT_RENDERER_SERVICE_WORKER_EMBEDDED_WORKER_CONTEXT_MESSAGE_FILTER_H_
 
-#include "content/child/child_message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
+#include "content/child/worker_thread_message_filter.h"
 
 namespace content {
 
-class EmbeddedWorkerContextMessageFilter : public ChildMessageFilter {
+class EmbeddedWorkerContextMessageFilter : public WorkerThreadMessageFilter {
  public:
   EmbeddedWorkerContextMessageFilter();
 
  protected:
   ~EmbeddedWorkerContextMessageFilter() override;
 
-  // ChildMessageFilter implementation:
-  base::TaskRunner* OverrideTaskRunnerForMessage(
-      const IPC::Message& msg) override;
-  bool OnMessageReceived(const IPC::Message& msg) override;
+  // WorkerThreadMessageFilter:
+  bool ShouldHandleMessage(const IPC::Message& msg) const override;
+  void OnFilteredMessageReceived(const IPC::Message& msg) override;
+  bool GetWorkerThreadIdForMessage(const IPC::Message& msg,
+                                   int* ipc_thread_id) override;
 
  private:
-  scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
-  scoped_refptr<ThreadSafeSender> thread_safe_sender_;
-
   DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerContextMessageFilter);
 };
 
diff --git a/content/renderer/service_worker/embedded_worker_devtools_agent.cc b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
index 791a2ca..e1c640a 100644
--- a/content/renderer/service_worker/embedded_worker_devtools_agent.cc
+++ b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
@@ -4,7 +4,6 @@
 
 #include "content/renderer/service_worker/embedded_worker_devtools_agent.h"
 
-#include "content/child/child_thread.h"
 #include "content/common/devtools_messages.h"
 #include "content/renderer/render_thread_impl.h"
 #include "third_party/WebKit/public/platform/WebCString.h"
diff --git a/content/renderer/service_worker/service_worker_script_context.cc b/content/renderer/service_worker/service_worker_script_context.cc
index 9d8acc4..f68a0053 100644
--- a/content/renderer/service_worker/service_worker_script_context.cc
+++ b/content/renderer/service_worker/service_worker_script_context.cc
@@ -106,6 +106,8 @@
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FocusClientResponse,
                         OnFocusClientResponse)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidSkipWaiting, OnDidSkipWaiting)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidClaimClients, OnDidClaimClients)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ClaimClientsError, OnClaimClientsError)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -243,6 +245,13 @@
       GetRoutingID(), request_id, client_id));
 }
 
+void ServiceWorkerScriptContext::ClaimClients(
+    blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
+  DCHECK(callbacks);
+  int request_id = pending_claim_clients_callbacks_.Add(callbacks);
+  Send(new ServiceWorkerHostMsg_ClaimClients(GetRoutingID(), request_id));
+}
+
 void ServiceWorkerScriptContext::SkipWaiting(
     blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
   DCHECK(callbacks);
@@ -460,4 +469,35 @@
   pending_skip_waiting_callbacks_.Remove(request_id);
 }
 
+void ServiceWorkerScriptContext::OnDidClaimClients(int request_id) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerScriptContext::OnDidClaimClients");
+  blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
+      pending_claim_clients_callbacks_.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  callbacks->onSuccess();
+  pending_claim_clients_callbacks_.Remove(request_id);
+}
+
+void ServiceWorkerScriptContext::OnClaimClientsError(
+    int request_id,
+    blink::WebServiceWorkerError::ErrorType error_type,
+    const base::string16& message) {
+  TRACE_EVENT0("ServiceWorker",
+               "ServiceWorkerScriptContext::OnClaimClientsError");
+  blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
+      pending_claim_clients_callbacks_.Lookup(request_id);
+  if (!callbacks) {
+    NOTREACHED() << "Got stray response: " << request_id;
+    return;
+  }
+  scoped_ptr<blink::WebServiceWorkerError> error(
+      new blink::WebServiceWorkerError(error_type, message));
+  callbacks->onError(error.release());
+  pending_claim_clients_callbacks_.Remove(request_id);
+}
+
 }  // namespace content
diff --git a/content/renderer/service_worker/service_worker_script_context.h b/content/renderer/service_worker/service_worker_script_context.h
index 5c8ff2c..3259a4f2 100644
--- a/content/renderer/service_worker/service_worker_script_context.h
+++ b/content/renderer/service_worker/service_worker_script_context.h
@@ -20,7 +20,9 @@
 #include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
 #include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
 #include "third_party/WebKit/public/platform/WebServiceWorkerClientFocusCallback.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerClientsClaimCallbacks.h"
 #include "third_party/WebKit/public/platform/WebServiceWorkerClientsInfo.h"
+#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
 #include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
 #include "third_party/WebKit/public/platform/WebServiceWorkerSkipWaitingCallbacks.h"
 
@@ -83,6 +85,7 @@
   void FocusClient(int client_id,
                    blink::WebServiceWorkerClientFocusCallback* callback);
   void SkipWaiting(blink::WebServiceWorkerSkipWaitingCallbacks* callbacks);
+  void ClaimClients(blink::WebServiceWorkerClientsClaimCallbacks* callbacks);
 
   // Send a message to the browser. Takes ownership of |message|.
   void Send(IPC::Message* message);
@@ -98,6 +101,8 @@
  private:
   typedef IDMap<blink::WebServiceWorkerClientsCallbacks, IDMapOwnPointer>
       ClientsCallbacksMap;
+  typedef IDMap<blink::WebServiceWorkerClientsClaimCallbacks, IDMapOwnPointer>
+      ClaimClientsCallbacksMap;
   typedef IDMap<blink::WebServiceWorkerClientFocusCallback, IDMapOwnPointer>
       FocusClientCallbacksMap;
   typedef IDMap<blink::WebServiceWorkerSkipWaitingCallbacks, IDMapOwnPointer>
@@ -130,6 +135,10 @@
       int request_id, const std::vector<ServiceWorkerClientInfo>& clients);
   void OnFocusClientResponse(int request_id, bool result);
   void OnDidSkipWaiting(int request_id);
+  void OnDidClaimClients(int request_id);
+  void OnClaimClientsError(int request_id,
+                           blink::WebServiceWorkerError::ErrorType error_type,
+                           const base::string16& message);
 
   scoped_ptr<ServiceWorkerCacheStorageDispatcher> cache_storage_dispatcher_;
 
@@ -153,6 +162,9 @@
   // Pending callbacks for SkipWaiting().
   SkipWaitingCallbacksMap pending_skip_waiting_callbacks_;
 
+  // Pending callbacks for ClaimClients().
+  ClaimClientsCallbacksMap pending_claim_clients_callbacks_;
+
   // Capture timestamps for UMA
   std::map<int, base::TimeTicks> activate_start_timings_;
   std::map<int, base::TimeTicks> fetch_start_timings_;
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index d026cec..121831f 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -168,7 +168,7 @@
       GURL(origin.toString()),
       origin.isUnique(),
       route_id_,
-      ChildThread::current()->thread_safe_sender());
+      ChildThreadImpl::current()->thread_safe_sender());
 }
 
 void EmbeddedSharedWorkerStub::sendDevToolsMessage(
diff --git a/content/renderer/shared_worker_repository.cc b/content/renderer/shared_worker_repository.cc
index a883464f..46dcb915 100644
--- a/content/renderer/shared_worker_repository.cc
+++ b/content/renderer/shared_worker_repository.cc
@@ -4,7 +4,7 @@
 
 #include "content/renderer/shared_worker_repository.h"
 
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/view_messages.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/websharedworker_proxy.h"
@@ -39,7 +39,7 @@
   if (route_id == MSG_ROUTING_NONE)
     return NULL;
   documents_with_workers_.insert(document_id);
-  return new WebSharedWorkerProxy(ChildThread::current()->GetRouter(),
+  return new WebSharedWorkerProxy(ChildThreadImpl::current()->GetRouter(),
                                   document_id,
                                   route_id,
                                   params.render_frame_route_id);
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.cc b/content/renderer/webgraphicscontext3d_provider_impl.cc
index 7a31a05..855bd3d 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.cc
+++ b/content/renderer/webgraphicscontext3d_provider_impl.cc
@@ -4,13 +4,14 @@
 
 #include "content/renderer/webgraphicscontext3d_provider_impl.h"
 
-#include "webkit/common/gpu/context_provider_web_context.h"
+#include "cc/blink/context_provider_web_context.h"
 
 namespace content {
 
 WebGraphicsContext3DProviderImpl::WebGraphicsContext3DProviderImpl(
-    scoped_refptr<webkit::gpu::ContextProviderWebContext> provider)
-    : provider_(provider) {}
+    scoped_refptr<cc_blink::ContextProviderWebContext> provider)
+    : provider_(provider) {
+}
 
 WebGraphicsContext3DProviderImpl::~WebGraphicsContext3DProviderImpl() {}
 
diff --git a/content/renderer/webgraphicscontext3d_provider_impl.h b/content/renderer/webgraphicscontext3d_provider_impl.h
index 69c2e984..8225ded 100644
--- a/content/renderer/webgraphicscontext3d_provider_impl.h
+++ b/content/renderer/webgraphicscontext3d_provider_impl.h
@@ -10,11 +10,9 @@
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3DProvider.h"
 
-namespace webkit {
-namespace gpu {
+namespace cc_blink {
 class ContextProviderWebContext;
-}  // namespace webkit
-}  // namespace gpu
+}
 
 namespace content {
 
@@ -22,7 +20,7 @@
     : public NON_EXPORTED_BASE(blink::WebGraphicsContext3DProvider) {
  public:
   explicit WebGraphicsContext3DProviderImpl(
-      scoped_refptr<webkit::gpu::ContextProviderWebContext> provider);
+      scoped_refptr<cc_blink::ContextProviderWebContext> provider);
   virtual ~WebGraphicsContext3DProviderImpl();
 
   // WebGraphicsContext3DProvider implementation.
@@ -30,7 +28,7 @@
   virtual GrContext* grContext() override;
 
  private:
-  scoped_refptr<webkit::gpu::ContextProviderWebContext> provider_;
+  scoped_refptr<cc_blink::ContextProviderWebContext> provider_;
 };
 
 }  // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_devtools_frontend.cc b/content/shell/browser/layout_test/layout_test_devtools_frontend.cc
index c8941c6..a9c1af33 100644
--- a/content/shell/browser/layout_test/layout_test_devtools_frontend.cc
+++ b/content/shell/browser/layout_test/layout_test_devtools_frontend.cc
@@ -33,15 +33,6 @@
   return devtools_frontend;
 }
 
-LayoutTestDevToolsFrontend::LayoutTestDevToolsFrontend(
-    Shell* frontend_shell,
-    DevToolsAgentHost* agent_host)
-    : ShellDevToolsFrontend(frontend_shell, agent_host) {
-}
-
-LayoutTestDevToolsFrontend::~LayoutTestDevToolsFrontend() {
-}
-
 // static.
 GURL LayoutTestDevToolsFrontend::GetDevToolsPathAsURL(
     const std::string& settings,
@@ -70,6 +61,27 @@
   return result;
 }
 
+void LayoutTestDevToolsFrontend::ReuseFrontend(WebContents* inspected_contents,
+                                               const std::string& settings,
+                                               const std::string frontend_url) {
+  AttachTo(inspected_contents);
+  frontend_shell()->LoadURL(GetDevToolsPathAsURL(settings, frontend_url));
+}
+
+LayoutTestDevToolsFrontend::LayoutTestDevToolsFrontend(
+    Shell* frontend_shell,
+    DevToolsAgentHost* agent_host)
+    : ShellDevToolsFrontend(frontend_shell, agent_host) {
+}
+
+LayoutTestDevToolsFrontend::~LayoutTestDevToolsFrontend() {
+}
+
+void LayoutTestDevToolsFrontend::AgentHostClosed(
+    DevToolsAgentHost* agent_host, bool replaced) {
+  // Do not close the front-end shell.
+}
+
 void LayoutTestDevToolsFrontend::RenderProcessGone(
     base::TerminationStatus status) {
   WebKitTestController::Get()->DevToolsProcessCrashed();
diff --git a/content/shell/browser/layout_test/layout_test_devtools_frontend.h b/content/shell/browser/layout_test/layout_test_devtools_frontend.h
index 5106a9b..20db644 100644
--- a/content/shell/browser/layout_test/layout_test_devtools_frontend.h
+++ b/content/shell/browser/layout_test/layout_test_devtools_frontend.h
@@ -24,11 +24,18 @@
   static GURL GetDevToolsPathAsURL(const std::string& settings,
                                    const std::string& frontend_url);
 
+  void ReuseFrontend(WebContents* inspected_contents,
+                     const std::string& settings,
+                     const std::string frontend_url);
+
  private:
   LayoutTestDevToolsFrontend(Shell* frontend_shell,
                              DevToolsAgentHost* agent_host);
   ~LayoutTestDevToolsFrontend() override;
 
+  // content::DevToolsAgentHostClient implementation.
+  void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override;
+
   // WebContentsObserver implementation.
   void RenderProcessGone(base::TerminationStatus status) override;
 
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc
index 5357b1f..546e5e3 100644
--- a/content/shell/browser/shell.cc
+++ b/content/shell/browser/shell.cc
@@ -213,10 +213,10 @@
 void Shell::AddNewContents(WebContents* source,
                            WebContents* new_contents,
                            WindowOpenDisposition disposition,
-                           const gfx::Rect& initial_pos,
+                           const gfx::Rect& initial_rect,
                            bool user_gesture,
                            bool* was_blocked) {
-  CreateShell(new_contents, AdjustWindowSize(initial_pos.size()));
+  CreateShell(new_contents, AdjustWindowSize(initial_rect.size()));
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDumpRenderTree))
     NotifyDoneForwarder::CreateForWebContents(new_contents);
@@ -248,19 +248,14 @@
 }
 
 void Shell::ShowDevTools() {
-  InnerShowDevTools("", "");
+  InnerShowDevTools();
 }
 
 void Shell::ShowDevToolsForElementAt(int x, int y) {
-  InnerShowDevTools("", "");
+  InnerShowDevTools();
   devtools_frontend_->InspectElementAt(x, y);
 }
 
-void Shell::ShowDevToolsForTest(const std::string& settings,
-                                const std::string& frontend_url) {
-  InnerShowDevTools(settings, frontend_url);
-}
-
 void Shell::CloseDevTools() {
   if (!devtools_frontend_)
     return;
@@ -418,16 +413,9 @@
     PlatformSetTitle(entry->GetTitle());
 }
 
-void Shell::InnerShowDevTools(const std::string& settings,
-                              const std::string& frontend_url) {
+void Shell::InnerShowDevTools() {
   if (!devtools_frontend_) {
-    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDumpRenderTree)) {
-      devtools_frontend_ = LayoutTestDevToolsFrontend::Show(
-          web_contents(), settings, frontend_url);
-    } else {
-      devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
-    }
+    devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
     devtools_observer_.reset(new DevToolsWebContentsObserver(
         this, devtools_frontend_->frontend_shell()->web_contents()));
   }
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
index c9f9c9f..1245315 100644
--- a/content/shell/browser/shell.h
+++ b/content/shell/browser/shell.h
@@ -70,8 +70,6 @@
   void Close();
   void ShowDevTools();
   void ShowDevToolsForElementAt(int x, int y);
-  void ShowDevToolsForTest(const std::string& settings,
-                           const std::string& frontend_url);
   void CloseDevTools();
 #if defined(OS_MACOSX)
   // Resizes the web content view to the given dimensions.
@@ -117,7 +115,7 @@
   void AddNewContents(WebContents* source,
                       WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   void LoadingStateChanged(WebContents* source,
@@ -216,8 +214,7 @@
   // WebContentsObserver
   void TitleWasSet(NavigationEntry* entry, bool explicit_set) override;
 
-  void InnerShowDevTools(const std::string& settings,
-                         const std::string& frontend_url);
+  void InnerShowDevTools();
   void OnDevToolsWebContentsDestroyed();
 
   scoped_ptr<ShellJavaScriptDialogManager> dialog_manager_;
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc
index 42ffa70..a6bead6 100644
--- a/content/shell/browser/shell_devtools_frontend.cc
+++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -60,13 +60,21 @@
 }
 
 void ShellDevToolsFrontend::InspectElementAt(int x, int y) {
-  agent_host_->InspectElement(x, y);
+  if (agent_host_)
+    agent_host_->InspectElement(x, y);
 }
 
 void ShellDevToolsFrontend::Close() {
   frontend_shell_->Close();
 }
 
+void ShellDevToolsFrontend::DisconnectFromTarget() {
+  if (!agent_host_)
+    return;
+  agent_host_->DetachClient();
+  agent_host_ = NULL;
+}
+
 ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell,
                                              DevToolsAgentHost* agent_host)
     : WebContentsObserver(frontend_shell->web_contents()),
@@ -82,17 +90,26 @@
   if (!frontend_host_) {
     frontend_host_.reset(
         DevToolsFrontendHost::Create(web_contents()->GetMainFrame(), this));
-    agent_host_->AttachClient(this);
   }
 }
 
+void ShellDevToolsFrontend::DidNavigateMainFrame(
+    const LoadCommittedDetails& details,
+    const FrameNavigateParams& params) {
+  if (agent_host_)
+    agent_host_->AttachClient(this);
+}
+
 void ShellDevToolsFrontend::WebContentsDestroyed() {
-  agent_host_->DetachClient();
+  if (agent_host_)
+    agent_host_->DetachClient();
   delete this;
 }
 
 void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend(
     const std::string& message) {
+  if (!agent_host_)
+    return;
   std::string method;
   int id = 0;
   base::ListValue* params = NULL;
@@ -127,7 +144,8 @@
 
 void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontendToBackend(
     const std::string& message) {
-  agent_host_->DispatchProtocolMessage(message);
+  if (agent_host_)
+    agent_host_->DispatchProtocolMessage(message);
 }
 
 void ShellDevToolsFrontend::DispatchProtocolMessage(
@@ -151,6 +169,11 @@
   }
 }
 
+void ShellDevToolsFrontend::AttachTo(WebContents* inspected_contents) {
+  DisconnectFromTarget();
+  agent_host_ = DevToolsAgentHost::GetOrCreateFor(inspected_contents);
+}
+
 void ShellDevToolsFrontend::AgentHostClosed(
     DevToolsAgentHost* agent_host, bool replaced) {
   frontend_shell_->Close();
diff --git a/content/shell/browser/shell_devtools_frontend.h b/content/shell/browser/shell_devtools_frontend.h
index 038b88b..adfe90e7 100644
--- a/content/shell/browser/shell_devtools_frontend.h
+++ b/content/shell/browser/shell_devtools_frontend.h
@@ -30,15 +30,26 @@
   void InspectElementAt(int x, int y);
   void Close();
 
+  void DisconnectFromTarget();
+
   Shell* frontend_shell() const { return frontend_shell_; }
 
  protected:
   ShellDevToolsFrontend(Shell* frontend_shell, DevToolsAgentHost* agent_host);
   ~ShellDevToolsFrontend() override;
 
+  // content::DevToolsAgentHostClient implementation.
+  void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override;
+  void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
+                               const std::string& message) override;
+  void AttachTo(WebContents* inspected_contents);
+
  private:
   // WebContentsObserver overrides
   void RenderViewCreated(RenderViewHost* render_view_host) override;
+  void DidNavigateMainFrame(
+      const LoadCommittedDetails& details,
+      const FrameNavigateParams& params) override;
   void WebContentsDestroyed() override;
 
   // content::DevToolsFrontendHost::Delegate implementation.
@@ -46,11 +57,6 @@
   void HandleMessageFromDevToolsFrontendToBackend(
       const std::string& message) override;
 
-  // content::DevToolsAgentHostClient implementation.
-  void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
-                               const std::string& message) override;
-  void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override;
-
   Shell* frontend_shell_;
   scoped_refptr<DevToolsAgentHost> agent_host_;
   scoped_ptr<DevToolsFrontendHost> frontend_host_;
diff --git a/content/shell/browser/webkit_test_controller.cc b/content/shell/browser/webkit_test_controller.cc
index 3712d32..a4dc574 100644
--- a/content/shell/browser/webkit_test_controller.cc
+++ b/content/shell/browser/webkit_test_controller.cc
@@ -205,7 +205,8 @@
       is_leak_detection_enabled_(
           base::CommandLine::ForCurrentProcess()->HasSwitch(
               switches::kEnableLeakDetection)),
-      crash_when_leak_found_(false) {
+      crash_when_leak_found_(false),
+      devtools_frontend_(NULL) {
   CHECK(!instance_);
   instance_ = this;
 
@@ -433,7 +434,9 @@
 void WebKitTestController::DevToolsProcessCrashed() {
   DCHECK(CalledOnValidThread());
   printer_->AddErrorMessage("#CRASHED - devtools");
-  DiscardMainWindow();
+  if (devtools_frontend_)
+      devtools_frontend_->Close();
+  devtools_frontend_ = NULL;
 }
 
 void WebKitTestController::WebContentsDestroyed() {
@@ -586,11 +589,20 @@
 
 void WebKitTestController::OnShowDevTools(const std::string& settings,
                                           const std::string& frontend_url) {
-  main_window_->ShowDevToolsForTest(settings, frontend_url);
+  if (!devtools_frontend_) {
+    devtools_frontend_ = LayoutTestDevToolsFrontend::Show(
+        main_window_->web_contents(), settings, frontend_url);
+  } else {
+    devtools_frontend_->ReuseFrontend(
+        main_window_->web_contents(), settings, frontend_url);
+  }
+  devtools_frontend_->Activate();
+  devtools_frontend_->Focus();
 }
 
 void WebKitTestController::OnCloseDevTools() {
-  main_window_->CloseDevTools();
+  if (devtools_frontend_)
+    devtools_frontend_->DisconnectFromTarget();
 }
 
 void WebKitTestController::OnGoToOffset(int offset) {
@@ -653,8 +665,10 @@
 void WebKitTestController::OnCloseRemainingWindows() {
   DevToolsAgentHost::DetachAllClients();
   std::vector<Shell*> open_windows(Shell::windows());
+  Shell* devtools_shell = devtools_frontend_ ?
+      devtools_frontend_->frontend_shell() : NULL;
   for (size_t i = 0; i < open_windows.size(); ++i) {
-    if (open_windows[i] != main_window_)
+    if (open_windows[i] != main_window_ && open_windows[i] != devtools_shell)
       open_windows[i]->Close();
   }
   base::MessageLoop::current()->RunUntilIdle();
diff --git a/content/shell/browser/webkit_test_controller.h b/content/shell/browser/webkit_test_controller.h
index 0bbe9957..1680c67 100644
--- a/content/shell/browser/webkit_test_controller.h
+++ b/content/shell/browser/webkit_test_controller.h
@@ -28,6 +28,7 @@
 
 namespace content {
 
+class LayoutTestDevToolsFrontend;
 class Shell;
 
 #if defined(OS_ANDROID)
@@ -214,6 +215,8 @@
   const bool is_leak_detection_enabled_;
   bool crash_when_leak_found_;
 
+  LayoutTestDevToolsFrontend* devtools_frontend_;
+
 #if defined(OS_ANDROID)
   // Because of the nested message pump implementation, Android needs to allow
   // waiting on the UI thread while layout tests are being ran.
diff --git a/content/test/data/accessibility/aria/aria-document-expected-android.txt b/content/test/data/accessibility/aria/aria-document-expected-android.txt
index 4783e71..cb393f69 100644
--- a/content/test/data/accessibility/aria/aria-document-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-document-expected-android.txt
@@ -1,2 +1,2 @@
 android.webkit.WebView focusable focused scrollable
-    android.view.View clickable scrollable name='aria role document'
+    android.view.View clickable name='aria role document'
diff --git a/content/test/data/accessibility/aria/aria-grid-expected-android.txt b/content/test/data/accessibility/aria/aria-grid-expected-android.txt
new file mode 100644
index 0000000..52b4bb3
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-grid-expected-android.txt
@@ -0,0 +1,11 @@
+android.webkit.WebView focusable focused scrollable
+    android.widget.GridView collection row_count=2 column_count=2
+        android.view.View
+            android.view.View clickable collection_item heading name='Browser' row_span=1 column_span=1
+            android.view.View clickable collection_item heading name='Rendering Engine' row_span=1 column_index=1 column_span=1
+        android.view.View
+            android.view.View clickable collection_item name='Chrome' row_index=1 row_span=1 column_span=1
+            android.view.View clickable collection_item name='Blink' row_index=1 row_span=1 column_index=1 column_span=1
+        android.view.View
+        android.view.View
+        android.view.View
diff --git a/content/test/data/accessibility/aria/aria-grid-expected-mac.txt b/content/test/data/accessibility/aria/aria-grid-expected-mac.txt
new file mode 100644
index 0000000..60efdf7
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-grid-expected-mac.txt
@@ -0,0 +1,15 @@
+AXWebArea AXRoleDescription='HTML content'
+    AXTable AXRoleDescription='table'
+        AXRow AXRoleDescription='row'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Browser'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Rendering Engine'
+        AXRow AXRoleDescription='row'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Chrome'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Blink'
+        AXColumn AXRoleDescription='column'
+        AXColumn AXRoleDescription='column'
+        AXGroup AXRoleDescription='group'
diff --git a/content/test/data/accessibility/aria/aria-grid-expected-win.txt b/content/test/data/accessibility/aria/aria-grid-expected-win.txt
new file mode 100644
index 0000000..c6e0ec4
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-grid-expected-win.txt
@@ -0,0 +1,15 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+    ROLE_SYSTEM_TABLE MULTISELECTABLE EXTSELECTABLE xml-roles:grid
+        ROLE_SYSTEM_ROW xml-roles:row
+            ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+                ROLE_SYSTEM_STATICTEXT name='Browser'
+            ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+                ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
+        ROLE_SYSTEM_ROW xml-roles:row
+            ROLE_SYSTEM_CELL xml-roles:gridcell
+                ROLE_SYSTEM_STATICTEXT name='Chrome'
+            ROLE_SYSTEM_CELL xml-roles:gridcell
+                ROLE_SYSTEM_STATICTEXT name='Blink'
+        ROLE_SYSTEM_COLUMN
+        ROLE_SYSTEM_COLUMN
+        IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria/aria-grid.html b/content/test/data/accessibility/aria/aria-grid.html
new file mode 100644
index 0000000..519ee29
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-grid.html
@@ -0,0 +1,20 @@
+<!--
+@MAC-ALLOW:AXRole*
+@WIN-ALLOW:*SELECTABLE
+@WIN-ALLOW:xml-roles*
+-->
+<!DOCTYPE html>
+<html>
+<body>
+<div role="grid">
+  <div role="row">
+    <span role="columnheader">Browser</span>
+    <span role="columnheader">Rendering Engine</span>
+  </div>
+  <div role="row">
+    <span role="gridcell">Chrome</span>
+    <span role="gridcell">Blink</span>
+  </div>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/aria/aria-gridcell-expected-android.txt b/content/test/data/accessibility/aria/aria-gridcell-expected-android.txt
new file mode 100644
index 0000000..52b4bb3
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-gridcell-expected-android.txt
@@ -0,0 +1,11 @@
+android.webkit.WebView focusable focused scrollable
+    android.widget.GridView collection row_count=2 column_count=2
+        android.view.View
+            android.view.View clickable collection_item heading name='Browser' row_span=1 column_span=1
+            android.view.View clickable collection_item heading name='Rendering Engine' row_span=1 column_index=1 column_span=1
+        android.view.View
+            android.view.View clickable collection_item name='Chrome' row_index=1 row_span=1 column_span=1
+            android.view.View clickable collection_item name='Blink' row_index=1 row_span=1 column_index=1 column_span=1
+        android.view.View
+        android.view.View
+        android.view.View
diff --git a/content/test/data/accessibility/aria/aria-gridcell-expected-mac.txt b/content/test/data/accessibility/aria/aria-gridcell-expected-mac.txt
new file mode 100644
index 0000000..60efdf7
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-gridcell-expected-mac.txt
@@ -0,0 +1,15 @@
+AXWebArea AXRoleDescription='HTML content'
+    AXTable AXRoleDescription='table'
+        AXRow AXRoleDescription='row'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Browser'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Rendering Engine'
+        AXRow AXRoleDescription='row'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Chrome'
+            AXCell AXRoleDescription='cell'
+                AXStaticText AXRoleDescription='text' AXValue='Blink'
+        AXColumn AXRoleDescription='column'
+        AXColumn AXRoleDescription='column'
+        AXGroup AXRoleDescription='group'
diff --git a/content/test/data/accessibility/aria/aria-gridcell-expected-win.txt b/content/test/data/accessibility/aria/aria-gridcell-expected-win.txt
new file mode 100644
index 0000000..c6e0ec4
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-gridcell-expected-win.txt
@@ -0,0 +1,15 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+    ROLE_SYSTEM_TABLE MULTISELECTABLE EXTSELECTABLE xml-roles:grid
+        ROLE_SYSTEM_ROW xml-roles:row
+            ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+                ROLE_SYSTEM_STATICTEXT name='Browser'
+            ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+                ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
+        ROLE_SYSTEM_ROW xml-roles:row
+            ROLE_SYSTEM_CELL xml-roles:gridcell
+                ROLE_SYSTEM_STATICTEXT name='Chrome'
+            ROLE_SYSTEM_CELL xml-roles:gridcell
+                ROLE_SYSTEM_STATICTEXT name='Blink'
+        ROLE_SYSTEM_COLUMN
+        ROLE_SYSTEM_COLUMN
+        IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria/aria-gridcell.html b/content/test/data/accessibility/aria/aria-gridcell.html
new file mode 100644
index 0000000..519ee29
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-gridcell.html
@@ -0,0 +1,20 @@
+<!--
+@MAC-ALLOW:AXRole*
+@WIN-ALLOW:*SELECTABLE
+@WIN-ALLOW:xml-roles*
+-->
+<!DOCTYPE html>
+<html>
+<body>
+<div role="grid">
+  <div role="row">
+    <span role="columnheader">Browser</span>
+    <span role="columnheader">Rendering Engine</span>
+  </div>
+  <div role="row">
+    <span role="gridcell">Chrome</span>
+    <span role="gridcell">Blink</span>
+  </div>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/aria/aria-group-expected-android.txt b/content/test/data/accessibility/aria/aria-group-expected-android.txt
new file mode 100644
index 0000000..fe79120
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-group-expected-android.txt
@@ -0,0 +1,4 @@
+android.webkit.WebView focusable focused scrollable
+    android.view.View
+        android.view.View clickable link name='Group Link1'
+        android.view.View clickable link name='Group Link2'
diff --git a/content/test/data/accessibility/aria/aria-group-expected-mac.txt b/content/test/data/accessibility/aria/aria-group-expected-mac.txt
new file mode 100644
index 0000000..8004720
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-group-expected-mac.txt
@@ -0,0 +1,6 @@
+AXWebArea AXRoleDescription='HTML content'
+    AXGroup AXRoleDescription='group'
+        AXLink AXRoleDescription='link' AXTitle='Group Link1'
+            AXStaticText AXRoleDescription='text' AXValue='Group Link1'
+        AXLink AXRoleDescription='link' AXTitle='Group Link2'
+            AXStaticText AXRoleDescription='text' AXValue='Group Link2'
diff --git a/content/test/data/accessibility/aria/aria-group-expected-win.txt b/content/test/data/accessibility/aria/aria-group-expected-win.txt
new file mode 100644
index 0000000..89c9c48
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-group-expected-win.txt
@@ -0,0 +1,6 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+    ROLE_SYSTEM_GROUPING xml-roles:group
+        ROLE_SYSTEM_LINK name='Group Link1' xml-roles:link
+            ROLE_SYSTEM_STATICTEXT name='Group Link1'
+        ROLE_SYSTEM_LINK name='Group Link2' xml-roles:link
+            ROLE_SYSTEM_STATICTEXT name='Group Link2'
diff --git a/content/test/data/accessibility/aria/aria-group.html b/content/test/data/accessibility/aria/aria-group.html
new file mode 100644
index 0000000..f70f4a5
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-group.html
@@ -0,0 +1,13 @@
+<!--
+@MAC-ALLOW:AXRole*
+@WIN-ALLOW:xml-roles*
+-->
+<!DOCTYPE html>
+<html>
+<body>
+  <div role="group">
+      <div role="link">Group Link1</div>
+      <div role="link">Group Link2</div>
+  </div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/aria/aria-selected-expected-android.txt b/content/test/data/accessibility/aria/aria-selected-expected-android.txt
index 9ee8f685..2b31af84 100644
--- a/content/test/data/accessibility/aria/aria-selected-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-selected-expected-android.txt
@@ -1,4 +1,4 @@
 android.webkit.WebView focusable focused scrollable
     android.widget.ListView collection item_count=2 row_count=2
-        android.view.View clickable collection_item focusable selected name='4'
-        android.view.View clickable collection_item focusable selected name='5' item_index=1 row_index=1
+        android.view.View clickable collection_item focusable selected name='1'
+        android.view.View clickable collection_item focusable name='2' item_index=1 row_index=1
diff --git a/content/test/data/accessibility/aria/aria-selected-expected-mac.txt b/content/test/data/accessibility/aria/aria-selected-expected-mac.txt
index 5f50267e..3ffd2f2 100644
--- a/content/test/data/accessibility/aria/aria-selected-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-selected-expected-mac.txt
@@ -1,4 +1,5 @@
+#<skip -- Expose AXSelected on selected child>
 AXWebArea
-    AXList AXSelectedChildren=["AXStaticText 4","AXStaticText 5"]
-        AXStaticText AXTitle='Item 4'
-        AXStaticText AXTitle='Item 5'
+    AXList AXSelectedChildren=["AXStaticText 1"]
+        AXStaticText AXTitle='Item 1'
+        AXStaticText AXTitle='Item 2'
diff --git a/content/test/data/accessibility/aria/aria-selected-expected-win.txt b/content/test/data/accessibility/aria/aria-selected-expected-win.txt
index 1dee781..af8726e5 100644
--- a/content/test/data/accessibility/aria/aria-selected-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-selected-expected-win.txt
@@ -1,4 +1,4 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
     ROLE_SYSTEM_LIST
-        ROLE_SYSTEM_LISTITEM name='4' SELECTED FOCUSABLE
-        ROLE_SYSTEM_LISTITEM name='5' SELECTED FOCUSABLE
+        ROLE_SYSTEM_LISTITEM name='1' SELECTED FOCUSABLE
+        ROLE_SYSTEM_LISTITEM name='2' FOCUSABLE
diff --git a/content/test/data/accessibility/aria/aria-selected.html b/content/test/data/accessibility/aria/aria-selected.html
index 7934adb..521998d 100644
--- a/content/test/data/accessibility/aria/aria-selected.html
+++ b/content/test/data/accessibility/aria/aria-selected.html
@@ -6,8 +6,8 @@
 <html>
 <body>
 <div role="listbox">
-  <div tabIndex="-1" aria-selected="true" aria-label="4" role="option">Item 4</div>
-  <div tabIndex="-1" aria-selected="true" aria-label="5" role="option">Item 5</div>
+  <div tabIndex="-1" aria-selected="true" aria-label="1" role="option">Item 1</div>
+  <div tabIndex="-1" aria-selected="false" aria-label="2" role="option">Item 2</div>
 </div>
 </body>
 </html>
diff --git a/content/test/data/accessibility/aria/aria-tabpanel-expected-android.txt b/content/test/data/accessibility/aria/aria-tabpanel-expected-android.txt
new file mode 100644
index 0000000..299eb2ab
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-tabpanel-expected-android.txt
@@ -0,0 +1,4 @@
+android.webkit.WebView focusable focused scrollable
+    android.view.View
+        android.view.View clickable name='Item'
+        android.view.View clickable name='Prices'
diff --git a/content/test/data/accessibility/aria/aria-tabpanel-expected-mac.txt b/content/test/data/accessibility/aria/aria-tabpanel-expected-mac.txt
new file mode 100644
index 0000000..d32959c
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-tabpanel-expected-mac.txt
@@ -0,0 +1,4 @@
+AXWebArea AXRoleDescription='HTML content'
+    AXGroup AXSubrole=AXTabPanel AXRoleDescription='tabpanel'
+        AXRadioButton AXRoleDescription='tab' AXTitle='Item' AXValue='0'
+        AXRadioButton AXRoleDescription='tab' AXTitle='Prices' AXValue='0'
diff --git a/content/test/data/accessibility/aria/aria-tabpanel-expected-win.txt b/content/test/data/accessibility/aria/aria-tabpanel-expected-win.txt
new file mode 100644
index 0000000..567c1908
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-tabpanel-expected-win.txt
@@ -0,0 +1,4 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+    ROLE_SYSTEM_PROPERTYPAGE xml-roles:tabpanel
+        ROLE_SYSTEM_PAGETAB name='Item' xml-roles:tab
+        ROLE_SYSTEM_PAGETAB name='Prices' xml-roles:tab
diff --git a/content/test/data/accessibility/aria/aria-tabpanel.html b/content/test/data/accessibility/aria/aria-tabpanel.html
new file mode 100644
index 0000000..e1dfa941
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-tabpanel.html
@@ -0,0 +1,18 @@
+<!--
+@MAC-ALLOW:AXRole*
+@MAC-ALLOW:AXSubrole*
+@WIN-ALLOW:xml-roles*
+-->
+<!DOCTYPE html>
+<html>
+<body>
+<div role="tabpanel">
+  <div role="tab">
+    <h3>Item</h3>
+  </div>
+  <div role="tab">
+    <h3>Prices</h3>
+  </div>
+</div>
+</body>
+</html>
diff --git a/content/test/data/accessibility/html/b-expected-android.txt b/content/test/data/accessibility/html/b-expected-android.txt
new file mode 100644
index 0000000..9f21fc6
--- /dev/null
+++ b/content/test/data/accessibility/html/b-expected-android.txt
@@ -0,0 +1 @@
+#<skip -- Doesn't have an accessible>
diff --git a/content/test/data/accessibility/html/b-expected-mac.txt b/content/test/data/accessibility/html/b-expected-mac.txt
new file mode 100644
index 0000000..9f21fc6
--- /dev/null
+++ b/content/test/data/accessibility/html/b-expected-mac.txt
@@ -0,0 +1 @@
+#<skip -- Doesn't have an accessible>
diff --git a/content/test/data/accessibility/html/b-expected-win.txt b/content/test/data/accessibility/html/b-expected-win.txt
new file mode 100644
index 0000000..9f21fc6
--- /dev/null
+++ b/content/test/data/accessibility/html/b-expected-win.txt
@@ -0,0 +1 @@
+#<skip -- Doesn't have an accessible>
diff --git a/content/test/data/accessibility/html/b.html b/content/test/data/accessibility/html/b.html
new file mode 100644
index 0000000..76b9c8b
--- /dev/null
+++ b/content/test/data/accessibility/html/b.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+  <b>This is bold text</b>
+
+</body>
+</html>
diff --git a/content/test/data/accessibility/html/base-expected-android.txt b/content/test/data/accessibility/html/base-expected-android.txt
new file mode 100644
index 0000000..4ce8140
--- /dev/null
+++ b/content/test/data/accessibility/html/base-expected-android.txt
@@ -0,0 +1 @@
+#<skip - Not Mapped>
diff --git a/content/test/data/accessibility/html/base-expected-mac.txt b/content/test/data/accessibility/html/base-expected-mac.txt
new file mode 100644
index 0000000..4ce8140
--- /dev/null
+++ b/content/test/data/accessibility/html/base-expected-mac.txt
@@ -0,0 +1 @@
+#<skip - Not Mapped>
diff --git a/content/test/data/accessibility/html/base-expected-win.txt b/content/test/data/accessibility/html/base-expected-win.txt
new file mode 100644
index 0000000..4ce8140
--- /dev/null
+++ b/content/test/data/accessibility/html/base-expected-win.txt
@@ -0,0 +1 @@
+#<skip - Not Mapped>
diff --git a/content/test/data/accessibility/html/base.html b/content/test/data/accessibility/html/base.html
new file mode 100644
index 0000000..d53d9cb
--- /dev/null
+++ b/content/test/data/accessibility/html/base.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+<base href="http://www.chromium.org/" target="_blank">
+</head>
+<body>
+</body>
+</html>
diff --git a/content/test/data/accessibility/html/input-hidden-expected-android.txt b/content/test/data/accessibility/html/input-hidden-expected-android.txt
new file mode 100644
index 0000000..d7df040
--- /dev/null
+++ b/content/test/data/accessibility/html/input-hidden-expected-android.txt
@@ -0,0 +1 @@
+#<skip - Do not expose this object>
diff --git a/content/test/data/accessibility/html/input-hidden-expected-mac.txt b/content/test/data/accessibility/html/input-hidden-expected-mac.txt
new file mode 100644
index 0000000..d7df040
--- /dev/null
+++ b/content/test/data/accessibility/html/input-hidden-expected-mac.txt
@@ -0,0 +1 @@
+#<skip - Do not expose this object>
diff --git a/content/test/data/accessibility/html/input-hidden-expected-win.txt b/content/test/data/accessibility/html/input-hidden-expected-win.txt
new file mode 100644
index 0000000..d7df040
--- /dev/null
+++ b/content/test/data/accessibility/html/input-hidden-expected-win.txt
@@ -0,0 +1 @@
+#<skip - Do not expose this object>
diff --git a/content/test/data/accessibility/html/input-hidden.html b/content/test/data/accessibility/html/input-hidden.html
new file mode 100644
index 0000000..eec394ce
--- /dev/null
+++ b/content/test/data/accessibility/html/input-hidden.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+    <body>
+        <input type="hidden">
+    </body>
+</html>
diff --git a/content/test/data/accessibility/html/input-password-expected-android.txt b/content/test/data/accessibility/html/input-password-expected-android.txt
new file mode 100644
index 0000000..1825c38
--- /dev/null
+++ b/content/test/data/accessibility/html/input-password-expected-android.txt
@@ -0,0 +1,3 @@
+android.webkit.WebView focusable focused scrollable
+    android.view.View
+        android.widget.EditText clickable editable_text focusable password input_type=225
diff --git a/content/test/data/accessibility/html/input-password-expected-mac.txt b/content/test/data/accessibility/html/input-password-expected-mac.txt
new file mode 100644
index 0000000..4a6d2d4
--- /dev/null
+++ b/content/test/data/accessibility/html/input-password-expected-mac.txt
@@ -0,0 +1,3 @@
+AXWebArea AXRoleDescription='HTML content'
+    AXGroup AXRoleDescription='group'
+        AXTextField AXSubrole=AXSecureTextField AXRoleDescription='text field'
diff --git a/content/test/data/accessibility/html/input-password-expected-win.txt b/content/test/data/accessibility/html/input-password-expected-win.txt
new file mode 100644
index 0000000..f98f047
--- /dev/null
+++ b/content/test/data/accessibility/html/input-password-expected-win.txt
@@ -0,0 +1,3 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
+    IA2_ROLE_SECTION
+        ROLE_SYSTEM_TEXT FOCUSABLE PROTECTED IA2_STATE_EDITABLE IA2_STATE_SELECTABLE_TEXT IA2_STATE_SINGLE_LINE text-input-type:password
diff --git a/content/test/data/accessibility/html/input-password.html b/content/test/data/accessibility/html/input-password.html
new file mode 100644
index 0000000..e6d23eb
--- /dev/null
+++ b/content/test/data/accessibility/html/input-password.html
@@ -0,0 +1,13 @@
+<!--
+@MAC-ALLOW:AXRole*
+@MAC-ALLOW:AXSubrole*
+@WIN-ALLOW:PROTECTED
+@WIN-ALLOW:IA2_STATE*
+@WIN-ALLOW:text-input-type*
+-->
+<!DOCTYPE html>
+<html>
+<body>
+  <input type="password">
+</body>
+</html>
diff --git a/content/test/data/accessibility/html/small-expected-android.txt b/content/test/data/accessibility/html/small-expected-android.txt
new file mode 100644
index 0000000..5d7ed88
--- /dev/null
+++ b/content/test/data/accessibility/html/small-expected-android.txt
@@ -0,0 +1 @@
+#<skip - Doesn't have an accessible>
diff --git a/content/test/data/accessibility/html/small-expected-mac.txt b/content/test/data/accessibility/html/small-expected-mac.txt
new file mode 100644
index 0000000..312c6da
--- /dev/null
+++ b/content/test/data/accessibility/html/small-expected-mac.txt
@@ -0,0 +1,4 @@
+AXWebArea
+    AXGroup
+        AXStaticText AXValue='Chromium'
+        AXStaticText AXValue='open source project'
diff --git a/content/test/data/accessibility/html/small-expected-win.txt b/content/test/data/accessibility/html/small-expected-win.txt
new file mode 100644
index 0000000..5d7ed88
--- /dev/null
+++ b/content/test/data/accessibility/html/small-expected-win.txt
@@ -0,0 +1 @@
+#<skip - Doesn't have an accessible>
diff --git a/content/test/data/accessibility/html/small.html b/content/test/data/accessibility/html/small.html
new file mode 100644
index 0000000..acdcb89
--- /dev/null
+++ b/content/test/data/accessibility/html/small.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+  <p>Chromium<small>open source project</small></p>
+
+</body>
+</html>
diff --git a/content/test/data/frame_tree/page_with_one_frame.html b/content/test/data/frame_tree/page_with_one_frame.html
index ecf5140..0f121d9 100644
--- a/content/test/data/frame_tree/page_with_one_frame.html
+++ b/content/test/data/frame_tree/page_with_one_frame.html
@@ -2,7 +2,7 @@
 <html>
 <head></head>
 <body>
-  This page has one iframe without src.
-  <iframe></iframe>
+  This page has one cross-site iframe.
+  <iframe src="/cross-site/baz.com/title1.html"></iframe>
 </body>
 </html>
diff --git a/content/test/data/frame_tree/page_with_two_frames.html b/content/test/data/frame_tree/page_with_two_frames.html
index a4bd921..3313ce4 100644
--- a/content/test/data/frame_tree/page_with_two_frames.html
+++ b/content/test/data/frame_tree/page_with_two_frames.html
@@ -2,9 +2,9 @@
 <head>
 </head>
 <body>
-  This page has two iframes without src.
-  <iframe></iframe>
-  <iframe></iframe>
+  This page has two iframes: one is cross-site, the other is same-site.
+  <iframe src="/cross-site/bar.com/title1.html"></iframe>
+  <iframe src="../title1.html"></iframe>
 </body>
 </html>
 
diff --git a/content/test/data/frame_tree/page_with_two_frames_nested.html b/content/test/data/frame_tree/page_with_two_frames_nested.html
new file mode 100644
index 0000000..5b556c5
--- /dev/null
+++ b/content/test/data/frame_tree/page_with_two_frames_nested.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<head>
+</head>
+<body>
+  This page has two iframes: one is cross-site, the other is same-site.
+  The cross-site frame also loads a cross-site page in it.
+  <iframe src="/cross-site/bar.com/frame_tree/page_with_one_frame.html"></iframe>
+  <iframe src="../title1.html"></iframe>
+</body>
+</html>
+
diff --git a/content/test/data/media/OWNERS b/content/test/data/media/OWNERS
index fe807ce8..61ca624 100644
--- a/content/test/data/media/OWNERS
+++ b/content/test/data/media/OWNERS
@@ -5,5 +5,4 @@
 sandersd@chromium.org
 scherkus@chromium.org
 tommi@chromium.org
-vrk@chromium.org
 xhwang@chromium.org
diff --git a/content/test/data/service_worker/fetch_event_blob.js b/content/test/data/service_worker/fetch_event_blob.js
new file mode 100644
index 0000000..8f15e1f
--- /dev/null
+++ b/content/test/data/service_worker/fetch_event_blob.js
@@ -0,0 +1,9 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+this.onfetch = function(event) {
+    var blob = new Blob(['<title>Title</title>']);
+    var response = new Response(blob);
+    event.respondWith(response);
+};
diff --git a/content/test/data/service_worker/fetch_event_blob.js.mock-http-headers b/content/test/data/service_worker/fetch_event_blob.js.mock-http-headers
new file mode 100644
index 0000000..c9a3625
--- /dev/null
+++ b/content/test/data/service_worker/fetch_event_blob.js.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Content-Type: text/javascript
diff --git a/content/test/fake_compositor_dependencies.cc b/content/test/fake_compositor_dependencies.cc
index 1f090a0..e33b7ef1 100644
--- a/content/test/fake_compositor_dependencies.cc
+++ b/content/test/fake_compositor_dependencies.cc
@@ -26,6 +26,10 @@
   return false;
 }
 
+bool FakeCompositorDependencies::IsThreadedGpuRasterizationEnabled() {
+  return false;
+}
+
 int FakeCompositorDependencies::GetGpuRasterizationMSAASampleCount() {
   return 0;
 }
diff --git a/content/test/fake_compositor_dependencies.h b/content/test/fake_compositor_dependencies.h
index d31c307..8e23ba4 100644
--- a/content/test/fake_compositor_dependencies.h
+++ b/content/test/fake_compositor_dependencies.h
@@ -20,6 +20,7 @@
   bool IsImplSidePaintingEnabled() override;
   bool IsGpuRasterizationForced() override;
   bool IsGpuRasterizationEnabled() override;
+  bool IsThreadedGpuRasterizationEnabled() override;
   int GetGpuRasterizationMSAASampleCount() override;
   bool IsLcdTextEnabled() override;
   bool IsDistanceFieldTextEnabled() override;
diff --git a/content/test/gpu/gpu_tests/trace_test.py b/content/test/gpu/gpu_tests/trace_test.py
index fb4de0f..df9e5b7 100644
--- a/content/test/gpu/gpu_tests/trace_test.py
+++ b/content/test/gpu/gpu_tests/trace_test.py
@@ -8,11 +8,12 @@
 from telemetry.page import page_test
 from telemetry.core.platform import tracing_category_filter
 from telemetry.core.platform import tracing_options
-from telemetry.timeline import model
+from telemetry.timeline import model as model_module
 
 TOPLEVEL_GL_CATEGORY = 'gpu_toplevel'
-TOPLEVEL_CATEGORIES = ['disabled-by-default-gpu.device',
-                       'disabled-by-default-gpu.service']
+TOPLEVEL_SERVICE_CATEGORY = 'disabled-by-default-gpu.service'
+TOPLEVEL_DEVICE_CATEGORY = 'disabled-by-default-gpu.device'
+TOPLEVEL_CATEGORIES = [TOPLEVEL_SERVICE_CATEGORY, TOPLEVEL_DEVICE_CATEGORY]
 
 test_harness_script = r"""
   var domAutomationController = {};
@@ -28,19 +29,24 @@
   window.domAutomationController = domAutomationController;
 """
 
-class _TraceValidator(page_test.PageTest):
+
+class _TraceValidatorBase(page_test.PageTest):
+  def GetCategoryName(self):
+    raise NotImplementedError("GetCategoryName() Not implemented!")
+
   def ValidateAndMeasurePage(self, page, tab, results):
     timeline_data = tab.browser.platform.tracing_controller.Stop()
-    timeline_model = model.TimelineModel(timeline_data)
+    timeline_model = model_module.TimelineModel(timeline_data)
 
-    categories_set = set(TOPLEVEL_CATEGORIES)
-    for event in timeline_model.IterAllEvents():
-      if event.args.get('gl_category', None) == TOPLEVEL_GL_CATEGORY:
-        categories_set.discard(event.category)
-      if not categories_set:
+    category_name = self.GetCategoryName()
+    event_iter = timeline_model.IterAllEvents(
+        event_type_predicate=model_module.IsSliceOrAsyncSlice)
+    for event in event_iter:
+      if (event.args.get('gl_category', None) == TOPLEVEL_GL_CATEGORY and
+          event.category == category_name):
         break
     else:
-      raise page_test.Failure(self._FormatException(sorted(categories_set)))
+      raise page_test.Failure(self._FormatException(category_name))
 
   def CustomizeBrowserOptions(self, options):
     options.AppendExtraBrowserArgs('--enable-logging')
@@ -52,11 +58,32 @@
     options.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.Start(options, cat_filter, 60)
 
-  def _FormatException(self, categories):
-    return 'Trace markers for GPU categories were not found: %s' % categories
+  def _FormatException(self, category):
+    return 'Trace markers for GPU category was not found: %s' % category
 
-class TraceTest(benchmark.Benchmark):
-  """Tests GPU traces"""
+
+class _TraceValidator(_TraceValidatorBase):
+  def GetCategoryName(self):
+    return TOPLEVEL_SERVICE_CATEGORY
+
+
+class _DeviceTraceValidator(_TraceValidatorBase):
+  def GetCategoryName(self):
+    return TOPLEVEL_DEVICE_CATEGORY
+
+
+class _TraceTestBase(benchmark.Benchmark):
+  """Base class for the trace tests."""
+  def CreatePageSet(self, options):
+    # Utilize pixel tests page set as a set of simple pages to load.
+    page_set = page_sets.PixelTestsPageSet()
+    for page in page_set.pages:
+      page.script_to_evaluate_on_commit = test_harness_script
+    return page_set
+
+
+class TraceTest(_TraceTestBase):
+  """Tests GPU traces are plumbed through properly."""
   test = _TraceValidator
 
   @classmethod
@@ -66,9 +93,14 @@
   def CreateExpectations(self):
     return trace_test_expectations.TraceTestExpectations()
 
-  def CreatePageSet(self, options):
-    # Utilize pixel tests page set as a set of simple pages to load.
-    page_set = page_sets.PixelTestsPageSet()
-    for page in page_set.pages:
-      page.script_to_evaluate_on_commit = test_harness_script
-    return page_set
+
+class DeviceTraceTest(_TraceTestBase):
+  """Tests GPU Device traces show up on devices that support it."""
+  test = _DeviceTraceValidator
+
+  @classmethod
+  def Name(cls):
+    return 'device_trace_test'
+
+  def CreateExpectations(self):
+    return trace_test_expectations.DeviceTraceTestExpectations()
diff --git a/content/test/gpu/gpu_tests/trace_test_expectations.py b/content/test/gpu/gpu_tests/trace_test_expectations.py
index 24f0cc75..f6c35b65 100644
--- a/content/test/gpu/gpu_tests/trace_test_expectations.py
+++ b/content/test/gpu/gpu_tests/trace_test_expectations.py
@@ -12,6 +12,9 @@
     # self.Fail('Pixel.Canvas2DRedBox',
     #     ['mac', 'amd', ('nvidia', 0x1234)], bug=123)
 
-    # Temporarily skip everything while bot recipes are being put in place.
-    self.Skip('*')
     pass
+
+class DeviceTraceTestExpectations(GpuTestExpectations):
+  def SetExpectations(self):
+    # Device traces are not supported on all machines.
+    self.Skip('*')
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index 67693578..f71fc76 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -87,7 +87,7 @@
 
   // RenderWidgetHostViewBase implementation.
   void InitAsPopup(RenderWidgetHostView* parent_host_view,
-                   const gfx::Rect& pos) override {}
+                   const gfx::Rect& bounds) override {}
   void InitAsFullscreen(RenderWidgetHostView* reference_host_view) override {}
   void MovePluginWindows(const std::vector<WebPluginGeometry>& moves) override {
   }
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 3009f5d..be20dcc 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -256,12 +256,12 @@
 
 void TestWebContents::ShowCreatedWindow(int route_id,
                                         WindowOpenDisposition disposition,
-                                        const gfx::Rect& initial_pos,
+                                        const gfx::Rect& initial_rect,
                                         bool user_gesture) {
 }
 
 void TestWebContents::ShowCreatedWidget(int route_id,
-                                        const gfx::Rect& initial_pos) {
+                                        const gfx::Rect& initial_rect) {
 }
 
 void TestWebContents::ShowCreatedFullscreenWidget(int route_id) {
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index 8e3c2b5..92f8db3 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -112,9 +112,9 @@
   void CreateNewFullscreenWidget(int render_process_id, int route_id) override;
   void ShowCreatedWindow(int route_id,
                          WindowOpenDisposition disposition,
-                         const gfx::Rect& initial_pos,
+                         const gfx::Rect& initial_rect,
                          bool user_gesture) override;
-  void ShowCreatedWidget(int route_id, const gfx::Rect& initial_pos) override;
+  void ShowCreatedWidget(int route_id, const gfx::Rect& initial_rect) override;
   void ShowCreatedFullscreenWidget(int route_id) override;
 
   RenderViewHostDelegateView* delegate_view_override_;
diff --git a/content/test/web_layer_tree_view_impl_for_testing.h b/content/test/web_layer_tree_view_impl_for_testing.h
index 9dabf4c3..904c985 100644
--- a/content/test/web_layer_tree_view_impl_for_testing.h
+++ b/content/test/web_layer_tree_view_impl_for_testing.h
@@ -65,7 +65,7 @@
   virtual void clearSelection() override;
 
   // cc::LayerTreeHostClient implementation.
-  void WillBeginMainFrame(int frame_id) override {}
+  void WillBeginMainFrame() override {}
   void DidBeginMainFrame() override {}
   void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
   void Layout() override;
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc
index 32f9814..26af2b1 100644
--- a/content/utility/utility_thread_impl.cc
+++ b/content/utility/utility_thread_impl.cc
@@ -40,7 +40,7 @@
 }
 
 UtilityThreadImpl::UtilityThreadImpl(const std::string& channel_name)
-    : ChildThread(Options(channel_name, false)),
+    : ChildThreadImpl(Options(channel_name, false)),
       single_process_(true) {
   Init();
 }
@@ -49,16 +49,12 @@
 }
 
 void UtilityThreadImpl::Shutdown() {
-  ChildThread::Shutdown();
+  ChildThreadImpl::Shutdown();
 
   if (!single_process_)
     blink::shutdown();
 }
 
-bool UtilityThreadImpl::Send(IPC::Message* msg) {
-  return ChildThread::Send(msg);
-}
-
 void UtilityThreadImpl::ReleaseProcessIfNeeded() {
   if (batch_mode_)
     return;
@@ -74,18 +70,6 @@
   }
 }
 
-#if defined(OS_WIN)
-
-void UtilityThreadImpl::PreCacheFont(const LOGFONT& log_font) {
-  Send(new ChildProcessHostMsg_PreCacheFont(log_font));
-}
-
-void UtilityThreadImpl::ReleaseCachedFonts() {
-  Send(new ChildProcessHostMsg_ReleaseCachedFonts());
-}
-
-#endif  // OS_WIN
-
 void UtilityThreadImpl::Init() {
   batch_mode_ = false;
   ChildProcess::current()->AddRefProcess();
diff --git a/content/utility/utility_thread_impl.h b/content/utility/utility_thread_impl.h
index 5b186fc..043aea9 100644
--- a/content/utility/utility_thread_impl.h
+++ b/content/utility/utility_thread_impl.h
@@ -10,7 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "content/child/child_thread.h"
+#include "content/child/child_thread_impl.h"
 #include "content/common/content_export.h"
 #include "content/public/utility/utility_thread.h"
 
@@ -21,9 +21,15 @@
 namespace content {
 class BlinkPlatformImpl;
 
+#if defined(COMPILER_MSVC)
+// See explanation for other RenderViewHostImpl which is the same issue.
+#pragma warning(push)
+#pragma warning(disable: 4250)
+#endif
+
 // This class represents the background thread where the utility task runs.
 class UtilityThreadImpl : public UtilityThread,
-                          public ChildThread {
+                          public ChildThreadImpl {
  public:
   UtilityThreadImpl();
   // Constructor that's used when running in single process mode.
@@ -31,12 +37,7 @@
   ~UtilityThreadImpl() override;
   void Shutdown() override;
 
-  bool Send(IPC::Message* msg) override;
   void ReleaseProcessIfNeeded() override;
-#if defined(OS_WIN)
-  virtual void PreCacheFont(const LOGFONT& log_font) override;
-  virtual void ReleaseCachedFonts() override;
-#endif
 
  private:
   void Init();
@@ -63,6 +64,10 @@
   DISALLOW_COPY_AND_ASSIGN(UtilityThreadImpl);
 };
 
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
 }  // namespace content
 
 #endif  // CONTENT_UTILITY_UTILITY_THREAD_IMPL_H_
diff --git a/crypto/openssl_util.cc b/crypto/openssl_util.cc
index f41b55a..8ea12323 100644
--- a/crypto/openssl_util.cc
+++ b/crypto/openssl_util.cc
@@ -48,6 +48,18 @@
  private:
   friend struct DefaultSingletonTraits<OpenSSLInitSingleton>;
   OpenSSLInitSingleton() {
+#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
+    const bool has_neon =
+        (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
+    // CRYPTO_set_NEON_capable is called before |SSL_library_init| because this
+    // stops BoringSSL from probing for NEON support via SIGILL in the case
+    // that getauxval isn't present.
+    CRYPTO_set_NEON_capable(has_neon);
+    // See https://code.google.com/p/chromium/issues/detail?id=341598
+    base::CPU cpu;
+    CRYPTO_set_NEON_functional(!cpu.has_broken_neon());
+#endif
+
     SSL_load_error_strings();
     SSL_library_init();
     int num_locks = CRYPTO_num_locks();
@@ -56,16 +68,6 @@
       locks_.push_back(new base::Lock());
     CRYPTO_set_locking_callback(LockingCallback);
     CRYPTO_THREADID_set_callback(CurrentThreadId);
-
-#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
-    const bool has_neon =
-        (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
-    if (has_neon)
-      CRYPTO_set_NEON_capable(1);
-    // See https://code.google.com/p/chromium/issues/detail?id=341598
-    base::CPU cpu;
-    CRYPTO_set_NEON_functional(!cpu.has_broken_neon());
-#endif
   }
 
   ~OpenSSLInitSingleton() {
diff --git a/device/serial/data_receiver.cc b/device/serial/data_receiver.cc
index 2f238e3..fdc23caa 100644
--- a/device/serial/data_receiver.cc
+++ b/device/serial/data_receiver.cc
@@ -107,19 +107,16 @@
   bool dispatched;
 };
 
-DataReceiver::DataReceiver(
-    mojo::InterfacePtr<serial::DataSource> source,
-    mojo::InterfaceRequest<serial::DataSourceClient> client,
-    uint32_t buffer_size,
-    int32_t fatal_error_value)
+DataReceiver::DataReceiver(mojo::InterfacePtr<serial::DataSource> source,
+                           uint32_t buffer_size,
+                           int32_t fatal_error_value)
     : source_(source.Pass()),
-      client_(this, client.Pass()),
       fatal_error_value_(fatal_error_value),
       shut_down_(false),
       weak_factory_(this) {
+  source_.set_client(this);
   source_.set_error_handler(this);
   source_->Init(buffer_size);
-  client_.set_error_handler(this);
 }
 
 bool DataReceiver::Receive(const ReceiveDataCallback& callback,
diff --git a/device/serial/data_receiver.h b/device/serial/data_receiver.h
index 95be6402..942bb5c 100644
--- a/device/serial/data_receiver.h
+++ b/device/serial/data_receiver.h
@@ -29,7 +29,6 @@
   // size of |buffer_size|, with connection errors reported as
   // |fatal_error_value|.
   DataReceiver(mojo::InterfacePtr<serial::DataSource> source,
-               mojo::InterfaceRequest<serial::DataSourceClient> client,
                uint32_t buffer_size,
                int32_t fatal_error_value);
 
@@ -73,7 +72,6 @@
 
   // The control connection to the data source.
   mojo::InterfacePtr<serial::DataSource> source_;
-  mojo::Binding<serial::DataSourceClient> client_;
 
   // The error value to report in the event of a fatal error.
   const int32_t fatal_error_value_;
diff --git a/device/serial/data_sender.cc b/device/serial/data_sender.cc
index bea8eb8..18b1a43e 100644
--- a/device/serial/data_sender.cc
+++ b/device/serial/data_sender.cc
@@ -62,17 +62,15 @@
 };
 
 DataSender::DataSender(mojo::InterfacePtr<serial::DataSink> sink,
-                       mojo::InterfaceRequest<serial::DataSinkClient> client,
                        uint32_t buffer_size,
                        int32_t fatal_error_value)
     : sink_(sink.Pass()),
-      client_(this, client.Pass()),
       fatal_error_value_(fatal_error_value),
       available_buffer_capacity_(buffer_size),
       shut_down_(false) {
   sink_.set_error_handler(this);
+  sink_.set_client(this);
   sink_->Init(buffer_size);
-  client_.set_error_handler(this);
 }
 
 DataSender::~DataSender() {
diff --git a/device/serial/data_sender.h b/device/serial/data_sender.h
index 0b5ea09a..f4db8bc 100644
--- a/device/serial/data_sender.h
+++ b/device/serial/data_sender.h
@@ -27,7 +27,6 @@
   // Constructs a DataSender to send data to |sink|, using a buffer size of
   // |buffer_size|, with connection errors reported as |fatal_error_value|.
   DataSender(mojo::InterfacePtr<serial::DataSink> sink,
-             mojo::InterfaceRequest<serial::DataSinkClient> client,
              uint32_t buffer_size,
              int32_t fatal_error_value);
 
@@ -74,7 +73,6 @@
 
   // The control connection to the data sink.
   mojo::InterfacePtr<serial::DataSink> sink_;
-  mojo::Binding<serial::DataSinkClient> client_;
 
   // The error value to report in the event of a fatal error.
   const int32_t fatal_error_value_;
diff --git a/device/serial/data_sink_receiver.cc b/device/serial/data_sink_receiver.cc
index 18dd5690..170f8b2c 100644
--- a/device/serial/data_sink_receiver.cc
+++ b/device/serial/data_sink_receiver.cc
@@ -61,15 +61,10 @@
   uint32_t offset_;
 };
 
-DataSinkReceiver::DataSinkReceiver(
-    mojo::InterfaceRequest<serial::DataSink> request,
-    mojo::InterfacePtr<serial::DataSinkClient> client,
-    const ReadyCallback& ready_callback,
-    const CancelCallback& cancel_callback,
-    const ErrorCallback& error_callback)
-    : binding_(this, request.Pass()),
-      client_(client.Pass()),
-      ready_callback_(ready_callback),
+DataSinkReceiver::DataSinkReceiver(const ReadyCallback& ready_callback,
+                                   const CancelCallback& cancel_callback,
+                                   const ErrorCallback& error_callback)
+    : ready_callback_(ready_callback),
       cancel_callback_(cancel_callback),
       error_callback_(error_callback),
       flush_pending_(false),
@@ -78,8 +73,6 @@
       available_buffer_capacity_(0),
       shut_down_(false),
       weak_factory_(this) {
-  binding_.set_error_handler(this);
-  client_.set_error_handler(this);
 }
 
 void DataSinkReceiver::ShutDown() {
@@ -158,7 +151,7 @@
 void DataSinkReceiver::Done(uint32_t bytes_read) {
   if (!DoneInternal(bytes_read))
     return;
-  client_->ReportBytesSent(bytes_read);
+  client()->ReportBytesSent(bytes_read);
   if (!pending_data_buffers_.empty()) {
     base::MessageLoop::current()->PostTask(
         FROM_HERE,
@@ -191,8 +184,9 @@
   // When we encounter an error, we must discard the data from any send buffers
   // transmitted by the DataSinkClient before it receives this error.
   flush_pending_ = true;
-  client_->ReportBytesSentAndError(
-      bytes_read, error,
+  client()->ReportBytesSentAndError(
+      bytes_read,
+      error,
       base::Bind(&DataSinkReceiver::DoFlush, weak_factory_.GetWeakPtr()));
 }
 
diff --git a/device/serial/data_sink_receiver.h b/device/serial/data_sink_receiver.h
index 0709f90..2126cdd9 100644
--- a/device/serial/data_sink_receiver.h
+++ b/device/serial/data_sink_receiver.h
@@ -18,8 +18,7 @@
 namespace device {
 
 class DataSinkReceiver : public base::RefCounted<DataSinkReceiver>,
-                         public serial::DataSink,
-                         public mojo::ErrorHandler {
+                         public mojo::InterfaceImpl<serial::DataSink> {
  public:
   typedef base::Callback<void(scoped_ptr<ReadOnlyBuffer>)> ReadyCallback;
   typedef base::Callback<void(int32_t error)> CancelCallback;
@@ -32,9 +31,7 @@
   // and the DataSinkReceiver will act as if ShutDown() had been called. If
   // |cancel_callback| is valid, it will be called when the DataSinkClient
   // requests cancellation of the in-progress read.
-  DataSinkReceiver(mojo::InterfaceRequest<serial::DataSink> request,
-                   mojo::InterfacePtr<serial::DataSinkClient> client,
-                   const ReadyCallback& ready_callback,
+  DataSinkReceiver(const ReadyCallback& ready_callback,
                    const CancelCallback& cancel_callback,
                    const ErrorCallback& error_callback);
 
@@ -78,9 +75,6 @@
   // Reports a fatal error to the client and shuts down.
   void DispatchFatalError();
 
-  mojo::Binding<serial::DataSink> binding_;
-  mojo::InterfacePtr<serial::DataSinkClient> client_;
-
   // The callback to call when there is data ready to read.
   const ReadyCallback ready_callback_;
 
diff --git a/device/serial/data_sink_unittest.cc b/device/serial/data_sink_unittest.cc
index 4108692b..24843623 100644
--- a/device/serial/data_sink_unittest.cc
+++ b/device/serial/data_sink_unittest.cc
@@ -38,16 +38,13 @@
   void SetUp() override {
     message_loop_.reset(new base::MessageLoop);
     mojo::InterfacePtr<serial::DataSink> sink_handle;
-    mojo::InterfacePtr<serial::DataSinkClient> sink_client_handle;
-    mojo::InterfaceRequest<serial::DataSinkClient> sink_client_request =
-        mojo::GetProxy(&sink_client_handle);
-    sink_receiver_ = new DataSinkReceiver(
-        mojo::GetProxy(&sink_handle), sink_client_handle.Pass(),
-        base::Bind(&DataSinkTest::OnDataToRead, base::Unretained(this)),
-        base::Bind(&DataSinkTest::OnCancel, base::Unretained(this)),
-        base::Bind(&DataSinkTest::OnError, base::Unretained(this)));
-    sender_.reset(new DataSender(sink_handle.Pass(), sink_client_request.Pass(),
-                                 kBufferSize, kFatalError));
+    sink_receiver_ = mojo::WeakBindToProxy(
+        new DataSinkReceiver(
+            base::Bind(&DataSinkTest::OnDataToRead, base::Unretained(this)),
+            base::Bind(&DataSinkTest::OnCancel, base::Unretained(this)),
+            base::Bind(&DataSinkTest::OnError, base::Unretained(this))),
+        &sink_handle);
+    sender_.reset(new DataSender(sink_handle.Pass(), kBufferSize, kFatalError));
   }
 
   void TearDown() override {
diff --git a/device/serial/data_source_sender.cc b/device/serial/data_source_sender.cc
index 97029dda..f9cc4f1 100644
--- a/device/serial/data_source_sender.cc
+++ b/device/serial/data_source_sender.cc
@@ -71,22 +71,15 @@
   uint32_t buffer_size_;
 };
 
-DataSourceSender::DataSourceSender(
-    mojo::InterfaceRequest<serial::DataSource> source,
-    mojo::InterfacePtr<serial::DataSourceClient> client,
-    const ReadyCallback& ready_callback,
-    const ErrorCallback& error_callback)
-    : binding_(this, source.Pass()),
-      client_(client.Pass()),
-      ready_callback_(ready_callback),
+DataSourceSender::DataSourceSender(const ReadyCallback& ready_callback,
+                                   const ErrorCallback& error_callback)
+    : ready_callback_(ready_callback),
       error_callback_(error_callback),
       available_buffer_capacity_(0),
       paused_(false),
       shut_down_(false),
       weak_factory_(this) {
   DCHECK(!ready_callback.is_null() && !error_callback.is_null());
-  binding_.set_error_handler(this);
-  client_.set_error_handler(this);
 }
 
 void DataSourceSender::ShutDown() {
@@ -145,7 +138,7 @@
                                      int32_t error) {
   DoneInternal(data);
   if (!shut_down_)
-    client_->OnError(error);
+    client()->OnError(error);
   paused_ = true;
   // We don't call GetMoreData here so we don't send any additional data until
   // Resume() is called.
@@ -160,7 +153,7 @@
   if (!data.empty()) {
     mojo::Array<uint8_t> data_to_send(data.size());
     std::copy(data.begin(), data.end(), &data_to_send[0]);
-    client_->OnData(data_to_send.Pass());
+    client()->OnData(data_to_send.Pass());
   }
   pending_send_.reset();
 }
diff --git a/device/serial/data_source_sender.h b/device/serial/data_source_sender.h
index a8c2c63..3a90240f 100644
--- a/device/serial/data_source_sender.h
+++ b/device/serial/data_source_sender.h
@@ -19,8 +19,7 @@
 // A DataSourceSender is an interface between a source of data and a
 // DataSourceClient.
 class DataSourceSender : public base::RefCounted<DataSourceSender>,
-                         public serial::DataSource,
-                         public mojo::ErrorHandler {
+                         public mojo::InterfaceImpl<serial::DataSource> {
  public:
   typedef base::Callback<void(scoped_ptr<WritableBuffer>)> ReadyCallback;
   typedef base::Callback<void()> ErrorCallback;
@@ -30,9 +29,7 @@
   // |ready_callback| will not be called again until the previous WritableBuffer
   // is destroyed. If a connection error occurs, |error_callback| will be
   // called and the DataSourceSender will act as if ShutDown() had been called.
-  DataSourceSender(mojo::InterfaceRequest<serial::DataSource> source,
-                   mojo::InterfacePtr<serial::DataSourceClient> client,
-                   const ReadyCallback& ready_callback,
+  DataSourceSender(const ReadyCallback& ready_callback,
                    const ErrorCallback& error_callback);
 
   // Shuts down this DataSourceSender. After shut down, |ready_callback| and
@@ -68,9 +65,6 @@
   // Reports a fatal error to the client and shuts down.
   void DispatchFatalError();
 
-  mojo::Binding<serial::DataSource> binding_;
-  mojo::InterfacePtr<serial::DataSourceClient> client_;
-
   // The callback to call when the client is ready for more data.
   ReadyCallback ready_callback_;
 
diff --git a/device/serial/data_source_unittest.cc b/device/serial/data_source_unittest.cc
index b725f35..71dfa81 100644
--- a/device/serial/data_source_unittest.cc
+++ b/device/serial/data_source_unittest.cc
@@ -31,18 +31,12 @@
   void SetUp() override {
     message_loop_.reset(new base::MessageLoop);
     mojo::InterfacePtr<serial::DataSource> source_sender_handle;
-    mojo::InterfacePtr<serial::DataSourceClient> source_sender_client_handle;
-    mojo::InterfaceRequest<serial::DataSourceClient>
-        source_sender_client_request =
-            mojo::GetProxy(&source_sender_client_handle);
-    source_sender_ = new DataSourceSender(
-        mojo::GetProxy(&source_sender_handle),
-        source_sender_client_handle.Pass(),
-        base::Bind(&DataSourceTest::CanWriteData, base::Unretained(this)),
-        base::Bind(&DataSourceTest::OnError, base::Unretained(this)));
-    receiver_ =
-        new DataReceiver(source_sender_handle.Pass(),
-                         source_sender_client_request.Pass(), 100, kFatalError);
+    source_sender_ = mojo::WeakBindToProxy(
+        new DataSourceSender(
+            base::Bind(&DataSourceTest::CanWriteData, base::Unretained(this)),
+            base::Bind(&DataSourceTest::OnError, base::Unretained(this))),
+        &source_sender_handle);
+    receiver_ = new DataReceiver(source_sender_handle.Pass(), 100, kFatalError);
   }
 
   void TearDown() override {
diff --git a/device/serial/data_stream.mojom b/device/serial/data_stream.mojom
index e5478067..a288eb2 100644
--- a/device/serial/data_stream.mojom
+++ b/device/serial/data_stream.mojom
@@ -4,6 +4,7 @@
 
 module device.serial;
 
+[Client=DataSourceClient]
 interface DataSource {
   // Initializes this DataSource with the amount of data its client will
   // buffer.
@@ -26,6 +27,7 @@
   OnData(array<uint8> data);
 };
 
+[Client=DataSinkClient]
 interface DataSink {
   // Initializes this DataSink with the amount of data it is expected to
   // buffer.
diff --git a/device/serial/data_stream_serialization.mojom b/device/serial/data_stream_serialization.mojom
index de580d3..259be28 100644
--- a/device/serial/data_stream_serialization.mojom
+++ b/device/serial/data_stream_serialization.mojom
@@ -10,8 +10,6 @@
 struct SerializedDataSender {
   // The control channel to the DataSink to which this DataSender sends data.
   DataSink sink;
-  // DataSinkClient&
-  handle<message_pipe> sink_client;
 
   // The error to report for sends in progress when a fatal error occurs.
   int32 fatal_error_value;
@@ -34,8 +32,6 @@
   // The control channel to the DataSource from which this DataReceiver receives
   // data.
   DataSource source;
-  // DataSourceClient&
-  handle<message_pipe> source_client;
 
   // The error to report for a receive in progress when a fatal error occurs.
   int32 fatal_error_value;
diff --git a/device/serial/serial.mojom b/device/serial/serial.mojom
index 877d1e2..6714a946 100644
--- a/device/serial/serial.mojom
+++ b/device/serial/serial.mojom
@@ -94,9 +94,7 @@
           ConnectionOptions? options,
           Connection& connection,
           DataSink& sink,
-          DataSinkClient sink_client,
-          DataSource& source,
-          DataSourceClient source_client);
+          DataSource& source);
 };
 
 interface Connection {
diff --git a/device/serial/serial_connection.cc b/device/serial/serial_connection.cc
index 04cccbe5..0d3e4171 100644
--- a/device/serial/serial_connection.cc
+++ b/device/serial/serial_connection.cc
@@ -15,19 +15,20 @@
 SerialConnection::SerialConnection(
     scoped_refptr<SerialIoHandler> io_handler,
     mojo::InterfaceRequest<serial::DataSink> sink,
-    mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-    mojo::InterfaceRequest<serial::DataSource> source,
-    mojo::InterfacePtr<serial::DataSourceClient> source_client)
+    mojo::InterfaceRequest<serial::DataSource> source)
     : io_handler_(io_handler) {
-  receiver_ = new DataSinkReceiver(
-      sink.Pass(), sink_client.Pass(),
-      base::Bind(&SerialConnection::OnSendPipeReady, base::Unretained(this)),
-      base::Bind(&SerialConnection::OnSendCancelled, base::Unretained(this)),
-      base::Bind(base::DoNothing));
-  sender_ = new DataSourceSender(
-      source.Pass(), source_client.Pass(),
-      base::Bind(&SerialConnection::OnReceivePipeReady, base::Unretained(this)),
-      base::Bind(base::DoNothing));
+  receiver_ = mojo::WeakBindToRequest(
+      new DataSinkReceiver(base::Bind(&SerialConnection::OnSendPipeReady,
+                                      base::Unretained(this)),
+                           base::Bind(&SerialConnection::OnSendCancelled,
+                                      base::Unretained(this)),
+                           base::Bind(base::DoNothing)),
+      &sink);
+  sender_ = mojo::WeakBindToRequest(
+      new DataSourceSender(base::Bind(&SerialConnection::OnReceivePipeReady,
+                                      base::Unretained(this)),
+                           base::Bind(base::DoNothing)),
+      &source);
 }
 
 SerialConnection::~SerialConnection() {
diff --git a/device/serial/serial_connection.h b/device/serial/serial_connection.h
index 6143c8b1..d0b940f 100644
--- a/device/serial/serial_connection.h
+++ b/device/serial/serial_connection.h
@@ -22,9 +22,7 @@
  public:
   SerialConnection(scoped_refptr<SerialIoHandler> io_handler,
                    mojo::InterfaceRequest<serial::DataSink> sink,
-                   mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-                   mojo::InterfaceRequest<serial::DataSource> source,
-                   mojo::InterfacePtr<serial::DataSourceClient> source_client);
+                   mojo::InterfaceRequest<serial::DataSource> source);
   ~SerialConnection() override;
 
   // mojo::InterfaceImpl<serial::Connection> overrides.
diff --git a/device/serial/serial_connection_factory.cc b/device/serial/serial_connection_factory.cc
index 9beb33ae..6b01490 100644
--- a/device/serial/serial_connection_factory.cc
+++ b/device/serial/serial_connection_factory.cc
@@ -37,9 +37,7 @@
               serial::ConnectionOptionsPtr options,
               mojo::InterfaceRequest<serial::Connection> connection_request,
               mojo::InterfaceRequest<serial::DataSink> sink,
-              mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-              mojo::InterfaceRequest<serial::DataSource> source,
-              mojo::InterfacePtr<serial::DataSourceClient> source_client);
+              mojo::InterfaceRequest<serial::DataSource> source);
   void Run();
 
  private:
@@ -53,9 +51,7 @@
   serial::ConnectionOptionsPtr options_;
   mojo::InterfaceRequest<serial::Connection> connection_request_;
   mojo::InterfaceRequest<serial::DataSink> sink_;
-  mojo::InterfacePtr<serial::DataSinkClient> sink_client_;
   mojo::InterfaceRequest<serial::DataSource> source_;
-  mojo::InterfacePtr<serial::DataSourceClient> source_client_;
   scoped_refptr<SerialIoHandler> io_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectTask);
@@ -73,12 +69,13 @@
     serial::ConnectionOptionsPtr options,
     mojo::InterfaceRequest<serial::Connection> connection_request,
     mojo::InterfaceRequest<serial::DataSink> sink,
-    mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-    mojo::InterfaceRequest<serial::DataSource> source,
-    mojo::InterfacePtr<serial::DataSourceClient> source_client) {
-  scoped_refptr<ConnectTask> task(new ConnectTask(
-      this, path, options.Pass(), connection_request.Pass(), sink.Pass(),
-      sink_client.Pass(), source.Pass(), source_client.Pass()));
+    mojo::InterfaceRequest<serial::DataSource> source) {
+  scoped_refptr<ConnectTask> task(new ConnectTask(this,
+                                                  path,
+                                                  options.Pass(),
+                                                  connection_request.Pass(),
+                                                  sink.Pass(),
+                                                  source.Pass()));
   task->Run();
 }
 
@@ -91,17 +88,13 @@
     serial::ConnectionOptionsPtr options,
     mojo::InterfaceRequest<serial::Connection> connection_request,
     mojo::InterfaceRequest<serial::DataSink> sink,
-    mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-    mojo::InterfaceRequest<serial::DataSource> source,
-    mojo::InterfacePtr<serial::DataSourceClient> source_client)
+    mojo::InterfaceRequest<serial::DataSource> source)
     : factory_(factory),
       path_(path),
       options_(options.Pass()),
       connection_request_(connection_request.Pass()),
       sink_(sink.Pass()),
-      sink_client_(sink_client.Pass()),
-      source_(source.Pass()),
-      source_client_(source_client.Pass()) {
+      source_(source.Pass()) {
   if (!options_) {
     options_ = serial::ConnectionOptions::New();
   }
@@ -131,8 +124,7 @@
   }
 
   mojo::BindToRequest(
-      new SerialConnection(io_handler_, sink_.Pass(), sink_client_.Pass(),
-                           source_.Pass(), source_client_.Pass()),
+      new SerialConnection(io_handler_, sink_.Pass(), source_.Pass()),
       &connection_request_);
 }
 
diff --git a/device/serial/serial_connection_factory.h b/device/serial/serial_connection_factory.h
index 2e1dcca..4200dca 100644
--- a/device/serial/serial_connection_factory.h
+++ b/device/serial/serial_connection_factory.h
@@ -32,9 +32,7 @@
       serial::ConnectionOptionsPtr options,
       mojo::InterfaceRequest<serial::Connection> connection_request,
       mojo::InterfaceRequest<serial::DataSink> sink,
-      mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-      mojo::InterfaceRequest<serial::DataSource> source,
-      mojo::InterfacePtr<serial::DataSourceClient> source_client);
+      mojo::InterfaceRequest<serial::DataSource> source);
 
  private:
   friend class base::RefCountedThreadSafe<SerialConnectionFactory>;
diff --git a/device/serial/serial_connection_unittest.cc b/device/serial/serial_connection_unittest.cc
index 53d530329..151ed77 100644
--- a/device/serial/serial_connection_unittest.cc
+++ b/device/serial/serial_connection_unittest.cc
@@ -74,23 +74,17 @@
             scoped_ptr<SerialDeviceEnumerator>(new FakeSerialDeviceEnumerator)),
         &service);
     service.set_error_handler(this);
-    mojo::InterfacePtr<serial::DataSink> sink;
-    mojo::InterfacePtr<serial::DataSinkClient> sink_client;
-    mojo::InterfaceRequest<serial::DataSinkClient> sink_client_request =
-        mojo::GetProxy(&sink_client);
-    mojo::InterfacePtr<serial::DataSource> source;
-    mojo::InterfacePtr<serial::DataSourceClient> source_client;
-    mojo::InterfaceRequest<serial::DataSourceClient> source_client_request =
-        mojo::GetProxy(&source_client);
-    service->Connect("device", serial::ConnectionOptions::New(),
-                     mojo::GetProxy(&connection_), mojo::GetProxy(&sink),
-                     sink_client.Pass(), mojo::GetProxy(&source),
-                     source_client.Pass());
-    sender_.reset(new DataSender(sink.Pass(), sink_client_request.Pass(),
-                                 kBufferSize, serial::SEND_ERROR_DISCONNECTED));
-    receiver_ =
-        new DataReceiver(source.Pass(), source_client_request.Pass(),
-                         kBufferSize, serial::RECEIVE_ERROR_DISCONNECTED);
+    mojo::InterfacePtr<serial::DataSink> consumer;
+    mojo::InterfacePtr<serial::DataSource> producer;
+    service->Connect("device",
+                     serial::ConnectionOptions::New(),
+                     mojo::GetProxy(&connection_),
+                     mojo::GetProxy(&consumer),
+                     mojo::GetProxy(&producer));
+    sender_.reset(new DataSender(
+        consumer.Pass(), kBufferSize, serial::SEND_ERROR_DISCONNECTED));
+    receiver_ = new DataReceiver(
+        producer.Pass(), kBufferSize, serial::RECEIVE_ERROR_DISCONNECTED);
     connection_.set_error_handler(this);
     connection_->GetInfo(
         base::Bind(&SerialConnectionTest::StoreInfo, base::Unretained(this)));
diff --git a/device/serial/serial_service_impl.cc b/device/serial/serial_service_impl.cc
index 6fd6ce0..fceb448 100644
--- a/device/serial/serial_service_impl.cc
+++ b/device/serial/serial_service_impl.cc
@@ -61,14 +61,14 @@
     serial::ConnectionOptionsPtr options,
     mojo::InterfaceRequest<serial::Connection> connection_request,
     mojo::InterfaceRequest<serial::DataSink> sink,
-    mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-    mojo::InterfaceRequest<serial::DataSource> source,
-    mojo::InterfacePtr<serial::DataSourceClient> source_client) {
+    mojo::InterfaceRequest<serial::DataSource> source) {
   if (!IsValidPath(path))
     return;
-  connection_factory_->CreateConnection(
-      path, options.Pass(), connection_request.Pass(), sink.Pass(),
-      sink_client.Pass(), source.Pass(), source_client.Pass());
+  connection_factory_->CreateConnection(path,
+                                        options.Pass(),
+                                        connection_request.Pass(),
+                                        sink.Pass(),
+                                        source.Pass());
 }
 
 SerialDeviceEnumerator* SerialServiceImpl::GetDeviceEnumerator() {
diff --git a/device/serial/serial_service_impl.h b/device/serial/serial_service_impl.h
index 8e6ce3bf..0caf00e 100644
--- a/device/serial/serial_service_impl.h
+++ b/device/serial/serial_service_impl.h
@@ -36,14 +36,11 @@
   void GetDevices(
       const mojo::Callback<void(mojo::Array<serial::DeviceInfoPtr>)>& callback)
       override;
-  void Connect(
-      const mojo::String& path,
-      serial::ConnectionOptionsPtr options,
-      mojo::InterfaceRequest<serial::Connection> connection_request,
-      mojo::InterfaceRequest<serial::DataSink> sink,
-      mojo::InterfacePtr<serial::DataSinkClient> sink_client,
-      mojo::InterfaceRequest<serial::DataSource> source,
-      mojo::InterfacePtr<serial::DataSourceClient> source_client) override;
+  void Connect(const mojo::String& path,
+               serial::ConnectionOptionsPtr options,
+               mojo::InterfaceRequest<serial::Connection> connection_request,
+               mojo::InterfaceRequest<serial::DataSink> sink,
+               mojo::InterfaceRequest<serial::DataSource> source) override;
 
  private:
   SerialDeviceEnumerator* GetDeviceEnumerator();
diff --git a/device/serial/serial_service_unittest.cc b/device/serial/serial_service_unittest.cc
index 103fb20..7f8beb23 100644
--- a/device/serial/serial_service_unittest.cc
+++ b/device/serial/serial_service_unittest.cc
@@ -84,15 +84,12 @@
         &service);
     mojo::InterfacePtr<serial::Connection> connection;
     mojo::InterfacePtr<serial::DataSink> sink;
-    mojo::InterfacePtr<serial::DataSinkClient> sink_client;
-    mojo::GetProxy(&sink_client);
     mojo::InterfacePtr<serial::DataSource> source;
-    mojo::InterfacePtr<serial::DataSourceClient> source_client;
-    mojo::GetProxy(&source_client);
-    service->Connect(path, serial::ConnectionOptions::New(),
-                     mojo::GetProxy(&connection), mojo::GetProxy(&sink),
-                     sink_client.Pass(), mojo::GetProxy(&source),
-                     source_client.Pass());
+    service->Connect(path,
+                     serial::ConnectionOptions::New(),
+                     mojo::GetProxy(&connection),
+                     mojo::GetProxy(&sink),
+                     mojo::GetProxy(&source));
     connection.set_error_handler(this);
     expecting_error_ = !expecting_success;
     connection->GetInfo(
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index b11f1d2..17d6563b 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -10,7 +10,6 @@
   sources = []
 
   deps = [
-    "//components/copresence_endpoints",
     "//components/keyed_service/content",
     "//components/keyed_service/core",
     "//components/pref_registry",
@@ -109,10 +108,6 @@
       "api/cast_channel/logger.h",
       "api/cast_channel/logger_util.cc",
       "api/cast_channel/logger_util.h",
-      "api/copresence_endpoints/copresence_endpoints_api.cc",
-      "api/copresence_endpoints/copresence_endpoints_api.h",
-      "api/copresence_endpoints/copresence_endpoint_resource.cc",
-      "api/copresence_endpoints/copresence_endpoint_resource.h",
       "api/declarative/declarative_api.cc",
       "api/declarative/declarative_api.h",
       "api/declarative/declarative_rule.h",
@@ -344,6 +339,8 @@
       "content_verifier_io_data.h",
       "content_verify_job.cc",
       "content_verify_job.h",
+      "crx_file_info.cc",
+      "crx_file_info.h",
       "error_map.cc",
       "error_map.h",
       "event_listener_map.cc",
@@ -580,6 +577,9 @@
 
     if (is_chromeos) {
       sources += [
+        "api/diagnostics/diagnostics_api.cc",
+        "api/diagnostics/diagnostics_api.h",
+        "api/diagnostics/diagnostics_api_chromeos.cc",
         "api/networking_config/networking_config_api.cc",
         "api/networking_config/networking_config_api.h",
         "api/networking_config/networking_config_service.cc",
diff --git a/extensions/browser/api/copresence_endpoints/DEPS b/extensions/browser/api/copresence_endpoints/DEPS
deleted file mode 100644
index e2c798c7..0000000
--- a/extensions/browser/api/copresence_endpoints/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+components/copresence_endpoints",
-]
diff --git a/extensions/browser/api/copresence_endpoints/OWNERS b/extensions/browser/api/copresence_endpoints/OWNERS
deleted file mode 100644
index 6a2cb03..0000000
--- a/extensions/browser/api/copresence_endpoints/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-rkc@chromium.org
diff --git a/extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.cc b/extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.cc
deleted file mode 100644
index 45d4542e..0000000
--- a/extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.cc
+++ /dev/null
@@ -1,43 +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.
-
-#include "extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.h"
-
-#include "base/lazy_instance.h"
-#include "components/copresence_endpoints/public/copresence_endpoint.h"
-#include "content/public/browser/browser_context.h"
-
-using copresence_endpoints::CopresenceEndpoint;
-
-namespace extensions {
-
-// CopresenceEndpointResource.
-
-// static
-static base::LazyInstance<BrowserContextKeyedAPIFactory<
-    ApiResourceManager<CopresenceEndpointResource>>> g_endpoint_factory =
-    LAZY_INSTANCE_INITIALIZER;
-
-// static
-template <>
-BrowserContextKeyedAPIFactory<ApiResourceManager<CopresenceEndpointResource>>*
-ApiResourceManager<CopresenceEndpointResource>::GetFactoryInstance() {
-  return g_endpoint_factory.Pointer();
-}
-
-CopresenceEndpointResource::CopresenceEndpointResource(
-    const std::string& owner_extension_id,
-    scoped_ptr<copresence_endpoints::CopresenceEndpoint> endpoint)
-    : ApiResource(owner_extension_id), endpoint_(endpoint.Pass()) {
-}
-
-CopresenceEndpointResource::~CopresenceEndpointResource() {
-}
-
-copresence_endpoints::CopresenceEndpoint*
-CopresenceEndpointResource::endpoint() {
-  return endpoint_.get();
-}
-
-}  // namespace extensions
diff --git a/extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.h b/extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.h
deleted file mode 100644
index bfadb3b..0000000
--- a/extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.h
+++ /dev/null
@@ -1,49 +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.
-
-#ifndef EXTENSIONS_BROWSER_API_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINTS_RESOURCES_H_
-#define EXTENSIONS_BROWSER_API_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINTS_RESOURCES_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "extensions/browser/api/api_resource.h"
-#include "extensions/browser/api/api_resource_manager.h"
-
-namespace copresence_endpoints {
-class CopresenceEndpoint;
-}
-
-namespace extensions {
-
-class CopresenceEndpointResource : public ApiResource {
- public:
-  CopresenceEndpointResource(
-      const std::string& owner_extension_id,
-      scoped_ptr<copresence_endpoints::CopresenceEndpoint> endpoint);
-  ~CopresenceEndpointResource() override;
-
-  copresence_endpoints::CopresenceEndpoint* endpoint();
-
-  std::string& packet() { return packet_; }
-
-  static const content::BrowserThread::ID kThreadId =
-      content::BrowserThread::UI;
-
- private:
-  friend class ApiResourceManager<CopresenceEndpointResource>;
-  static const char* service_name() {
-    return "CopresenceEndpointResourceManager";
-  }
-
-  scoped_ptr<copresence_endpoints::CopresenceEndpoint> endpoint_;
-  std::string packet_;
-
-  DISALLOW_COPY_AND_ASSIGN(CopresenceEndpointResource);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_API_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINTS_RESOURCES_H_
diff --git a/extensions/browser/api/copresence_endpoints/copresence_endpoints_api.cc b/extensions/browser/api/copresence_endpoints/copresence_endpoints_api.cc
deleted file mode 100644
index 6ecb7728..0000000
--- a/extensions/browser/api/copresence_endpoints/copresence_endpoints_api.cc
+++ /dev/null
@@ -1,336 +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.
-
-#include "extensions/browser/api/copresence_endpoints/copresence_endpoints_api.h"
-
-#include "base/base64.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/lazy_instance.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "components/copresence_endpoints/public/copresence_endpoint.h"
-#include "content/public/browser/browser_context.h"
-#include "extensions/browser/api/copresence_endpoints/copresence_endpoint_resource.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/common/api/copresence_endpoints.h"
-#include "net/base/io_buffer.h"
-
-using copresence_endpoints::CopresenceEndpoint;
-
-namespace extensions {
-
-namespace {
-
-const size_t kSizeBytes = 2;
-const char kToField[] = "to";
-const char kDataField[] = "data";
-const char kReplyToField[] = "replyTo";
-
-bool Base64DecodeWithoutPadding(const std::string& data, std::string* out) {
-  std::string ret = data;
-  while (ret.size() % 4)
-    ret.push_back('=');
-
-  if (!base::Base64Decode(ret, &ret))
-    return false;
-
-  out->swap(ret);
-  return true;
-}
-
-std::string Base64EncodeWithoutPadding(const std::string& data) {
-  std::string ret = data;
-  base::Base64Encode(ret, &ret);
-  while (*(ret.end() - 1) == '=')
-    ret.erase(ret.end() - 1);
-  return ret;
-}
-
-// Create a message to send to another endpoint.
-std::string CreateMessage(const std::vector<char>& data,
-                          const std::string& local_endpoint_locator,
-                          int remote_endpoint_id) {
-  base::DictionaryValue dict;
-  dict.SetString(kToField, base::IntToString(remote_endpoint_id));
-  dict.SetString(kDataField, Base64EncodeWithoutPadding(
-                                 std::string(data.begin(), data.end())));
-  dict.SetString(kReplyToField,
-                 Base64EncodeWithoutPadding(local_endpoint_locator));
-
-  std::string json;
-  base::JSONWriter::Write(&dict, &json);
-
-  std::string message;
-  message.push_back(static_cast<unsigned char>(json.size() & 0xff));
-  message.push_back(static_cast<unsigned char>(json.size() >> 8));
-
-  message.append(json);
-  return message;
-}
-
-bool IsMessageComplete(const std::string& message, size_t* length) {
-  if (message.size() < kSizeBytes)
-    return false;
-
-  // message[1] = upper order 8 bits.
-  // message[0] = lower order 8 bits.
-  size_t message_length = (static_cast<size_t>(message[1]) << 8) |
-                          (static_cast<size_t>(message[0]) & 0xff);
-
-  if (message.size() >= kSizeBytes + message_length) {
-    *length = message_length;
-    return true;
-  }
-
-  return false;
-}
-
-bool ExtractEndpointId(const std::string& endpoint_locator, int* id) {
-  std::vector<std::string> tokens;
-  if (Tokenize(endpoint_locator, ".", &tokens) <= 1)
-    return false;
-
-  if (!base::StringToInt(tokens[0], id))
-    return false;
-
-  return true;
-}
-
-// Parse a message received from another endpoint.
-bool ParseReceivedMessage(const std::string& message,
-                          std::string* data,
-                          int* remote_endpoint_id) {
-  scoped_ptr<base::Value> value(base::JSONReader::Read(message));
-
-  // Check to see that we have a valid dictionary.
-  base::DictionaryValue* dict = nullptr;
-  if (!value || !value->GetAsDictionary(&dict) || !dict->HasKey(kDataField)) {
-    LOG(WARNING) << "Invalid message: " << message;
-    return false;
-  }
-
-  // The fields in the json string are,
-  // to: Endpoint Id this message is meant for (unused atm, we only support one
-  //     local endpoint). TODO(rkc): Fix this to support multiple endpoints.
-  // data: Data content of the message.
-  // replyTo: Sender of this message (in the locator data format). We only need
-  //          the endpoint id that we have to reply to, but currently we get
-  //          the full locator. TODO(rkc): Fix this once other platforms change
-  //          over to only sending us the ID.
-  if (!dict->GetStringASCII(kDataField, data))
-    return false;
-  if (!Base64DecodeWithoutPadding(*data, data))
-    return false;
-
-  std::string endpoint_locator;
-  if (!dict->GetStringASCII(kReplyToField, &endpoint_locator))
-    return false;
-  if (!Base64DecodeWithoutPadding(endpoint_locator, &endpoint_locator))
-    return false;
-
-  if (!ExtractEndpointId(endpoint_locator, remote_endpoint_id))
-    return false;
-
-  VLOG(3) << "Valid message parsed.";
-  return true;
-}
-
-}  // namespace
-
-// CopresenceEndpointFunction public methods:
-
-CopresenceEndpointFunction::CopresenceEndpointFunction()
-    : endpoints_manager_(nullptr) {
-}
-
-void CopresenceEndpointFunction::DispatchOnConnectedEvent(int endpoint_id) {
-  // Send the messages to the client app.
-  scoped_ptr<Event> event(new Event(
-      core_api::copresence_endpoints::OnConnected::kEventName,
-      core_api::copresence_endpoints::OnConnected::Create(endpoint_id),
-      browser_context()));
-  EventRouter::Get(browser_context())
-      ->DispatchEventToExtension(extension_id(), event.Pass());
-  VLOG(2) << "Dispatched OnConnected event: endpointId = " << endpoint_id;
-}
-
-// CopresenceEndpointFunction protected methods:
-
-int CopresenceEndpointFunction::AddEndpoint(
-    CopresenceEndpointResource* endpoint) {
-  return endpoints_manager_->Add(endpoint);
-}
-
-void CopresenceEndpointFunction::ReplaceEndpoint(
-    const std::string& extension_id,
-    int endpoint_id,
-    CopresenceEndpointResource* endpoint) {
-  endpoints_manager_->Replace(extension_id, endpoint_id, endpoint);
-}
-
-CopresenceEndpointResource* CopresenceEndpointFunction::GetEndpoint(
-    int endpoint_id) {
-  return endpoints_manager_->Get(extension_id(), endpoint_id);
-}
-
-void CopresenceEndpointFunction::RemoveEndpoint(int endpoint_id) {
-  endpoints_manager_->Remove(extension_id(), endpoint_id);
-}
-
-ExtensionFunction::ResponseAction CopresenceEndpointFunction::Run() {
-  Initialize();
-  return Execute();
-}
-
-// CopresenceEndpointFunction private methods:
-
-CopresenceEndpointFunction::~CopresenceEndpointFunction() {
-}
-
-void CopresenceEndpointFunction::Initialize() {
-  endpoints_manager_ =
-      ApiResourceManager<CopresenceEndpointResource>::Get(browser_context());
-}
-
-void CopresenceEndpointFunction::OnDataReceived(
-    int local_endpoint_id,
-    const scoped_refptr<net::IOBuffer>& buffer,
-    int size) {
-  CopresenceEndpointResource* local_endpoint = GetEndpoint(local_endpoint_id);
-  if (!local_endpoint) {
-    VLOG(2) << "Receiving endpoint not found. ID = " << local_endpoint_id;
-    return;
-  }
-
-  std::string& packet = local_endpoint->packet();
-  packet.append(std::string(buffer->data(), size));
-  size_t message_length;
-  if (IsMessageComplete(packet, &message_length)) {
-    std::string message_data;
-    int remote_endpoint_id;
-    if (ParseReceivedMessage(packet.substr(kSizeBytes, message_length),
-                             &message_data, &remote_endpoint_id)) {
-      DispatchOnReceiveEvent(local_endpoint_id, remote_endpoint_id,
-                             message_data);
-    } else {
-      LOG(WARNING) << "Invalid message received: "
-                   << packet.substr(kSizeBytes, message_length)
-                   << " of length: " << message_length;
-    }
-
-    if (packet.size() > message_length + kSizeBytes) {
-      packet = packet.substr(message_length + kSizeBytes);
-    } else {
-      packet.clear();
-    }
-  }
-}
-
-void CopresenceEndpointFunction::DispatchOnReceiveEvent(
-    int local_endpoint_id,
-    int remote_endpoint_id,
-    const std::string& data) {
-  core_api::copresence_endpoints::ReceiveInfo info;
-  info.local_endpoint_id = local_endpoint_id;
-  info.remote_endpoint_id = remote_endpoint_id;
-  info.data.assign(data.begin(), data.end());
-  // Send the data to the client app.
-  scoped_ptr<Event> event(
-      new Event(core_api::copresence_endpoints::OnReceive::kEventName,
-                core_api::copresence_endpoints::OnReceive::Create(info),
-                browser_context()));
-  EventRouter::Get(browser_context())
-      ->DispatchEventToExtension(extension_id(), event.Pass());
-  VLOG(2) << "Dispatched OnReceive event: localEndpointId = "
-          << local_endpoint_id << ", remoteEndpointId = " << remote_endpoint_id
-          << " and data = " << data;
-}
-
-// CopresenceEndpointsCreateLocalEndpointFunction implementation:
-ExtensionFunction::ResponseAction
-CopresenceEndpointsCreateLocalEndpointFunction::Execute() {
-  // Add an empty endpoint to create a placeholder endpoint_id. We will need to
-  // bind
-  // this id to the OnConnected event dispatcher, so we need it before we
-  // create the actual endpoint. Once we have the endpoint created, we'll
-  // replace the
-  // placeholder with the actual endpoint object.
-  int endpoint_id =
-      AddEndpoint(new CopresenceEndpointResource(extension_id(), nullptr));
-
-  scoped_ptr<CopresenceEndpoint> endpoint =
-      make_scoped_ptr(new CopresenceEndpoint(
-          endpoint_id,
-          base::Bind(&CopresenceEndpointsCreateLocalEndpointFunction::OnCreated,
-                     this, endpoint_id),
-          base::Bind(&CopresenceEndpointFunction::DispatchOnConnectedEvent,
-                     this, endpoint_id),
-          base::Bind(&CopresenceEndpointFunction::OnDataReceived, this,
-                     endpoint_id)));
-
-  ReplaceEndpoint(
-      extension_id(), endpoint_id,
-      new CopresenceEndpointResource(extension_id(), endpoint.Pass()));
-
-  return RespondLater();
-}
-
-void CopresenceEndpointsCreateLocalEndpointFunction::OnCreated(
-    int endpoint_id,
-    const std::string& locator) {
-  core_api::copresence_endpoints::EndpointInfo endpoint_info;
-  endpoint_info.endpoint_id = endpoint_id;
-  endpoint_info.locator = locator;
-  Respond(ArgumentList(
-      core_api::copresence_endpoints::CreateLocalEndpoint::Results::Create(
-          endpoint_info)));
-}
-
-// CopresenceEndpointsDestroyEndpointFunction implementation:
-ExtensionFunction::ResponseAction
-CopresenceEndpointsDestroyEndpointFunction::Execute() {
-  scoped_ptr<core_api::copresence_endpoints::DestroyEndpoint::Params> params(
-      core_api::copresence_endpoints::DestroyEndpoint::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-
-  RemoveEndpoint(params->endpoint_id);
-  return RespondNow(NoArguments());
-}
-
-// CopresenceEndpointsSendFunction implementation:
-ExtensionFunction::ResponseAction CopresenceEndpointsSendFunction::Execute() {
-  scoped_ptr<core_api::copresence_endpoints::Send::Params> params(
-      core_api::copresence_endpoints::Send::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-
-  CopresenceEndpointResource* endpoint = GetEndpoint(params->local_endpoint_id);
-  if (!endpoint) {
-    VLOG(1) << "Endpoint not found. ID = " << params->local_endpoint_id;
-    return RespondNow(
-        ArgumentList(core_api::copresence_endpoints::Send::Results::Create(
-            core_api::copresence_endpoints::
-                ENDPOINT_STATUS_INVALID_LOCAL_ENDPOINT)));
-  }
-  DCHECK(endpoint->endpoint());
-
-  const std::string& message =
-      CreateMessage(params->data, endpoint->endpoint()->GetLocator(),
-                    params->remote_endpoint_id);
-  VLOG(3) << "Sending message to remote_endpoint_id = "
-          << params->remote_endpoint_id
-          << " from local_endpoint_id = " << params->local_endpoint_id
-          << " with data[0] = " << static_cast<int>(message[0])
-          << ", data[1] = " << static_cast<int>(message[1]) << ", data[2:] = "
-          << std::string((message.c_str() + 2), message.size() - 2);
-
-  endpoint->endpoint()->Send(new net::StringIOBuffer(message), message.size());
-
-  return RespondNow(
-      ArgumentList(core_api::copresence_endpoints::Send::Results::Create(
-          core_api::copresence_endpoints::ENDPOINT_STATUS_NO_ERROR)));
-}
-
-}  // namespace extensions
diff --git a/extensions/browser/api/copresence_endpoints/copresence_endpoints_api.h b/extensions/browser/api/copresence_endpoints/copresence_endpoints_api.h
deleted file mode 100644
index e02ce4c..0000000
--- a/extensions/browser/api/copresence_endpoints/copresence_endpoints_api.h
+++ /dev/null
@@ -1,111 +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.
-
-#ifndef EXTENSIONS_BROWSER_API_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINTS_API_H_
-#define EXTENSIONS_BROWSER_API_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINTS_API_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "extensions/browser/api/api_resource_manager.h"
-#include "extensions/browser/browser_context_keyed_api_factory.h"
-#include "extensions/browser/extension_function.h"
-#include "extensions/browser/extension_function_histogram_value.h"
-
-namespace copresence_endpoints {
-class CopresenceEndpoint;
-}
-
-namespace net {
-class IOBuffer;
-}
-
-namespace extensions {
-
-class CopresenceEndpointResource;
-
-class CopresenceEndpointFunction : public UIThreadExtensionFunction {
- public:
-  CopresenceEndpointFunction();
-
-  void DispatchOnConnectedEvent(int endpoint_id);
-
-  // Needs to be used from CreateLocalEndpoint.
-  void OnDataReceived(int endpoint_id,
-                      const scoped_refptr<net::IOBuffer>& buffer,
-                      int size);
-
- protected:
-  ~CopresenceEndpointFunction() override;
-
-  // Override this and do actual work here.
-  virtual ExtensionFunction::ResponseAction Execute() = 0;
-
-  // Takes ownership of endpoint.
-  int AddEndpoint(CopresenceEndpointResource* endpoint);
-
-  // Takes ownership of endpoint.
-  void ReplaceEndpoint(const std::string& extension_id,
-                       int endpoint_id,
-                       CopresenceEndpointResource* endpoint);
-
-  CopresenceEndpointResource* GetEndpoint(int endpoint_id);
-
-  void RemoveEndpoint(int endpoint_id);
-
-  // ExtensionFunction overrides:
-  ExtensionFunction::ResponseAction Run() override;
-
- private:
-  void Initialize();
-
-  void DispatchOnReceiveEvent(int local_endpoint_id,
-                              int remote_endpoint_id,
-                              const std::string& data);
-
-  ApiResourceManager<CopresenceEndpointResource>* endpoints_manager_;
-};
-
-class CopresenceEndpointsCreateLocalEndpointFunction
-    : public CopresenceEndpointFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("copresenceEndpoints.createLocalEndpoint",
-                             COPRESENCEENDPOINTS_CREATELOCALENDPOINT);
-
- protected:
-  ~CopresenceEndpointsCreateLocalEndpointFunction() override {}
-  ExtensionFunction::ResponseAction Execute() override;
-
- private:
-  void OnCreated(int endpoint_id, const std::string& locator);
-};
-
-class CopresenceEndpointsDestroyEndpointFunction
-    : public CopresenceEndpointFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("copresenceEndpoints.destroyLocalEndpoint",
-                             COPRESENCEENDPOINTS_DESTROYLOCALENDPOINT);
-
- protected:
-  ~CopresenceEndpointsDestroyEndpointFunction() override {}
-  ExtensionFunction::ResponseAction Execute() override;
-};
-
-class CopresenceEndpointsSendFunction : public CopresenceEndpointFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("copresenceEndpoints.send",
-                             COPRESENCEENDPOINTS_SEND);
-
- protected:
-  ~CopresenceEndpointsSendFunction() override {}
-  ExtensionFunction::ResponseAction Execute() override;
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_API_COPRESENCE_ENDPOINTS_COPRESENCE_ENDPOINTS_API_H_
diff --git a/chrome/browser/extensions/api/diagnostics/diagnostics_api.cc b/extensions/browser/api/diagnostics/diagnostics_api.cc
similarity index 85%
rename from chrome/browser/extensions/api/diagnostics/diagnostics_api.cc
rename to extensions/browser/api/diagnostics/diagnostics_api.cc
index 0f6e8d2..684577c 100644
--- a/chrome/browser/extensions/api/diagnostics/diagnostics_api.cc
+++ b/extensions/browser/api/diagnostics/diagnostics_api.cc
@@ -2,22 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/diagnostics/diagnostics_api.h"
-
-namespace SendPacket = extensions::api::diagnostics::SendPacket;
+#include "extensions/browser/api/diagnostics/diagnostics_api.h"
 
 namespace {
 
 const char kErrorPingNotImplemented[] = "Not implemented";
 const char kErrorPingFailed[] = "Failed to send ping packet";
-
 }
 
 namespace extensions {
 
-DiagnosticsSendPacketFunction::DiagnosticsSendPacketFunction() {}
+namespace SendPacket = core_api::diagnostics::SendPacket;
 
-DiagnosticsSendPacketFunction::~DiagnosticsSendPacketFunction() {}
+DiagnosticsSendPacketFunction::DiagnosticsSendPacketFunction() {
+}
+
+DiagnosticsSendPacketFunction::~DiagnosticsSendPacketFunction() {
+}
 
 bool DiagnosticsSendPacketFunction::Prepare() {
   parameters_ = SendPacket::Params::Create(*args_);
@@ -35,7 +36,7 @@
     double latency) {
   switch (result_code) {
     case SEND_PACKET_OK: {
-      extensions::api::diagnostics::SendPacketResult result;
+      core_api::diagnostics::SendPacketResult result;
       result.ip = ip;
       result.latency = latency;
       results_ = SendPacket::Results::Create(result);
diff --git a/chrome/browser/extensions/api/diagnostics/diagnostics_api.h b/extensions/browser/api/diagnostics/diagnostics_api.h
similarity index 73%
rename from chrome/browser/extensions/api/diagnostics/diagnostics_api.h
rename to extensions/browser/api/diagnostics/diagnostics_api.h
index ac0da63..451bd79 100644
--- a/chrome/browser/extensions/api/diagnostics/diagnostics_api.h
+++ b/extensions/browser/api/diagnostics/diagnostics_api.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
+#ifndef EXTENSIONS_BROWSER_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
+#define EXTENSIONS_BROWSER_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
 
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
-#include "chrome/common/extensions/api/diagnostics.h"
 #include "extensions/browser/api/async_api_function.h"
+#include "extensions/common/api/diagnostics.h"
 
 namespace extensions {
 
@@ -28,8 +28,7 @@
     SEND_PACKET_FAILED,
   };
 
-  DECLARE_EXTENSION_FUNCTION("diagnostics.sendPacket",
-                             DIAGNOSTICS_SENDPACKET);
+  DECLARE_EXTENSION_FUNCTION("diagnostics.sendPacket", DIAGNOSTICS_SENDPACKET);
 
   DiagnosticsSendPacketFunction();
 
@@ -48,10 +47,9 @@
                    const std::string& ip,
                    double latency);
 
-  scoped_ptr<extensions::api::diagnostics::SendPacket::Params>
-      parameters_;
+  scoped_ptr<core_api::diagnostics::SendPacket::Params> parameters_;
 };
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
+#endif  // EXTENSIONS_BROWSER_API_DIAGNOSTICS_DIAGNOSTICS_API_H_
diff --git a/chrome/browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc b/extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
similarity index 79%
rename from chrome/browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc
rename to extensions/browser/api/diagnostics/diagnostics_api_chromeos.cc
index 9ae0f18..f14b8fb 100644
--- a/chrome/browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc
+++ b/extensions/browser/api/diagnostics/diagnostics_api_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 "chrome/browser/extensions/api/diagnostics/diagnostics_api.h"
+#include "extensions/browser/api/diagnostics/diagnostics_api.h"
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -25,12 +25,9 @@
 typedef base::Callback<void(
     DiagnosticsSendPacketFunction::SendPacketResultCode result_code,
     const std::string& ip,
-    double latency)>
-    SendPacketCallback;
+    double latency)> SendPacketCallback;
 
-bool ParseResult(const std::string& status,
-                 std::string* ip,
-                 double* latency) {
+bool ParseResult(const std::string& status, std::string* ip, double* latency) {
   // Parses the result and returns IP and latency.
   scoped_ptr<base::Value> parsed_value(base::JSONReader::Read(status));
   if (!parsed_value)
@@ -54,18 +51,15 @@
   return true;
 }
 
-void OnTestICMPCompleted(
-    const SendPacketCallback& callback,
-    bool succeeded,
-    const std::string& status) {
+void OnTestICMPCompleted(const SendPacketCallback& callback,
+                         bool succeeded,
+                         const std::string& status) {
   std::string ip;
   double latency;
   if (!succeeded || !ParseResult(status, &ip, &latency)) {
     callback.Run(DiagnosticsSendPacketFunction::SEND_PACKET_FAILED, "", 0.0);
   } else {
-    callback.Run(DiagnosticsSendPacketFunction::SEND_PACKET_OK,
-                 ip,
-                 latency);
+    callback.Run(DiagnosticsSendPacketFunction::SEND_PACKET_OK, ip, latency);
   }
 }
 
@@ -81,8 +75,9 @@
   if (parameters_->options.size)
     config[kSize] = base::IntToString(*parameters_->options.size);
 
-  chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()->
-      TestICMPWithOptions(
+  chromeos::DBusThreadManager::Get()
+      ->GetDebugDaemonClient()
+      ->TestICMPWithOptions(
           parameters_->options.ip, config,
           base::Bind(
               OnTestICMPCompleted,
diff --git a/extensions/browser/api/printer_provider/printer_provider_api.cc b/extensions/browser/api/printer_provider/printer_provider_api.cc
index 04f663b..d0244e4 100644
--- a/extensions/browser/api/printer_provider/printer_provider_api.cc
+++ b/extensions/browser/api/printer_provider/printer_provider_api.cc
@@ -24,6 +24,35 @@
 static base::LazyInstance<BrowserContextKeyedAPIFactory<PrinterProviderAPI>>
     g_api_factory = LAZY_INSTANCE_INITIALIZER;
 
+// The separator between extension id and the extension's internal printer id
+// used when generating a printer id unique across extensions.
+const char kPrinterIdSeparator = ':';
+
+// Given an extension ID and an ID of a printer reported by the extension, it
+// generates a ID for the printer unique across extensions (assuming that the
+// printer id is unique in the extension's space).
+std::string GeneratePrinterId(const std::string& extension_id,
+                              const std::string& internal_printer_id) {
+  std::string result = extension_id;
+  result.append(1, kPrinterIdSeparator);
+  result.append(internal_printer_id);
+  return result;
+}
+
+// Parses an ID created using |GeneratePrinterId| to it's components:
+// the extension ID and the printer ID internal to the extension.
+// Returns whenter the ID was succesfully parsed.
+bool ParsePrinterId(const std::string& printer_id,
+                    std::string* extension_id,
+                    std::string* internal_printer_id) {
+  size_t separator = printer_id.find_first_of(kPrinterIdSeparator);
+  if (separator == std::string::npos)
+    return false;
+  *extension_id = printer_id.substr(0, separator);
+  *internal_printer_id = printer_id.substr(separator + 1);
+  return true;
+}
+
 PrinterProviderAPI::PrintError APIPrintErrorToInternalType(
     core_api::printer_provider_internal::PrintError error) {
   switch (error) {
@@ -100,9 +129,15 @@
 }
 
 void PrinterProviderAPI::DispatchGetCapabilityRequested(
-    const std::string& extension_id,
     const std::string& printer_id,
     const PrinterProviderAPI::GetCapabilityCallback& callback) {
+  std::string extension_id;
+  std::string internal_printer_id;
+  if (!ParsePrinterId(printer_id, &extension_id, &internal_printer_id)) {
+    callback.Run(base::DictionaryValue());
+    return;
+  }
+
   EventRouter* event_router = EventRouter::Get(browser_context_);
   if (!event_router->ExtensionHasEventListener(
           extension_id,
@@ -117,7 +152,7 @@
   // Request id is not part of the public API, but it will be massaged out in
   // custom bindings.
   internal_args->AppendInteger(request_id);
-  internal_args->AppendString(printer_id);
+  internal_args->AppendString(internal_printer_id);
 
   scoped_ptr<Event> event(new Event(
       core_api::printer_provider::OnGetCapabilityRequested::kEventName,
@@ -127,9 +162,15 @@
 }
 
 void PrinterProviderAPI::DispatchPrintRequested(
-    const std::string& extension_id,
     const PrinterProviderAPI::PrintJob& job,
     const PrinterProviderAPI::PrintCallback& callback) {
+  std::string extension_id;
+  std::string internal_printer_id;
+  if (!ParsePrinterId(job.printer_id, &extension_id, &internal_printer_id)) {
+    callback.Run(PRINT_ERROR_FAILED);
+    return;
+  }
+
   EventRouter* event_router = EventRouter::Get(browser_context_);
   if (!event_router->ExtensionHasEventListener(
           extension_id,
@@ -139,7 +180,7 @@
   }
 
   core_api::printer_provider::PrintJob print_job;
-  print_job.printer_id = job.printer_id;
+  print_job.printer_id = internal_printer_id;
   print_job.content_type = job.content_type;
   print_job.document =
       std::vector<char>(job.document_bytes.begin(), job.document_bytes.end());
@@ -268,11 +309,26 @@
   return true;
 }
 
-void PrinterProviderAPI::OnGetPrintersResult(const Extension* extension,
-                                             int request_id,
-                                             const base::ListValue& result) {
+void PrinterProviderAPI::OnGetPrintersResult(
+    const Extension* extension,
+    int request_id,
+    const PrinterProviderInternalAPIObserver::PrinterInfoVector& result) {
+  base::ListValue printer_list;
+
+  // Update some printer description properties to better identify the extension
+  // managing the printer.
+  for (size_t i = 0; i < result.size(); ++i) {
+    scoped_ptr<base::DictionaryValue> printer(result[i]->ToValue());
+    std::string internal_printer_id;
+    CHECK(printer->GetString("id", &internal_printer_id));
+    printer->SetString("id",
+                       GeneratePrinterId(extension->id(), internal_printer_id));
+    printer->SetString("extensionId", extension->id());
+    printer_list.Append(printer.release());
+  }
+
   pending_get_printers_requests_.CompleteForExtension(extension->id(),
-                                                      request_id, result);
+                                                      request_id, printer_list);
 }
 
 void PrinterProviderAPI::OnGetCapabilityResult(
diff --git a/extensions/browser/api/printer_provider/printer_provider_api.h b/extensions/browser/api/printer_provider/printer_provider_api.h
index fbec8b3a9..04fde74b 100644
--- a/extensions/browser/api/printer_provider/printer_provider_api.h
+++ b/extensions/browser/api/printer_provider/printer_provider_api.h
@@ -49,9 +49,11 @@
     PrintJob();
     ~PrintJob();
 
-    // The id of the printer that should handle the print job. This identifies
-    // a printer within an extension and is provided by the extension via
-    // chrome.printerProvider.onGetPrintersRequested event callback.
+    // The id of the printer that should handle the print job. The id is
+    // formatted as <extension_id>:<printer_id>, where <extension_id> is the
+    // id of the extension that manages the printer, and <printer_id> is
+    // the the printer's id within the extension (as reported via
+    // chrome.printerProvider.onGetPrintersRequested event callback).
     std::string printer_id;
 
     // The print job ticket.
@@ -83,25 +85,28 @@
   // supported printers. The printer values reported by an extension are
   // added "extensionId" property that is set to the ID of the extension
   // returning the list.
+  // Note that the "id" property of printer values reported by an extension are
+  // rewriten as "<extension_id>:<id>" to ensure they are unique across
+  // different extensions.
   void DispatchGetPrintersRequested(const GetPrintersCallback& callback);
 
-  // Requests printer capability from the extension with id |extension_id| for
-  // the printer with id |printer_id|. |printer_id| should be one of the printer
-  // ids reported by |GetPrinters| callback.
+  // Requests printer capability for a printer with id |printer_id|.
+  // |printer_id| should be one of the printer ids reported by |GetPrinters|
+  // callback.
   // It dispatches chrome.printerProvider.onGetCapabilityRequested event
-  // to the extension.
+  // to the extension that manages the printer (which can be determined from
+  // |printer_id| value).
   // |callback| is passed a dictionary value containing printer capabilities as
   // reported by the extension.
-  void DispatchGetCapabilityRequested(const std::string& extension_id,
-                                      const std::string& printer_id,
+  void DispatchGetCapabilityRequested(const std::string& printer_id,
                                       const GetCapabilityCallback& callback);
 
-  // It dispatches chrome.printerProvider.onPrintRequested event to the
-  // extension with id |extension_id| with the provided print job.
+  // It dispatches chrome.printerProvider.onPrintRequested event with the
+  // provided print job. The event is dispatched only to the extension that
+  // manages printer with id |job.printer_id|.
   // |callback| is passed the print status returned by the extension, and it
   // must not be null.
-  void DispatchPrintRequested(const std::string& extension_id,
-                              const PrintJob& job,
+  void DispatchPrintRequested(const PrintJob& job,
                               const PrintCallback& callback);
 
  private:
@@ -207,9 +212,11 @@
   static const char* service_name() { return "PrinterProvider"; }
 
   // PrinterProviderInternalAPIObserver implementation:
-  void OnGetPrintersResult(const Extension* extension,
-                           int request_id,
-                           const base::ListValue& result) override;
+  void OnGetPrintersResult(
+      const Extension* extension,
+      int request_id,
+      const PrinterProviderInternalAPIObserver::PrinterInfoVector& result)
+      override;
   void OnGetCapabilityResult(const Extension* extension,
                              int request_id,
                              const base::DictionaryValue& result) override;
diff --git a/extensions/browser/api/printer_provider/printer_provider_apitest.cc b/extensions/browser/api/printer_provider/printer_provider_apitest.cc
index 3be5c56..0dd8df0 100644
--- a/extensions/browser/api/printer_provider/printer_provider_apitest.cc
+++ b/extensions/browser/api/printer_provider/printer_provider_apitest.cc
@@ -72,14 +72,14 @@
   void StartPrintRequest(const std::string& extension_id,
                          const PrinterProviderAPI::PrintCallback& callback) {
     PrinterProviderAPI::PrintJob job;
-    job.printer_id = "printer_id";
+    job.printer_id = extension_id + ":printer_id";
     job.ticket_json = "{}";
     job.content_type = "content_type";
     job.document_bytes = "bytes";
 
     PrinterProviderAPI::GetFactoryInstance()
         ->Get(browser_context())
-        ->DispatchPrintRequested(extension_id, job, callback);
+        ->DispatchPrintRequested(job, callback);
   }
 
   void StartCapabilityRequest(
@@ -87,7 +87,8 @@
       const PrinterProviderAPI::GetCapabilityCallback& callback) {
     PrinterProviderAPI::GetFactoryInstance()
         ->Get(browser_context())
-        ->DispatchGetCapabilityRequested(extension_id, "printer_id", callback);
+        ->DispatchGetCapabilityRequested(extension_id + ":printer_id",
+                                         callback);
   }
 
   // Loads chrome.printerProvider test app and initializes is for test
@@ -266,15 +267,15 @@
   expected_printers.push_back(base::StringPrintf(
       "{"
       "\"description\":\"Test printer\","
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printer1\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printer1\","
       "\"name\":\"Printer 1\""
       "}",
       extension_id.c_str()));
   expected_printers.push_back(base::StringPrintf(
       "{"
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printerNoDesc\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printerNoDesc\","
       "\"name\":\"Printer 2\""
       "}",
       extension_id.c_str()));
@@ -304,8 +305,8 @@
   expected_printers.push_back(base::StringPrintf(
       "{"
       "\"description\":\"Test printer\","
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printer1\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printer1\","
       "\"name\":\"Printer 1\""
       "}",
       extension_id.c_str()));
@@ -342,30 +343,30 @@
   expected_printers.push_back(base::StringPrintf(
       "{"
       "\"description\":\"Test printer\","
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printer1\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printer1\","
       "\"name\":\"Printer 1\""
       "}",
       extension_id_1.c_str()));
   expected_printers.push_back(base::StringPrintf(
       "{"
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printerNoDesc\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printerNoDesc\","
       "\"name\":\"Printer 2\""
       "}",
       extension_id_1.c_str()));
   expected_printers.push_back(base::StringPrintf(
       "{"
       "\"description\":\"Test printer\","
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printer1\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printer1\","
       "\"name\":\"Printer 1\""
       "}",
       extension_id_2.c_str()));
   expected_printers.push_back(base::StringPrintf(
       "{"
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printerNoDesc\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printerNoDesc\","
       "\"name\":\"Printer 2\""
       "}",
       extension_id_2.c_str()));
@@ -403,15 +404,15 @@
   expected_printers.push_back(base::StringPrintf(
       "{"
       "\"description\":\"Test printer\","
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printer1\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printer1\","
       "\"name\":\"Printer 1\""
       "}",
       extension_id_2.c_str()));
   expected_printers.push_back(base::StringPrintf(
       "{"
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printerNoDesc\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printerNoDesc\","
       "\"name\":\"Printer 2\""
       "}",
       extension_id_2.c_str()));
@@ -449,15 +450,15 @@
   expected_printers.push_back(base::StringPrintf(
       "{"
       "\"description\":\"Test printer\","
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printer1\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printer1\","
       "\"name\":\"Printer 1\""
       "}",
       extension_id_2.c_str()));
   expected_printers.push_back(base::StringPrintf(
       "{"
-      "\"extensionId\":\"%s\","
-      "\"id\":\"printerNoDesc\","
+      "\"extensionId\":\"%1$s\","
+      "\"id\":\"%1$s:printerNoDesc\","
       "\"name\":\"Printer 2\""
       "}",
       extension_id_2.c_str()));
diff --git a/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc b/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc
index a5bd9eb..e887965 100644
--- a/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc
+++ b/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc
@@ -47,7 +47,7 @@
 void PrinterProviderInternalAPI::NotifyGetPrintersResult(
     const Extension* extension,
     int request_id,
-    const base::ListValue& printers) {
+    const PrinterProviderInternalAPIObserver::PrinterInfoVector& printers) {
   FOR_EACH_OBSERVER(PrinterProviderInternalAPIObserver, observers_,
                     OnGetPrintersResult(extension, request_id, printers));
 }
@@ -132,17 +132,17 @@
 
   base::ListValue printers;
   if (params->printers) {
-    for (size_t i = 0; i < params->printers->size(); ++i) {
-      scoped_ptr<base::DictionaryValue> printer(
-          params->printers->at(i)->ToValue());
-      printer->SetString("extensionId", extension()->id());
-      printers.Append(printer.release());
-    }
+    PrinterProviderInternalAPI::GetFactoryInstance()
+        ->Get(browser_context())
+        ->NotifyGetPrintersResult(extension(), params->request_id,
+                                  *params->printers);
+  } else {
+    PrinterProviderInternalAPI::GetFactoryInstance()
+        ->Get(browser_context())
+        ->NotifyGetPrintersResult(
+            extension(), params->request_id,
+            PrinterProviderInternalAPIObserver::PrinterInfoVector());
   }
-
-  PrinterProviderInternalAPI::GetFactoryInstance()
-      ->Get(browser_context())
-      ->NotifyGetPrintersResult(extension(), params->request_id, printers);
   return RespondNow(NoArguments());
 }
 
diff --git a/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h b/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h
index f2493027..ac34c50 100644
--- a/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h
+++ b/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h
@@ -49,9 +49,10 @@
   // Notifies observers that a printerProvider.onGetPrintersRequested callback
   // has been called. Called from
   // |PrinterProviderInternalReportPrintersFunction|.
-  void NotifyGetPrintersResult(const Extension* extension,
-                               int request_id,
-                               const base::ListValue& printers);
+  void NotifyGetPrintersResult(
+      const Extension* extension,
+      int request_id,
+      const PrinterProviderInternalAPIObserver::PrinterInfoVector& printers);
 
   // Notifies observers that a printerProvider.onGetCapabilityRequested callback
   // has been called. Called from
diff --git a/extensions/browser/api/printer_provider_internal/printer_provider_internal_api_observer.h b/extensions/browser/api/printer_provider_internal/printer_provider_internal_api_observer.h
index 86337aa5..02cbacd8a6 100644
--- a/extensions/browser/api/printer_provider_internal/printer_provider_internal_api_observer.h
+++ b/extensions/browser/api/printer_provider_internal/printer_provider_internal_api_observer.h
@@ -5,6 +5,9 @@
 #ifndef EXTENSIONS_BROWSER_API_PRINTER_PROVIDER_INTERNAL_PRINTER_PROVIDER_INTERNAL_API_OBSERVER_H_
 #define EXTENSIONS_BROWSER_API_PRINTER_PROVIDER_INTERNAL_PRINTER_PROVIDER_INTERNAL_API_OBSERVER_H_
 
+#include <vector>
+
+#include "extensions/common/api/printer_provider.h"
 #include "extensions/common/api/printer_provider_internal.h"
 
 namespace base {
@@ -19,6 +22,9 @@
 // Interface for observing chrome.printerProviderInternal API function calls.
 class PrinterProviderInternalAPIObserver {
  public:
+  using PrinterInfoVector =
+      std::vector<linked_ptr<core_api::printer_provider::PrinterInfo>>;
+
   // Used by chrome.printerProviderInternal API to report
   // chrome.printerProvider.onGetPrintersRequested result returned by the
   // extension |extension|.
@@ -26,7 +32,7 @@
   // chrome.printerProvider.onGetPrintersRequested event.
   virtual void OnGetPrintersResult(const Extension* extension,
                                    int request_id,
-                                   const base::ListValue& result) = 0;
+                                   const PrinterInfoVector& result) = 0;
 
   // Used by chrome.printerProviderInternal API to report
   // chrome.printerProvider.onGetCapabilityRequested result returned by the
diff --git a/extensions/browser/api_unittest.cc b/extensions/browser/api_unittest.cc
index c7023a1d..ab8fc276 100644
--- a/extensions/browser/api_unittest.cc
+++ b/extensions/browser/api_unittest.cc
@@ -32,8 +32,6 @@
 
 ApiUnitTest::ApiUnitTest()
     : notification_service_(content::NotificationService::Create()) {
-  extensions_browser_client()->set_extension_system_factory(
-      &extension_system_factory_);
 }
 
 ApiUnitTest::~ApiUnitTest() {
diff --git a/extensions/browser/api_unittest.h b/extensions/browser/api_unittest.h
index f26629d..dcb09fa 100644
--- a/extensions/browser/api_unittest.h
+++ b/extensions/browser/api_unittest.h
@@ -11,7 +11,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/testing_pref_service.h"
 #include "extensions/browser/extensions_test.h"
-#include "extensions/browser/mock_extension_system.h"
 
 namespace base {
 class Value;
@@ -92,8 +91,6 @@
   scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
   TestingPrefServiceSimple testing_pref_service_;
 
-  MockExtensionSystemFactory<MockExtensionSystem> extension_system_factory_;
-
   // The WebContents used to associate a RenderViewHost with API function calls,
   // or null.
   scoped_ptr<content::WebContents> contents_;
diff --git a/extensions/browser/app_window/app_delegate.h b/extensions/browser/app_window/app_delegate.h
index 70f9f12..36bcc92 100644
--- a/extensions/browser/app_window/app_delegate.h
+++ b/extensions/browser/app_window/app_delegate.h
@@ -50,7 +50,7 @@
   virtual void AddNewContents(content::BrowserContext* context,
                               content::WebContents* new_contents,
                               WindowOpenDisposition disposition,
-                              const gfx::Rect& initial_pos,
+                              const gfx::Rect& initial_rect,
                               bool user_gesture,
                               bool* was_blocked) = 0;
 
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc
index fe9b758..9256228d 100644
--- a/extensions/browser/app_window/app_window.cc
+++ b/extensions/browser/app_window/app_window.cc
@@ -373,14 +373,14 @@
 void AppWindow::AddNewContents(WebContents* source,
                                WebContents* new_contents,
                                WindowOpenDisposition disposition,
-                               const gfx::Rect& initial_pos,
+                               const gfx::Rect& initial_rect,
                                bool user_gesture,
                                bool* was_blocked) {
   DCHECK(new_contents->GetBrowserContext() == browser_context_);
   app_delegate_->AddNewContents(browser_context_,
                                 new_contents,
                                 disposition,
-                                initial_pos,
+                                initial_rect,
                                 user_gesture,
                                 was_blocked);
 }
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h
index 3eef866..8d6ffea1 100644
--- a/extensions/browser/app_window/app_window.h
+++ b/extensions/browser/app_window/app_window.h
@@ -394,7 +394,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   bool PreHandleKeyboardEvent(content::WebContents* source,
diff --git a/extensions/browser/crx_file_info.cc b/extensions/browser/crx_file_info.cc
new file mode 100644
index 0000000..34c48820
--- /dev/null
+++ b/extensions/browser/crx_file_info.cc
@@ -0,0 +1,36 @@
+// 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 "extensions/browser/crx_file_info.h"
+
+#include "base/logging.h"
+
+namespace extensions {
+
+CRXFileInfo::CRXFileInfo() : path() {
+}
+
+CRXFileInfo::CRXFileInfo(const std::string& i,
+                         const base::FilePath& p,
+                         const std::string& h)
+    : extension_id(i), path(p), expected_hash(h) {
+  DCHECK(!path.empty());
+}
+
+CRXFileInfo::CRXFileInfo(const std::string& i, const base::FilePath& p)
+    : extension_id(i), path(p), expected_hash() {
+  DCHECK(!path.empty());
+}
+
+CRXFileInfo::CRXFileInfo(const base::FilePath& p)
+    : extension_id(), path(p), expected_hash() {
+  DCHECK(!path.empty());
+}
+
+bool CRXFileInfo::operator==(const CRXFileInfo& that) const {
+  return extension_id == that.extension_id && path == that.path &&
+         expected_hash == that.expected_hash;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/crx_file_info.h b/extensions/browser/crx_file_info.h
new file mode 100644
index 0000000..49a5341
--- /dev/null
+++ b/extensions/browser/crx_file_info.h
@@ -0,0 +1,34 @@
+// 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 EXTENSIONS_BROWSER_CRX_FILE_INFO_H_
+#define EXTENSIONS_BROWSER_CRX_FILE_INFO_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+
+namespace extensions {
+
+// CRXFileInfo holds general information about a cached CRX file
+struct CRXFileInfo {
+  CRXFileInfo();
+  CRXFileInfo(const std::string& extension_id,
+              const base::FilePath& path,
+              const std::string& hash);
+  CRXFileInfo(const std::string& extension_id, const base::FilePath& path);
+  explicit CRXFileInfo(const base::FilePath& path);
+
+  bool operator==(const CRXFileInfo& that) const;
+
+  // The only mandatory field is the file path, whereas extension_id and hash
+  // are only being checked if those are non-empty.
+  std::string extension_id;
+  base::FilePath path;
+  std::string expected_hash;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_CRX_FILE_H_
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index ae8e2cd3..ab2f8af 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -995,9 +995,9 @@
   AUTOTESTPRIVATE_SETNATURALSCROLL,
   AUTOTESTPRIVATE_SETMOUSESENSITIVITY,
   AUTOTESTPRIVATE_SETPRIMARYBUTTONRIGHT,
-  COPRESENCEENDPOINTS_CREATELOCALENDPOINT,
-  COPRESENCEENDPOINTS_DESTROYLOCALENDPOINT,
-  COPRESENCEENDPOINTS_SEND,
+  DELETED_COPRESENCEENDPOINTS_CREATELOCALENDPOINT,
+  DELETED_COPRESENCEENDPOINTS_DESTROYLOCALENDPOINT,
+  DELETED_COPRESENCEENDPOINTS_SEND,
   INLINE_INSTALL_PRIVATE_INSTALL,
   LAUNCHERPAGE_SETENABLED,
   CRYPTOTOKENPRIVATE_REQUESTPERMISSION,
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc
index 3125701..7874528 100644
--- a/extensions/browser/extension_host.cc
+++ b/extensions/browser/extension_host.cc
@@ -434,7 +434,7 @@
 void ExtensionHost::AddNewContents(WebContents* source,
                                    WebContents* new_contents,
                                    WindowOpenDisposition disposition,
-                                   const gfx::Rect& initial_pos,
+                                   const gfx::Rect& initial_rect,
                                    bool user_gesture,
                                    bool* was_blocked) {
   // First, if the creating extension view was associated with a tab contents,
@@ -453,7 +453,7 @@
       WebContentsDelegate* delegate = associated_contents->GetDelegate();
       if (delegate) {
         delegate->AddNewContents(
-            associated_contents, new_contents, disposition, initial_pos,
+            associated_contents, new_contents, disposition, initial_rect,
             user_gesture, was_blocked);
         return;
       }
@@ -461,7 +461,7 @@
   }
 
   delegate_->CreateTab(
-      new_contents, extension_id_, disposition, initial_pos, user_gesture);
+      new_contents, extension_id_, disposition, initial_rect, user_gesture);
 }
 
 void ExtensionHost::RenderViewReady() {
diff --git a/extensions/browser/extension_host.h b/extensions/browser/extension_host.h
index 62925fc3..567499b 100644
--- a/extensions/browser/extension_host.h
+++ b/extensions/browser/extension_host.h
@@ -109,7 +109,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   void CloseContents(content::WebContents* contents) override;
diff --git a/extensions/browser/extension_host_delegate.h b/extensions/browser/extension_host_delegate.h
index b14580d5..71c0990 100644
--- a/extensions/browser/extension_host_delegate.h
+++ b/extensions/browser/extension_host_delegate.h
@@ -46,7 +46,7 @@
   virtual void CreateTab(content::WebContents* web_contents,
                          const std::string& extension_id,
                          WindowOpenDisposition disposition,
-                         const gfx::Rect& initial_pos,
+                         const gfx::Rect& initial_rect,
                          bool user_gesture) = 0;
 
   // Requests access to an audio or video media stream. Invokes |callback|
diff --git a/extensions/browser/extensions_test.cc b/extensions/browser/extensions_test.cc
index 103ade09..c6962ed05 100644
--- a/extensions/browser/extensions_test.cc
+++ b/extensions/browser/extensions_test.cc
@@ -32,6 +32,8 @@
   content::SetUtilityClientForTesting(content_utility_client_.get());
   content::SetBrowserClientForTesting(content_browser_client_.get());
   ExtensionsBrowserClient::Set(extensions_browser_client_.get());
+  extensions_browser_client_->set_extension_system_factory(
+      &extension_system_factory_);
 }
 
 ExtensionsTest::~ExtensionsTest() {
diff --git a/extensions/browser/extensions_test.h b/extensions/browser/extensions_test.h
index 3189e27e..e930421 100644
--- a/extensions/browser/extensions_test.h
+++ b/extensions/browser/extensions_test.h
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/public/test/test_renderer_host.h"
+#include "extensions/browser/mock_extension_system.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -61,6 +62,8 @@
   // RenderViewHostTester.
   content::RenderViewHostTestEnabler rvh_test_enabler_;
 
+  MockExtensionSystemFactory<MockExtensionSystem> extension_system_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionsTest);
 };
 
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index e9c25ba2..3641898 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -48,6 +48,7 @@
 #include "net/base/escape.h"
 #include "net/base/net_errors.h"
 #include "ui/base/models/simple_menu_model.h"
+#include "url/url_constants.h"
 
 using base::UserMetricsAction;
 using content::RenderFrameHost;
@@ -879,6 +880,7 @@
   if (scheme_is_blocked || !url.is_valid()) {
     LoadAbort(true /* is_top_level */, url,
               net::ErrorToShortString(net::ERR_ABORTED));
+    NavigateGuest(url::kAboutBlankURL, true /* force_navigation */);
     return;
   }
   if (!force_navigation && (src_ == url))
@@ -1084,13 +1086,13 @@
 void WebViewGuest::AddNewContents(content::WebContents* source,
                                   content::WebContents* new_contents,
                                   WindowOpenDisposition disposition,
-                                  const gfx::Rect& initial_pos,
+                                  const gfx::Rect& initial_rect,
                                   bool user_gesture,
                                   bool* was_blocked) {
   if (was_blocked)
     *was_blocked = false;
   RequestNewWindowPermission(disposition,
-                             initial_pos,
+                             initial_rect,
                              user_gesture,
                              new_contents);
 }
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h
index 35daea01..a7ccfff 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -148,7 +148,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   content::WebContents* OpenURLFromTab(
diff --git a/extensions/browser/mojo/keep_alive_impl_unittest.cc b/extensions/browser/mojo/keep_alive_impl_unittest.cc
index b9ca700..4bdb588b 100644
--- a/extensions/browser/mojo/keep_alive_impl_unittest.cc
+++ b/extensions/browser/mojo/keep_alive_impl_unittest.cc
@@ -7,12 +7,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "content/public/browser/notification_service.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_system.h"
 #include "extensions/browser/extensions_test.h"
-#include "extensions/browser/mock_extension_system.h"
 #include "extensions/browser/process_manager.h"
-#include "extensions/browser/test_extensions_browser_client.h"
 #include "extensions/common/extension_builder.h"
 
 namespace extensions {
@@ -26,9 +22,6 @@
   void SetUp() override {
     ExtensionsTest::SetUp();
     message_loop_.reset(new base::MessageLoop);
-    browser_client_.reset(new TestExtensionsBrowserClient(browser_context()));
-    browser_client_->set_extension_system_factory(&extension_system_factory_);
-    ExtensionsBrowserClient::Set(browser_client_.get());
     extension_ =
         ExtensionBuilder()
             .SetManifest(
@@ -71,10 +64,8 @@
 
  private:
   scoped_ptr<base::MessageLoop> message_loop_;
-  MockExtensionSystemFactory<MockExtensionSystem> extension_system_factory_;
   scoped_ptr<content::NotificationService> notification_service_;
   scoped_refptr<const Extension> extension_;
-  scoped_ptr<TestExtensionsBrowserClient> browser_client_;
 
   DISALLOW_COPY_AND_ASSIGN(KeepAliveTest);
 };
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index cd535a83..76d44e9 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -18,6 +18,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "components/crx_file/constants.h"
@@ -26,6 +27,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/common/common_param_traits.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
 #include "crypto/signature_verifier.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
@@ -35,6 +38,7 @@
 #include "extensions/common/file_util.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
+#include "extensions/common/switches.h"
 #include "grit/extensions_strings.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -209,19 +213,25 @@
 }  // namespace
 
 SandboxedUnpacker::SandboxedUnpacker(
-    const base::FilePath& crx_path,
+    const CRXFileInfo& file,
     Manifest::Location location,
     int creation_flags,
     const base::FilePath& extensions_dir,
     const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner,
     SandboxedUnpackerClient* client)
-    : crx_path_(crx_path),
+    : crx_path_(file.path),
+      package_hash_(file.expected_hash),
+      check_crx_hash_(false),
       client_(client),
       extensions_dir_(extensions_dir),
       got_response_(false),
       location_(location),
       creation_flags_(creation_flags),
       unpacker_io_task_runner_(unpacker_io_task_runner) {
+  if (!package_hash_.empty()) {
+    check_crx_hash_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
+        extensions::switches::kEnableCrxHashCheck);
+  }
 }
 
 bool SandboxedUnpacker::CreateTempDirectory() {
@@ -402,9 +412,49 @@
       l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error));
 }
 
+static size_t ReadAndHash(void* ptr,
+                          size_t size,
+                          size_t nmemb,
+                          FILE* stream,
+                          scoped_ptr<crypto::SecureHash>& hash) {
+  size_t len = fread(ptr, size, nmemb, stream);
+  if (len > 0 && hash) {
+    hash->Update(ptr, len * size);
+  }
+  return len;
+}
+
+bool SandboxedUnpacker::FinalizeHash(scoped_ptr<crypto::SecureHash>& hash) {
+  if (hash) {
+    uint8 output[crypto::kSHA256Length];
+    hash->Finish(output, sizeof(output));
+    bool result = (base::StringToLowerASCII(base::HexEncode(
+                       output, sizeof(output))) == package_hash_);
+    UMA_HISTOGRAM_BOOLEAN("Extensions.SandboxUnpackHashCheck", result);
+    if (!result && check_crx_hash_) {
+      // Package hash verification failed
+      std::string name = crx_path_.BaseName().AsUTF8Unsafe();
+      LOG(ERROR) << "Hash check failed for extension: " << name;
+      ReportFailure(CRX_HASH_VERIFICATION_FAILED,
+                    l10n_util::GetStringFUTF16(
+                        IDS_EXTENSION_PACKAGE_ERROR_CODE,
+                        ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED")));
+      return false;
+    }
+  }
+
+  return true;
+}
+
 bool SandboxedUnpacker::ValidateSignature() {
   base::ScopedFILE file(base::OpenFile(crx_path_, "rb"));
 
+  scoped_ptr<crypto::SecureHash> hash;
+
+  if (!package_hash_.empty()) {
+    hash.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+  }
+
   if (!file.get()) {
 // Could not open crx file for reading.
 #if defined(OS_WIN)
@@ -437,7 +487,7 @@
   // code in the code base.  So for now, this assumes that we're running
   // on a little endian machine with 4 byte alignment.
   CrxFile::Header header;
-  size_t len = fread(&header, 1, sizeof(header), file.get());
+  size_t len = ReadAndHash(&header, 1, sizeof(header), file.get(), hash);
   if (len < sizeof(header)) {
     // Invalid crx header
     ReportFailure(CRX_HEADER_INVALID, l10n_util::GetStringFUTF16(
@@ -492,7 +542,8 @@
 
   std::vector<uint8> key;
   key.resize(header.key_size);
-  len = fread(&key.front(), sizeof(uint8), header.key_size, file.get());
+  len = ReadAndHash(&key.front(), sizeof(uint8), header.key_size, file.get(),
+                    hash);
   if (len < header.key_size) {
     // Invalid public key
     ReportFailure(
@@ -504,8 +555,8 @@
 
   std::vector<uint8> signature;
   signature.resize(header.signature_size);
-  len = fread(&signature.front(), sizeof(uint8), header.signature_size,
-              file.get());
+  len = ReadAndHash(&signature.front(), sizeof(uint8), header.signature_size,
+                    file.get(), hash);
   if (len < header.signature_size) {
     // Invalid signature
     ReportFailure(
@@ -530,7 +581,7 @@
   }
 
   unsigned char buf[1 << 12];
-  while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
+  while ((len = ReadAndHash(buf, 1, sizeof(buf), file.get(), hash)) > 0)
     verifier.VerifyUpdate(buf, len);
 
   if (!verifier.VerifyFinal()) {
@@ -542,6 +593,10 @@
     return false;
   }
 
+  if (!FinalizeHash(hash)) {
+    return false;
+  }
+
   std::string public_key =
       std::string(reinterpret_cast<char*>(&key.front()), key.size());
   base::Base64Encode(public_key, &public_key_);
diff --git a/extensions/browser/sandboxed_unpacker.h b/extensions/browser/sandboxed_unpacker.h
index 60a5bbd..398600bf 100644
--- a/extensions/browser/sandboxed_unpacker.h
+++ b/extensions/browser/sandboxed_unpacker.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "content/public/browser/utility_process_host_client.h"
+#include "extensions/browser/crx_file_info.h"
 #include "extensions/common/manifest.h"
 
 class SkBitmap;
@@ -21,6 +22,10 @@
 class SequencedTaskRunner;
 }
 
+namespace crypto {
+class SecureHash;
+}
+
 namespace extensions {
 class Extension;
 
@@ -79,7 +84,7 @@
   // |client| with the result. If |run_out_of_process| is provided, unpacking
   // is done in a sandboxed subprocess. Otherwise, it is done in-process.
   SandboxedUnpacker(
-      const base::FilePath& crx_path,
+      const CRXFileInfo& file,
       Manifest::Location location,
       int creation_flags,
       const base::FilePath& extensions_dir,
@@ -148,6 +153,9 @@
     ERROR_SERIALIZING_CATALOG,
     ERROR_SAVING_CATALOG,
 
+    // SandboxedUnpacker::ValidateSignature()
+    CRX_HASH_VERIFICATION_FAILED,
+
     NUM_FAILURE_REASONS
   };
 
@@ -160,6 +168,11 @@
   // Return true on success.
   virtual bool CreateTempDirectory();
 
+  // Finalizes hash calculation and checks the result against the expected
+  // package hash. In case of mismatch, depending on the command-line option,
+  // we will either fail installation, or just update histograms.
+  bool FinalizeHash(scoped_ptr<crypto::SecureHash>& hash);
+
   // Validates the signature of the extension and extract the key to
   // |public_key_|. Returns true if the signature validates, false otherwise.
   //
@@ -202,6 +215,12 @@
   // The path to the CRX to unpack.
   base::FilePath crx_path_;
 
+  // The package hash that was reported from the Web Store.
+  std::string package_hash_;
+
+  // Whether we need to check the .crx hash sum.
+  bool check_crx_hash_;
+
   // Our client.
   scoped_refptr<SandboxedUnpackerClient> client_;
 
diff --git a/extensions/browser/sandboxed_unpacker_unittest.cc b/extensions/browser/sandboxed_unpacker_unittest.cc
index 7451b28..5d4281b 100644
--- a/extensions/browser/sandboxed_unpacker_unittest.cc
+++ b/extensions/browser/sandboxed_unpacker_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
@@ -17,6 +18,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_paths.h"
+#include "extensions/common/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
@@ -32,6 +34,7 @@
   }
 
   base::FilePath temp_dir() const { return temp_dir_; }
+  base::string16 unpack_err() const { return error_; }
 
  private:
   ~MockSandboxedUnpackerClient() override {}
@@ -46,9 +49,11 @@
   }
 
   void OnUnpackFailure(const base::string16& error) override {
-    ASSERT_TRUE(false);
+    error_ = error;
+    quit_closure_.Run();
   }
 
+  base::string16 error_;
   base::Closure quit_closure_;
   base::FilePath temp_dir_;
 };
@@ -74,15 +79,17 @@
     ExtensionsTest::TearDown();
   }
 
-  void SetupUnpacker(const std::string& crx_name) {
+  void SetupUnpacker(const std::string& crx_name,
+                     const std::string& package_hash) {
     base::FilePath original_path;
     ASSERT_TRUE(PathService::Get(extensions::DIR_TEST_DATA, &original_path));
     original_path = original_path.AppendASCII("unpacker").AppendASCII(crx_name);
     ASSERT_TRUE(base::PathExists(original_path)) << original_path.value();
 
     sandboxed_unpacker_ = new SandboxedUnpacker(
-        original_path, Manifest::INTERNAL, Extension::NO_FLAGS,
-        extensions_dir_.path(), base::MessageLoopProxy::current(), client_);
+        extensions::CRXFileInfo(std::string(), original_path, package_hash),
+        Manifest::INTERNAL, Extension::NO_FLAGS, extensions_dir_.path(),
+        base::MessageLoopProxy::current(), client_);
 
     base::MessageLoopProxy::current()->PostTask(
         FROM_HERE,
@@ -94,6 +101,8 @@
     return client_->temp_dir().AppendASCII(kTempExtensionName);
   }
 
+  base::string16 GetInstallError() { return client_->unpack_err(); }
+
  protected:
   base::ScopedTempDir extensions_dir_;
   MockSandboxedUnpackerClient* client_;
@@ -104,17 +113,41 @@
 };
 
 TEST_F(SandboxedUnpackerTest, NoCatalogsSuccess) {
-  SetupUnpacker("no_l10n.crx");
+  SetupUnpacker("no_l10n.crx", "");
   // Check that there is no _locales folder.
   base::FilePath install_path = GetInstallPath().Append(kLocaleFolder);
   EXPECT_FALSE(base::PathExists(install_path));
 }
 
 TEST_F(SandboxedUnpackerTest, WithCatalogsSuccess) {
-  SetupUnpacker("good_l10n.crx");
+  SetupUnpacker("good_l10n.crx", "");
   // Check that there is _locales folder.
   base::FilePath install_path = GetInstallPath().Append(kLocaleFolder);
   EXPECT_TRUE(base::PathExists(install_path));
 }
 
+TEST_F(SandboxedUnpackerTest, FailHashCheck) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      extensions::switches::kEnableCrxHashCheck);
+  SetupUnpacker("good_l10n.crx", "badhash");
+  // Check that there is an error message.
+  EXPECT_NE(base::string16(), GetInstallError());
+}
+
+TEST_F(SandboxedUnpackerTest, PassHashCheck) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      extensions::switches::kEnableCrxHashCheck);
+  SetupUnpacker(
+      "good_l10n.crx",
+      "6fa171c726373785aa4fcd2df448c3db0420a95d5044fbee831f089b979c4068");
+  // Check that there is no error message.
+  EXPECT_EQ(base::string16(), GetInstallError());
+}
+
+TEST_F(SandboxedUnpackerTest, SkipHashCheck) {
+  SetupUnpacker("good_l10n.crx", "badhash");
+  // Check that there is no error message.
+  EXPECT_EQ(base::string16(), GetInstallError());
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/updater/extension_downloader.cc b/extensions/browser/updater/extension_downloader.cc
index da4ff410..3e06083 100644
--- a/extensions/browser/updater/extension_downloader.cc
+++ b/extensions/browser/updater/extension_downloader.cc
@@ -731,13 +731,10 @@
     scoped_ptr<ExtensionFetch> fetch_data,
     const base::FilePath& crx_path,
     bool file_ownership_passed) {
-  delegate_->OnExtensionDownloadFinished(fetch_data->id,
-                                         crx_path,
-                                         file_ownership_passed,
-                                         fetch_data->url,
-                                         fetch_data->version,
-                                         ping_results_[fetch_data->id],
-                                         fetch_data->request_ids);
+  delegate_->OnExtensionDownloadFinished(
+      CRXFileInfo(fetch_data->id, crx_path, fetch_data->package_hash),
+      file_ownership_passed, fetch_data->url, fetch_data->version,
+      ping_results_[fetch_data->id], fetch_data->request_ids);
   ping_results_.erase(fetch_data->id);
 }
 
diff --git a/extensions/browser/updater/extension_downloader_delegate.h b/extensions/browser/updater/extension_downloader_delegate.h
index aed6885..2e5eaa5 100644
--- a/extensions/browser/updater/extension_downloader_delegate.h
+++ b/extensions/browser/updater/extension_downloader_delegate.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/time/time.h"
+#include "extensions/browser/crx_file_info.h"
 #include "extensions/browser/updater/manifest_fetch_data.h"
 
 class GURL;
@@ -82,8 +83,7 @@
   // successfully downloaded to |path|. |ownership_passed| is true if delegate
   // should get ownership of the file.
   virtual void OnExtensionDownloadFinished(
-      const std::string& id,
-      const base::FilePath& path,
+      const CRXFileInfo& file,
       bool file_ownership_passed,
       const GURL& download_url,
       const std::string& version,
diff --git a/extensions/browser/updater/update_service.cc b/extensions/browser/updater/update_service.cc
index ece627a..10a86c3 100644
--- a/extensions/browser/updater/update_service.cc
+++ b/extensions/browser/updater/update_service.cc
@@ -53,8 +53,7 @@
 }
 
 void UpdateService::OnExtensionDownloadFinished(
-    const std::string& id,
-    const base::FilePath& path,
+    const CRXFileInfo& file,
     bool file_ownership_passed,
     const GURL& download_url,
     const std::string& version,
diff --git a/extensions/browser/updater/update_service.h b/extensions/browser/updater/update_service.h
index 008917d..2f4cd80 100644
--- a/extensions/browser/updater/update_service.h
+++ b/extensions/browser/updater/update_service.h
@@ -48,8 +48,7 @@
                                  Error error,
                                  const PingResult& ping,
                                  const std::set<int>& request_ids) override;
-  void OnExtensionDownloadFinished(const std::string& id,
-                                   const base::FilePath& path,
+  void OnExtensionDownloadFinished(const CRXFileInfo& file,
                                    bool file_ownership_passed,
                                    const GURL& download_url,
                                    const std::string& version,
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 68e3fa3..c42f525 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -106,9 +106,9 @@
     "dependencies": ["permission:declarativeWebRequest"],
     "contexts": ["blessed_extension"]
   },
-  "copresenceEndpoints": {
-    "channel" : "canary",
-    "dependencies": ["permission:copresence"],
+  "diagnostics": {
+    "dependencies": ["permission:diagnostics"],
+    "extension_types": ["platform_app"],
     "contexts": ["blessed_extension"]
   },
   "dns": {
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index 9f24ab9..d2f39ff 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -151,6 +151,21 @@
       "channel": "beta",
       "extension_types": ["extension", "legacy_packaged_app"]
   },
+  "diagnostics": [
+    {
+      "channel": "dev",
+      "extension_types": ["platform_app"]
+    },
+    {
+      "channel": "stable",
+      "extension_types": ["platform_app"],
+      "whitelist": [
+        "7AE714FFD394E073F0294CFA134C9F91DB5FBAA4",  // CCD Development
+        "C7DA3A55C2355F994D3FDDAD120B426A0DF63843",  // CCD Testing
+        "75E3CFFFC530582C583E4690EF97C70B9C8423B7"   // CCD Release
+      ]
+    }
+  ],
   "dns": [
     {
       "channel": "dev",
diff --git a/extensions/common/api/copresence_endpoints.idl b/extensions/common/api/copresence_endpoints.idl
deleted file mode 100644
index b77bde4b..0000000
--- a/extensions/common/api/copresence_endpoints.idl
+++ /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.
-
-// Use the <code>chrome.copresenceEndpoints</code> API to create persistent
-// sockets to send data to and receive from data nearby devices.
-namespace copresenceEndpoints {
-  // Result of the <code>createEndpoint</code> call.
-  [noinline_doc] dictionary EndpointInfo {
-    // The ID of the newly created endpoint.
-    long endpointId;
-
-    // An opaque string containing the locator data for this endpoint. This
-    // locator is needed to connect to this endpoint.
-    DOMString locator;
-  };
-
-  // Data from an <code>onReceive</code> event.
-  [noinline_doc] dictionary ReceiveInfo {
-    // The local endpoint this data is for.
-    long localEndpointId;
-
-    // The remote endpoint this data came from.
-    long remoteEndpointId;
-
-    // The data received.
-    ArrayBuffer data;
-  };
-
-  // Status of a socket operation.
-  enum EndpointStatus {
-    // There was no error in the previous operation.
-    no_error,
-
-    // The socket was disconnected.
-    disconnected,
-
-    // The local endpoint id provided is invalid.
-    invalid_local_endpoint,
-
-    // The remote endpoint id provided is invalid.
-    invalid_remote_endpoint,
-
-    // There was a failure during connection.
-    connect_failure,
-
-    // There was an error while trying to send data.
-    send_failure,
-
-    // There was an error while trying to receive data.
-    receive_failure
-  };
-
-  // Callback from the <code>createEndpoint</code> method.
-  // |endpointInfo| : The result of the endpoint creation.
-  callback CreateCallback = void (EndpointInfo endpointInfo);
-
-  // Callback from the <code>send</code> method.
-  // |status| : Status of the send operation.
-  callback SendCallback = void (EndpointStatus status);
-
-  // These functions all report failures via chrome.runtime.lastError.
-  interface Functions {
-    // Endpoint functions.
-
-    // Creates a endpoint that can be connected to by a nearby devices.
-    // |callback| : Called when the endpoint has been created.
-    static void createLocalEndpoint(CreateCallback callback);
-
-    // Destroys the endpoint. This will close any connections to this endpoint
-    // from remote hosts and will prevent any further connections to it.
-    // |endpointId|: Endpoint ID returned by <code>createEndpoint</code>.
-    static void destroyEndpoint(long endpointId);
-
-    // Sends data from a local Copresence endpoint to a remote endpoint.
-    // |localEndpointId| : The local endpoint identifier.
-    // |remoteEndpointId| : The remote endpoint identifier.
-    // |data| : The data to send.
-    // |callback| : Called when the <code>send</code> operation completes.
-    static void send(long localEndpointId, long remoteEndpointId,
-                     ArrayBuffer data, optional SendCallback callback);
-  };
-
-  interface Events {
-    // Event raised when data has been received for a given socket.
-    // |info| : The event data.
-    static void onReceive(ReceiveInfo info);
-
-    // Event raised when a endpoint receives a new connection. A new socket is
-    // created and the id is passed to this event via socketId.
-    // |localEndpointId| : ID of the local endpoint that received this
-    //                     connection.
-    // TODO(rkc): This API needs to be modified to give a valid remote endpoint
-    // id also. This currently doesn't happen because of the lack of a
-    // handshake on a sockets connection. Once we have a handshake, modify this
-    // API to also return a remote endpoint id.
-    static void onConnected(long localEndpointId);
-  };
-};
diff --git a/chrome/common/extensions/api/diagnostics.idl b/extensions/common/api/diagnostics.idl
similarity index 100%
rename from chrome/common/extensions/api/diagnostics.idl
rename to extensions/common/api/diagnostics.idl
diff --git a/extensions/common/api/schemas.gypi b/extensions/common/api/schemas.gypi
index ab8f880..0d170f9 100644
--- a/extensions/common/api/schemas.gypi
+++ b/extensions/common/api/schemas.gypi
@@ -20,7 +20,6 @@
       'bluetooth_private.json',
       'bluetooth_socket.idl',
       'cast_channel.idl',
-      'copresence_endpoints.idl',
       'dns.idl',
       'events.json',
       'extensions_manifest_types.json',
@@ -59,6 +58,7 @@
     ],
     # ChromeOS-specific schemas.
     'chromeos_schema_files': [
+      'diagnostics.idl',
       'networking_config.idl',
       'vpn_provider.idl',
       'webcam_private.idl',
diff --git a/extensions/common/permissions/extensions_api_permissions.cc b/extensions/common/permissions/extensions_api_permissions.cc
index 825ccf2..d9a811e 100644
--- a/extensions/common/permissions/extensions_api_permissions.cc
+++ b/extensions/common/permissions/extensions_api_permissions.cc
@@ -61,6 +61,9 @@
        APIPermissionInfo::kFlagNone,
        IDS_EXTENSION_PROMPT_WARNING_DECLARATIVE_WEB_REQUEST,
        PermissionMessage::kDeclarativeWebRequest},
+      {APIPermission::kDiagnostics,
+       "diagnostics",
+       APIPermissionInfo::kFlagCannotBeOptional},
       {APIPermission::kDns, "dns"},
       {APIPermission::kExtensionView,
        "extensionview",
diff --git a/extensions/common/switches.cc b/extensions/common/switches.cc
index fcc6f499..f3ea11a 100644
--- a/extensions/common/switches.cc
+++ b/extensions/common/switches.cc
@@ -101,6 +101,10 @@
 // Pass launch source to platform apps.
 const char kTraceAppSource[] = "enable-trace-app-source";
 
+// Enable package hash check: the .crx file sha256 hash sum should be equal to
+// the one received from update manifest.
+const char kEnableCrxHashCheck[] = "enable-crx-hash-check";
+
 }  // namespace switches
 
 }  // namespace extensions
diff --git a/extensions/common/switches.h b/extensions/common/switches.h
index dcad5c1..a55028b 100644
--- a/extensions/common/switches.h
+++ b/extensions/common/switches.h
@@ -35,6 +35,7 @@
 extern const char kShowComponentExtensionOptions[];
 extern const char kTraceAppSource[];
 extern const char kWhitelistedExtensionID[];
+extern const char kEnableCrxHashCheck[];
 
 }  // namespace switches
 
diff --git a/extensions/common/update_manifest.cc b/extensions/common/update_manifest.cc
index 26d794f..57162da 100644
--- a/extensions/common/update_manifest.cc
+++ b/extensions/common/update_manifest.cc
@@ -187,9 +187,9 @@
     }
   }
 
-  // package_hash is optional. It is only required for blacklist. It is a
-  // sha256 hash of the package in hex format.
-  result->package_hash = GetAttribute(updatecheck, "hash");
+  // package_hash is optional. It is a sha256 hash of the package in hex
+  // format.
+  result->package_hash = GetAttribute(updatecheck, "hash_sha256");
 
   int size = 0;
   if (base::StringToInt(GetAttribute(updatecheck, "size"), &size)) {
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index a0e4370..ac43483 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -321,7 +321,6 @@
       'dependencies': [
         '../base/base.gyp:base',
         '../base/base.gyp:base_prefs',
-        '../components/components.gyp:copresence_endpoints',
         '../components/components.gyp:keyed_service_content',
         '../components/components.gyp:keyed_service_core',
         '../components/components.gyp:onc_component',
@@ -431,10 +430,6 @@
         'browser/api/cast_channel/logger.h',
         'browser/api/cast_channel/logger_util.cc',
         'browser/api/cast_channel/logger_util.h',
-        'browser/api/copresence_endpoints/copresence_endpoints_api.cc',
-        'browser/api/copresence_endpoints/copresence_endpoints_api.h',
-        'browser/api/copresence_endpoints/copresence_endpoint_resource.cc',
-        'browser/api/copresence_endpoints/copresence_endpoint_resource.h',
         'browser/api/declarative/deduping_factory.h',
         'browser/api/declarative/declarative_api.cc',
         'browser/api/declarative/declarative_api.h',
@@ -666,6 +661,8 @@
         'browser/content_verifier_io_data.h',
         'browser/content_verify_job.cc',
         'browser/content_verify_job.h',
+        'browser/crx_file_info.cc',
+        'browser/crx_file_info.h',
         'browser/error_map.cc',
         'browser/error_map.h',
         'browser/event_listener_map.cc',
@@ -890,6 +887,9 @@
             '../chromeos/chromeos.gyp:chromeos',
           ],
           'sources': [
+            'browser/api/diagnostics/diagnostics_api.cc',
+            'browser/api/diagnostics/diagnostics_api.h',
+            'browser/api/diagnostics/diagnostics_api_chromeos.cc',
             'browser/api/networking_config/networking_config_api.cc',
             'browser/api/networking_config/networking_config_api.h',
             'browser/api/networking_config/networking_config_service.cc',
diff --git a/extensions/extensions_browsertests.isolate b/extensions/extensions_browsertests.isolate
index f0381c0..6cae91bf 100644
--- a/extensions/extensions_browsertests.isolate
+++ b/extensions/extensions_browsertests.isolate
@@ -28,6 +28,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -51,6 +53,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/extensions/renderer/api/serial/data_receiver_unittest.cc b/extensions/renderer/api/serial/data_receiver_unittest.cc
index 1be15969..f699d02 100644
--- a/extensions/renderer/api/serial/data_receiver_unittest.cc
+++ b/extensions/renderer/api/serial/data_receiver_unittest.cc
@@ -7,56 +7,10 @@
 #include "device/serial/data_source_sender.h"
 #include "device/serial/data_stream.mojom.h"
 #include "extensions/renderer/api_test_base.h"
-#include "gin/dictionary.h"
-#include "gin/wrappable.h"
 #include "grit/extensions_renderer_resources.h"
 
 namespace extensions {
 
-class DataReceiverFactory : public gin::Wrappable<DataReceiverFactory> {
- public:
-  using Callback = base::Callback<void(
-      mojo::InterfaceRequest<device::serial::DataSource>,
-      mojo::InterfacePtr<device::serial::DataSourceClient>)>;
-  static gin::Handle<DataReceiverFactory> Create(v8::Isolate* isolate,
-                                                 const Callback& callback) {
-    return gin::CreateHandle(isolate,
-                             new DataReceiverFactory(callback, isolate));
-  }
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override {
-    return Wrappable<DataReceiverFactory>::GetObjectTemplateBuilder(isolate)
-        .SetMethod("create", &DataReceiverFactory::CreateReceiver);
-  }
-
-  gin::Dictionary CreateReceiver() {
-    mojo::InterfacePtr<device::serial::DataSource> sink;
-    mojo::InterfacePtr<device::serial::DataSourceClient> client;
-    mojo::InterfaceRequest<device::serial::DataSourceClient> client_request =
-        mojo::GetProxy(&client);
-    callback_.Run(mojo::GetProxy(&sink), client.Pass());
-
-    gin::Dictionary result = gin::Dictionary::CreateEmpty(isolate_);
-    result.Set("source", sink.PassMessagePipe().release());
-    result.Set("client", client_request.PassMessagePipe().release());
-    return result;
-  }
-
-  static gin::WrapperInfo kWrapperInfo;
-
- private:
-  DataReceiverFactory(const Callback& callback, v8::Isolate* isolate)
-      : callback_(callback), isolate_(isolate) {}
-
-  base::Callback<void(mojo::InterfaceRequest<device::serial::DataSource>,
-                      mojo::InterfacePtr<device::serial::DataSourceClient>)>
-      callback_;
-  v8::Isolate* isolate_;
-};
-
-gin::WrapperInfo DataReceiverFactory::kWrapperInfo = {gin::kEmbedderNativeGin};
-
 // Runs tests defined in extensions/test/data/data_receiver_unittest.js
 class DataReceiverTest : public ApiTestBase {
  public:
@@ -64,13 +18,8 @@
 
   void SetUp() override {
     ApiTestBase::SetUp();
-    gin::ModuleRegistry::From(env()->context()->v8_context())
-        ->AddBuiltinModule(env()->isolate(),
-                           "device/serial/data_receiver_test_factory",
-                           DataReceiverFactory::Create(
-                               env()->isolate(),
-                               base::Bind(&DataReceiverTest::CreateDataSource,
-                                          base::Unretained(this))).ToV8());
+    service_provider()->AddService(base::Bind(
+        &DataReceiverTest::CreateDataSource, base::Unretained(this)));
   }
 
   void TearDown() override {
@@ -86,12 +35,12 @@
 
  private:
   void CreateDataSource(
-      mojo::InterfaceRequest<device::serial::DataSource> request,
-      mojo::InterfacePtr<device::serial::DataSourceClient> client) {
-    sender_ = new device::DataSourceSender(
-        request.Pass(), client.Pass(),
-        base::Bind(&DataReceiverTest::ReadyToSend, base::Unretained(this)),
-        base::Bind(base::DoNothing));
+      mojo::InterfaceRequest<device::serial::DataSource> request) {
+    sender_ = mojo::WeakBindToRequest(
+        new device::DataSourceSender(
+            base::Bind(&DataReceiverTest::ReadyToSend, base::Unretained(this)),
+            base::Bind(base::DoNothing)),
+        &request);
   }
 
   void ReadyToSend(scoped_ptr<device::WritableBuffer> buffer) {
diff --git a/extensions/renderer/api/serial/data_sender_unittest.cc b/extensions/renderer/api/serial/data_sender_unittest.cc
index f137007..e6a13af 100644
--- a/extensions/renderer/api/serial/data_sender_unittest.cc
+++ b/extensions/renderer/api/serial/data_sender_unittest.cc
@@ -7,55 +7,10 @@
 #include "device/serial/data_sink_receiver.h"
 #include "device/serial/data_stream.mojom.h"
 #include "extensions/renderer/api_test_base.h"
-#include "gin/dictionary.h"
-#include "gin/wrappable.h"
 #include "grit/extensions_renderer_resources.h"
 
 namespace extensions {
 
-class DataSenderFactory : public gin::Wrappable<DataSenderFactory> {
- public:
-  using Callback =
-      base::Callback<void(mojo::InterfaceRequest<device::serial::DataSink>,
-                          mojo::InterfacePtr<device::serial::DataSinkClient>)>;
-  static gin::Handle<DataSenderFactory> Create(v8::Isolate* isolate,
-                                               const Callback& callback) {
-    return gin::CreateHandle(isolate, new DataSenderFactory(callback, isolate));
-  }
-
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override {
-    return Wrappable<DataSenderFactory>::GetObjectTemplateBuilder(isolate)
-        .SetMethod("create", &DataSenderFactory::CreateReceiver);
-  }
-
-  gin::Dictionary CreateReceiver() {
-    mojo::InterfacePtr<device::serial::DataSink> sink;
-    mojo::InterfacePtr<device::serial::DataSinkClient> client;
-    mojo::InterfaceRequest<device::serial::DataSinkClient> client_request =
-        mojo::GetProxy(&client);
-    callback_.Run(mojo::GetProxy(&sink), client.Pass());
-
-    gin::Dictionary result = gin::Dictionary::CreateEmpty(isolate_);
-    result.Set("sink", sink.PassMessagePipe().release());
-    result.Set("client", client_request.PassMessagePipe().release());
-    return result;
-  }
-
-  static gin::WrapperInfo kWrapperInfo;
-
- private:
-  DataSenderFactory(const Callback& callback, v8::Isolate* isolate)
-      : callback_(callback), isolate_(isolate) {}
-
-  base::Callback<void(mojo::InterfaceRequest<device::serial::DataSink>,
-                      mojo::InterfacePtr<device::serial::DataSinkClient>)>
-      callback_;
-  v8::Isolate* isolate_;
-};
-
-gin::WrapperInfo DataSenderFactory::kWrapperInfo = {gin::kEmbedderNativeGin};
-
 // Runs tests defined in extensions/test/data/data_sender_unittest.js
 class DataSenderTest : public ApiTestBase {
  public:
@@ -63,12 +18,8 @@
 
   void SetUp() override {
     ApiTestBase::SetUp();
-    gin::ModuleRegistry::From(env()->context()->v8_context())
-        ->AddBuiltinModule(
-            env()->isolate(), "device/serial/data_sender_test_factory",
-            DataSenderFactory::Create(
-                env()->isolate(), base::Bind(&DataSenderTest::CreateDataSink,
-                                             base::Unretained(this))).ToV8());
+    service_provider()->AddService(
+        base::Bind(&DataSenderTest::CreateDataSink, base::Unretained(this)));
   }
 
   void TearDown() override {
@@ -86,13 +37,13 @@
 
  private:
   void CreateDataSink(
-      mojo::InterfaceRequest<device::serial::DataSink> request,
-      mojo::InterfacePtr<device::serial::DataSinkClient> client) {
-    receiver_ = new device::DataSinkReceiver(
-        request.Pass(), client.Pass(),
-        base::Bind(&DataSenderTest::ReadyToReceive, base::Unretained(this)),
-        base::Bind(&DataSenderTest::OnCancel, base::Unretained(this)),
-        base::Bind(base::DoNothing));
+      mojo::InterfaceRequest<device::serial::DataSink> request) {
+    receiver_ = mojo::WeakBindToRequest(
+        new device::DataSinkReceiver(
+            base::Bind(&DataSenderTest::ReadyToReceive, base::Unretained(this)),
+            base::Bind(&DataSenderTest::OnCancel, base::Unretained(this)),
+            base::Bind(base::DoNothing)),
+        &request);
   }
 
   void ReadyToReceive(scoped_ptr<device::ReadOnlyBuffer> buffer) {
diff --git a/extensions/renderer/resources/data_receiver.js b/extensions/renderer/resources/data_receiver.js
index 8df9d25..0f286be 100644
--- a/extensions/renderer/resources/data_receiver.js
+++ b/extensions/renderer/resources/data_receiver.js
@@ -86,16 +86,15 @@
 
   /**
    * A DataReceiver that receives data from a DataSource.
-   * @param {!MojoHandle} source The handle to the DataSource.
-   * @param {!MojoHandle} client The handle to the DataSourceClient.
+   * @param {!MojoHandle} handle The handle to the DataSource.
    * @param {number} bufferSize How large a buffer to use.
    * @param {number} fatalErrorValue The receive error value to report in the
    *     event of a fatal error.
    * @constructor
    * @alias module:data_receiver.DataReceiver
    */
-  function DataReceiver(source, client, bufferSize, fatalErrorValue) {
-    this.init_(source, client, fatalErrorValue, 0, null, [], false);
+  function DataReceiver(handle, bufferSize, fatalErrorValue) {
+    this.init_(handle, fatalErrorValue, 0, null, [], false);
     this.source_.init(bufferSize);
   }
 
@@ -110,7 +109,6 @@
       return;
     this.shutDown_ = true;
     this.router_.close();
-    this.clientRouter_.close();
     if (this.receive_) {
       this.receive_.dispatchFatalError(this.fatalErrorValue_);
       this.receive_ = null;
@@ -119,8 +117,7 @@
 
   /**
    * Initialize this DataReceiver.
-   * @param {!MojoHandle} source A handle to the DataSource.
-   * @param {!MojoHandle} client A handle to the DataSourceClient.
+   * @param {!MojoHandle} source A handle to the DataSource
    * @param {number} fatalErrorValue The error to dispatch in the event of a
    *     fatal error.
    * @param {number} bytesReceived The number of bytes already received.
@@ -131,9 +128,12 @@
    * @param {boolean} paused Whether the DataSource is paused.
    * @private
    */
-  DataReceiver.prototype.init_ = function(source, client, fatalErrorValue,
-                                          bytesReceived, pendingError,
-                                          pendingData, paused) {
+  DataReceiver.prototype.init_ = function(source,
+                                          fatalErrorValue,
+                                          bytesReceived,
+                                          pendingError,
+                                          pendingData,
+                                          paused) {
     /**
      * The [Router]{@link module:mojo/public/js/router.Router} for the
      * connection to the DataSource.
@@ -141,18 +141,11 @@
      */
     this.router_ = new router.Router(source);
     /**
-     * The [Router]{@link module:mojo/public/js/router.Router} for the
-     * connection to the DataSource.
-     * @private
-     */
-    this.clientRouter_ = new router.Router(client);
-    /**
      * The connection to the DataSource.
      * @private
      */
     this.source_ = new dataStream.DataSource.proxyClass(this.router_);
-    this.client_ = new dataStream.DataSourceClient.stubClass(this);
-    this.clientRouter_.setIncomingReceiver(this.client_);
+    this.router_.setIncomingReceiver(this);
     /**
      * The current receive operation.
      * @type {module:data_receiver~PendingReceive}
@@ -209,7 +202,6 @@
     }
     var serialized = new serialization.SerializedDataReceiver();
     serialized.source = this.router_.connector_.handle_;
-    serialized.client = this.clientRouter_.connector_.handle_;
     serialized.fatal_error_value = this.fatalErrorValue_;
     serialized.paused = this.paused_;
     serialized.pending_error = this.pendingError_;
@@ -219,8 +211,6 @@
     });
     this.router_.connector_.handle_ = null;
     this.router_.close();
-    this.clientRouter_.connector_.handle_ = null;
-    this.clientRouter_.close();
     this.shutDown_ = true;
     return Promise.resolve(serialized);
   };
@@ -252,9 +242,12 @@
       buffer.set(data);
       pendingData.push(buffer.buffer);
     });
-    this.init_(serialized.source, serialized.client,
-               serialized.fatal_error_value, serialized.bytes_received,
-               serialized.pending_error, pendingData, serialized.paused);
+    this.init_(serialized.source,
+               serialized.fatal_error_value,
+               serialized.bytes_received,
+               serialized.pending_error,
+               pendingData,
+               serialized.paused);
   };
 
   /**
diff --git a/extensions/renderer/resources/data_sender.js b/extensions/renderer/resources/data_sender.js
index 310682a..db259ec 100644
--- a/extensions/renderer/resources/data_sender.js
+++ b/extensions/renderer/resources/data_sender.js
@@ -165,16 +165,15 @@
 
   /**
    * A DataSender that sends data to a DataSink.
-   * @param {!MojoHandle} sink The handle to the DataSink.
-   * @param {!MojoHandle} client The handle to the DataSinkClient.
+   * @param {!MojoHandle} handle The handle to the DataSink.
    * @param {number} bufferSize How large a buffer to use for data.
    * @param {number} fatalErrorValue The send error value to report in the
    *     event of a fatal error.
    * @constructor
    * @alias module:data_sender.DataSender
    */
-  function DataSender(sink, client, bufferSize, fatalErrorValue) {
-    this.init_(sink, client, fatalErrorValue, bufferSize);
+  function DataSender(handle, bufferSize, fatalErrorValue) {
+    this.init_(handle, fatalErrorValue, bufferSize);
     this.sink_.init(bufferSize);
   }
 
@@ -189,7 +188,6 @@
       return;
     this.shutDown_ = true;
     this.router_.close();
-    this.clientRouter_.close();
     while (this.pendingSends_.length) {
       this.pendingSends_.pop().reportBytesSentAndError(
           0, this.fatalErrorValue_);
@@ -203,15 +201,13 @@
 
   /**
    * Initialize this DataSender.
-   * @param {!MojoHandle} sink A handle to the DataSink.
-   * @param {!MojoHandle} sinkClient A handle to the DataSinkClient.
+   * @param {!MojoHandle} sink A handle to the DataSink
    * @param {number} fatalErrorValue The error to dispatch in the event of a
    *     fatal error.
    * @param {number} bufferSize The size of the send buffer.
    * @private
    */
-  DataSender.prototype.init_ = function(sink, sinkClient, fatalErrorValue,
-                                        bufferSize) {
+  DataSender.prototype.init_ = function(sink, fatalErrorValue, bufferSize) {
     /**
      * The error to be dispatched in the event of a fatal error.
      * @const {number}
@@ -231,18 +227,11 @@
      */
     this.router_ = new routerModule.Router(sink);
     /**
-     * The [Router]{@link module:mojo/public/js/router.Router} for the
-     * connection to the DataSinkClient.
-     * @private
-     */
-    this.clientRouter_ = new routerModule.Router(sinkClient);
-    /**
      * The connection to the DataSink.
      * @private
      */
     this.sink_ = new dataStreamMojom.DataSink.proxyClass(this.router_);
-    this.client_ = new dataStreamMojom.DataSinkClient.stubClass(this);
-    this.clientRouter_.setIncomingReceiver(this.client_);
+    this.router_.setIncomingReceiver(this);
     /**
      * A queue of sends that have not fully sent their data to the DataSink.
      * @type {!module:data_sender~PendingSend[]}
@@ -301,13 +290,10 @@
     return readyToSerialize.then(function() {
       var serialized = new serialization.SerializedDataSender();
       serialized.sink = this.router_.connector_.handle_;
-      serialized.client = this.clientRouter_.connector_.handle_;
       serialized.fatal_error_value = this.fatalErrorValue_;
       serialized.buffer_size = this.availableBufferCapacity_;
       this.router_.connector_.handle_ = null;
       this.router_.close();
-      this.clientRouter_.connector_.handle_ = null;
-      this.clientRouter_.close();
       this.shutDown_ = true;
       return serialized;
     }.bind(this));
@@ -334,8 +320,8 @@
       this.shutDown_ = true;
       return;
     }
-    this.init_(serialized.sink, serialized.client, serialized.fatal_error_value,
-               serialized.buffer_size);
+    this.init_(
+        serialized.sink, serialized.fatal_error_value, serialized.buffer_size);
   };
 
   /**
diff --git a/extensions/renderer/resources/serial_service.js b/extensions/renderer/resources/serial_service.js
index be232144..d0f29761 100644
--- a/extensions/renderer/resources/serial_service.js
+++ b/extensions/renderer/resources/serial_service.js
@@ -134,17 +134,14 @@
       clientOptions.bufferSize = options.bufferSize;
   };
 
-  function Connection(connection, router, receivePipe, receiveClientPipe,
-                      sendPipe, sendClientPipe, id, options) {
+  function Connection(connection, router, receivePipe, sendPipe, id, options) {
     var state = new serialization.ConnectionState();
     state.connectionId = id;
     updateClientOptions(state, options);
     var receiver = new dataReceiver.DataReceiver(
-        receivePipe, receiveClientPipe, state.bufferSize,
-        serialMojom.ReceiveError.DISCONNECTED);
-    var sender =
-        new dataSender.DataSender(sendPipe, sendClientPipe, state.bufferSize,
-                                  serialMojom.SendError.DISCONNECTED);
+        receivePipe, state.bufferSize, serialMojom.ReceiveError.DISCONNECTED);
+    var sender = new dataSender.DataSender(
+        sendPipe, state.bufferSize, serialMojom.SendError.DISCONNECTED);
     this.init_(state,
                connection,
                router,
@@ -190,16 +187,12 @@
     var serviceOptions = getServiceOptions(options);
     var pipe = core.createMessagePipe();
     var sendPipe = core.createMessagePipe();
-    var sendPipeClient = core.createMessagePipe();
     var receivePipe = core.createMessagePipe();
-    var receivePipeClient = core.createMessagePipe();
     service.connect(path,
                     serviceOptions,
                     pipe.handle0,
                     sendPipe.handle0,
-                    sendPipeClient.handle0,
-                    receivePipe.handle0,
-                    receivePipeClient.handle0);
+                    receivePipe.handle0);
     var router = new routerModule.Router(pipe.handle1);
     var connection = new serialMojom.Connection.proxyClass(router);
     return connection.getInfo().then(convertServiceInfo).then(function(info) {
@@ -207,9 +200,7 @@
     }).catch(function(e) {
       router.close();
       core.close(sendPipe.handle1);
-      core.close(sendPipeClient.handle1);
       core.close(receivePipe.handle1);
-      core.close(receivePipeClient.handle1);
       throw e;
     }).then(function(results) {
       var info = results[0];
@@ -217,9 +208,7 @@
       var serialConnectionClient = new Connection(connection,
                                                   router,
                                                   receivePipe.handle1,
-                                                  receivePipeClient.handle1,
                                                   sendPipe.handle1,
-                                                  sendPipeClient.handle1,
                                                   id,
                                                   options);
       var clientInfo = serialConnectionClient.getClientInfo_();
diff --git a/extensions/shell/browser/api/shell_gcd/shell_gcd_api.cc b/extensions/shell/browser/api/shell_gcd/shell_gcd_api.cc
index 637e8ce..ea3d35c 100644
--- a/extensions/shell/browser/api/shell_gcd/shell_gcd_api.cc
+++ b/extensions/shell/browser/api/shell_gcd/shell_gcd_api.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/shell/browser/api/shell_gcd/shell_gcd_api.h"
 
+#include <string>
+
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/privet_daemon_client.h"
@@ -30,4 +32,20 @@
   Respond(OneArgument(new base::FundamentalValue(success)));
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
+ShellGcdGetWiFiBootstrapStateFunction::ShellGcdGetWiFiBootstrapStateFunction() {
+}
+
+ShellGcdGetWiFiBootstrapStateFunction::
+    ~ShellGcdGetWiFiBootstrapStateFunction() {
+}
+
+ExtensionFunction::ResponseAction ShellGcdGetWiFiBootstrapStateFunction::Run() {
+  std::string state = chromeos::DBusThreadManager::Get()
+                          ->GetPrivetDaemonClient()
+                          ->GetWifiBootstrapState();
+  return RespondNow(OneArgument(new base::StringValue(state)));
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/browser/api/shell_gcd/shell_gcd_api.h b/extensions/shell/browser/api/shell_gcd/shell_gcd_api.h
index 986f32fc..327f3aad 100644
--- a/extensions/shell/browser/api/shell_gcd/shell_gcd_api.h
+++ b/extensions/shell/browser/api/shell_gcd/shell_gcd_api.h
@@ -10,7 +10,7 @@
 
 namespace extensions {
 
-// See shell_gcd.idl for documentation.
+// Used for manual testing in app_shell. See shell_gcd.idl for documentation.
 class ShellGcdPingFunction : public UIThreadExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("shell.gcd.ping", UNKNOWN);
@@ -30,6 +30,24 @@
   DISALLOW_COPY_AND_ASSIGN(ShellGcdPingFunction);
 };
 
+///////////////////////////////////////////////////////////////////////////////
+
+// Used for manual testing in app_shell. See shell_gcd.idl for documentation.
+class ShellGcdGetWiFiBootstrapStateFunction : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("shell.gcd.getWiFiBootstrapState", UNKNOWN);
+
+  ShellGcdGetWiFiBootstrapStateFunction();
+
+  // ExtensionFunction:
+  ResponseAction Run() override;
+
+ private:
+  ~ShellGcdGetWiFiBootstrapStateFunction() override;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellGcdGetWiFiBootstrapStateFunction);
+};
+
 }  // namespace extensions
 
 #endif  // EXTENSIONS_SHELL_BROWSER_API_SHELL_GCD_SHELL_GCD_API_H_
diff --git a/extensions/shell/browser/api/shell_gcd/shell_gcd_api_unittest.cc b/extensions/shell/browser/api/shell_gcd/shell_gcd_api_unittest.cc
index 046fc7a..66e4401b 100644
--- a/extensions/shell/browser/api/shell_gcd/shell_gcd_api_unittest.cc
+++ b/extensions/shell/browser/api/shell_gcd/shell_gcd_api_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/privet_daemon_client.h"
 #include "extensions/browser/api_unittest.h"
 
 namespace extensions {
@@ -33,7 +34,7 @@
   DISALLOW_COPY_AND_ASSIGN(ShellGcdApiTest);
 };
 
-TEST_F(ShellGcdApiTest, GetBootstrapStatus) {
+TEST_F(ShellGcdApiTest, Ping) {
   // Function succeeds and returns a result (for its callback).
   scoped_ptr<base::Value> result =
       RunFunctionAndReturnValue(new ShellGcdPingFunction, "[{}]");
@@ -43,4 +44,14 @@
   EXPECT_TRUE(success);
 }
 
+TEST_F(ShellGcdApiTest, GetWiFiBootstrapState) {
+  // Function succeeds and returns a result (for its callback).
+  scoped_ptr<base::Value> result = RunFunctionAndReturnValue(
+      new ShellGcdGetWiFiBootstrapStateFunction, "[{}]");
+  ASSERT_TRUE(result.get());
+  std::string state;
+  result->GetAsString(&state);
+  EXPECT_EQ(privetd::kWiFiBootstrapStateMonitoring, state);
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/browser/shell_app_delegate.cc b/extensions/shell/browser/shell_app_delegate.cc
index fcb46a6..3871027 100644
--- a/extensions/shell/browser/shell_app_delegate.cc
+++ b/extensions/shell/browser/shell_app_delegate.cc
@@ -42,7 +42,7 @@
 void ShellAppDelegate::AddNewContents(content::BrowserContext* context,
                                       content::WebContents* new_contents,
                                       WindowOpenDisposition disposition,
-                                      const gfx::Rect& initial_pos,
+                                      const gfx::Rect& initial_rect,
                                       bool user_gesture,
                                       bool* was_blocked) {
   NOTIMPLEMENTED();
diff --git a/extensions/shell/browser/shell_app_delegate.h b/extensions/shell/browser/shell_app_delegate.h
index a5fff4aa..6690d7a0 100644
--- a/extensions/shell/browser/shell_app_delegate.h
+++ b/extensions/shell/browser/shell_app_delegate.h
@@ -29,7 +29,7 @@
   void AddNewContents(content::BrowserContext* context,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   content::ColorChooser* ShowColorChooser(content::WebContents* web_contents,
diff --git a/extensions/shell/browser/shell_extension_host_delegate.cc b/extensions/shell/browser/shell_extension_host_delegate.cc
index a02d604..d06363e 100644
--- a/extensions/shell/browser/shell_extension_host_delegate.cc
+++ b/extensions/shell/browser/shell_extension_host_delegate.cc
@@ -36,7 +36,7 @@
 void ShellExtensionHostDelegate::CreateTab(content::WebContents* web_contents,
                                            const std::string& extension_id,
                                            WindowOpenDisposition disposition,
-                                           const gfx::Rect& initial_pos,
+                                           const gfx::Rect& initial_rect,
                                            bool user_gesture) {
   // TODO(jamescook): Should app_shell support opening popup windows?
   NOTREACHED();
diff --git a/extensions/shell/browser/shell_extension_host_delegate.h b/extensions/shell/browser/shell_extension_host_delegate.h
index 4f796016..ba2a364 100644
--- a/extensions/shell/browser/shell_extension_host_delegate.h
+++ b/extensions/shell/browser/shell_extension_host_delegate.h
@@ -23,7 +23,7 @@
   void CreateTab(content::WebContents* web_contents,
                  const std::string& extension_id,
                  WindowOpenDisposition disposition,
-                 const gfx::Rect& initial_pos,
+                 const gfx::Rect& initial_rect,
                  bool user_gesture) override;
   void ProcessMediaAccessRequest(content::WebContents* web_contents,
                                  const content::MediaStreamRequest& request,
diff --git a/extensions/shell/common/api/shell_gcd.idl b/extensions/shell/common/api/shell_gcd.idl
index 7f2175a..65c80300 100644
--- a/extensions/shell/common/api/shell_gcd.idl
+++ b/extensions/shell/common/api/shell_gcd.idl
@@ -5,12 +5,20 @@
 // Setup related functions for a Google Cloud Devices (GCD) target device
 // running on Chrome OS Core. The actual bootstrapping and GCD registration is
 // handled by the privetd and buffet system daemons.
+//
+// TODO(jamescook): This API exists only for manual testing of GCD in app_shell.
+// Delete it when GCD setup is integrated into OOBE.
 namespace shell.gcd {
  
   callback PingCallback = void(boolean success);
+  callback StateCallback = void(DOMString state);
 
   interface Functions {
     // Attempts to ping the daemon via D-Bus.
     static void ping(PingCallback callback);
+
+    // Returns the Wi-Fi bootstrap state. Return values are found in
+    // platform2/privetd/dbus_bindings/org.chromium.privetd.Manager.xml.
+    static void getWiFiBootstrapState(StateCallback callback);
   };
 };
diff --git a/extensions/test/data/data_receiver_unittest.js b/extensions/test/data/data_receiver_unittest.js
index b46189a4..75d3ca76f 100644
--- a/extensions/test/data/data_receiver_unittest.js
+++ b/extensions/test/data/data_receiver_unittest.js
@@ -13,14 +13,17 @@
 // Returns a promise to a newly created DataReceiver.
 function createReceiver() {
   return Promise.all([
+    requireAsync('content/public/renderer/service_provider'),
     requireAsync('data_receiver'),
-    requireAsync('device/serial/data_receiver_test_factory'),
+    requireAsync('device/serial/data_stream.mojom'),
   ]).then(function(modules) {
-    var dataReceiver = modules[0];
-    var factory = modules[1];
-    var receiver = factory.create();
-    return new dataReceiver.DataReceiver(receiver.source, receiver.client,
-                                         BUFFER_SIZE, FATAL_ERROR);
+    var serviceProvider = modules[0];
+    var dataReceiver = modules[1];
+    var dataStream = modules[2];
+    return new dataReceiver.DataReceiver(
+        serviceProvider.connectToService(dataStream.DataSource.name),
+        BUFFER_SIZE,
+        FATAL_ERROR);
   });
 }
 
diff --git a/extensions/test/data/data_sender_unittest.js b/extensions/test/data/data_sender_unittest.js
index 9cd1771..0b6a5cfe 100644
--- a/extensions/test/data/data_sender_unittest.js
+++ b/extensions/test/data/data_sender_unittest.js
@@ -24,14 +24,17 @@
 // Returns a promise to a newly created DataSender.
 function createSender() {
   return Promise.all([
+    requireAsync('content/public/renderer/service_provider'),
     requireAsync('data_sender'),
-    requireAsync('device/serial/data_sender_test_factory'),
+    requireAsync('device/serial/data_stream.mojom'),
   ]).then(function(modules) {
-    var dataSender = modules[0];
-    var factory = modules[1];
-    var sender = factory.create();
-    return new dataSender.DataSender(sender.sink, sender.client, BUFFER_SIZE,
-                                     FATAL_ERROR);
+    var serviceProvider = modules[0];
+    var dataSender = modules[1];
+    var dataStream = modules[2];
+    return new dataSender.DataSender(
+        serviceProvider.connectToService(dataStream.DataSink.name),
+        BUFFER_SIZE,
+        FATAL_ERROR);
   });
 }
 
diff --git a/extensions/test/data/web_view/apitest/main.js b/extensions/test/data/web_view/apitest/main.js
index 4495ed4..95fee6e 100644
--- a/extensions/test/data/web_view/apitest/main.js
+++ b/extensions/test/data/web_view/apitest/main.js
@@ -964,16 +964,14 @@
 // chrome URL is provided.
 function testLoadAbortIllegalChromeURL() {
   var webview = document.createElement('webview');
-  var onFirstLoadStop = function(e) {
-    webview.removeEventListener('loadstop', onFirstLoadStop);
-    webview.setAttribute('src', 'chrome://newtab');
-  };
-  webview.addEventListener('loadstop', onFirstLoadStop);
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
+  });
+  webview.addEventListener('loadstop', function(e)  {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
-  webview.setAttribute('src', 'about:blank');
+  webview.src = 'chrome://newtab';
   document.body.appendChild(webview);
 }
 
@@ -981,9 +979,12 @@
   var webview = document.createElement('webview');
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
-  webview.setAttribute('src', 'file://foo');
+  webview.src = 'file://foo';
   document.body.appendChild(webview);
 }
 
@@ -991,6 +992,9 @@
   var webview = document.createElement('webview');
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
   webview.setAttribute('src', 'javascript:void(document.bgColor="#0000FF")');
@@ -1000,17 +1004,19 @@
 // Verifies that navigating to invalid URL (e.g. 'http:') doesn't cause a crash.
 function testLoadAbortInvalidNavigation() {
   var webview = document.createElement('webview');
-  var validSchemeWithEmptyURL = 'http:';
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
     embedder.test.assertEq('', e.url);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
   webview.addEventListener('exit', function(e) {
     // We should not crash.
     embedder.test.fail();
   });
-  webview.setAttribute('src', validSchemeWithEmptyURL);
+  webview.src = 'http:';
   document.body.appendChild(webview);
 }
 
@@ -1018,17 +1024,20 @@
 // pseudo-scheme fires loadabort and doesn't cause a crash.
 function testLoadAbortNonWebSafeScheme() {
   var webview = document.createElement('webview');
-  var chromeGuestURL = 'chrome-guest://abc123';
+  var chromeGuestURL = 'chrome-guest://abc123/';
   webview.addEventListener('loadabort', function(e) {
     embedder.test.assertEq('ERR_ABORTED', e.reason);
-    embedder.test.assertEq('chrome-guest://abc123/', e.url);
+    embedder.test.assertEq(chromeGuestURL, e.url);
+  });
+  webview.addEventListener('loadstop', function(e) {
+    embedder.test.assertEq('about:blank', webview.src);
     embedder.test.succeed();
   });
   webview.addEventListener('exit', function(e) {
     // We should not crash.
     embedder.test.fail();
   });
-  webview.setAttribute('src', chromeGuestURL);
+  webview.src = chromeGuestURL;
   document.body.appendChild(webview);
 };
 
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index affe4d8..82a3f58 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -142,6 +142,7 @@
       "command_buffer/client/fenced_allocator_test.cc",
       "command_buffer/client/gles2_implementation_unittest.cc",
       "command_buffer/client/mapped_memory_unittest.cc",
+      "command_buffer/client/program_info_manager_unittest.cc",
       "command_buffer/client/query_tracker_unittest.cc",
       "command_buffer/client/ring_buffer_test.cc",
       "command_buffer/client/transfer_buffer_unittest.cc",
diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc
index 7196372..205d1b9 100644
--- a/gpu/command_buffer/client/program_info_manager.cc
+++ b/gpu/command_buffer/client/program_info_manager.cc
@@ -4,6 +4,8 @@
 
 #include "gpu/command_buffer/client/program_info_manager.h"
 
+#include "base/numerics/safe_math.h"
+
 namespace {
 
 template<typename T> static T LocalGetAs(
@@ -44,11 +46,23 @@
 ProgramInfoManager::Program::UniformInfo::~UniformInfo() {
 }
 
+ProgramInfoManager::Program::UniformBlock::UniformBlock()
+    : binding(0),
+      data_size(0),
+      referenced_by_vertex_shader(false),
+      referenced_by_fragment_shader(false) {
+}
+
+ProgramInfoManager::Program::UniformBlock::~UniformBlock() {
+}
+
 ProgramInfoManager::Program::Program()
-    : cached_(false),
+    : cached_es2_(false),
       max_attrib_name_length_(0),
       max_uniform_name_length_(0),
-      link_status_(false) {
+      link_status_(false),
+      cached_es3_uniform_blocks_(false),
+      active_uniform_block_max_name_length_(0) {
 }
 
 ProgramInfoManager::Program::~Program() {
@@ -78,6 +92,11 @@
       &uniform_infos_[index] : NULL;
 }
 
+const ProgramInfoManager::Program::UniformBlock*
+ProgramInfoManager::Program::GetUniformBlock(GLuint index) const {
+  return (index < uniform_blocks_.size()) ? &uniform_blocks_[index] : NULL;
+}
+
 GLint ProgramInfoManager::Program::GetUniformLocation(
     const std::string& name) const {
   bool getting_array_location = false;
@@ -125,31 +144,45 @@
     GLenum pname, GLint* params) {
   switch (pname) {
     case GL_LINK_STATUS:
-      *params = link_status_;
+      *params = static_cast<GLint>(link_status_);
       return true;
     case GL_ACTIVE_ATTRIBUTES:
-      *params = attrib_infos_.size();
+      *params = static_cast<GLint>(attrib_infos_.size());
       return true;
     case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
-      *params = max_attrib_name_length_;
+      *params = static_cast<GLint>(max_attrib_name_length_);
       return true;
     case GL_ACTIVE_UNIFORMS:
-      *params = uniform_infos_.size();
+      *params = static_cast<GLint>(uniform_infos_.size());
       return true;
     case GL_ACTIVE_UNIFORM_MAX_LENGTH:
-      *params = max_uniform_name_length_;
+      *params = static_cast<GLint>(max_uniform_name_length_);
+      return true;
+    case GL_ACTIVE_UNIFORM_BLOCKS:
+      *params = static_cast<GLint>(uniform_blocks_.size());
+      return true;
+    case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
+      *params = static_cast<GLint>(active_uniform_block_max_name_length_);
       return true;
     default:
+      NOTREACHED();
       break;
   }
   return false;
 }
 
-void ProgramInfoManager::Program::Update(
-    GLES2Implementation* gl,
-    GLuint program,
-    const std::vector<int8>& result) {
-  if (cached_) {
+GLuint ProgramInfoManager::Program::GetUniformBlockIndex(
+    const std::string& name) const {
+  for (size_t ii = 0; ii < uniform_blocks_.size(); ++ii) {
+    if (uniform_blocks_[ii].name == name) {
+      return static_cast<GLuint>(ii);
+    }
+  }
+  return GL_INVALID_INDEX;
+}
+
+void ProgramInfoManager::Program::UpdateES2(const std::vector<int8>& result) {
+  if (cached_es2_) {
     return;
   }
   if (result.empty()) {
@@ -200,12 +233,91 @@
     ++input;
   }
   DCHECK_EQ(header->num_attribs + header->num_uniforms,
-                static_cast<uint32>(input - inputs));
-  cached_ = true;
+            static_cast<uint32>(input - inputs));
+  cached_es2_ = true;
 }
 
-bool ProgramInfoManager::Program::cached() const {
-  return cached_;
+void ProgramInfoManager::Program::UpdateES3UniformBlocks(
+    const std::vector<int8>& result) {
+  if (cached_es3_uniform_blocks_) {
+    return;
+  }
+  if (result.empty()) {
+    // This should only happen on a lost context.
+    return;
+  }
+  uniform_blocks_.clear();
+  active_uniform_block_max_name_length_ = 0;
+
+  uint32_t header_size = sizeof(UniformBlocksHeader);
+  DCHECK_GE(result.size(), header_size);
+  const UniformBlocksHeader* header = LocalGetAs<const UniformBlocksHeader*>(
+      result, 0, header_size);
+  DCHECK(header);
+  if (header->num_uniform_blocks == 0) {
+    DCHECK_EQ(result.size(), header_size);
+    // TODO(zmo): Here we can't tell if no uniform blocks are defined, or
+    // the previous link failed.
+    return;
+  }
+  uniform_blocks_.resize(header->num_uniform_blocks);
+
+  uint32_t entry_size = sizeof(UniformBlockInfo) * header->num_uniform_blocks;
+  DCHECK_GE(result.size(), header_size + entry_size);
+  uint32_t data_size = result.size() - header_size - entry_size;
+  DCHECK_LT(0u, data_size);
+  const UniformBlockInfo* entries = LocalGetAs<const UniformBlockInfo*>(
+      result, header_size, entry_size);
+  DCHECK(entries);
+  const char* data = LocalGetAs<const char*>(
+      result, header_size + entry_size, data_size);
+  DCHECK(data);
+
+  uint32_t size = 0;
+  for (uint32_t ii = 0; ii < header->num_uniform_blocks; ++ii) {
+    uniform_blocks_[ii].binding = static_cast<GLuint>(entries[ii].binding);
+    uniform_blocks_[ii].data_size = static_cast<GLuint>(entries[ii].data_size);
+    uniform_blocks_[ii].active_uniform_indices.resize(
+        entries[ii].active_uniforms);
+    uniform_blocks_[ii].referenced_by_vertex_shader = static_cast<GLboolean>(
+        entries[ii].referenced_by_vertex_shader);
+    uniform_blocks_[ii].referenced_by_fragment_shader = static_cast<GLboolean>(
+        entries[ii].referenced_by_fragment_shader);
+    // Uniform block names can't be empty strings.
+    DCHECK_LT(1u, entries[ii].name_length);
+    if (entries[ii].name_length > active_uniform_block_max_name_length_) {
+      active_uniform_block_max_name_length_ = entries[ii].name_length;
+    }
+    size += entries[ii].name_length;
+    DCHECK_GE(data_size, size);
+    uniform_blocks_[ii].name = std::string(data, entries[ii].name_length - 1);
+    data += entries[ii].name_length;
+    size += entries[ii].active_uniforms * sizeof(uint32_t);
+    DCHECK_GE(data_size, size);
+    const uint32_t* indices = reinterpret_cast<const uint32_t*>(data);
+    for (uint32_t uu = 0; uu < entries[ii].active_uniforms; ++uu) {
+      uniform_blocks_[ii].active_uniform_indices[uu] =
+          static_cast<GLuint>(indices[uu]);
+    }
+    indices += entries[ii].active_uniforms;
+    data = reinterpret_cast<const char*>(indices);
+  }
+  DCHECK_EQ(data_size, size);
+  cached_es3_uniform_blocks_ = true;
+}
+
+bool ProgramInfoManager::Program::IsCached(ProgramInfoType type) const {
+  switch (type) {
+    case kES2:
+      return cached_es2_;
+    case kES3UniformBlocks:
+      return cached_es3_uniform_blocks_;
+    case kNone:
+      return true;
+    default:
+      NOTREACHED();
+      return true;
+  }
 }
 
 
@@ -216,29 +328,42 @@
 }
 
 ProgramInfoManager::Program* ProgramInfoManager::GetProgramInfo(
-    GLES2Implementation* gl, GLuint program) {
+    GLES2Implementation* gl, GLuint program, ProgramInfoType type) {
   lock_.AssertAcquired();
   ProgramInfoMap::iterator it = program_infos_.find(program);
   if (it == program_infos_.end()) {
     return NULL;
   }
   Program* info = &it->second;
-  if (info->cached())
+  if (info->IsCached(type))
     return info;
-  std::vector<int8> result;
-  {
-    base::AutoUnlock unlock(lock_);
-    // lock_ can't be held across IPC call or else it may deadlock in pepper.
-    // http://crbug.com/418651
-    gl->GetProgramInfoCHROMIUMHelper(program, &result);
-  }
 
-  it = program_infos_.find(program);
-  if (it == program_infos_.end()) {
-    return NULL;
+  std::vector<int8> result;
+  switch (type) {
+    case kES2:
+      {
+        base::AutoUnlock unlock(lock_);
+        // lock_ can't be held across IPC call or else it may deadlock in
+        // pepper. http://crbug.com/418651
+        gl->GetProgramInfoCHROMIUMHelper(program, &result);
+      }
+      info->UpdateES2(result);
+      break;
+    case kES3UniformBlocks:
+      {
+        base::AutoUnlock unlock(lock_);
+        // lock_ can't be held across IPC call or else it may deadlock in
+        // pepper. http://crbug.com/418651
+
+        // TODO(zmo): Uncomment the below line once GetUniformBlocksCHROMIUM
+        // command is implemented.
+        // gl->GetUniformBlocksCHROMIUMHeler(program, &result);
+      }
+      info->UpdateES3UniformBlocks(result);
+    default:
+      NOTREACHED();
+      return NULL;
   }
-  info = &it->second;
-  info->Update(gl, program, result);
   return info;
 }
 
@@ -259,7 +384,23 @@
 bool ProgramInfoManager::GetProgramiv(
     GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) {
   base::AutoLock auto_lock(lock_);
-  Program* info = GetProgramInfo(gl, program);
+  ProgramInfoType type = kNone;
+  switch (pname) {
+    case GL_ACTIVE_ATTRIBUTES:
+    case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+    case GL_ACTIVE_UNIFORMS:
+    case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+    case GL_LINK_STATUS:
+      type = kES2;
+      break;
+    case GL_ACTIVE_UNIFORM_BLOCKS:
+    case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
+      type = kES3UniformBlocks;
+      break;
+    default:
+      return false;
+  }
+  Program* info = GetProgramInfo(gl, program, type);
   if (!info) {
     return false;
   }
@@ -270,7 +411,7 @@
     GLES2Implementation* gl, GLuint program, const char* name) {
   {
     base::AutoLock auto_lock(lock_);
-    Program* info = GetProgramInfo(gl, program);
+    Program* info = GetProgramInfo(gl, program, kES2);
     if (info) {
       return info->GetAttribLocation(name);
     }
@@ -282,7 +423,7 @@
     GLES2Implementation* gl, GLuint program, const char* name) {
   {
     base::AutoLock auto_lock(lock_);
-    Program* info = GetProgramInfo(gl, program);
+    Program* info = GetProgramInfo(gl, program, kES2);
     if (info) {
       return info->GetUniformLocation(name);
     }
@@ -296,7 +437,7 @@
   // fetched altogether from the service side.  See crbug.com/452104.
   {
     base::AutoLock auto_lock(lock_);
-    Program* info = GetProgramInfo(gl, program);
+    Program* info = GetProgramInfo(gl, program, kNone);
     if (info) {
       GLint possible_loc = info->GetFragDataLocation(name);
       if (possible_loc != -1)
@@ -306,7 +447,7 @@
   GLint loc = gl->GetFragDataLocationHelper(program, name);
   if (loc != -1) {
     base::AutoLock auto_lock(lock_);
-    Program* info = GetProgramInfo(gl, program);
+    Program* info = GetProgramInfo(gl, program, kNone);
     if (info) {
       info->CacheFragDataLocation(name, loc);
     }
@@ -320,7 +461,7 @@
     GLint* size, GLenum* type, char* name) {
   {
     base::AutoLock auto_lock(lock_);
-    Program* info = GetProgramInfo(gl, program);
+    Program* info = GetProgramInfo(gl, program, kES2);
     if (info) {
       const Program::VertexAttrib* attrib_info = info->GetAttribInfo(index);
       if (attrib_info) {
@@ -356,7 +497,7 @@
     GLint* size, GLenum* type, char* name) {
   {
     base::AutoLock auto_lock(lock_);
-    Program* info = GetProgramInfo(gl, program);
+    Program* info = GetProgramInfo(gl, program, kES2);
     if (info) {
       const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
       if (uniform_info) {
@@ -386,6 +527,108 @@
       program, index, bufsize, length, size, type, name);
 }
 
+GLuint ProgramInfoManager::GetUniformBlockIndex(
+    GLES2Implementation* gl, GLuint program, const char* name) {
+  {
+    base::AutoLock auto_lock(lock_);
+    Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
+    if (info) {
+      return info->GetUniformBlockIndex(name);
+    }
+  }
+  return false;
+  // TODO(zmo): return gl->GetUniformBlockIndexHelper(program, name);
+}
+
+bool ProgramInfoManager::GetActiveUniformBlockName(
+    GLES2Implementation* gl, GLuint program, GLuint index,
+    GLsizei buf_size, GLsizei* length, char* name) {
+  {
+    base::AutoLock auto_lock(lock_);
+    Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
+    if (info) {
+      const Program::UniformBlock* uniform_block = info->GetUniformBlock(index);
+      if (uniform_block && buf_size >= 1) {
+        GLsizei written_size = std::min(
+            buf_size, static_cast<GLsizei>(uniform_block->name.size()) + 1);
+        if (length) {
+          *length = written_size - 1;
+        }
+        memcpy(name, uniform_block->name.c_str(), written_size);
+        return true;
+      }
+    }
+  }
+  return false;
+  // TODO(zmo): return gl->GetActiveUniformBlockNameHelper(
+  //                program, index, buf_size, length, name);
+}
+
+bool ProgramInfoManager::GetActiveUniformBlockiv(
+    GLES2Implementation* gl, GLuint program, GLuint index,
+    GLenum pname, GLint* params) {
+  {
+    base::AutoLock auto_lock(lock_);
+    Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
+    if (info) {
+      const Program::UniformBlock* uniform_block = info->GetUniformBlock(index);
+      bool valid_pname;
+      switch (pname) {
+        case GL_UNIFORM_BLOCK_BINDING:
+        case GL_UNIFORM_BLOCK_DATA_SIZE:
+        case GL_UNIFORM_BLOCK_NAME_LENGTH:
+        case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+        case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+        case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+        case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+          valid_pname = true;
+          break;
+        default:
+          valid_pname = false;
+          break;
+      }
+      if (uniform_block && valid_pname && params) {
+        switch (pname) {
+          case GL_UNIFORM_BLOCK_BINDING:
+            *params = static_cast<GLint>(uniform_block->binding);
+            break;
+          case GL_UNIFORM_BLOCK_DATA_SIZE:
+            *params = static_cast<GLint>(uniform_block->data_size);
+            break;
+          case GL_UNIFORM_BLOCK_NAME_LENGTH:
+            *params = static_cast<GLint>(uniform_block->name.size()) + 1;
+            break;
+          case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+            *params = static_cast<GLint>(
+                uniform_block->active_uniform_indices.size());
+            break;
+          case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+            for (size_t ii = 0;
+                 ii < uniform_block->active_uniform_indices.size(); ++ii) {
+              params[ii] = static_cast<GLint>(
+                  uniform_block->active_uniform_indices[ii]);
+            }
+            break;
+          case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+            *params = static_cast<GLint>(
+                uniform_block->referenced_by_vertex_shader);
+            break;
+          case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+            *params = static_cast<GLint>(
+                uniform_block->referenced_by_fragment_shader);
+            break;
+          default:
+            NOTREACHED();
+        }
+        return true;
+      }
+    }
+  }
+  return false;
+  // TODO(zmo): return gl->GetActiveUniformBlockivHelper(
+  //                program, index, pname, params);
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/client/program_info_manager.h b/gpu/command_buffer/client/program_info_manager.h
index 712b8ed..efbff73f 100644
--- a/gpu/command_buffer/client/program_info_manager.h
+++ b/gpu/command_buffer/client/program_info_manager.h
@@ -5,12 +5,13 @@
 #ifndef GPU_COMMAND_BUFFER_CLIENT_PROGRAM_INFO_MANAGER_H_
 #define GPU_COMMAND_BUFFER_CLIENT_PROGRAM_INFO_MANAGER_H_
 
-#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
 
 #include <string>
 #include <vector>
 
 #include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
 #include "base/synchronization/lock.h"
 #include "gles2_impl_export.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
@@ -48,8 +49,30 @@
       GLES2Implementation* gl, GLuint program, GLuint index, GLsizei bufsize,
       GLsizei* length, GLint* size, GLenum* type, char* name);
 
+  GLuint GetUniformBlockIndex(
+      GLES2Implementation* gl, GLuint program, const char* name);
+
+  bool GetActiveUniformBlockName(
+      GLES2Implementation* gl, GLuint program, GLuint index,
+      GLsizei buf_size, GLsizei* length, char* name);
+
+  bool GetActiveUniformBlockiv(
+      GLES2Implementation* gl, GLuint program, GLuint index,
+      GLenum pname, GLint* params);
+
  private:
-  class Program {
+  friend class ProgramInfoManagerTest;
+
+  FRIEND_TEST_ALL_PREFIXES(ProgramInfoManagerTest, UpdateES3UniformBlocks);
+
+  enum ProgramInfoType {
+    kES2,
+    kES3UniformBlocks,
+    kNone,
+  };
+
+  // Need GLES2_IMPL_EXPORT for tests.
+  class GLES2_IMPL_EXPORT Program {
    public:
     struct UniformInfo {
       UniformInfo(GLsizei _size, GLenum _type, const std::string& _name);
@@ -71,6 +94,17 @@
       GLint location;
       std::string name;
     };
+    struct UniformBlock {
+      UniformBlock();
+      ~UniformBlock();
+
+      GLuint binding;
+      GLuint data_size;
+      std::vector<GLuint> active_uniform_indices;
+      GLboolean referenced_by_vertex_shader;
+      GLboolean referenced_by_fragment_shader;
+      std::string name;
+    };
 
     Program();
     ~Program();
@@ -89,15 +123,20 @@
 
     bool GetProgramiv(GLenum pname, GLint* params);
 
-    // Updates the program info after a successful link.
-    void Update(GLES2Implementation* gl,
-                GLuint program,
-                const std::vector<int8>& result);
+    // Gets the index of a uniform block by name.
+    GLuint GetUniformBlockIndex(const std::string& name) const;
+    const UniformBlock* GetUniformBlock(GLuint index) const;
 
-    bool cached() const;
+    // Updates the ES2 only program info after a successful link.
+    void UpdateES2(const std::vector<int8>& result);
+
+    // Updates the ES3 UniformBlock info after a successful link.
+    void UpdateES3UniformBlocks(const std::vector<int8>& result);
+
+    bool IsCached(ProgramInfoType type) const;
 
    private:
-    bool cached_;
+    bool cached_es2_;
 
     GLsizei max_attrib_name_length_;
 
@@ -109,13 +148,23 @@
     // Uniform info by index.
     std::vector<UniformInfo> uniform_infos_;
 
-    base::hash_map<std::string, GLint> frag_data_locations_;
-
     // This is true if glLinkProgram was successful last time it was called.
     bool link_status_;
+
+    // BELOW ARE ES3 ONLY INFORMATION.
+
+    bool cached_es3_uniform_blocks_;
+
+    uint32_t active_uniform_block_max_name_length_;
+
+    // Uniform blocks by index.
+    std::vector<UniformBlock> uniform_blocks_;
+
+    base::hash_map<std::string, GLint> frag_data_locations_;
   };
 
-  Program* GetProgramInfo(GLES2Implementation* gl, GLuint program);
+  Program* GetProgramInfo(
+      GLES2Implementation* gl, GLuint program, ProgramInfoType type);
 
   typedef base::hash_map<GLuint, Program> ProgramInfoMap;
 
diff --git a/gpu/command_buffer/client/program_info_manager_unittest.cc b/gpu/command_buffer/client/program_info_manager_unittest.cc
new file mode 100644
index 0000000..a2fc722
--- /dev/null
+++ b/gpu/command_buffer/client/program_info_manager_unittest.cc
@@ -0,0 +1,111 @@
+// 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 "gpu/command_buffer/client/program_info_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+uint32 ComputeOffset(const void* start, const void* position) {
+  return static_cast<const uint8*>(position) -
+         static_cast<const uint8*>(start);
+}
+
+}  // namespace anonymous
+
+namespace gpu {
+namespace gles2 {
+
+class ProgramInfoManagerTest : public testing::Test {
+ public:
+  ProgramInfoManagerTest() {}
+  ~ProgramInfoManagerTest() override {}
+
+ protected:
+  void SetUp() override {}
+
+  void TearDown() override {}
+};
+
+TEST_F(ProgramInfoManagerTest, UpdateES3UniformBlocks) {
+  struct Data {
+    UniformBlocksHeader header;
+    UniformBlockInfo entry[2];
+    char name0[4];
+    uint32_t indices0[2];
+    char name1[8];
+    uint32_t indices1[1];
+  };
+  Data data;
+  // The names needs to be of size 4*k-1 to avoid padding in the struct Data.
+  // This is a testing only problem.
+  const char* kName[] = { "cow", "chicken" };
+  const uint32_t kIndices0[] = { 1, 2 };
+  const uint32_t kIndices1[] = { 3 };
+  const uint32_t* kIndices[] = { kIndices0, kIndices1 };
+  data.header.num_uniform_blocks = 2;
+  data.entry[0].binding = 0;
+  data.entry[0].data_size = 8;
+  data.entry[0].name_offset = ComputeOffset(&data, data.name0);
+  data.entry[0].name_length = arraysize(data.name0);
+  data.entry[0].active_uniforms = arraysize(data.indices0);
+  data.entry[0].active_uniform_offset = ComputeOffset(&data, data.indices0);
+  data.entry[0].referenced_by_vertex_shader = static_cast<uint32_t>(true);
+  data.entry[0].referenced_by_fragment_shader = static_cast<uint32_t>(false);
+  data.entry[1].binding = 1;
+  data.entry[1].data_size = 4;
+  data.entry[1].name_offset = ComputeOffset(&data, data.name1);
+  data.entry[1].name_length = arraysize(data.name1);
+  data.entry[1].active_uniforms = arraysize(data.indices1);
+  data.entry[1].active_uniform_offset = ComputeOffset(&data, data.indices1);
+  data.entry[1].referenced_by_vertex_shader = static_cast<uint32_t>(false);
+  data.entry[1].referenced_by_fragment_shader = static_cast<uint32_t>(true);
+  memcpy(data.name0, kName[0], arraysize(data.name0));
+  data.indices0[0] = kIndices[0][0];
+  data.indices0[1] = kIndices[0][1];
+  memcpy(data.name1, kName[1], arraysize(data.name1));
+  data.indices1[0] = kIndices[1][0];
+
+  std::vector<int8> result(sizeof(data));
+  memcpy(&result[0], &data, sizeof(data));
+
+  ProgramInfoManager::Program program;
+  EXPECT_FALSE(program.IsCached(ProgramInfoManager::kES3UniformBlocks));
+  program.UpdateES3UniformBlocks(result);
+  EXPECT_TRUE(program.IsCached(ProgramInfoManager::kES3UniformBlocks));
+  GLint uniform_block_count = 0;
+  EXPECT_TRUE(program.GetProgramiv(
+      GL_ACTIVE_UNIFORM_BLOCKS, &uniform_block_count));
+  EXPECT_EQ(data.header.num_uniform_blocks,
+            static_cast<uint32_t>(uniform_block_count));
+  GLint max_name_length = 0;
+  EXPECT_TRUE(program.GetProgramiv(
+      GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_name_length));
+  for (uint32_t ii = 0; ii < data.header.num_uniform_blocks; ++ii) {
+    EXPECT_EQ(ii, program.GetUniformBlockIndex(kName[ii]));
+    const ProgramInfoManager::Program::UniformBlock* info =
+        program.GetUniformBlock(ii);
+    EXPECT_TRUE(info != NULL);
+    EXPECT_EQ(data.entry[ii].binding, info->binding);
+    EXPECT_EQ(data.entry[ii].data_size, info->data_size);
+    EXPECT_EQ(data.entry[ii].active_uniforms,
+              info->active_uniform_indices.size());
+    for (uint32_t uu = 0; uu < data.entry[ii].active_uniforms; ++uu) {
+      EXPECT_EQ(kIndices[ii][uu], info->active_uniform_indices[uu]);
+    }
+    EXPECT_EQ(data.entry[ii].referenced_by_vertex_shader,
+              static_cast<GLboolean>(info->referenced_by_vertex_shader));
+    EXPECT_EQ(data.entry[ii].referenced_by_fragment_shader,
+              static_cast<GLboolean>(info->referenced_by_fragment_shader));
+    EXPECT_EQ(kName[ii], info->name);
+    EXPECT_GE(max_name_length, static_cast<GLint>(info->name.size()) + 1);
+  }
+
+  EXPECT_EQ(GL_INVALID_INDEX, program.GetUniformBlockIndex("BadName"));
+  EXPECT_EQ(NULL, program.GetUniformBlock(data.header.num_uniform_blocks));
+}
+
+}  // namespace gles2
+}  // namespace gpu
+
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 138d858..73a1059 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -178,6 +178,7 @@
         'command_buffer/client/fenced_allocator_test.cc',
         'command_buffer/client/gles2_implementation_unittest.cc',
         'command_buffer/client/mapped_memory_unittest.cc',
+        'command_buffer/client/program_info_manager_unittest.cc',
         'command_buffer/client/query_tracker_unittest.cc',
         'command_buffer/client/ring_buffer_test.cc',
         'command_buffer/client/transfer_buffer_unittest.cc',
diff --git a/gpu/gpu_unittests.isolate b/gpu/gpu_unittests.isolate
index 3380606..48fb1c5 100644
--- a/gpu/gpu_unittests.isolate
+++ b/gpu/gpu_unittests.isolate
@@ -21,6 +21,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -37,6 +39,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
@@ -49,6 +53,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/ios/chrome/browser/arch_util.cc b/ios/chrome/browser/arch_util.cc
new file mode 100644
index 0000000..eb0111b
--- /dev/null
+++ b/ios/chrome/browser/arch_util.cc
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/arch_util.h"
+
+namespace arch_util {
+
+// const char[] can be initialized only with literal.
+#define _ARM_ARCH "arm"
+#define _ARM_64_ARCH "arm64"
+
+const char kARMArch[] = _ARM_ARCH;
+
+const char kARM64Arch[] = _ARM_64_ARCH;
+
+#if defined(__LP64__)
+const char kCurrentArch[] = _ARM_64_ARCH;
+#else
+const char kCurrentArch[] = _ARM_ARCH;
+#endif
+
+}  // namespace arch_util
diff --git a/ios/chrome/browser/arch_util.h b/ios/chrome/browser/arch_util.h
new file mode 100644
index 0000000..74ab9f2
--- /dev/null
+++ b/ios/chrome/browser/arch_util.h
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_ARCH_UTIL_H_
+#define IOS_CHROME_BROWSER_ARCH_UTIL_H_
+
+namespace arch_util {
+
+// Architecture of the currently running binary. Depends on the combination of
+// app binary archs and device's arch. e.g. for arm7/arm64 fat binary running
+// on 64-bit processor the value will be "arm64", but for the same fat binary
+// running on 32-bit processor the value will be "arm".
+extern const char kCurrentArch[];
+
+// Constant for 32-bit ARM architecture.
+extern const char kARMArch[];
+
+// Constant for 64-bit ARM architecture.
+extern const char kARM64Arch[];
+
+}  // namespace arch_util
+
+#endif  // IOS_CHROME_BROWSER_ARCH_UTIL_H_
diff --git a/ios/chrome/browser/chrome_url_constants.cc b/ios/chrome/browser/chrome_url_constants.cc
new file mode 100644
index 0000000..f8b2c91
--- /dev/null
+++ b/ios/chrome/browser/chrome_url_constants.cc
@@ -0,0 +1,9 @@
+// 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 "ios/chrome/browser/chrome_url_constants.h"
+
+const char kChromeUIExternalFileHost[] = "external-file";
+const char kChromeUIOmahaHost[] = "omaha";
+const char kChromeUISetUpForTestingHost[] = "setupfortesting";
diff --git a/ios/chrome/browser/chrome_url_constants.h b/ios/chrome/browser/chrome_url_constants.h
new file mode 100644
index 0000000..df061b46
--- /dev/null
+++ b/ios/chrome/browser/chrome_url_constants.h
@@ -0,0 +1,15 @@
+// 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.
+
+// Contains constants for known URLs and portions thereof.
+
+#ifndef IOS_CHROME_BROWSER_CHROME_URL_CONSTANTS_H_
+#define IOS_CHROME_BROWSER_CHROME_URL_CONSTANTS_H_
+
+// URL components for Chrome on iOS.
+extern const char kChromeUIExternalFileHost[];
+extern const char kChromeUIOmahaHost[];
+extern const char kChromeUISetUpForTestingHost[];
+
+#endif  // IOS_CHROME_BROWSER_CHROME_URL_CONSTANTS_H_
diff --git a/ios/chrome/browser/translate/translate_service_ios_unittest.cc b/ios/chrome/browser/translate/translate_service_ios_unittest.cc
index 0cbd6b00..f9ea614b 100644
--- a/ios/chrome/browser/translate/translate_service_ios_unittest.cc
+++ b/ios/chrome/browser/translate/translate_service_ios_unittest.cc
@@ -10,9 +10,6 @@
 #include "url/gurl.h"
 
 TEST(TranslateServiceIOSTest, CheckTranslatableURL) {
-  // TODO(droger): Remove this once http://crbug.com/437332 is fixed.
-  ios::TestChromeProviderInitializer test_chrome_provider_initializer;
-
   GURL empty_url = GURL(std::string());
   EXPECT_FALSE(TranslateServiceIOS::IsTranslatableURL(empty_url));
 
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp
index 76cb0c8d..89f7abe 100644
--- a/ios/chrome/ios_chrome.gyp
+++ b/ios/chrome/ios_chrome.gyp
@@ -48,8 +48,12 @@
         'browser/application_context.h',
         'browser/application_context_impl.cc',
         'browser/application_context_impl.h',
+        'browser/arch_util.cc',
+        'browser/arch_util.h',
         'browser/browser_state/browser_state_otr_helper.cc',
         'browser/browser_state/browser_state_otr_helper.h',
+        'browser/chrome_url_constants.cc',
+        'browser/chrome_url_constants.h',
         'browser/infobars/confirm_infobar_controller.h',
         'browser/infobars/confirm_infobar_controller.mm',
         'browser/infobars/infobar.h',
diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp
index 17370a9..ce9adfa 100644
--- a/ios/chrome/ios_chrome_tests.gyp
+++ b/ios/chrome/ios_chrome_tests.gyp
@@ -11,7 +11,6 @@
       'type': '<(gtest_target_type)',
       'dependencies': [
         '../../base/base.gyp:base',
-        '../../base/base.gyp:run_all_unittests',
         '../../base/base.gyp:test_support_base',
         '../../net/net.gyp:net_test_support',
         '../../testing/gmock.gyp:gmock',
@@ -21,6 +20,7 @@
         '../web/ios_web.gyp:ios_web',
         '../web/ios_web.gyp:test_support_ios_web',
         'ios_chrome.gyp:ios_chrome_browser',
+        'ios_chrome_test_support',
       ],
       'sources': [
         'browser/net/image_fetcher_unittest.mm',
@@ -35,10 +35,14 @@
       'type': 'static_library',
       'dependencies': [
         '../../base/base.gyp:base',
+        '../../testing/gtest.gyp:gtest',
         '../provider/ios_provider_chrome.gyp:ios_provider_chrome_browser',
         'ios_chrome.gyp:ios_chrome_browser',
       ],
       'sources': [
+        'test/ios_chrome_unit_test_suite.cc',
+        'test/ios_chrome_unit_test_suite.h',
+        'test/run_all_unittests.cc',
         'test/testing_application_context.cc',
         'test/testing_application_context.h',
       ],
diff --git a/ios/chrome/test/ios_chrome_unit_test_suite.cc b/ios/chrome/test/ios_chrome_unit_test_suite.cc
new file mode 100644
index 0000000..1043e59e
--- /dev/null
+++ b/ios/chrome/test/ios_chrome_unit_test_suite.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 "ios/chrome/test/ios_chrome_unit_test_suite.h"
+
+#include "ios/public/test/test_chrome_browser_provider.h"
+#include "ios/public/test/test_chrome_provider_initializer.h"
+#include "ios/web/public/web_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ui_base_paths.h"
+#include "url/url_util.h"
+
+namespace {
+
+class IOSChromeUnitTestSuiteInitializer
+    : public testing::EmptyTestEventListener {
+ public:
+  IOSChromeUnitTestSuiteInitializer() {}
+  ~IOSChromeUnitTestSuiteInitializer() override {}
+
+  void OnTestStart(const testing::TestInfo& test_info) override {
+    web_client_.reset(new web::WebClient());
+    web::SetWebClient(web_client_.get());
+    test_ios_chrome_provider_initializer_.reset(
+        new ios::TestChromeProviderInitializer());
+  }
+
+  void OnTestEnd(const testing::TestInfo& test_info) override {
+    web_client_.reset();
+    web::SetWebClient(NULL);
+    test_ios_chrome_provider_initializer_.reset();
+  }
+
+ private:
+  scoped_ptr<web::WebClient> web_client_;
+  scoped_ptr<ios::TestChromeProviderInitializer>
+      test_ios_chrome_provider_initializer_;
+  DISALLOW_COPY_AND_ASSIGN(IOSChromeUnitTestSuiteInitializer);
+};
+
+}  // namespace
+
+IOSChromeUnitTestSuite::IOSChromeUnitTestSuite(int argc, char** argv)
+    : base::TestSuite(argc, argv) {
+}
+
+IOSChromeUnitTestSuite::~IOSChromeUnitTestSuite() {
+}
+
+void IOSChromeUnitTestSuite::Initialize() {
+  // Add an additional listener to do the extra initialization for unit tests.
+  // It will be started before the base class listeners and ended after the
+  // base class listeners.
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new IOSChromeUnitTestSuiteInitializer);
+
+  ui::RegisterPathProvider();
+
+  {
+    ios::TestChromeBrowserProvider provider;
+    url::AddStandardScheme(provider.GetChromeUIScheme());
+  }
+
+  base::TestSuite::Initialize();
+}
diff --git a/ios/chrome/test/ios_chrome_unit_test_suite.h b/ios/chrome/test/ios_chrome_unit_test_suite.h
new file mode 100644
index 0000000..5185ab56
--- /dev/null
+++ b/ios/chrome/test/ios_chrome_unit_test_suite.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 IOS_CHROME_TEST_IOS_CHROME_UNIT_TEST_SUITE_H_
+#define IOS_CHROME_TEST_IOS_CHROME_UNIT_TEST_SUITE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/test/test_suite.h"
+
+// Test suite for unit tests.
+class IOSChromeUnitTestSuite : public base::TestSuite {
+ public:
+  IOSChromeUnitTestSuite(int argc, char** argv);
+  ~IOSChromeUnitTestSuite() override;
+
+  // base::TestSuite overrides:
+  void Initialize() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(IOSChromeUnitTestSuite);
+};
+
+#endif  // IOS_CHROME_TEST_IOS_CHROME_UNIT_TEST_SUITE_H_
diff --git a/ios/chrome/test/run_all_unittests.cc b/ios/chrome/test/run_all_unittests.cc
new file mode 100644
index 0000000..f7c0f95
--- /dev/null
+++ b/ios/chrome/test/run_all_unittests.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "ios/chrome/test/ios_chrome_unit_test_suite.h"
+
+int main(int argc, char** argv) {
+  IOSChromeUnitTestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::Bind(&IOSChromeUnitTestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h
index 2d677aa..e57008b 100644
--- a/ipc/ipc_message.h
+++ b/ipc/ipc_message.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "base/debug/trace_event.h"
 #include "base/memory/ref_counted.h"
 #include "base/pickle.h"
 #include "base/trace_event/trace_event.h"
diff --git a/media/BUILD.gn b/media/BUILD.gn
index c4d3ea3..f71d6f8 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -347,7 +347,7 @@
     }
   }
 
-  if (cpu_arch != "arm" && is_chromeos && use_x11) {
+  if (cpu_arch != "arm" && is_chromeos) {
     sources += [
       "filters/h264_bitstream_buffer.cc",
       "filters/h264_bitstream_buffer.h",
diff --git a/media/OWNERS b/media/OWNERS
index b7a0a75..fdb8c86 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -3,7 +3,6 @@
 jrummell@chromium.org
 sandersd@chromium.org
 scherkus@chromium.org
-vrk@chromium.org
 wolenetz@chromium.org
 xhwang@chromium.org
 
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index 9db1cb9..48dd8dcc 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -15,6 +15,7 @@
     "//media",
     "//media:shared_memory_support",
     "//net",
+    "//skia",
     "//third_party/WebKit/public:blink",
     "//ui/gfx",
     "//ui/gfx/geometry",
diff --git a/media/blink/media_blink.gyp b/media/blink/media_blink.gyp
index 71751fe..6c6ccc7 100644
--- a/media/blink/media_blink.gyp
+++ b/media/blink/media_blink.gyp
@@ -15,6 +15,7 @@
         '../../gpu/blink/gpu_blink.gyp:gpu_blink',
         '../../ui/gfx/gfx.gyp:gfx_geometry',
         '../../net/net.gyp:net',
+        '../../skia/skia.gyp:skia',
         '../../third_party/WebKit/public/blink.gyp:blink',
         '../media.gyp:media',
         '../media.gyp:shared_memory_support',
diff --git a/media/blink/webcontentdecryptionmoduleaccess_impl.cc b/media/blink/webcontentdecryptionmoduleaccess_impl.cc
index ec4e9194..ab98b43 100644
--- a/media/blink/webcontentdecryptionmoduleaccess_impl.cc
+++ b/media/blink/webcontentdecryptionmoduleaccess_impl.cc
@@ -2,24 +2,31 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "webcontentdecryptionmoduleaccess_impl.h"
+#include "media/blink/webcontentdecryptionmoduleaccess_impl.h"
 
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/message_loop/message_loop_proxy.h"
-#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
-#include "webcontentdecryptionmodule_impl.h"
+#include "media/blink/webencryptedmediaclient_impl.h"
 
 namespace media {
 
 // The caller owns the created cdm (passed back using |result|).
-static void CreateCdm(CdmFactory* cdm_factory,
-                      blink::WebSecurityOrigin security_origin,
-                      blink::WebString key_system,
+static void CreateCdm(const base::WeakPtr<WebEncryptedMediaClientImpl>& client,
+                      const blink::WebString& key_system,
+                      const blink::WebSecurityOrigin& security_origin,
                       blink::WebContentDecryptionModuleResult result) {
-  WebContentDecryptionModuleImpl::Create(cdm_factory, security_origin,
-                                         key_system, result);
+  // If |client| is gone (due to the frame getting destroyed), it is
+  // impossible to create the CDM, so fail.
+  if (!client) {
+    result.completeWithError(
+        blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
+        "Failed to create CDM.");
+    return;
+  }
+
+  client->CreateCdm(key_system, security_origin, result);
 }
 
 WebContentDecryptionModuleAccessImpl*
@@ -27,20 +34,20 @@
     const blink::WebString& key_system,
     const blink::WebMediaKeySystemConfiguration& configuration,
     const blink::WebSecurityOrigin& security_origin,
-    CdmFactory* cdm_factory) {
+    const base::WeakPtr<WebEncryptedMediaClientImpl>& client) {
   return new WebContentDecryptionModuleAccessImpl(key_system, configuration,
-                                                  security_origin, cdm_factory);
+                                                  security_origin, client);
 }
 
 WebContentDecryptionModuleAccessImpl::WebContentDecryptionModuleAccessImpl(
     const blink::WebString& key_system,
     const blink::WebMediaKeySystemConfiguration& configuration,
     const blink::WebSecurityOrigin& security_origin,
-    CdmFactory* cdm_factory)
+    const base::WeakPtr<WebEncryptedMediaClientImpl>& client)
     : key_system_(key_system),
       configuration_(configuration),
       security_origin_(security_origin),
-      cdm_factory_(cdm_factory) {
+      client_(client) {
 }
 
 WebContentDecryptionModuleAccessImpl::~WebContentDecryptionModuleAccessImpl() {
@@ -58,8 +65,8 @@
   // blink side, copy all values needed by CreateCdm() in case the blink object
   // gets garbage-collected.
   base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE, base::Bind(&CreateCdm, cdm_factory_, security_origin_,
-                            key_system_, result));
+      FROM_HERE,
+      base::Bind(&CreateCdm, client_, key_system_, security_origin_, result));
 }
 
 }  // namespace media
diff --git a/media/blink/webcontentdecryptionmoduleaccess_impl.h b/media/blink/webcontentdecryptionmoduleaccess_impl.h
index 9d54823..131bb21 100644
--- a/media/blink/webcontentdecryptionmoduleaccess_impl.h
+++ b/media/blink/webcontentdecryptionmoduleaccess_impl.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "media/base/cdm_factory.h"
 #include "third_party/WebKit/public/platform/WebContentDecryptionModuleAccess.h"
 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h"
@@ -19,6 +20,8 @@
 
 namespace media {
 
+class WebEncryptedMediaClientImpl;
+
 class WebContentDecryptionModuleAccessImpl
     : public blink::WebContentDecryptionModuleAccess {
  public:
@@ -26,7 +29,7 @@
       const blink::WebString& key_system,
       const blink::WebMediaKeySystemConfiguration& configuration,
       const blink::WebSecurityOrigin& security_origin,
-      CdmFactory* cdm_factory);
+      const base::WeakPtr<WebEncryptedMediaClientImpl>& client);
   virtual ~WebContentDecryptionModuleAccessImpl();
 
   // blink::WebContentDecryptionModuleAccess interface.
@@ -39,14 +42,16 @@
       const blink::WebString& key_system,
       const blink::WebMediaKeySystemConfiguration& configuration,
       const blink::WebSecurityOrigin& security_origin,
-      CdmFactory* cdm_factory);
+      const base::WeakPtr<WebEncryptedMediaClientImpl>& client);
 
   DISALLOW_COPY_AND_ASSIGN(WebContentDecryptionModuleAccessImpl);
 
   blink::WebString key_system_;
   blink::WebMediaKeySystemConfiguration configuration_;
   blink::WebSecurityOrigin security_origin_;
-  CdmFactory* cdm_factory_;
+
+  // Keep a WeakPtr as client is owned by render_frame_impl.
+  base::WeakPtr<WebEncryptedMediaClientImpl> client_;
 };
 
 }  // namespace media
diff --git a/media/blink/webencryptedmediaclient_impl.cc b/media/blink/webencryptedmediaclient_impl.cc
index 5cd9611..264d5c6d 100644
--- a/media/blink/webencryptedmediaclient_impl.cc
+++ b/media/blink/webencryptedmediaclient_impl.cc
@@ -15,6 +15,7 @@
 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
+#include "webcontentdecryptionmodule_impl.h"
 #include "webcontentdecryptionmoduleaccess_impl.h"
 
 namespace media {
@@ -189,7 +190,7 @@
 WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl(
     scoped_ptr<CdmFactory> cdm_factory,
     MediaPermission* media_permission)
-    : cdm_factory_(cdm_factory.Pass()) {
+    : cdm_factory_(cdm_factory.Pass()), weak_factory_(this) {
   // TODO(sandersd): Use |media_permission| to check for media permissions in
   // this class.
   DCHECK(media_permission);
@@ -237,7 +238,7 @@
     reporter->ReportSupported();
     request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
         request.keySystem(), blink::WebMediaKeySystemConfiguration(),
-        request.securityOrigin(), cdm_factory_.get()));
+        request.securityOrigin(), weak_factory_.GetWeakPtr()));
     return;
   }
 
@@ -250,7 +251,7 @@
       reporter->ReportSupported();
       request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
           request.keySystem(), accumulated_configuration,
-          request.securityOrigin(), cdm_factory_.get()));
+          request.securityOrigin(), weak_factory_.GetWeakPtr()));
       return;
     }
   }
@@ -260,6 +261,14 @@
       "None of the requested configurations were supported.");
 }
 
+void WebEncryptedMediaClientImpl::CreateCdm(
+    const blink::WebString& key_system,
+    const blink::WebSecurityOrigin& security_origin,
+    blink::WebContentDecryptionModuleResult result) {
+  WebContentDecryptionModuleImpl::Create(cdm_factory_.get(), security_origin,
+                                         key_system, result);
+}
+
 // Lazily create Reporters.
 WebEncryptedMediaClientImpl::Reporter* WebEncryptedMediaClientImpl::GetReporter(
     const std::string& key_system) {
diff --git a/media/blink/webencryptedmediaclient_impl.h b/media/blink/webencryptedmediaclient_impl.h
index d101ecb..7b606dc4 100644
--- a/media/blink/webencryptedmediaclient_impl.h
+++ b/media/blink/webencryptedmediaclient_impl.h
@@ -9,8 +9,10 @@
 
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "media/base/cdm_factory.h"
 #include "media/base/media_export.h"
+#include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
 #include "third_party/WebKit/public/platform/WebEncryptedMediaClient.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 
@@ -29,6 +31,12 @@
   virtual void requestMediaKeySystemAccess(
       blink::WebEncryptedMediaRequest request);
 
+  // Create the CDM for |key_system| and |security_origin|. The caller owns
+  // the created cdm (passed back using |result|).
+  void CreateCdm(const blink::WebString& key_system,
+                 const blink::WebSecurityOrigin& security_origin,
+                 blink::WebContentDecryptionModuleResult result);
+
  private:
   // Report usage of key system to UMA. There are 2 different counts logged:
   // 1. The key system is requested.
@@ -45,6 +53,8 @@
   Reporters reporters_;
 
   scoped_ptr<CdmFactory> cdm_factory_;
+
+  base::WeakPtrFactory<WebEncryptedMediaClientImpl> weak_factory_;
 };
 
 }  // namespace media
diff --git a/media/media_unittests.isolate b/media/media_unittests.isolate
index cea8c33f..669f3fc3 100644
--- a/media/media_unittests.isolate
+++ b/media/media_unittests.isolate
@@ -31,6 +31,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/xvfb.py',
@@ -48,6 +50,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '<(PRODUCT_DIR)/ffmpegsumo.so',
@@ -63,6 +67,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '<(PRODUCT_DIR)/ffmpegsumo.dll',
diff --git a/media/test/data/eme_player_js/player_utils.js b/media/test/data/eme_player_js/player_utils.js
index 60d4b613..23f4a29 100644
--- a/media/test/data/eme_player_js/player_utils.js
+++ b/media/test/data/eme_player_js/player_utils.js
@@ -85,7 +85,8 @@
 
   this.registerDefaultEventListeners(player);
   Utils.timeLog('Setting video media keys: ' + player.testConfig.keySystem);
-  return navigator.requestMediaKeySystemAccess(player.testConfig.keySystem)
+  return navigator.requestMediaKeySystemAccess(
+      player.testConfig.keySystem, [{}])
       .then(function(access) { return access.createMediaKeys(); })
       .then(function(mediaKeys) {
         return player.video.setMediaKeys(mediaKeys);
diff --git a/media/video/picture.cc b/media/video/picture.cc
index 6b4c927..6205795 100644
--- a/media/video/picture.cc
+++ b/media/video/picture.cc
@@ -7,9 +7,17 @@
 namespace media {
 
 PictureBuffer::PictureBuffer(int32 id, gfx::Size size, uint32 texture_id)
+    : id_(id), size_(size), texture_id_(texture_id), internal_texture_id_(0) {
+}
+
+PictureBuffer::PictureBuffer(int32 id,
+                             gfx::Size size,
+                             uint32 texture_id,
+                             uint32 internal_texture_id)
     : id_(id),
       size_(size),
-      texture_id_(texture_id) {
+      texture_id_(texture_id),
+      internal_texture_id_(internal_texture_id) {
 }
 
 PictureBuffer::PictureBuffer(int32 id,
@@ -19,6 +27,7 @@
     : id_(id),
       size_(size),
       texture_id_(texture_id),
+      internal_texture_id_(0),
       texture_mailbox_(texture_mailbox) {
 }
 
diff --git a/media/video/picture.h b/media/video/picture.h
index 2fe10bf2..1fb5096 100644
--- a/media/video/picture.h
+++ b/media/video/picture.h
@@ -21,6 +21,10 @@
   PictureBuffer(int32 id,
                 gfx::Size size,
                 uint32 texture_id,
+                uint32 internal_texture_id);
+  PictureBuffer(int32 id,
+                gfx::Size size,
+                uint32 texture_id,
                 const gpu::Mailbox& texture_mailbox);
 
   // Returns the client-specified id of the buffer.
@@ -40,6 +44,8 @@
     return texture_id_;
   }
 
+  uint32 internal_texture_id() const { return internal_texture_id_; }
+
   const gpu::Mailbox& texture_mailbox() const {
     return texture_mailbox_;
   }
@@ -48,6 +54,7 @@
   int32 id_;
   gfx::Size size_;
   uint32 texture_id_;
+  uint32 internal_texture_id_;
   gpu::Mailbox texture_mailbox_;
 };
 
diff --git a/mojo/services/html_viewer/weblayertreeview_impl.cc b/mojo/services/html_viewer/weblayertreeview_impl.cc
index 0c2811a9..a9a6945e 100644
--- a/mojo/services/html_viewer/weblayertreeview_impl.cc
+++ b/mojo/services/html_viewer/weblayertreeview_impl.cc
@@ -59,7 +59,7 @@
 WebLayerTreeViewImpl::~WebLayerTreeViewImpl() {
 }
 
-void WebLayerTreeViewImpl::WillBeginMainFrame(int frame_id) {
+void WebLayerTreeViewImpl::WillBeginMainFrame() {
 }
 
 void WebLayerTreeViewImpl::DidBeginMainFrame() {
diff --git a/mojo/services/html_viewer/weblayertreeview_impl.h b/mojo/services/html_viewer/weblayertreeview_impl.h
index 42ae1bc..269fc9f4 100644
--- a/mojo/services/html_viewer/weblayertreeview_impl.h
+++ b/mojo/services/html_viewer/weblayertreeview_impl.h
@@ -48,7 +48,7 @@
   void set_view(mojo::View* view) { view_ = view; }
 
   // cc::LayerTreeHostClient implementation.
-  void WillBeginMainFrame(int frame_id) override;
+  void WillBeginMainFrame() override;
   void DidBeginMainFrame() override;
   void BeginMainFrame(const cc::BeginFrameArgs& args) override;
   void Layout() override;
diff --git a/mojo/services/network/udp_socket_unittest.cc b/mojo/services/network/udp_socket_unittest.cc
deleted file mode 100644
index ddb9d93d..0000000
--- a/mojo/services/network/udp_socket_unittest.cc
+++ /dev/null
@@ -1,458 +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.
-
-#include "base/at_exit.h"
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "mojo/services/network/public/cpp/udp_socket_wrapper.h"
-#include "mojo/services/network/public/interfaces/network_service.mojom.h"
-#include "mojo/services/network/public/interfaces/udp_socket.mojom.h"
-#include "mojo/shell/shell_test_helper.h"
-#include "net/base/net_errors.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/callback.h"
-#include "url/gurl.h"
-
-namespace mojo {
-namespace service {
-namespace {
-
-NetAddressPtr GetLocalHostWithAnyPort() {
-  NetAddressPtr addr(NetAddress::New());
-  addr->family = NET_ADDRESS_FAMILY_IPV4;
-  addr->ipv4 = NetAddressIPv4::New();
-  addr->ipv4->port = 0;
-  addr->ipv4->addr.resize(4);
-  addr->ipv4->addr[0] = 127;
-  addr->ipv4->addr[1] = 0;
-  addr->ipv4->addr[2] = 0;
-  addr->ipv4->addr[3] = 1;
-
-  return addr.Pass();
-}
-
-Array<uint8_t> CreateTestMessage(uint8_t initial, size_t size) {
-  Array<uint8_t> array(size);
-  for (size_t i = 0; i < size; ++i)
-    array[i] = static_cast<uint8_t>((i + initial) % 256);
-  return array.Pass();
-}
-
-template <typename CallbackType>
-class TestCallbackBase {
- public:
-  TestCallbackBase() : state_(nullptr), run_loop_(nullptr), ran_(false) {}
-
-  ~TestCallbackBase() {
-    state_->set_test_callback(nullptr);
-  }
-
-  CallbackType callback() const { return callback_; }
-
-  void WaitForResult() {
-    if (ran_)
-      return;
-
-    base::RunLoop run_loop;
-    run_loop_ = &run_loop;
-    run_loop.Run();
-    run_loop_ = nullptr;
-  }
-
- protected:
-  struct StateBase : public CallbackType::Runnable {
-    StateBase() : test_callback_(nullptr) {}
-    virtual ~StateBase() {}
-
-    void set_test_callback(TestCallbackBase* test_callback) {
-      test_callback_ = test_callback;
-    }
-
-   protected:
-    void NotifyRun() const {
-      if (test_callback_) {
-        test_callback_->ran_ = true;
-        if (test_callback_->run_loop_)
-          test_callback_->run_loop_->Quit();
-      }
-    }
-
-    TestCallbackBase* test_callback_;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(StateBase);
-  };
-
-  // Takes ownership of |state|, and guarantees that it lives at least as long
-  // as this object.
-  void Initialize(StateBase* state) {
-    state_ = state;
-    state_->set_test_callback(this);
-    callback_ = CallbackType(
-        static_cast<typename CallbackType::Runnable*>(state_));
-  }
-
- private:
-  // The lifespan is managed by |callback_| (and its copies).
-  StateBase* state_;
-  CallbackType callback_;
-  base::RunLoop* run_loop_;
-  bool ran_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestCallbackBase);
-};
-
-class TestCallback : public TestCallbackBase<Callback<void(NetworkErrorPtr)>> {
- public:
-  TestCallback() {
-    Initialize(new State());
-  }
-  ~TestCallback() {}
-
-  const NetworkErrorPtr& result() const { return result_; }
-
- private:
-  struct State: public StateBase {
-    ~State() override {}
-
-    void Run(NetworkErrorPtr result) const override {
-      if (test_callback_) {
-        TestCallback* callback = static_cast<TestCallback*>(test_callback_);
-        callback->result_ = result.Pass();
-      }
-      NotifyRun();
-    }
-  };
-
-  NetworkErrorPtr result_;
-};
-
-class TestCallbackWithAddress
-    : public TestCallbackBase<Callback<void(NetworkErrorPtr, NetAddressPtr)>> {
- public:
-  TestCallbackWithAddress() {
-    Initialize(new State());
-  }
-  ~TestCallbackWithAddress() {}
-
-  const NetworkErrorPtr& result() const { return result_; }
-  const NetAddressPtr& net_address() const { return net_address_; }
-
- private:
-  struct State : public StateBase {
-    ~State() override {}
-
-    void Run(NetworkErrorPtr result, NetAddressPtr net_address) const override {
-      if (test_callback_) {
-        TestCallbackWithAddress* callback =
-            static_cast<TestCallbackWithAddress*>(test_callback_);
-        callback->result_ = result.Pass();
-        callback->net_address_ = net_address.Pass();
-      }
-      NotifyRun();
-    }
-  };
-
-  NetworkErrorPtr result_;
-  NetAddressPtr net_address_;
-};
-
-class TestCallbackWithUint32
-    : public TestCallbackBase<Callback<void(uint32_t)>> {
- public:
-  TestCallbackWithUint32() : result_(0) {
-    Initialize(new State());
-  }
-  ~TestCallbackWithUint32() {}
-
-  uint32_t result() const { return result_; }
-
- private:
-  struct State : public StateBase {
-    ~State() override {}
-
-    void Run(uint32_t result) const override {
-      if (test_callback_) {
-        TestCallbackWithUint32* callback =
-            static_cast<TestCallbackWithUint32*>(test_callback_);
-        callback->result_ = result;
-      }
-      NotifyRun();
-    }
-  };
-
-  uint32_t result_;
-};
-
-class TestReceiveCallback
-    : public TestCallbackBase<
-        Callback<void(NetworkErrorPtr, NetAddressPtr, Array<uint8_t>)>> {
- public:
-  TestReceiveCallback() {
-    Initialize(new State());
-  }
-  ~TestReceiveCallback() {}
-
-  const NetworkErrorPtr& result() const { return result_; }
-  const NetAddressPtr& src_addr() const { return src_addr_; }
-  const Array<uint8_t>& data() const { return data_; }
-
- private:
-  struct State : public StateBase {
-    ~State() override {}
-
-    void Run(NetworkErrorPtr result,
-             NetAddressPtr src_addr,
-             Array<uint8_t> data) const override {
-      if (test_callback_) {
-        TestReceiveCallback* callback =
-            static_cast<TestReceiveCallback*>(test_callback_);
-        callback->result_ = result.Pass();
-        callback->src_addr_ = src_addr.Pass();
-        callback->data_ = data.Pass();
-      }
-      NotifyRun();
-    }
-  };
-
-  NetworkErrorPtr result_;
-  NetAddressPtr src_addr_;
-  Array<uint8_t> data_;
-};
-
-class UDPSocketTest : public testing::Test {
- public:
-  UDPSocketTest() {}
-  virtual ~UDPSocketTest() {}
-
-  virtual void SetUp() override {
-    test_helper_.Init();
-
-    test_helper_.application_manager()->ConnectToService(
-        GURL("mojo:network_service"), &network_service_);
-
-    network_service_->CreateUDPSocket(GetProxy(&udp_socket_));
-    udp_socket_.set_client(&udp_socket_client_);
-  }
-
- protected:
-  struct ReceiveResult {
-    NetworkErrorPtr result;
-    NetAddressPtr addr;
-    Array<uint8_t> data;
-  };
-
-  class UDPSocketClientImpl : public UDPSocketClient {
-   public:
-
-    UDPSocketClientImpl() : run_loop_(nullptr), expected_receive_count_(0) {}
-
-    ~UDPSocketClientImpl() override {
-      while (!results_.empty()) {
-        delete results_.front();
-        results_.pop();
-      }
-    }
-
-    void OnReceived(NetworkErrorPtr result,
-                    NetAddressPtr src_addr,
-                    Array<uint8_t> data) override {
-      ReceiveResult* entry = new ReceiveResult();
-      entry->result = result.Pass();
-      entry->addr = src_addr.Pass();
-      entry->data = data.Pass();
-
-      results_.push(entry);
-
-      if (results_.size() == expected_receive_count_ && run_loop_) {
-        expected_receive_count_ = 0;
-        run_loop_->Quit();
-      }
-    }
-
-    base::RunLoop* run_loop_;
-    std::queue<ReceiveResult*> results_;
-    size_t expected_receive_count_;
-
-    DISALLOW_COPY_AND_ASSIGN(UDPSocketClientImpl);
-  };
-
-  std::queue<ReceiveResult*>* GetReceiveResults() {
-    return &udp_socket_client_.results_;
-  }
-
-  void WaitForReceiveResults(size_t count) {
-    if (GetReceiveResults()->size() == count)
-      return;
-
-    udp_socket_client_.expected_receive_count_ = count;
-    base::RunLoop run_loop;
-    udp_socket_client_.run_loop_ = &run_loop;
-    run_loop.Run();
-    udp_socket_client_.run_loop_ = nullptr;
-  }
-
-  base::ShadowingAtExitManager at_exit_;
-  shell::ShellTestHelper test_helper_;
-
-  NetworkServicePtr network_service_;
-  UDPSocketPtr udp_socket_;
-  UDPSocketClientImpl udp_socket_client_;
-
-  DISALLOW_COPY_AND_ASSIGN(UDPSocketTest);
-};
-
-}  // namespace
-
-TEST_F(UDPSocketTest, Settings) {
-  TestCallback callback1;
-  udp_socket_->AllowAddressReuse(callback1.callback());
-  callback1.WaitForResult();
-  EXPECT_EQ(net::OK, callback1.result()->code);
-
-  // Should fail because the socket hasn't been bound.
-  TestCallback callback2;
-  udp_socket_->SetSendBufferSize(1024, callback2.callback());
-  callback2.WaitForResult();
-  EXPECT_NE(net::OK, callback2.result()->code);
-
-  // Should fail because the socket hasn't been bound.
-  TestCallback callback3;
-  udp_socket_->SetReceiveBufferSize(2048, callback3.callback());
-  callback3.WaitForResult();
-  EXPECT_NE(net::OK, callback3.result()->code);
-
-  TestCallbackWithAddress callback4;
-  udp_socket_->Bind(GetLocalHostWithAnyPort(), callback4.callback());
-  callback4.WaitForResult();
-  EXPECT_EQ(net::OK, callback4.result()->code);
-  EXPECT_NE(0u, callback4.net_address()->ipv4->port);
-
-  // Should fail because the socket has been bound.
-  TestCallback callback5;
-  udp_socket_->AllowAddressReuse(callback5.callback());
-  callback5.WaitForResult();
-  EXPECT_NE(net::OK, callback5.result()->code);
-
-  TestCallback callback6;
-  udp_socket_->SetSendBufferSize(1024, callback6.callback());
-  callback6.WaitForResult();
-  EXPECT_EQ(net::OK, callback6.result()->code);
-
-  TestCallback callback7;
-  udp_socket_->SetReceiveBufferSize(2048, callback7.callback());
-  callback7.WaitForResult();
-  EXPECT_EQ(net::OK, callback7.result()->code);
-
-  TestCallbackWithUint32 callback8;
-  udp_socket_->NegotiateMaxPendingSendRequests(0, callback8.callback());
-  callback8.WaitForResult();
-  EXPECT_GT(callback8.result(), 0u);
-
-  TestCallbackWithUint32 callback9;
-  udp_socket_->NegotiateMaxPendingSendRequests(16, callback9.callback());
-  callback9.WaitForResult();
-  EXPECT_GT(callback9.result(), 0u);
-}
-
-TEST_F(UDPSocketTest, TestReadWrite) {
-  TestCallbackWithAddress callback1;
-  udp_socket_->Bind(GetLocalHostWithAnyPort(), callback1.callback());
-  callback1.WaitForResult();
-  ASSERT_EQ(net::OK, callback1.result()->code);
-  ASSERT_NE(0u, callback1.net_address()->ipv4->port);
-
-  NetAddressPtr server_addr = callback1.net_address().Clone();
-
-  UDPSocketPtr client_socket;
-  network_service_->CreateUDPSocket(GetProxy(&client_socket));
-
-  TestCallbackWithAddress callback2;
-  client_socket->Bind(GetLocalHostWithAnyPort(), callback2.callback());
-  callback2.WaitForResult();
-  ASSERT_EQ(net::OK, callback2.result()->code);
-  ASSERT_NE(0u, callback2.net_address()->ipv4->port);
-
-  NetAddressPtr client_addr = callback2.net_address().Clone();
-
-  const size_t kDatagramCount = 6;
-  const size_t kDatagramSize = 255;
-  udp_socket_->ReceiveMore(kDatagramCount);
-
-  for (size_t i = 0; i < kDatagramCount; ++i) {
-    TestCallback callback;
-    client_socket->SendTo(
-        server_addr.Clone(),
-        CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize),
-        callback.callback());
-    callback.WaitForResult();
-    EXPECT_EQ(255, callback.result()->code);
-  }
-
-  WaitForReceiveResults(kDatagramCount);
-  for (size_t i = 0; i < kDatagramCount; ++i) {
-    scoped_ptr<ReceiveResult> result(GetReceiveResults()->front());
-    GetReceiveResults()->pop();
-
-    EXPECT_EQ(static_cast<int>(kDatagramSize), result->result->code);
-    EXPECT_TRUE(result->addr.Equals(client_addr));
-    EXPECT_TRUE(result->data.Equals(
-        CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize)));
-  }
-}
-
-TEST_F(UDPSocketTest, TestUDPSocketWrapper) {
-  UDPSocketWrapper udp_socket(udp_socket_.Pass(), 4, 4);
-
-  TestCallbackWithAddress callback1;
-  udp_socket.Bind(GetLocalHostWithAnyPort(), callback1.callback());
-  callback1.WaitForResult();
-  ASSERT_EQ(net::OK, callback1.result()->code);
-  ASSERT_NE(0u, callback1.net_address()->ipv4->port);
-
-  NetAddressPtr server_addr = callback1.net_address().Clone();
-
-  UDPSocketPtr raw_client_socket;
-  network_service_->CreateUDPSocket(GetProxy(&raw_client_socket));
-  UDPSocketWrapper client_socket(raw_client_socket.Pass(), 4, 4);
-
-  TestCallbackWithAddress callback2;
-  client_socket.Bind(GetLocalHostWithAnyPort(), callback2.callback());
-  callback2.WaitForResult();
-  ASSERT_EQ(net::OK, callback2.result()->code);
-  ASSERT_NE(0u, callback2.net_address()->ipv4->port);
-
-  NetAddressPtr client_addr = callback2.net_address().Clone();
-
-  const size_t kDatagramCount = 16;
-  const size_t kDatagramSize = 255;
-
-  for (size_t i = 1; i < kDatagramCount; ++i) {
-    scoped_ptr<TestCallback[]> send_callbacks(new TestCallback[i]);
-    scoped_ptr<TestReceiveCallback[]> receive_callbacks(
-        new TestReceiveCallback[i]);
-
-    for (size_t j = 0; j < i; ++j) {
-      client_socket.SendTo(
-          server_addr.Clone(),
-          CreateTestMessage(static_cast<uint8_t>(j), kDatagramSize),
-          send_callbacks[j].callback());
-
-      udp_socket.ReceiveFrom(receive_callbacks[j].callback());
-    }
-
-    receive_callbacks[i - 1].WaitForResult();
-
-    for (size_t j = 0; j < i; ++j) {
-      EXPECT_EQ(static_cast<int>(kDatagramSize),
-                receive_callbacks[j].result()->code);
-      EXPECT_TRUE(receive_callbacks[j].src_addr().Equals(client_addr));
-      EXPECT_TRUE(receive_callbacks[j].data().Equals(
-          CreateTestMessage(static_cast<uint8_t>(j), kDatagramSize)));
-    }
-  }
-}
-
-}  // namespace service
-}  // namespace mojo
diff --git a/mojo/services/network/upload_network_service.py b/mojo/services/network/upload_network_service.py
deleted file mode 100755
index ac7b619a..0000000
--- a/mojo/services/network/upload_network_service.py
+++ /dev/null
@@ -1,101 +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.
-
-import argparse
-import imp
-import os
-import subprocess
-import sys
-import tempfile
-import time
-import zipfile
-
-if not sys.platform.startswith("linux"):
-  print "Only support linux for now"
-  sys.exit(1)
-
-root_path = os.path.realpath(
-    os.path.join(
-        os.path.dirname(
-            os.path.realpath(__file__)),
-        os.pardir,
-        os.pardir,
-        os.pardir))
-version = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=root_path)
-version = version.strip()
-
-find_depot_tools_path = os.path.join(root_path, "tools", "find_depot_tools.py")
-find_depot_tools = imp.load_source("find_depot_tools", find_depot_tools_path)
-
-depot_tools_path = find_depot_tools.add_depot_tools_to_path()
-gsutil_exe = os.path.join(depot_tools_path, "third_party", "gsutil", "gsutil")
-
-
-def gsutil_cp(source, dest, dry_run):
-  if dry_run:
-    print "gsutil cp %s %s" % (source, dest)
-  else:
-    subprocess.check_call([gsutil_exe, "cp", source, dest])
-
-
-def upload_mojoms(dry_run):
-  absolute_mojom_directory_path = os.path.join(
-      os.path.dirname(os.path.realpath(__file__)),
-      "public",
-      "interfaces")
-  dest = "gs://mojo/network/" + version + "/" + "mojoms.zip"
-  with tempfile.NamedTemporaryFile() as mojom_zip_file:
-    with zipfile.ZipFile(mojom_zip_file, 'w') as z:
-      for root, _, files in os.walk(absolute_mojom_directory_path):
-        for filename in files:
-          absolute_file_path = os.path.join(root, filename)
-          relative_file_path = os.path.relpath(absolute_file_path, root)
-          z.write(absolute_file_path, relative_file_path)
-    gsutil_cp(mojom_zip_file.name, dest, dry_run)
-
-
-def upload_binary(binary_path, platform, dry_run):
-  absolute_binary_path = os.path.join(root_path, binary_path)
-  binary_dest = "gs://mojo/network/" + version + "/" + platform + ".zip"
-  with tempfile.NamedTemporaryFile() as binary_zip_file:
-    with zipfile.ZipFile(binary_zip_file, 'w') as z:
-      with open(absolute_binary_path) as service_binary:
-        zipinfo = zipfile.ZipInfo("network_service.mojo")
-        zipinfo.external_attr = 0o777 << 16
-        zipinfo.compress_type = zipfile.ZIP_DEFLATED
-        zipinfo.date_time = time.gmtime(os.path.getmtime(absolute_binary_path))
-        z.writestr(zipinfo, service_binary.read())
-    gsutil_cp(binary_zip_file.name, binary_dest, dry_run)
-
-
-def main():
-  parser = argparse.ArgumentParser(
-      description="Upload network service mojoms and binaries to Google " +
-                  "storage")
-  parser.add_argument("-n", "--dry-run", action="store_true", help="Dry run")
-  parser.add_argument(
-      "--linux-x64-binary-path",
-      help="Path to the linux-x64 network service binary relative to the " +
-           "repo root, e.g. out/Release/network_service.mojo")
-  parser.add_argument(
-      "--android-arm-binary-path",
-      help="Path to the android-arm network service binary relative to the " +
-           "repo root, e.g. out/android_Release/network_service.mojo")
-
-  args = parser.parse_args()
-  upload_mojoms(args.dry_run)
-  if args.linux_x64_binary_path:
-    upload_binary(args.linux_x64_binary_path, "linux-x64", args.dry_run)
-  if args.android_arm_binary_path:
-    upload_binary(args.android_arm_binary_path, "android-arm", args.dry_run)
-
-  if not args.dry_run:
-    print "Uploaded artifacts for version %s" % (version, )
-  else:
-    print "No artifacts uploaded (dry run)"
-  return 0
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/mojo/services/upload_service.py b/mojo/services/upload_service.py
new file mode 100755
index 0000000..5666dea
--- /dev/null
+++ b/mojo/services/upload_service.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import imp
+import os
+import subprocess
+import sys
+import tempfile
+import time
+import zipfile
+
+# A service's name is defined as the name of its subdirectory in the directory
+# containing this file.
+SERVICES = [ "network", "html_viewer" ]
+
+SERVICE_BINARY_NAMES = {
+    "network" : "network_service.mojo",
+    "html_viewer" : "html_viewer.mojo"
+}
+
+# The network service is downloaded out-of-band rather than dynamically by the
+# shell and thus can be stored zipped in the cloud. Other services are intended
+# to be downloaded dynamically by the shell, which doesn't currently understand
+# zipped binaries.
+SERVICES_WITH_ZIPPED_BINARIES = [ "network" ]
+
+if not sys.platform.startswith("linux"):
+  print "Only support linux for now"
+  sys.exit(1)
+
+root_path = os.path.realpath(
+    os.path.join(
+        os.path.dirname(
+            os.path.realpath(__file__)),
+        os.pardir,
+        os.pardir))
+version = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=root_path)
+version = version.strip()
+
+find_depot_tools_path = os.path.join(root_path, "tools", "find_depot_tools.py")
+find_depot_tools = imp.load_source("find_depot_tools", find_depot_tools_path)
+
+depot_tools_path = find_depot_tools.add_depot_tools_to_path()
+gsutil_exe = os.path.join(depot_tools_path, "third_party", "gsutil", "gsutil")
+
+
+def gsutil_cp(source, dest, dry_run):
+  if dry_run:
+    print "gsutil cp %s %s" % (source, dest)
+  else:
+    subprocess.check_call([gsutil_exe, "cp", source, dest])
+
+
+def upload_mojoms(service, dry_run):
+  script_dir = os.path.dirname(os.path.realpath(__file__))
+  service_dir = os.path.join(script_dir, service)
+  absolute_mojom_directory_path = os.path.join(
+      service_dir,
+      "public",
+      "interfaces")
+
+  if not os.path.exists(absolute_mojom_directory_path):
+    # This service has no interfaces.
+    return
+
+  dest = "gs://mojo/" + service + "/" + version + "/" + "mojoms.zip"
+  with tempfile.NamedTemporaryFile() as mojom_zip_file:
+    with zipfile.ZipFile(mojom_zip_file, 'w') as z:
+      for root, _, files in os.walk(absolute_mojom_directory_path):
+        for filename in files:
+          absolute_file_path = os.path.join(root, filename)
+          relative_file_path = os.path.relpath(absolute_file_path, root)
+          z.write(absolute_file_path, relative_file_path)
+    gsutil_cp(mojom_zip_file.name, dest, dry_run)
+
+
+def upload_binary(service, binary_dir, platform, dry_run):
+  binary_name = SERVICE_BINARY_NAMES[service]
+  absolute_binary_path = os.path.join(root_path, binary_dir, binary_name)
+  binary_dest_prefix = "gs://mojo/" + service + "/" + version + "/" + platform
+
+  if service not in SERVICES_WITH_ZIPPED_BINARIES:
+    binary_dest = binary_dest_prefix + "/" + binary_name
+    gsutil_cp(absolute_binary_path, binary_dest, dry_run)
+    return
+
+  # Zip the binary before uploading it to the cloud.
+  binary_dest = binary_dest_prefix + ".zip"
+  with tempfile.NamedTemporaryFile() as binary_zip_file:
+    with zipfile.ZipFile(binary_zip_file, 'w') as z:
+      with open(absolute_binary_path) as service_binary:
+        zipinfo = zipfile.ZipInfo(binary_name)
+        zipinfo.external_attr = 0o777 << 16
+        zipinfo.compress_type = zipfile.ZIP_DEFLATED
+        zipinfo.date_time = time.gmtime(os.path.getmtime(absolute_binary_path))
+        z.writestr(zipinfo, service_binary.read())
+    gsutil_cp(binary_zip_file.name, binary_dest, dry_run)
+
+
+def main():
+  parser = argparse.ArgumentParser(
+      description="Upload service mojoms and binaries to Google storage")
+  parser.add_argument("-n", "--dry-run", action="store_true", help="Dry run")
+  parser.add_argument(
+      "--linux-x64-binary-dir",
+      help="Path to the dir containing the linux-x64 service binary relative "
+           "to the repo root, e.g. out/Release")
+  parser.add_argument(
+      "--android-arm-binary-dir",
+      help="Path to the dir containing the android-arm service binary relative "
+           "to the repo root, e.g. out/android_Release")
+  parser.add_argument("service",
+                      help="The service to be uploaded (one of %s)" % SERVICES)
+
+  args = parser.parse_args()
+
+  if args.service not in SERVICES:
+    print args.service + " is not one of the recognized services:"
+    print SERVICES
+    return 1
+
+  upload_mojoms(args.service, args.dry_run)
+  if args.linux_x64_binary_dir:
+    upload_binary(args.service, args.linux_x64_binary_dir,
+                  "linux-x64", args.dry_run)
+  if args.android_arm_binary_dir:
+    upload_binary(args.service, args.android_arm_binary_dir,
+                  "android-arm", args.dry_run)
+
+  if not args.dry_run:
+    print "Uploaded artifacts for version %s" % (version, )
+  else:
+    print "No artifacts uploaded (dry run)"
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/native_client_sdk/src/libraries/nacl_io/html5fs/html5_fs.cc b/native_client_sdk/src/libraries/nacl_io/html5fs/html5_fs.cc
index f744750e..bb6b9cc8 100644
--- a/native_client_sdk/src/libraries/nacl_io/html5fs/html5_fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/html5fs/html5_fs.cc
@@ -155,6 +155,9 @@
     int32_t query_result = file_ref_iface_->Query(
         fileref_resource.pp_resource(), &file_info, PP_BlockUntilComplete());
     if (query_result != PP_OK) {
+      if (query_result == PP_ERROR_FILENOTFOUND) {
+        return ENOENT;
+      }
       LOG_ERROR("Error querying file type");
       return EINVAL;
     }
diff --git a/native_client_sdk/src/tests/nacl_io_test/html5_fs_test.cc b/native_client_sdk/src/tests/nacl_io_test/html5_fs_test.cc
index 3cb8d164..abffa13 100644
--- a/native_client_sdk/src/tests/nacl_io_test/html5_fs_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/html5_fs_test.cc
@@ -198,6 +198,7 @@
   ASSERT_TRUE(fs->Exists(kPath));
   ASSERT_EQ(0, fs->Remove(path));
   EXPECT_FALSE(fs->Exists(kPath));
+  ASSERT_EQ(ENOENT, fs->Remove(path));
 }
 
 TEST_F(Html5FsTest, Unlink) {
@@ -213,6 +214,7 @@
   ASSERT_EQ(EISDIR, fs->Unlink(Path("/dir")));
   EXPECT_FALSE(fs->Exists("/file"));
   EXPECT_TRUE(fs->Exists("/dir"));
+  ASSERT_EQ(ENOENT, fs->Unlink(Path("/file")));
 }
 
 TEST_F(Html5FsTest, Rmdir) {
@@ -226,6 +228,7 @@
   EXPECT_EQ(0, fs->Rmdir(Path("/dir")));
   EXPECT_FALSE(fs->Exists("/dir"));
   EXPECT_TRUE(fs->Exists("/file"));
+  EXPECT_EQ(ENOENT, fs->Rmdir(Path("/dir")));
 }
 
 TEST_F(Html5FsTest, Rename) {
diff --git a/net/base/file_stream_context.cc b/net/base/file_stream_context.cc
index 5acaab6..fc2af1b 100644
--- a/net/base/file_stream_context.cc
+++ b/net/base/file_stream_context.cc
@@ -77,6 +77,12 @@
 
   orphaned_ = true;
 
+#if defined(OS_WIN)
+  // Clean up weak pointers here to ensure that they are destroyed on the
+  // same thread where they were created.
+  weak_ptr_factory_.InvalidateWeakPtrs();
+#endif
+
   if (!async_in_progress_) {
     CloseAndDelete();
   } else if (file_.IsValid()) {
diff --git a/net/base/file_stream_context.h b/net/base/file_stream_context.h
index 82a2412..4f01d9d2 100644
--- a/net/base/file_stream_context.h
+++ b/net/base/file_stream_context.h
@@ -28,6 +28,7 @@
 #define NET_BASE_FILE_STREAM_CONTEXT_H_
 
 #include "base/files/file.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/move.h"
 #include "base/task_runner.h"
@@ -159,6 +160,35 @@
   virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
                              DWORD bytes_read,
                              DWORD error) override;
+
+  // The ReadFile call on Windows can execute synchonously at times.
+  // http://support.microsoft.com/kb/156932. This ends up blocking the calling
+  // thread which is undesirable. To avoid this we execute the ReadFile call
+  // on a worker thread.
+  // The |context| parameter is a weak pointer instance passed to the worker
+  // pool.
+  // The |file| parameter is the handle to the file being read.
+  // The |buf| parameter is the buffer where we want the ReadFile to read the
+  // data into.
+  // The |buf_len| parameter contains the number of bytes to be read.
+  // The |overlapped| parameter is a pointer to the OVERLAPPED structure being
+  // used.
+  // The |origin_thread_loop| is a MessageLoopProxy instance used to post tasks
+  // back to the originating thread.
+  static void ReadAsync(
+      const base::WeakPtr<FileStream::Context>& context,
+      HANDLE file,
+      scoped_refptr<net::IOBuffer> buf,
+      int buf_len,
+      OVERLAPPED* overlapped,
+      scoped_refptr<base::MessageLoopProxy> origin_thread_loop);
+
+  // This callback executes on the main calling thread. It informs the caller
+  // about the result of the ReadFile call.
+  // The |os_error| parameter contains the value of the last error returned by
+  // the ReadFile API.
+  void ReadAsyncResult(DWORD os_error);
+
 #elif defined(OS_POSIX)
   // ReadFileImpl() is a simple wrapper around read() that handles EINTR
   // signals and calls RecordAndMapError() to map errno to net error codes.
@@ -179,6 +209,8 @@
   base::MessageLoopForIO::IOContext io_context_;
   CompletionCallback callback_;
   scoped_refptr<IOBuffer> in_flight_buf_;
+  // WeakPtrFactory for posting tasks back to |this|.
+  base::WeakPtrFactory<Context> weak_ptr_factory_;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(Context);
diff --git a/net/base/file_stream_context_win.cc b/net/base/file_stream_context_win.cc
index 85a5968..d225ee3 100644
--- a/net/base/file_stream_context_win.cc
+++ b/net/base/file_stream_context_win.cc
@@ -8,9 +8,12 @@
 
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/task_runner.h"
+#include "base/threading/worker_pool.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 
@@ -37,7 +40,8 @@
     : io_context_(),
       async_in_progress_(false),
       orphaned_(false),
-      task_runner_(task_runner) {
+      task_runner_(task_runner),
+      weak_ptr_factory_(this) {
   io_context_.handler = this;
   memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
 }
@@ -48,7 +52,8 @@
       file_(file.Pass()),
       async_in_progress_(false),
       orphaned_(false),
-      task_runner_(task_runner) {
+      task_runner_(task_runner),
+      weak_ptr_factory_(this) {
   io_context_.handler = this;
   memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
   if (file_.IsValid()) {
@@ -69,20 +74,16 @@
 
   DCHECK(!async_in_progress_);
 
-  DWORD bytes_read;
-  if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len,
-                &bytes_read, &io_context_.overlapped)) {
-    IOResult error = IOResult::FromOSError(GetLastError());
-    if (error.os_error == ERROR_HANDLE_EOF)
-      return 0;  // Report EOF by returning 0 bytes read.
-    if (error.os_error == ERROR_IO_PENDING)
-      IOCompletionIsPending(callback, buf);
-    else
-      LOG(WARNING) << "ReadFile failed: " << error.os_error;
-    return static_cast<int>(error.result);
-  }
-
   IOCompletionIsPending(callback, buf);
+
+  base::WorkerPool::PostTask(
+      FROM_HERE,
+      base::Bind(&FileStream::Context::ReadAsync,
+                 weak_ptr_factory_.GetWeakPtr(), file_.GetPlatformFile(),
+                 make_scoped_refptr(buf), buf_len, &io_context_.overlapped,
+                 base::MessageLoop::current()->message_loop_proxy()),
+      false);
+
   return ERR_IO_PENDING;
 }
 
@@ -165,4 +166,34 @@
   temp_callback.Run(result);
 }
 
+// static
+void FileStream::Context::ReadAsync(
+    const base::WeakPtr<FileStream::Context>& context,
+    HANDLE file,
+    scoped_refptr<net::IOBuffer> buf,
+    int buf_len,
+    OVERLAPPED* overlapped,
+    scoped_refptr<base::MessageLoopProxy> origin_thread_loop) {
+  DWORD bytes_read = 0;
+  if (!ReadFile(file, buf->data(), buf_len, &bytes_read, overlapped)) {
+    origin_thread_loop->PostTask(
+        FROM_HERE, base::Bind(&FileStream::Context::ReadAsyncResult, context,
+                              ::GetLastError()));
+  }
+}
+
+void FileStream::Context::ReadAsyncResult(DWORD os_error) {
+  IOResult error = IOResult::FromOSError(os_error);
+  if (error.os_error == ERROR_HANDLE_EOF) {
+    // Report EOF by returning 0 bytes read.
+    OnIOCompleted(&io_context_, 0, error.os_error);
+  } else if (error.os_error != ERROR_IO_PENDING) {
+    // We don't need to inform the caller about ERROR_PENDING_IO as that was
+    // already done when the ReadFile call was queued to the worker pool.
+    if (error.os_error)
+      LOG(WARNING) << "ReadFile failed: " << error.os_error;
+    OnIOCompleted(&io_context_, 0, error.os_error);
+  }
+}
+
 }  // namespace net
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
index fc9257e..8b47ecc 100644
--- a/net/base/file_stream_unittest.cc
+++ b/net/base/file_stream_unittest.cc
@@ -546,6 +546,25 @@
 
   const CompletionCallback& callback() const { return callback_; }
 
+  void ValidateWrittenData() {
+    TestCompletionCallback callback;
+    int rv = 0;
+    for (;;) {
+      scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
+      rv = stream_->Read(buf.get(), buf->size(), callback.callback());
+      if (rv == ERR_IO_PENDING) {
+        base::MessageLoop::ScopedNestableTaskAllower allow(
+            base::MessageLoop::current());
+        rv = callback.WaitForResult();
+      }
+      EXPECT_LE(0, rv);
+      if (rv <= 0)
+        break;
+      *total_bytes_read_ += rv;
+      data_read_->append(buf->data(), rv);
+    }
+  }
+
  private:
   void OnComplete(int result) {
     DCHECK_LT(0, result);
@@ -577,22 +596,6 @@
             base::MessageLoop::current());
         EXPECT_LE(0, callback64.WaitForResult());
       }
-
-      TestCompletionCallback callback;
-      for (;;) {
-        scoped_refptr<IOBufferWithSize> buf = new IOBufferWithSize(4);
-        rv = stream_->Read(buf.get(), buf->size(), callback.callback());
-        if (rv == ERR_IO_PENDING) {
-          base::MessageLoop::ScopedNestableTaskAllower allow(
-              base::MessageLoop::current());
-          rv = callback.WaitForResult();
-        }
-        EXPECT_LE(0, rv);
-        if (rv <= 0)
-          break;
-        *total_bytes_read_ += rv;
-        data_read_->append(buf->data(), rv);
-      }
     }
 
     result_ = *total_bytes_written_;
@@ -646,6 +649,8 @@
   EXPECT_LT(0, rv);
   EXPECT_EQ(kTestDataSize, total_bytes_written);
 
+  callback.ValidateWrittenData();
+
   stream.reset();
 
   EXPECT_TRUE(base::GetFileSize(temp_file_path(), &file_size));
diff --git a/net/base/filename_util_unittest.cc b/net/base/filename_util_unittest.cc
index 9d91fb7f..4a8c4b5 100644
--- a/net/base/filename_util_unittest.cc
+++ b/net/base/filename_util_unittest.cc
@@ -116,48 +116,56 @@
 };
 
 static const base::FilePath::CharType* kSafePortableRelativePaths[] = {
-  FILE_PATH_LITERAL("a/a"),
+    FILE_PATH_LITERAL("a/a"),
 #if defined(OS_WIN)
-  FILE_PATH_LITERAL("a\\a"),
+    FILE_PATH_LITERAL("a\\a"),
 #endif
 };
 
 TEST(FilenameUtilTest, IsSafePortablePathComponent) {
-  for (size_t i = 0 ; i < arraysize(kSafePortableBasenames); ++i) {
-    EXPECT_TRUE(IsSafePortablePathComponent(base::FilePath(
-        kSafePortableBasenames[i]))) << kSafePortableBasenames[i];
+  for (size_t i = 0; i < arraysize(kSafePortableBasenames); ++i) {
+    EXPECT_TRUE(
+        IsSafePortablePathComponent(base::FilePath(kSafePortableBasenames[i])))
+        << kSafePortableBasenames[i];
   }
-  for (size_t i = 0 ; i < arraysize(kUnsafePortableBasenames); ++i) {
-    EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
-        kUnsafePortableBasenames[i]))) << kUnsafePortableBasenames[i];
+  for (size_t i = 0; i < arraysize(kUnsafePortableBasenames); ++i) {
+    EXPECT_FALSE(IsSafePortablePathComponent(
+        base::FilePath(kUnsafePortableBasenames[i])))
+        << kUnsafePortableBasenames[i];
   }
-  for (size_t i = 0 ; i < arraysize(kSafePortableRelativePaths); ++i) {
-    EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
-        kSafePortableRelativePaths[i]))) << kSafePortableRelativePaths[i];
+  for (size_t i = 0; i < arraysize(kSafePortableRelativePaths); ++i) {
+    EXPECT_FALSE(IsSafePortablePathComponent(
+        base::FilePath(kSafePortableRelativePaths[i])))
+        << kSafePortableRelativePaths[i];
   }
 }
 
 TEST(FilenameUtilTest, IsSafePortableRelativePath) {
   base::FilePath safe_dirname(FILE_PATH_LITERAL("a"));
-  for (size_t i = 0 ; i < arraysize(kSafePortableBasenames); ++i) {
-    EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
-        kSafePortableBasenames[i]))) << kSafePortableBasenames[i];
-    EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname.Append(base::FilePath(
-        kSafePortableBasenames[i])))) << kSafePortableBasenames[i];
+  for (size_t i = 0; i < arraysize(kSafePortableBasenames); ++i) {
+    EXPECT_TRUE(
+        IsSafePortableRelativePath(base::FilePath(kSafePortableBasenames[i])))
+        << kSafePortableBasenames[i];
+    EXPECT_TRUE(IsSafePortableRelativePath(
+        safe_dirname.Append(base::FilePath(kSafePortableBasenames[i]))))
+        << kSafePortableBasenames[i];
   }
-  for (size_t i = 0 ; i < arraysize(kSafePortableRelativePaths); ++i) {
-    EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
-        kSafePortableRelativePaths[i]))) << kSafePortableRelativePaths[i];
-    EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname.Append(base::FilePath(
-        kSafePortableRelativePaths[i])))) << kSafePortableRelativePaths[i];
+  for (size_t i = 0; i < arraysize(kSafePortableRelativePaths); ++i) {
+    EXPECT_TRUE(IsSafePortableRelativePath(
+        base::FilePath(kSafePortableRelativePaths[i])))
+        << kSafePortableRelativePaths[i];
+    EXPECT_TRUE(IsSafePortableRelativePath(
+        safe_dirname.Append(base::FilePath(kSafePortableRelativePaths[i]))))
+        << kSafePortableRelativePaths[i];
   }
-  for (size_t i = 0 ; i < arraysize(kUnsafePortableBasenames); ++i) {
-    EXPECT_FALSE(IsSafePortableRelativePath(base::FilePath(
-        kUnsafePortableBasenames[i]))) << kUnsafePortableBasenames[i];
-    if (!base::FilePath::StringType(kUnsafePortableBasenames[i]).empty()) {
-      EXPECT_FALSE(IsSafePortableRelativePath(safe_dirname.Append(
-          base::FilePath(kUnsafePortableBasenames[i]))))
+  for (size_t i = 0; i < arraysize(kUnsafePortableBasenames); ++i) {
+    EXPECT_FALSE(
+        IsSafePortableRelativePath(base::FilePath(kUnsafePortableBasenames[i])))
         << kUnsafePortableBasenames[i];
+    if (!base::FilePath::StringType(kUnsafePortableBasenames[i]).empty()) {
+      EXPECT_FALSE(IsSafePortableRelativePath(
+          safe_dirname.Append(base::FilePath(kUnsafePortableBasenames[i]))))
+          << kUnsafePortableBasenames[i];
     }
   }
 }
@@ -168,19 +176,18 @@
 #if defined(OS_WIN)
     {L"C:\\foo\\bar.txt", "file:///C:/foo/bar.txt"},
     {L"\\\\some computer\\foo\\bar.txt",
-     "file://some%20computer/foo/bar.txt"}, // UNC
+     "file://some%20computer/foo/bar.txt"},  // UNC
     {L"D:\\Name;with%some symbols*#",
      "file:///D:/Name%3Bwith%25some%20symbols*%23"},
     // issue 14153: To be tested with the OS default codepage other than 1252.
     {L"D:\\latin1\\caf\x00E9\x00DD.txt",
      "file:///D:/latin1/caf%C3%A9%C3%9D.txt"},
-    {L"D:\\otherlatin\\caf\x0119.txt",
-     "file:///D:/otherlatin/caf%C4%99.txt"},
+    {L"D:\\otherlatin\\caf\x0119.txt", "file:///D:/otherlatin/caf%C4%99.txt"},
     {L"D:\\greek\\\x03B1\x03B2\x03B3.txt",
      "file:///D:/greek/%CE%B1%CE%B2%CE%B3.txt"},
     {L"D:\\Chinese\\\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
      "file:///D:/Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD%91"
-         "%E9%A1%B5.doc"},
+     "%E9%A1%B5.doc"},
     {L"D:\\plane1\\\xD835\xDC00\xD835\xDC01.txt",  // Math alphabet "AB"
      "file:///D:/plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
 #elif defined(OS_POSIX)
@@ -195,7 +202,7 @@
     {L"/greek/\x03B1\x03B2\x03B3.txt", "file:///greek/%CE%B1%CE%B2%CE%B3.txt"},
     {L"/Chinese/\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
      "file:///Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD"
-         "%91%E9%A1%B5.doc"},
+     "%91%E9%A1%B5.doc"},
     {L"/plane1/\x1D400\x1D401.txt",  // Math alphabet "AB"
      "file:///plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
 #endif
@@ -205,8 +212,8 @@
   base::FilePath output;
   for (size_t i = 0; i < arraysize(round_trip_cases); i++) {
     // convert to the file URL
-    GURL file_url(FilePathToFileURL(
-                      WStringAsFilePath(round_trip_cases[i].file)));
+    GURL file_url(
+        FilePathToFileURL(WStringAsFilePath(round_trip_cases[i].file)));
     EXPECT_EQ(round_trip_cases[i].url, file_url.spec());
 
     // Back to the filename.
@@ -239,13 +246,13 @@
     {L"/foo/bar.txt", "file:////foo////bar.txt"},
     {L"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
     {L"/c:/foo/bar.txt", "file:c:/foo/bar.txt"},
-    // We get these wrong because GURL turns back slashes into forward
-    // slashes.
-    //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
-    //{L"/c|/foo%5Cbar.txt", "file:c|/foo\\bar.txt"},
-    //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
-    //{L"/foo%5Cbar.txt", "file:////foo\\bar.txt"},
-    //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
+//  We get these wrong because GURL turns back slashes into forward
+//  slashes.
+//  {L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
+//  {L"/c|/foo%5Cbar.txt", "file:c|/foo\\bar.txt"},
+//  {L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
+//  {L"/foo%5Cbar.txt", "file:////foo\\bar.txt"},
+//  {L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
 #endif
   };
   for (size_t i = 0; i < arraysize(url_cases); i++) {
@@ -253,14 +260,13 @@
     EXPECT_EQ(url_cases[i].file, FilePathAsWString(output));
   }
 
-  // Unfortunately, UTF8ToWide discards invalid UTF8 input.
+// Unfortunately, UTF8ToWide discards invalid UTF8 input.
 #ifdef BUG_878908_IS_FIXED
   // Test that no conversion happens if the UTF-8 input is invalid, and that
   // the input is preserved in UTF-8
   const char invalid_utf8[] = "file:///d:/Blah/\xff.doc";
   const wchar_t invalid_wide[] = L"D:\\Blah\\\xff.doc";
-  EXPECT_TRUE(FileURLToFilePath(
-      GURL(std::string(invalid_utf8)), &output));
+  EXPECT_TRUE(FileURLToFilePath(GURL(std::string(invalid_utf8)), &output));
   EXPECT_EQ(std::wstring(invalid_wide), output);
 #endif
 
@@ -288,144 +294,88 @@
     const base::FilePath::CharType* expected_filename;
   } safe_tests[] = {
 #if defined(OS_WIN)
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
-      FILE_PATH_LITERAL("C:\\foo\\bar.htm")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\bar.html"),
-      FILE_PATH_LITERAL("C:\\foo\\bar.html")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\bar"),
-      FILE_PATH_LITERAL("C:\\foo\\bar.htm")
-    },
-    {
-      "image/png",
-      FILE_PATH_LITERAL("C:\\bar.html"),
-      FILE_PATH_LITERAL("C:\\bar.html")
-    },
-    {
-      "image/png",
-      FILE_PATH_LITERAL("C:\\bar"),
-      FILE_PATH_LITERAL("C:\\bar.png")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
-      FILE_PATH_LITERAL("C:\\foo\\bar.exe")
-    },
-    {
-      "image/gif",
-      FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
-      FILE_PATH_LITERAL("C:\\foo\\bar.exe")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\google.com"),
-      FILE_PATH_LITERAL("C:\\foo\\google.com")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\con.htm"),
-      FILE_PATH_LITERAL("C:\\foo\\_con.htm")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\con"),
-      FILE_PATH_LITERAL("C:\\foo\\_con.htm")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\harmless.{not-really-this-may-be-a-guid}"),
-      FILE_PATH_LITERAL("C:\\foo\\harmless.download")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\harmless.local"),
-      FILE_PATH_LITERAL("C:\\foo\\harmless.download")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\harmless.lnk"),
-      FILE_PATH_LITERAL("C:\\foo\\harmless.download")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-"),
-      FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-")
-    },
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
+     FILE_PATH_LITERAL("C:\\foo\\bar.htm")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\bar.html"),
+     FILE_PATH_LITERAL("C:\\foo\\bar.html")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\bar"),
+     FILE_PATH_LITERAL("C:\\foo\\bar.htm")},
+    {"image/png",
+     FILE_PATH_LITERAL("C:\\bar.html"),
+     FILE_PATH_LITERAL("C:\\bar.html")},
+    {"image/png",
+     FILE_PATH_LITERAL("C:\\bar"),
+     FILE_PATH_LITERAL("C:\\bar.png")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
+     FILE_PATH_LITERAL("C:\\foo\\bar.exe")},
+    {"image/gif",
+     FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
+     FILE_PATH_LITERAL("C:\\foo\\bar.exe")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\google.com"),
+     FILE_PATH_LITERAL("C:\\foo\\google.com")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\con.htm"),
+     FILE_PATH_LITERAL("C:\\foo\\_con.htm")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\con"),
+     FILE_PATH_LITERAL("C:\\foo\\_con.htm")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\harmless.{not-really-this-may-be-a-guid}"),
+     FILE_PATH_LITERAL("C:\\foo\\harmless.download")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\harmless.local"),
+     FILE_PATH_LITERAL("C:\\foo\\harmless.download")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\harmless.lnk"),
+     FILE_PATH_LITERAL("C:\\foo\\harmless.download")},
+    {"text/html",
+     FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-"),
+     FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-")},
     // Allow extension synonyms.
-    {
-      "image/jpeg",
-      FILE_PATH_LITERAL("C:\\foo\\bar.jpg"),
-      FILE_PATH_LITERAL("C:\\foo\\bar.jpg")
-    },
-    {
-      "image/jpeg",
-      FILE_PATH_LITERAL("C:\\foo\\bar.jpeg"),
-      FILE_PATH_LITERAL("C:\\foo\\bar.jpeg")
-    },
-#else  // !defined(OS_WIN)
-    {
-      "text/html",
-      FILE_PATH_LITERAL("/foo/bar.htm"),
-      FILE_PATH_LITERAL("/foo/bar.htm")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("/foo/bar.html"),
-      FILE_PATH_LITERAL("/foo/bar.html")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("/foo/bar"),
-      FILE_PATH_LITERAL("/foo/bar.html")
-    },
-    {
-      "image/png",
-      FILE_PATH_LITERAL("/bar.html"),
-      FILE_PATH_LITERAL("/bar.html")
-    },
-    {
-      "image/png",
-      FILE_PATH_LITERAL("/bar"),
-      FILE_PATH_LITERAL("/bar.png")
-    },
-    {
-      "image/gif",
-      FILE_PATH_LITERAL("/foo/bar.exe"),
-      FILE_PATH_LITERAL("/foo/bar.exe")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("/foo/google.com"),
-      FILE_PATH_LITERAL("/foo/google.com")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("/foo/con.htm"),
-      FILE_PATH_LITERAL("/foo/con.htm")
-    },
-    {
-      "text/html",
-      FILE_PATH_LITERAL("/foo/con"),
-      FILE_PATH_LITERAL("/foo/con.html")
-    },
+    {"image/jpeg",
+     FILE_PATH_LITERAL("C:\\foo\\bar.jpg"),
+     FILE_PATH_LITERAL("C:\\foo\\bar.jpg")},
+    {"image/jpeg",
+     FILE_PATH_LITERAL("C:\\foo\\bar.jpeg"),
+     FILE_PATH_LITERAL("C:\\foo\\bar.jpeg")},
+#else   // !defined(OS_WIN)
+    {"text/html",
+     FILE_PATH_LITERAL("/foo/bar.htm"),
+     FILE_PATH_LITERAL("/foo/bar.htm")},
+    {"text/html",
+     FILE_PATH_LITERAL("/foo/bar.html"),
+     FILE_PATH_LITERAL("/foo/bar.html")},
+    {"text/html",
+     FILE_PATH_LITERAL("/foo/bar"),
+     FILE_PATH_LITERAL("/foo/bar.html")},
+    {"image/png",
+     FILE_PATH_LITERAL("/bar.html"),
+     FILE_PATH_LITERAL("/bar.html")},
+    {"image/png", FILE_PATH_LITERAL("/bar"), FILE_PATH_LITERAL("/bar.png")},
+    {"image/gif",
+     FILE_PATH_LITERAL("/foo/bar.exe"),
+     FILE_PATH_LITERAL("/foo/bar.exe")},
+    {"text/html",
+     FILE_PATH_LITERAL("/foo/google.com"),
+     FILE_PATH_LITERAL("/foo/google.com")},
+    {"text/html",
+     FILE_PATH_LITERAL("/foo/con.htm"),
+     FILE_PATH_LITERAL("/foo/con.htm")},
+    {"text/html",
+     FILE_PATH_LITERAL("/foo/con"),
+     FILE_PATH_LITERAL("/foo/con.html")},
     // Allow extension synonyms.
-    {
-      "image/jpeg",
-      FILE_PATH_LITERAL("/bar.jpg"),
-      FILE_PATH_LITERAL("/bar.jpg")
-    },
-    {
-      "image/jpeg",
-      FILE_PATH_LITERAL("/bar.jpeg"),
-      FILE_PATH_LITERAL("/bar.jpeg")
-    },
+    {"image/jpeg",
+     FILE_PATH_LITERAL("/bar.jpg"),
+     FILE_PATH_LITERAL("/bar.jpg")},
+    {"image/jpeg",
+     FILE_PATH_LITERAL("/bar.jpeg"),
+     FILE_PATH_LITERAL("/bar.jpeg")},
 #endif  // !defined(OS_WIN)
   };
 
@@ -442,392 +392,287 @@
   // parameters and that Content-Disposition headers are properly
   // handled including failovers when the header is malformed.
   const GenerateFilenameCase selection_tests[] = {
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=test.html",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=\"test.html\"",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename= \"test.html\"",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename   =   \"test.html\"",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    { // filename is whitespace.  Should failover to URL host
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=  ",
-      "",
-      "",
-      "",
-      L"",
-      L"www.google.com"
-    },
-    { // No filename.
-      __LINE__,
-      "http://www.google.com/path/test.html",
-      "attachment",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    { // Ditto
-      __LINE__,
-      "http://www.google.com/path/test.html",
-      "attachment;",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    { // No C-D
-      __LINE__,
-      "http://www.google.com/",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"www.google.com"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/test.html",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    { // Now that we use src/url's ExtractFileName, this case falls back to
-      // the hostname. If this behavior is not desirable, we'd better change
-      // ExtractFileName (in url_parse.cc).
-      __LINE__,
-      "http://www.google.com/path/",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"www.google.com"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/path",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"path"
-    },
-    {
-      __LINE__,
-      "file:///",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"download"
-    },
-    {
-      __LINE__,
-      "file:///path/testfile",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"testfile"
-    },
-    {
-      __LINE__,
-      "non-standard-scheme:",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"download"
-    },
-    { // C-D should override default
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename =\"test.html\"",
-      "",
-      "",
-      "",
-      L"download",
-      L"test.html"
-    },
-    { // But the URL shouldn't
-      __LINE__,
-      "http://www.google.com/",
-      "",
-      "",
-      "",
-      "",
-      L"download",
-      L"download"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=\"../test.html\"",
-      "",
-      "",
-      "",
-      L"",
-      L"-test.html"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=\"..\\test.html\"",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=\"..\\\\test.html\"",
-      "",
-      "",
-      "",
-      L"",
-      L"-test.html"
-    },
-    { // Filename disappears after leading and trailing periods are removed.
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=\"..\"",
-      "",
-      "",
-      "",
-      L"default",
-      L"default"
-    },
-    { // C-D specified filename disappears.  Failover to final filename.
-      __LINE__,
-      "http://www.google.com/test.html",
-      "attachment; filename=\"..\"",
-      "",
-      "",
-      "",
-      L"default",
-      L"default"
-    },
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename=test.html",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename=\"test.html\"",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename= \"test.html\"",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename   =   \"test.html\"",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {// filename is whitespace.  Should failover to URL host
+     __LINE__,
+     "http://www.google.com/",
+     "attachment; filename=  ",
+     "",
+     "",
+     "",
+     L"",
+     L"www.google.com"},
+    {// No filename.
+     __LINE__,
+     "http://www.google.com/path/test.html",
+     "attachment",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {// Ditto
+     __LINE__,
+     "http://www.google.com/path/test.html",
+     "attachment;",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {// No C-D
+     __LINE__,
+     "http://www.google.com/",
+     "",
+     "",
+     "",
+     "",
+     L"",
+     L"www.google.com"},
+    {__LINE__,
+     "http://www.google.com/test.html",
+     "",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {// Now that we use src/url's ExtractFileName, this case falls back to
+     // the hostname. If this behavior is not desirable, we'd better change
+     // ExtractFileName (in url_parse.cc).
+     __LINE__,
+     "http://www.google.com/path/",
+     "",
+     "",
+     "",
+     "",
+     L"",
+     L"www.google.com"},
+    {__LINE__, "http://www.google.com/path", "", "", "", "", L"", L"path"},
+    {__LINE__, "file:///", "", "", "", "", L"", L"download"},
+    {__LINE__, "file:///path/testfile", "", "", "", "", L"", L"testfile"},
+    {__LINE__, "non-standard-scheme:", "", "", "", "", L"", L"download"},
+    {// C-D should override default
+     __LINE__,
+     "http://www.google.com/",
+     "attachment; filename =\"test.html\"",
+     "",
+     "",
+     "",
+     L"download",
+     L"test.html"},
+    {// But the URL shouldn't
+     __LINE__,
+     "http://www.google.com/",
+     "",
+     "",
+     "",
+     "",
+     L"download",
+     L"download"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename=\"../test.html\"",
+     "",
+     "",
+     "",
+     L"",
+     L"-test.html"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename=\"..\\test.html\"",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename=\"..\\\\test.html\"",
+     "",
+     "",
+     "",
+     L"",
+     L"-test.html"},
+    {// Filename disappears after leading and trailing periods are removed.
+     __LINE__,
+     "http://www.google.com/",
+     "attachment; filename=\"..\"",
+     "",
+     "",
+     "",
+     L"default",
+     L"default"},
+    {// C-D specified filename disappears.  Failover to final filename.
+     __LINE__,
+     "http://www.google.com/test.html",
+     "attachment; filename=\"..\"",
+     "",
+     "",
+     "",
+     L"default",
+     L"default"},
     // Below is a small subset of cases taken from HttpContentDisposition tests.
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=\"%EC%98%88%EC%88%A0%20"
-      "%EC%98%88%EC%88%A0.jpg\"",
-      "",
-      "",
-      "",
-      L"",
-      L"\uc608\uc220 \uc608\uc220.jpg"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
-      "",
-      "",
-      "",
-      "",
-      L"download",
-      L"\uc608\uc220 \uc608\uc220.jpg"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment;",
-      "",
-      "",
-      "",
-      L"\uB2E4\uC6B4\uB85C\uB4DC",
-      L"\uB2E4\uC6B4\uB85C\uB4DC"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/",
-      "attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
-      "D13=2Epng?=\"",
-      "",
-      "",
-      "",
-      L"download",
-      L"\u82b8\u88533.png"
-    },
-    {
-      __LINE__,
-      "http://www.example.com/images?id=3",
-      "attachment; filename=caf\xc3\xa9.png",
-      "iso-8859-1",
-      "",
-      "",
-      L"",
-      L"caf\u00e9.png"
-    },
-    {
-      __LINE__,
-      "http://www.example.com/images?id=3",
-      "attachment; filename=caf\xe5.png",
-      "windows-1253",
-      "",
-      "",
-      L"",
-      L"caf\u03b5.png"
-    },
-    {
-      __LINE__,
-      "http://www.example.com/file?id=3",
-      "attachment; name=\xcf\xc2\xd4\xd8.zip",
-      "GBK",
-      "",
-      "",
-      L"",
-      L"\u4e0b\u8f7d.zip"
-    },
-    { // Invalid C-D header. Extracts filename from url.
-      __LINE__,
-      "http://www.google.com/test.html",
-      "attachment; filename==?iiso88591?Q?caf=EG?=",
-      "",
-      "",
-      "",
-      L"",
-      L"test.html"
-    },
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename=\"%EC%98%88%EC%88%A0%20"
+     "%EC%98%88%EC%88%A0.jpg\"",
+     "",
+     "",
+     "",
+     L"",
+     L"\uc608\uc220 \uc608\uc220.jpg"},
+    {__LINE__,
+     "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
+     "",
+     "",
+     "",
+     "",
+     L"download",
+     L"\uc608\uc220 \uc608\uc220.jpg"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment;",
+     "",
+     "",
+     "",
+     L"\uB2E4\uC6B4\uB85C\uB4DC",
+     L"\uB2E4\uC6B4\uB85C\uB4DC"},
+    {__LINE__,
+     "http://www.google.com/",
+     "attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
+     "D13=2Epng?=\"",
+     "",
+     "",
+     "",
+     L"download",
+     L"\u82b8\u88533.png"},
+    {__LINE__,
+     "http://www.example.com/images?id=3",
+     "attachment; filename=caf\xc3\xa9.png",
+     "iso-8859-1",
+     "",
+     "",
+     L"",
+     L"caf\u00e9.png"},
+    {__LINE__,
+     "http://www.example.com/images?id=3",
+     "attachment; filename=caf\xe5.png",
+     "windows-1253",
+     "",
+     "",
+     L"",
+     L"caf\u03b5.png"},
+    {__LINE__,
+     "http://www.example.com/file?id=3",
+     "attachment; name=\xcf\xc2\xd4\xd8.zip",
+     "GBK",
+     "",
+     "",
+     L"",
+     L"\u4e0b\u8f7d.zip"},
+    {// Invalid C-D header. Extracts filename from url.
+     __LINE__,
+     "http://www.google.com/test.html",
+     "attachment; filename==?iiso88591?Q?caf=EG?=",
+     "",
+     "",
+     "",
+     L"",
+     L"test.html"},
     // about: and data: URLs
-    {
-      __LINE__,
-      "about:chrome",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"download"
-    },
-    {
-      __LINE__,
-      "data:,looks/like/a.path",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"download"
-    },
-    {
-      __LINE__,
-      "data:text/plain;base64,VG8gYmUgb3Igbm90IHRvIGJlLg=",
-      "",
-      "",
-      "",
-      "",
-      L"",
-      L"download"
-    },
-    {
-      __LINE__,
-      "data:,looks/like/a.path",
-      "",
-      "",
-      "",
-      "",
-      L"default_filename_is_given",
-      L"default_filename_is_given"
-    },
-    {
-      __LINE__,
-      "data:,looks/like/a.path",
-      "",
-      "",
-      "",
-      "",
-      L"\u65e5\u672c\u8a9e",  // Japanese Kanji.
-      L"\u65e5\u672c\u8a9e"
-    },
-    { // The filename encoding is specified by the referrer charset.
-      __LINE__,
-      "http://example.com/V%FDvojov%E1%20psychologie.doc",
-      "",
-      "iso-8859-1",
-      "",
-      "",
-      L"",
-      L"V\u00fdvojov\u00e1 psychologie.doc"
-    },
-    { // Suggested filename takes precedence over URL
-      __LINE__,
-      "http://www.google.com/test",
-      "",
-      "",
-      "suggested",
-      "",
-      L"",
-      L"suggested"
-    },
-    { // The content-disposition has higher precedence over the suggested name.
-      __LINE__,
-      "http://www.google.com/test",
-      "attachment; filename=test.html",
-      "",
-      "suggested",
-      "",
-      L"",
-      L"test.html"
-    },
-    {
-      __LINE__,
-      "http://www.google.com/test",
-      "attachment; filename=test",
-      "utf-8",
-      "",
-      "image/png",
-      L"",
-      L"test"
-    },
+    {__LINE__, "about:chrome", "", "", "", "", L"", L"download"},
+    {__LINE__, "data:,looks/like/a.path", "", "", "", "", L"", L"download"},
+    {__LINE__,
+     "data:text/plain;base64,VG8gYmUgb3Igbm90IHRvIGJlLg=",
+     "",
+     "",
+     "",
+     "",
+     L"",
+     L"download"},
+    {__LINE__,
+     "data:,looks/like/a.path",
+     "",
+     "",
+     "",
+     "",
+     L"default_filename_is_given",
+     L"default_filename_is_given"},
+    {__LINE__,
+     "data:,looks/like/a.path",
+     "",
+     "",
+     "",
+     "",
+     L"\u65e5\u672c\u8a9e",  // Japanese Kanji.
+     L"\u65e5\u672c\u8a9e"},
+    {// The filename encoding is specified by the referrer charset.
+     __LINE__,
+     "http://example.com/V%FDvojov%E1%20psychologie.doc",
+     "",
+     "iso-8859-1",
+     "",
+     "",
+     L"",
+     L"V\u00fdvojov\u00e1 psychologie.doc"},
+    {// Suggested filename takes precedence over URL
+     __LINE__,
+     "http://www.google.com/test",
+     "",
+     "",
+     "suggested",
+     "",
+     L"",
+     L"suggested"},
+    {// The content-disposition has higher precedence over the suggested name.
+     __LINE__,
+     "http://www.google.com/test",
+     "attachment; filename=test.html",
+     "",
+     "suggested",
+     "",
+     L"",
+     L"test.html"},
+    {__LINE__,
+     "http://www.google.com/test",
+     "attachment; filename=test",
+     "utf-8",
+     "",
+     "image/png",
+     L"",
+     L"test"},
 #if 0
     { // The filename encoding doesn't match the referrer charset, the system
       // charset, or UTF-8.
@@ -843,108 +688,95 @@
     },
 #endif
     // Raw 8bit characters in C-D
-    {
-      __LINE__,
-      "http://www.example.com/images?id=3",
-      "attachment; filename=caf\xc3\xa9.png",
-      "iso-8859-1",
-      "",
-      "image/png",
-      L"",
-      L"caf\u00e9.png"
-    },
-    {
-      __LINE__,
-      "http://www.example.com/images?id=3",
-      "attachment; filename=caf\xe5.png",
-      "windows-1253",
-      "",
-      "image/png",
-      L"",
-      L"caf\u03b5.png"
-    },
-    { // No 'filename' keyword in the disposition, use the URL
-      __LINE__,
-      "http://www.evil.com/my_download.txt",
-      "a_file_name.txt",
-      "",
-      "",
-      "text/plain",
-      L"download",
-      L"my_download.txt"
-    },
-    { // Spaces in the disposition file name
-      __LINE__,
-      "http://www.frontpagehacker.com/a_download.exe",
-      "filename=My Downloaded File.exe",
-      "",
-      "",
-      "application/octet-stream",
-      L"download",
-      L"My Downloaded File.exe"
-    },
-    { // % encoded
-      __LINE__,
-      "http://www.examples.com/",
-      "attachment; "
-      "filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
-      "",
-      "",
-      "image/jpeg",
-      L"download",
-      L"\uc608\uc220 \uc608\uc220.jpg"
-    },
-    { // name= parameter
-      __LINE__,
-      "http://www.examples.com/q.cgi?id=abc",
-      "attachment; name=abc de.pdf",
-      "",
-      "",
-      "application/octet-stream",
-      L"download",
-      L"abc de.pdf"
-    },
-    {
-      __LINE__,
-      "http://www.example.com/path",
-      "filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
-      "",
-      "",
-      "image/png",
-      L"download",
-      L"\x82b8\x8853" L"3.png"
-    },
-    { // The following two have invalid CD headers and filenames come from the
-      // URL.
-      __LINE__,
-      "http://www.example.com/test%20123",
-      "attachment; filename==?iiso88591?Q?caf=EG?=",
-      "",
-      "",
-      "image/jpeg",
-      L"download",
-      L"test 123" JPEG_EXT
-    },
-    {
-      __LINE__,
-      "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
-      "malformed_disposition",
-      "",
-      "",
-      "image/jpeg",
-      L"download",
-      L"\uc608\uc220 \uc608\uc220.jpg"
-    },
-    { // Invalid C-D. No filename from URL. Falls back to 'download'.
-      __LINE__,
-      "http://www.google.com/path1/path2/",
-      "attachment; filename==?iso88591?Q?caf=E3?",
-      "",
-      "",
-      "image/jpeg",
-      L"download",
-      L"download" JPEG_EXT
-    },
+    {__LINE__,
+     "http://www.example.com/images?id=3",
+     "attachment; filename=caf\xc3\xa9.png",
+     "iso-8859-1",
+     "",
+     "image/png",
+     L"",
+     L"caf\u00e9.png"},
+    {__LINE__,
+     "http://www.example.com/images?id=3",
+     "attachment; filename=caf\xe5.png",
+     "windows-1253",
+     "",
+     "image/png",
+     L"",
+     L"caf\u03b5.png"},
+    {// No 'filename' keyword in the disposition, use the URL
+     __LINE__,
+     "http://www.evil.com/my_download.txt",
+     "a_file_name.txt",
+     "",
+     "",
+     "text/plain",
+     L"download",
+     L"my_download.txt"},
+    {// Spaces in the disposition file name
+     __LINE__,
+     "http://www.frontpagehacker.com/a_download.exe",
+     "filename=My Downloaded File.exe",
+     "",
+     "",
+     "application/octet-stream",
+     L"download",
+     L"My Downloaded File.exe"},
+    {// % encoded
+     __LINE__,
+     "http://www.examples.com/",
+     "attachment; "
+     "filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
+     "",
+     "",
+     "image/jpeg",
+     L"download",
+     L"\uc608\uc220 \uc608\uc220.jpg"},
+    {// name= parameter
+     __LINE__,
+     "http://www.examples.com/q.cgi?id=abc",
+     "attachment; name=abc de.pdf",
+     "",
+     "",
+     "application/octet-stream",
+     L"download",
+     L"abc de.pdf"},
+    {__LINE__,
+     "http://www.example.com/path",
+     "filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
+     "",
+     "",
+     "image/png",
+     L"download",
+     L"\x82b8\x8853"
+     L"3.png"},
+    {// The following two have invalid CD headers and filenames come from the
+     // URL.
+     __LINE__,
+     "http://www.example.com/test%20123",
+     "attachment; filename==?iiso88591?Q?caf=EG?=",
+     "",
+     "",
+     "image/jpeg",
+     L"download",
+     L"test 123" JPEG_EXT},
+    {__LINE__,
+     "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
+     "malformed_disposition",
+     "",
+     "",
+     "image/jpeg",
+     L"download",
+     L"\uc608\uc220 \uc608\uc220.jpg"},
+    {// Invalid C-D. No filename from URL. Falls back to 'download'.
+     __LINE__,
+     "http://www.google.com/path1/path2/",
+     "attachment; filename==?iso88591?Q?caf=E3?",
+     "",
+     "",
+     "image/jpeg",
+     L"download",
+     L"download" JPEG_EXT},
   };
 
   // Tests filename generation.  Once the correct filename is
@@ -1067,7 +899,7 @@
      "text/plain",
      L"download",
      L"my-cat.jpg"},
-    // Windows specific tests
+// Windows specific tests
 #if defined(OS_WIN)
     {__LINE__,
      "http://www.goodguy.com/evil.exe",
diff --git a/net/disk_cache/blockfile/block_files.cc b/net/disk_cache/blockfile/block_files.cc
index 9aa8f0f1..f46a937 100644
--- a/net/disk_cache/blockfile/block_files.cc
+++ b/net/disk_cache/blockfile/block_files.cc
@@ -656,11 +656,11 @@
   if (file_size < file_header.Size())
     return false;  // file_size > 2GB is also an error.
 
-  const int kMinBlockSize = 36;
-  const int kMaxBlockSize = 4096;
+  const int kMinHeaderBlockSize = 36;
+  const int kMaxHeaderBlockSize = 4096;
   BlockFileHeader* header = file_header.Header();
-  if (header->entry_size < kMinBlockSize ||
-      header->entry_size > kMaxBlockSize || header->num_entries < 0)
+  if (header->entry_size < kMinHeaderBlockSize ||
+      header->entry_size > kMaxHeaderBlockSize || header->num_entries < 0)
     return false;
 
   // Make sure that we survive crashes.
diff --git a/net/dns/dns_hosts.cc b/net/dns/dns_hosts.cc
index b4d213b..697ea14 100644
--- a/net/dns/dns_hosts.cc
+++ b/net/dns/dns_hosts.cc
@@ -131,7 +131,6 @@
                              DnsHosts* dns_hosts,
                              ParseHostsCommaMode comma_mode) {
   CHECK(dns_hosts);
-  DnsHosts& hosts = *dns_hosts;
 
   StringPiece ip_text;
   IPAddressNumber ip;
@@ -156,9 +155,9 @@
     } else {
       DnsHostsKey key(parser.token().as_string(), family);
       base::StringToLowerASCII(&key.first);
-      IPAddressNumber& mapped_ip = hosts[key];
-      if (mapped_ip.empty())
-        mapped_ip = ip;
+      IPAddressNumber* mapped_ip = &(*dns_hosts)[key];
+      if (mapped_ip->empty())
+        *mapped_ip = ip;
       // else ignore this entry (first hit counts)
     }
   }
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 1c70393..c3eab76 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -8508,8 +8508,9 @@
   HostPortPair http_host_port_pair("www.google.com", 80);
   HttpServerProperties& http_server_properties =
       *session->http_server_properties();
-  EXPECT_FALSE(
-      http_server_properties.HasAlternateProtocol(http_host_port_pair));
+  AlternateProtocolInfo alternate =
+      http_server_properties.GetAlternateProtocol(http_host_port_pair);
+  EXPECT_EQ(alternate.protocol, UNINITIALIZED_ALTERNATE_PROTOCOL);
 
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -8524,12 +8525,10 @@
   ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
   EXPECT_EQ("hello world", response_data);
 
-  ASSERT_TRUE(http_server_properties.HasAlternateProtocol(http_host_port_pair));
-  const AlternateProtocolInfo alternate =
-      http_server_properties.GetAlternateProtocol(http_host_port_pair);
-  AlternateProtocolInfo expected_alternate(
-      443, AlternateProtocolFromNextProto(GetParam()), 1);
-  EXPECT_TRUE(expected_alternate.Equals(alternate));
+  alternate = http_server_properties.GetAlternateProtocol(http_host_port_pair);
+  EXPECT_EQ(443, alternate.port);
+  EXPECT_EQ(AlternateProtocolFromNextProto(GetParam()), alternate.protocol);
+  EXPECT_EQ(1.0, alternate.probability);
 }
 
 TEST_P(HttpNetworkTransactionTest,
@@ -8583,11 +8582,10 @@
   ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data));
   EXPECT_EQ("hello world", response_data);
 
-  ASSERT_TRUE(http_server_properties->HasAlternateProtocol(
-      HostPortPair::FromURL(request.url)));
   const AlternateProtocolInfo alternate =
       http_server_properties->GetAlternateProtocol(
           HostPortPair::FromURL(request.url));
+  EXPECT_NE(UNINITIALIZED_ALTERNATE_PROTOCOL, alternate.protocol);
   EXPECT_TRUE(alternate.is_broken);
 }
 
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h
index 840a359..a73b4eb1 100644
--- a/net/http/http_server_properties.h
+++ b/net/http/http_server_properties.h
@@ -190,11 +190,9 @@
   virtual void MaybeForceHTTP11(const HostPortPair& server,
                                 SSLConfig* ssl_config) = 0;
 
-  // Returns true if |server| has an Alternate-Protocol header.
-  virtual bool HasAlternateProtocol(const HostPortPair& server) = 0;
-
-  // Returns the Alternate-Protocol and port for |server|.
-  // HasAlternateProtocol(server) must be true.
+  // Returns the AlternateProtocol for |server| if it has probability equal to
+  // or exceeding threshold, or else the forced AlternateProtocol if there is
+  // one, or else one with UNINITIALIZED_ALTERNATE_PROTOCOL.
   virtual AlternateProtocolInfo GetAlternateProtocol(
       const HostPortPair& server) = 0;
 
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc
index a53e73f..0b6b9743 100644
--- a/net/http/http_server_properties_impl.cc
+++ b/net/http/http_server_properties_impl.cc
@@ -179,10 +179,7 @@
   if (spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second)
     return true;
 
-  if (!HasAlternateProtocol(host_port_pair))
-    return false;
-
-  AlternateProtocolInfo info = GetAlternateProtocol(host_port_pair);
+  const AlternateProtocolInfo info = GetAlternateProtocol(host_port_pair);
   return info.protocol == QUIC;
 }
 
@@ -228,16 +225,6 @@
   }
 }
 
-bool HttpServerPropertiesImpl::HasAlternateProtocol(
-    const HostPortPair& server) {
-  if (g_forced_alternate_protocol)
-    return true;
-  AlternateProtocolMap::const_iterator it =
-      GetAlternateProtocolIterator(server);
-  return it != alternate_protocol_map_.end() &&
-         it->second.probability >= alternate_protocol_probability_threshold_;
-}
-
 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
     const std::string& host) {
   // If this host ends with a canonical suffix, then return the canonical
@@ -251,19 +238,19 @@
   return std::string();
 }
 
-AlternateProtocolInfo
-HttpServerPropertiesImpl::GetAlternateProtocol(
+AlternateProtocolInfo HttpServerPropertiesImpl::GetAlternateProtocol(
     const HostPortPair& server) {
-  DCHECK(HasAlternateProtocol(server));
-
   AlternateProtocolMap::const_iterator it =
       GetAlternateProtocolIterator(server);
-  if (it != alternate_protocol_map_.end())
+  if (it != alternate_protocol_map_.end() &&
+      it->second.probability >= alternate_protocol_probability_threshold_)
     return it->second;
 
-  // We must be forcing an alternate.
-  DCHECK(g_forced_alternate_protocol);
-  return *g_forced_alternate_protocol;
+  if (g_forced_alternate_protocol)
+    return *g_forced_alternate_protocol;
+
+  AlternateProtocolInfo uninitialized_alternate_protocol;
+  return uninitialized_alternate_protocol;
 }
 
 void HttpServerPropertiesImpl::SetAlternateProtocol(
@@ -322,15 +309,16 @@
 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
     const HostPortPair& server) {
   AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
+  const AlternateProtocolInfo alternate = GetAlternateProtocol(server);
   if (it == alternate_protocol_map_.end()) {
-    if (!HasAlternateProtocol(server)) {
+    if (alternate.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) {
       LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
       return;
     }
     // This server's alternate protocol information is coming from a canonical
     // server. Add an entry in the map for this server explicitly so that
     // it can be marked as broken.
-    it = alternate_protocol_map_.Put(server, GetAlternateProtocol(server));
+    it = alternate_protocol_map_.Put(server, alternate);
   }
   it->second.is_broken = true;
   int count = ++broken_alternate_protocol_map_[server];
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h
index 8d251a2..9c2a73c 100644
--- a/net/http/http_server_properties_impl.h
+++ b/net/http/http_server_properties_impl.h
@@ -79,7 +79,6 @@
   void SetHTTP11Required(const HostPortPair& server) override;
   void MaybeForceHTTP11(const HostPortPair& server,
                         SSLConfig* ssl_config) override;
-  bool HasAlternateProtocol(const HostPortPair& server) override;
   AlternateProtocolInfo GetAlternateProtocol(
       const HostPortPair& server) override;
   void SetAlternateProtocol(const HostPortPair& server,
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc
index be5e6b9..e4d70470 100644
--- a/net/http/http_server_properties_impl_unittest.cc
+++ b/net/http/http_server_properties_impl_unittest.cc
@@ -27,6 +27,11 @@
 
 class HttpServerPropertiesImplTest : public testing::Test {
  protected:
+  bool HasAlternateProtocol(const HostPortPair& server) {
+    const AlternateProtocolInfo alternate = impl_.GetAlternateProtocol(server);
+    return alternate.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL;
+  }
+
   HttpServerPropertiesImpl impl_;
 };
 
@@ -219,23 +224,23 @@
 
 TEST_F(AlternateProtocolServerPropertiesTest, Basic) {
   HostPortPair test_host_port_pair("foo", 80);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
   impl_.SetAlternateProtocol(test_host_port_pair, 443, NPN_SPDY_3, 1.0);
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair));
   const AlternateProtocolInfo alternate =
       impl_.GetAlternateProtocol(test_host_port_pair);
   EXPECT_EQ(443, alternate.port);
   EXPECT_EQ(NPN_SPDY_3, alternate.protocol);
 
   impl_.Clear();
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, DefaultProbabilityExcluded) {
   HostPortPair test_host_port_pair("foo", 80);
   impl_.SetAlternateProtocol(test_host_port_pair, 443, NPN_SPDY_3, .99);
 
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, Probability) {
@@ -244,7 +249,7 @@
   HostPortPair test_host_port_pair("foo", 80);
   impl_.SetAlternateProtocol(test_host_port_pair, 443, NPN_SPDY_3, .5);
 
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair));
   const AlternateProtocolInfo alternate =
       impl_.GetAlternateProtocol(test_host_port_pair);
   EXPECT_EQ(443, alternate.port);
@@ -258,7 +263,7 @@
   HostPortPair test_host_port_pair("foo", 80);
 
   impl_.SetAlternateProtocol(test_host_port_pair, 443, NPN_SPDY_3, .5);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, Initialize) {
@@ -284,8 +289,8 @@
   EXPECT_EQ(1234, it->second.port);
   EXPECT_EQ(NPN_SPDY_3, it->second.protocol);
 
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair1));
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair2));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair1));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair2));
   alternate = impl_.GetAlternateProtocol(test_host_port_pair1);
   EXPECT_TRUE(alternate.is_broken);
   alternate = impl_.GetAlternateProtocol(test_host_port_pair2);
@@ -293,26 +298,6 @@
   EXPECT_EQ(NPN_SPDY_3, alternate.protocol);
 }
 
-TEST_F(AlternateProtocolServerPropertiesTest, MRUOfHasAlternateProtocol) {
-  HostPortPair test_host_port_pair1("foo1", 80);
-  impl_.SetAlternateProtocol(test_host_port_pair1, 443, NPN_SPDY_3, 1.0);
-  HostPortPair test_host_port_pair2("foo2", 80);
-  impl_.SetAlternateProtocol(test_host_port_pair2, 1234, NPN_SPDY_3, 1.0);
-
-  const AlternateProtocolMap& map = impl_.alternate_protocol_map();
-  AlternateProtocolMap::const_iterator it = map.begin();
-  EXPECT_TRUE(it->first.Equals(test_host_port_pair2));
-  EXPECT_EQ(1234, it->second.port);
-  EXPECT_EQ(NPN_SPDY_3, it->second.protocol);
-
-  // HasAlternateProtocol should reorder the AlternateProtocol map.
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair1));
-  it = map.begin();
-  EXPECT_TRUE(it->first.Equals(test_host_port_pair1));
-  EXPECT_EQ(443, it->second.port);
-  EXPECT_EQ(NPN_SPDY_3, it->second.protocol);
-}
-
 TEST_F(AlternateProtocolServerPropertiesTest, MRUOfGetAlternateProtocol) {
   HostPortPair test_host_port_pair1("foo1", 80);
   impl_.SetAlternateProtocol(test_host_port_pair1, 443, NPN_SPDY_3, 1.0);
@@ -340,7 +325,7 @@
   HostPortPair test_host_port_pair("foo", 80);
   impl_.SetAlternateProtocol(test_host_port_pair, 443, NPN_SPDY_3, 1.0);
   impl_.SetBrokenAlternateProtocol(test_host_port_pair);
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair));
   AlternateProtocolInfo alternate =
       impl_.GetAlternateProtocol(test_host_port_pair);
   EXPECT_TRUE(alternate.is_broken);
@@ -354,12 +339,12 @@
   HostPortPair test_host_port_pair("foo", 80);
   impl_.SetAlternateProtocol(test_host_port_pair, 443, NPN_SPDY_3, 1.0);
   impl_.SetBrokenAlternateProtocol(test_host_port_pair);
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair));
   AlternateProtocolInfo alternate =
       impl_.GetAlternateProtocol(test_host_port_pair);
   EXPECT_TRUE(alternate.is_broken);
   impl_.ClearAlternateProtocol(test_host_port_pair);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, Forced) {
@@ -370,7 +355,7 @@
 
   // Verify the forced protocol.
   HostPortPair test_host_port_pair("foo", 80);
-  EXPECT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_TRUE(HasAlternateProtocol(test_host_port_pair));
   AlternateProtocolInfo alternate =
       impl_.GetAlternateProtocol(test_host_port_pair);
   EXPECT_EQ(default_protocol.port, alternate.port);
@@ -378,7 +363,7 @@
 
   // Verify the real protocol overrides the forced protocol.
   impl_.SetAlternateProtocol(test_host_port_pair, 443, NPN_SPDY_3, 1.0);
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair));
   alternate = impl_.GetAlternateProtocol(test_host_port_pair);
   EXPECT_EQ(443, alternate.port);
   EXPECT_EQ(NPN_SPDY_3, alternate.protocol);
@@ -389,22 +374,22 @@
 
   // Verify the forced protocol is off.
   HostPortPair test_host_port_pair2("bar", 80);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair2));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair2));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, Canonical) {
   HostPortPair test_host_port_pair("foo.c.youtube.com", 80);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 
   HostPortPair canonical_port_pair("bar.c.youtube.com", 80);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(canonical_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(canonical_port_pair));
 
   AlternateProtocolInfo canonical_protocol(1234, QUIC, 1);
 
   impl_.SetAlternateProtocol(canonical_port_pair, canonical_protocol.port,
                              canonical_protocol.protocol, 1.0);
   // Verify the forced protocol.
-  ASSERT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  ASSERT_TRUE(HasAlternateProtocol(test_host_port_pair));
   AlternateProtocolInfo alternate =
       impl_.GetAlternateProtocol(test_host_port_pair);
   EXPECT_EQ(canonical_protocol.port, alternate.port);
@@ -427,8 +412,8 @@
   impl_.SetAlternateProtocol(canonical_port_pair, canonical_protocol.port,
                              canonical_protocol.protocol,
                              canonical_protocol.probability);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(canonical_port_pair));
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(canonical_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, CanonicalAboveThreshold) {
@@ -441,8 +426,8 @@
   impl_.SetAlternateProtocol(canonical_port_pair, canonical_protocol.port,
                              canonical_protocol.protocol,
                              canonical_protocol.probability);
-  EXPECT_TRUE(impl_.HasAlternateProtocol(canonical_port_pair));
-  EXPECT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_TRUE(HasAlternateProtocol(canonical_port_pair));
+  EXPECT_TRUE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, ClearCanonical) {
@@ -456,7 +441,7 @@
                              canonical_protocol.probability);
 
   impl_.ClearAlternateProtocol(canonical_port_pair);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, CanonicalBroken) {
@@ -470,7 +455,7 @@
                              canonical_protocol.probability);
 
   impl_.SetBrokenAlternateProtocol(canonical_port_pair);
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 TEST_F(AlternateProtocolServerPropertiesTest, CanonicalBroken2) {
@@ -500,7 +485,7 @@
                              canonical_protocol.probability);
 
   impl_.Clear();
-  EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
+  EXPECT_FALSE(HasAlternateProtocol(test_host_port_pair));
 }
 
 typedef HttpServerPropertiesImplTest SpdySettingsServerPropertiesTest;
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc
index c02518d5..c6783d3 100644
--- a/net/http/http_server_properties_manager.cc
+++ b/net/http/http_server_properties_manager.cc
@@ -50,6 +50,20 @@
 // Persist 200 ServerNetworkStats.
 const int kMaxServerNetworkStatsHostsToPersist = 200;
 
+const char kVersionKey[] = "version";
+const char kServersKey[] = "servers";
+const char kSupportsSpdyKey[] = "supports_spdy";
+const char kSettingsKey[] = "settings";
+const char kSupportsQuicKey[] = "supports_quic";
+const char kUsedQuicKey[] = "used_quic";
+const char kAddressKey[] = "address";
+const char kAlternateProtocolKey[] = "alternate_protocol";
+const char kPortKey[] = "port";
+const char kProtocolKey[] = "protocol_str";
+const char kProbabilityKey[] = "probability";
+const char kNetworkStatsKey[] = "network_stats";
+const char kSrttKey[] = "srtt";
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -113,7 +127,7 @@
     version_number = kVersionNumber;
   DCHECK_LE(version_number, kVersionNumber);
   if (version_number <= kVersionNumber)
-    http_server_properties_dict->SetInteger("version", version_number);
+    http_server_properties_dict->SetInteger(kVersionKey, version_number);
 }
 
 // This is required for conformance with the HttpServerProperties interface.
@@ -166,12 +180,6 @@
   http_server_properties_impl_->MaybeForceHTTP11(server, ssl_config);
 }
 
-bool HttpServerPropertiesManager::HasAlternateProtocol(
-    const HostPortPair& server) {
-  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
-  return http_server_properties_impl_->HasAlternateProtocol(server);
-}
-
 AlternateProtocolInfo HttpServerPropertiesManager::GetAlternateProtocol(
     const HostPortPair& server) {
   DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
@@ -343,7 +351,7 @@
       *pref_service_->GetDictionary(path_);
 
   int version = kMissingVersion;
-  if (!http_server_properties_dict.GetIntegerWithoutPathExpansion("version",
+  if (!http_server_properties_dict.GetIntegerWithoutPathExpansion(kVersionKey,
                                                                   &version)) {
     DVLOG(1) << "Missing version. Clearing all properties.";
     return;
@@ -353,7 +361,7 @@
   // http_server_properties_dict["servers"][server].
   const base::DictionaryValue* servers_dict = NULL;
   if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
-          "servers", &servers_dict)) {
+          kServersKey, &servers_dict)) {
     DVLOG(1) << "Malformed http_server_properties for servers.";
     return;
   }
@@ -388,123 +396,19 @@
 
     // Get if server supports Spdy.
     bool supports_spdy = false;
-    if ((server_pref_dict->GetBoolean("supports_spdy", &supports_spdy)) &&
+    if ((server_pref_dict->GetBoolean(kSupportsSpdyKey, &supports_spdy)) &&
         supports_spdy) {
       spdy_servers->push_back(server_str);
     }
 
-    // Get SpdySettings.
-    DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
-    const base::DictionaryValue* spdy_settings_dict = NULL;
-    if (server_pref_dict->GetDictionaryWithoutPathExpansion(
-            "settings", &spdy_settings_dict)) {
-      SettingsMap settings_map;
-      for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
-           !dict_it.IsAtEnd();
-           dict_it.Advance()) {
-        const std::string& id_str = dict_it.key();
-        int id = 0;
-        if (!base::StringToInt(id_str, &id)) {
-          DVLOG(1) << "Malformed id in SpdySettings for server: " << server_str;
-          NOTREACHED();
-          continue;
-        }
-        int value = 0;
-        if (!dict_it.value().GetAsInteger(&value)) {
-          DVLOG(1) << "Malformed value in SpdySettings for server: "
-                   << server_str;
-          NOTREACHED();
-          continue;
-        }
-        SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
-        settings_map[static_cast<SpdySettingsIds>(id)] = flags_and_value;
-      }
-      spdy_settings_map->Put(server, settings_map);
-    }
-
-    // Get alternate_protocol server.
-    DCHECK(alternate_protocol_map->Peek(server) ==
-           alternate_protocol_map->end());
-    const base::DictionaryValue* port_alternate_protocol_dict = NULL;
-    if (server_pref_dict->GetDictionaryWithoutPathExpansion(
-            "alternate_protocol", &port_alternate_protocol_dict)) {
-      int port = 0;
-      if (!port_alternate_protocol_dict->GetIntegerWithoutPathExpansion(
-              "port", &port) ||
-          !IsPortValid(port)) {
-        DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
-        detected_corrupted_prefs = true;
-        continue;
-      }
-      std::string protocol_str;
-      if (!port_alternate_protocol_dict->GetStringWithoutPathExpansion(
-              "protocol_str", &protocol_str)) {
-        DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
-        detected_corrupted_prefs = true;
-        continue;
-      }
-      AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
-      if (!IsAlternateProtocolValid(protocol)) {
-        DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
-        detected_corrupted_prefs = true;
-        continue;
-      }
-
-      double probability = 1;
-      if (port_alternate_protocol_dict->HasKey("probability") &&
-          !port_alternate_protocol_dict->GetDoubleWithoutPathExpansion(
-              "probability", &probability)) {
-        DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
-        detected_corrupted_prefs = true;
-        continue;
-      }
-
-      AlternateProtocolInfo port_alternate_protocol(static_cast<uint16>(port),
-                                                    protocol, probability);
-      alternate_protocol_map->Put(server, port_alternate_protocol);
-    }
-
-    // Get SupportsQuic.
-    DCHECK(supports_quic_map->find(server) == supports_quic_map->end());
-    const base::DictionaryValue* supports_quic_dict = NULL;
-    if (server_pref_dict->GetDictionaryWithoutPathExpansion(
-            "supports_quic", &supports_quic_dict)) {
-      bool used_quic = 0;
-      if (!supports_quic_dict->GetBooleanWithoutPathExpansion(
-              "used_quic", &used_quic)) {
-        DVLOG(1) << "Malformed SupportsQuic server: " << server_str;
-        detected_corrupted_prefs = true;
-        continue;
-      }
-      std::string address;
-      if (!supports_quic_dict->GetStringWithoutPathExpansion(
-              "address", &address)) {
-        DVLOG(1) << "Malformed SupportsQuic server: " << server_str;
-        detected_corrupted_prefs = true;
-        continue;
-      }
-      SupportsQuic supports_quic(used_quic, address);
-      supports_quic_map->insert(std::make_pair(server, supports_quic));
-    }
-
-    // Get ServerNetworkStats.
-    DCHECK(server_network_stats_map->Peek(server) ==
-           server_network_stats_map->end());
-    const base::DictionaryValue* server_network_stats_dict = NULL;
-    if (server_pref_dict->GetDictionaryWithoutPathExpansion(
-            "network_stats", &server_network_stats_dict)) {
-      int srtt;
-      if (!server_network_stats_dict->GetIntegerWithoutPathExpansion("srtt",
-                                                                     &srtt)) {
-        DVLOG(1) << "Malformed ServerNetworkStats for server: " << server_str;
-        detected_corrupted_prefs = true;
-        continue;
-      }
-      ServerNetworkStats server_network_stats;
-      server_network_stats.srtt = base::TimeDelta::FromInternalValue(srtt);
-      // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
-      // bandwidth_estimate.
-      server_network_stats_map->Put(server, server_network_stats);
+    AddToSpdySettingsMap(server, *server_pref_dict, spdy_settings_map.get());
+    if (!AddToAlternateProtocolMap(server, *server_pref_dict,
+                                   alternate_protocol_map.get()) ||
+        !AddToSupportsQuicMap(server, *server_pref_dict,
+                              supports_quic_map.get()) ||
+        !AddToNetworkStatsMap(server, *server_pref_dict,
+                              server_network_stats_map.get())) {
+      detected_corrupted_prefs = true;
     }
   }
 
@@ -520,6 +424,136 @@
           detected_corrupted_prefs));
 }
 
+void HttpServerPropertiesManager::AddToSpdySettingsMap(
+    const HostPortPair& server,
+    const base::DictionaryValue& server_pref_dict,
+    SpdySettingsMap* spdy_settings_map) {
+  // Get SpdySettings.
+  DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
+  const base::DictionaryValue* spdy_settings_dict = NULL;
+  if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
+          kSettingsKey, &spdy_settings_dict)) {
+    return;
+  }
+  SettingsMap settings_map;
+  for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
+       !dict_it.IsAtEnd(); dict_it.Advance()) {
+    const std::string& id_str = dict_it.key();
+    int id = 0;
+    if (!base::StringToInt(id_str, &id)) {
+      DVLOG(1) << "Malformed id in SpdySettings for server: "
+               << server.ToString();
+      NOTREACHED();
+      continue;
+    }
+    int value = 0;
+    if (!dict_it.value().GetAsInteger(&value)) {
+      DVLOG(1) << "Malformed value in SpdySettings for server: "
+               << server.ToString();
+      NOTREACHED();
+      continue;
+    }
+    SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
+    settings_map[static_cast<SpdySettingsIds>(id)] = flags_and_value;
+  }
+  spdy_settings_map->Put(server, settings_map);
+}
+
+bool HttpServerPropertiesManager::AddToAlternateProtocolMap(
+    const HostPortPair& server,
+    const base::DictionaryValue& server_pref_dict,
+    AlternateProtocolMap* alternate_protocol_map) {
+  // Get alternate_protocol server.
+  DCHECK(alternate_protocol_map->Peek(server) == alternate_protocol_map->end());
+  const base::DictionaryValue* port_alternate_protocol_dict = NULL;
+  if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
+          kAlternateProtocolKey, &port_alternate_protocol_dict)) {
+    return true;
+  }
+  int port = 0;
+  if (!port_alternate_protocol_dict->GetIntegerWithoutPathExpansion(kPortKey,
+                                                                    &port) ||
+      !IsPortValid(port)) {
+    DVLOG(1) << "Malformed Alternate-Protocol server: " << server.ToString();
+    return false;
+  }
+  std::string protocol_str;
+  if (!port_alternate_protocol_dict->GetStringWithoutPathExpansion(
+          kProtocolKey, &protocol_str)) {
+    DVLOG(1) << "Malformed Alternate-Protocol server: " << server.ToString();
+    return false;
+  }
+  AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
+  if (!IsAlternateProtocolValid(protocol)) {
+    DVLOG(1) << "Malformed Alternate-Protocol server: " << server.ToString();
+    return false;
+  }
+  double probability = 1;
+  if (port_alternate_protocol_dict->HasKey(kProbabilityKey) &&
+      !port_alternate_protocol_dict->GetDoubleWithoutPathExpansion(
+          kProbabilityKey, &probability)) {
+    DVLOG(1) << "Malformed Alternate-Protocol server: " << server.ToString();
+    return false;
+  }
+
+  AlternateProtocolInfo port_alternate_protocol(static_cast<uint16>(port),
+                                                protocol, probability);
+  alternate_protocol_map->Put(server, port_alternate_protocol);
+  return true;
+}
+
+bool HttpServerPropertiesManager::AddToSupportsQuicMap(
+    const HostPortPair& server,
+    const base::DictionaryValue& server_pref_dict,
+    SupportsQuicMap* supports_quic_map) {
+  DCHECK(supports_quic_map->find(server) == supports_quic_map->end());
+  const base::DictionaryValue* supports_quic_dict = NULL;
+  if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
+          kSupportsQuicKey, &supports_quic_dict)) {
+    return true;
+  }
+  bool used_quic = 0;
+  if (!supports_quic_dict->GetBooleanWithoutPathExpansion(kUsedQuicKey,
+                                                          &used_quic)) {
+    DVLOG(1) << "Malformed SupportsQuic server: " << server.ToString();
+    return false;
+  }
+  std::string address;
+  if (!supports_quic_dict->GetStringWithoutPathExpansion(kAddressKey,
+                                                         &address)) {
+    DVLOG(1) << "Malformed SupportsQuic server: " << server.ToString();
+    return false;
+  }
+  SupportsQuic supports_quic(used_quic, address);
+  supports_quic_map->insert(std::make_pair(server, supports_quic));
+  return true;
+}
+
+bool HttpServerPropertiesManager::AddToNetworkStatsMap(
+    const HostPortPair& server,
+    const base::DictionaryValue& server_pref_dict,
+    ServerNetworkStatsMap* network_stats_map) {
+  DCHECK(network_stats_map->Peek(server) == network_stats_map->end());
+  const base::DictionaryValue* server_network_stats_dict = NULL;
+  if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
+          kNetworkStatsKey, &server_network_stats_dict)) {
+    return true;
+  }
+  int srtt;
+  if (!server_network_stats_dict->GetIntegerWithoutPathExpansion(kSrttKey,
+                                                                 &srtt)) {
+    DVLOG(1) << "Malformed ServerNetworkStats for server: "
+             << server.ToString();
+    return false;
+  }
+  ServerNetworkStats server_network_stats;
+  server_network_stats.srtt = base::TimeDelta::FromInternalValue(srtt);
+  // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
+  // bandwidth_estimate.
+  network_stats_map->Put(server, server_network_stats);
+  return true;
+}
+
 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
     StringVector* spdy_servers,
     SpdySettingsMap* spdy_settings_map,
@@ -697,14 +731,7 @@
        ++list_it) {
     if ((*list_it)->GetAsString(&s)) {
       HostPortPair server = HostPortPair::FromString(s);
-
-      ServerPrefMap::iterator it = server_pref_map.find(server);
-      if (it == server_pref_map.end()) {
-        ServerPref server_pref(true, NULL, NULL, NULL, NULL);
-        server_pref_map[server] = server_pref;
-      } else {
-        it->second.supports_spdy = true;
-      }
+      server_pref_map[server].supports_spdy = true;
     }
   }
 
@@ -712,14 +739,7 @@
   for (SpdySettingsMap::iterator map_it = spdy_settings_map->begin();
        map_it != spdy_settings_map->end(); ++map_it) {
     const HostPortPair& server = map_it->first;
-
-    ServerPrefMap::iterator it = server_pref_map.find(server);
-    if (it == server_pref_map.end()) {
-      ServerPref server_pref(false, &map_it->second, NULL, NULL, NULL);
-      server_pref_map[server] = server_pref;
-    } else {
-      it->second.settings_map = &map_it->second;
-    }
+    server_pref_map[server].settings_map = &map_it->second;
   }
 
   // Add AlternateProtocol servers to server_pref_map.
@@ -731,28 +751,14 @@
     if (!IsAlternateProtocolValid(port_alternate_protocol.protocol)) {
       continue;
     }
-
-    ServerPrefMap::iterator it = server_pref_map.find(server);
-    if (it == server_pref_map.end()) {
-      ServerPref server_pref(false, NULL, &map_it->second, NULL, NULL);
-      server_pref_map[server] = server_pref;
-    } else {
-      it->second.alternate_protocol = &map_it->second;
-    }
+    server_pref_map[server].alternate_protocol = &map_it->second;
   }
 
   // Add SupportsQuic servers to server_pref_map.
   for (SupportsQuicMap::const_iterator map_it = supports_quic_map->begin();
        map_it != supports_quic_map->end(); ++map_it) {
     const HostPortPair& server = map_it->first;
-
-    ServerPrefMap::iterator it = server_pref_map.find(server);
-    if (it == server_pref_map.end()) {
-      ServerPref server_pref(false, NULL, NULL, &map_it->second, NULL);
-      server_pref_map[server] = server_pref;
-    } else {
-      it->second.supports_quic = &map_it->second;
-    }
+    server_pref_map[server].supports_quic = &map_it->second;
   }
 
   // Add ServerNetworkStats servers to server_pref_map.
@@ -760,14 +766,7 @@
            server_network_stats_map->begin();
        map_it != server_network_stats_map->end(); ++map_it) {
     const HostPortPair& server = map_it->first;
-
-    ServerPrefMap::iterator it = server_pref_map.find(server);
-    if (it == server_pref_map.end()) {
-      ServerPref server_pref(false, NULL, NULL, NULL, &map_it->second);
-      server_pref_map[server] = server_pref;
-    } else {
-      it->second.server_network_stats = &map_it->second;
-    }
+    server_pref_map[server].server_network_stats = &map_it->second;
   }
 
   // Persist properties to the |path_|.
@@ -783,68 +782,19 @@
 
     // Save supports_spdy.
     if (server_pref.supports_spdy)
-      server_pref_dict->SetBoolean("supports_spdy", server_pref.supports_spdy);
-
-    // Save SPDY settings.
-    if (server_pref.settings_map) {
-      base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
-      for (SettingsMap::const_iterator it = server_pref.settings_map->begin();
-           it != server_pref.settings_map->end(); ++it) {
-        SpdySettingsIds id = it->first;
-        uint32 value = it->second.second;
-        std::string key = base::StringPrintf("%u", id);
-        spdy_settings_dict->SetInteger(key, value);
-      }
-      server_pref_dict->SetWithoutPathExpansion("settings", spdy_settings_dict);
-    }
-
-    // Save alternate_protocol.
-    const AlternateProtocolInfo* port_alternate_protocol =
-        server_pref.alternate_protocol;
-    if (port_alternate_protocol && !port_alternate_protocol->is_broken) {
-      base::DictionaryValue* port_alternate_protocol_dict =
-          new base::DictionaryValue;
-      port_alternate_protocol_dict->SetInteger("port",
-                                               port_alternate_protocol->port);
-      const char* protocol_str =
-          AlternateProtocolToString(port_alternate_protocol->protocol);
-      port_alternate_protocol_dict->SetString("protocol_str", protocol_str);
-      port_alternate_protocol_dict->SetDouble(
-          "probability", port_alternate_protocol->probability);
-      server_pref_dict->SetWithoutPathExpansion(
-          "alternate_protocol", port_alternate_protocol_dict);
-    }
-
-    // Save supports_quic.
-    if (server_pref.supports_quic) {
-      base::DictionaryValue* supports_quic_dict = new base::DictionaryValue;
-      const SupportsQuic* supports_quic = server_pref.supports_quic;
-      supports_quic_dict->SetBoolean("used_quic", supports_quic->used_quic);
-      supports_quic_dict->SetString("address", supports_quic->address);
-      server_pref_dict->SetWithoutPathExpansion(
-          "supports_quic", supports_quic_dict);
-    }
-
-    // Save ServerNetworkStats.
-    if (server_pref.server_network_stats) {
-      base::DictionaryValue* server_network_stats_dict =
-          new base::DictionaryValue;
-      const ServerNetworkStats* server_network_stats =
-          server_pref.server_network_stats;
-      // Becasue JSON doesn't support int64, persist int64 as a string.
-      server_network_stats_dict->SetInteger(
-          "srtt",
-          static_cast<int>(server_network_stats->srtt.ToInternalValue()));
-      // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
-      // bandwidth_estimate.
-      server_pref_dict->SetWithoutPathExpansion("network_stats",
-                                                server_network_stats_dict);
-    }
+      server_pref_dict->SetBoolean(kSupportsSpdyKey, server_pref.supports_spdy);
+    SaveSpdySettingsToServerPrefs(server_pref.settings_map, server_pref_dict);
+    SaveAlternateProtocolToServerPrefs(server_pref.alternate_protocol,
+                                       server_pref_dict);
+    SaveSupportsQuicToServerPrefs(server_pref.supports_quic, server_pref_dict);
+    SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
+                                  server_pref_dict);
 
     servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
   }
 
-  http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict);
+  http_server_properties_dict.SetWithoutPathExpansion(kServersKey,
+                                                      servers_dict);
   SetVersion(&http_server_properties_dict, kVersionNumber);
   setting_prefs_ = true;
   pref_service_->Set(path_, http_server_properties_dict);
@@ -858,6 +808,72 @@
     completion.Run();
 }
 
+void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
+    const SettingsMap* settings_map,
+    base::DictionaryValue* server_pref_dict) {
+  if (!settings_map) {
+    return;
+  }
+  base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
+  for (SettingsMap::const_iterator it = settings_map->begin();
+       it != settings_map->end(); ++it) {
+    SpdySettingsIds id = it->first;
+    uint32 value = it->second.second;
+    std::string key = base::StringPrintf("%u", id);
+    spdy_settings_dict->SetInteger(key, value);
+  }
+  server_pref_dict->SetWithoutPathExpansion(kSettingsKey, spdy_settings_dict);
+}
+
+void HttpServerPropertiesManager::SaveAlternateProtocolToServerPrefs(
+    const AlternateProtocolInfo* port_alternate_protocol,
+    base::DictionaryValue* server_pref_dict) {
+  if (!port_alternate_protocol || port_alternate_protocol->is_broken)
+    return;
+
+  base::DictionaryValue* port_alternate_protocol_dict =
+      new base::DictionaryValue;
+  port_alternate_protocol_dict->SetInteger(kPortKey,
+                                           port_alternate_protocol->port);
+  const char* protocol_str =
+      AlternateProtocolToString(port_alternate_protocol->protocol);
+  port_alternate_protocol_dict->SetString(kProtocolKey, protocol_str);
+  port_alternate_protocol_dict->SetDouble(kProbabilityKey,
+                                          port_alternate_protocol->probability);
+  server_pref_dict->SetWithoutPathExpansion(kAlternateProtocolKey,
+                                            port_alternate_protocol_dict);
+}
+
+void HttpServerPropertiesManager::SaveSupportsQuicToServerPrefs(
+    const SupportsQuic* supports_quic,
+    base::DictionaryValue* server_pref_dict) {
+  // Save supports_quic.
+  if (!supports_quic)
+    return;
+
+  base::DictionaryValue* supports_quic_dict = new base::DictionaryValue;
+  supports_quic_dict->SetBoolean(kUsedQuicKey, supports_quic->used_quic);
+  supports_quic_dict->SetString(kAddressKey, supports_quic->address);
+  server_pref_dict->SetWithoutPathExpansion(kSupportsQuicKey,
+                                            supports_quic_dict);
+}
+
+void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
+    const ServerNetworkStats* server_network_stats,
+    base::DictionaryValue* server_pref_dict) {
+  if (!server_network_stats)
+    return;
+
+  base::DictionaryValue* server_network_stats_dict = new base::DictionaryValue;
+  // Becasue JSON doesn't support int64, persist int64 as a string.
+  server_network_stats_dict->SetInteger(
+      kSrttKey, static_cast<int>(server_network_stats->srtt.ToInternalValue()));
+  // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
+  // bandwidth_estimate.
+  server_pref_dict->SetWithoutPathExpansion(kNetworkStatsKey,
+                                            server_network_stats_dict);
+}
+
 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
   DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
   if (!setting_prefs_)
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h
index 00e5a13..21d817a0 100644
--- a/net/http/http_server_properties_manager.h
+++ b/net/http/http_server_properties_manager.h
@@ -86,7 +86,6 @@
   void SetHTTP11Required(const HostPortPair& server) override;
   void MaybeForceHTTP11(const HostPortPair& server,
                         SSLConfig* ssl_config) override;
-  bool HasAlternateProtocol(const HostPortPair& server) override;
   AlternateProtocolInfo GetAlternateProtocol(
       const HostPortPair& server) override;
   void SetAlternateProtocol(const HostPortPair& server,
@@ -181,6 +180,30 @@
  private:
   void OnHttpServerPropertiesChanged();
 
+  void AddToSpdySettingsMap(const HostPortPair& server,
+                            const base::DictionaryValue& server_dict,
+                            SpdySettingsMap* spdy_settings_map);
+  bool AddToAlternateProtocolMap(const HostPortPair& server,
+                                 const base::DictionaryValue& server_dict,
+                                 AlternateProtocolMap* alternate_protocol_map);
+  bool AddToSupportsQuicMap(const HostPortPair& server,
+                            const base::DictionaryValue& server_dict,
+                            SupportsQuicMap* supports_quic_map);
+  bool AddToNetworkStatsMap(const HostPortPair& server,
+                            const base::DictionaryValue& server_dict,
+                            ServerNetworkStatsMap* network_stats_map);
+
+  void SaveSpdySettingsToServerPrefs(const SettingsMap* spdy_settings_map,
+                                     base::DictionaryValue* server_pref_dict);
+  void SaveAlternateProtocolToServerPrefs(
+      const AlternateProtocolInfo* port_alternate_protocol,
+      base::DictionaryValue* server_pref_dict);
+  void SaveSupportsQuicToServerPrefs(const SupportsQuic* supports_quic,
+                                     base::DictionaryValue* server_pref_dict);
+  void SaveNetworkStatsToServerPrefs(
+      const ServerNetworkStats* server_network_stats,
+      base::DictionaryValue* server_pref_dict);
+
   // -----------
   // Pref thread
   // -----------
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index d021fc5..cbc2275e 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -134,6 +134,12 @@
                        UpdatePrefsFromCacheOnNetworkThreadConcrete));
   }
 
+  bool HasAlternateProtocol(const HostPortPair& server) {
+    const AlternateProtocolInfo alternate =
+        http_server_props_manager_->GetAlternateProtocol(server);
+    return alternate.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL;
+  }
+
   //base::RunLoop loop_;
   TestingPrefServiceSimple pref_service_;
   scoped_ptr<TestingHttpServerPropertiesManager> http_server_props_manager_;
@@ -230,8 +236,6 @@
       HostPortPair::FromString("foo.google.com:1337")));
 
   // Verify AlternateProtocol.
-  ASSERT_TRUE(http_server_props_manager_->HasAlternateProtocol(google_server));
-  ASSERT_TRUE(http_server_props_manager_->HasAlternateProtocol(mail_server));
   AlternateProtocolInfo port_alternate_protocol =
       http_server_props_manager_->GetAlternateProtocol(google_server);
   EXPECT_EQ(443, port_alternate_protocol.port);
@@ -307,8 +311,8 @@
   // Verify that nothing is set.
   EXPECT_FALSE(http_server_props_manager_->SupportsRequestPriority(
       HostPortPair::FromString("www.google.com:65536")));
-  EXPECT_FALSE(http_server_props_manager_->HasAlternateProtocol(
-      HostPortPair::FromString("www.google.com:65536")));
+  EXPECT_FALSE(
+      HasAlternateProtocol(HostPortPair::FromString("www.google.com:65536")));
   SupportsQuic supports_quic2 = http_server_props_manager_->GetSupportsQuic(
       HostPortPair::FromString("www.google.com:65536"));
   EXPECT_FALSE(supports_quic2.used_quic);
@@ -352,8 +356,8 @@
   Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
 
   // Verify AlternateProtocol is not set.
-  EXPECT_FALSE(http_server_props_manager_->HasAlternateProtocol(
-      HostPortPair::FromString("www.google.com:80")));
+  EXPECT_FALSE(
+      HasAlternateProtocol(HostPortPair::FromString("www.google.com:80")));
 }
 
 TEST_F(HttpServerPropertiesManagerTest, SupportsSpdy) {
@@ -477,12 +481,11 @@
   Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
 }
 
-TEST_F(HttpServerPropertiesManagerTest, HasAlternateProtocol) {
+TEST_F(HttpServerPropertiesManagerTest, GetAlternateProtocol) {
   ExpectPrefsUpdate();
 
   HostPortPair spdy_server_mail("mail.google.com", 80);
-  EXPECT_FALSE(
-      http_server_props_manager_->HasAlternateProtocol(spdy_server_mail));
+  EXPECT_FALSE(HasAlternateProtocol(spdy_server_mail));
   http_server_props_manager_->SetAlternateProtocol(spdy_server_mail, 443,
                                                    NPN_SPDY_3, 1.0);
 
@@ -490,12 +493,11 @@
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
 
-  ASSERT_TRUE(
-      http_server_props_manager_->HasAlternateProtocol(spdy_server_mail));
-  AlternateProtocolInfo port_alternate_protocol =
+  const AlternateProtocolInfo alternate_protocol =
       http_server_props_manager_->GetAlternateProtocol(spdy_server_mail);
-  EXPECT_EQ(443, port_alternate_protocol.port);
-  EXPECT_EQ(NPN_SPDY_3, port_alternate_protocol.protocol);
+  EXPECT_EQ(443, alternate_protocol.port);
+  EXPECT_EQ(NPN_SPDY_3, alternate_protocol.protocol);
+  EXPECT_EQ(1.0, alternate_protocol.probability);
 }
 
 TEST_F(HttpServerPropertiesManagerTest, SupportsQuic) {
@@ -561,8 +563,7 @@
 
   EXPECT_TRUE(
       http_server_props_manager_->SupportsRequestPriority(spdy_server_mail));
-  EXPECT_TRUE(
-      http_server_props_manager_->HasAlternateProtocol(spdy_server_mail));
+  EXPECT_TRUE(HasAlternateProtocol(spdy_server_mail));
   SupportsQuic supports_quic =
       http_server_props_manager_->GetSupportsQuic(spdy_server_mail);
   EXPECT_TRUE(supports_quic.used_quic);
@@ -591,8 +592,7 @@
 
   EXPECT_FALSE(
       http_server_props_manager_->SupportsRequestPriority(spdy_server_mail));
-  EXPECT_FALSE(
-      http_server_props_manager_->HasAlternateProtocol(spdy_server_mail));
+  EXPECT_FALSE(HasAlternateProtocol(spdy_server_mail));
   SupportsQuic supports_quic1 =
       http_server_props_manager_->GetSupportsQuic(spdy_server_mail);
   EXPECT_FALSE(supports_quic1.used_quic);
@@ -654,8 +654,6 @@
   // Verify AlternateProtocol.
   for (int i = 0; i < 200; ++i) {
     std::string server = StringPrintf("www.google.com:%d", i);
-    ASSERT_TRUE(http_server_props_manager_->HasAlternateProtocol(
-        HostPortPair::FromString(server)));
     AlternateProtocolInfo port_alternate_protocol =
         http_server_props_manager_->GetAlternateProtocol(
             HostPortPair::FromString(server));
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc
index f84b80c..754372bb 100644
--- a/net/http/http_stream_factory.cc
+++ b/net/http/http_stream_factory.cc
@@ -86,14 +86,6 @@
   if (mapping_rules)
     mapping_rules->RewriteHost(&host_port);
 
-  if (http_server_properties->HasAlternateProtocol(host_port)) {
-    const AlternateProtocolInfo existing_alternate =
-        http_server_properties->GetAlternateProtocol(host_port);
-    // If we think the alternate protocol is broken, don't change it.
-    if (existing_alternate.is_broken)
-      return;
-  }
-
   http_server_properties->SetAlternateProtocol(
       host_port, static_cast<uint16>(port), protocol, probability);
 }
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index 9e932ee..78238b94 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -175,8 +175,7 @@
 AlternateProtocolInfo HttpStreamFactoryImpl::GetAlternateProtocolRequestFor(
     const GURL& original_url,
     GURL* alternate_url) {
-  const AlternateProtocolInfo kNoAlternateProtocol =
-      AlternateProtocolInfo(0,  UNINITIALIZED_ALTERNATE_PROTOCOL, 0);
+  const AlternateProtocolInfo kNoAlternateProtocol;
 
   if (!session_->params().use_alternate_protocols)
     return kNoAlternateProtocol;
@@ -185,19 +184,17 @@
     return kNoAlternateProtocol;
 
   HostPortPair origin = HostPortPair::FromURL(original_url);
-
   HttpServerProperties& http_server_properties =
       *session_->http_server_properties();
-  if (!http_server_properties.HasAlternateProtocol(origin))
-    return kNoAlternateProtocol;
-
-  AlternateProtocolInfo alternate =
+  const AlternateProtocolInfo alternate =
       http_server_properties.GetAlternateProtocol(origin);
+
+  if (alternate.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
+    return kNoAlternateProtocol;
   if (alternate.is_broken) {
     HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_BROKEN);
     return kNoAlternateProtocol;
   }
-
   if (!IsAlternateProtocolValid(alternate.protocol)) {
     NOTREACHED();
     return kNoAlternateProtocol;
diff --git a/net/interfaces/BUILD.gn b/net/interfaces/BUILD.gn
new file mode 100644
index 0000000..03a07785
--- /dev/null
+++ b/net/interfaces/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2015 The Chromium 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/mojo/src/mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "host_resolver_service.mojom",
+    "proxy_resolver_service.mojom",
+  ]
+}
diff --git a/net/interfaces/host_resolver_service.mojom b/net/interfaces/host_resolver_service.mojom
new file mode 100644
index 0000000..c8acc38
--- /dev/null
+++ b/net/interfaces/host_resolver_service.mojom
@@ -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.
+
+// WARNING! Do NOT use this mojom. It is intended as a temporary interface to
+// implement out-of-process proxy resolution. If you wish to use a Mojo DNS
+// service, contact amistry@/sammc@ and net-dev to discuss a permanent Mojo DNS
+// interface.
+
+// Put Mojo definitions into their own namespace to avoid collisions with C++
+// definitions.
+// TODO(amistry): Resolve the conflict between these two sets of definitions.
+module net.interfaces;
+
+// Mirror of net::AddressFamily.
+enum AddressFamily {
+  UNSPECIFIED,
+  IPV4,
+  IPV6,
+};
+
+// Mirror of net::HostResolver::RequestInfo.
+struct HostResolverRequestInfo {
+  string host;
+  uint16 port;
+  AddressFamily address_family;
+  bool is_my_ip_address;
+};
+
+// Mirror of net::IPEndPoint.
+struct IPEndPoint {
+  // IP address as a numeric value from most to least significant byte.
+  // Will be of length 4 for IPv4 addresses and 16 for IPv6.
+  array<uint8> address;
+  uint16 port;
+};
+
+// Mirror of net::AddressList.
+struct AddressList {
+  array<IPEndPoint> addresses;
+};
+
+interface HostResolverService {
+  // Use a HostResolverRequestClient instead of returning a result so we can
+  // cancel in-flight requests by destroying the client.  IPC requests in Mojo
+  // cannot be cancelled directly.
+  // TODO(amistry): Add BoundNetLog.
+  Resolve(HostResolverRequestInfo request_info,
+          HostResolverRequestClient client);
+};
+
+interface HostResolverRequestClient {
+  // |error| is a value in net::Error.
+  ReportResult(int32 error, AddressList? result);
+};
diff --git a/net/interfaces/proxy_resolver_service.mojom b/net/interfaces/proxy_resolver_service.mojom
new file mode 100644
index 0000000..2cb7a0b7
--- /dev/null
+++ b/net/interfaces/proxy_resolver_service.mojom
@@ -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.
+
+// Put Mojo definitions into their own namespace to avoid collisions with C++
+// definitions.
+// TODO(amistry): Resolve the conflict between these two sets of definitions.
+module net.interfaces;
+
+import "host_resolver_service.mojom";
+
+// Mirror of net::ProxyServer::Scheme.
+enum ProxyScheme {
+  INVALID,
+  DIRECT,
+  HTTP,
+  SOCKS4,
+  SOCKS5,
+  HTTPS,
+  QUIC,
+};
+
+// Mirror of net::ProxyServer.
+struct ProxyServer {
+  ProxyScheme scheme;
+  string host;
+  uint16 port;
+};
+
+interface ProxyResolverService {
+  SetPacScript(string data) => (int32 result);
+
+  // Use a ProxyResolverRequestClient instead of returning a result so we can
+  // receive load state updates and cancel in-flight requests by destroying the
+  // client.
+  // TODO(amistry): Add BoundNetLog.
+  GetProxyForUrl(string url, ProxyResolverRequestClient client);
+};
+
+interface ProxyResolverRequestClient {
+  ReportResult(int32 error, array<ProxyServer>? proxy_servers);
+};
+
+interface ProxyResolverFactory {
+  // TODO(amistry): Add NetLog and ProxyResolverErrorObserver.
+  CreateResolver(ProxyResolverService& resolver,
+                 HostResolverService host_resolver);
+};
diff --git a/net/net.gyp b/net/net.gyp
index 834a4c6..6dac5c8 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -1203,6 +1203,22 @@
         },
       ],
     }],
+    ['use_v8_in_net == 1 and OS != "android"', {
+      'targets': [
+        {
+          # GN version: //net/interfaces
+          'target_name': 'net_interfaces',
+          'type': 'static_library',
+          'sources': [
+            'interfaces/host_resolver_service.mojom',
+            'interfaces/proxy_resolver_service.mojom',
+          ],
+          'includes': [
+            '../third_party/mojo/mojom_bindings_generator.gypi',
+          ],
+        },
+      ],
+    }],
     ['OS != "ios" and OS != "android"', {
       'targets': [
         # iOS doesn't have the concept of simple executables, these targets
diff --git a/net/net_unittests.isolate b/net/net_unittests.isolate
index e062a7d6..ec515fbe 100644
--- a/net/net_unittests.isolate
+++ b/net/net_unittests.isolate
@@ -19,6 +19,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../testing/test_env.py',
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 5219d1e..203aa3e 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -284,17 +284,14 @@
   }
 
   void ExpectBrokenAlternateProtocolMapping() {
-    ASSERT_TRUE(session_->http_server_properties()->HasAlternateProtocol(
-        HostPortPair::FromURL(request_.url)));
     const AlternateProtocolInfo alternate =
         session_->http_server_properties()->GetAlternateProtocol(
             HostPortPair::FromURL(request_.url));
+    EXPECT_NE(UNINITIALIZED_ALTERNATE_PROTOCOL, alternate.protocol);
     EXPECT_TRUE(alternate.is_broken);
   }
 
   void ExpectQuicAlternateProtocolMapping() {
-    ASSERT_TRUE(session_->http_server_properties()->HasAlternateProtocol(
-        HostPortPair::FromURL(request_.url)));
     const AlternateProtocolInfo alternate =
         session_->http_server_properties()->GetAlternateProtocol(
             HostPortPair::FromURL(request_.url));
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index f957c18..f38ae01 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -1249,7 +1249,9 @@
   const HostPortPair& server = server_id.host_port_pair();
   // Don't try to change the alternate-protocol state, if the
   // alternate-protocol state is unknown.
-  if (!http_server_properties_->HasAlternateProtocol(server))
+  const AlternateProtocolInfo alternate =
+      http_server_properties_->GetAlternateProtocol(server);
+  if (alternate.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
     return;
 
   // TODO(rch):  In the special case where the session has received no
@@ -1258,8 +1260,6 @@
   // session connected until the handshake has been confirmed.
   HistogramBrokenAlternateProtocolLocation(
       BROKEN_ALTERNATE_PROTOCOL_LOCATION_QUIC_STREAM_FACTORY);
-  AlternateProtocolInfo alternate =
-      http_server_properties_->GetAlternateProtocol(server);
   DCHECK_EQ(QUIC, alternate.protocol);
 
   // Since the session was active, there's no longer an
diff --git a/net/test/url_request/url_request_mock_http_job.cc b/net/test/url_request/url_request_mock_http_job.cc
index 9e63c25..e0905f2 100644
--- a/net/test/url_request/url_request_mock_http_job.cc
+++ b/net/test/url_request/url_request_mock_http_job.cc
@@ -122,16 +122,6 @@
 }
 
 // static
-void URLRequestMockHTTPJob::AddHostnameToFileHandler(
-    const std::string& hostname,
-    const base::FilePath& file,
-    const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
-  net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
-  filter->AddHostnameInterceptor(
-      "http", hostname, CreateInterceptorForSingleFile(file, worker_pool));
-}
-
-// static
 GURL URLRequestMockHTTPJob::GetMockUrl(const base::FilePath& path) {
   return GetMockUrlForScheme(path, "http");
 }
diff --git a/net/test/url_request/url_request_mock_http_job.h b/net/test/url_request/url_request_mock_http_job.h
index 6e454f4..61d5069 100644
--- a/net/test/url_request/url_request_mock_http_job.h
+++ b/net/test/url_request/url_request_mock_http_job.h
@@ -54,13 +54,6 @@
       const base::FilePath& base_path,
       const scoped_refptr<base::SequencedWorkerPool>& worker_pool);
 
-  // Respond to all HTTP requests of |hostname| with contents of the file
-  // located at |file_path|.
-  static void AddHostnameToFileHandler(
-      const std::string& hostname,
-      const base::FilePath& file,
-      const scoped_refptr<base::SequencedWorkerPool>& worker_pool);
-
   // Given the path to a file relative to the path passed to AddUrlHandler(),
   // construct a mock URL.
   static GURL GetMockUrl(const base::FilePath& path);
diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn
index b028290..4ecd961f 100644
--- a/pdf/BUILD.gn
+++ b/pdf/BUILD.gn
@@ -4,8 +4,7 @@
 
 pdf_engine = 0  # 0 PDFium
 
-# TODO(GYP) need support for loadable modules
-shared_library("pdf") {
+static_library("pdf") {
   sources = [
     "button.h",
     "button.cc",
@@ -35,7 +34,6 @@
     "paint_manager.h",
     "pdf.cc",
     "pdf.h",
-    "pdf.rc",
     "progress_control.cc",
     "progress_control.h",
     "pdf_engine.h",
@@ -45,8 +43,6 @@
     "resource_consts.h",
     "thumbnail_control.cc",
     "thumbnail_control.h",
-    "../components/ui/zoom/page_zoom_constants.cc",
-    "../content/common/page_zoom.cc",
   ]
 
   if (pdf_engine == 0) {
@@ -68,33 +64,15 @@
   }
 
   if (is_win) {
-    defines = [ "COMPILE_CONTENT_STATICALLY" ]
     cflags = [ "/wd4267" ]  # TODO(jschuh) size_t to int truncations.
   }
 
-  if (is_mac) {
-    # TODO(GYP)
-    #'mac_bundle': 1,
-    #'product_name': 'PDF',
-    #'product_extension': 'plugin',
-    ## Strip the shipping binary of symbols so "Foxit" doesn't appear in
-    ## the binary.  Symbols are stored in a separate .dSYM.
-    #'variables': {
-    #  'mac_real_dsym': 1,
-    #},
-    #'sources+': [
-    #  'Info.plist'
-    #]
-    #'xcode_settings': {
-    #  'INFOPLIST_FILE': 'Info.plist',
-    #},
-  }
-
   deps = [
     "//base",
+    "//components/ui/zoom:ui_zoom",
+    "//content/public/common",
     "//net",
-    "//ppapi:ppapi_cpp",
+    "//ppapi:ppapi_internal_module",
     "//third_party/pdfium",
   ]
 }
-# TODO(GYP) pdf_linux_symbols target.
diff --git a/pdf/Info.plist b/pdf/Info.plist
deleted file mode 100644
index 9f3dfdf..0000000
--- a/pdf/Info.plist
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>English</string>
-	<key>CFBundleExecutable</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.chromium.pdf_plugin</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>${PRODUCT_NAME}</string>
-	<key>CFBundlePackageType</key>
-	<string>BRPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1.0</string>
-	<key>CFPlugInDynamicRegisterFunction</key>
-	<string></string>
-	<key>CFPlugInDynamicRegistration</key>
-	<string>NO</string>
-	<key>WebPluginDescription</key>
-	<string>Chrome PDF Viewer</string>
-	<key>WebPluginMIMETypes</key>
-	<dict>
-		<key>application/pdf</key>
-		<dict>
-			<key>WebPluginExtensions</key>
-			<array>
-				<string>pdf</string>
-			</array>
-			<key>WebPluginTypeDescription</key>
-			<string>Acrobat Portable Document Format</string>
-		</dict>
-	</dict>
-	<key>WebPluginName</key>
-	<string>Chrome PDF Viewer</string>
-</dict>
-</plist>
diff --git a/pdf/pdf.cc b/pdf/pdf.cc
index d6c9863..7aba412 100644
--- a/pdf/pdf.cc
+++ b/pdf/pdf.cc
@@ -13,73 +13,12 @@
 #include "pdf/instance.h"
 #include "pdf/out_of_process_instance.h"
 #include "ppapi/c/ppp.h"
+#include "ppapi/cpp/private/internal_module.h"
 #include "ppapi/cpp/private/pdf.h"
 #include "v8/include/v8.h"
 
 bool g_sdk_initialized_via_pepper = false;
 
-// The Mac release builds discard CreateModule and the entire PDFModule
-// definition because they are not referenced here. This causes the Pepper
-// exports (PPP_GetInterface etc) to not be exported. So we force the linker
-// to include this code by using __attribute__((used)).
-#if __GNUC__ >= 4
-#define PDF_USED __attribute__((used))
-#else
-#define PDF_USED
-#endif
-
-#if defined(OS_WIN)
-
-void HandleInvalidParameter(const wchar_t* expression,
-                            const wchar_t* function,
-                            const wchar_t* file,
-                            unsigned int line,
-                            uintptr_t reserved) {
-  // Do the same as Chrome's CHECK(false) which is undefined.
-  ::base::debug::BreakDebugger();
-  return;
-}
-
-void HandlePureVirtualCall() {
-  // Do the same as Chrome's CHECK(false) which is undefined.
-  ::base::debug::BreakDebugger();
-  return;
-}
-
-
-BOOL APIENTRY DllMain(HMODULE module, DWORD reason_for_call, LPVOID reserved) {
-  if (reason_for_call == DLL_PROCESS_ATTACH) {
-    // On windows following handlers work only inside module. So breakpad in
-    // chrome.dll does not catch that. To avoid linking related code or
-    // duplication breakpad_win.cc::InitCrashReporter() just catch errors here
-    // and crash in a way interceptable by breakpad of parent module.
-    _set_invalid_parameter_handler(HandleInvalidParameter);
-    _set_purecall_handler(HandlePureVirtualCall);
-
-#if defined(ARCH_CPU_X86_64) && _MSC_VER <= 1800
-    // VS2013's CRT only checks the existence of FMA3 instructions, not the
-    // enabled-ness of them at the OS level (this is fixed in VS2015). We force
-    // off usage of FMA3 instructions in the CRT to avoid using that path and
-    // hitting illegal instructions when running on CPUs that support FMA3, but
-    // OSs that don't. Because we use the static library CRT we have to call
-    // this function once in each DLL.
-    // See http://crbug.com/436603.
-    _set_FMA3_enable(0);
-#endif  // ARCH_CPU_X86_64 && _MSC_VER <= 1800
-  }
-  return TRUE;
-}
-
-#endif
-
-namespace pp {
-
-PDF_USED Module* CreateModule() {
-  return new chrome_pdf::PDFModule();
-}
-
-}  // namespace pp
-
 namespace chrome_pdf {
 
 PDFModule::PDFModule() {
@@ -117,49 +56,37 @@
   return new Instance(instance);
 }
 
-}  // namespace chrome_pdf
 
-extern "C" {
+// Implementation of Global PPP functions ---------------------------------
+int32_t PPP_InitializeModule(PP_Module module_id,
+                             PPB_GetInterface get_browser_interface) {
+  PDFModule* module = new PDFModule();
+  if (!module->InternalInit(module_id, get_browser_interface)) {
+    delete module;
+    return PP_ERROR_FAILED;
+  }
 
-// TODO(sanjeevr): It might make sense to provide more stateful wrappers over
-// the internal PDF SDK (such as LoadDocument, LoadPage etc). Determine if we
-// need to provide this.
-// Wrapper exports over the PDF engine that can be used by an external module
-// such as Chrome (since Chrome cannot directly pull in PDFium sources).
+  pp::InternalSetModuleSingleton(module);
+  return PP_OK;
+}
+
+void PPP_ShutdownModule() {
+  delete pp::Module::Get();
+  pp::InternalSetModuleSingleton(NULL);
+}
+
+const void* PPP_GetInterface(const char* interface_name) {
+  if (!pp::Module::Get())
+    return NULL;
+  return pp::Module::Get()->GetPluginInterface(interface_name);
+}
+
 #if defined(OS_WIN)
-// |pdf_buffer| is the buffer that contains the entire PDF document to be
-//     rendered.
-// |buffer_size| is the size of |pdf_buffer| in bytes.
-// |page_number| is the 0-based index of the page to be rendered.
-// |dc| is the device context to render into.
-// |dpi_x| and |dpi_y| are the x and y resolutions respectively. If either
-//     value is -1, the dpi from the DC will be used.
-// |bounds_origin_x|, |bounds_origin_y|, |bounds_width| and |bounds_height|
-//     specify a bounds rectangle within the DC in which to render the PDF
-//     page.
-// |fit_to_bounds| specifies whether the output should be shrunk to fit the
-//     supplied bounds if the page size is larger than the bounds in any
-//     dimension. If this is false, parts of the PDF page that lie outside
-//     the bounds will be clipped.
-// |stretch_to_bounds| specifies whether the output should be stretched to fit
-//     the supplied bounds if the page size is smaller than the bounds in any
-//     dimension.
-// If both |fit_to_bounds| and |stretch_to_bounds| are true, then
-//     |fit_to_bounds| is honored first.
-// |keep_aspect_ratio| If any scaling is to be done is true, this flag
-//     specifies whether the original aspect ratio of the page should be
-//     preserved while scaling.
-// |center_in_bounds| specifies whether the final image (after any scaling is
-//     done) should be centered within the given bounds.
-// |autorotate| specifies whether the final image should be rotated to match
-//     the output bound.
-// Returns false if the document or the page number are not valid.
-PP_EXPORT bool RenderPDFPageToDC(const void* pdf_buffer,
+bool RenderPDFPageToDC(const void* pdf_buffer,
                                  int buffer_size,
                                  int page_number,
                                  HDC dc,
-                                 int dpi_x,
-                                 int dpi_y,
+                                 int dpi,
                                  int bounds_origin_x,
                                  int bounds_origin_y,
                                  int bounds_width,
@@ -177,8 +104,8 @@
   scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
       chrome_pdf::PDFEngineExports::Create());
   chrome_pdf::PDFEngineExports::RenderingSettings settings(
-      dpi_x, dpi_y, pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width,
-                             bounds_height),
+      dpi, dpi, pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width,
+                         bounds_height),
       fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds,
       autorotate);
   bool ret = engine_exports->RenderPDFPageToDC(pdf_buffer, buffer_size,
@@ -191,9 +118,6 @@
 
 #endif  // OS_WIN
 
-// |page_count| and |max_page_width| are optional and can be NULL.
-// Returns false if the document is not valid.
-PDF_USED PP_EXPORT
 bool GetPDFDocInfo(const void* pdf_buffer,
                    int buffer_size, int* page_count,
                    double* max_page_width) {
@@ -211,16 +135,6 @@
   return ret;
 }
 
-// Gets the dimensions of a specific page in a document.
-// |pdf_buffer| is the buffer that contains the entire PDF document to be
-//     rendered.
-// |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
-// |page_number| is the page number that the function will get the dimensions
-//     of.
-// |width| is the output for the width of the page in points.
-// |height| is the output for the height of the page in points.
-// Returns false if the document or the page number are not valid.
-PDF_USED PP_EXPORT
 bool GetPDFPageSizeByIndex(const void* pdf_buffer,
                            int pdf_buffer_size, int page_number,
                            double* width, double* height) {
@@ -237,19 +151,6 @@
   return ret;
 }
 
-// Renders PDF page into 4-byte per pixel BGRA color bitmap.
-// |pdf_buffer| is the buffer that contains the entire PDF document to be
-//     rendered.
-// |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
-// |page_number| is the 0-based index of the page to be rendered.
-// |bitmap_buffer| is the output buffer for bitmap.
-// |bitmap_width| is the width of the output bitmap.
-// |bitmap_height| is the height of the output bitmap.
-// |dpi| is the resolutions.
-// |autorotate| specifies whether the final image should be rotated to match
-//     the output bound.
-// Returns false if the document or the page number are not valid.
-PDF_USED PP_EXPORT
 bool RenderPDFPageToBitmap(const void* pdf_buffer,
                            int pdf_buffer_size,
                            int page_number,
@@ -275,4 +176,4 @@
   return ret;
 }
 
-}  // extern "C"
+}  // namespace chrome_pdf
diff --git a/pdf/pdf.def b/pdf/pdf.def
deleted file mode 100644
index b36918b..0000000
--- a/pdf/pdf.def
+++ /dev/null
@@ -1,7 +0,0 @@
-LIBRARY pdf
-
-EXPORTS
-  NP_GetEntryPoints   @1
-  NP_Initialize       @2
-  NP_Shutdown         @3
-
diff --git a/pdf/pdf.gyp b/pdf/pdf.gyp
index 02259215..d49a0f1c 100644
--- a/pdf/pdf.gyp
+++ b/pdf/pdf.gyp
@@ -3,28 +3,18 @@
     'chromium_code': 1,
     'pdf_engine%': 0,  # 0 PDFium
   },
-  'target_defaults': {
-    'cflags': [
-      '-fPIC',
-    ],
-  },
   'targets': [
     {
       'target_name': 'pdf',
-      'type': 'loadable_module',
-      'msvs_guid': '647863C0-C7A3-469A-B1ED-AD7283C34BED',
+      'type': 'static_library',
       'dependencies': [
         '../base/base.gyp:base',
+        '../components/components.gyp:ui_zoom',
+        '../content/content.gyp:content_common',
         '../net/net.gyp:net',
-        '../ppapi/ppapi.gyp:ppapi_cpp',
+        '../ppapi/ppapi.gyp:ppapi_internal_module',
         '../third_party/pdfium/pdfium.gyp:pdfium',
       ],
-      'xcode_settings': {
-        'INFOPLIST_FILE': 'Info.plist',
-      },
-      'mac_framework_dirs': [
-        '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework/Frameworks',
-      ],
       'ldflags': [ '-L<(PRODUCT_DIR)',],
       'sources': [
         'button.h',
@@ -55,7 +45,6 @@
         'paint_manager.h',
         'pdf.cc',
         'pdf.h',
-        'pdf.rc',
         'progress_control.cc',
         'progress_control.h',
         'pdf_engine.h',
@@ -65,8 +54,6 @@
         'resource_consts.h',
         'thumbnail_control.cc',
         'thumbnail_control.h',
-        '../components/ui/zoom/page_zoom_constants.cc',
-        '../content/common/page_zoom.cc',
       ],
       'conditions': [
         ['pdf_engine==0', {
@@ -86,117 +73,11 @@
             'pdfium/pdfium_range.h',
           ],
         }],
-        ['OS!="win"', {
-          'sources!': [
-            'pdf.rc',
-          ],
-        }],
-        ['OS=="mac"', {
-          'mac_bundle': 1,
-          'product_name': 'PDF',
-          'product_extension': 'plugin',
-          # Strip the shipping binary of symbols so "Foxit" doesn't appear in
-          # the binary.  Symbols are stored in a separate .dSYM.
-          'variables': {
-            'mac_real_dsym': 1,
-          },
-          'sources+': [
-            'Info.plist'
-          ],
-        }],
         ['OS=="win"', {
-          'defines': [
-            'COMPILE_CONTENT_STATICALLY',
-          ],
           # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
           'msvs_disabled_warnings': [ 4267, ],
         }],
-        ['OS=="linux"', {
-          'configurations': {
-            'Release_Base': {
-              #'cflags': [ '-fno-weak',],  # get rid of symbols that strip doesn't remove.
-              # Don't do this for now since official builder will take care of it.  That
-              # way symbols can still be uploaded to the crash server.
-              #'ldflags': [ '-s',],  # strip local symbols from binary.
-            },
-          },
-        }],
       ],
     },
   ],
-  'conditions': [
-    # CrOS has a separate step to do this.
-    ['OS=="linux" and chromeos==0',
-      { 'targets': [
-        {
-          'target_name': 'pdf_linux_symbols',
-          'type': 'none',
-          'conditions': [
-            ['linux_dump_symbols==1', {
-              'actions': [
-                {
-                  'action_name': 'dump_symbols',
-                  'inputs': [
-                    '<(DEPTH)/build/linux/dump_app_syms',
-                    '<(PRODUCT_DIR)/dump_syms',
-                    '<(PRODUCT_DIR)/libpdf.so',
-                  ],
-                  'outputs': [
-                    '<(PRODUCT_DIR)/libpdf.so.breakpad.<(target_arch)',
-                  ],
-                  'action': ['<(DEPTH)/build/linux/dump_app_syms',
-                             '<(PRODUCT_DIR)/dump_syms',
-                             '<(linux_strip_binary)',
-                             '<(PRODUCT_DIR)/libpdf.so',
-                             '<@(_outputs)'],
-                  'message': 'Dumping breakpad symbols to <(_outputs)',
-                  'process_outputs_as_sources': 1,
-                },
-              ],
-              'dependencies': [
-                'pdf',
-                '../breakpad/breakpad.gyp:dump_syms',
-              ],
-            }],
-          ],
-        },
-      ],
-    },],  # OS=="linux" and chromeos==0
-    ['OS=="win" and fastbuild==0 and target_arch=="ia32" and syzyasan==1', {
-      'variables': {
-        'dest_dir': '<(PRODUCT_DIR)/syzygy',
-      },
-      'targets': [
-        {
-          'target_name': 'pdf_syzyasan',
-          'type': 'none',
-          'sources' : [],
-          'dependencies': [
-            'pdf',
-          ],
-          # Instrument PDFium with SyzyAsan.
-          'actions': [
-            {
-              'action_name': 'Instrument PDFium with SyzyAsan',
-              'inputs': [
-                '<(PRODUCT_DIR)/pdf.dll',
-              ],
-              'outputs': [
-                '<(dest_dir)/pdf.dll',
-                '<(dest_dir)/pdf.dll.pdb',
-              ],
-              'action': [
-                'python',
-                '<(DEPTH)/chrome/tools/build/win/syzygy/instrument.py',
-                '--mode', 'asan',
-                '--input_executable', '<(PRODUCT_DIR)/pdf.dll',
-                '--input_symbol', '<(PRODUCT_DIR)/pdf.dll.pdb',
-                '--destination_dir', '<(dest_dir)',
-              ],
-            },
-          ],
-        },
-      ],
-    }],  # OS=="win" and fastbuild==0 and target_arch=="ia32" and syzyasan==1
-  ],
 }
diff --git a/pdf/pdf.h b/pdf/pdf.h
index d797bbb..37e72e51 100644
--- a/pdf/pdf.h
+++ b/pdf/pdf.h
@@ -5,6 +5,7 @@
 #ifndef PDF_PDF_H_
 #define PDF_PDF_H_
 
+#include "ppapi/c/ppb.h"
 #include "ppapi/cpp/module.h"
 
 namespace chrome_pdf {
@@ -19,6 +20,94 @@
   virtual pp::Instance* CreateInstance(PP_Instance instance);
 };
 
+int PPP_InitializeModule(PP_Module module_id,
+                         PPB_GetInterface get_browser_interface);
+void PPP_ShutdownModule();
+const void* PPP_GetInterface(const char* interface_name);
+
+#if defined(OS_WIN)
+// |pdf_buffer| is the buffer that contains the entire PDF document to be
+//     rendered.
+// |buffer_size| is the size of |pdf_buffer| in bytes.
+// |page_number| is the 0-based index of the page to be rendered.
+// |dc| is the device context to render into.
+// |dpi| and |dpi_y| is the resolution. If the value is -1, the dpi from the DC
+//     will be used.
+// |bounds_origin_x|, |bounds_origin_y|, |bounds_width| and |bounds_height|
+//     specify a bounds rectangle within the DC in which to render the PDF
+//     page.
+// |fit_to_bounds| specifies whether the output should be shrunk to fit the
+//     supplied bounds if the page size is larger than the bounds in any
+//     dimension. If this is false, parts of the PDF page that lie outside
+//     the bounds will be clipped.
+// |stretch_to_bounds| specifies whether the output should be stretched to fit
+//     the supplied bounds if the page size is smaller than the bounds in any
+//     dimension.
+// If both |fit_to_bounds| and |stretch_to_bounds| are true, then
+//     |fit_to_bounds| is honored first.
+// |keep_aspect_ratio| If any scaling is to be done is true, this flag
+//     specifies whether the original aspect ratio of the page should be
+//     preserved while scaling.
+// |center_in_bounds| specifies whether the final image (after any scaling is
+//     done) should be centered within the given bounds.
+// |autorotate| specifies whether the final image should be rotated to match
+//     the output bound.
+// Returns false if the document or the page number are not valid.
+bool RenderPDFPageToDC(const void* pdf_buffer,
+                       int buffer_size,
+                       int page_number,
+                       HDC dc,
+                       int dpi,
+                       int bounds_origin_x,
+                       int bounds_origin_y,
+                       int bounds_width,
+                       int bounds_height,
+                       bool fit_to_bounds,
+                       bool stretch_to_bounds,
+                       bool keep_aspect_ratio,
+                       bool center_in_bounds,
+                       bool autorotate);
+#endif
+// |page_count| and |max_page_width| are optional and can be NULL.
+// Returns false if the document is not valid.
+bool GetPDFDocInfo(const void* pdf_buffer,
+                   int buffer_size, int* page_count,
+                   double* max_page_width);
+
+// Gets the dimensions of a specific page in a document.
+// |pdf_buffer| is the buffer that contains the entire PDF document to be
+//     rendered.
+// |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
+// |page_number| is the page number that the function will get the dimensions
+//     of.
+// |width| is the output for the width of the page in points.
+// |height| is the output for the height of the page in points.
+// Returns false if the document or the page number are not valid.
+bool GetPDFPageSizeByIndex(const void* pdf_buffer,
+                           int pdf_buffer_size, int page_number,
+                           double* width, double* height);
+
+// Renders PDF page into 4-byte per pixel BGRA color bitmap.
+// |pdf_buffer| is the buffer that contains the entire PDF document to be
+//     rendered.
+// |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
+// |page_number| is the 0-based index of the page to be rendered.
+// |bitmap_buffer| is the output buffer for bitmap.
+// |bitmap_width| is the width of the output bitmap.
+// |bitmap_height| is the height of the output bitmap.
+// |dpi| is the resolutions.
+// |autorotate| specifies whether the final image should be rotated to match
+//     the output bound.
+// Returns false if the document or the page number are not valid.
+bool RenderPDFPageToBitmap(const void* pdf_buffer,
+                           int pdf_buffer_size,
+                           int page_number,
+                           void* bitmap_buffer,
+                           int bitmap_width,
+                           int bitmap_height,
+                           int dpi,
+                           bool autorotate);
+
 }  // namespace chrome_pdf
 
 #endif  // PDF_PDF_H_
diff --git a/pdf/pdf.rc b/pdf/pdf.rc
deleted file mode 100644
index 50cb295..0000000
--- a/pdf/pdf.rc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904e4"
-        BEGIN
-            VALUE "FileDescription", "Chrome PDF Viewer"
-            VALUE "FileVersion", "1, 0, 0, 1"
-            VALUE "InternalName", "pdf"
-            VALUE "LegalCopyright", "Copyright (C) 2010"
-            VALUE "MIMEType", "application/pdf"
-            VALUE "FileExtents", "pdf"
-            VALUE "FileOpenName", "Acrobat Portable Document Format"
-            VALUE "OriginalFilename", "pdf.dll"
-            VALUE "ProductName", "Chrome PDF Viewer"
-            VALUE "ProductVersion", "1, 0, 0, 1"
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1252
-    END
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 81fa059..2990f40 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -9,6 +9,7 @@
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
diff --git a/ppapi/examples/video_decode/OWNERS b/ppapi/examples/video_decode/OWNERS
index ec1eaca9..7de84a4 100644
--- a/ppapi/examples/video_decode/OWNERS
+++ b/ppapi/examples/video_decode/OWNERS
@@ -1 +1 @@
-vrk@chromium.org
+bbudge@chromium.org
diff --git a/remoting/app_remoting_webapp.gyp b/remoting/app_remoting_webapp.gyp
index 1ceba7b..d9d8cda85 100644
--- a/remoting/app_remoting_webapp.gyp
+++ b/remoting/app_remoting_webapp.gyp
@@ -69,10 +69,12 @@
 
   'targets': [
     {
+      # Sample AppRemoting app.
       'target_name': 'ar_sample_app',
       'app_id': 'ljacajndfccfgnfohlgkdphmbnpkjflk',
       'app_name': 'App Remoting Client',
       'app_description': 'App Remoting client',
+      'app_capabilities': ['GOOGLE_DRIVE'],
     },
   ],  # end of targets
 }
diff --git a/remoting/app_remoting_webapp_build.gypi b/remoting/app_remoting_webapp_build.gypi
index 1c3e68c..d5da9eb 100644
--- a/remoting/app_remoting_webapp_build.gypi
+++ b/remoting/app_remoting_webapp_build.gypi
@@ -122,6 +122,8 @@
           '<(remoting_app_name)',
           '--app_description',
           '<(remoting_app_description)',
+          '--app_capabilities',
+          '>@(_app_capabilities)',
           '--service_environment',
           '<@(ar_service_environment)',
         ],
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 1027fc9f..0f40d356 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -59,6 +59,7 @@
     'remoting_client.gypi',
     'remoting_host.gypi',
     'remoting_host_srcs.gypi',
+    'remoting_key_tester.gypi',
     'remoting_locales.gypi',
     'remoting_srcs.gypi',
     'remoting_test.gypi',
diff --git a/remoting/remoting_key_tester.gypi b/remoting/remoting_key_tester.gypi
new file mode 100644
index 0000000..d1aab86
--- /dev/null
+++ b/remoting/remoting_key_tester.gypi
@@ -0,0 +1,100 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../build/common_untrusted.gypi',
+  ],
+
+  'variables': {
+    'remoting_key_tester_js_files': [
+        'tools/javascript_key_tester/background.js',
+        'tools/javascript_key_tester/chord_tracker.js',
+        'tools/javascript_key_tester/keyboard_map.js',
+        'tools/javascript_key_tester/main.js',
+     ],
+  },
+
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'remoting_key_tester',
+          'type': 'none',
+          'dependencies': [
+            'remoting_key_tester_pexe',
+            'remoting_key_tester_jscompile',
+          ],
+          'copies': [
+            {
+              'destination': '<(PRODUCT_DIR)/remoting/key_tester',
+              'files': [
+                '<@(remoting_key_tester_js_files)',
+                'tools/javascript_key_tester/main.css',
+                'tools/javascript_key_tester/main.html',
+                'tools/javascript_key_tester/manifest.json',
+                'tools/javascript_key_tester/pnacl/remoting_key_tester.nmf',
+                '<(PRODUCT_DIR)/remoting_key_tester_newlib.pexe',
+              ],
+            }
+          ],
+        },  # end of target 'remoting_key_tester'
+
+        {
+          'target_name': 'remoting_key_tester_jscompile',
+          'type': 'none',
+          'conditions': [
+            # TODO(lukasza): Enable when remoting_key_tester_jscompile is clean.
+            # ['run_jscompile != 0', {
+            ['0 != 0', {
+              'variables': {
+                'success_stamp': '<(PRODUCT_DIR)/<(_target_name).stamp',
+              },
+              'actions': [
+                {
+                  'action_name': 'jscompile remoting_key_tester',
+                  'inputs': [
+                    '<@(remoting_key_tester_js_files)',
+                  ],
+                  'outputs': [
+                    '<(success_stamp)',
+                  ],
+                  'action': [
+                    'python', '../third_party/closure_compiler/checker.py',
+                    '--strict',
+                    '--no-single-file',
+                    '--success-stamp', '<(success_stamp)',
+                    '<@(remoting_key_tester_js_files)',
+                  ],
+                },
+              ],  # actions
+            }],
+          ],
+        },  # end of target 'remoting_key_tester_jscompile'
+
+        {
+          'target_name': 'remoting_key_tester_pexe',
+          'type': 'none',
+          'sources': [
+            'tools/javascript_key_tester/pnacl/remoting_key_tester.cc',
+          ],
+          'variables': {
+            'nexe_target': 'remoting_key_tester',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_pnacl_newlib': 1,
+            'extra_deps_pnacl_newlib': [
+              '>(tc_lib_dir_pnacl_newlib)/libppapi.a',
+              '>(tc_lib_dir_pnacl_newlib)/libppapi_cpp.a',
+            ],
+          },
+          'link_flags': [
+            '-lppapi_stub',
+            '-lppapi_cpp',
+          ],
+        },  # end of target 'remoting_key_tester_pexe'
+      ],
+    }]
+  ],
+}
diff --git a/remoting/remoting_nacl.gyp b/remoting/remoting_nacl.gyp
index c541296..0b66b6b 100644
--- a/remoting/remoting_nacl.gyp
+++ b/remoting/remoting_nacl.gyp
@@ -4,7 +4,7 @@
 
 {
   'includes': [
-    '../native_client/build/untrusted.gypi',
+    '../build/common_untrusted.gypi',
     'remoting_srcs.gypi',
   ],
 
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi
index da059785..6f1bf585 100644
--- a/remoting/remoting_webapp_files.gypi
+++ b/remoting/remoting_webapp_files.gypi
@@ -57,6 +57,7 @@
     ],
     # Remoting core JavaScript files.
     'remoting_webapp_js_core_files': [
+      'webapp/base/js/app_capabilities.js',
       'webapp/base/js/application.js',
       'webapp/base/js/base.js',
       'webapp/base/js/ipc.js',
@@ -237,6 +238,7 @@
       'webapp/crd/js/background.js',
       'webapp/crd/js/client_session.js',
       'webapp/crd/js/error.js',
+      'webapp/crd/js/hangout_consent_dialog.js',
       'webapp/crd/js/host_installer.js',
       'webapp/crd/js/host_session.js',
       'webapp/crd/js/it2me_helpee_channel.js',
@@ -246,6 +248,7 @@
       'webapp/crd/js/l10n.js',
       'webapp/crd/js/oauth2.js',
       'webapp/crd/js/oauth2_api.js',
+      'webapp/crd/js/oauth2_api_impl.js',
       'webapp/crd/js/plugin_settings.js',
       'webapp/crd/js/typecheck.js',
       'webapp/crd/js/xhr.js',
@@ -265,6 +268,8 @@
       '<@(remoting_webapp_background_js_files)',
       # JS files for message_window.html
       'webapp/base/js/message_window.js',
+      # JS files for dialog_hangout_consent.html
+      'webapp/crd/js/hangout_consent_dialog_main.js',
       # JS files for wcs_sandbox.html.
       # Use r_w_js_wcs_sandbox_files instead of r_w_wcs_sandbox_html_js_files
       # so that we don't double include error.js and plugin_settings.js.
@@ -301,13 +306,15 @@
       'resources/reload.webp',
       'resources/tick.webp',
       'webapp/base/html/connection_stats.css',
-      'webapp/base/html/message_window.html',
       'webapp/base/html/main.css',
+      'webapp/base/html/message_window.html',
       'webapp/base/html/message_window.css',
       'webapp/base/resources/open_sans.css',
       'webapp/base/resources/open_sans.woff',
       'webapp/base/resources/spinner.gif',
       'webapp/crd/html/butter_bar.css',
+      'webapp/crd/html/dialog_hangout_consent.html',
+      'webapp/crd/html/dialog_hangout_consent.css',
       'webapp/crd/html/toolbar.css',
       'webapp/crd/html/menu_button.css',
       'webapp/crd/html/window_frame.css',
diff --git a/remoting/tools/javascript_key_tester/DEPS b/remoting/tools/javascript_key_tester/DEPS
new file mode 100644
index 0000000..d5f5a0bf
--- /dev/null
+++ b/remoting/tools/javascript_key_tester/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+ppapi"
+]
diff --git a/remoting/tools/javascript_key_tester/README b/remoting/tools/javascript_key_tester/README
new file mode 100644
index 0000000..0b0e492
--- /dev/null
+++ b/remoting/tools/javascript_key_tester/README
@@ -0,0 +1,9 @@
+The key tester is a Chrome app that dumps:
+- PNaCl KeyboardInputEvent events
+- JavaScript keydown/keyup events
+
+To use the key tester:
+1. Build: ninja -C out/Debug remoting_key_tester
+2. In Chrome navigate to: chrome://extensions
+3. Use "Load unpacked extension" to load the key tester
+
diff --git a/remoting/tools/javascript_key_tester/chord_tracker.js b/remoting/tools/javascript_key_tester/chord_tracker.js
index ee2a327..a7cded1 100644
--- a/remoting/tools/javascript_key_tester/chord_tracker.js
+++ b/remoting/tools/javascript_key_tester/chord_tracker.js
@@ -14,26 +14,42 @@
 };
 
 /**
- * @param {Event} event The keyup or keydown event.
+ * @param {number} keyCode
+ * @param {string} title
+ * @return {void}
  */
-ChordTracker.prototype.addKeyEvent = function(event) {
-  this.begin_();
-  var span = document.createElement('span');
-  span.title = this.makeTitle_(event);
-  if (event.type == 'keydown') {
-    span.classList.add('key-down');
-    this.pressedKeys_[event.keyCode] = span;
-  } else {
-    span.classList.add('key-up');
-    delete this.pressedKeys_[event.keyCode];
-  }
-  span.innerText = this.keyName_(event.keyCode);
-  this.currentDiv_.appendChild(span);
+ChordTracker.prototype.addKeyUpEvent = function(keyCode, title) {
+  var text = this.keyName_(keyCode);
+  var span = this.addSpanElement_('key-up', text, title);
+  delete this.pressedKeys_[keyCode];
   if (!this.keysPressed_()) {
     this.end_();
   }
 };
 
+/**
+ * @param {number} keyCode
+ * @param {string} title
+ * @return {void}
+ */
+ChordTracker.prototype.addKeyDownEvent = function(keyCode, title) {
+  var text = this.keyName_(keyCode);
+  var span = this.addSpanElement_('key-down', text, title);
+  this.pressedKeys_[keyCode] = span;
+};
+
+/**
+ * @param {string} characterText
+ * @param {string} title
+ * @return {void}
+ */
+ChordTracker.prototype.addCharEvent = function(characterText, title) {
+  this.addSpanElement_('char-event', characterText, title);
+};
+
+/**
+ * @return {void}
+ */
 ChordTracker.prototype.releaseAllKeys = function() {
   this.end_();
   for (var i in this.pressedKeys_) {
@@ -44,6 +60,22 @@
 
 /**
  * @private
+ * @param {string} className
+ * @param {string} text
+ * @param {string} title
+ */
+ChordTracker.prototype.addSpanElement_ = function(className, text, title) {
+  this.begin_();
+  var span = document.createElement('span');
+  span.classList.add(className);
+  span.innerText = text;
+  span.title = title;
+  this.currentDiv_.appendChild(span);
+  return span;
+}
+
+/**
+ * @private
  */
 ChordTracker.prototype.begin_ = function() {
   if (this.currentDiv_) {
@@ -93,18 +125,3 @@
   return result;
 };
 
-/**
- * @param {Event} event The keyup or keydown event.
- * @private
- */
-ChordTracker.prototype.makeTitle_ = function(event) {
-  return 'type: ' + event.type + '\n' +
-         'alt: ' + event.altKey + '\n' +
-         'shift: ' + event.shiftKey + '\n' +
-         'control: ' + event.controlKey + '\n' +
-         'meta: ' + event.metaKey + '\n' +
-         'charCode: ' + event.charCode + '\n' +
-         'keyCode: ' + event.keyCode + '\n' +
-         'keyIdentifier: ' + event.keyIdentifier + '\n' +
-         'repeat: ' + event.repeat + '\n';
-};
diff --git a/remoting/tools/javascript_key_tester/keyboard_map.js b/remoting/tools/javascript_key_tester/keyboard_map.js
index 869bf54..8fd268a 100644
--- a/remoting/tools/javascript_key_tester/keyboard_map.js
+++ b/remoting/tools/javascript_key_tester/keyboard_map.js
@@ -3,6 +3,7 @@
  * found in the LICENSE file.
  */
 
+/** @type {Array.<string>} */
 var keyboardMap = [
   '',
   '',
diff --git a/remoting/tools/javascript_key_tester/main.css b/remoting/tools/javascript_key_tester/main.css
index 725f2ca0..8010f61 100644
--- a/remoting/tools/javascript_key_tester/main.css
+++ b/remoting/tools/javascript_key_tester/main.css
@@ -12,6 +12,30 @@
   height: 100%;
 }
 
+#pnacl-plugin {
+  background-color: gray;
+  border: 1px solid
+}
+
+#pnacl-plugin:focus {
+  background-color: yellow;
+}
+
+.summary-log-container {
+  width: 50%;
+  height: 50vh;
+  overflow-y: auto;
+  float: left;
+}
+
+.text-log-container {
+  width: 100%;
+  max-height: 25vh;
+  overflow-y: auto;
+  float: left;
+}
+
+.char-event,
 .key-down,
 .key-up {
   border-radius: 4px;
@@ -20,6 +44,14 @@
   margin-right: 2px;
 }
 
+.char-event {
+  background-color: yellow;
+}
+
+.char-event::before {
+  content: "char:";
+}
+
 .key-up {
   background-color: #DFD;
 }
diff --git a/remoting/tools/javascript_key_tester/main.html b/remoting/tools/javascript_key_tester/main.html
index 141b03b..791c024 100644
--- a/remoting/tools/javascript_key_tester/main.html
+++ b/remoting/tools/javascript_key_tester/main.html
@@ -15,8 +15,30 @@
   </head>
   <body>
     <h2>Chrome AppsV2  Key Event Tester</h2>
-    <button id="clear-log">Clear log</button>
-    <div id="key-log">
+    <div id="pnacl-listener">
+      PNaCl focus box:
+      <embed id="pnacl-plugin" width=100 height=12
+             src="remoting_key_tester.nmf" type="application/x-pnacl" />
+      (click inside to get focus, yellow background means it has focus).
+    </div>
+    <button id="clear-log">Clear logs</button>
+    <hr/>
+    <div class="logs">
+      <div class="summary-log-container">
+        Summary of JavaScript logs:
+        <div id="javascript-log">
+        </div>
+      </div>
+      <div class="summary-log-container">
+        Summary of PNaCl logs:
+        <div id="pnacl-log">
+        </div>
+      </div>
+      <div class="text-log-container">
+        Text log of JSON-ified events:
+        <div id="text-log">
+        </div>
+      </div>
     </div>
   </body>
 </html>
diff --git a/remoting/tools/javascript_key_tester/main.js b/remoting/tools/javascript_key_tester/main.js
index e777b48..e37e426 100644
--- a/remoting/tools/javascript_key_tester/main.js
+++ b/remoting/tools/javascript_key_tester/main.js
@@ -3,17 +3,142 @@
  * found in the LICENSE file.
  */
 
+/**
+ * @param {string} eventName
+ * @param {number=} opt_space
+ * @return {string}
+ */
+function jsonifyJavascriptKeyEvent(event, eventName, opt_space) {
+  return "JavaScript '" + eventName + "' event = " + JSON.stringify(
+      event,
+      ['type', 'alt', 'shift', 'control', 'meta', 'charCode', 'keyCode',
+          'keyIdentifier', 'repeat'],
+      opt_space);
+};
+
+/**
+ * @param {ChordTracker} jsChordTracker
+ * @param {Event} event
+ * @return {void}
+ */
+function handleJavascriptKeyDownEvent(jsChordTracker, event) {
+  appendToTextLog(jsonifyJavascriptKeyEvent(event, 'keydown', undefined));
+  jsChordTracker.addKeyDownEvent(
+      event.keyCode, jsonifyJavascriptKeyEvent(event, 'keydown', 2));
+}
+
+/**
+ * @param {ChordTracker} jsChordTracker
+ * @param {Event} event
+ * @return {void}
+ */
+function handleJavascriptKeyUpEvent(jsChordTracker, event) {
+  appendToTextLog(jsonifyJavascriptKeyEvent(event, 'keyup', undefined));
+  jsChordTracker.addKeyUpEvent(
+      event.keyCode, jsonifyJavascriptKeyEvent(event, 'keyup', 2));
+}
+
+/** @constructor */
+var PNaClEvent = function() {
+  /** @type {string} */
+  this.type = "";
+  /** @type {number} */
+  this.modifiers = 0;
+  /** @type {number} */
+  this.keyCode = 0;
+  /** @type {string|undefined} */
+  this.characterText = undefined;
+  /** @type {string} */
+  this.code = "";
+};
+
+/**
+ * @param {PNaClEvent} event
+ * @param {number|undefined} space
+ * @return {string}
+ */
+function jsonifyPnaclKeyboardInputEvent(event, space) {
+  return "PNaCl KeyboardInputEvent = " + JSON.stringify(
+      event,
+      ['type', 'modifiers', 'keyCode', 'characterText', 'code'],
+      space);
+};
+
+/**
+ * @param {ChordTracker} pnaclChordTracker
+ * @param {Event} event
+ * @return {void}
+ */
+function handlePNaclMessage(pnaclChordTracker, event) {
+  var pnaclEvent = /** @type {PNaClEvent} */ (event.data);
+
+  appendToTextLog(jsonifyPnaclKeyboardInputEvent(pnaclEvent, undefined));
+  var title = jsonifyPnaclKeyboardInputEvent(pnaclEvent, 2);
+  if (pnaclEvent.type == "KEYDOWN") {
+    pnaclChordTracker.addKeyDownEvent(pnaclEvent.keyCode, title);
+  }
+  if (pnaclEvent.type == "KEYUP") {
+    pnaclChordTracker.addKeyUpEvent(pnaclEvent.keyCode, title);
+  }
+  if (pnaclEvent.type == "CHAR") {
+    pnaclChordTracker.addCharEvent(pnaclEvent.characterText, title);
+  }
+}
+
+/**
+ * @param {string} str
+ * @return {void}
+ */
+function appendToTextLog(str) {
+  var textLog = document.getElementById('text-log');
+  var div = document.createElement('div');
+  div.innerText = str;
+  textLog.appendChild(div);
+}
+
 function onLoad() {
-  var parentDiv = document.getElementById('key-log');
-  var chordTracker = new ChordTracker(parentDiv);
+  // Start listening to Javascript keyup/keydown events.
+  var jsLog = document.getElementById('javascript-log');
+  var jsChordTracker = new ChordTracker(jsLog);
   document.body.addEventListener(
-      'keydown', chordTracker.addKeyEvent.bind(chordTracker), false);
+      'keydown',
+      function (event) {
+        handleJavascriptKeyDownEvent(jsChordTracker, event);
+      },
+      false);
   document.body.addEventListener(
-      'keyup', chordTracker.addKeyEvent.bind(chordTracker), false);
+      'keyup',
+      function (event) {
+        handleJavascriptKeyUpEvent(jsChordTracker, event);
+      },
+      false);
+
+  // Start listening to PNaCl keyboard input events.
+  var pnaclLog = document.getElementById('pnacl-log');
+  var pnaclChordTracker = new ChordTracker(pnaclLog);
+  document.getElementById('pnacl-listener').addEventListener(
+       'message',
+       function (message) {
+         handlePNaclMessage(pnaclChordTracker, message);
+       },
+       true);
+
+  // Start listening to generic, source-agnostic events.
   window.addEventListener(
-      'blur', chordTracker.releaseAllKeys.bind(chordTracker), false);
+      'blur',
+      function () {
+        jsChordTracker.releaseAllKeys();
+        pnaclChordTracker.releaseAllKeys();
+      },
+      false);
   document.getElementById('clear-log').addEventListener(
-      'click', function() { parentDiv.innerText = ''; }, false);
+      'click',
+      function() {
+        jsLog.innerText = '';
+        pnaclLog.innerText = '';
+        document.getElementById('text-log').innerText = '';
+      },
+      false);
 }
 
 window.addEventListener('load', onLoad, false);
diff --git a/remoting/tools/javascript_key_tester/pnacl/remoting_key_tester.cc b/remoting/tools/javascript_key_tester/pnacl/remoting_key_tester.cc
new file mode 100644
index 0000000..408725c5
--- /dev/null
+++ b/remoting/tools/javascript_key_tester/pnacl/remoting_key_tester.cc
@@ -0,0 +1,114 @@
+// 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 <sstream>
+
+#include "ppapi/cpp/input_event.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi/cpp/var_dictionary.h"
+
+namespace remoting {
+
+class KeyTesterInstance : public pp::Instance {
+ public:
+  explicit KeyTesterInstance(PP_Instance instance) : pp::Instance(instance) {
+    RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
+  }
+
+  virtual ~KeyTesterInstance() {}
+
+  virtual bool HandleInputEvent(const pp::InputEvent& event) {
+    switch (event.GetType()) {
+      case PP_INPUTEVENT_TYPE_KEYDOWN:
+      case PP_INPUTEVENT_TYPE_KEYUP:
+      case PP_INPUTEVENT_TYPE_CHAR: {
+        HandleKeyboardEvent(pp::KeyboardInputEvent(event));
+        break;
+      }
+      default:
+        break;
+    }
+    return true;
+  }
+
+ private:
+  void HandleKeyboardEvent(const pp::KeyboardInputEvent& event) {
+    pp::VarDictionary out;
+    out.Set("type", EventTypeToString(event.GetType()));
+    out.Set("modifiers", (double)event.GetModifiers());
+    out.Set("keyCode", (double)event.GetKeyCode());
+    out.Set("characterText", event.GetCharacterText());
+    out.Set("code", event.GetCode());
+    PostMessage(out);
+  }
+
+  std::string EventTypeToString(PP_InputEvent_Type t) {
+    switch (t) {
+      case PP_INPUTEVENT_TYPE_UNDEFINED:
+        return "UNDEFINED";
+      case PP_INPUTEVENT_TYPE_MOUSEDOWN:
+        return "MOUSEDOWN";
+      case PP_INPUTEVENT_TYPE_MOUSEUP:
+        return "MOUSEUP";
+      case PP_INPUTEVENT_TYPE_MOUSEMOVE:
+        return "MOUSEMOVE";
+      case PP_INPUTEVENT_TYPE_MOUSEENTER:
+        return "MOUSEENTER";
+      case PP_INPUTEVENT_TYPE_MOUSELEAVE:
+        return "MOUSELEAVE";
+      case PP_INPUTEVENT_TYPE_WHEEL:
+        return "WHEEL";
+      case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
+        return "RAWKEYDOWN";
+      case PP_INPUTEVENT_TYPE_KEYDOWN:
+        return "KEYDOWN";
+      case PP_INPUTEVENT_TYPE_KEYUP:
+        return "KEYUP";
+      case PP_INPUTEVENT_TYPE_CHAR:
+        return "CHAR";
+      case PP_INPUTEVENT_TYPE_CONTEXTMENU:
+        return "CONTEXTMENU";
+      case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
+        return "IME_COMPOSITION_START";
+      case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
+        return "IME_COMPOSITION_UPDATE";
+      case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
+        return "IME_COMPOSITION_END";
+      case PP_INPUTEVENT_TYPE_IME_TEXT:
+        return "IME_TEXT";
+      case PP_INPUTEVENT_TYPE_TOUCHSTART:
+        return "TOUCHSTART";
+      case PP_INPUTEVENT_TYPE_TOUCHMOVE:
+        return "TOUCHMOVE";
+      case PP_INPUTEVENT_TYPE_TOUCHEND:
+        return "TOUCHEND";
+      case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
+        return "TOUCHCANCEL";
+      default:
+        return "[UNRECOGNIZED]";
+    }
+  }
+};
+
+class KeyTesterModule : public pp::Module {
+ public:
+  KeyTesterModule() : pp::Module() {}
+  virtual ~KeyTesterModule() {}
+
+  virtual pp::Instance* CreateInstance(PP_Instance instance) {
+    return new KeyTesterInstance(instance);
+  }
+};
+
+}  // namespace remoting
+
+namespace pp {
+
+Module* CreateModule() {
+  return new remoting::KeyTesterModule();
+}
+
+}  // namespace pp
diff --git a/remoting/tools/javascript_key_tester/pnacl/remoting_key_tester.nmf b/remoting/tools/javascript_key_tester/pnacl/remoting_key_tester.nmf
new file mode 100644
index 0000000..5f49117
--- /dev/null
+++ b/remoting/tools/javascript_key_tester/pnacl/remoting_key_tester.nmf
@@ -0,0 +1,9 @@
+{
+  "program": {
+    "portable": {
+      "pnacl-translate": {
+        "url": "remoting_key_tester_newlib.pexe"
+      }
+    }
+  }
+}
diff --git a/remoting/webapp/app_remoting/js/app_remoting.js b/remoting/webapp/app_remoting/js/app_remoting.js
index f07f847..8e8bb62 100644
--- a/remoting/webapp/app_remoting/js/app_remoting.js
+++ b/remoting/webapp/app_remoting/js/app_remoting.js
@@ -214,19 +214,6 @@
 };
 
 /**
- * @return {Array.<string>} A list of |ClientSession.Capability|s required
- *     by this application.
- */
-remoting.AppRemoting.prototype.getRequiredCapabilities = function() {
-  return [
-    remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION,
-    remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS,
-    remoting.ClientSession.Capability.VIDEO_RECORDER,
-    remoting.ClientSession.Capability.GOOGLE_DRIVE
-  ];
-};
-
-/**
  * Called when a new session has been connected.
  *
  * @param {remoting.ClientSession} clientSession
diff --git a/remoting/webapp/app_remoting/js/ar_main.js b/remoting/webapp/app_remoting/js/ar_main.js
index b15cdff..269b5ff9 100644
--- a/remoting/webapp/app_remoting/js/ar_main.js
+++ b/remoting/webapp/app_remoting/js/ar_main.js
@@ -11,7 +11,7 @@
  * Entry point ('load' handler) for App Remoting webapp.
  */
 remoting.startAppRemoting = function() {
-  remoting.app = new remoting.Application();
+  remoting.app = new remoting.Application(remoting.app_capabilities());
   var app_remoting = new remoting.AppRemoting(remoting.app);
   remoting.app.start();
 };
diff --git a/remoting/webapp/app_remoting/manifest_common.json.jinja2 b/remoting/webapp/app_remoting/manifest_common.json.jinja2
index 6001a10a..95d6908 100644
--- a/remoting/webapp/app_remoting/manifest_common.json.jinja2
+++ b/remoting/webapp/app_remoting/manifest_common.json.jinja2
@@ -49,7 +49,7 @@
   "oauth2": {
     "client_id": "{{ REMOTING_IDENTITY_API_CLIENT_ID }}",
     "scopes": [
-      "https://www.googleapis.com/auth/appremoting.runapplication https://www.googleapis.com/auth/googletalk https://www.googleapis.com/auth/userinfo#email https://www.googleapis.com/auth/userinfo.profile https://docs.google.com/feeds/ https://www.googleapis.com/auth/drive"
+      "https://www.googleapis.com/auth/appremoting.runapplication https://www.googleapis.com/auth/googletalk https://www.googleapis.com/auth/userinfo#email https://www.googleapis.com/auth/userinfo.profile {{ OAUTH_GDRIVE_SCOPE }}"
     ]
   },
   "sandbox": {
diff --git a/remoting/webapp/base/js/app_capabilities.js b/remoting/webapp/base/js/app_capabilities.js
new file mode 100644
index 0000000..655e913
--- /dev/null
+++ b/remoting/webapp/base/js/app_capabilities.js
@@ -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.
+
+'use strict';
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+/**
+ * Note that this needs to be a function because it gets expanded at
+ * compile-time into remoting.ClientSession.Capability enums and these
+ * are not guaranteed to be present yet when this file is loaded.
+ * @return {Array.<remoting.ClientSession.Capability>}
+ */
+remoting.app_capabilities = function() {
+  return ['APPLICATION_CAPABILITIES'];
+}
diff --git a/remoting/webapp/base/js/application.js b/remoting/webapp/base/js/application.js
index 7390d8c..d0810be7c 100644
--- a/remoting/webapp/base/js/application.js
+++ b/remoting/webapp/base/js/application.js
@@ -13,9 +13,10 @@
 var remoting = remoting || {};
 
 /**
+ * @param {Array.<string>} app_capabilities Array of application capabilities.
  * @constructor
  */
-remoting.Application = function() {
+remoting.Application = function(app_capabilities) {
   /**
    * @type {remoting.Application.Delegate}
    * @private
@@ -23,6 +24,12 @@
   this.delegate_ = null;
 
   /**
+   * @type {Array.<string>}
+   * @private
+   */
+  this.app_capabilities_ = app_capabilities;
+
+  /**
    * @type {remoting.SessionConnector}
    * @private
    */
@@ -38,6 +45,30 @@
 };
 
 /**
+ * @return {Array.<string>} A list of |ClientSession.Capability|s required
+ *     by this application.
+ */
+remoting.Application.prototype.getRequiredCapabilities_ = function() {
+  var capabilities = [
+    remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION,
+    remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS,
+    remoting.ClientSession.Capability.VIDEO_RECORDER
+  ];
+  // Append the app-specific capabilities.
+  capabilities.push.apply(capabilities, this.app_capabilities_);
+  return capabilities;
+};
+
+/**
+ * @param {remoting.ClientSession.Capability} capability
+ * @return {boolean}
+ */
+remoting.Application.prototype.hasCapability = function(capability) {
+  var capabilities = remoting.app.getRequiredCapabilities_();
+  return capabilities.indexOf(capability) != -1;
+};
+
+/**
  * Initialize the application and register all event handlers. After this
  * is called, the app is running and waiting for user events.
  *
@@ -153,7 +184,7 @@
         this.onError.bind(this),
         this.onExtensionMessage.bind(this),
         this.onConnectionFailed.bind(this),
-        this.delegate_.getRequiredCapabilities(),
+        this.getRequiredCapabilities_(),
         this.delegate_.getDefaultRemapKeys());
   }
   return this.session_connector_;
@@ -180,12 +211,6 @@
 remoting.Application.Delegate.prototype.getDefaultRemapKeys = function() {};
 
 /**
- * @return {Array.<string>} A list of |ClientSession.Capability|s required
- *     by this application.
- */
-remoting.Application.Delegate.prototype.getRequiredCapabilities = function() {};
-
-/**
  * Called when a new session has been connected.
  *
  * @param {remoting.ClientSession} clientSession
diff --git a/remoting/webapp/base/js/base.js b/remoting/webapp/base/js/base.js
index 30f13a0aa..e9454553 100644
--- a/remoting/webapp/base/js/base.js
+++ b/remoting/webapp/base/js/base.js
@@ -179,6 +179,20 @@
   return url + '?' + queryParameters.join('&');
 };
 
+
+/**
+ * @return {Object.<string, string>} The URL parameters.
+ */
+base.getUrlParameters = function() {
+  var result = {};
+  var parts = window.location.search.substring(1).split('&');
+  for (var i = 0; i < parts.length; i++) {
+    var pair = parts[i].split('=');
+    result[pair[0]] = decodeURIComponent(pair[1]);
+  }
+  return result;
+};
+
 /**
  * Convert special characters (e.g. &, < and >) to HTML entities.
  *
@@ -582,3 +596,16 @@
     return undefined;
   }
 };
+
+/**
+ * Size the current window to fit its content vertically.
+ */
+base.resizeWindowToContent = function() {
+  var appWindow = chrome.app.window.current();
+  var outerBounds = appWindow.outerBounds;
+  var borderY = outerBounds.height - appWindow.innerBounds.height;
+  appWindow.resizeTo(outerBounds.width, document.body.clientHeight + borderY);
+  // Sometimes, resizing the window causes its position to be reset to (0, 0),
+  // so restore it explicitly.
+  appWindow.moveTo(outerBounds.left, outerBounds.top);
+};
diff --git a/remoting/webapp/base/js/ipc.js b/remoting/webapp/base/js/ipc.js
index 07d175c..122ea5f 100644
--- a/remoting/webapp/base/js/ipc.js
+++ b/remoting/webapp/base/js/ipc.js
@@ -89,7 +89,7 @@
 
 /**
  * @param {string} methodName
- * @param {function(?)} handler The handler can be invoked by calling
+ * @param {function(...?)} handler The handler can be invoked by calling
  *   base.Ipc.invoke(|methodName|, arg1, arg2, ...)
  * Async handlers that return promises are currently not supported.
  * @return {boolean} Whether the handler is successfully registered.
diff --git a/remoting/webapp/base/js/message_window.js b/remoting/webapp/base/js/message_window.js
index d80c2053..cc7b82e7 100644
--- a/remoting/webapp/base/js/message_window.js
+++ b/remoting/webapp/base/js/message_window.js
@@ -45,20 +45,6 @@
 };
 
 /**
- * Size the window to its content vertically.
- * @private
- */
-MessageWindowImpl.prototype.updateSize_ = function() {
-  var outerBounds = chrome.app.window.current().outerBounds;
-  var innerBounds = chrome.app.window.current().innerBounds;
-  var borderY = outerBounds.height - innerBounds.height;
-  window.resizeTo(outerBounds.width, document.body.clientHeight + borderY);
-  // Sometimes, resizing the window causes its position to be reset to (0, 0),
-  // so restore it explicitly.
-  window.moveTo(outerBounds.left, outerBounds.top);
-};
-
-/**
  * Initializes the button with the label and the click handler.
  * Hides the button if the label is null or undefined.
  *
@@ -145,7 +131,7 @@
       chrome.app.window.current().onClosed.addListener(
           this.sendReply_.bind(this, event.source, messageId, 0));
 
-      this.updateSize_();
+      base.resizeWindowToContent();
       chrome.app.window.current().show();
       break;
 
@@ -159,7 +145,7 @@
       var messageDiv = document.getElementById('message');
       messageDiv.innerText = message;
 
-      this.updateSize_();
+      base.resizeWindowToContent();
       break;
 
     default:
diff --git a/remoting/webapp/build-webapp.py b/remoting/webapp/build-webapp.py
index 833e1f3ea..9868b6c 100755
--- a/remoting/webapp/build-webapp.py
+++ b/remoting/webapp/build-webapp.py
@@ -75,10 +75,9 @@
   rendered = template.render(context)
   io.open(output_file, 'w', encoding='utf-8').write(rendered)
 
-
 def buildWebApp(buildtype, version, destination, zip_path,
                 manifest_template, webapp_type, app_id, app_name,
-                app_description, files, locales, jinja_paths,
+                app_description, app_capabilities, files, locales, jinja_paths,
                 service_environment):
   """Does the main work of building the webapp directory and zipfile.
 
@@ -95,6 +94,8 @@
              test API server.
     app_name: A string with the name of the application.
     app_description: A string with the description of the application.
+    app_capabilities: A set of strings naming the capabilities that should be
+                      enabled for this application.
     files: An array of strings listing the paths for resources to include
            in this webapp.
     locales: An array of strings listing locales, which are copied, along
@@ -316,6 +317,12 @@
   replaceString(destination, 'API_CLIENT_ID', apiClientId)
   replaceString(destination, 'API_CLIENT_SECRET', apiClientSecret)
 
+  # Write the application capabilities.
+  appCapabilities = ','.join(
+      ['remoting.ClientSession.Capability.' + x for x in app_capabilities])
+  findAndReplace(os.path.join(destination, 'app_capabilities.js'),
+                 "'APPLICATION_CAPABILITIES'", appCapabilities)
+
   # Use a consistent extension id for dev builds.
   # AppRemoting builds always use the dev app id - the correct app id gets
   # written into the manifest later.
@@ -342,7 +349,11 @@
         'GOOGLE_API_HOSTS': googleApiHosts,
         'APP_NAME': app_name,
         'APP_DESCRIPTION': app_description,
+        'OAUTH_GDRIVE_SCOPE': '',
     }
+    if 'GOOGLE_DRIVE' in app_capabilities:
+      context['OAUTH_GDRIVE_SCOPE'] = ('https://docs.google.com/feeds/ '
+                                       'https://www.googleapis.com/auth/drive')
     processJinjaTemplate(manifest_template,
                          jinja_paths,
                          os.path.join(destination, 'manifest.json'),
@@ -361,6 +372,7 @@
            '<webapp_type> <other files...> '
            '--app_name <name> '
            '--app_description <description> '
+           '--app_capabilities <capabilities...> '
            '[--appid <appid>] '
            '[--locales <locales...>] '
            '[--jinja_paths <paths...>] '
@@ -374,6 +386,7 @@
   app_id = None
   app_name = None
   app_description = None
+  app_capabilities = set([])
   service_environment = ''
 
   for arg in sys.argv[7:]:
@@ -382,6 +395,7 @@
                '--appid',
                '--app_name',
                '--app_description',
+               '--app_capabilities',
                '--service_environment']:
       arg_type = arg
     elif arg_type == '--locales':
@@ -397,6 +411,8 @@
     elif arg_type == '--app_description':
       app_description = arg
       arg_type = ''
+    elif arg_type == '--app_capabilities':
+      app_capabilities.add(arg)
     elif arg_type == '--service_environment':
       service_environment = arg
       arg_type = ''
@@ -405,8 +421,8 @@
 
   return buildWebApp(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4],
                      sys.argv[5], sys.argv[6], app_id, app_name,
-                     app_description, files, locales, jinja_paths,
-                     service_environment)
+                     app_description, app_capabilities, files, locales,
+                     jinja_paths, service_environment)
 
 
 if __name__ == '__main__':
diff --git a/remoting/webapp/crd/html/dialog_hangout_consent.css b/remoting/webapp/crd/html/dialog_hangout_consent.css
new file mode 100644
index 0000000..7bd4378f
--- /dev/null
+++ b/remoting/webapp/crd/html/dialog_hangout_consent.css
@@ -0,0 +1,103 @@
+/* Copyright 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+html, div, span, body, ul, li {
+  border: 0;
+  margin: 0;
+  padding: 0;
+  font-family: "Arial", "Helvetica", sans-serif;
+  font-weight: normal;
+  /* Allows the user to move the window by dragging its content. */
+  -webkit-app-region: drag;
+}
+
+.header {
+  height: 46px;
+  background: #1c91c0;
+  padding: 15px;
+}
+
+.header .title {
+  color: white;
+  float: left;
+  font-size: 24px;
+  line-height: 46px;
+  padding-left: 15px;
+}
+
+.header .logo {
+  float: left;
+  height: 46px;
+  width: 46px;
+  background: url('chromoting48.webp');
+}
+
+.content {
+  text-align: center;
+  margin: auto;
+  width: 70%;
+}
+
+.content .message {
+  padding: 30px;
+  font-size: 20px;
+}
+
+.content ul {
+  list-style: none;
+  border-width: 0px 0px 1px 0px;
+  border-style: solid;
+  border-color: #f0f0f0;
+}
+
+.content li {
+  border-width: 1px 0px 0px 0px;
+  border-style: solid;
+  border-color: #f0f0f0;
+  padding: 15px;
+  text-align: left;
+  font-size: 14px;
+}
+
+.button {
+  padding: 0px 20px;
+  border: 1px solid #f0f0f0;
+  border-radius: 5px;
+  font-size: 14px;
+  font-weight: bold;
+  line-height: 36px;
+  color: #737373;
+  -webkit-app-region: no-drag;
+}
+
+.footer {
+  padding-top: 30px;
+  padding-bottom: 30px;
+  /* Clear the float of its children. */
+  overflow: auto;
+  width: 100%
+}
+
+.button.default {
+  background: #427fed;
+  color: white;
+}
+
+.button:hover {
+ border-color: #cecece;
+}
+
+.button.default:active {
+  background: #2c56b1;
+}
+
+.ok-button {
+  float: right;
+  margin-left: 10px;
+}
+
+.cancel-button {
+  float: right;
+}
diff --git a/remoting/webapp/crd/html/dialog_hangout_consent.html b/remoting/webapp/crd/html/dialog_hangout_consent.html
new file mode 100644
index 0000000..3ad7ebd
--- /dev/null
+++ b/remoting/webapp/crd/html/dialog_hangout_consent.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<!--
+Copyright 2014 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<html>
+  <head>
+    <meta charset="utf-8">
+    <link rel="stylesheet" href="dialog_hangout_consent.css">
+    <script type="text/javascript" src="base.js"></script>
+    <script type="text/javascript" src="hangout_consent_dialog_main.js"></script>
+    <script type="text/javascript" src="ipc.js"></script>
+    <script type="text/javascript" src="l10n.js"></script>
+    <script type="text/javascript" src="typecheck.js"></script>
+  </head>
+  <body>
+    <div class="header">
+      <div class="logo"></div>
+      <div class="title" i18n-content="MODE_IT2ME"></div>
+    </div>
+    <div class="content">
+      <div class="message" i18n-content="HANGOUTS_CONFIRM_DIALOG_MESSAGE_1"></div>
+      <ul>
+        <li i18n-content="HANGOUTS_CONFIRM_DIALOG_MESSAGE_2"></li>
+        <li i18n-content="HANGOUTS_CONFIRM_DIALOG_MESSAGE_3"></li>
+        <li i18n-content="DESCRIPTION_AUTHORIZE" class='auth-message'></li>
+      </ul>
+      <div class="footer">
+        <div class="button default ok-button" i18n-content="HANGOUTS_CONFIRM_DIALOG_ACCEPT"></div>
+        <div class="button cancel-button" i18n-content="HANGOUTS_CONFIRM_DIALOG_DECLINE"></div>
+      </div>
+    </div>
+  </body>
+</html>
diff --git a/remoting/webapp/crd/js/client_session.js b/remoting/webapp/crd/js/client_session.js
index 73bf54e..3edecfe 100644
--- a/remoting/webapp/crd/js/client_session.js
+++ b/remoting/webapp/crd/js/client_session.js
@@ -32,13 +32,6 @@
 remoting.ACCESS_TOKEN_RESEND_INTERVAL_MS = 15 * 60 * 1000;
 
 /**
- * True if Cast capability is supported.
- *
- * @type {boolean}
- */
-remoting.enableCast = false;
-
-/**
  * True to enable mouse lock.
  * This is currently disabled because the current client plugin does not
  * properly handle mouse lock and delegated large cursors at the same time.
@@ -1677,7 +1670,8 @@
  * @private
  */
 remoting.ClientSession.prototype.createCastExtensionHandler_ = function() {
-  if (remoting.enableCast && this.mode_ == remoting.ClientSession.Mode.ME2ME) {
+  if (remoting.app.hasCapability(remoting.ClientSession.Capability.CAST) &&
+      this.mode_ == remoting.ClientSession.Mode.ME2ME) {
     this.castExtensionHandler_ = new remoting.CastExtensionHandler(this);
   }
 };
diff --git a/remoting/webapp/crd/js/crd_main.js b/remoting/webapp/crd/js/crd_main.js
index f772320..1fdc7a2 100644
--- a/remoting/webapp/crd/js/crd_main.js
+++ b/remoting/webapp/crd/js/crd_main.js
@@ -56,7 +56,7 @@
 
   var onLoad = function() {
     // Parse URL parameters.
-    var urlParams = getUrlParameters_();
+    var urlParams = base.getUrlParameters();
     if ('mode' in urlParams) {
       if (urlParams['mode'] === 'me2me') {
         var hostId = urlParams['hostId'];
@@ -188,7 +188,7 @@
  * hold in some corner cases.
  */
 remoting.startDesktopRemotingForTesting = function() {
-  var urlParams = getUrlParameters_();
+  var urlParams = base.getUrlParameters();
   if (urlParams['source'] === 'test') {
     document.getElementById('browser-test-continue-init').addEventListener(
         'click', remoting.startDesktopRemoting, false);
@@ -200,7 +200,7 @@
 
 
 remoting.startDesktopRemoting = function() {
-  remoting.app = new remoting.Application();
+  remoting.app = new remoting.Application(remoting.app_capabilities());
   var desktop_remoting = new remoting.DesktopRemoting(remoting.app);
   remoting.app.start();
 };
diff --git a/remoting/webapp/crd/js/desktop_remoting.js b/remoting/webapp/crd/js/desktop_remoting.js
index 9e2e1010..5d9abb8 100644
--- a/remoting/webapp/crd/js/desktop_remoting.js
+++ b/remoting/webapp/crd/js/desktop_remoting.js
@@ -156,21 +156,6 @@
 };
 
 /**
- * @return {Array.<string>} A list of |ClientSession.Capability|s required
- *     by this application.
- */
-remoting.DesktopRemoting.prototype.getRequiredCapabilities = function() {
-  return [
-    remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION,
-    remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS,
-    remoting.ClientSession.Capability.VIDEO_RECORDER,
-    // TODO(aiguha): Add this capability based on a gyp/command-line flag,
-    // rather than by default.
-    remoting.ClientSession.Capability.CAST
-  ];
-};
-
-/**
  * Called when a new session has been connected.
  *
  * @param {remoting.ClientSession} clientSession
diff --git a/remoting/webapp/crd/js/hangout_consent_dialog.js b/remoting/webapp/crd/js/hangout_consent_dialog.js
new file mode 100644
index 0000000..87f8807
--- /dev/null
+++ b/remoting/webapp/crd/js/hangout_consent_dialog.js
@@ -0,0 +1,106 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+(function() {
+
+'use strict';
+
+var instance_ = null;
+
+/**
+ * Shows a dialog to ask for the user's permission to accept remote assistance
+ * from a Hangout participant.
+ *
+ * @constructor
+ * @private
+ */
+remoting.HangoutConsentDialog = function() {
+  /**
+   * @type {base.Deferred}
+   * @private
+   */
+  this.onConsentResponseDeferred_ = null;
+
+  /** @private */
+  this.requestToken_ = base.generateXsrfToken();
+
+  base.Ipc.getInstance().register('remoting.HangoutConsentDialog.confirm',
+                                  this.onConfirmResponse_.bind(this));
+};
+
+/**
+ * @param {boolean} confirm Whether the user authorized the it2me connection
+ * @param {string} responseToken
+ * @private
+ */
+remoting.HangoutConsentDialog.prototype.onConfirmResponse_ = function(
+    confirm, responseToken) {
+  if (responseToken !== this.requestToken_) {
+    return;
+  }
+
+  if (confirm) {
+    this.onConsentResponseDeferred_.resolve();
+  } else {
+    this.onConsentResponseDeferred_.reject(
+        new Error(remoting.Error.CANCELLED));
+  }
+  this.onConsentResponseDeferred_ = null;
+};
+
+/**
+ * @param {boolean} authorized If true, the consent dialog will hide the
+ *  authorization section.
+ * @param {Bounds=} opt_parentBounds If present, the consent dialog will be
+ *  centered within |opt_parentBounds|.
+ * @return {Promise} A Promise that will resolve when permission is granted or
+ *   reject if the user cancels.
+ */
+remoting.HangoutConsentDialog.prototype.show = function(authorized,
+                                                        opt_parentBounds) {
+  if (!this.onConsentResponseDeferred_) {
+    var DIALOG_WIDTH = 750;
+    var DIALOG_HEIGHT = 480;
+
+    var createOptions = {
+      frame: 'none',
+      resizable: false,
+      outerBounds: { width: DIALOG_WIDTH, height: DIALOG_HEIGHT }
+    };
+
+    var params = {
+      token: this.requestToken_,
+      authorized: Boolean(authorized)
+    };
+
+    var url = base.urlJoin('dialog_hangout_consent.html', params);
+
+    if (opt_parentBounds) {
+      // Center the dialog on the parent bounds.
+      var rect = opt_parentBounds;
+      createOptions.outerBounds.top =
+          Math.round(rect.top + rect.height / 2 - DIALOG_HEIGHT / 2);
+      createOptions.outerBounds.left =
+          Math.round(rect.left + rect.width / 2 - DIALOG_WIDTH / 2);
+    }
+
+    this.onConsentResponseDeferred_ = new base.Deferred();
+    chrome.app.window.create(url, createOptions);
+  }
+  return this.onConsentResponseDeferred_.promise();
+};
+
+/** @return {remoting.HangoutConsentDialog} */
+remoting.HangoutConsentDialog.getInstance = function() {
+  if (!instance_) {
+    instance_ = new remoting.HangoutConsentDialog();
+  }
+  return instance_;
+};
+
+}());
+
diff --git a/remoting/webapp/crd/js/hangout_consent_dialog_main.js b/remoting/webapp/crd/js/hangout_consent_dialog_main.js
new file mode 100644
index 0000000..8ced7a86
--- /dev/null
+++ b/remoting/webapp/crd/js/hangout_consent_dialog_main.js
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+* @fileoverview
+* The entry point for dialog_hangout_consent.html.
+*/
+
+
+/** @suppress {duplicate} */
+var remoting = remoting || {};
+
+(function() {
+
+'use strict';
+
+/**
+ * @constructor
+ * @param {HTMLElement} rootElement
+ * @param {string} requestToken
+ * @param {boolean} authorized Whether the user is authorized or not.
+ */
+var ConsentDialog = function(rootElement, requestToken, authorized) {
+  /** @private */
+  this.okButton_ = rootElement.querySelector('.ok-button');
+  /** @private */
+  this.cancelButton_ = rootElement.querySelector('.cancel-button');
+  /** @private */
+  this.authSection_ = rootElement.querySelector('.auth-message');
+  /** @private */
+  this.requestToken_ = requestToken;
+
+  if (authorized) {
+    this.authSection_.hidden = true;
+  }
+
+  this.okButton_.addEventListener('click', this.onButton_.bind(this, true));
+  this.cancelButton_.addEventListener('click',this.onButton_.bind(this, false));
+  base.resizeWindowToContent();
+};
+
+/**
+ * @param {boolean} confirm
+ * @private
+ */
+ConsentDialog.prototype.onButton_ = function(confirm) {
+  base.Ipc.invoke('remoting.HangoutConsentDialog.confirm', confirm,
+                  this.requestToken_);
+  chrome.app.window.current().close();
+};
+
+function onDomContentLoaded() {
+  var params = base.getUrlParameters();
+  var authorized = getBooleanAttr(params, 'authorized', false);
+  var token = getStringAttr(params, 'token');
+  l10n.localize();
+  var confirmDialog = new ConsentDialog(document.body, token, authorized);
+}
+
+window.addEventListener('load', onDomContentLoaded);
+
+}());
diff --git a/remoting/webapp/crd/js/it2me_helpee_channel.js b/remoting/webapp/crd/js/it2me_helpee_channel.js
index af28dd49..97a14c2 100644
--- a/remoting/webapp/crd/js/it2me_helpee_channel.js
+++ b/remoting/webapp/crd/js/it2me_helpee_channel.js
@@ -250,6 +250,8 @@
 remoting.It2MeHelpeeChannel.prototype.handleConnect_ =
     function(message) {
   var email = getStringAttr(message, 'email');
+  var bounds =
+      /** @type {Bounds} */ (getObjectAttr(message, 'hangoutBounds', null));
 
   if (!email) {
     throw new Error('Missing required parameter: email');
@@ -259,13 +261,20 @@
     throw new Error('An existing connection is in progress.');
   }
 
-  this.showConfirmDialog_().then(
+  var that = this;
+  this.showConfirmDialog_(bounds).then(
     this.initializeHost_.bind(this)
   ).then(
     this.fetchOAuthToken_.bind(this)
   ).then(
-    /** @type {function(*):void} */(this.connectToHost_.bind(this, email)),
-    /** @type {function(*):void} */(this.sendErrorResponse_.bind(this, message))
+    /** @type {function(*):void} */(this.connectToHost_.bind(this, email))
+  ).catch(
+    /** @param {*} reason */
+    function(reason) {
+      var error = /** @type {Error} */ (reason);
+      that.sendErrorResponse_(message, error);
+      that.dispose();
+    }
   );
 };
 
@@ -274,21 +283,22 @@
  * ensures that even if Hangouts is compromised, an attacker cannot start the
  * host without explicit user confirmation.
  *
- * @return {Promise} A promise that resolves to a boolean value, indicating
- *     whether the user accepts the remote assistance or not.
+ * @param {Bounds} bounds Bounds of the hangout window
+ * @return {Promise} A promise that will resolve if the user accepts remote
+ *   assistance or reject otherwise.
  * @private
  */
-remoting.It2MeHelpeeChannel.prototype.showConfirmDialog_ = function() {
+remoting.It2MeHelpeeChannel.prototype.showConfirmDialog_ = function(bounds) {
   if (base.isAppsV2()) {
-    return this.showConfirmDialogV2_();
+    return this.showConfirmDialogV2_(bounds);
   } else {
     return this.showConfirmDialogV1_();
   }
 };
 
 /**
- * @return {Promise} A promise that resolves to a boolean value, indicating
- *     whether the user accepts the remote assistance or not.
+ * @return {Promise}  A promise that will resolve if the user accepts remote
+ *   assistance or reject otherwise.
  * @private
  */
 remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV1_ = function() {
@@ -310,45 +320,22 @@
 };
 
 /**
- * @return {Promise} A promise that resolves to a boolean value, indicating
- *     whether the user accepts the remote assistance or not.
+ * @param {Bounds} bounds the bounds of the Hangouts Window.  If set, the
+ *   confirm dialog will be centered within |bounds|.
+ * @return {Promise} A promise that will resolve if the user accepts remote
+ *   assistance or reject otherwise.
  * @private
  */
-remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV2_ = function() {
-  var messageHeader = l10n.getTranslationOrError(
-      /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_1');
-  var message1 = l10n.getTranslationOrError(
-      /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_2');
-  var message2 = l10n.getTranslationOrError(
-      /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_3');
-  var message = '<div>' + base.escapeHTML(messageHeader) + '</div>' +
-                '<ul class="insetList">' +
-                  '<li>' + base.escapeHTML(message1) + '</li>' +
-                  '<li>' + base.escapeHTML(message2) + '</li>' +
-                '</ul>';
-  /**
-   * @param {function(*=):void} resolve
-   * @param {function(*=):void} reject
-   */
-  return new Promise(function(resolve, reject) {
-    /** @param {number} result */
-    function confirmDialogCallback(result) {
-      if (result === 1) {
-        resolve(true);
-      } else {
-        reject(new Error(remoting.Error.CANCELLED));
-      }
-    }
-    remoting.MessageWindow.showConfirmWindow(
-        '', // Empty string to use the package name as the dialog title.
-        message,
-        l10n.getTranslationOrError(
-            /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_ACCEPT'),
-        l10n.getTranslationOrError(
-            /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_DECLINE'),
-        confirmDialogCallback
-    );
-  });
+remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV2_ = function(bounds) {
+  var getToken =
+      base.Promise.as(chrome.identity.getAuthToken, [{interactive: false}]);
+
+  return getToken.then(
+    /** @param {string} token */
+    function(token) {
+      return remoting.HangoutConsentDialog.getInstance().show(Boolean(token),
+                                                              bounds);
+    });
 };
 
 /**
@@ -374,7 +361,8 @@
 };
 
 /**
- * @return {Promise} Promise that resolves with the OAuth token as the value.
+ * @return {Promise<string>} Promise that resolves with the OAuth token as the
+ * value.
  */
 remoting.It2MeHelpeeChannel.prototype.fetchOAuthToken_ = function() {
   if (base.isAppsV2()) {
@@ -382,27 +370,25 @@
      * @param {function(*=):void} resolve
      */
     return new Promise(function(resolve){
-      // TODO(jamiewalch): Make this work with {interactive: true} as well.
-      chrome.identity.getAuthToken({ 'interactive': false }, resolve);
+      chrome.identity.getAuthToken({'interactive': true}, resolve);
     });
   } else {
     /**
      * @param {function(*=):void} resolve
+     * @param {function(*=):void} reject
      */
-    return new Promise(function(resolve) {
+    return new Promise(function(resolve, reject) {
       /** @type {remoting.OAuth2} */
       var oauth2 = new remoting.OAuth2();
-      var onAuthenticated = function() {
-        oauth2.callWithToken(
-            resolve,
-            function() { throw new Error('Authentication failed.'); });
-      };
       /** @param {remoting.Error} error */
       var onError = function(error) {
-        if (error != remoting.Error.NOT_AUTHENTICATED) {
-          throw new Error('Unexpected error fetch auth token: ' + error);
+        if (error === remoting.Error.NOT_AUTHENTICATED) {
+          oauth2.doAuthRedirect(function() {
+            oauth2.callWithToken(resolve, reject);
+          });
+          return;
         }
-        oauth2.removeCachedAuthToken();
+        reject(new Error(remoting.Error.NOT_AUTHENTICATED));
       };
       oauth2.callWithToken(resolve, onError);
     });
diff --git a/remoting/webapp/crd/js/remoting.js b/remoting/webapp/crd/js/remoting.js
index d86e6ec3..320019c9 100644
--- a/remoting/webapp/crd/js/remoting.js
+++ b/remoting/webapp/crd/js/remoting.js
@@ -144,19 +144,6 @@
 }
 
 /**
- * @return {Object.<string, string>} The URL parameters.
- */
-function getUrlParameters_() {
-  var result = {};
-  var parts = window.location.search.substring(1).split('&');
-  for (var i = 0; i < parts.length; i++) {
-    var pair = parts[i].split('=');
-    result[pair[0]] = decodeURIComponent(pair[1]);
-  }
-  return result;
-}
-
-/**
  * Return the current time as a formatted string suitable for logging.
  *
  * @return {string} The current time, formatted as [mmdd/hhmmss.xyz]
diff --git a/remoting/webapp/crd/js/typecheck.js b/remoting/webapp/crd/js/typecheck.js
index fa31f55a..7365238 100644
--- a/remoting/webapp/crd/js/typecheck.js
+++ b/remoting/webapp/crd/js/typecheck.js
@@ -41,7 +41,10 @@
  */
 function getBooleanAttr(dict, key, opt_default) {
   var value = /** @type {boolean} */ (dict[key]);
-  if (typeof value != 'boolean') {
+  if (value == 'true' || value == 'false') {
+    return (value == 'true');
+  }
+  if (typeof value !== 'boolean') {
     if (opt_default === undefined) {
       throw 'Invalid data type for ' + key +
           ' (expected: boolean, actual: ' + typeof value + ')';
diff --git a/remoting/webapp/js_proto/chrome_proto.js b/remoting/webapp/js_proto/chrome_proto.js
index d47ef43..99fb4598 100644
--- a/remoting/webapp/js_proto/chrome_proto.js
+++ b/remoting/webapp/js_proto/chrome_proto.js
@@ -386,6 +386,17 @@
 AppWindow.prototype.focus = function() {};
 AppWindow.prototype.maximize = function() {};
 AppWindow.prototype.minimize = function() {};
+/**
+ * @param {number} left
+ * @param {number} top
+ */
+AppWindow.prototype.moveTo = function(left, top) {};
+/**
+ * @param {number} width
+ * @param {number} height
+ */
+AppWindow.prototype.resizeTo = function(width, height) {};
+
 AppWindow.prototype.restore = function() {};
 AppWindow.prototype.show = function() {};
 /** @return {boolean} */
@@ -424,7 +435,7 @@
   this.width = 0;
   /** @type {number} */
   this.height = 0;
-};
+}
 
 /** @type {Object} */
 chrome.cast = {};
diff --git a/remoting/webapp/unittests/it2me_helpee_channel_unittest.js b/remoting/webapp/unittests/it2me_helpee_channel_unittest.js
index 4ccfb08..3a8cb962 100644
--- a/remoting/webapp/unittests/it2me_helpee_channel_unittest.js
+++ b/remoting/webapp/unittests/it2me_helpee_channel_unittest.js
@@ -129,8 +129,11 @@
     function() {
   // Stubs authentication.
   sinon.stub(base, 'isAppsV2').returns(true);
-  sinon.stub(remoting.MessageWindow, 'showConfirmWindow')
-      .callsArgWith(4, 1 /* 1 for OK. */);
+  sinon.stub(remoting.HangoutConsentDialog, 'getInstance').returns({
+    show : function() {
+      return Promise.resolve();
+    }
+  });
   sinon.stub(chrome.identity, 'getAuthToken')
       .callsArgWith(1, 'token');
   // Stubs Host behavior.
@@ -142,7 +145,8 @@
   var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes;
   hangoutPort.onMessage.mock$fire({
     method: MessageTypes.CONNECT,
-    email: 'test@chromium.org'
+    email: 'test@chromium.org',
+    hangoutBounds: {widht: 10, height: 10, left:10, top: 10}
   });
 
   window.requestAnimationFrame(function(){
@@ -154,7 +158,6 @@
 
     chrome.identity.getAuthToken.restore();
     base.isAppsV2.restore();
-    remoting.MessageWindow.showConfirmWindow.restore();
     QUnit.start();
   });
 });
diff --git a/sandbox/linux/services/credentials_unittest.cc b/sandbox/linux/services/credentials_unittest.cc
index 1209fdf29..40a2bc4 100644
--- a/sandbox/linux/services/credentials_unittest.cc
+++ b/sandbox/linux/services/credentials_unittest.cc
@@ -123,11 +123,11 @@
 }
 
 // Test the WorkingDirectoryIsRoot() helper.
-TEST(Credentials, CanDetectRoot) {
-  ASSERT_EQ(0, chdir("/proc/"));
-  ASSERT_FALSE(WorkingDirectoryIsRoot());
-  ASSERT_EQ(0, chdir("/"));
-  ASSERT_TRUE(WorkingDirectoryIsRoot());
+SANDBOX_TEST(Credentials, CanDetectRoot) {
+  PCHECK(0 == chdir("/proc/"));
+  CHECK(!WorkingDirectoryIsRoot());
+  PCHECK(0 == chdir("/"));
+  CHECK(WorkingDirectoryIsRoot());
 }
 
 // Disabled on ASAN because of crbug.com/451603.
diff --git a/sandbox/linux/services/namespace_sandbox_unittest.cc b/sandbox/linux/services/namespace_sandbox_unittest.cc
index ace1f925..91e1db92 100644
--- a/sandbox/linux/services/namespace_sandbox_unittest.cc
+++ b/sandbox/linux/services/namespace_sandbox_unittest.cc
@@ -90,7 +90,8 @@
   return 0;
 }
 
-TEST_F(NamespaceSandboxTest, ChrootAndDropCapabilities) {
+// Temporarily disabled on ASAN due to crbug.com/451603.
+TEST_F(NamespaceSandboxTest, DISABLE_ON_ASAN(ChrootAndDropCapabilities)) {
   TestProc("ChrootMe");
 }
 
diff --git a/sandbox/linux/suid/client/setuid_sandbox_client.cc b/sandbox/linux/suid/client/setuid_sandbox_client.cc
index f0b5cef..9eb538a 100644
--- a/sandbox/linux/suid/client/setuid_sandbox_client.cc
+++ b/sandbox/linux/suid/client/setuid_sandbox_client.cc
@@ -18,7 +18,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/logging.h"
-#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/posix/eintr_wrapper.h"
@@ -32,7 +31,7 @@
 namespace {
 
 bool IsFileSystemAccessDenied() {
-  base::ScopedFD self_exe(HANDLE_EINTR(open(base::kProcSelfExe, O_RDONLY)));
+  base::ScopedFD self_exe(HANDLE_EINTR(open("/", O_RDONLY)));
   return !self_exe.is_valid();
 }
 
@@ -208,11 +207,6 @@
   return true;
 }
 
-bool SetuidSandboxClient::CreateInitProcessReaper(
-    base::Closure* post_fork_parent_callback) {
-  return sandbox::CreateInitProcessReaper(post_fork_parent_callback);
-}
-
 bool SetuidSandboxClient::IsSuidSandboxUpToDate() const {
   return GetHelperApi(env_) == kSUIDSandboxApiNumber;
 }
diff --git a/sandbox/linux/suid/client/setuid_sandbox_client.h b/sandbox/linux/suid/client/setuid_sandbox_client.h
index e6a3e4c..b24eb4c5f 100644
--- a/sandbox/linux/suid/client/setuid_sandbox_client.h
+++ b/sandbox/linux/suid/client/setuid_sandbox_client.h
@@ -6,7 +6,8 @@
 #define SANDBOX_LINUX_SUID_SETUID_SANDBOX_CLIENT_H_
 
 #include "base/basictypes.h"
-#include "base/callback_forward.h"
+#include "base/command_line.h"
+#include "base/environment.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_file.h"
 #include "base/process/launch.h"
@@ -52,11 +53,6 @@
   // to an empty directory.
   // Will only work if we have been launched through the setuid helper.
   bool ChrootMe();
-  // When a new PID namespace is created, the process with pid == 1 should
-  // assume the role of init.
-  // See sandbox/linux/services/init_process_reaper.h for more information
-  // on this API.
-  bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback);
 
   // Did we get launched through an up to date setuid binary ?
   bool IsSuidSandboxUpToDate() const;
diff --git a/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java b/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java
deleted file mode 100644
index 7660434d..0000000
--- a/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java
+++ /dev/null
@@ -1,438 +0,0 @@
-// Copyright 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.sync.notifier;
-
-import android.accounts.Account;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SyncStatusObserver;
-import android.os.StrictMode;
-
-import org.chromium.base.ObserverList;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.sync.SyncContentResolverDelegate;
-import org.chromium.sync.SystemSyncContentResolverDelegate;
-import org.chromium.sync.signin.AccountManagerHelper;
-import org.chromium.sync.signin.ChromeSigninController;
-
-import javax.annotation.concurrent.NotThreadSafe;
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * A helper class to handle the current status of sync for Chrome in Android settings.
- *
- * It also provides an observer to be used whenever Android sync settings change.
- *
- * To retrieve an instance of this class, call SyncStatusHelper.get(someContext).
- *
- * All new public methods MUST call notifyObservers at the end.
- */
-@ThreadSafe
-public class SyncStatusHelper {
-
-    /**
-     * In-memory holder of the sync configurations for a given account. On each
-     * access, updates the cache if the account has changed. This lazy-updating
-     * model is appropriate as the account changes rarely but may not be known
-     * when initially constructed. So long as we keep a single account, no
-     * expensive calls to Android are made.
-     */
-    @NotThreadSafe
-    @VisibleForTesting
-    public static class CachedAccountSyncSettings {
-        private final String mContractAuthority;
-        private final SyncContentResolverDelegate mSyncContentResolverDelegate;
-        private Account mAccount;
-        private boolean mDidUpdate;
-        private boolean mSyncAutomatically;
-        private int mIsSyncable;
-
-        public CachedAccountSyncSettings(String contractAuthority,
-                SyncContentResolverDelegate contentResolverWrapper) {
-            mContractAuthority = contractAuthority;
-            mSyncContentResolverDelegate = contentResolverWrapper;
-        }
-
-        private void ensureSettingsAreForAccount(Account account) {
-            assert account != null;
-            if (account.equals(mAccount)) return;
-            updateSyncSettingsForAccount(account);
-            mDidUpdate = true;
-        }
-
-        public void clearUpdateStatus() {
-            mDidUpdate = false;
-        }
-
-        public boolean getDidUpdateStatus() {
-            return mDidUpdate;
-        }
-
-        // Calling this method may have side-effects.
-        public boolean getSyncAutomatically(Account account) {
-            ensureSettingsAreForAccount(account);
-            return mSyncAutomatically;
-        }
-
-        public void updateSyncSettingsForAccount(Account account) {
-            if (account == null) return;
-            updateSyncSettingsForAccountInternal(account);
-        }
-
-        public void setIsSyncable(Account account) {
-            ensureSettingsAreForAccount(account);
-            if (mIsSyncable == 1) return;
-            setIsSyncableInternal(account);
-        }
-
-        public void setSyncAutomatically(Account account, boolean value) {
-            ensureSettingsAreForAccount(account);
-            if (mSyncAutomatically == value) return;
-            setSyncAutomaticallyInternal(account, value);
-        }
-
-        @VisibleForTesting
-        protected void updateSyncSettingsForAccountInternal(Account account) {
-            // Null check here otherwise Findbugs complains.
-            if (account == null) return;
-
-            boolean oldSyncAutomatically = mSyncAutomatically;
-            int oldIsSyncable = mIsSyncable;
-            Account oldAccount = mAccount;
-
-            mAccount = account;
-
-            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-            mSyncAutomatically = mSyncContentResolverDelegate.getSyncAutomatically(
-                    account, mContractAuthority);
-            mIsSyncable = mSyncContentResolverDelegate.getIsSyncable(account, mContractAuthority);
-            StrictMode.setThreadPolicy(oldPolicy);
-            mDidUpdate = (oldIsSyncable != mIsSyncable)
-                || (oldSyncAutomatically != mSyncAutomatically)
-                || (!account.equals(oldAccount));
-        }
-
-        @VisibleForTesting
-        protected void setIsSyncableInternal(Account account) {
-            mIsSyncable = 1;
-            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-            mSyncContentResolverDelegate.setIsSyncable(account, mContractAuthority, 1);
-            StrictMode.setThreadPolicy(oldPolicy);
-            mDidUpdate = true;
-        }
-
-        @VisibleForTesting
-        protected void setSyncAutomaticallyInternal(Account account, boolean value) {
-            mSyncAutomatically = value;
-            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-            mSyncContentResolverDelegate.setSyncAutomatically(account, mContractAuthority, value);
-            StrictMode.setThreadPolicy(oldPolicy);
-            mDidUpdate = true;
-        }
-    }
-
-    // This should always have the same value as GaiaConstants::kChromeSyncOAuth2Scope.
-    public static final String CHROME_SYNC_OAUTH2_SCOPE =
-            "https://www.googleapis.com/auth/chromesync";
-
-    public static final String TAG = "SyncStatusHelper";
-
-    /**
-     * Lock for ensuring singleton instantiation across threads.
-     */
-    private static final Object INSTANCE_LOCK = new Object();
-
-    private static SyncStatusHelper sSyncStatusHelper;
-
-    private final String mContractAuthority;
-
-    private final Context mApplicationContext;
-
-    private final SyncContentResolverDelegate mSyncContentResolverDelegate;
-
-    private boolean mCachedMasterSyncAutomatically;
-
-    // Instantiation of SyncStatusHelper is guarded by a lock so volatile is unneeded.
-    private CachedAccountSyncSettings mCachedSettings;
-
-    private final ObserverList<SyncSettingsChangedObserver> mObservers =
-            new ObserverList<SyncSettingsChangedObserver>();
-
-    /**
-     * Provides notifications when Android sync settings have changed.
-     */
-    public interface SyncSettingsChangedObserver {
-        public void syncSettingsChanged();
-    }
-
-    /**
-     * @param context the context
-     * @param syncContentResolverDelegate an implementation of {@link SyncContentResolverDelegate}.
-     */
-    private SyncStatusHelper(Context context,
-            SyncContentResolverDelegate syncContentResolverDelegate,
-            CachedAccountSyncSettings cachedAccountSettings) {
-        mApplicationContext = context.getApplicationContext();
-        mSyncContentResolverDelegate = syncContentResolverDelegate;
-        mContractAuthority = getContractAuthority();
-        mCachedSettings = cachedAccountSettings;
-
-        updateMasterSyncAutomaticallySetting();
-
-        mSyncContentResolverDelegate.addStatusChangeListener(
-                ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
-                new AndroidSyncSettingsChangedObserver());
-    }
-
-    private void updateMasterSyncAutomaticallySetting() {
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-        synchronized (mCachedSettings) {
-            mCachedMasterSyncAutomatically = mSyncContentResolverDelegate
-                    .getMasterSyncAutomatically();
-        }
-        StrictMode.setThreadPolicy(oldPolicy);
-    }
-
-    /**
-     * A factory method for the SyncStatusHelper.
-     *
-     * It is possible to override the {@link SyncContentResolverDelegate} to use in tests for the
-     * instance of the SyncStatusHelper by calling overrideSyncStatusHelperForTests(...) with
-     * your {@link SyncContentResolverDelegate}.
-     *
-     * @param context the ApplicationContext is retrieved from the context used as an argument.
-     * @return a singleton instance of the SyncStatusHelper
-     */
-    public static SyncStatusHelper get(Context context) {
-        synchronized (INSTANCE_LOCK) {
-            if (sSyncStatusHelper == null) {
-                SyncContentResolverDelegate contentResolverDelegate =
-                        new SystemSyncContentResolverDelegate();
-                CachedAccountSyncSettings cache = new CachedAccountSyncSettings(
-                        context.getPackageName(), contentResolverDelegate);
-                sSyncStatusHelper = new SyncStatusHelper(context, contentResolverDelegate, cache);
-            }
-        }
-        return sSyncStatusHelper;
-    }
-
-    /**
-     * Tests might want to consider overriding the context and {@link SyncContentResolverDelegate}
-     * so they do not use the real ContentResolver in Android.
-     *
-     * @param context the context to use
-     * @param syncContentResolverDelegate the {@link SyncContentResolverDelegate} to use
-     */
-    @VisibleForTesting
-    public static void overrideSyncStatusHelperForTests(Context context,
-            SyncContentResolverDelegate syncContentResolverDelegate,
-            CachedAccountSyncSettings cachedAccountSettings) {
-        synchronized (INSTANCE_LOCK) {
-            if (sSyncStatusHelper != null) {
-                throw new IllegalStateException("SyncStatusHelper already exists");
-            }
-            sSyncStatusHelper = new SyncStatusHelper(context, syncContentResolverDelegate,
-                    cachedAccountSettings);
-        }
-    }
-
-    @VisibleForTesting
-    public static void overrideSyncStatusHelperForTests(Context context,
-            SyncContentResolverDelegate syncContentResolverDelegate) {
-        CachedAccountSyncSettings cachedAccountSettings = new CachedAccountSyncSettings(
-                context.getPackageName(), syncContentResolverDelegate);
-        overrideSyncStatusHelperForTests(context, syncContentResolverDelegate,
-                cachedAccountSettings);
-    }
-
-    /**
-     * Returns the contract authority to use when requesting sync.
-     */
-    public String getContractAuthority() {
-        return mApplicationContext.getPackageName();
-    }
-
-    /**
-     * Wrapper method for the ContentResolver.addStatusChangeListener(...) when we are only
-     * interested in the settings type.
-     */
-    public void registerSyncSettingsChangedObserver(SyncSettingsChangedObserver observer) {
-        mObservers.addObserver(observer);
-    }
-
-    /**
-     * Wrapper method for the ContentResolver.removeStatusChangeListener(...).
-     */
-    public void unregisterSyncSettingsChangedObserver(SyncSettingsChangedObserver observer) {
-        mObservers.removeObserver(observer);
-    }
-
-    /**
-     * Checks whether sync is currently enabled from Chrome for a given account.
-     *
-     * It checks both the master sync for the device, and Chrome sync setting for the given account.
-     *
-     * @param account the account to check if Chrome sync is enabled on.
-     * @return true if sync is on, false otherwise
-     */
-    public boolean isSyncEnabled(Account account) {
-        if (account == null) return false;
-        boolean returnValue;
-        synchronized (mCachedSettings) {
-            returnValue = mCachedMasterSyncAutomatically
-                    && mCachedSettings.getSyncAutomatically(account);
-        }
-
-        notifyObserversIfAccountSettingsChanged();
-        return returnValue;
-    }
-
-    /**
-     * Checks whether sync is currently enabled from Chrome for the currently signed in account.
-     *
-     * It checks both the master sync for the device, and Chrome sync setting for the given account.
-     * If no user is currently signed in it returns false.
-     *
-     * @return true if sync is on, false otherwise
-     */
-    public boolean isSyncEnabled() {
-        return isSyncEnabled(ChromeSigninController.get(mApplicationContext).getSignedInUser());
-    }
-
-    /**
-     * Checks whether sync is currently enabled from Chrome for a given account.
-     *
-     * It checks only Chrome sync setting for the given account,
-     * and ignores the master sync setting.
-     *
-     * @param account the account to check if Chrome sync is enabled on.
-     * @return true if sync is on, false otherwise
-     */
-    public boolean isSyncEnabledForChrome(Account account) {
-        if (account == null) return false;
-
-        boolean returnValue;
-        synchronized (mCachedSettings) {
-            returnValue = mCachedSettings.getSyncAutomatically(account);
-        }
-
-        notifyObserversIfAccountSettingsChanged();
-        return returnValue;
-    }
-
-    /**
-     * Checks whether the master sync flag for Android is currently set.
-     *
-     * @return true if the global master sync is on, false otherwise
-     */
-    public boolean isMasterSyncAutomaticallyEnabled() {
-        synchronized (mCachedSettings) {
-            return mCachedMasterSyncAutomatically;
-        }
-    }
-
-    /**
-     * Make sure Chrome is syncable, and enable sync.
-     *
-     * @param account the account to enable sync on
-     */
-    public void enableAndroidSync(Account account) {
-        makeSyncable(account);
-
-        synchronized (mCachedSettings) {
-            mCachedSettings.setSyncAutomatically(account, true);
-        }
-
-        notifyObserversIfAccountSettingsChanged();
-    }
-
-    /**
-     * Disables Android Chrome sync
-     *
-     * @param account the account to disable Chrome sync on
-     */
-    public void disableAndroidSync(Account account) {
-        synchronized (mCachedSettings) {
-            mCachedSettings.setSyncAutomatically(account, false);
-        }
-
-        notifyObserversIfAccountSettingsChanged();
-    }
-
-    /**
-     * Register with Android Sync Manager. This is what causes the "Chrome" option to appear in
-     * Settings -> Accounts / Sync .
-     *
-     * @param account the account to enable Chrome sync on
-     */
-    private void makeSyncable(Account account) {
-        synchronized (mCachedSettings) {
-            mCachedSettings.setIsSyncable(account);
-        }
-
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-        // Disable the syncability of Chrome for all other accounts. Don't use
-        // our cache as we're touching many accounts that aren't signed in, so this saves
-        // extra calls to Android sync configuration.
-        Account[] googleAccounts = AccountManagerHelper.get(mApplicationContext)
-                .getGoogleAccounts();
-        for (Account accountToSetNotSyncable : googleAccounts) {
-            if (!accountToSetNotSyncable.equals(account)
-                    && mSyncContentResolverDelegate.getIsSyncable(
-                            accountToSetNotSyncable, mContractAuthority) > 0) {
-                mSyncContentResolverDelegate.setIsSyncable(accountToSetNotSyncable,
-                        mContractAuthority, 0);
-            }
-        }
-        StrictMode.setThreadPolicy(oldPolicy);
-    }
-
-    /**
-     * Helper class to be used by observers whenever sync settings change.
-     *
-     * To register the observer, call SyncStatusHelper.registerObserver(...).
-     */
-    private class AndroidSyncSettingsChangedObserver implements SyncStatusObserver {
-        @Override
-        public void onStatusChanged(int which) {
-            if (ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS == which) {
-                // Sync settings have changed; update our in-memory caches
-                synchronized (mCachedSettings) {
-                    mCachedSettings.updateSyncSettingsForAccount(
-                            ChromeSigninController.get(mApplicationContext).getSignedInUser());
-                }
-
-                boolean oldMasterSyncEnabled = isMasterSyncAutomaticallyEnabled();
-                updateMasterSyncAutomaticallySetting();
-                boolean didMasterSyncChanged =
-                        oldMasterSyncEnabled != isMasterSyncAutomaticallyEnabled();
-                // Notify observers if MasterSync or account level settings change.
-                if (didMasterSyncChanged || getAndClearDidUpdateStatus())
-                    notifyObservers();
-            }
-        }
-    }
-
-    private boolean getAndClearDidUpdateStatus() {
-        boolean didGetStatusUpdate;
-        synchronized (mCachedSettings) {
-            didGetStatusUpdate = mCachedSettings.getDidUpdateStatus();
-            mCachedSettings.clearUpdateStatus();
-        }
-        return didGetStatusUpdate;
-    }
-
-    private void notifyObserversIfAccountSettingsChanged() {
-        if (getAndClearDidUpdateStatus()) {
-            notifyObservers();
-        }
-    }
-
-    private void notifyObservers() {
-        for (SyncSettingsChangedObserver observer : mObservers) {
-            observer.syncSettingsChanged();
-        }
-    }
-}
diff --git a/sync/internal_api/public/util/experiments.h b/sync/internal_api/public/util/experiments.h
index b61742d..d2b82c62 100644
--- a/sync/internal_api/public/util/experiments.h
+++ b/sync/internal_api/public/util/experiments.h
@@ -16,6 +16,7 @@
 const char kGCMChannelTag[] = "gcm_channel";
 const char kEnhancedBookmarksTag[] = "enhanced_bookmarks";
 const char kGCMInvalidationsTag[] = "gcm_invalidations";
+const char kWalletSyncTag[] = "wallet_sync";
 
 // A structure to hold the enable status of experimental sync features.
 struct Experiments {
@@ -29,15 +30,16 @@
       : favicon_sync_limit(200),
         gcm_channel_state(UNSET),
         enhanced_bookmarks_enabled(false),
-        gcm_invalidations_enabled(true)  // By default GCM channel is enabled.
-  {}
+        gcm_invalidations_enabled(true),  // By default GCM channel is enabled.
+        wallet_sync_enabled(false) {}
 
   bool Matches(const Experiments& rhs) {
     return (favicon_sync_limit == rhs.favicon_sync_limit &&
             gcm_channel_state == rhs.gcm_channel_state &&
             enhanced_bookmarks_enabled == rhs.enhanced_bookmarks_enabled &&
             enhanced_bookmarks_ext_id == rhs.enhanced_bookmarks_ext_id &&
-            gcm_invalidations_enabled == rhs.gcm_invalidations_enabled);
+            gcm_invalidations_enabled == rhs.gcm_invalidations_enabled &&
+            wallet_sync_enabled == rhs.wallet_sync_enabled);
   }
 
   // The number of favicons that a client is permitted to sync.
@@ -54,6 +56,9 @@
 
   // Enhanced bookmarks extension id.
   std::string enhanced_bookmarks_ext_id;
+
+  // Enable the Wallet Autofill sync datatype.
+  bool wallet_sync_enabled;
 };
 
 }  // namespace syncer
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index 8ff4843..1655a24 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -1010,6 +1010,17 @@
     }
   }
 
+  ReadNode wallet_sync_node(&trans);
+  if (wallet_sync_node.InitByClientTagLookup(
+          syncer::EXPERIMENTS, syncer::kWalletSyncTag) == BaseNode::INIT_OK) {
+    const sync_pb::WalletSyncFlags& wallet_sync =
+        wallet_sync_node.GetExperimentsSpecifics().wallet_sync();
+    if (wallet_sync.has_enabled()) {
+      experiments->wallet_sync_enabled = wallet_sync.enabled();
+      found_experiment = true;
+    }
+  }
+
   return found_experiment;
 }
 
diff --git a/sync/protocol/experiments_specifics.proto b/sync/protocol/experiments_specifics.proto
index 723fe55..3006223 100644
--- a/sync/protocol/experiments_specifics.proto
+++ b/sync/protocol/experiments_specifics.proto
@@ -55,6 +55,11 @@
   optional bool enabled = 1;
 }
 
+// Flags for enabling wallet data syncing.
+message WalletSyncFlags {
+  optional bool enabled = 1;
+}
+
 // Contains one flag or set of related flags.  Each node of the experiments type
 // will have a unique_client_tag identifying which flags it contains.  By
 // convention, the tag name should match the sub-message name.
@@ -67,4 +72,5 @@
   optional GcmChannelFlags gcm_channel = 6;
   optional EnhancedBookmarksFlags enhanced_bookmarks = 7;
   optional GcmInvalidationsFlags gcm_invalidations = 8;
+  optional WalletSyncFlags wallet_sync = 9;
 }
diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc
index 377a4322..d1786f8 100644
--- a/sync/protocol/proto_value_conversions.cc
+++ b/sync/protocol/proto_value_conversions.cc
@@ -422,6 +422,7 @@
   SET_EXPERIMENT_ENABLED_FIELD(gcm_channel);
   SET(enhanced_bookmarks, EnhancedBookmarksFlagsToValue);
   SET_EXPERIMENT_ENABLED_FIELD(gcm_invalidations);
+  SET_EXPERIMENT_ENABLED_FIELD(wallet_sync);
   return value;
 }
 
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index c9059e7..55e5481 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -101,6 +101,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
@@ -245,6 +246,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
@@ -389,6 +391,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
@@ -534,6 +537,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 452fc51c..c462aaf 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -92,6 +92,7 @@
           "can_use_on_swarming_builders": true
         }
       },
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
@@ -233,6 +234,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
@@ -382,6 +384,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
@@ -535,6 +538,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
@@ -681,6 +685,7 @@
       "mojo_public_system_unittests",
       "mojo_public_utility_unittests",
       "mojo_system_unittests",
+      "nacl_loader_unittests",
       {
         "test": "net_unittests",
         "swarming": {
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json
index c5e51b6a..c2d7e72 100644
--- a/testing/buildbot/chromium_trybot.json
+++ b/testing/buildbot/chromium_trybot.json
@@ -174,10 +174,7 @@
     "mojo_public_system_unittests",
     "mojo_public_utility_unittests",
     "mojo_system_unittests",
-    {
-      "test": "nacl_loader_unittests",
-      "platforms": ["linux"]
-    },
+    "nacl_loader_unittests",
     {
       "test": "net_unittests",
       "swarming": {
diff --git a/testing/gtest.gyp b/testing/gtest.gyp
index c4510f6..d61772e 100644
--- a/testing/gtest.gyp
+++ b/testing/gtest.gyp
@@ -39,6 +39,7 @@
           'sources': [
             'gtest_mac.h',
             'gtest_mac.mm',
+            'platform_test_mac.mm',
           ],
           'link_settings': {
             'libraries': [
@@ -46,11 +47,6 @@
             ],
           },
         }],
-        ['OS == "mac"', {
-          'sources': [
-            'platform_test_mac.mm',
-          ],
-        }],
         ['OS == "ios"', {
           'dependencies' : [
             '<(DEPTH)/testing/iossim/iossim.gyp:iossim#host',
@@ -85,7 +81,6 @@
           'sources': [
             'coverage_util_ios.cc',
             'coverage_util_ios.h',
-            'platform_test_ios.mm',
           ],
         }],
         ['OS=="ios" and asan==1', {
diff --git a/testing/platform_test_ios.mm b/testing/platform_test_ios.mm
deleted file mode 100644
index 5162c1db..0000000
--- a/testing/platform_test_ios.mm
+++ /dev/null
@@ -1,18 +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.
-
-#include "platform_test.h"
-
-#import <Foundation/Foundation.h>
-
-#include "coverage_util_ios.h"
-
-PlatformTest::PlatformTest()
-    : pool_([[NSAutoreleasePool alloc] init]) {
-}
-
-PlatformTest::~PlatformTest() {
-  [pool_ release];
-  coverage_util::FlushCoverageDataIfNecessary();
-}
diff --git a/testing/test_env.py b/testing/test_env.py
index 0743f34..48cbac9 100755
--- a/testing/test_env.py
+++ b/testing/test_env.py
@@ -35,7 +35,10 @@
 def trim_cmd(cmd):
   """Removes internal flags from cmd since they're just used to communicate from
   the host machine to this script running on the swarm slaves."""
-  internal_flags = frozenset(['--asan=0', '--asan=1', '--lsan=0', '--lsan=1'])
+  sanitizers = ['asan', 'lsan', 'msan', 'tsan']
+  internal_flags = frozenset('--%s=%d' % (name, value)
+                             for name in sanitizers
+                             for value in [0, 1])
   return [i for i in cmd if i not in internal_flags]
 
 
@@ -49,12 +52,12 @@
   return out
 
 
-def get_asan_env(cmd, lsan):
-  """Returns the envirnoment flags needed for ASan and LSan."""
+def get_sanitizer_env(cmd, asan, lsan, msan, tsan):
+  """Returns the envirnoment flags needed for sanitizer tools."""
 
   extra_env = {}
 
-  # Instruct GTK to use malloc while running ASan or LSan tests.
+  # Instruct GTK to use malloc while running sanitizer-instrumented tests.
   extra_env['G_SLICE'] = 'always-malloc'
 
   extra_env['NSS_DISABLE_ARENA_FREE_LIST'] = '1'
@@ -65,25 +68,12 @@
   symbolizer_path = os.path.abspath(os.path.join(ROOT_DIR, 'third_party',
       'llvm-build', 'Release+Asserts', 'bin', 'llvm-symbolizer'))
 
-  asan_options = []
-  if lsan:
-    asan_options.append('detect_leaks=1')
-    if sys.platform == 'linux2':
-      # Use the debug version of libstdc++ under LSan. If we don't, there will
-      # be a lot of incomplete stack traces in the reports.
-      extra_env['LD_LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu/debug:'
-
+  if lsan or tsan:
     # LSan is not sandbox-compatible, so we can use online symbolization. In
     # fact, it needs symbolization to be able to apply suppressions.
     symbolization_options = ['symbolize=1',
                              'external_symbolizer_path=%s' % symbolizer_path]
-
-    suppressions_file = os.path.join(ROOT_DIR, 'tools', 'lsan',
-        'suppressions.txt')
-    lsan_options = ['suppressions=%s' % suppressions_file,
-                    'print_suppressions=1']
-    extra_env['LSAN_OPTIONS'] = ' '.join(lsan_options)
-  else:
+  elif asan or msan:
     # ASan uses a script for offline symbolization.
     # Important note: when running ASan with leak detection enabled, we must use
     # the LSan symbolization options above.
@@ -91,16 +81,45 @@
     # Set the path to llvm-symbolizer to be used by asan_symbolize.py
     extra_env['LLVM_SYMBOLIZER_PATH'] = symbolizer_path
 
-  asan_options.extend(symbolization_options)
+  if asan:
+    asan_options = symbolization_options[:]
+    if lsan:
+      asan_options.append('detect_leaks=1')
 
-  extra_env['ASAN_OPTIONS'] = ' '.join(asan_options)
+    extra_env['ASAN_OPTIONS'] = ' '.join(asan_options)
 
-  if sys.platform == 'darwin':
-    isolate_output_dir = os.path.abspath(os.path.dirname(cmd[0]))
-    # This is needed because the test binary has @executable_path embedded in it
-    # it that the OS tries to resolve to the cache directory and not the mapped
-    #  directory.
-    extra_env['DYLD_LIBRARY_PATH'] = str(isolate_output_dir)
+    if sys.platform == 'darwin':
+      isolate_output_dir = os.path.abspath(os.path.dirname(cmd[0]))
+      # This is needed because the test binary has @executable_path embedded in
+      # it that the OS tries to resolve to the cache directory and not the
+      # mapped directory.
+      extra_env['DYLD_LIBRARY_PATH'] = str(isolate_output_dir)
+
+  if lsan:
+    if asan or msan:
+      lsan_options = []
+    else:
+      lsan_options = symbolization_options[:]
+    if sys.platform == 'linux2':
+      # Use the debug version of libstdc++ under LSan. If we don't, there will
+      # be a lot of incomplete stack traces in the reports.
+      extra_env['LD_LIBRARY_PATH'] = '/usr/lib/x86_64-linux-gnu/debug:'
+
+    suppressions_file = os.path.join(ROOT_DIR, 'tools', 'lsan',
+        'suppressions.txt')
+    lsan_options += ['suppressions=%s' % suppressions_file,
+                     'print_suppressions=1']
+    extra_env['LSAN_OPTIONS'] = ' '.join(lsan_options)
+
+  if msan:
+    msan_options = symbolization_options[:]
+    if lsan:
+      msan_options.append('detect_leaks=1')
+    extra_env['MSAN_OPTIONS'] = ' '.join(msan_options)
+
+  if tsan:
+    tsan_options = symbolization_options[:]
+    extra_env['TSAN_OPTIONS'] = ' '.join(tsan_options)
 
   return extra_env
 
@@ -159,15 +178,17 @@
   # Copy logic from  tools/build/scripts/slave/runtest.py.
   asan = '--asan=1' in cmd
   lsan = '--lsan=1' in cmd
-  use_symbolization_script = asan and not lsan
+  msan = '--msan=1' in cmd
+  tsan = '--tsan=1' in cmd
+  use_symbolization_script = (asan or msan) and not lsan
 
-  if asan:
-    extra_env.update(get_asan_env(cmd, lsan))
-    # ASan is not yet sandbox-friendly on Windows (http://crbug.com/382867).
-    if sys.platform == 'win32':
+  if asan or lsan or msan or tsan:
+    extra_env.update(get_sanitizer_env(cmd, asan, lsan, msan, tsan))
+
+  if lsan or tsan or (asan and sys.platform == 'win32'):
+      # ASan is not yet sandbox-friendly on Windows (http://crbug.com/382867).
+      # LSan and TSan are not sandbox-friendly.
       cmd.append('--no-sandbox')
-  if lsan:
-    cmd.append('--no-sandbox')
 
   cmd = trim_cmd(cmd)
 
diff --git a/third_party/boringssl/boringssl.gypi b/third_party/boringssl/boringssl.gypi
index 2691ef8..0750678 100644
--- a/third_party/boringssl/boringssl.gypi
+++ b/third_party/boringssl/boringssl.gypi
@@ -331,6 +331,7 @@
       'linux-arm/crypto/sha/sha256-armv4.S',
       'linux-arm/crypto/sha/sha512-armv4.S',
       'src/crypto/chacha/chacha_vec_arm.S',
+      'src/crypto/cpu-arm-asm.S',
       'src/crypto/poly1305/poly1305_arm_asm.S',
     ],
     'boringssl_linux_x86_sources': [
diff --git a/third_party/boringssl/update_gypi_and_asm.py b/third_party/boringssl/update_gypi_and_asm.py
index 476e42fde..db11e647 100644
--- a/third_party/boringssl/update_gypi_and_asm.py
+++ b/third_party/boringssl/update_gypi_and_asm.py
@@ -29,6 +29,7 @@
     ('linux', 'arm'): [
         'src/crypto/poly1305/poly1305_arm_asm.S',
         'src/crypto/chacha/chacha_vec_arm.S',
+        'src/crypto/cpu-arm-asm.S',
     ],
 }
 
diff --git a/third_party/google_input_tools/README.chromium b/third_party/google_input_tools/README.chromium
index 026f2a63f..3ae0a96b5 100644
--- a/third_party/google_input_tools/README.chromium
+++ b/third_party/google_input_tools/README.chromium
@@ -2,7 +2,7 @@
 Short Name: google_input_tools
 URL: https://github.com/googlei18n/google-input-tools.git
 Version: 1.0.6.0
-Revision: @9682ab568163879e00499bd94937016426afddfb
+Revision: @30ffaf3940d79fe88160fa2d3eccb5134953481a
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/google_input_tools/inputview.gypi b/third_party/google_input_tools/inputview.gypi
index 3c27b66..82a68ac3 100644
--- a/third_party/google_input_tools/inputview.gypi
+++ b/third_party/google_input_tools/inputview.gypi
@@ -25,6 +25,7 @@
       'src/chrome/os/inputview/direction.js',
       'src/chrome/os/inputview/dom.js',
       'src/chrome/os/inputview/elements/content/altdataview.js',
+      'src/chrome/os/inputview/elements/content/backspacekey.js',
       'src/chrome/os/inputview/elements/content/candidate.js',
       'src/chrome/os/inputview/elements/content/candidatebutton.js',
       'src/chrome/os/inputview/elements/content/candidateview.js',
@@ -50,10 +51,13 @@
       'src/chrome/os/inputview/elements/content/menuview.js',
       'src/chrome/os/inputview/elements/content/modifierkey.js',
       'src/chrome/os/inputview/elements/content/morekeysshiftoperation.js',
+      'src/chrome/os/inputview/elements/content/selectview.js',
       'src/chrome/os/inputview/elements/content/softkey.js',
       'src/chrome/os/inputview/elements/content/spacekey.js',
+      'src/chrome/os/inputview/elements/content/swipeview.js',
       'src/chrome/os/inputview/elements/content/switcherkey.js',
       'src/chrome/os/inputview/elements/content/tabbarkey.js',
+      'src/chrome/os/inputview/elements/content/toolbarbutton.js',
       'src/chrome/os/inputview/elements/content/voiceview.js',
       'src/chrome/os/inputview/elements/element.js',
       'src/chrome/os/inputview/elements/elementtype.js',
@@ -66,6 +70,7 @@
       'src/chrome/os/inputview/emojitype.js',
       'src/chrome/os/inputview/events.js',
       'src/chrome/os/inputview/events/keycodes.js',
+      'src/chrome/os/inputview/globalflags.js',
       'src/chrome/os/inputview/globalsettings.js',
       'src/chrome/os/inputview/handler/pointeractionbundle.js',
       'src/chrome/os/inputview/handler/pointerhandler.js',
@@ -92,8 +97,6 @@
       'src/chrome/os/inputview/readystate.js',
       'src/chrome/os/inputview/settings.js',
       'src/chrome/os/inputview/sizespec.js',
-      'src/chrome/os/inputview/soundcontroller.js',
-      'src/chrome/os/inputview/sounds.js',
       'src/chrome/os/inputview/specnodename.js',
       'src/chrome/os/inputview/statemanager.js',
       'src/chrome/os/inputview/statetype.js',
@@ -109,6 +112,8 @@
       'src/chrome/os/message/event.js',
       'src/chrome/os/message/name.js',
       'src/chrome/os/message/type.js',
+      'src/chrome/os/soundcontroller.js',
+      'src/chrome/os/sounds.js',
       'src/chrome/os/statistics.js',
       'third_party/closure_library/closure/goog/a11y/aria/announcer.js',
       'third_party/closure_library/closure/goog/a11y/aria/aria.js',
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json
index 6b7399c..8bde55a 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/am/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u12c8\u12f0 \u12e8\u130d\u120d \u1218\u12dd\u1308\u1260 \u1243\u120b\u1275 \u12a0\u12ad\u120d"
+  },
   "advanced": {
     "message": "\u12e8\u120b\u1240"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u12e8\u1235\u1353\u1292\u123d\u129b \u1241\u120d\u134d \u1230\u120c\u12f3 \u1245\u1295\u1265\u122e\u127d \u1308\u133d"
   },
+  "expand": {
+    "message": "\u12d8\u122d\u130b"
+  },
+  "expand_candidates": {
+    "message": "\u12e8\u12d5\u1329 \u12dd\u122d\u12dd\u122d\u1295 \u12d8\u122d\u130b"
+  },
   "fi_fin_settings_page": {
     "message": "\u12e8\u134a\u1295\u120b\u1295\u12f5\u129b \u1241\u120d\u134d \u1230\u120c\u12f3 \u1245\u1295\u1265\u122e\u127d \u1308\u133d"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u12e8\u1264\u120b\u1229\u1235\u129b \u1241\u120d\u134d \u1230\u120c\u12f3 \u1245\u1295\u1265\u122e\u127d \u1308\u133d"
   },
+  "ignore_correction": {
+    "message": "\u1208\u121a\u12a8\u1270\u1208\u12cd \u12a5\u122d\u121b\u1276\u127d\u1295 \u127d\u120b \u1260\u120d"
+  },
   "il_heb_settings_page": {
     "message": "\u12e8\u12a5\u1265\u122b\u12ed\u1235\u1325 \u1241\u120d\u134d \u1230\u120c\u12f3 \u1245\u1295\u1265\u122e\u127d \u1308\u133d"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u12e8\u122e\u121b\u1292\u12eb\u129b \u1241\u120d\u134d \u1230\u120c\u12f3"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u12e8\u122e\u121b\u1292\u12eb \u1218\u12f0\u1260\u129b \u12e8\u1241\u120d\u134d \u1230\u120c\u12f3"
   },
   "keyboard_russian": {
     "message": "\u12e8\u1229\u1232\u12eb\u129b \u1241\u120d\u134d \u1230\u120c\u12f3"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u12e8\u1235\u12ca\u12f2\u1295\u129b \u1241\u120d\u134d \u1230\u120c\u12f3 \u1245\u1295\u1265\u122e\u127d \u1308\u133d"
   },
+  "settings": {
+    "message": "\u1245\u1295\u1265\u122e\u127d"
+  },
   "shift": {
     "message": "\u1218\u1240\u12e8\u122a\u12eb"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u12e8Hangul \u12a0\u1235\u1270\u12eb\u12e8\u1275 \u1325\u1246\u121b\u12ce\u127d\u1295 \u12a0\u1233\u12ed"
   },
+  "shrink_candidates": {
+    "message": "\u12e8\u12d5\u1329 \u12dd\u122d\u12dd\u122d\u1295 \u12d8\u122d\u130b"
+  },
   "si_slv_settings_page": {
     "message": "\u12e8\u1235\u120e\u126b\u1295\u12eb\u129b \u1241\u120d\u134d \u1230\u120c\u12f3 \u1245\u1295\u1265\u122e\u127d \u1308\u133d"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u12e8\u1270\u1218\u1228\u1321\u1275\u1295 \u12a0\u1235\u12c8\u130d\u12f5"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u12a0\u1235\u1240\u121d\u1325"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json
index 090167f9..39b778e6 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ar/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0627\u0644\u0625\u0636\u0627\u0641\u0629 \u0625\u0644\u0649 \u0627\u0644\u0642\u0627\u0645\u0648\u0633 \u0627\u0644\u0634\u062e\u0635\u064a"
+  },
   "advanced": {
     "message": "\u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0645\u062a\u0642\u062f\u0645\u0629"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0635\u0641\u062d\u0629 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0625\u0633\u0628\u0627\u0646\u064a\u0629"
   },
+  "expand": {
+    "message": "\u062a\u0648\u0633\u064a\u0639"
+  },
+  "expand_candidates": {
+    "message": "\u062a\u0648\u0633\u064a\u0639 \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0631\u0634\u062d\u064a\u0646"
+  },
   "fi_fin_settings_page": {
     "message": "\u0635\u0641\u062d\u0629 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0642\u0637\u0627\u0644\u0648\u0646\u064a\u0629"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0635\u0641\u062d\u0629 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0623\u064a\u0631\u0644\u0646\u062f\u064a\u0629"
   },
+  "ignore_correction": {
+    "message": "\u062a\u062c\u0627\u0647\u0644 \u062a\u0635\u062d\u064a\u062d \u0644\u0640"
+  },
   "il_heb_settings_page": {
     "message": "\u0635\u0641\u062d\u0629 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0639\u0628\u0631\u064a\u0629"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0631\u0648\u0645\u0627\u0646\u064a\u0629"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0631\u0648\u0645\u0627\u0646\u064a\u0629 \u0627\u0644\u0642\u064a\u0627\u0633\u064a\u0629"
   },
   "keyboard_russian": {
     "message": "\u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0631\u0648\u0633\u064a\u0629"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0635\u0641\u062d\u0629 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0633\u0648\u064a\u062f\u064a\u0629"
   },
+  "settings": {
+    "message": "\u0625\u0639\u062f\u0627\u062f\u0627\u062a"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0639\u0631\u0636 \u0627\u0642\u062a\u0631\u0627\u062d\u0627\u062a \u0627\u0644\u0647\u0627\u0646\u063a\u0648\u0644"
   },
+  "shrink_candidates": {
+    "message": "\u062a\u0642\u0644\u064a\u0635 \u0642\u0627\u0626\u0645\u0629 \u0627\u0644\u0645\u0631\u0634\u062d\u064a\u0646"
+  },
   "si_slv_settings_page": {
     "message": "\u0635\u0641\u062d\u0629 \u0625\u0639\u062f\u0627\u062f\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0627\u0644\u0633\u0644\u0648\u0641\u0627\u0646\u064a\u0629"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u0645\u062e\u062a\u0627\u0631\u0629"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u062d\u0641\u0638"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json
index 3fc8910..7c23209 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bg/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043a\u044a\u043c \u043b\u0438\u0447\u043d\u0438\u044f \u0440\u0435\u0447\u043d\u0438\u043a"
+  },
   "advanced": {
     "message": "\u0420\u0430\u0437\u0448\u0438\u0440\u0435\u043d\u0438"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0437\u0430 \u0438\u0441\u043f\u0430\u043d\u0441\u043a\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
+  "expand": {
+    "message": "\u0420\u0430\u0437\u0433\u044a\u0432\u0430\u043d\u0435"
+  },
+  "expand_candidates": {
+    "message": "\u0440\u0430\u0437\u0433\u044a\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u043f\u0438\u0441\u044a\u043a\u0430 \u0441 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f"
+  },
   "fi_fin_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0437\u0430 \u0444\u0438\u043d\u043b\u0430\u043d\u0434\u0441\u043a\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0437\u0430 \u0438\u0440\u043b\u0430\u043d\u0434\u0441\u043a\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
+  "ignore_correction": {
+    "message": "\u041f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0433\u0432\u0430\u043d\u0435 \u043d\u0430 \u043a\u043e\u0440\u0435\u043a\u0446\u0438\u044f\u0442\u0430 \u0437\u0430"
+  },
   "il_heb_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0437\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430\u0442\u0430 \u043d\u0430 \u0438\u0432\u0440\u0438\u0442"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0420\u0443\u043c\u044a\u043d\u0441\u043a\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0420\u0443\u043c\u044a\u043d\u0441\u043a\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
   "keyboard_russian": {
     "message": "\u0420\u0443\u0441\u043a\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0437\u0430 \u0448\u0432\u0435\u0434\u0441\u043a\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
+  "settings": {
+    "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u041f\u043e\u043a\u0430\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0445\u0430\u043d\u0433\u044a\u043b"
   },
+  "shrink_candidates": {
+    "message": "\u0441\u0432\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u043f\u0438\u0441\u044a\u043a\u0430 \u0441 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f"
+  },
   "si_slv_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0437\u0430 \u0441\u043b\u043e\u0432\u0435\u043d\u0441\u043a\u0430\u0442\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u041f\u0440\u0435\u043c\u0430\u0445\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0431\u0440\u0430\u043d\u043e\u0442\u043e"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0417\u0430\u043f\u0430\u0437\u0432\u0430\u043d\u0435"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json
index 600d640..d1fbac5 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/bn/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u09ac\u09cd\u09af\u0995\u09cd\u09a4\u09bf\u0997\u09a4 \u0985\u09ad\u09bf\u09a7\u09be\u09a8\u09c7 \u09af\u09cb\u0997 \u0995\u09b0\u09c1\u09a8"
+  },
   "advanced": {
     "message": "\u0989\u09a8\u09cd\u09a8\u09a4"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u09b8\u09cd\u09aa\u09cd\u09af\u09be\u09a8\u09bf\u09b6 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be"
   },
+  "expand": {
+    "message": "\u09aa\u09cd\u09b0\u09b8\u09be\u09b0\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8"
+  },
+  "expand_candidates": {
+    "message": "\u09aa\u09cd\u09b0\u09be\u09b0\u09cd\u09a5\u09c0 \u09a4\u09be\u09b2\u09bf\u0995\u09be \u09aa\u09cd\u09b0\u09b8\u09be\u09b0\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8"
+  },
   "fi_fin_settings_page": {
     "message": "\u09ab\u09bf\u09a8\u09bf\u09b6 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0986\u0987\u09b0\u09bf\u09b6 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be"
   },
+  "ignore_correction": {
+    "message": "\u098f\u09b0 \u099c\u09a8\u09cd\u09af \u0995\u09b0\u09be \u09b8\u0982\u09b6\u09cb\u09a7\u09a8 \u0989\u09aa\u09c7\u0995\u09cd\u09b7\u09be \u0995\u09b0\u09c1\u09a8"
+  },
   "il_heb_settings_page": {
     "message": "\u09b9\u09bf\u09ac\u09cd\u09b0\u09c1 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u09b0\u09cb\u09ae\u09be\u09a8\u09bf\u09df \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u09b0\u09cb\u09ae\u09be\u09a8\u09bf\u09af\u09bc\u09be\u09a8 \u0986\u09a6\u09b0\u09cd\u09b6 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1"
   },
   "keyboard_russian": {
     "message": "\u09b0\u09be\u09b6\u09bf\u09df\u09be\u09a8 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u09b8\u09c1\u0987\u09a1\u09bf\u09b6 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be"
   },
+  "settings": {
+    "message": "\u09b8\u09c7\u099f\u09bf\u0982\u09b8"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u09b9\u09be\u0999\u09cd\u0997\u09c1\u09b2 \u09aa\u09cd\u09b0\u09b8\u09cd\u09a4\u09be\u09ac\u09a8\u09be\u0997\u09c1\u09b2\u09bf \u09a6\u09c7\u0996\u09be\u09a8"
   },
+  "shrink_candidates": {
+    "message": "\u09aa\u09cd\u09b0\u09be\u09b0\u09cd\u09a5\u09c0 \u09a4\u09be\u09b2\u09bf\u0995\u09be \u09b8\u0999\u09cd\u0995\u09c1\u099a\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8"
+  },
   "si_slv_settings_page": {
     "message": "\u09b8\u09cd\u09b2\u09cb\u09ad\u09c7\u09a8\u09bf\u09af\u09bc \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u09a8\u09bf\u09b0\u09cd\u09ac\u09be\u099a\u09bf\u09a4 \u09b8\u09b0\u09be\u09a8"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u09b8\u0982\u09b0\u0995\u09cd\u09b7\u09a3 \u0995\u09b0\u09c1\u09a8"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json
index 72ad907e..5af81f0 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ca/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Afegeix al diccionari personal"
+  },
   "advanced": {
     "message": "Avan\u00e7ada"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "P\u00e0gina de configuraci\u00f3 del teclat espanyol"
   },
+  "expand": {
+    "message": "Amplia"
+  },
+  "expand_candidates": {
+    "message": "amplia la llista de candidats"
+  },
   "fi_fin_settings_page": {
     "message": "P\u00e0gina de configuraci\u00f3 del teclat fin\u00e8s"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "P\u00e0gina de configuraci\u00f3 del teclat irland\u00e8s"
   },
+  "ignore_correction": {
+    "message": "Ignora la correcci\u00f3 de"
+  },
   "il_heb_settings_page": {
     "message": "P\u00e0gina de configuraci\u00f3 del teclat hebreu"
   },
@@ -2847,7 +2859,7 @@
     "message": "Teclat roman\u00e8s"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Teclat est\u00e0ndard roman\u00e8s"
   },
   "keyboard_russian": {
     "message": "Teclat rus"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "P\u00e0gina de configuraci\u00f3 del teclat suec"
   },
+  "settings": {
+    "message": "Configuraci\u00f3"
+  },
   "shift": {
     "message": "maj"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Mostra suggeriments d'hangul"
   },
+  "shrink_candidates": {
+    "message": "redueix la llista de candidats"
+  },
   "si_slv_settings_page": {
     "message": "P\u00e0gina de configuraci\u00f3 del teclat eslov\u00e8"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Suprimeix les seleccionades"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Desa"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json
index 2c689a8..72dffcc 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/cs/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "P\u0159idat do osobn\u00edho slovn\u00edku"
+  },
   "advanced": {
     "message": "Roz\u0161\u00ed\u0159en\u00e1 nastaven\u00ed"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Str\u00e1nka nastaven\u00ed \u0161pan\u011blsk\u00e9 kl\u00e1vesnice"
   },
+  "expand": {
+    "message": "Rozbalit"
+  },
+  "expand_candidates": {
+    "message": "rozbalit seznam kandid\u00e1t\u016f"
+  },
   "fi_fin_settings_page": {
     "message": "Str\u00e1nka nastaven\u00ed finsk\u00e9 kl\u00e1vesnice"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Str\u00e1nka nastaven\u00ed irsk\u00e9 kl\u00e1vesnice"
   },
+  "ignore_correction": {
+    "message": "Ignorovat opravu pro"
+  },
   "il_heb_settings_page": {
     "message": "Str\u00e1nka nastaven\u00ed hebrejsk\u00e9 kl\u00e1vesnice"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rumunsk\u00e1 kl\u00e1vesnice"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Standardn\u00ed rumunsk\u00e1 kl\u00e1vesnice"
   },
   "keyboard_russian": {
     "message": "Rusk\u00e1 kl\u00e1vesnice"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Str\u00e1nka nastaven\u00ed \u0161v\u00e9dsk\u00e9 kl\u00e1vesnice"
   },
+  "settings": {
+    "message": "Nastaven\u00ed"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Zobrazovat n\u00e1vrhy korejsk\u00e9ho p\u00edsma"
   },
+  "shrink_candidates": {
+    "message": "sbalit seznam kandid\u00e1t\u016f"
+  },
   "si_slv_settings_page": {
     "message": "Str\u00e1nka nastaven\u00ed slovinsk\u00e9 kl\u00e1vesnice"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Odstranit vybran\u00e9"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Ulo\u017eit"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json
index 8543fe3..f928550 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/da/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "F\u00f8j til personlig ordbog"
+  },
   "advanced": {
     "message": "Avanceret"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Side med indstillinger for spansk tastatur"
   },
+  "expand": {
+    "message": "Udvid"
+  },
+  "expand_candidates": {
+    "message": "udvid kandidatlisten"
+  },
   "fi_fin_settings_page": {
     "message": "Side med indstillinger for finsk tastatur"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Side med indstillinger for irsk tastatur"
   },
+  "ignore_correction": {
+    "message": "Ignorer rettelsen af"
+  },
   "il_heb_settings_page": {
     "message": "Side med indstillinger for hebraisk tastatur"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rum\u00e6nsk tastatur"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rum\u00e6nsk standardtastatur"
   },
   "keyboard_russian": {
     "message": "Russisk tastatur"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Side med indstillinger for svensk tastatur"
   },
+  "settings": {
+    "message": "Indstillinger"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Vis forslag p\u00e5 hangul"
   },
+  "shrink_candidates": {
+    "message": "g\u00f8r kandidatlisten mindre"
+  },
   "si_slv_settings_page": {
     "message": "Side med indstillinger for slovensk tastatur"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Fjern markering"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Gem"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json
index 22eda943..9d8bf655 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/de/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "In pers\u00f6nliches W\u00f6rterbuch aufnehmen"
+  },
   "advanced": {
     "message": "Erweitert"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Seite mit Einstellungen f\u00fcr spanische Tastatur"
   },
+  "expand": {
+    "message": "Maximieren"
+  },
+  "expand_candidates": {
+    "message": "Kandidatenliste maximieren"
+  },
   "fi_fin_settings_page": {
     "message": "Seite mit Einstellungen f\u00fcr finnische Tastatur"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Seite mit Einstellungen f\u00fcr irische Tastatur"
   },
+  "ignore_correction": {
+    "message": "Korrektur ignorieren f\u00fcr"
+  },
   "il_heb_settings_page": {
     "message": "Seite mit Einstellungen f\u00fcr hebr\u00e4ische Tastatur"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rum\u00e4nische Tastatur"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rum\u00e4nische Standardtastatur"
   },
   "keyboard_russian": {
     "message": "Russische Tastatur"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Seite mit Einstellungen f\u00fcr schwedische Tastatur"
   },
+  "settings": {
+    "message": "Einstellungen"
+  },
   "shift": {
     "message": "Umschalttaste"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Hangul-Vorschl\u00e4ge anzeigen"
   },
+  "shrink_candidates": {
+    "message": "Kandidatenliste minimieren"
+  },
   "si_slv_settings_page": {
     "message": "Seite mit Einstellungen f\u00fcr slowenische Tastatur"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Auswahl entfernen"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Speichern"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json
index f274d422..58b4d65 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/el/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03c3\u03c4\u03bf \u03c0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03cc \u03bb\u03b5\u03be\u03b9\u03ba\u03cc"
+  },
   "advanced": {
     "message": "\u03a3\u03cd\u03bd\u03b8\u03b5\u03c4\u03b5\u03c2"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 \u03b9\u03c3\u03c0\u03b1\u03bd\u03b9\u03ba\u03ce\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd"
   },
+  "expand": {
+    "message": "\u0391\u03bd\u03ac\u03c0\u03c4\u03c5\u03be\u03b7"
+  },
+  "expand_candidates": {
+    "message": "\u03b1\u03bd\u03ac\u03c0\u03c4\u03c5\u03be\u03b7 \u03bb\u03af\u03c3\u03c4\u03b1\u03c2 \u03c5\u03c0\u03bf\u03c8\u03ae\u03c6\u03b9\u03c9\u03bd"
+  },
   "fi_fin_settings_page": {
     "message": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 \u03c6\u03b9\u03bd\u03bb\u03b1\u03bd\u03b4\u03b9\u03ba\u03ce\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 \u03b9\u03c1\u03bb\u03b1\u03bd\u03b4\u03b9\u03ba\u03ce\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd"
   },
+  "ignore_correction": {
+    "message": "\u03a0\u03b1\u03c1\u03ac\u03b2\u03bb\u03b5\u03c8\u03b7 \u03b4\u03b9\u03cc\u03c1\u03b8\u03c9\u03c3\u03b7\u03c2 \u03b3\u03b9\u03b1"
+  },
   "il_heb_settings_page": {
     "message": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 \u03b5\u03b2\u03c1\u03b1\u03ca\u03ba\u03ce\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u03a0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf \u03bc\u03b5 \u03c1\u03bf\u03c5\u03bc\u03b1\u03bd\u03b9\u03ba\u03bf\u03cd\u03c2 \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03b5\u03c2"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u03a4\u03c5\u03c0\u03b9\u03ba\u03cc \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf \u03a1\u03bf\u03c5\u03bc\u03b1\u03bd\u03b9\u03ba\u03ce\u03bd"
   },
   "keyboard_russian": {
     "message": "\u03a0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf \u03bc\u03b5 \u03c1\u03c9\u03c3\u03b9\u03ba\u03bf\u03cd\u03c2 \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03b5\u03c2"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 \u03c3\u03bf\u03c5\u03b7\u03b4\u03b9\u03ba\u03ce\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd"
   },
+  "settings": {
+    "message": "\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c0\u03c1\u03bf\u03c4\u03ac\u03c3\u03b5\u03c9\u03bd \u03a7\u03b1\u03bd\u03b3\u03ba\u03bf\u03cd\u03bb"
   },
+  "shrink_candidates": {
+    "message": "\u03c3\u03cd\u03bc\u03c0\u03c4\u03c5\u03be\u03b7 \u03bb\u03af\u03c3\u03c4\u03b1\u03c2 \u03c5\u03c0\u03bf\u03c8\u03ae\u03c6\u03b9\u03c9\u03bd"
+  },
   "si_slv_settings_page": {
     "message": "\u03a3\u03b5\u03bb\u03af\u03b4\u03b1 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03c9\u03bd \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5 \u03c3\u03bb\u03bf\u03b2\u03b5\u03bd\u03b9\u03ba\u03ce\u03bd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u039a\u03b1\u03c4\u03ac\u03c1\u03b3\u03b7\u03c3\u03b7 \u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03c9\u03bd"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json
index 564113a..724c42c 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Add to personal dictionary"
+  },
   "advanced": {
     "message": "Advanced"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Spanish Keyboard Settings Page"
   },
+  "expand": {
+    "message": "Expand"
+  },
+  "expand_candidates": {
+    "message": "expand candidate list"
+  },
   "fi_fin_settings_page": {
     "message": "Finnish Keyboard Settings Page"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Irish Keyboard Settings Page"
   },
+  "ignore_correction": {
+    "message": "Ignore correction for"
+  },
   "il_heb_settings_page": {
     "message": "Hebrew Keyboard Settings Page"
   },
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Swedish Keyboard Settings Page"
   },
+  "settings": {
+    "message": "Settings"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Show Hangul suggestions"
   },
+  "shrink_candidates": {
+    "message": "shrink candidate list"
+  },
   "si_slv_settings_page": {
     "message": "Slovenian Keyboard Settings Page"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Remove Selected"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Save"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json
index ecec283..90bf9183 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/en_GB/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Add to personal dictionary"
+  },
   "advanced": {
     "message": "Advanced"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Spanish Keyboard Settings Page"
   },
+  "expand": {
+    "message": "Expand"
+  },
+  "expand_candidates": {
+    "message": "expand candidate list"
+  },
   "fi_fin_settings_page": {
     "message": "Finnish Keyboard Settings Page"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Irish Keyboard Settings Page"
   },
+  "ignore_correction": {
+    "message": "Ignore correction for"
+  },
   "il_heb_settings_page": {
     "message": "Hebrew Keyboard Settings Page"
   },
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Swedish Keyboard Settings Page"
   },
+  "settings": {
+    "message": "Settings"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Show Hangul suggestions"
   },
+  "shrink_candidates": {
+    "message": "shrink candidate list"
+  },
   "si_slv_settings_page": {
     "message": "Slovenian Keyboard Settings Page"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Remove Selected"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Save"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json
index 112ab832..767ae62 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "A\u00f1adir a diccionario personal"
+  },
   "advanced": {
     "message": "Avanzada"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado espa\u00f1ol"
   },
+  "expand": {
+    "message": "Ampliar"
+  },
+  "expand_candidates": {
+    "message": "mostrar lista de candidatos"
+  },
   "fi_fin_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado fin\u00e9s"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado irland\u00e9s"
   },
+  "ignore_correction": {
+    "message": "Ignorar correcci\u00f3n de"
+  },
   "il_heb_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado hebreo"
   },
@@ -2847,7 +2859,7 @@
     "message": "Teclado rumano"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Teclado rumano est\u00e1ndar"
   },
   "keyboard_russian": {
     "message": "Teclado ruso"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado sueco"
   },
+  "settings": {
+    "message": "Configuraci\u00f3n"
+  },
   "shift": {
     "message": "may\u00fas"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Mostrar sugerencias de hangul"
   },
+  "shrink_candidates": {
+    "message": "contraer lista de candidatos"
+  },
   "si_slv_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado esloveno"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Eliminar selecci\u00f3n"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Guardar"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json
index 84eabf2..ab90857 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/es_419/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Agregar a diccionario personal"
+  },
   "advanced": {
     "message": "Configuraci\u00f3n avanzada"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado espa\u00f1ol"
   },
+  "expand": {
+    "message": "Expandir"
+  },
+  "expand_candidates": {
+    "message": "ampliar lista de candidatos"
+  },
   "fi_fin_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado fin\u00e9s"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado irland\u00e9s"
   },
+  "ignore_correction": {
+    "message": "Ignorar correcci\u00f3n de"
+  },
   "il_heb_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado hebreo"
   },
@@ -2847,7 +2859,7 @@
     "message": "Teclado rumano"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Teclado est\u00e1ndar rumano"
   },
   "keyboard_russian": {
     "message": "Teclado ruso"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado sueco"
   },
+  "settings": {
+    "message": "Configuraci\u00f3n"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Mostrar sugerencias en hangul"
   },
+  "shrink_candidates": {
+    "message": "reducir lista de candidatos"
+  },
   "si_slv_settings_page": {
     "message": "P\u00e1gina de configuraci\u00f3n del teclado esloveno"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Eliminar selecci\u00f3n"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Guardar"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json
index 7fd017e..d45b93f 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/et/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Isiklikku s\u00f5nastikku lisamine"
+  },
   "advanced": {
     "message": "T\u00e4psemad"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Hispaania klaviatuuri seadete leht"
   },
+  "expand": {
+    "message": "Laienda"
+  },
+  "expand_candidates": {
+    "message": "laienda kandidaatide loendit"
+  },
   "fi_fin_settings_page": {
     "message": "Soome klaviatuuri seadete leht"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Iiri klaviatuuri seadete leht"
   },
+  "ignore_correction": {
+    "message": "Ignoreeri parandust:"
+  },
   "il_heb_settings_page": {
     "message": "Heebrea klaviatuuri seadete leht"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rumeenia klaviatuur"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rumeenia standardne klaviatuur"
   },
   "keyboard_russian": {
     "message": "Vene klaviatuur"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Rootsi klaviatuuri seadete leht"
   },
+  "settings": {
+    "message": "Seaded"
+  },
   "shift": {
     "message": "t\u00f5stuklahv"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Kuva hanguli soovitused"
   },
+  "shrink_candidates": {
+    "message": "kahanda kandidaatide loendit"
+  },
   "si_slv_settings_page": {
     "message": "Sloveenia klaviatuuri seadete leht"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Eemalda valitud"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Salvesta"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json
index 9d6f584..ee2afa3 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fa/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0627\u0641\u0632\u0648\u062f\u0646 \u0628\u0647 \u0641\u0631\u0647\u0646\u06af \u0644\u063a\u062a \u0634\u062e\u0635\u06cc"
+  },
   "advanced": {
     "message": "\u067e\u06cc\u0634\u0631\u0641\u062a\u0647"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0635\u0641\u062d\u0647 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0627\u0633\u067e\u0627\u0646\u06cc\u0627\u06cc\u06cc"
   },
+  "expand": {
+    "message": "\u0628\u0632\u0631\u06af \u06a9\u0631\u062f\u0646"
+  },
+  "expand_candidates": {
+    "message": "\u0628\u0632\u0631\u06af \u06a9\u0631\u062f\u0646 \u0641\u0647\u0631\u0633\u062a \u067e\u06cc\u0634\u0646\u0647\u0627\u062f\u0627\u062a"
+  },
   "fi_fin_settings_page": {
     "message": "\u0635\u0641\u062d\u0647 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0641\u0646\u0644\u0627\u0646\u062f\u06cc"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0635\u0641\u062d\u0647 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0627\u06cc\u0631\u0644\u0646\u062f\u06cc"
   },
+  "ignore_correction": {
+    "message": "\u0646\u0627\u062f\u06cc\u062f\u0647 \u06af\u0631\u0641\u062a\u0646 \u062a\u0635\u062d\u06cc\u062d \u0628\u0631\u0627\u06cc"
+  },
   "il_heb_settings_page": {
     "message": "\u0635\u0641\u062d\u0647 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0639\u0628\u0631\u06cc"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0631\u0648\u0645\u0627\u0646\u06cc\u0627\u06cc\u06cc"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f \u0631\u0648\u0645\u0627\u0646\u06cc\u0627\u06cc\u06cc"
   },
   "keyboard_russian": {
     "message": "\u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0631\u0648\u0633\u06cc"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0635\u0641\u062d\u0647 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0633\u0648\u0626\u062f\u06cc"
   },
+  "settings": {
+    "message": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0646\u0645\u0627\u06cc\u0634 \u067e\u06cc\u0634\u0646\u0647\u0627\u062f\u0627\u062a \u0647\u0627\u0646\u06af\u0648\u0644"
   },
+  "shrink_candidates": {
+    "message": "\u06a9\u0648\u0686\u06a9 \u06a9\u0631\u062f\u0646 \u0641\u0647\u0631\u0633\u062a \u067e\u06cc\u0634\u0646\u0647\u0627\u062f\u0627\u062a"
+  },
   "si_slv_settings_page": {
     "message": "\u0635\u0641\u062d\u0647 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0635\u0641\u062d\u0647\u200c\u06a9\u0644\u06cc\u062f \u0627\u0633\u0644\u0648\u0648\u0646\u06cc\u0627\u06cc\u06cc"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u062d\u0630\u0641 \u0627\u0646\u062a\u062e\u0627\u0628\u200c\u0634\u062f\u0647\u200c\u0647\u0627"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0630\u062e\u06cc\u0631\u0647"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json
index 4303d5f..3fd23275 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fi/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Lis\u00e4\u00e4 omaan sanakirjaan"
+  },
   "advanced": {
     "message": "Lis\u00e4asetukset"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Espanjan n\u00e4pp\u00e4imist\u00f6n asetukset"
   },
+  "expand": {
+    "message": "Laajenna"
+  },
+  "expand_candidates": {
+    "message": "laajenna vaihtoehtoluettelo"
+  },
   "fi_fin_settings_page": {
     "message": "Suomen n\u00e4pp\u00e4imist\u00f6n asetukset"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Irlannin iirinkielisen n\u00e4pp\u00e4imist\u00f6n asetukset"
   },
+  "ignore_correction": {
+    "message": "\u00c4l\u00e4 korjaa:"
+  },
   "il_heb_settings_page": {
     "message": "Hepreankielisen n\u00e4pp\u00e4imist\u00f6n asetukset"
   },
@@ -2847,7 +2859,7 @@
     "message": "N\u00e4pp\u00e4imist\u00f6: romania"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Romanialainen vakion\u00e4pp\u00e4imist\u00f6"
   },
   "keyboard_russian": {
     "message": "N\u00e4pp\u00e4imist\u00f6: ven\u00e4j\u00e4"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Ruotsin n\u00e4pp\u00e4imist\u00f6n asetukset"
   },
+  "settings": {
+    "message": "Asetukset"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "N\u00e4yt\u00e4 Hangul-ehdotukset"
   },
+  "shrink_candidates": {
+    "message": "pienenn\u00e4 vaihtoehtoluettelo"
+  },
   "si_slv_settings_page": {
     "message": "Slovenian n\u00e4pp\u00e4imist\u00f6n asetukset"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Poista valitut"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Tallenna"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json
index d15aad8d6..e7a294a 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fil/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Idagdag sa personal na diksyunaryo"
+  },
   "advanced": {
     "message": "Advanced"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Page ng Mga Setting ng Spanish na Keyboard"
   },
+  "expand": {
+    "message": "Palawakin"
+  },
+  "expand_candidates": {
+    "message": "palawakin ang listahan ng kandidato"
+  },
   "fi_fin_settings_page": {
     "message": "Page ng Mga Setting ng Finnish na Keyboard"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Page ng Mga Setting ng Irish na Keyboard"
   },
+  "ignore_correction": {
+    "message": "Huwag pansinin ang pagwawasto para sa"
+  },
   "il_heb_settings_page": {
     "message": "Page ng Mga Setting ng Hebrew na Keyboard"
   },
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Page ng Mga Setting ng Swedish na Keyboard"
   },
+  "settings": {
+    "message": "Mga Setting"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Ipakita ang mga suhestyon sa Hangul"
   },
+  "shrink_candidates": {
+    "message": "paliitin ang listahan ng kandidato"
+  },
   "si_slv_settings_page": {
     "message": "Page ng Mga Setting ng Slovenian na Keyboard"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Alisin ang Napili"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "I-save"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json
index 59f4cd2..b8dcbab 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/fr/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Ajouter au dictionnaire personnel"
+  },
   "advanced": {
     "message": "Param\u00e8tres avanc\u00e9s"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Page des param\u00e8tres du clavier espagnol"
   },
+  "expand": {
+    "message": "D\u00e9velopper"
+  },
+  "expand_candidates": {
+    "message": "d\u00e9velopper la liste des propositions"
+  },
   "fi_fin_settings_page": {
     "message": "Page des param\u00e8tres du clavier finnois"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Page des param\u00e8tres du clavier irlandais"
   },
+  "ignore_correction": {
+    "message": "Ignorer la correction pour"
+  },
   "il_heb_settings_page": {
     "message": "Page des param\u00e8tres du clavier h\u00e9breu"
   },
@@ -2847,7 +2859,7 @@
     "message": "Clavier roumain"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Clavier roumain standard"
   },
   "keyboard_russian": {
     "message": "Clavier russe"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Page des param\u00e8tres du clavier su\u00e9dois"
   },
+  "settings": {
+    "message": "Param\u00e8tres"
+  },
   "shift": {
     "message": "maj"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Afficher les suggestions en hang\u00fbl"
   },
+  "shrink_candidates": {
+    "message": "r\u00e9duire la liste des propositions"
+  },
   "si_slv_settings_page": {
     "message": "Page des param\u00e8tres du clavier slov\u00e8ne"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Supprimer la s\u00e9lection"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Enregistrer"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json
index 2173ddb..dc80c641 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/gu/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0ab5\u0acd\u0aaf\u0a95\u0acd\u0aa4\u0abf\u0a97\u0aa4 \u0ab6\u0aac\u0acd\u0aa6\u0a95\u0acb\u0ab6\u0aae\u0abe\u0a82 \u0a89\u0aae\u0ac7\u0ab0\u0acb"
+  },
   "advanced": {
     "message": "\u0ab5\u0abf\u0a97\u0aa4\u0ab5\u0abe\u0ab0"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0ab8\u0acd\u0aaa\u0ac7\u0aa8\u0abf\u0ab6 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0"
   },
+  "expand": {
+    "message": "\u0ab5\u0abf\u0ab8\u0acd\u0aa4\u0ac3\u0aa4 \u0a95\u0ab0\u0acb"
+  },
+  "expand_candidates": {
+    "message": "\u0a89\u0aae\u0ac7\u0aa6\u0ab5\u0abe\u0ab0\u0acb\u0aa8\u0ac0 \u0ab8\u0ac2\u0a9a\u0abf \u0ab5\u0abf\u0ab8\u0acd\u0aa4\u0ac3\u0aa4 \u0a95\u0ab0\u0acb"
+  },
   "fi_fin_settings_page": {
     "message": "\u0aab\u0abf\u0aa8\u0abf\u0ab6 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0a86\u0a87\u0ab0\u0abf\u0ab6 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0"
   },
+  "ignore_correction": {
+    "message": "\u0a86 \u0aae\u0abe\u0a9f\u0ac7\u0aa8\u0abe \u0ab8\u0ac1\u0aa7\u0abe\u0ab0\u0aa8\u0ac7 \u0a85\u0ab5\u0a97\u0aa3\u0acb"
+  },
   "il_heb_settings_page": {
     "message": "\u0ab9\u0ac0\u0aac\u0acd\u0ab0\u0ac1 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0ab0\u0acb\u0aae\u0ac7\u0aa8\u0abf\u0aaf\u0aa8 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0ab0\u0acb\u0aae\u0abe\u0aa8\u0abf\u0aaf\u0aa8 \u0aae\u0abe\u0aa8\u0a95 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1"
   },
   "keyboard_russian": {
     "message": "\u0ab0\u0ab6\u0abf\u0aaf\u0aa8 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0ab8\u0acd\u0ab5\u0ac0\u0aa1\u0abf\u0ab6 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0"
   },
+  "settings": {
+    "message": "\u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0ab9\u0a82\u0a97\u0ac1\u0ab2 \u0ab8\u0ac2\u0a9a\u0aa8\u0acb \u0aa6\u0ab0\u0acd\u0ab6\u0abe\u0ab5\u0acb"
   },
+  "shrink_candidates": {
+    "message": "\u0a89\u0aae\u0ac7\u0aa6\u0ab5\u0abe\u0ab0\u0acb\u0aa8\u0ac0 \u0ab8\u0ac2\u0a9a\u0abf \u0ab8\u0a82\u0a95\u0acb\u0a9a\u0abf\u0aa4 \u0a95\u0ab0\u0acb"
+  },
   "si_slv_settings_page": {
     "message": "\u0ab8\u0acd\u0ab2\u0acb\u0ab5\u0ac7\u0aa8\u0abf\u0aaf\u0aa8 \u0a95\u0ac0\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac3\u0ab7\u0acd\u0aa0"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0aaa\u0ab8\u0a82\u0aa6 \u0a95\u0ab0\u0ac7\u0ab2\u0ac1\u0a82 \u0aa6\u0ac2\u0ab0 \u0a95\u0ab0\u0acb"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0ab8\u0abe\u0a9a\u0ab5\u0acb"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json
index 1c88905c..57e1f6c 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hi/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0935\u094d\u092f\u0915\u094d\u0924\u093f\u0917\u0924 \u0936\u092c\u094d\u0926\u0915\u094b\u0936 \u092e\u0947\u0902 \u091c\u094b\u0921\u093c\u0947\u0902"
+  },
   "advanced": {
     "message": "\u0909\u0928\u094d\u0928\u0924"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0938\u094d\u200d\u092a\u0947\u0928\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917 \u092a\u0943\u0937\u094d\u200d\u0920"
   },
+  "expand": {
+    "message": "\u0935\u093f\u0938\u094d\u0924\u0943\u0924 \u0915\u0930\u0947\u0902"
+  },
+  "expand_candidates": {
+    "message": "\u0909\u092e\u094d\u092e\u0940\u0926\u0935\u093e\u0930 \u0938\u0942\u091a\u0940 \u0935\u093f\u0938\u094d\u0924\u0943\u0924 \u0915\u0930\u0947\u0902"
+  },
   "fi_fin_settings_page": {
     "message": "\u092b\u093c\u093f\u0928\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917 \u092a\u0943\u0937\u094d\u200d\u0920"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0906\u092f\u0930\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917 \u092a\u0943\u0937\u094d\u200d\u0920"
   },
+  "ignore_correction": {
+    "message": "\u0907\u0938\u0915\u0947 \u0932\u093f\u090f \u0938\u0941\u0927\u093e\u0930 \u092a\u0930 \u0927\u094d\u092f\u093e\u0928 \u0928 \u0926\u0947\u0902"
+  },
   "il_heb_settings_page": {
     "message": "\u0939\u093f\u092c\u094d\u0930\u0942 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917 \u092a\u0943\u0937\u094d\u200d\u0920"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0930\u094b\u092e\u093e\u0928\u093f\u092f\u093e\u0908 \u0915\u0940\u092c\u094b\u0930\u094d\u0921"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0930\u094b\u092e\u093e\u0928\u093f\u092f\u093e\u0908 \u092e\u093e\u0928\u0915 \u0915\u0940\u092c\u094b\u0930\u094d\u0921"
   },
   "keyboard_russian": {
     "message": "\u0930\u0942\u0938\u0940 \u0915\u0940\u092c\u094b\u0930\u094d\u0921"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0938\u094d\u200d\u0935\u0940\u0921\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917 \u092a\u0943\u0937\u094d\u200d\u0920"
   },
+  "settings": {
+    "message": "\u0938\u0947\u091f\u093f\u0902\u0917"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0939\u0902\u0917\u0941\u0932 \u0938\u0941\u091d\u093e\u0935 \u0926\u093f\u0916\u093e\u090f\u0902"
   },
+  "shrink_candidates": {
+    "message": "\u0909\u092e\u094d\u092e\u0940\u0926\u0935\u093e\u0930 \u0938\u0942\u091a\u0940 \u091b\u094b\u091f\u0940 \u0915\u0930\u0947\u0902"
+  },
   "si_slv_settings_page": {
     "message": "\u0938\u094d\u200d\u0932\u094b\u0935\u0947\u0928\u093f\u092f\u093e\u0908 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917 \u092a\u0943\u0937\u094d\u200d\u0920"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u091a\u092f\u0928\u093f\u0924 \u0915\u094b \u0928\u093f\u0915\u093e\u0932\u0947\u0902"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0938\u0939\u0947\u091c\u0947\u0902"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json
index f2d5a57..20d6c0e 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hr/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Dodaj u osobni rje\u010dnik"
+  },
   "advanced": {
     "message": "Napredno"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Stranica postavki \u0161panjolske tipkovnice"
   },
+  "expand": {
+    "message": "Pro\u0161iri"
+  },
+  "expand_candidates": {
+    "message": "pro\u0161iri popis kandidata"
+  },
   "fi_fin_settings_page": {
     "message": "Stranica postavki finske tipkovnice"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Stranica postavki irske tipkovnice"
   },
+  "ignore_correction": {
+    "message": "Zanemari ispravak za"
+  },
   "il_heb_settings_page": {
     "message": "Stranica postavki hebrejske tipkovnice"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rumunjska tipkovnica"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rumunjska standardna tipkovnica"
   },
   "keyboard_russian": {
     "message": "Ruska tipkovnica"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Stranica postavki \u0161vedske tipkovnice"
   },
+  "settings": {
+    "message": "Postavke"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Prika\u017ei prijedloge za hangul"
   },
+  "shrink_candidates": {
+    "message": "smanji popis kandidata"
+  },
   "si_slv_settings_page": {
     "message": "Stranica postavki slovenske tipkovnice"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Ukloni odabrano"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Spremi"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json
index 4f49508f..3bdb3d4d 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/hu/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Hozz\u00e1ad\u00e1s a szem\u00e9lyes sz\u00f3t\u00e1rhoz"
+  },
   "advanced": {
     "message": "Halad\u00f3"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Spanyol billenty\u0171zet be\u00e1ll\u00edt\u00e1sainak oldala"
   },
+  "expand": {
+    "message": "Kibont\u00e1s"
+  },
+  "expand_candidates": {
+    "message": "javaslati lista kibont\u00e1sa"
+  },
   "fi_fin_settings_page": {
     "message": "Finn billenty\u0171zet be\u00e1ll\u00edt\u00e1sainak oldala"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u00cdr billenty\u0171zet be\u00e1ll\u00edt\u00e1sainak oldala"
   },
+  "ignore_correction": {
+    "message": "Jav\u00edt\u00e1s mell\u0151z\u00e9se enn\u00e9l a sz\u00f3n\u00e1l:"
+  },
   "il_heb_settings_page": {
     "message": "H\u00e9ber billenty\u0171zet be\u00e1ll\u00edt\u00e1sainak oldala"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rom\u00e1n billenty\u0171zet"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Hagyom\u00e1nyos rom\u00e1n billenty\u0171zet"
   },
   "keyboard_russian": {
     "message": "Orosz billenty\u0171zet"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Sv\u00e9d billenty\u0171zet be\u00e1ll\u00edt\u00e1sainak oldala"
   },
+  "settings": {
+    "message": "Be\u00e1ll\u00edt\u00e1sok"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Hanguljavaslatok megjelen\u00edt\u00e9se"
   },
+  "shrink_candidates": {
+    "message": "javaslati lista \u00f6sszecsuk\u00e1sa"
+  },
   "si_slv_settings_page": {
     "message": "Szlov\u00e9n billenty\u0171zet be\u00e1ll\u00edt\u00e1sainak oldala"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Kijel\u00f6lt(ek) elt\u00e1vol\u00edt\u00e1sa"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Ment\u00e9s"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json
index 45d5077..46234451 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/id/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Tambahkan ke kamus pribadi"
+  },
   "advanced": {
     "message": "Lanjutan"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Laman Setelan Keyboard Spanyol"
   },
+  "expand": {
+    "message": "Luaskan"
+  },
+  "expand_candidates": {
+    "message": "luaskan daftar calon"
+  },
   "fi_fin_settings_page": {
     "message": "Laman Setelan Keyboard Suomi"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Laman Setelan Keyboard Irlandia"
   },
+  "ignore_correction": {
+    "message": "Abaikan koreksi untuk"
+  },
   "il_heb_settings_page": {
     "message": "Laman Setelan Keyboard Ibrani"
   },
@@ -2847,7 +2859,7 @@
     "message": "Keyboard Rumania"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Keyboard standar Rumania"
   },
   "keyboard_russian": {
     "message": "Keyboard Rusia"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Laman Setelan Keyboard Swensk"
   },
+  "settings": {
+    "message": "Setelan"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Tampilkan saran Hangul"
   },
+  "shrink_candidates": {
+    "message": "ciutkan daftar calon"
+  },
   "si_slv_settings_page": {
     "message": "Laman Setelan Keyboard Sloven"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Hapus yang Dipilih"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Simpan"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json
index 654ee0e1..b11c616 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/it/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Aggiungi al dizionario personale"
+  },
   "advanced": {
     "message": "Avanzata"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Pagina Impostazioni tastiera Spagnolo"
   },
+  "expand": {
+    "message": "Espandi"
+  },
+  "expand_candidates": {
+    "message": "espandi elenco candidati"
+  },
   "fi_fin_settings_page": {
     "message": "Pagina Impostazioni tastiera Finlandese"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Pagina Impostazioni tastiera Irlandese"
   },
+  "ignore_correction": {
+    "message": "Ignora correzione di:"
+  },
   "il_heb_settings_page": {
     "message": "Pagina Impostazioni tastiera Ebraico"
   },
@@ -2847,7 +2859,7 @@
     "message": "Tastiera Rumeno"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Tastiera Rumeno standard"
   },
   "keyboard_russian": {
     "message": "Tastiera Russo"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Pagina Impostazioni tastiera Svedese"
   },
+  "settings": {
+    "message": "Impostazioni"
+  },
   "shift": {
     "message": "maiusc"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Mostra suggerimenti in hangul"
   },
+  "shrink_candidates": {
+    "message": "comprimi elenco candidati"
+  },
   "si_slv_settings_page": {
     "message": "Pagina Impostazioni tastiera Sloveno"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Rimuovi selezionati"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Salva"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json
index 5c2249f..205cc72 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/iw/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u05d4\u05d5\u05e1\u05e3 \u05dc\u05de\u05d9\u05dc\u05d5\u05df \u05d4\u05d0\u05d9\u05e9\u05d9"
+  },
   "advanced": {
     "message": "\u05de\u05ea\u05e7\u05d3\u05dd"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u05d3\u05e3 \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05dc \u05de\u05e7\u05dc\u05d3\u05ea \u05e1\u05e4\u05e8\u05d3\u05d9\u05ea"
   },
+  "expand": {
+    "message": "\u05d4\u05e8\u05d7\u05d1"
+  },
+  "expand_candidates": {
+    "message": "\u05d4\u05e8\u05d7\u05d1 \u05d0\u05ea \u05e8\u05e9\u05d9\u05de\u05ea \u05d4\u05d4\u05e6\u05e2\u05d5\u05ea"
+  },
   "fi_fin_settings_page": {
     "message": "\u05d3\u05e3 \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05dc \u05de\u05e7\u05dc\u05d3\u05ea \u05e4\u05d9\u05e0\u05d9\u05ea"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u05d3\u05e3 \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05dc \u05de\u05e7\u05dc\u05d3\u05ea \u05d0\u05d9\u05e8\u05d9\u05ea"
   },
+  "ignore_correction": {
+    "message": "\u05d4\u05ea\u05e2\u05dc\u05dd \u05de\u05ea\u05d9\u05e7\u05d5\u05df \u05e9\u05dc"
+  },
   "il_heb_settings_page": {
     "message": "\u05d3\u05e3 \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05dc \u05de\u05e7\u05dc\u05d3\u05ea \u05e2\u05d1\u05e8\u05d9\u05ea"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u05de\u05e7\u05dc\u05d3\u05ea \u05e8\u05d5\u05de\u05e0\u05d9\u05ea"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u05de\u05e7\u05dc\u05d3\u05ea \u05e8\u05d5\u05de\u05e0\u05d9\u05ea \u05e8\u05d2\u05d9\u05dc\u05d4"
   },
   "keyboard_russian": {
     "message": "\u05de\u05e7\u05dc\u05d3\u05ea \u05e8\u05d5\u05e1\u05d9\u05ea"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u05d3\u05e3 \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05dc \u05de\u05e7\u05dc\u05d3\u05ea \u05e9\u05d5\u05d5\u05d3\u05d9\u05ea"
   },
+  "settings": {
+    "message": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u200f\u05d4\u05e6\u05d2\u05ea \u05d4\u05e6\u05e2\u05d5\u05ea \u05d1-Hangul"
   },
+  "shrink_candidates": {
+    "message": "\u05db\u05d5\u05d5\u05e5 \u05d0\u05ea \u05e8\u05e9\u05d9\u05de\u05ea \u05d4\u05d4\u05e6\u05e2\u05d5\u05ea"
+  },
   "si_slv_settings_page": {
     "message": "\u05d3\u05e3 \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e9\u05dc \u05de\u05e7\u05dc\u05d3\u05ea \u05e1\u05dc\u05d5\u05d1\u05e0\u05d9\u05ea"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u05d4\u05e1\u05e8 \u05e2\u05e8\u05da \u05e0\u05d1\u05d7\u05e8"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u05e9\u05de\u05d5\u05e8"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json
index eef51fbb..a1beb42 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ja/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u30e6\u30fc\u30b6\u30fc\u8f9e\u66f8\u306b\u8ffd\u52a0"
+  },
   "advanced": {
     "message": "\u8a73\u7d30\u8a2d\u5b9a"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u30b9\u30da\u30a4\u30f3\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9\u8a2d\u5b9a\u30da\u30fc\u30b8"
   },
+  "expand": {
+    "message": "\u5c55\u958b"
+  },
+  "expand_candidates": {
+    "message": "\u5019\u88dc\u306e\u6570\u3092\u5897\u3084\u3059"
+  },
   "fi_fin_settings_page": {
     "message": "\u30d5\u30a3\u30f3\u30e9\u30f3\u30c9\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9\u8a2d\u5b9a\u30da\u30fc\u30b8"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u30a2\u30a4\u30eb\u30e9\u30f3\u30c9\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9\u8a2d\u5b9a\u30da\u30fc\u30b8"
   },
+  "ignore_correction": {
+    "message": "\u6b21\u306e\u8a9e\u306f\u4fee\u6b63\u3057\u306a\u3044:"
+  },
   "il_heb_settings_page": {
     "message": "\u30d8\u30d6\u30e9\u30a4\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9\u8a2d\u5b9a\u30da\u30fc\u30b8"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u30eb\u30fc\u30de\u30cb\u30a2\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u30eb\u30fc\u30de\u30cb\u30a2\u8a9e\u6a19\u6e96\u30ad\u30fc\u30dc\u30fc\u30c9"
   },
   "keyboard_russian": {
     "message": "\u30ed\u30b7\u30a2\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u30b9\u30a6\u30a7\u30fc\u30c7\u30f3\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9\u8a2d\u5b9a\u30da\u30fc\u30b8"
   },
+  "settings": {
+    "message": "\u8a2d\u5b9a"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u30cf\u30f3\u30b0\u30eb\u5019\u88dc\u8868\u793a"
   },
+  "shrink_candidates": {
+    "message": "\u5019\u88dc\u306e\u6570\u3092\u6e1b\u3089\u3059"
+  },
   "si_slv_settings_page": {
     "message": "\u30b9\u30ed\u30d9\u30cb\u30a2\u8a9e\u30ad\u30fc\u30dc\u30fc\u30c9\u8a2d\u5b9a\u30da\u30fc\u30b8"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u9078\u629e\u9805\u76ee\u3092\u524a\u9664"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u4fdd\u5b58"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json
index f23a26a..d976d11f 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/kn/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0cb5\u0cc6\u0cd6\u0caf\u0c95\u0ccd\u0ca4\u0cbf\u0c95 \u0ca8\u0cbf\u0c98\u0c82\u0c9f\u0cbf\u0c97\u0cc6 \u0cb8\u0cc6\u0cd5\u0cb0\u0cbf\u0cb8\u0cbf"
+  },
   "advanced": {
     "message": "\u0cb8\u0cc1\u0ca7\u0cbe\u0cb0\u0cbf\u0ca4"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0cb8\u0ccd\u0caa\u0ccd\u0caf\u0cbe\u0ca8\u0cbf\u0cb7\u0ccd \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd \u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0cc1\u0c9f"
   },
+  "expand": {
+    "message": "\u0cb5\u0cbf\u0cb8\u0ccd\u0ca4\u0cb0\u0cbf\u0cb8\u0cbf"
+  },
+  "expand_candidates": {
+    "message": "\u0c85\u0cad\u0ccd\u0caf\u0cb0\u0ccd\u0ca5\u0cbf \u0caa\u0c9f\u0ccd\u0c9f\u0cbf\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0cb5\u0cbf\u0cb8\u0ccd\u0ca4\u0cb0\u0cbf\u0cb8\u0cbf"
+  },
   "fi_fin_settings_page": {
     "message": "\u0cab\u0cbf\u0ca8\u0ccd\u0ca8\u0cbf\u0cb6\u0ccd \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd \u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0cc1\u0c9f"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0c90\u0cb0\u0cbf\u0cb7\u0ccd \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd \u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0cc1\u0c9f"
   },
+  "ignore_correction": {
+    "message": "\u0c87\u0ca6\u0c95\u0ccd\u0c95\u0cbe\u0c97\u0cbf \u0cb8\u0cb0\u0cbf\u0caa\u0ca1\u0cbf\u0cb8\u0cc1\u0cb5\u0cbf\u0c95\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cbf\u0cb0\u0ccd\u0cb2\u0c95\u0ccd\u0cb7\u0cbf\u0cb8\u0cbf"
+  },
   "il_heb_settings_page": {
     "message": "\u0cb9\u0cbf\u0cac\u0ccd\u0cb0\u0cc2 \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd \u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0cc1\u0c9f"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0cb0\u0cca\u0cae\u0cc7\u0ca8\u0cbf\u0caf\u0ca8\u0ccd \u0c95\u0cc0\u0cac\u0ccb\u0cb0\u0ccd\u0ca1\u0ccd"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0cb0\u0cc6\u0cc2\u0cae\u0cc6\u0cd5\u0ca8\u0cbf\u0caf\u0ca8\u0ccd \u0caa\u0ccd\u0cb0\u0cae\u0cbe\u0ca3\u0cbf\u0ca4 \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd"
   },
   "keyboard_russian": {
     "message": "\u0cb0\u0cb7\u0ccd\u0caf\u0ca8\u0ccd \u0c95\u0cc0\u0cac\u0ccb\u0cb0\u0ccd\u0ca1\u0ccd"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0cb8\u0ccd\u0cb5\u0cbf\u0cd5\u0ca1\u0cbf\u0cb6\u0ccd \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd \u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0cc1\u0c9f"
   },
+  "settings": {
+    "message": "\u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3\u0cc1"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0cb9\u0c82\u0c97\u0cc1\u0cb2\u0ccd \u0cb8\u0cb2\u0cb9\u0cc6\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca4\u0cc6\u0cc2\u0cd5\u0cb0\u0cbf\u0cb8\u0cbf"
   },
+  "shrink_candidates": {
+    "message": "\u0c85\u0cad\u0ccd\u0caf\u0cb0\u0ccd\u0ca5\u0cbf \u0caa\u0c9f\u0ccd\u0c9f\u0cbf\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0c95\u0cc1\u0c97\u0ccd\u0c97\u0cbf\u0cb8\u0cbf"
+  },
   "si_slv_settings_page": {
     "message": "\u0cb8\u0ccd\u0cb2\u0cc6\u0cc2\u0cd5\u0cb5\u0cc6\u0cd5\u0ca8\u0cbf\u0caf\u0ca8\u0ccd \u0c95\u0cbf\u0cd5\u0cac\u0cc6\u0cc2\u0cd5\u0cb0\u0ccd\u0ca1\u0ccd \u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0cc1\u0c9f"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0c86\u0caf\u0ccd\u0c95\u0cc6\u0cae\u0cbe\u0ca1\u0cb2\u0cbe\u0c97\u0cbf\u0cb0\u0cc1\u0cb5\u0cc1\u0ca6\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca4\u0cc6\u0c97\u0cc6\u0ca6\u0cc1\u0cb9\u0cbe\u0c95\u0cbf"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0c89\u0cb3\u0cbf\u0cb8\u0cc1"
   },
@@ -3282,7 +3303,7 @@
     "message": "\u0ca7\u0ccd\u0cb5\u0ca8\u0cbf \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd \u0c9f\u0cc2\u0cb2\u0ccd \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 \u0c86\u0cab\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
   },
   "voice_turn_on": {
-    "message": "\u0ca7\u0ccd\u0cb5\u0ca8\u0cbf \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd \u0c9f\u0cc2\u0cb2\u0ccd \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 \u0c86\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
+    "message": "\u0ca7\u0ccd\u0cb5\u0ca8\u0cbf \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd \u0caa\u0cb0\u0cbf\u0c95\u0cb0\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c86\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
   },
   "wait": {
     "message": "\u0c95\u0cbe\u0caf\u0cbf\u0cb0\u0cbf"
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json
index 9fe890d8..20a139d 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ko/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\uac1c\uc778 \uc0ac\uc804\uc5d0 \ucd94\uac00"
+  },
   "advanced": {
     "message": "\uace0\uae09"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\uc2a4\ud398\uc778\uc5b4 \ud0a4\ubcf4\ub4dc \uc124\uc815 \ud398\uc774\uc9c0"
   },
+  "expand": {
+    "message": "\ud3bc\uce58\uae30"
+  },
+  "expand_candidates": {
+    "message": "\ud6c4\ubcf4 \ubaa9\ub85d \ud3bc\uce58\uae30"
+  },
   "fi_fin_settings_page": {
     "message": "\ud540\ub780\ub4dc\uc5b4 \ud0a4\ubcf4\ub4dc \uc124\uc815 \ud398\uc774\uc9c0"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\uc544\uc77c\ub79c\ub4dc\uc5b4 \ud0a4\ubcf4\ub4dc \uc124\uc815 \ud398\uc774\uc9c0"
   },
+  "ignore_correction": {
+    "message": "\uc790\ub3d9 \uc218\uc815 \uae30\ub2a5 \ubb34\uc2dc"
+  },
   "il_heb_settings_page": {
     "message": "\ud788\ube0c\ub9ac\uc5b4 \ud0a4\ubcf4\ub4dc \uc124\uc815 \ud398\uc774\uc9c0"
   },
@@ -2847,7 +2859,7 @@
     "message": "\ub8e8\ub9c8\ub2c8\uc544\uc5b4 \ud0a4\ubcf4\ub4dc"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\ub8e8\ub9c8\ub2c8\uc544 \ud45c\uc900 \ud0a4\ubcf4\ub4dc"
   },
   "keyboard_russian": {
     "message": "\ub7ec\uc2dc\uc544\uc5b4 \ud0a4\ubcf4\ub4dc"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\uc2a4\uc6e8\ub374\uc5b4 \ud0a4\ubcf4\ub4dc \uc124\uc815 \ud398\uc774\uc9c0"
   },
+  "settings": {
+    "message": "\uc124\uc815"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\ud55c\uae00 \ucd94\ucc9c \ud56d\ubaa9 \ud45c\uc2dc"
   },
+  "shrink_candidates": {
+    "message": "\ud6c4\ubcf4 \ubaa9\ub85d \uc228\uae30\uae30"
+  },
   "si_slv_settings_page": {
     "message": "\uc2ac\ub85c\ubca0\ub2c8\uc544\uc5b4 \ud0a4\ubcf4\ub4dc \uc124\uc815 \ud398\uc774\uc9c0"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\uc120\ud0dd \ud56d\ubaa9 \uc0ad\uc81c"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\uc800\uc7a5"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json
index 60cdb5f9..57ebfd7 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lt/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Prid\u0117ti prie asmeninio \u017eodyno"
+  },
   "advanced": {
     "message": "I\u0161pl\u0117stiniai"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Ispani\u0161kos klaviat\u016bros nustatym\u0173 puslapis"
   },
+  "expand": {
+    "message": "I\u0161skleisti"
+  },
+  "expand_candidates": {
+    "message": "i\u0161skleisti variant\u0173 s\u0105ra\u0161\u0105"
+  },
   "fi_fin_settings_page": {
     "message": "Suomi\u0161kos klaviat\u016bros nustatym\u0173 puslapis"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Airi\u0161kos klaviat\u016bros nustatym\u0173 puslapis"
   },
+  "ignore_correction": {
+    "message": "Ignoruoti pataisym\u0105"
+  },
   "il_heb_settings_page": {
     "message": "Hebraji\u0161kos klaviat\u016bros nustatym\u0173 puslapis"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rumuni\u0161ka klaviat\u016bra"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rumun\u0173 k. standartin\u0117 klaviat\u016bra"
   },
   "keyboard_russian": {
     "message": "Rusi\u0161ka klaviat\u016bra"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0160vedi\u0161kos klaviat\u016bros nustatym\u0173 puslapis"
   },
+  "settings": {
+    "message": "Nustatymai"
+  },
   "shift": {
     "message": "klavi\u0161as \u201eshift\u201c"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Rodyti hangul pasi\u016blymus"
   },
+  "shrink_candidates": {
+    "message": "sutraukti variant\u0173 s\u0105ra\u0161\u0105"
+  },
   "si_slv_settings_page": {
     "message": "Slov\u0117ni\u0161kos klaviat\u016bros nustatym\u0173 puslapis"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Pa\u0161alinti pasirinktus"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "I\u0161saugoti"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json
index dc4b34f..7d90fc9 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/lv/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Pievienot personiskajai v\u0101rdn\u012bcai"
+  },
   "advanced": {
     "message": "Papildu"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Sp\u0101\u0146u valodas tastat\u016bras iestat\u012bjumu lapa"
   },
+  "expand": {
+    "message": "Izv\u0113rst"
+  },
+  "expand_candidates": {
+    "message": "papla\u0161in\u0101t kandid\u0101tu sarakstu"
+  },
   "fi_fin_settings_page": {
     "message": "Somu valodas tastat\u016bras iestat\u012bjumu lapa"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u012aru valodas tastat\u016bras iestat\u012bjumu lapa"
   },
+  "ignore_correction": {
+    "message": "Ignor\u0113t labojumu v\u0101rdam"
+  },
   "il_heb_settings_page": {
     "message": "Ebreju valodas tastat\u016bras iestat\u012bjumu lapa"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rum\u0101\u0146u valodas tastat\u016bra"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rum\u0101\u0146u standarta tastat\u016bra"
   },
   "keyboard_russian": {
     "message": "Krievu valodas tastat\u016bra"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Zviedru valodas tastat\u016bras iestat\u012bjumu lapa"
   },
+  "settings": {
+    "message": "Iestat\u012bjumi"
+  },
   "shift": {
     "message": "tausti\u0146\u0161 Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "R\u0101d\u012bt ieteikumus korejie\u0161u valod\u0101"
   },
+  "shrink_candidates": {
+    "message": "sa\u0161aurin\u0101t kandid\u0101tu sarakstu"
+  },
   "si_slv_settings_page": {
     "message": "Slov\u0113\u0146u valodas tastat\u016bras iestat\u012bjumu lapa"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "No\u0146emt atlas\u012btos"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Saglab\u0101t"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json
index 2d2f356..5860bc5 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ml/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0d35\u0d4d\u0d2f\u0d15\u0d4d\u0d24\u0d3f\u0d17\u0d24 \u0d28\u0d3f\u0d18\u0d23\u0d4d\u0d1f\u0d41\u0d35\u0d3f\u0d7d \u0d1a\u0d47\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d15"
+  },
   "advanced": {
     "message": "\u0d35\u0d3f\u0d2a\u0d41\u0d32\u0d2e\u0d3e\u0d2f"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0d38\u0d4d\u200c\u0d2a\u0d3e\u0d28\u0d3f\u0d37\u0d4d \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23 \u0d2a\u0d47\u0d1c\u0d4d"
   },
+  "expand": {
+    "message": "\u0d35\u0d3f\u0d2a\u0d41\u0d32\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+  },
+  "expand_candidates": {
+    "message": "\u0d15\u0d3e\u0d7b\u0d21\u0d3f\u0d21\u0d47\u0d31\u0d4d\u0d31\u0d4d \u0d32\u0d3f\u0d38\u0d4d\u200c\u0d31\u0d4d\u0d31\u0d4d \u0d35\u0d3f\u0d2a\u0d41\u0d32\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+  },
   "fi_fin_settings_page": {
     "message": "\u0d2b\u0d3f\u0d28\u0d4d\u0d28\u0d3f\u0d37\u0d4d \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23 \u0d2a\u0d47\u0d1c\u0d4d"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0d10\u0d31\u0d3f\u0d37\u0d4d \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23 \u0d2a\u0d47\u0d1c\u0d4d"
   },
+  "ignore_correction": {
+    "message": "\u0d0e\u0d28\u0d4d\u0d28\u0d24\u0d3f\u0d28\u0d41\u0d33\u0d4d\u0d33 \u0d24\u0d3f\u0d30\u0d41\u0d24\u0d4d\u0d24\u0d7d \u0d05\u0d35\u0d17\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+  },
   "il_heb_settings_page": {
     "message": "\u0d39\u0d40\u0d2c\u0d4d\u0d30\u0d41 \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23 \u0d2a\u0d47\u0d1c\u0d4d"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0d31\u0d4a\u0d2e\u0d3e\u0d28\u0d3f\u0d2f\u0d28\u0d4d\u200d \u0d15\u0d40\u0d2c\u0d4b\u0d30\u0d4d\u200d\u0d21\u0d4d"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0d31\u0d4a\u0d2e\u0d3e\u0d28\u0d3f\u0d2f\u0d7b \u0d05\u0d1f\u0d3f\u0d38\u0d4d\u0d25\u0d3e\u0d28 \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d"
   },
   "keyboard_russian": {
     "message": "\u0d31\u0d37\u0d4d\u0d2f\u0d28\u0d4d\u200d \u0d15\u0d40\u0d2c\u0d4b\u0d30\u0d4d\u200d\u0d21\u0d4d"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0d38\u0d4d\u0d35\u0d40\u0d21\u0d3f\u0d37\u0d4d \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23 \u0d2a\u0d47\u0d1c\u0d4d"
   },
+  "settings": {
+    "message": "\u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23\u0d02"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0d39\u0d02\u0d17\u0d41\u0d7d \u0d28\u0d3f\u0d7c\u0d26\u0d4d\u0d26\u0d47\u0d36\u0d19\u0d4d\u0d19\u0d7e \u0d15\u0d3e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
   },
+  "shrink_candidates": {
+    "message": "\u0d15\u0d3e\u0d7b\u0d21\u0d3f\u0d21\u0d47\u0d31\u0d4d\u0d31\u0d4d \u0d32\u0d3f\u0d38\u0d4d\u200c\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d41\u0d30\u0d41\u0d15\u0d4d\u0d15\u0d41\u0d15"
+  },
   "si_slv_settings_page": {
     "message": "\u0d38\u0d4d\u200c\u0d32\u0d4b\u0d35\u0d47\u0d28\u0d3f\u0d2f\u0d7b \u0d15\u0d40\u0d2c\u0d4b\u0d7c\u0d21\u0d4d \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23 \u0d2a\u0d47\u0d1c\u0d4d"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0d24\u0d3f\u0d30\u0d1e\u0d4d\u0d1e\u0d46\u0d1f\u0d41\u0d24\u0d4d\u0d24\u0d35 \u0d28\u0d40\u0d15\u0d4d\u0d15\u0d02\u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0d38\u0d02\u0d30\u0d15\u0d4d\u0d37\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json
index 7728083..f1bd1ba 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/mr/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0935\u0948\u092f\u0915\u094d\u0924\u093f\u0915 \u0936\u092c\u094d\u0926\u0915\u094b\u0936\u093e\u0924 \u091c\u094b\u0921\u093e"
+  },
   "advanced": {
     "message": "\u092a\u094d\u0930\u0917\u0924"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0938\u094d\u092a\u0945\u0928\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0943\u0937\u094d\u0920"
   },
+  "expand": {
+    "message": "\u0935\u093f\u0938\u094d\u0924\u0943\u0924 \u0915\u0930\u093e"
+  },
+  "expand_candidates": {
+    "message": "\u0909\u092e\u0947\u0926\u0935\u093e\u0930 \u0938\u0942\u091a\u0940 \u0935\u093f\u0938\u094d\u0924\u0943\u0924 \u0915\u0930\u093e"
+  },
   "fi_fin_settings_page": {
     "message": "\u092b\u093f\u0928\u094d\u0928\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0943\u0937\u094d\u0920"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0906\u092f\u0930\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0943\u0937\u094d\u0920"
   },
+  "ignore_correction": {
+    "message": "\u092f\u093e\u0938\u093e\u0920\u0940 \u0938\u0941\u0927\u093e\u0930\u0923\u0947\u0915\u0921\u0947 \u0926\u0941\u0930\u094d\u0932\u0915\u094d\u0937 \u0915\u0930\u093e"
+  },
   "il_heb_settings_page": {
     "message": "\u0939\u093f\u092c\u094d\u0930\u0942 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0943\u0937\u094d\u0920"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0930\u094b\u092e\u093e\u0928\u093f\u092f\u0928 \u0915\u0940\u092c\u094b\u0930\u094d\u0921"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0930\u094b\u092e\u0947\u0928\u093f\u092f\u0928 \u092e\u093e\u0928\u0915 \u0915\u0940\u092c\u094b\u0930\u094d\u0921"
   },
   "keyboard_russian": {
     "message": "\u0930\u0936\u093f\u092f\u0928 \u0915\u0940\u092c\u094b\u0930\u094d\u0921"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0938\u094d\u0935\u0940\u0921\u093f\u0936 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0943\u0937\u094d\u0920"
   },
+  "settings": {
+    "message": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0939\u0902\u0917\u0941\u0932 \u0938\u0942\u091a\u0928\u093e \u0926\u0930\u094d\u0936\u0935\u093e"
   },
+  "shrink_candidates": {
+    "message": "\u0909\u092e\u0947\u0926\u0935\u093e\u0930 \u0938\u0942\u091a\u0940 \u0938\u0902\u0915\u094d\u0937\u093f\u092a\u094d\u0924 \u0915\u0930\u093e"
+  },
   "si_slv_settings_page": {
     "message": "\u0938\u094d\u0932\u094b\u0935\u094d\u0939\u0947\u0928\u093f\u092f\u0928 \u0915\u0940\u092c\u094b\u0930\u094d\u0921 \u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0943\u0937\u094d\u0920"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0928\u093f\u0935\u0921\u0932\u0947\u0932\u0947 \u0915\u093e\u0922\u093e"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u091c\u0924\u0928 \u0915\u0930\u093e"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json
index f1509eb..a8684822c 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ms/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Tambahkan pada kamus peribadi"
+  },
   "advanced": {
     "message": "Terperinci"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Halaman Tetapan Papan Kekunci Sepanyol"
   },
+  "expand": {
+    "message": "Kembangkan"
+  },
+  "expand_candidates": {
+    "message": "kembangkan senarai calon"
+  },
   "fi_fin_settings_page": {
     "message": "Halaman Tetapan Papan Kekunci Finland"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Halaman Tetapan Papan Kekunci Ireland"
   },
+  "ignore_correction": {
+    "message": "Abaikan pembetulan untuk"
+  },
   "il_heb_settings_page": {
     "message": "Halaman Tetapan Papan Kekunci Ibrani"
   },
@@ -2847,7 +2859,7 @@
     "message": "Papan kekunci Romania"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Papan kekunci standard Romania"
   },
   "keyboard_russian": {
     "message": "Papan kekunci Rusia"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Halaman Tetapan Papan Kekunci Sweden"
   },
+  "settings": {
+    "message": "Tetapan"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Tunjukkan cadangan Hangul"
   },
+  "shrink_candidates": {
+    "message": "kecilkan senarai calon"
+  },
   "si_slv_settings_page": {
     "message": "Halaman Tetapan Papan Kekunci Slovenia"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Alih Keluar Pilihan"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Simpan"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json
index 418e3fcc..6b5ce04 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nb/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Legg til i den personlige ordboken"
+  },
   "advanced": {
     "message": "Avansert"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Innstillinger-side for spansk tastatur"
   },
+  "expand": {
+    "message": "Vis"
+  },
+  "expand_candidates": {
+    "message": "vis kandidatlisten"
+  },
   "fi_fin_settings_page": {
     "message": "Innstillinger-side for finsk tastatur"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Innstillinger-side for irsk tastatur"
   },
+  "ignore_correction": {
+    "message": "Ignorer korrigering av"
+  },
   "il_heb_settings_page": {
     "message": "Innstillinger-side for hebraisk tastatur"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rumensk tastatur"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rumensk standardtastatur"
   },
   "keyboard_russian": {
     "message": "Russisk tastatur"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Innstillinger-side for svensk tastatur"
   },
+  "settings": {
+    "message": "Innstillinger"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Vis foresl\u00e5tte hangul-tegn"
   },
+  "shrink_candidates": {
+    "message": "skjul kandidatlisten"
+  },
   "si_slv_settings_page": {
     "message": "Innstillinger-side for slovensk tastatur"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Fjern valgte"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Lagre"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json
index bd70257..63de460d 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/nl/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Toevoegen aan persoonlijk woordenboek"
+  },
   "advanced": {
     "message": "Geavanceerd"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Pagina met instellingen voor Spaans toetsenbord"
   },
+  "expand": {
+    "message": "Uitvouwen"
+  },
+  "expand_candidates": {
+    "message": "kandidatenlijst uitvouwen"
+  },
   "fi_fin_settings_page": {
     "message": "Pagina met instellingen voor Fins toetsenbord"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Pagina met instellingen voor Iers toetsenbord"
   },
+  "ignore_correction": {
+    "message": "Correctie negeren voor"
+  },
   "il_heb_settings_page": {
     "message": "Pagina met instellingen voor Hebreeuws toetsenbord"
   },
@@ -2847,7 +2859,7 @@
     "message": "Roemeens toetsenbord"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Standaardtoetsenbord voor Roemeens"
   },
   "keyboard_russian": {
     "message": "Russisch toetsenbord"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Pagina met instellingen voor Zweeds toetsenbord"
   },
+  "settings": {
+    "message": "Instellingen"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Hangul-suggesties weergeven"
   },
+  "shrink_candidates": {
+    "message": "kandidatenlijst verkleinen"
+  },
   "si_slv_settings_page": {
     "message": "Pagina met instellingen voor Sloveens toetsenbord"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Selectie verwijderen"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Opslaan"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json
index b33c1f2..aa9150c 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pl/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Dodaj do s\u0142ownika osobistego"
+  },
   "advanced": {
     "message": "Zaawansowane"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Strona ustawie\u0144 klawiatury hiszpa\u0144skiej"
   },
+  "expand": {
+    "message": "Rozwi\u0144"
+  },
+  "expand_candidates": {
+    "message": "rozwi\u0144 list\u0119 sugestii"
+  },
   "fi_fin_settings_page": {
     "message": "Strona ustawie\u0144 klawiatury fi\u0144skiej"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Strona ustawie\u0144 klawiatury irlandzkiej"
   },
+  "ignore_correction": {
+    "message": "Ignoruj korekt\u0119"
+  },
   "il_heb_settings_page": {
     "message": "Strona ustawie\u0144 klawiatury hebrajskiej"
   },
@@ -2847,7 +2859,7 @@
     "message": "Klawiatura rumu\u0144ska"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Standardowa klawiatura rumu\u0144ska"
   },
   "keyboard_russian": {
     "message": "Klawiatura rosyjska"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Strona ustawie\u0144 klawiatury szwedzkiej"
   },
+  "settings": {
+    "message": "Ustawienia"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Wy\u015bwietlaj sugestie w hangulu"
   },
+  "shrink_candidates": {
+    "message": "zwi\u0144 list\u0119 sugestii"
+  },
   "si_slv_settings_page": {
     "message": "Strona ustawie\u0144 klawiatury s\u0142owe\u0144skiej"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Usu\u0144 zaznaczone"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Zapisz"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json
index 6c63341..3b42b3c 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_BR/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Adicionar ao dicion\u00e1rio pessoal"
+  },
   "advanced": {
     "message": "Avan\u00e7ado"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "P\u00e1gina de configura\u00e7\u00f5es do teclado espanhol"
   },
+  "expand": {
+    "message": "Expandir"
+  },
+  "expand_candidates": {
+    "message": "expandir lista de candidatos"
+  },
   "fi_fin_settings_page": {
     "message": "P\u00e1gina de configura\u00e7\u00f5es do teclado finland\u00eas"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "P\u00e1gina de configura\u00e7\u00f5es do teclado irland\u00eas"
   },
+  "ignore_correction": {
+    "message": "Ignorar corre\u00e7\u00e3o para"
+  },
   "il_heb_settings_page": {
     "message": "P\u00e1gina de configura\u00e7\u00f5es do teclado hebraico"
   },
@@ -2847,7 +2859,7 @@
     "message": "Teclado romeno"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Teclado romeno padr\u00e3o"
   },
   "keyboard_russian": {
     "message": "Teclado russo"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "P\u00e1gina de configura\u00e7\u00f5es do teclado sueco"
   },
+  "settings": {
+    "message": "Configura\u00e7\u00f5es"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Mostrar sugest\u00f5es em hangul"
   },
+  "shrink_candidates": {
+    "message": "encolher lista de candidatos"
+  },
   "si_slv_settings_page": {
     "message": "P\u00e1gina de configura\u00e7\u00f5es do teclado esloveno"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Remover entradas selecionadas"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Salvar"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json
index 6cfe8846..d4bd96e 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/pt_PT/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Adicionar ao dicion\u00e1rio pessoal"
+  },
   "advanced": {
     "message": "Avan\u00e7ada"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "P\u00e1gina de defini\u00e7\u00f5es do teclado espanhol"
   },
+  "expand": {
+    "message": "Expandir"
+  },
+  "expand_candidates": {
+    "message": "expandir lista de candidatos"
+  },
   "fi_fin_settings_page": {
     "message": "P\u00e1gina de defini\u00e7\u00f5es do teclado finland\u00eas"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "P\u00e1gina de defini\u00e7\u00f5es do teclado irland\u00eas"
   },
+  "ignore_correction": {
+    "message": "Ignorar corre\u00e7\u00e3o para"
+  },
   "il_heb_settings_page": {
     "message": "P\u00e1gina de defini\u00e7\u00f5es do teclado hebraico"
   },
@@ -2847,7 +2859,7 @@
     "message": "Teclado romeno"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Teclado padr\u00e3o romeno"
   },
   "keyboard_russian": {
     "message": "Teclado russo"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "P\u00e1gina de defini\u00e7\u00f5es do teclado sueco"
   },
+  "settings": {
+    "message": "Defini\u00e7\u00f5es"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Mostrar sugest\u00f5es em hangul"
   },
+  "shrink_candidates": {
+    "message": "reduzir lista de candidatos"
+  },
   "si_slv_settings_page": {
     "message": "P\u00e1gina de defini\u00e7\u00f5es do teclado esloveno"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Remover selecionadas"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Guardar"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json
index 585696a7..d156016c 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ro/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Adaug\u0103 \u00een dic\u021bionarul personal"
+  },
   "advanced": {
     "message": "Set\u0103ri avansate"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Pagina de set\u0103ri pentru tastatura spaniol\u0103"
   },
+  "expand": {
+    "message": "Extinde"
+  },
+  "expand_candidates": {
+    "message": "extinde lista de sugestii"
+  },
   "fi_fin_settings_page": {
     "message": "Pagina de set\u0103ri pentru tastatura finlandez\u0103"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Pagina de set\u0103ri pentru tastatura irlandez\u0103"
   },
+  "ignore_correction": {
+    "message": "Ignor\u0103 corectura pentru"
+  },
   "il_heb_settings_page": {
     "message": "Pagina de set\u0103ri pentru tastatura ebraic\u0103"
   },
@@ -2847,7 +2859,7 @@
     "message": "Tastatur\u0103 rom\u00e2n\u0103"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Tastatur\u0103 rom\u00e2n\u0103 standard"
   },
   "keyboard_russian": {
     "message": "Tastatur\u0103 rus\u0103"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Pagina de set\u0103ri pentru tastatura suedez\u0103"
   },
+  "settings": {
+    "message": "Set\u0103ri"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Afi\u0219eaz\u0103 sugestii \u00een Hangul"
   },
+  "shrink_candidates": {
+    "message": "restr\u00e2nge lista de sugestii"
+  },
   "si_slv_settings_page": {
     "message": "Pagina de set\u0103ri pentru tastatura sloven\u0103"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Elimin\u0103-le pe cele selectate"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Salveaz\u0103"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json
index c74b2f2..6dfb2d00 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ru/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c"
+  },
   "advanced": {
     "message": "\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0441\u043f\u0430\u043d\u0441\u043a\u043e\u0439 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0438"
   },
+  "expand": {
+    "message": "\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c"
+  },
+  "expand_candidates": {
+    "message": "\u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432"
+  },
   "fi_fin_settings_page": {
     "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0444\u0438\u043d\u0441\u043a\u043e\u0439 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0438"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0440\u043b\u0430\u043d\u0434\u0441\u043a\u043e\u0439 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0438"
   },
+  "ignore_correction": {
+    "message": "\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c:"
+  },
   "il_heb_settings_page": {
     "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0438 \u043d\u0430 \u0438\u0432\u0440\u0438\u0442\u0435"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0420\u0443\u043c\u044b\u043d\u0441\u043a\u0430\u044f \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0430"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0443\u043c\u044b\u043d\u0441\u043a\u0430\u044f \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430"
   },
   "keyboard_russian": {
     "message": "\u0420\u0443\u0441\u0441\u043a\u0430\u044f \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0430"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0448\u0432\u0435\u0434\u0441\u043a\u043e\u0439 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0438"
   },
+  "settings": {
+    "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u0434\u043b\u044f \u0445\u0430\u043d\u0433\u044b\u043b\u044f"
   },
+  "shrink_candidates": {
+    "message": "\u0441\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432"
+  },
   "si_slv_settings_page": {
     "message": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u043b\u043e\u0432\u0435\u043d\u0441\u043a\u043e\u0439 \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0438"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json
index 7fd376d..fb0d7f3 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sk/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Prida\u0165 do osobn\u00e9ho slovn\u00edka"
+  },
   "advanced": {
     "message": "Roz\u0161\u00edren\u00e9"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Str\u00e1nka s nastaveniami \u0161panielskej kl\u00e1vesnice"
   },
+  "expand": {
+    "message": "Rozbali\u0165"
+  },
+  "expand_candidates": {
+    "message": "rozbali\u0165 zoznam kandid\u00e1tov"
+  },
   "fi_fin_settings_page": {
     "message": "Str\u00e1nka s nastaveniami f\u00ednskej kl\u00e1vesnice"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Str\u00e1nka s nastaveniami \u00edrskej kl\u00e1vesnice"
   },
+  "ignore_correction": {
+    "message": "Ignorova\u0165 opravu pre"
+  },
   "il_heb_settings_page": {
     "message": "Str\u00e1nka s nastaveniami hebrejskej kl\u00e1vesnice"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rumunsk\u00e1 kl\u00e1vesnica"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rumunsk\u00e1 \u0161tandardn\u00e1 kl\u00e1vesnica"
   },
   "keyboard_russian": {
     "message": "Rusk\u00e1 kl\u00e1vesnica"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Str\u00e1nka s nastaveniami \u0161v\u00e9dskej kl\u00e1vesnice"
   },
+  "settings": {
+    "message": "Nastavenia"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Zobrazenie n\u00e1vrhov v p\u00edsme Hangul"
   },
+  "shrink_candidates": {
+    "message": "zbali\u0165 zoznam kandid\u00e1tov"
+  },
   "si_slv_settings_page": {
     "message": "Str\u00e1nka s nastaveniami slovinskej kl\u00e1vesnice"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Odstr\u00e1ni\u0165 vybran\u00e9"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Ulo\u017ei\u0165"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json
index fae3d065..f2aaca2 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sl/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Dodaj v osebni slovar"
+  },
   "advanced": {
     "message": "Dodatno"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Stran z nastavitvami \u0161panske tipkovnice"
   },
+  "expand": {
+    "message": "Raz\u0161iri"
+  },
+  "expand_candidates": {
+    "message": "raz\u0161iri seznam kandidatov"
+  },
   "fi_fin_settings_page": {
     "message": "Stran z nastavitvami finske tipkovnice"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Stran z nastavitvami irske tipkovnice"
   },
+  "ignore_correction": {
+    "message": "Prezri popravek za"
+  },
   "il_heb_settings_page": {
     "message": "Stran z nastavitvami hebrejske tipkovnice"
   },
@@ -2847,7 +2859,7 @@
     "message": "Romunska tipkovnica"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Romunska standardna tipkovnica"
   },
   "keyboard_russian": {
     "message": "Ruska tipkovnica"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Stran z nastavitvami \u0161vedske tipkovnice"
   },
+  "settings": {
+    "message": "Nastavitve"
+  },
   "shift": {
     "message": "dvigalka"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Poka\u017ei predloge za hangul"
   },
+  "shrink_candidates": {
+    "message": "skr\u010di seznam kandidatov"
+  },
   "si_slv_settings_page": {
     "message": "Stran z nastavitvami slovenske tipkovnice"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Odstrani izbor"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Shrani"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json
index 7f8ae3a..54a16b3f 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sr/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0414\u043e\u0434\u0430\u0458 \u0443 \u043b\u0438\u0447\u043d\u0438 \u0440\u0435\u0447\u043d\u0438\u043a"
+  },
   "advanced": {
     "message": "\u041d\u0430\u043f\u0440\u0435\u0434\u043d\u0435 \u043e\u043f\u0446\u0438\u0458\u0435"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0430 \u043f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0438\u043c\u0430 \u0448\u043f\u0430\u043d\u0441\u043a\u0435 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0435"
   },
+  "expand": {
+    "message": "\u041f\u0440\u043e\u0448\u0438\u0440\u0438"
+  },
+  "expand_candidates": {
+    "message": "\u043f\u0440\u043e\u0448\u0438\u0440\u0438 \u043b\u0438\u0441\u0442\u0443 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0430"
+  },
   "fi_fin_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0430 \u043f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0438\u043c\u0430 \u0444\u0438\u043d\u0441\u043a\u0435 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0435"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0430 \u043f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0438\u043c\u0430 \u0438\u0440\u0441\u043a\u0435 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0435"
   },
+  "ignore_correction": {
+    "message": "\u0417\u0430\u043d\u0435\u043c\u0430\u0440\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u043a\u0443 \u0437\u0430"
+  },
   "il_heb_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0430 \u043f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0438\u043c\u0430 \u0445\u0435\u0431\u0440\u0435\u0458\u0441\u043a\u0435 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0435"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0420\u0443\u043c\u0443\u043d\u0441\u043a\u0430 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0430"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0434\u043d\u0430 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0430 \u0437\u0430 \u0440\u0443\u043c\u0443\u043d\u0441\u043a\u0438"
   },
   "keyboard_russian": {
     "message": "\u0420\u0443\u0441\u043a\u0430 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0430"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0430 \u043f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0438\u043c\u0430 \u0448\u0432\u0435\u0434\u0441\u043a\u0435 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0435"
   },
+  "settings": {
+    "message": "\u041f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0430"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u041f\u0440\u0438\u043a\u0430\u0436\u0438 \u0445\u0430\u043d\u0433\u0443\u043b \u043f\u0440\u0435\u0434\u043b\u043e\u0433\u0435"
   },
+  "shrink_candidates": {
+    "message": "\u0441\u043a\u0443\u043f\u0438 \u043b\u0438\u0441\u0442\u0443 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0430"
+  },
   "si_slv_settings_page": {
     "message": "\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0430 \u043f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0438\u043c\u0430 \u0441\u043b\u043e\u0432\u0435\u043d\u0430\u0447\u043a\u0435 \u0442\u0430\u0441\u0442\u0430\u0442\u0443\u0440\u0435"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0423\u043a\u043b\u043e\u043d\u0438 \u0438\u0437\u0430\u0431\u0440\u0430\u043d\u043e"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0421\u0430\u0447\u0443\u0432\u0430\u0458"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json
index a187ae5..1bc9b29 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sv/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "L\u00e4gg till i personlig ordlista"
+  },
   "advanced": {
     "message": "Avancerat"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Inst\u00e4llningssidan f\u00f6r spanskt tangentbord"
   },
+  "expand": {
+    "message": "Ut\u00f6ka"
+  },
+  "expand_candidates": {
+    "message": "visa fler alternativ"
+  },
   "fi_fin_settings_page": {
     "message": "Inst\u00e4llningssidan f\u00f6r finskt tangentbord"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Inst\u00e4llningssidan f\u00f6r irl\u00e4ndskt tangentbord"
   },
+  "ignore_correction": {
+    "message": "Ignorera korrigeringen av"
+  },
   "il_heb_settings_page": {
     "message": "Inst\u00e4llningssidan f\u00f6r hebreiskt tangentbord"
   },
@@ -2847,7 +2859,7 @@
     "message": "Rum\u00e4nskt tangentbord"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rum\u00e4nskt standardtangentbord"
   },
   "keyboard_russian": {
     "message": "Ryskt tangentbord"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Inst\u00e4llningssidan f\u00f6r svenskt tangentbord"
   },
+  "settings": {
+    "message": "Inst\u00e4llningar"
+  },
   "shift": {
     "message": "skift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Visa f\u00f6rslag med hangul-tecken"
   },
+  "shrink_candidates": {
+    "message": "visa f\u00e4rre alternativ"
+  },
   "si_slv_settings_page": {
     "message": "Inst\u00e4llningssidan f\u00f6r slovenskt tangentbord"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Ta bort markerade poster"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Spara"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json
index b68a824..a1a125d 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/sw/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Ongeza kwenye kamusi ya binafsi"
+  },
   "advanced": {
     "message": "Mipangilio ya kina"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Ukurasa wa Mipangilio ya Kibodi ya Kihispania"
   },
+  "expand": {
+    "message": "Panua"
+  },
+  "expand_candidates": {
+    "message": "panua orodha ya wagombea"
+  },
   "fi_fin_settings_page": {
     "message": "Ukurasa wa Mipangilio ya Kibodi ya Kifini"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Ukurasa wa Mipangilio ya Kibodi ya Kiairishi"
   },
+  "ignore_correction": {
+    "message": "Puuza marekebisho ya neno"
+  },
   "il_heb_settings_page": {
     "message": "Ukurasa wa Mipangilio ya Kibodi ya Kiyahudi"
   },
@@ -2847,7 +2859,7 @@
     "message": "Kibodi ya Kiromania"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Kibodi wastani ya Kiromania"
   },
   "keyboard_russian": {
     "message": "Kibodi ya Kirusi"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Ukurasa wa Mipangilio ya Kibodi ya Kiswidi"
   },
+  "settings": {
+    "message": "Mipangilio"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Onyesha mapendekezo ya Hangul"
   },
+  "shrink_candidates": {
+    "message": "punguza orodha ya wagombea"
+  },
   "si_slv_settings_page": {
     "message": "Ukurasa wa Mipangilio ya Kibodi ya Kislovania"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Ondoa Uliochaguliwa"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Hifadhi"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json
index 00aa57d..dcf08b3d 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/ta/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0ba4\u0ba9\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f \u0b85\u0b95\u0bb0\u0bbe\u0ba4\u0bbf\u0baf\u0bbf\u0bb2\u0bcd \u0b9a\u0bc7\u0bb0\u0bcd"
+  },
   "advanced": {
     "message": "\u0bae\u0bc7\u0bae\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0bb8\u0bcd\u0baa\u0bbe\u0ba9\u0bbf\u0bb7\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd"
   },
+  "expand": {
+    "message": "\u0bb5\u0bbf\u0bb0\u0bbf\u0bb5\u0bbe\u0b95\u0bcd\u0b95\u0bc1"
+  },
+  "expand_candidates": {
+    "message": "\u0baa\u0bb0\u0bbf\u0ba8\u0bcd\u0ba4\u0bc1\u0bb0\u0bc8\u0baa\u0bcd \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bc8 \u0bb5\u0bbf\u0bb0\u0bbf"
+  },
   "fi_fin_settings_page": {
     "message": "\u0b83\u0baa\u0bbf\u0ba9\u0bcd\u0ba9\u0bbf\u0bb7\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0b90\u0bb0\u0bbf\u0bb7\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd"
   },
+  "ignore_correction": {
+    "message": "\u0b87\u0ba8\u0bcd\u0ba4\u0b9a\u0bcd \u0b9a\u0bca\u0bb2\u0bcd\u0bb2\u0bbf\u0ba9\u0bcd \u0ba4\u0bbf\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0ba4\u0bcd\u0ba4\u0bc8\u0ba4\u0bcd \u0ba4\u0bb5\u0bbf\u0bb0\u0bcd"
+  },
   "il_heb_settings_page": {
     "message": "\u0bb9\u0bc0\u0baa\u0bcd\u0bb0\u0bc1 \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0bb0\u0bcb\u0bae\u0bbe\u0ba9\u0bbf\u0baf\u0ba9\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0bb5\u0bb4\u0b95\u0bcd\u0b95\u0bae\u0bbe\u0ba9 \u0bb0\u0bcb\u0bae\u0bbe\u0ba9\u0bbf\u0baf\u0ba9\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8"
   },
   "keyboard_russian": {
     "message": "\u0bb0\u0bb7\u0bcd\u0baf\u0ba9\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0bb8\u0bcd\u0bb5\u0bc0\u0b9f\u0bbf\u0bb7\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd"
   },
+  "settings": {
+    "message": "\u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd"
+  },
   "shift": {
     "message": "\u0bb7\u0bbf\u0b83\u0baa\u0bcd\u0b9f\u0bc1"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0bb9\u0bbe\u0b99\u0bcd\u0b95\u0bc1\u0bb2\u0bcd \u0baa\u0bb0\u0bbf\u0ba8\u0bcd\u0ba4\u0bc1\u0bb0\u0bc8\u0b95\u0bb3\u0bc8\u0b95\u0bcd \u0b95\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1"
   },
+  "shrink_candidates": {
+    "message": "\u0baa\u0bb0\u0bbf\u0ba8\u0bcd\u0ba4\u0bc1\u0bb0\u0bc8\u0baa\u0bcd \u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bc8\u0b9a\u0bcd \u0b9a\u0bc1\u0bb0\u0bc1\u0b95\u0bcd\u0b95\u0bc1"
+  },
   "si_slv_settings_page": {
     "message": "\u0bb8\u0bcd\u0bb2\u0bcb\u0bb5\u0bc7\u0ba9\u0bbf\u0baf\u0ba9\u0bcd \u0bb5\u0bbf\u0b9a\u0bc8\u0baa\u0bcd\u0baa\u0bb2\u0b95\u0bc8 \u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0bae\u0bcd"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0ba4\u0bc7\u0bb0\u0bcd\u0ba8\u0bcd\u0ba4\u0bc6\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bb5\u0bb1\u0bcd\u0bb1\u0bc8 \u0b85\u0b95\u0bb1\u0bcd\u0bb1\u0bc1"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0b9a\u0bc7\u0bae\u0bbf"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json
index ac15709..086a4ff1 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/te/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0c35\u0c4d\u0c2f\u0c15\u0c4d\u0c24\u0c3f\u0c17\u0c24 \u0c28\u0c3f\u0c18\u0c02\u0c1f\u0c41\u0c35\u0c41\u0c15\u0c3f \u0c1c\u0c4b\u0c21\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+  },
   "advanced": {
     "message": "\u0c05\u0c27\u0c41\u0c28\u0c3e\u0c24\u0c28\u0c02"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0c38\u0c4d\u0c2a\u0c3e\u0c28\u0c3f\u0c37\u0c4d \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d \u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c47\u0c1c\u0c40"
   },
+  "expand": {
+    "message": "\u0c35\u0c3f\u0c38\u0c4d\u0c24\u0c30\u0c3f\u0c02\u0c2a\u0c1c\u0c47\u0c2f\u0c3f"
+  },
+  "expand_candidates": {
+    "message": "\u0c38\u0c42\u0c1a\u0c3f\u0c24 \u0c2a\u0c26\u0c02 \u0c1c\u0c3e\u0c2c\u0c3f\u0c24\u0c3e\u0c28\u0c41 \u0c35\u0c3f\u0c38\u0c4d\u0c24\u0c30\u0c3f\u0c02\u0c2a\u0c1c\u0c47\u0c2f\u0c3f"
+  },
   "fi_fin_settings_page": {
     "message": "\u0c2b\u0c3f\u0c28\u0c4d\u0c28\u0c3f\u0c37\u0c4d \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d \u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c47\u0c1c\u0c40"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0c10\u0c30\u0c3f\u0c37\u0c4d \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d \u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c47\u0c1c\u0c40"
   },
+  "ignore_correction": {
+    "message": "\u0c26\u0c40\u0c28\u0c3f \u0c26\u0c3f\u0c26\u0c4d\u0c26\u0c41\u0c2c\u0c3e\u0c1f\u0c41\u0c28\u0c3f \u0c35\u0c3f\u0c38\u0c4d\u0c2e\u0c30\u0c3f\u0c02\u0c1a\u0c41"
+  },
   "il_heb_settings_page": {
     "message": "\u0c39\u0c3f\u0c2c\u0c4d\u0c30\u0c42 \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d \u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c47\u0c1c\u0c40"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0c30\u0c4a\u0c2e\u0c47\u0c28\u0c3f\u0c2f\u0c28\u0c4d \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0c30\u0c4a\u0c2e\u0c47\u0c28\u0c3f\u0c2f\u0c28\u0c4d \u0c2a\u0c4d\u0c30\u0c3e\u0c2e\u0c3e\u0c23\u0c3f\u0c15 \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d"
   },
   "keyboard_russian": {
     "message": "\u0c30\u0c37\u0c4d\u0c2f\u0c28\u0c4d \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0c38\u0c4d\u0c35\u0c40\u0c21\u0c3f\u0c37\u0c4d \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d \u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c47\u0c1c\u0c40"
   },
+  "settings": {
+    "message": "\u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32\u0c41"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0c39\u0c3e\u0c02\u0c17\u0c41\u0c32\u0c4d \u0c38\u0c42\u0c1a\u0c28\u0c32\u0c28\u0c41 \u0c1a\u0c42\u0c2a\u0c41"
   },
+  "shrink_candidates": {
+    "message": "\u0c38\u0c42\u0c1a\u0c3f\u0c24 \u0c2a\u0c26\u0c02 \u0c1c\u0c3e\u0c2c\u0c3f\u0c24\u0c3e\u0c28\u0c41 \u0c15\u0c41\u0c26\u0c3f\u0c02\u0c1a\u0c41"
+  },
   "si_slv_settings_page": {
     "message": "\u0c38\u0c4d\u0c32\u0c4a\u0c35\u0c47\u0c28\u0c3f\u0c2f\u0c28\u0c4d \u0c15\u0c40\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d \u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c47\u0c1c\u0c40"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0c0e\u0c02\u0c1a\u0c41\u0c15\u0c41\u0c28\u0c4d\u0c28 \u0c35\u0c3e\u0c1f\u0c3f\u0c28\u0c3f \u0c24\u0c40\u0c38\u0c3f\u0c35\u0c47\u0c2f\u0c3f"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0c38\u0c47\u0c35\u0c4d \u0c1a\u0c47\u0c2f\u0c3f"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json
index 4725a785..c433fc09 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/th/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e44\u0e1b\u0e22\u0e31\u0e07\u0e1e\u0e08\u0e19\u0e32\u0e19\u0e38\u0e01\u0e23\u0e21\u0e2a\u0e48\u0e27\u0e19\u0e15\u0e31\u0e27"
+  },
   "advanced": {
     "message": "\u0e02\u0e31\u0e49\u0e19\u0e2a\u0e39\u0e07"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e2a\u0e40\u0e1b\u0e19"
   },
+  "expand": {
+    "message": "\u0e02\u0e22\u0e32\u0e22"
+  },
+  "expand_candidates": {
+    "message": "\u0e02\u0e22\u0e32\u0e22\u0e23\u0e32\u0e22\u0e0a\u0e37\u0e48\u0e2d\u0e1c\u0e39\u0e49\u0e2a\u0e21\u0e31\u0e04\u0e23"
+  },
   "fi_fin_settings_page": {
     "message": "\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e1f\u0e34\u0e19\u0e41\u0e25\u0e19\u0e14\u0e4c"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e44\u0e2d\u0e23\u0e4c\u0e41\u0e25\u0e19\u0e14\u0e4c"
   },
+  "ignore_correction": {
+    "message": "\u0e25\u0e30\u0e40\u0e27\u0e49\u0e19\u0e01\u0e32\u0e23\u0e41\u0e01\u0e49\u0e44\u0e02\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a"
+  },
   "il_heb_settings_page": {
     "message": "\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e2e\u0e35\u0e1a\u0e23\u0e39"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e42\u0e23\u0e21\u0e32\u0e40\u0e19\u0e35\u0e22"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e21\u0e32\u0e15\u0e23\u0e10\u0e32\u0e19\u0e42\u0e23\u0e21\u0e32\u0e40\u0e19\u0e35\u0e22"
   },
   "keyboard_russian": {
     "message": "\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e23\u0e31\u0e2a\u0e40\u0e0b\u0e35\u0e22"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e2a\u0e27\u0e35\u0e40\u0e14\u0e19"
   },
+  "settings": {
+    "message": "\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u0e41\u0e2a\u0e14\u0e07\u0e04\u0e33\u0e41\u0e19\u0e30\u0e19\u0e33\u0e2d\u0e31\u0e01\u0e29\u0e23\u0e2e\u0e31\u0e19\u0e01\u0e36\u0e25"
   },
+  "shrink_candidates": {
+    "message": "\u0e2b\u0e14\u0e23\u0e32\u0e22\u0e0a\u0e37\u0e48\u0e2d\u0e1c\u0e39\u0e49\u0e2a\u0e21\u0e31\u0e04\u0e23"
+  },
   "si_slv_settings_page": {
     "message": "\u0e2b\u0e19\u0e49\u0e32\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e20\u0e32\u0e29\u0e32\u0e2a\u0e42\u0e25\u0e27\u0e35\u0e40\u0e19\u0e35\u0e22"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0e19\u0e33\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e17\u0e35\u0e48\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e2d\u0e2d\u0e01"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json
index c19cdbd2..05d1d34a5 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/tr/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Ki\u015fisel s\u00f6zl\u00fc\u011fe ekle"
+  },
   "advanced": {
     "message": "Geli\u015fmi\u015f"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0130spanyolca Klavye Ayarlar\u0131 Sayfas\u0131"
   },
+  "expand": {
+    "message": "Geni\u015flet"
+  },
+  "expand_candidates": {
+    "message": "\u00f6neri listesini geni\u015flet"
+  },
   "fi_fin_settings_page": {
     "message": "Fince Klavye Ayarlar\u0131 Sayfas\u0131"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0130rlandaca Klavye Ayarlar\u0131 Sayfas\u0131"
   },
+  "ignore_correction": {
+    "message": "\u015eu kelime i\u00e7in d\u00fczeltmeyi yoksay"
+  },
   "il_heb_settings_page": {
     "message": "\u0130branice Klavye Ayarlar\u0131 Sayfas\u0131"
   },
@@ -2847,7 +2859,7 @@
     "message": "Romence klavye"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "Rumence"
   },
   "keyboard_russian": {
     "message": "Rus\u00e7a klavye"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0130sve\u00e7\u00e7e Klavye Ayarlar\u0131 Sayfas\u0131"
   },
+  "settings": {
+    "message": "Ayarlar"
+  },
   "shift": {
     "message": "\u00fcstkrktr"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Hangul \u00f6nerilerini g\u00f6ster"
   },
+  "shrink_candidates": {
+    "message": "\u00f6neri listesini daralt"
+  },
   "si_slv_settings_page": {
     "message": "Slovence Klavye Ayarlar\u0131 Sayfas\u0131"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "Se\u00e7ileni Kald\u0131r"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "Kaydet"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json
index 030d80c..6a1f460 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/uk/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u0414\u043e\u0434\u0430\u0442\u0438 \u0432 \u043e\u0441\u043e\u0431\u0438\u0441\u0442\u0438\u0439 \u0441\u043b\u043e\u0432\u043d\u0438\u043a"
+  },
   "advanced": {
     "message": "\u0420\u043e\u0437\u0448\u0438\u0440\u0435\u043d\u0456"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u044c \u0456\u0441\u043f\u0430\u043d\u0441\u044c\u043a\u043e\u0457 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0438"
   },
+  "expand": {
+    "message": "\u0420\u043e\u0437\u0433\u043e\u0440\u043d\u0443\u0442\u0438"
+  },
+  "expand_candidates": {
+    "message": "\u0440\u043e\u0437\u0433\u043e\u0440\u043d\u0443\u0442\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u0440\u0456\u0430\u043d\u0442\u0456\u0432"
+  },
   "fi_fin_settings_page": {
     "message": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u044c \u0444\u0456\u043d\u0441\u044c\u043a\u043e\u0457 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0438"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u044c \u0456\u0440\u043b\u0430\u043d\u0434\u0441\u044c\u043a\u043e\u0457 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0438"
   },
+  "ignore_correction": {
+    "message": "\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438 \u0432\u0438\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044f \u0441\u043b\u043e\u0432\u0430"
+  },
   "il_heb_settings_page": {
     "message": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u044c \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0438 \u0434\u043b\u044f \u0456\u0432\u0440\u0438\u0442\u0443"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u0420\u0443\u043c\u0443\u043d\u0441\u044c\u043a\u0430 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0430"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430 \u0440\u0443\u043c\u0443\u043d\u0441\u044c\u043a\u0430 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0430"
   },
   "keyboard_russian": {
     "message": "\u0420\u043e\u0441\u0456\u0439\u0441\u044c\u043a\u0430 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0430"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u044c \u0448\u0432\u0435\u0434\u0441\u044c\u043a\u043e\u0457 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0438"
   },
+  "settings": {
+    "message": "\u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f"
+  },
   "shift": {
     "message": "Shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u041f\u043e\u043a\u0430\u0437\u0443\u0432\u0430\u0442\u0438 \u043f\u0440\u043e\u043f\u043e\u0437\u0438\u0446\u0456\u0457 \u0434\u043b\u044f \u0430\u043b\u0444\u0430\u0432\u0456\u0442\u0443 \u0445\u0430\u043d\u0433\u0443\u043b"
   },
+  "shrink_candidates": {
+    "message": "\u0437\u0433\u043e\u0440\u043d\u0443\u0442\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0430\u0440\u0456\u0430\u043d\u0442\u0456\u0432"
+  },
   "si_slv_settings_page": {
     "message": "\u0421\u0442\u043e\u0440\u0456\u043d\u043a\u0430 \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u044c \u0441\u043b\u043e\u0432\u0435\u043d\u0441\u044c\u043a\u043e\u0457 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0438"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0432\u0438\u0434\u0456\u043b\u0435\u043d\u0435"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json
index 2ec90901..fd6ab5a 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/vi/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "Th\u00eam v\u00e0o t\u1eeb \u0111i\u1ec3n c\u00e1 nh\u00e2n"
+  },
   "advanced": {
     "message": "N\u00e2ng cao"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "Trang c\u00e0i \u0111\u1eb7t b\u00e0n ph\u00edm ti\u1ebfng T\u00e2y Ban Nha"
   },
+  "expand": {
+    "message": "M\u1edf r\u1ed9ng"
+  },
+  "expand_candidates": {
+    "message": "m\u1edf r\u1ed9ng danh s\u00e1ch \u1ee9ng vi\u00ean"
+  },
   "fi_fin_settings_page": {
     "message": "Trang c\u00e0i \u0111\u1eb7t b\u00e0n ph\u00edm ti\u1ebfng Ph\u1ea7n Lan"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "Trang c\u00e0i \u0111\u1eb7t b\u00e0n ph\u00edm ti\u1ebfng Ai-len"
   },
+  "ignore_correction": {
+    "message": "B\u1ecf qua t\u00ednh n\u0103ng s\u1eeda cho"
+  },
   "il_heb_settings_page": {
     "message": "Trang c\u00e0i \u0111\u1eb7t b\u00e0n ph\u00edm ti\u1ebfng Do Th\u00e1i"
   },
@@ -2847,7 +2859,7 @@
     "message": "B\u00e0n ph\u00edm ti\u1ebfng Rumani"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "B\u00e0n ph\u00edm chu\u1ea9n ti\u1ebfng Rumani"
   },
   "keyboard_russian": {
     "message": "B\u00e0n ph\u00edm ti\u1ebfng Nga"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "Trang c\u00e0i \u0111\u1eb7t b\u00e0n ph\u00edm ti\u1ebfng Th\u1ee5y \u0110i\u1ec3n"
   },
+  "settings": {
+    "message": "C\u00e0i \u0111\u1eb7t"
+  },
   "shift": {
     "message": "shift"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "Hi\u1ec3n th\u1ecb g\u1ee3i \u00fd b\u1eb1ng ti\u1ebfng Hangul"
   },
+  "shrink_candidates": {
+    "message": "thu nh\u1ecf danh s\u00e1ch \u1ee9ng vi\u00ean"
+  },
   "si_slv_settings_page": {
     "message": "Trang c\u00e0i \u0111\u1eb7t b\u00e0n ph\u00edm ti\u1ebfng Slovenia"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "X\u00f3a m\u1ee5c \u0111\u00e3 ch\u1ecdn"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "L\u01b0u"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json
index 2d333fb1..2e14fe2 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_CN/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u6dfb\u52a0\u5230\u4e2a\u4eba\u5b57\u5178"
+  },
   "advanced": {
     "message": "\u9ad8\u7ea7\u8bbe\u7f6e"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u897f\u73ed\u7259\u8bed\u952e\u76d8\u8bbe\u7f6e\u9875\u9762"
   },
+  "expand": {
+    "message": "\u5c55\u5f00"
+  },
+  "expand_candidates": {
+    "message": "\u5c55\u5f00\u5019\u9009\u5b57\u8bcd\u5217\u8868"
+  },
   "fi_fin_settings_page": {
     "message": "\u82ac\u5170\u8bed\u952e\u76d8\u8bbe\u7f6e\u9875\u9762"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u7231\u5c14\u5170\u8bed\u952e\u76d8\u8bbe\u7f6e\u9875\u9762"
   },
+  "ignore_correction": {
+    "message": "\u4e0d\u81ea\u52a8\u66f4\u6b63\u4ee5\u4e0b\u5b57\u8bcd\uff1a"
+  },
   "il_heb_settings_page": {
     "message": "\u5e0c\u4f2f\u6765\u8bed\u952e\u76d8\u8bbe\u7f6e\u9875\u9762"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u7f57\u9a6c\u5c3c\u4e9a\u8bed\u952e\u76d8"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u7f57\u9a6c\u5c3c\u4e9a\u8bed\u6807\u51c6\u952e\u76d8"
   },
   "keyboard_russian": {
     "message": "\u4fc4\u8bed\u952e\u76d8"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u745e\u5178\u8bed\u952e\u76d8\u8bbe\u7f6e\u9875\u9762"
   },
+  "settings": {
+    "message": "\u8bbe\u7f6e"
+  },
   "shift": {
     "message": "Shift\u952e"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u663e\u793a\u97e9\u8bed\u5efa\u8bae"
   },
+  "shrink_candidates": {
+    "message": "\u6536\u8d77\u5019\u9009\u5b57\u8bcd\u5217\u8868"
+  },
   "si_slv_settings_page": {
     "message": "\u65af\u6d1b\u6587\u5c3c\u4e9a\u8bed\u952e\u76d8\u8bbe\u7f6e\u9875\u9762"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u79fb\u9664\u6240\u9009\u5185\u5bb9"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u4fdd\u5b58"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json
index 21e0a1f..4b16377 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json
+++ b/third_party/google_input_tools/src/chrome/os/inputview/_locales/zh_TW/messages.json
@@ -1,4 +1,7 @@
 {
+  "add_to_personal_dictionary": {
+    "message": "\u52a0\u5165\u500b\u4eba\u5b57\u5178"
+  },
   "advanced": {
     "message": "\u9032\u968e"
   },
@@ -2564,6 +2567,12 @@
   "es_spa_settings_page": {
     "message": "\u897f\u73ed\u7259\u6587\u9375\u76e4\u8a2d\u5b9a\u9801\u9762"
   },
+  "expand": {
+    "message": "\u5c55\u958b"
+  },
+  "expand_candidates": {
+    "message": "\u5c55\u958b\u5019\u9078\u6e05\u55ae"
+  },
   "fi_fin_settings_page": {
     "message": "\u82ac\u862d\u6587\u9375\u76e4\u8a2d\u5b9a\u9801\u9762"
   },
@@ -2621,6 +2630,9 @@
   "ie_ga_settings_page": {
     "message": "\u611b\u723e\u862d\u6587\u9375\u76e4\u8a2d\u5b9a\u9801\u9762"
   },
+  "ignore_correction": {
+    "message": "\u4e0d\u66f4\u6b63\u4ee5\u4e0b\u5b57\u8a5e\uff1a"
+  },
   "il_heb_settings_page": {
     "message": "\u5e0c\u4f2f\u4f86\u6587\u9375\u76e4\u8a2d\u5b9a\u9801\u9762"
   },
@@ -2847,7 +2859,7 @@
     "message": "\u7f85\u99ac\u5c3c\u4e9e\u6587\u9375\u76e4"
   },
   "keyboard_romanian_standard": {
-    "message": "Romanian standard keyboard"
+    "message": "\u7f85\u99ac\u5c3c\u4e9e\u6587\u6a19\u6e96\u9375\u76e4"
   },
   "keyboard_russian": {
     "message": "\u4fc4\u6587\u9375\u76e4"
@@ -3062,6 +3074,9 @@
   "se_swe_settings_page": {
     "message": "\u745e\u5178\u6587\u9375\u76e4\u8a2d\u5b9a\u9801\u9762"
   },
+  "settings": {
+    "message": "\u8a2d\u5b9a"
+  },
   "shift": {
     "message": "Shift \u9375"
   },
@@ -3089,6 +3104,9 @@
   "show_hangul_candidate": {
     "message": "\u986f\u793a\u97d3\u6587\u5efa\u8b70"
   },
+  "shrink_candidates": {
+    "message": "\u6536\u5408\u5019\u9078\u6e05\u55ae"
+  },
   "si_slv_settings_page": {
     "message": "\u65af\u6d1b\u7dad\u5c3c\u4e9e\u6587\u9375\u76e4\u8a2d\u5b9a\u9801\u9762"
   },
@@ -3263,6 +3281,9 @@
   "user_dict_remove": {
     "message": "\u522a\u9664\u6240\u9078\u9805\u76ee"
   },
+  "user_dict_reset": {
+    "message": "Reset All Dictionary Entries"
+  },
   "user_dict_save": {
     "message": "\u5132\u5b58"
   },
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/adapter.js b/third_party/google_input_tools/src/chrome/os/inputview/adapter.js
index c5783d8b..df41620 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/adapter.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/adapter.js
@@ -19,6 +19,7 @@
 goog.require('goog.events.EventType');
 goog.require('goog.object');
 goog.require('i18n.input.chrome.DataSource');
+goog.require('i18n.input.chrome.inputview.GlobalFlags');
 goog.require('i18n.input.chrome.inputview.ReadyState');
 goog.require('i18n.input.chrome.inputview.StateType');
 goog.require('i18n.input.chrome.inputview.events.EventType');
@@ -87,6 +88,17 @@
 var Adapter = i18n.input.chrome.inputview.Adapter;
 
 
+/**
+ * URL prefixes of common Google sites.
+ *
+ * @enum {string}
+ */
+Adapter.GoogleSites = {
+  // TODO: Add support for spreadsheets.
+  DOCS: 'https://docs.google.com/document/d'
+};
+
+
 /** @type {boolean} */
 Adapter.prototype.isA11yMode = false;
 
@@ -96,9 +108,12 @@
 
 
 /** @type {boolean} */
-Adapter.prototype.showGlobeKey = false;
+Adapter.prototype.isVoiceInputEnabled = true;
 
 
+/** @type {boolean} */
+Adapter.prototype.showGlobeKey = false;
+
 /** @type {string} */
 Adapter.prototype.contextType = ContextType.DEFAULT;
 
@@ -135,6 +150,7 @@
  */
 Adapter.prototype.onUpdateSettings_ = function(message) {
   this.screen = message[Name.SCREEN];
+  this.queryCurrentSite();
   this.contextType = /** @type {string} */ (message[Name.CONTEXT_TYPE]);
   // Resets the flag, since when inputview receive the update setting response,
   // it means the background switching is done.
@@ -170,14 +186,25 @@
  * @param {string} code
  * @param {number=} opt_keyCode The key code.
  * @param {!Object=} opt_spatialData .
+ * @param {!Object.<{ctrl: boolean, shift: boolean}>=} opt_modifiers .
  */
 Adapter.prototype.sendKeyDownAndUpEvent = function(key, code, opt_keyCode,
-    opt_spatialData) {
+    opt_spatialData, opt_modifiers) {
   this.sendKeyEvent_([
     this.generateKeyboardEvent_(
-        goog.events.EventType.KEYDOWN, key, code, opt_keyCode, opt_spatialData),
+        goog.events.EventType.KEYDOWN,
+        key,
+        code,
+        opt_keyCode,
+        opt_spatialData,
+        opt_modifiers),
     this.generateKeyboardEvent_(
-        goog.events.EventType.KEYUP, key, code, opt_keyCode, opt_spatialData)
+        goog.events.EventType.KEYUP,
+        key,
+        code,
+        opt_keyCode,
+        opt_spatialData,
+        opt_modifiers)
   ]);
 };
 
@@ -234,14 +261,23 @@
  * @param {string} code The code.
  * @param {number=} opt_keyCode The key code.
  * @param {!Object=} opt_spatialData .
+ * @param {!Object.<{ctrl: boolean, shift: boolean}>=} opt_modifiers .
  * @return {!Object.<string, string|boolean>}
  * @private
  */
 Adapter.prototype.generateKeyboardEvent_ = function(
-    type, key, code, opt_keyCode, opt_spatialData) {
+    type, key, code, opt_keyCode, opt_spatialData, opt_modifiers) {
   var StateType = i18n.input.chrome.inputview.StateType;
   var ctrl = !!this.modifierState_[StateType.CTRL];
   var alt = !!this.modifierState_[StateType.ALT];
+  var shift = !!this.modifierState_[StateType.SHIFT];
+
+  if (opt_modifiers) {
+    if (opt_modifiers.ctrl)
+      ctrl = opt_modifiers.ctrl;
+    if (opt_modifiers.shift)
+      shift = opt_modifiers.shift;
+  }
 
   if (ctrl || alt) {
     key = '';
@@ -256,7 +292,7 @@
 
   result['altKey'] = alt;
   result['ctrlKey'] = ctrl;
-  result['shiftKey'] = !!this.modifierState_[StateType.SHIFT];
+  result['shiftKey'] = shift;
   result['capsLock'] = !!this.modifierState_[StateType.CAPSLOCK];
 
   return result;
@@ -267,12 +303,14 @@
  * Callback when surrounding text is changed.
  *
  * @param {string} text .
+ * @param {number} anchor .
+ * @param {number} focus .
  * @private
  */
-Adapter.prototype.onSurroundingTextChanged_ = function(text) {
+Adapter.prototype.onSurroundingTextChanged_ = function(text, anchor, focus) {
   this.textBeforeCursor = text;
   this.dispatchEvent(new i18n.input.chrome.inputview.events.
-      SurroundingTextChangedEvent(this.textBeforeCursor));
+      SurroundingTextChangedEvent(this.textBeforeCursor, anchor, focus));
 };
 
 
@@ -311,6 +349,31 @@
 
 
 /**
+ * True to enable gesture deletion.
+ *
+ * @return {boolean}
+ */
+Adapter.prototype.isGestureDeletionEnabled = function() {
+  // TODO: Omni bar sends wrong anchor/focus when autocompleting
+  // URLs. Re-enable when that is fixed.
+  if (this.contextType == ContextType.URL) {
+    return false;
+  }
+  return this.isGestureEdittingEnabled();
+};
+
+
+/**
+ * True to enable gesture editting.
+ *
+ * @return {boolean}
+ */
+Adapter.prototype.isGestureEdittingEnabled = function() {
+  return this.isExperimental;
+};
+
+
+/**
  * Callback when blurs in the context.
  *
  * @private
@@ -323,12 +386,55 @@
 
 
 /**
+ * Asynchronously queries the current site.
+ */
+Adapter.prototype.queryCurrentSite = function() {
+  var adapter = this;
+  var criteria = {'active': true, 'lastFocusedWindow': true};
+  if (chrome && chrome.tabs) {
+    chrome.tabs.query(criteria, function(tabs) {
+        tabs[0] && adapter.setCurrentSite_(tabs[0].url);
+    });
+  }
+};
+
+
+/**
+ * Sets the current context URL.
+ *
+ * @param {string} url .
+ * @private
+ */
+Adapter.prototype.setCurrentSite_ = function(url) {
+  if (url != this.currentSite_) {
+    this.currentSite_ = url;
+    this.dispatchEvent(new goog.events.Event(
+        i18n.input.chrome.inputview.events.EventType.URL_CHANGED));
+  }
+};
+
+
+/**
+ * Returns whether the current context is Google Documents.
+ *
+ * @return {boolean} .
+ */
+Adapter.prototype.isGoogleDocument = function() {
+  return this.currentSite_ &&
+      this.currentSite_.lastIndexOf(Adapter.GoogleSites.DOCS) === 0;
+};
+
+
+/**
  * Callback when focus on a context.
  *
  * @param {!Object<string, *>} message .
  * @private
  */
 Adapter.prototype.onContextFocus_ = function(message) {
+  // URL might have changed.
+  this.queryCurrentSite();
+
   this.contextType = /** @type {string} */ (message[Name.CONTEXT_TYPE]);
   this.dispatchEvent(new goog.events.Event(
       i18n.input.chrome.inputview.events.EventType.CONTEXT_FOCUS));
@@ -362,6 +468,10 @@
     }).bind(this));
     chrome.accessibilityFeatures.spokenFeedback.onChange.addListener((function(
         details) {
+          if (!this.isChromeVoxOn && details['value']) {
+            this.dispatchEvent(new goog.events.Event(
+                i18n.input.chrome.inputview.events.EventType.REFRESH));
+          }
           this.isChromeVoxOn = details['value'];
         }).bind(this));
   }
@@ -385,6 +495,12 @@
     }).bind(this));
     inputview.getInputMethodConfig((function(config) {
       this.isQPInputView = !!config['isNewQPInputViewEnabled'];
+      var voiceEnabled = config['isVoiceInputEnabled'];
+      if (goog.isDef(voiceEnabled)) {
+        this.isVoiceInputEnabled = !!voiceEnabled;
+      }
+      i18n.input.chrome.inputview.GlobalFlags.isQPInputView =
+          this.isQPInputView;
       this.readyState_.markStateReady(StateType.INPUT_METHOD_CONFIG_READY);
       this.maybeDispatchSettingsReadyEvent_();
     }).bind(this));
@@ -606,7 +722,9 @@
       this.onContextBlur_();
       break;
     case Type.SURROUNDING_TEXT_CHANGED:
-      this.onSurroundingTextChanged_(request[Name.TEXT]);
+      this.onSurroundingTextChanged_(request[Name.TEXT],
+          request[Name.ANCHOR],
+          request[Name.FOCUS]);
       break;
     case Type.UPDATE_SETTINGS:
       this.onUpdateSettings_(msg);
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/common.css b/third_party/google_input_tools/src/chrome/os/inputview/common.css
index 4a16f54b..1238b4d4 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/common.css
+++ b/third_party/google_input_tools/src/chrome/os/inputview/common.css
@@ -225,6 +225,7 @@
   width: 21px;
   height: 21px;
 }
+.inputview-swipe-view,
 .inputview-menu-view,
 .inputview-altdata-view {
   position: fixed;
@@ -237,12 +238,26 @@
                       0 0 6px rgba(204, 204, 204, 0.65);
   cursor: default;
 }
+.inputview-swipe-separator {
+  background-color: #ebebeb;
+  position: relative;
+  display: inline-block;
+}
 .inputview-altdata-separator {
   height: 20px;
   border-left: 1px solid #ddd;
   position: relative;
   display: inline-block;
 }
+.inputview-swipe-key {
+  background-color: #dddddd;
+  display: table-cell;
+  font-size: 23px;
+  color: black;
+  vertical-align: middle;
+  position: relative;
+  text-align: center;
+}
 .inputview-altdata-key {
   display: table-cell;
   font-size: 23px;
@@ -265,9 +280,13 @@
   display: table-cell;
   height: 32px;
 }
+.inputview-toolbar-button,
 .inputview-candidate-button {
   float: right;
 }
+.inputview-toolbar-button.float-left {
+  float: left;
+}
 .inputview-candidate {
   display: table-cell;
   font-size: 18px;
@@ -279,6 +298,7 @@
 .inputview-a11y .inputview-candidate {
   font-size: 12px;
 }
+.inputview-toolbar-separator,
 .inputview-candidate-separator {
   border-left: 1px solid #ddd;
   position: relative;
@@ -311,6 +331,7 @@
   -webkit-box-shadow: 0 0 5px 1px #397FFB;
   opacity: 0.9;
 }
+.inputview-track-cover,
 .inputview-altdata-cover {
   position: fixed;
   bottom: 0;
@@ -319,6 +340,9 @@
   opacity: 0.5;
   z-index: 1;
 }
+.inputview-track-cover {
+  z-index: 998;
+}
 .inputview-arrow-key {
   display: inline-block;
   height: 13.5px;
@@ -369,6 +393,7 @@
   height: 14.5px;
 }
 .inputview-candidate.inputview-candidate-highlight,
+.inputview-toolbar-button.inputview-candidate-highlight,
 .inputview-element-highlight {
   background-color: #dddddd;
 }
@@ -377,6 +402,10 @@
 .inputview-view .inputview-special-key-bg.inputview-special-key-highlight {
   background-color: #cccccc;
 }
+.inputview-swipe-separator.inputview-element-highlight,
+.inputview-swipe-key.inputview-element-highlight {
+  background-color: #bbbbbb;
+}
 .inputview-backspace-icon {
   background: transparent url('images/backspace.png');
   background-size: 22.5px 13px;
@@ -500,6 +529,60 @@
   width: 16.5px;
 }
 
+.inputview-copy-icon {
+  background: transparent url('images/copy.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-cut-icon {
+  background: transparent url('images/cut.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-paste-icon {
+  background: transparent url('images/paste.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-bold-icon {
+  background: transparent url('images/bold.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-italics-icon {
+  background: transparent url('images/italic.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-underline-icon {
+  background: transparent url('images/underline.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-select-all-icon {
+  background: transparent url('images/select_all.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-redo-icon {
+  background: transparent url('images/redo.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
+.inputview-undo-icon {
+  background: transparent url('images/undo.png') 0 0/17px 16.5px no-repeat;
+  height: 17px;
+  width: 16.5px;
+}
+
 /**
  * The following css style is for handwriting panel,
  * please keep it in the end of the file
@@ -642,6 +725,49 @@
   height: 16px;
   width: 40px;
 }
+.inputview-select-knob-left,
+.inputview-select-knob-right {
+  position: absolute;
+  top: 0;
+  margin: 0;
+  padding: 0;
+  z-index: 100;
+}
+.inputview-select-knob-left {
+  left: 0px;
+}
+.inputview-select-knob-right {
+
+}
+/* Anchor to the center of the column */
+.inputview-select-knob-right > div,
+.inputview-select-knob-left > div {
+  width: 100%;
+  position: relative;
+  height: 1px;
+  top: 50%;
+  left: 0;
+}
+/* Semi-circular knob */
+.inputview-select-knob-left > div > div,
+.inputview-select-knob-right > div > div {
+  width : 100%;
+  height: 50px;
+  background-color: #dddddd;
+  -webkit-transform: translateY(-25px);
+  line-height: 50px;
+  color: white;
+  text-align: center;
+  font-size: medium;
+  font-weight: bolder;
+}
+.inputview-select-knob-left > div > div {
+  -webkit-border-radius: 0 30px 30px 0;
+}
+.inputview-select-knob-right > div > div {
+  -webkit-border-radius: 30px 0 0 30px;
+}
+
 .inputview-candidate-internal-wrapper {
   text-overflow: ellipsis;
   overflow-x: hidden;
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/config/material/emoji_data.js b/third_party/google_input_tools/src/chrome/os/inputview/config/material/emoji_data.js
new file mode 100644
index 0000000..a0b6da8
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/config/material/emoji_data.js
@@ -0,0 +1,557 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.EmojiType');
+goog.require('i18n.input.chrome.inputview.SpecNodeName');
+goog.require('i18n.input.chrome.inputview.content.util');
+goog.require('i18n.input.chrome.inputview.elements.ElementType');
+
+(function() {
+
+  var viewIdPrefix = 'emoji-k-';
+  var emojiKeyAmount = 27;
+  var util = i18n.input.chrome.inputview.content.util;
+  var ElementType = i18n.input.chrome.inputview.elements.ElementType;
+  var EmojiType = i18n.input.chrome.inputview.EmojiType;
+  var SpecNodeName = i18n.input.chrome.inputview.SpecNodeName;
+  var Css = i18n.input.chrome.inputview.Css;
+
+  var keyCharacters = [
+    // Recent
+    [''],
+
+    // Hot
+    ['\u2665', '\ud83d\ude02', '\u263a',
+      '\u2764', '\ud83d\ude12', '\ud83d\ude0d',
+      '\ud83d\udc4c', '\ud83d\ude18', '\ud83d\ude0a',
+      '\ud83d\ude14', '\ud83d\ude0f', '\ud83d\ude29',
+      '\ud83d\ude01', '\ud83d\ude2d', '\ud83d\ude33',
+      '\ud83d\udc95', '\u270c', '\ud83d\udc4d',
+      '\ud83d\ude09', '\ud83d\udc81', '\ud83d\ude4c',
+      '\ud83d\ude0c', '\ud83d\ude0e', '\ud83d\ude48',
+      '\ud83d\ude11', '\ud83d\ude1c', '\ud83d\ude0b',
+      '\ud83d\ude1e', '\ud83d\ude4f', '\u270b',
+      '\ud83d\ude04', '\ud83d\ude4a', '\ud83d\ude15',
+      '\ud83d\ude21', '\ud83d\udc4f', '\ud83d\ude22',
+      '\ud83d\ude34', '\ud83d\udc40', '\ud83d\ude10',
+      '\ud83d\ude31', '\ud83d\ude2b', '\ud83d\ude1d',
+      '\ud83d\udc9c', '\ud83d\udc94', '\ud83d\udc8b',
+      '\ud83d\ude03', '\ud83d\ude2a', '\ud83d\ude23',
+      '\ud83d\udc99', '\ud83d\ude24', '\ud83d\udc4b',
+      '\ud83d\udc4a', '\ud83d\ude37', '\ud83d\ude20',
+      '\ud83d\ude16', '\ud83d\ude2c', '\ud83d\udc97',
+      '\ud83d\ude45', '\ud83d\ude08', '\ud83d\ude05',
+      '\ud83d\udc4e', '\ud83d\ude25', '\ud83d\ude4b',
+      '\ud83d\ude06', '\ud83d\ude13', '\ud83d\udcaa',
+      '\ud83d\udc96', '\ud83d\ude36', '\ud83d\ude1a',
+      '\ud83d\udc9b', '\ud83d\udc9a', '\ud83d\ude1b',
+      '\ud83d\udc83', '\ud83d\udc9e', '\ud83d\ude00',
+      '\ud83d\ude30', '\u270a', '\ud83d\udca9',
+      '\ud83d\udc98', '\u261d'],
+
+    // Emotion
+    ['\u263a', '\ud83d\ude0a', '\ud83d\ude00',
+     '\ud83d\ude01', '\ud83d\ude02', '\ud83d\ude03',
+     '\ud83d\ude04', '\ud83d\ude05', '\ud83d\ude06',
+     '\ud83d\ude07', '\ud83d\ude08', '\ud83d\ude09',
+     '\ud83d\ude2f', '\ud83d\ude10', '\ud83d\ude11',
+     '\ud83d\ude15', '\ud83d\ude20', '\ud83d\ude2c',
+     '\ud83d\ude21', '\ud83d\ude22', '\ud83d\ude34',
+     '\ud83d\ude2e', '\ud83d\ude23', '\ud83d\ude24',
+     '\ud83d\ude25', '\ud83d\ude26', '\ud83d\ude27',
+     '\ud83d\ude28', '\ud83d\ude29', '\ud83d\ude30',
+     '\ud83d\ude1f', '\ud83d\ude31', '\ud83d\ude32',
+     '\ud83d\ude33', '\ud83d\ude35', '\ud83d\ude36',
+     '\ud83d\ude37', '\ud83d\ude1e', '\ud83d\ude12',
+     '\ud83d\ude0d', '\ud83d\ude1b', '\ud83d\ude1c',
+     '\ud83d\ude1d', '\ud83d\ude0b', '\ud83d\ude17',
+     '\ud83d\ude19', '\ud83d\ude18', '\ud83d\ude1a',
+     '\ud83d\ude0e', '\ud83d\ude2d', '\ud83d\ude0c',
+     '\ud83d\ude16', '\ud83d\ude14', '\ud83d\ude2a',
+     '\ud83d\ude0f', '\ud83d\ude13', '\ud83d\ude2b',
+     '\ud83d\ude4b', '\ud83d\ude4c', '\ud83d\ude4d',
+     '\ud83d\ude45', '\ud83d\ude46' , '\ud83d\ude47',
+     '\ud83d\ude4e', '\ud83d\ude4f', '\ud83d\ude3a',
+     '\ud83d\ude3c', '\ud83d\ude38' , '\ud83d\ude39',
+     '\ud83d\ude3b', '\ud83d\ude3d', '\ud83d\ude3f',
+     '\ud83d\ude3e', '\ud83d\ude40', '\ud83d\ude48',
+     '\ud83d\ude49', '\ud83d\ude4a', '\ud83d\udca9',
+     '\ud83d\udc76', '\ud83d\udc66', '\ud83d\udc67',
+     '\ud83d\udc68', '\ud83d\udc69', '\ud83d\udc74',
+     '\ud83d\udc75', '\ud83d\udc8f', '\ud83d\udc91',
+     '\ud83d\udc6a', '\ud83d\udc6b', '\ud83d\udc6c',
+     '\ud83d\udc6d', '\ud83d\udc64', '\ud83d\udc65',
+     '\ud83d\udc6e', '\ud83d\udc77', '\ud83d\udc81',
+     '\ud83d\udc82', '\ud83d\udc6f', '\ud83d\udc70',
+     '\ud83d\udc78', '\ud83c\udf85', '\ud83d\udc7c',
+     '\ud83d\udc71', '\ud83d\udc72', '\ud83d\udc73',
+     '\ud83d\udc83', '\ud83d\udc86', '\ud83d\udc87',
+     '\ud83d\udc85', '\ud83d\udc7b', '\ud83d\udc79',
+     '\ud83d\udc7a', '\ud83d\udc7d', '\ud83d\udc7e',
+     '\ud83d\udc7f', '\ud83d\udc80', '\ud83d\udcaa',
+     '\ud83d\udc40', '\ud83d\udc42', '\ud83d\udc43',
+     '\ud83d\udc63', '\ud83d\udc44', '\ud83d\udc45',
+     '\ud83d\udc8b', '\u2764', '\ud83d\udc99',
+     '\ud83d\udc9a', '\ud83d\udc9b', '\ud83d\udc9c',
+     '\ud83d\udc93', '\ud83d\udc94', '\ud83d\udc95',
+     '\ud83d\udc96', '\ud83d\udc97', '\ud83d\udc98',
+     '\ud83d\udc9d', '\ud83d\udc9e', '\ud83d\udc9f',
+     '\ud83d\udc4d', '\ud83d\udc4e', '\ud83d\udc4c',
+     '\u270a', '\u270c', '\u270b',
+     '\ud83d\udc4a', '\u261d', '\ud83d\udc46',
+     '\ud83d\udc47', '\ud83d\udc48', '\ud83d\udc49',
+     '\ud83d\udc4b', '\ud83d\udc4f', '\ud83d\udc50'],
+
+    // Items
+    ['\ud83d\udd30', '\ud83d\udc84', '\ud83d\udc5e',
+     '\ud83d\udc5f', '\ud83d\udc51', '\ud83d\udc52',
+     '\ud83c\udfa9', '\ud83c\udf93', '\ud83d\udc53',
+     '\u231a', '\ud83d\udc54', '\ud83d\udc55',
+     '\ud83d\udc56', '\ud83d\udc57', '\ud83d\udc58',
+     '\ud83d\udc59', '\ud83d\udc60', '\ud83d\udc61',
+     '\ud83d\udc62', '\ud83d\udc5a', '\ud83d\udc5c',
+     '\ud83d\udcbc', '\ud83c\udf92', '\ud83d\udc5d',
+     '\ud83d\udc5b', '\ud83d\udcb0', '\ud83d\udcb3',
+     '\ud83d\udcb2', '\ud83d\udcb5', '\ud83d\udcb4',
+     '\ud83d\udcb6', '\ud83d\udcb7', '\ud83d\udcb8',
+     '\ud83d\udcb1', '\ud83d\udcb9', '\ud83d\udd2b',
+     '\ud83d\udd2a', '\ud83d\udca3', '\ud83d\udc89',
+     '\ud83d\udc8a', '\ud83d\udeac', '\ud83d\udd14',
+     '\ud83d\udd15', '\ud83d\udeaa', '\ud83d\udd2c',
+     '\ud83d\udd2d', '\ud83d\udd2e', '\ud83d\udd26',
+     '\ud83d\udd0b', '\ud83d\udd0c', '\ud83d\udcdc',
+     '\ud83d\udcd7', '\ud83d\udcd8', '\ud83d\udcd9',
+     '\ud83d\udcda', '\ud83d\udcd4', '\ud83d\udcd2',
+     '\ud83d\udcd1', '\ud83d\udcd3', '\ud83d\udcd5',
+     '\ud83d\udcd6', '\ud83d\udcf0', '\ud83d\udcdb',
+     '\ud83c\udf83', '\ud83c\udf84', '\ud83c\udf80',
+     '\ud83c\udf81', '\ud83c\udf82', '\ud83c\udf88',
+     '\ud83c\udf86', '\ud83c\udf87', '\ud83c\udf89',
+     '\ud83c\udf8a', '\ud83c\udf8d', '\ud83c\udf8f',
+     '\ud83c\udf8c', '\ud83c\udf90', '\ud83c\udf8b',
+     '\ud83c\udf8e', '\ud83d\udcf1', '\ud83d\udcf2',
+     '\ud83d\udcdf', '\u260e', '\ud83d\udcde',
+     '\ud83d\udce0', '\ud83d\udce6', '\u2709',
+     '\ud83d\udce8', '\ud83d\udce9', '\ud83d\udcea',
+     '\ud83d\udceb', '\ud83d\udced', '\ud83d\udcec',
+     '\ud83d\udcee', '\ud83d\udce4', '\ud83d\udce5',
+     '\ud83d\udcef', '\ud83d\udce2', '\ud83d\udce3',
+     '\ud83d\udce1', '\ud83d\udcac', '\ud83d\udcad',
+     '\u2712', '\u270f', '\ud83d\udcdd',
+     '\ud83d\udccf', '\ud83d\udcd0', '\ud83d\udccd',
+     '\ud83d\udccc', '\ud83d\udcce', '\u2702',
+     '\ud83d\udcba', '\ud83d\udcbb', '\ud83d\udcbd',
+     '\ud83d\udcbe', '\ud83d\udcbf', '\ud83d\udcc6',
+     '\ud83d\udcc5', '\ud83d\udcc7', '\ud83d\udccb',
+     '\ud83d\udcc1', '\ud83d\udcc2', '\ud83d\udcc3',
+     '\ud83d\udcc4', '\ud83d\udcca', '\ud83d\udcc8',
+     '\ud83d\udcc9', '\u26fa', '\ud83c\udfa1',
+     '\ud83c\udfa2', '\ud83c\udfa0', '\ud83c\udfaa',
+     '\ud83c\udfa8', '\ud83c\udfac', '\ud83c\udfa5',
+     '\ud83d\udcf7', '\ud83d\udcf9', '\ud83c\udfa6',
+     '\ud83c\udfad', '\ud83c\udfab', '\ud83c\udfae',
+     '\ud83c\udfb2', '\ud83c\udfb0', '\ud83c\udccf',
+     '\ud83c\udfb4', '\ud83c\udc04', '\ud83c\udfaf',
+     '\ud83d\udcfa', '\ud83d\udcfb', '\ud83d\udcc0',
+     '\ud83d\udcfc', '\ud83c\udfa7', '\ud83c\udfa4',
+     '\ud83c\udfb5', '\ud83c\udfb6', '\ud83c\udfbc',
+     '\ud83c\udfbb', '\ud83c\udfb9', '\ud83c\udfb7',
+     '\ud83c\udfba', '\ud83c\udfb8', '\u303d'],
+
+    // Nature
+    ['\ud83d\udc15', '\ud83d\udc36', '\ud83d\udc29',
+     '\ud83d\udc08', '\ud83d\udc31', '\ud83d\udc00',
+     '\ud83d\udc01', '\ud83d\udc2d', '\ud83d\udc39',
+     '\ud83d\udc22', '\ud83d\udc07', '\ud83d\udc30',
+     '\ud83d\udc13', '\ud83d\udc14', '\ud83d\udc23',
+     '\ud83d\udc24', '\ud83d\udc25', '\ud83d\udc26',
+     '\ud83d\udc0f', '\ud83d\udc11', '\ud83d\udc10',
+     '\ud83d\udc3a', '\ud83d\udc03', '\ud83d\udc02',
+     '\ud83d\udc04', '\ud83d\udc2e', '\ud83d\udc34',
+     '\ud83d\udc17', '\ud83d\udc16', '\ud83d\udc37',
+     '\ud83d\udc3d', '\ud83d\udc38', '\ud83d\udc0d',
+     '\ud83d\udc3c', '\ud83d\udc27', '\ud83d\udc18',
+     '\ud83d\udc28', '\ud83d\udc12', '\ud83d\udc35',
+     '\ud83d\udc06', '\ud83d\udc2f', '\ud83d\udc3b',
+     '\ud83d\udc2b', '\ud83d\udc2a', '\ud83d\udc0a',
+     '\ud83d\udc33', '\ud83d\udc0b', '\ud83d\udc1f',
+     '\ud83d\udc20', '\ud83d\udc21', '\ud83d\udc19',
+     '\ud83d\udc1a', '\ud83d\udc2c', '\ud83d\udc0c',
+     '\ud83d\udc1b', '\ud83d\udc1c', '\ud83d\udc1d',
+     '\ud83d\udc1e', '\ud83d\udc32', '\ud83d\udc09',
+     '\ud83d\udc3e', '\ud83c\udf78', '\ud83c\udf7a',
+     '\ud83c\udf7b', '\ud83c\udf77', '\ud83c\udf79',
+     '\ud83c\udf76', '\u2615', '\ud83c\udf75',
+     '\ud83c\udf7c', '\ud83c\udf74', '\ud83c\udf68',
+     '\ud83c\udf67', '\ud83c\udf66', '\ud83c\udf69',
+     '\ud83c\udf70', '\ud83c\udf6a', '\ud83c\udf6b',
+     '\ud83c\udf6c', '\ud83c\udf6d', '\ud83c\udf6e',
+     '\ud83c\udf6f', '\ud83c\udf73', '\ud83c\udf54',
+     '\ud83c\udf5f', '\ud83c\udf5d', '\ud83c\udf55',
+     '\ud83c\udf56', '\ud83c\udf57', '\ud83c\udf64',
+     '\ud83c\udf63', '\ud83c\udf71', '\ud83c\udf5e',
+     '\ud83c\udf5c', '\ud83c\udf59', '\ud83c\udf5a',
+     '\ud83c\udf5b', '\ud83c\udf72', '\ud83c\udf65',
+     '\ud83c\udf62', '\ud83c\udf61', '\ud83c\udf58',
+     '\ud83c\udf60', '\ud83c\udf4c', '\ud83c\udf4e',
+     '\ud83c\udf4f', '\ud83c\udf4a', '\ud83c\udf4b',
+     '\ud83c\udf44', '\ud83c\udf45', '\ud83c\udf46',
+     '\ud83c\udf47', '\ud83c\udf48', '\ud83c\udf49',
+     '\ud83c\udf50', '\ud83c\udf51', '\ud83c\udf52',
+     '\ud83c\udf53', '\ud83c\udf4d', '\ud83c\udf30',
+     '\ud83c\udf31', '\ud83c\udf32', '\ud83c\udf33',
+     '\ud83c\udf34', '\ud83c\udf35', '\ud83c\udf37',
+     '\ud83c\udf38', '\ud83c\udf39', '\ud83c\udf40',
+     '\ud83c\udf41', '\ud83c\udf42', '\ud83c\udf43',
+     '\ud83c\udf3a', '\ud83c\udf3b', '\ud83c\udf3c',
+     '\ud83c\udf3d', '\ud83c\udf3e', '\ud83c\udf3f',
+     '\u2600', '\ud83c\udf08', '\u26c5',
+     '\u2601', '\ud83c\udf01', '\ud83c\udf02',
+     '\u2614', '\ud83d\udca7', '\u26a1',
+     '\ud83c\udf00', '\u2744', '\u26c4',
+     '\ud83c\udf19', '\ud83c\udf1e', '\ud83c\udf1d',
+     '\ud83c\udf1a', '\ud83c\udf1b', '\ud83c\udf1c',
+     '\ud83c\udf11', '\ud83c\udf12', '\ud83c\udf13',
+     '\ud83c\udf14', '\ud83c\udf15', '\ud83c\udf16',
+     '\ud83c\udf17', '\ud83c\udf18', '\ud83c\udf91',
+     '\ud83c\udf04', '\ud83c\udf05', '\ud83c\udf07',
+     '\ud83c\udf06', '\ud83c\udf03', '\ud83c\udf0c',
+     '\ud83c\udf09', '\ud83c\udf0a', '\ud83c\udf0b',
+     '\ud83c\udf0e', '\ud83c\udf0f', '\ud83c\udf0d',
+     '\ud83c\udf10'],
+
+    // Places of interests
+    ['\ud83c\udfe0', '\ud83c\udfe1', '\ud83c\udfe2',
+     '\ud83c\udfe3', '\ud83c\udfe4', '\ud83c\udfe5',
+     '\ud83c\udfe6', '\ud83c\udfe7', '\ud83c\udfe8',
+     '\ud83c\udfe9', '\ud83c\udfea', '\ud83c\udfeb',
+     '\u26ea', '\u26f2', '\ud83c\udfec',
+     '\ud83c\udfef', '\ud83c\udff0', '\ud83c\udfed',
+     '\ud83d\uddfb', '\ud83d\uddfc', '\ud83d\uddfd',
+     '\ud83d\uddfe', '\ud83d\uddff', '\u2693',
+     '\ud83c\udfee', '\ud83d\udc88', '\ud83d\udd27',
+     '\ud83d\udd28', '\ud83d\udd29', '\ud83d\udebf',
+     '\ud83d\udec1', '\ud83d\udec0', '\ud83d\udebd',
+     '\ud83d\udebe', '\ud83c\udfbd', '\ud83c\udfa3',
+     '\ud83c\udfb1', '\ud83c\udfb3', '\u26be',
+     '\u26f3', '\ud83c\udfbe', '\u26bd',
+     '\ud83c\udfbf', '\ud83c\udfc0', '\ud83c\udfc1',
+     '\ud83c\udfc2', '\ud83c\udfc3', '\ud83c\udfc4',
+     '\ud83c\udfc6', '\ud83c\udfc7', '\ud83d\udc0e',
+     '\ud83c\udfc8', '\ud83c\udfc9', '\ud83c\udfca',
+     '\ud83d\ude82', '\ud83d\ude83', '\ud83d\ude84',
+     '\ud83d\ude85', '\ud83d\ude86', '\ud83d\ude87',
+     '\u24c2', '\ud83d\ude88', '\ud83d\ude8a',
+     '\ud83d\ude8b', '\ud83d\ude8c', '\ud83d\ude8d',
+     '\ud83d\ude8e', '\ud83d\ude8f', '\ud83d\ude90',
+     '\ud83d\ude91', '\ud83d\ude92', '\ud83d\ude93',
+     '\ud83d\ude94', '\ud83d\ude95', '\ud83d\ude96',
+     '\ud83d\ude97', '\ud83d\ude98', '\ud83d\ude99',
+     '\ud83d\ude9a', '\ud83d\ude9b', '\ud83d\ude9c',
+     '\ud83d\ude9d', '\ud83d\ude9e', '\ud83d\ude9f',
+     '\ud83d\udea0', '\ud83d\udea1', '\ud83d\udea2',
+     '\ud83d\udea3', '\ud83d\ude81', '\u2708',
+     '\ud83d\udec2', '\ud83d\udec3', '\ud83d\udec4',
+     '\ud83d\udec5', '\u26f5', '\ud83d\udeb2',
+     '\ud83d\udeb3', '\ud83d\udeb4', '\ud83d\udeb5',
+     '\ud83d\udeb7', '\ud83d\udeb8', '\ud83d\ude89',
+     '\ud83d\ude80', '\ud83d\udea4', '\ud83d\udeb6',
+     '\u26fd', '\ud83c\udd7f', '\ud83d\udea5',
+     '\ud83d\udea6', '\ud83d\udea7', '\ud83d\udea8',
+     '\u2668', '\ud83d\udc8c', '\ud83d\udc8d',
+     '\ud83d\udc8e', '\ud83d\udc90', '\ud83d\udc92'],
+
+    // Special characters
+    ['\ud83d\udd1d', '\ud83d\udd19', '\ud83d\udd1b',
+     '\ud83d\udd1c', '\ud83d\udd1a', '\u23f3',
+     '\u231b', '\u23f0', '\u2648',
+     '\u2649', '\u264a', '\u264b',
+     '\u264c', '\u264d', '\u264e',
+     '\u264f', '\u2650', '\u2651',
+     '\u2652', '\u2653', '\u26ce',
+     '\ud83d\udd31', '\ud83d\udd2f', '\ud83d\udebb',
+     '\ud83d\udeae', '\ud83d\udeaf', '\ud83d\udeb0',
+     '\ud83d\udeb1', '\ud83c\udd70', '\ud83c\udd71',
+     '\ud83c\udd8e', '\ud83c\udd7e', '\ud83d\udcae',
+     '\ud83d\udcaf', '\ud83d\udd20', '\ud83d\udd21',
+     '\ud83d\udd22', '\ud83d\udd23', '\ud83d\udd24',
+     '\u27bf', '\ud83d\udcf6', '\ud83d\udcf3',
+     '\ud83d\udcf4', '\ud83d\udcf5', '\ud83d\udeb9',
+     '\ud83d\udeba', '\ud83d\udebc', '\u267f',
+     '\u267b', '\ud83d\udead', '\ud83d\udea9',
+     '\u26a0', '\ud83c\ude01', '\ud83d\udd1e',
+     '\u26d4', '\ud83c\udd92', '\ud83c\udd97',
+     '\ud83c\udd95', '\ud83c\udd98', '\ud83c\udd99',
+     '\ud83c\udd93', '\ud83c\udd96', '\ud83c\udd9a',
+     '\ud83c\ude32', '\ud83c\ude33', '\ud83c\ude34',
+     '\ud83c\ude35', '\ud83c\ude36', '\ud83c\ude37',
+     '\ud83c\ude38', '\ud83c\ude39', '\ud83c\ude02',
+     '\ud83c\ude3a', '\ud83c\ude50', '\ud83c\ude51',
+     '\u3299', '\u00ae', '\u00a9',
+     '\u2122', '\ud83c\ude1a', '\ud83c\ude2f',
+     '\u3297', '\u2b55', '\u274c',
+     '\u274e', '\u2139', '\ud83d\udeab',
+     '\u2705', '\u2714', '\ud83d\udd17',
+     '\u2734', '\u2733', '\u2795',
+     '\u2796', '\u2716', '\u2797',
+     '\ud83d\udca0', '\ud83d\udca1', '\ud83d\udca4',
+     '\ud83d\udca2', '\ud83d\udd25', '\ud83d\udca5',
+     '\ud83d\udca8', '\ud83d\udca6', '\ud83d\udcab',
+     '\ud83d\udd5b', '\ud83d\udd67', '\ud83d\udd50',
+     '\ud83d\udd5c', '\ud83d\udd51', '\ud83d\udd5d',
+     '\ud83d\udd52', '\ud83d\udd5e', '\ud83d\udd53',
+     '\ud83d\udd5f', '\ud83d\udd54', '\ud83d\udd60',
+     '\ud83d\udd55', '\ud83d\udd61', '\ud83d\udd56',
+     '\ud83d\udd62', '\ud83d\udd57', '\ud83d\udd63',
+     '\ud83d\udd58', '\ud83d\udd64', '\ud83d\udd59',
+     '\ud83d\udd65', '\ud83d\udd5a', '\ud83d\udd66',
+     '\u2195', '\u2b06', '\u2197',
+     '\u27a1', '\u2198', '\u2b07',
+     '\u2199', '\u2b05', '\u2196',
+     '\u2194', '\u2934', '\u2935',
+     '\u23ea', '\u23eb', '\u23ec',
+     '\u23e9', '\u25c0', '\u25b6',
+     '\ud83d\udd3d', '\ud83d\udd3c', '\u2747',
+     '\u2728', '\ud83d\udd34', '\ud83d\udd35',
+     '\u26aa', '\u26ab', '\ud83d\udd33',
+     '\ud83d\udd32', '\u2b50', '\ud83c\udf1f',
+     '\ud83c\udf20', '\u25ab', '\u25aa',
+     '\u25fd', '\u25fe', '\u25fb',
+     '\u25fc', '\u2b1c', '\u2b1b',
+     '\ud83d\udd38', '\ud83d\udd39', '\ud83d\udd36',
+     '\ud83d\udd37', '\ud83d\udd3a', '\ud83d\udd3b',
+     '\u2754', '\u2753', '\u2755',
+     '\u2757', '\u203c', '\u2049',
+     '\u3030', '\u27b0', '\u2660',
+     '\u2665', '\u2663', '\u2666',
+     '\ud83c\udd94', '\ud83d\udd11', '\u21a9',
+     '\ud83c\udd91', '\ud83d\udd0d', '\ud83d\udd12',
+     '\ud83d\udd13', '\u21aa', '\ud83d\udd10',
+     '\u2611', '\ud83d\udd18', '\ud83d\udd0e',
+     '\ud83d\udd16', '\ud83d\udd0f', '\ud83d\udd03',
+     '\ud83d\udd00', '\ud83d\udd01', '\ud83d\udd02',
+     '\ud83d\udd04', '\ud83d\udce7', '\ud83d\udd05',
+     '\ud83d\udd06', '\ud83d\udd07', '\ud83d\udd08',
+     '\ud83d\udd09', '\ud83d\udd0a'],
+
+    // Emoticon
+    [':)',
+     ';-)',
+     ':-D',
+     ':P',
+     ':-(',
+     ':\'(',
+     ':-)',
+     ':-*',
+     ':-$',
+     ':-\\',
+     ':-[',
+     ':-!',
+     ':S',
+     ':O',
+     ':-O',
+     'B-)',
+     'o_O',
+     'O_o',
+     '^O^',
+     '-.-',
+     '^_^',
+     '^﹏^',
+     '^m^',
+     '^/^',
+     '~_~',
+     '-_-',
+     '-_-||',
+     '>_<',
+     '><',
+     '>﹏<',
+     '_#',
+     '\#_#',
+     '*-*',
+     '(^^)',
+     '(^_^)',
+     '(^.^)',
+     '(^!^)',
+     '(^J^)',
+     '(^m^)',
+     '(^\'^)',
+     '(^_-)',
+     '(^O^)',
+     '(^o^)',
+     '(^q^)',
+     '(^○^)',
+     '(^O^;)',
+     '(^m^;)',
+     '(^Q^)',
+     '!(^^)!',
+     'T_T',
+     '(ToT)',
+     '(T_T)',
+     '\@_\@',
+     '=.=',
+     '=.=!',
+     '=_=',
+     '╰_╯',
+     '-_-z',
+     '^_-',
+     '囧rz',
+     'Orz',
+     '→_→',
+     '←_←',
+     '≧◇≦',
+     '(x_x)',
+     '(′o`)',
+     '(′ェ`)',
+     '(?_?)',
+     '(′θ`)',
+     '(*_*)',
+     '(@@)',
+     '⊙▽⊙',
+     '⊙△⊙',
+     '⊙_⊙',
+     '⊙﹏⊙',
+     '◑﹏◐',
+     '◑︿◐',
+     '◑__◐',
+     '∩__∩',
+     '∩﹏∩',
+     '(ˇˍˇ)',
+     '(′▽`〃)',
+     '(′0ノ`*)',
+     '(^_^;)',
+     '(@_@)',
+     '(*^^*)',
+     '(´・ω・`)',
+     '(=θωθ=)',
+     '(°ο°)',
+     '^(oo)^',
+     '(#^.^#)',
+     '(*^_^*)',
+     '(¯(●●)¯)',
+     '>"<|||',
+     '(′~`;)',
+     '(=′?`=)',
+     '(○’ω’○)',
+     'o(≧o≦)o',
+     '(??_??)?',
+     '└(^o^)┘',
+     '(︶^︶)',
+     '(>.<*)',
+     '(⊙o⊙)',
+     '(⊙﹏⊙)',
+     '=^_^=',
+     '::>_<::',
+     '↖(^ω^)↗',
+     '~w_w~']
+  ];
+  var keyList = [];
+  var mapping = {};
+  keyList.push(util.createTabBarKey('Tabbar0', EmojiType.RECENT,
+      Css.EMOJI_TABBAR_RECENT));
+  keyList.push(util.createTabBarKey('Tabbar1', EmojiType.HOT,
+      Css.EMOJI_TABBAR_HOT));
+  keyList.push(util.createTabBarKey('Tabbar2', EmojiType.EMOTION,
+      Css.EMOJI_TABBAR_EMOTION));
+  keyList.push(util.createTabBarKey('Tabbar3', EmojiType.ITEMS,
+      Css.EMOJI_TABBAR_ITEMS));
+  keyList.push(util.createTabBarKey('Tabbar4', EmojiType.NATURE,
+      Css.EMOJI_TABBAR_NATURE));
+  keyList.push(util.createTabBarKey('Tabbar5', EmojiType.PLACES_OF_INTERESTS,
+      Css.EMOJI_TABBAR_PLACES_OF_INTERESTS));
+  keyList.push(util.createTabBarKey('Tabbar6',
+      EmojiType.SPECIAL_CHARACTERS,
+      Css.EMOJI_TABBAR_SPECIAL_CHARACTERS));
+  keyList.push(util.createTabBarKey('Tabbar7', EmojiType.EMOTICON,
+      Css.EMOJI_TABBAR_EMOTICON));
+
+  var amount = 0;
+  var acturalLength = 0;
+  for (var i = 0, len = keyCharacters.length; i < len; i++) {
+    acturalLength = Math.ceil(keyCharacters[i].length / emojiKeyAmount) *
+        emojiKeyAmount;
+    for (var j = 0, lenJ = keyCharacters[i].length; j < lenJ; j++) {
+      var spec = {};
+      spec[SpecNodeName.ID] = 'emojikey' + amount;
+      spec[SpecNodeName.TYPE] = ElementType.EMOJI_KEY;
+      spec[SpecNodeName.TEXT] = keyCharacters[i][j];
+      spec[SpecNodeName.IS_EMOTICON] = (i == EmojiType.EMOTICON);
+      var key = i18n.input.chrome.inputview.content.util.createKey(spec);
+      keyList.push(key);
+      amount++;
+    }
+    for (var j = keyCharacters[i].length; j < acturalLength; j++) {
+      var spec = {};
+      spec[SpecNodeName.ID] = 'emojikey' + amount;
+      spec[SpecNodeName.TYPE] = ElementType.EMOJI_KEY;
+      spec[SpecNodeName.TEXT] = '';
+      spec[SpecNodeName.IS_EMOTICON] = (i == EmojiType.EMOTICON);
+      var key = i18n.input.chrome.inputview.content.util.createKey(spec);
+      keyList.push(key);
+      amount++;
+    }
+  }
+  keyList.push(util.createBackspaceKey());
+  keyList.push(util.createEnterKey());
+  keyList.push(util.createHideKeyboardKey());
+
+  var tabbarLength = 1 + keyCharacters.length;
+  var key = [];
+
+  // Map the tabbars.
+  for (var i = 0, len = keyCharacters.length; i < len; i++) {
+    key = keyList[i];
+    mapping[key['spec'][SpecNodeName.ID]] = viewIdPrefix + i;
+  }
+
+  // Map the emoji keys.
+  amount = 0;
+  var offset = tabbarLength + 1;
+  for (var i = 0, len = keyCharacters.length; i < len; i++) {
+    acturalLength = Math.ceil(keyCharacters[i].length / emojiKeyAmount) *
+        emojiKeyAmount;
+    for (var j = 0, lenJ = acturalLength; j < lenJ; j++) {
+      key = keyList[amount + len];
+      mapping[key['spec'][SpecNodeName.ID]] = viewIdPrefix + (amount +
+          offset);
+      amount++;
+    }
+  }
+
+  // Map the side keys
+  for (var i = 0; i < 3; ++i) {
+    key = keyList[i + amount + keyCharacters.length];
+    mapping[key['spec'][SpecNodeName.ID]] = viewIdPrefix +
+        (i + amount + offset);
+  }
+
+  amount = amount + offset + 3;
+  //The space row.
+  var tmp = util.createBackToKeyboardKey();
+  keyList.push(tmp);
+  mapping[tmp['spec'][SpecNodeName.ID]] = viewIdPrefix + amount++;
+  tmp = util.createSpaceKey();
+  keyList.push(tmp);
+  mapping[tmp['spec'][SpecNodeName.ID]] = viewIdPrefix + amount++;
+  tmp = util.createHideKeyboardKey();
+  keyList.push(tmp);
+  mapping[tmp['spec'][SpecNodeName.ID]] = viewIdPrefix + amount++;
+
+  var result = [];
+  result[SpecNodeName.TEXT] = keyCharacters;
+  result[SpecNodeName.KEY_LIST] = keyList;
+  result[SpecNodeName.MAPPING] = mapping;
+  result[SpecNodeName.LAYOUT] = 'emoji';
+  result['id'] = 'emoji';
+  google.ime.chrome.inputview.onConfigLoaded(result);
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/config/material/hwt_data.js b/third_party/google_input_tools/src/chrome/os/inputview/config/material/hwt_data.js
new file mode 100644
index 0000000..b266bb0
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/config/material/hwt_data.js
@@ -0,0 +1,75 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.SpecNodeName');
+goog.require('i18n.input.chrome.inputview.content.util');
+goog.require('i18n.input.chrome.inputview.elements.ElementType');
+
+(function() {
+  var util = i18n.input.chrome.inputview.content.util;
+  var ElementType = i18n.input.chrome.inputview.elements.ElementType;
+  var SpecNodeName = i18n.input.chrome.inputview.SpecNodeName;
+  var Css = i18n.input.chrome.inputview.Css;
+
+  var viewIdPrefix = 'handwriting-k-';
+
+  var spec = {};
+  spec[SpecNodeName.ID] = 'SingleQuote';
+  spec[SpecNodeName.TYPE] = ElementType.CHARACTER_KEY;
+  spec[SpecNodeName.CHARACTERS] = ['\''];
+  var singleQuoteKey = util.createKey(spec);
+
+  spec[SpecNodeName.ID] = 'Comma';
+  spec[SpecNodeName.TYPE] = ElementType.CHARACTER_KEY;
+  spec[SpecNodeName.CHARACTERS] = [','];
+  var commaKey = util.createKey(spec);
+
+  spec = {};
+  spec[SpecNodeName.ID] = 'Period';
+  spec[SpecNodeName.TYPE] = ElementType.CHARACTER_KEY;
+  spec[SpecNodeName.CHARACTERS] = ['.'];
+  var periodKey = util.createKey(spec);
+
+  spec = {};
+  spec[SpecNodeName.TEXT] = '';
+  spec[SpecNodeName.ICON_CSS_CLASS] = Css.SPACE_ICON;
+  spec[SpecNodeName.TYPE] = ElementType.SPACE_KEY;
+  spec[SpecNodeName.ID] = 'Space';
+  var spaceKey = i18n.input.chrome.inputview.content.util.createKey(spec);
+
+  var keyList = [
+    singleQuoteKey,
+    commaKey,
+    periodKey,
+    util.createBackToKeyboardKey(),
+    util.createBackspaceKey(),
+    util.createEnterKey(),
+    spaceKey,
+    util.createHideKeyboardKey()
+  ];
+
+  var mapping = {};
+  for (var i = 0; i < keyList.length; i++) {
+    var key = keyList[i];
+    mapping[key['spec'][SpecNodeName.ID]] = viewIdPrefix + i;
+  }
+
+  var result = [];
+  result[SpecNodeName.KEY_LIST] = keyList;
+  result[SpecNodeName.MAPPING] = mapping;
+  result[SpecNodeName.LAYOUT] = 'handwriting';
+  result[SpecNodeName.HAS_ALTGR_KEY] = false;
+  result['id'] = 'hwt';
+  google.ime.chrome.inputview.onConfigLoaded(result);
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/config/util.js b/third_party/google_input_tools/src/chrome/os/inputview/config/util.js
index 560ba12..928fd8cf 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/config/util.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/config/util.js
@@ -153,6 +153,21 @@
 
 
 /**
+ * Create the key which leads to keyboard from emoji/hwt.
+ *
+ * @return {!Object} The back key.
+ */
+i18n.input.chrome.inputview.content.util.createBackToKeyboardKey = function() {
+  var spec = {};
+  spec[SpecNodeName.ICON_CSS_CLASS] =
+      i18n.input.chrome.inputview.Css.BACK_TO_KEYBOARD_ICON;
+  spec[SpecNodeName.TYPE] = ElementType.BACK_TO_KEYBOARD;
+  spec[SpecNodeName.ID] = 'backToKeyboard';
+  return i18n.input.chrome.inputview.content.util.createKey(spec);
+};
+
+
+/**
  * Creates a ctrl key.
  *
  * @return {!Object} The ctrl key.
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/controller.js b/third_party/google_input_tools/src/chrome/os/inputview/controller.js
index f0f49795..fecf7b0 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/controller.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/controller.js
@@ -24,6 +24,7 @@
 goog.require('goog.i18n.bidi');
 goog.require('goog.object');
 goog.require('i18n.input.chrome.DataSource');
+goog.require('i18n.input.chrome.SoundController');
 goog.require('i18n.input.chrome.Statistics');
 goog.require('i18n.input.chrome.inputview.Adapter');
 goog.require('i18n.input.chrome.inputview.CandidatesInfo');
@@ -36,7 +37,6 @@
 goog.require('i18n.input.chrome.inputview.ReadyState');
 goog.require('i18n.input.chrome.inputview.Settings');
 goog.require('i18n.input.chrome.inputview.SizeSpec');
-goog.require('i18n.input.chrome.inputview.SoundController');
 goog.require('i18n.input.chrome.inputview.SpecNodeName');
 goog.require('i18n.input.chrome.inputview.StateType');
 goog.require('i18n.input.chrome.inputview.SwipeDirection');
@@ -76,7 +76,7 @@
 var SpecNodeName = i18n.input.chrome.inputview.SpecNodeName;
 var StateType = i18n.input.chrome.inputview.StateType;
 var content = i18n.input.chrome.inputview.elements.content;
-var SoundController = i18n.input.chrome.inputview.SoundController;
+var SoundController = i18n.input.chrome.SoundController;
 var Sounds = i18n.input.chrome.inputview.Sounds;
 var Type = i18n.input.chrome.message.Type;
 var util = i18n.input.chrome.inputview.util;
@@ -116,6 +116,23 @@
   this.layoutDataMap_ = {};
 
   /**
+   * The element map.
+   *
+   * @private {!Object.<ElementType, !KeyCodes>}
+   */
+  this.elementTypeToKeyCode_ = goog.object.create(
+      ElementType.BOLD, KeyCodes.KEY_B,
+      ElementType.ITALICS, KeyCodes.KEY_I,
+      ElementType.UNDERLINE, KeyCodes.KEY_U,
+      ElementType.COPY, KeyCodes.KEY_C,
+      ElementType.PASTE, KeyCodes.KEY_V,
+      ElementType.CUT, KeyCodes.KEY_X,
+      ElementType.SELECT_ALL, KeyCodes.KEY_A,
+      ElementType.REDO, KeyCodes.KEY_Y,
+      ElementType.UNDO, KeyCodes.KEY_Z
+      );
+
+  /**
    * The keyset data map.
    *
    * @type {!Object.<string, !Object>}
@@ -162,14 +179,14 @@
   /** @private {!i18n.input.chrome.inputview.Adapter} */
   this.adapter_ = new i18n.input.chrome.inputview.Adapter(this.readyState_);
 
+  /** @private {!i18n.input.chrome.SoundController} */
+  this.soundController_ = new SoundController(false);
+
   /** @private {!i18n.input.chrome.inputview.KeyboardContainer} */
   this.container_ = new i18n.input.chrome.inputview.KeyboardContainer(
-      this.adapter_);
+      this.adapter_, this.soundController_);
   this.container_.render();
 
-  /** @private {!i18n.input.chrome.inputview.SoundController} */
-  this.soundController_ = new SoundController(false);
-
   /**
    * The context type and keyset mapping group by input method id.
    * key: input method id.
@@ -359,6 +376,17 @@
 
 
 /**
+ * A temporary list to track keysets have customized in material design.
+ *
+ * @private {!Array.<string>}
+ */
+Controller.MATERIAL_KEYSETS_ = [
+  'emoji',
+  'hwt'
+];
+
+
+/**
  * The active language code.
  *
  * @type {string}
@@ -440,28 +468,21 @@
           ], this.onPointerEvent_).
       listen(window, goog.events.EventType.RESIZE, this.resize).
       listen(this.adapter_,
-          i18n.input.chrome.inputview.events.EventType.
-              SURROUNDING_TEXT_CHANGED,
-          this.onSurroundingTextChanged_).
+          EventType.SURROUNDING_TEXT_CHANGED, this.onSurroundingTextChanged_).
       listen(this.adapter_,
           i18n.input.chrome.DataSource.EventType.CANDIDATES_BACK,
           this.onCandidatesBack_).
-      listen(this.adapter_,
-          i18n.input.chrome.inputview.events.EventType.CONTEXT_FOCUS,
-          this.onContextFocus_).
-      listen(this.adapter_,
-          i18n.input.chrome.inputview.events.EventType.CONTEXT_BLUR,
-          this.onContextBlur_).
-      listen(this.adapter_,
-          i18n.input.chrome.inputview.events.EventType.VISIBILITY_CHANGE,
+      listen(this.adapter_, EventType.URL_CHANGED, this.onURLChanged_).
+      listen(this.adapter_, EventType.CONTEXT_FOCUS, this.onContextFocus_).
+      listen(this.adapter_, EventType.CONTEXT_BLUR, this.onContextBlur_).
+      listen(this.adapter_, EventType.VISIBILITY_CHANGE,
           this.onVisibilityChange_).
-      listen(this.adapter_,
-          i18n.input.chrome.inputview.events.EventType.SETTINGS_READY,
-          this.onSettingsReady_).
+      listen(this.adapter_, EventType.SETTINGS_READY, this.onSettingsReady_).
       listen(this.adapter_, Type.UPDATE_SETTINGS, this.onUpdateSettings_).
       listen(this.adapter_, Type.FRONT_TOGGLE_LANGUAGE_STATE,
           this.onUpdateToggleLanguateState_).
-      listen(this.adapter_, Type.VOICE_STATE_CHANGE, this.onVoiceStateChange_);
+      listen(this.adapter_, Type.VOICE_STATE_CHANGE, this.onVoiceStateChange_).
+      listen(this.adapter_, EventType.REFRESH, this.onRefresh_);
 };
 
 
@@ -482,6 +503,16 @@
 
 
 /**
+ * Handles the refresh event from adapter.
+ *
+ * @private
+ */
+Controller.prototype.onRefresh_ = function() {
+  window.location.reload();
+};
+
+
+/**
  * Sets the default keyset for context types.
  *
  * @param {string} newKeyset .
@@ -536,6 +567,16 @@
 
 
 /**
+ * Callback for url changed.
+ *
+ * @private
+ */
+Controller.prototype.onURLChanged_ = function() {
+  this.container_.candidateView.setToolbarVisible(this.shouldShowToolBar_());
+};
+
+
+/**
  * Callback for setting ready.
  *
  * @private
@@ -561,6 +602,8 @@
   if (newKeyset) {
     this.setDefaultKeyset_(newKeyset);
   }
+  this.container_.selectView.setVisible(
+      this.adapter_.isGestureEdittingEnabled());
   // Loads resources in case the default keyset is changed.
   this.loadAllResources_();
   this.maybeCreateViews_();
@@ -695,6 +738,13 @@
     this.container_.altDataView.highlightItem(e.x, e.y);
     return;
   }
+  if (view.type == ElementType.BACKSPACE_KEY) {
+    if (this.container_.swipeView.isVisible() ||
+        this.container_.swipeView.isArmed()) {
+      this.stopBackspaceAutoRepeat_();
+      return;
+    }
+  }
 
   if (view.type == ElementType.CHARACTER_KEY) {
     view = /** @type {!content.CharacterKey} */ (view);
@@ -780,12 +830,13 @@
         'InputMethod.VirtualKeyboard.TapCount', 1, 4095, 4096);
   }
 
-  if (e.type == i18n.input.chrome.inputview.events.EventType.SWIPE) {
+  if (e.type == EventType.SWIPE) {
     e = /** @type {!i18n.input.chrome.inputview.events.SwipeEvent} */ (e);
     this.handleSwipeAction_(view, e);
   }
   switch (view.type) {
     case ElementType.BACK_BUTTON:
+    case ElementType.BACK_TO_KEYBOARD:
       if (e.type == EventType.POINTER_OUT || e.type == EventType.POINTER_UP) {
         view.setHighlighted(false);
       } else if (e.type == EventType.POINTER_DOWN ||
@@ -897,7 +948,7 @@
       return;
 
     case ElementType.VOICE_BTN:
-      if (e.type == EventType.CLICK) {
+      if (e.type == EventType.POINTER_UP) {
         this.container_.candidateView.switchToIcon(
             CandidateView.IconType.VOICE, false);
         this.container_.voiceView.start();
@@ -913,7 +964,33 @@
         this.container_.voiceView.stop();
       }
       return;
-
+    case ElementType.SWIPE_VIEW:
+      this.stopBackspaceAutoRepeat_();
+      if (e.type == EventType.POINTER_UP ||
+          e.type == EventType.POINTER_OUT) {
+        this.clearUnstickyState_();
+      }
+      return;
+    case ElementType.CUT:
+    case ElementType.COPY:
+    case ElementType.PASTE:
+    case ElementType.BOLD:
+    case ElementType.ITALICS:
+    case ElementType.UNDERLINE:
+    case ElementType.REDO:
+    case ElementType.UNDO:
+    case ElementType.SELECT_ALL:
+      view.setHighlighted(e.type == EventType.POINTER_DOWN ||
+          e.type == EventType.POINTER_OVER);
+      if (e.type == EventType.POINTER_UP) {
+        this.adapter_.sendKeyDownAndUpEvent(
+            '', this.elementTypeToKeyCode_[view.type], undefined, undefined, {
+              ctrl: true,
+              alt: false,
+              shift: false
+            });
+      }
+      return;
     case ElementType.SOFT_KEY_VIEW:
       // Delegates the events on the soft key view to its soft key.
       view = /** @type {!i18n.input.chrome.inputview.elements.layout.
@@ -926,7 +1003,8 @@
 
   if (view.type != ElementType.MODIFIER_KEY &&
       !this.container_.altDataView.isVisible() &&
-      !this.container_.menuView.isVisible()) {
+      !this.container_.menuView.isVisible() &&
+      !this.container_.swipeView.isVisible()) {
     // The highlight of the modifier key is depending on the state instead
     // of the key down or up.
     if (e.type == EventType.POINTER_OVER || e.type == EventType.POINTER_DOWN ||
@@ -1012,8 +1090,9 @@
         this.backspaceTick_();
       } else if (e.type == EventType.POINTER_UP || e.type == EventType.
           POINTER_OUT) {
-        this.stopBackspaceAutoRepeat_();
-        this.adapter_.sendKeyUpEvent('\u0008', KeyCodes.BACKSPACE);
+        if (!this.container_.swipeView.isVisible()) {
+          this.stopBackspaceAutoRepeat_();
+        }
       }
       break;
 
@@ -1075,7 +1154,8 @@
     case ElementType.SPACE_KEY:
       key = /** @type {!content.SpaceKey} */ (softKey);
       var doubleSpacePeriod = this.model_.settings.doubleSpacePeriod &&
-          this.currentKeyset_ != Controller.HANDWRITING_VIEW_CODE_;
+          this.currentKeyset_ != Controller.HANDWRITING_VIEW_CODE_ &&
+          this.currentKeyset_ != Controller.EMOJI_VIEW_CODE_;
       if (e.type == EventType.POINTER_UP || (!doubleSpacePeriod && e.type ==
           EventType.DOUBLE_CLICK_END)) {
         this.adapter_.sendKeyDownAndUpEvent(key.getCharacter(),
@@ -1286,11 +1366,24 @@
   this.resize();
   this.container_.expandedCandidateView.close();
   this.container_.menuView.hide();
+  this.container_.swipeView.reset();
   this.container_.altDataView.hide();
 };
 
 
 /**
+ * Returns whether the toolbar should be shown.
+ *
+ * @return {boolean}
+ * @private
+ */
+Controller.prototype.shouldShowToolBar_ = function() {
+  return this.adapter_.isExperimental && this.adapter_.isGoogleDocument() &&
+      this.adapter_.contextType == ContextType.DEFAULT;
+};
+
+
+/**
  * Callback when the context is changed.
  *
  * @private
@@ -1501,13 +1594,15 @@
   if (this.container_.currentKeysetView) {
     this.container_.currentKeysetView.setVisible(true);
   }
-  if (this.currentKeyset_ == Controller.HANDWRITING_VIEW_CODE_) {
-    this.container_.candidateView.switchToIcon(
-        CandidateView.IconType.BACK, true);
-  } else {
-    this.container_.candidateView.switchToIcon(CandidateView.IconType.VOICE,
-        this.currentKeyset_ != Controller.EMOJI_VIEW_CODE_ &&
-            this.adapter_.isExperimental);
+  if (!this.adapter_.isQPInputView) {
+    if (this.currentKeyset_ == Controller.HANDWRITING_VIEW_CODE_ ||
+        this.currentKeyset_ == Controller.EMOJI_VIEW_CODE_) {
+      this.container_.candidateView.switchToIcon(
+          CandidateView.IconType.BACK, true);
+    } else {
+      this.container_.candidateView.switchToIcon(CandidateView.IconType.VOICE,
+          this.adapter_.isVoiceInputEnabled);
+    }
   }
 };
 
@@ -1636,7 +1731,12 @@
       this.contextTypeToKeysetMap_[this.currentInputMethod_][contextType] =
           keyset;
     }
-    this.loadResource_(keyset);
+    if (this.adapter_.isQPInputView &&
+        goog.array.contains(Controller.MATERIAL_KEYSETS_, keyset)) {
+      this.loadResource_('m-' + keyset);
+    } else {
+      this.loadResource_(keyset);
+    }
   }
 };
 
@@ -1665,7 +1765,7 @@
   }
 
   var layoutId = data[i18n.input.chrome.inputview.SpecNodeName.LAYOUT];
-  if (this.adapter_.isQPInputView && layoutId == 'compactkbd-qwerty') {
+  if (this.adapter_.isQPInputView) {
     layoutId = 'm-' + layoutId;
     data[i18n.input.chrome.inputview.SpecNodeName.LAYOUT] = layoutId;
   }
@@ -1733,6 +1833,7 @@
 
   this.container_.resize(screen.width, height, widthPercent,
       candidateViewHeight);
+  this.container_.candidateView.setToolbarVisible(this.shouldShowToolBar_());
   if (this.container_.currentKeysetView) {
     this.isKeyboardReady = true;
   }
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/css.js b/third_party/google_input_tools/src/chrome/os/inputview/css.js
index ca4c5da2..d08b111 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/css.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/css.js
@@ -28,6 +28,8 @@
   ALTGR_CONTENT: goog.getCssName('inputview-ac'),
   ARROW_KEY: goog.getCssName('inputview-arrow-key'),
   BACKSPACE_ICON: goog.getCssName('inputview-backspace-icon'),
+  BACK_TO_KEYBOARD_ICON: goog.getCssName('inputview-back-to-keyboard'),
+  BOLD_ICON: goog.getCssName('inputview-bold-icon'),
   CANDIDATE: goog.getCssName('inputview-candidate'),
   CANDIDATES_LINE: goog.getCssName('inputview-candidates-line'),
   CANDIDATES_TOP_LINE: goog.getCssName('inputview-candidates-top-line'),
@@ -52,6 +54,8 @@
   CHECKED_MENU_LIST: goog.getCssName('inputview-checked-menu-list'),
   COMPACT_KEY: goog.getCssName('inputview-compact-key'),
   COMPACT_SWITCHER: goog.getCssName('inputview-compact-switcher'),
+  COPY_ICON: goog.getCssName('inputview-copy-icon'),
+  CUT_ICON: goog.getCssName('inputview-cut-icon'),
   CONTAINER: goog.getCssName('inputview-container'),
   DEFAULT_CONTENT: goog.getCssName('inputview-dc'),
   DIGIT_CHARACTER: goog.getCssName('inputview-digit-character'),
@@ -90,6 +94,7 @@
   EN_SWITCHER_ENGLISH: goog.getCssName('inputview-en-switcher-english'),
   EXPAND_CANDIDATES_ICON: goog.getCssName('inputview-expand-candidates-icon'),
   EXTENDED_LAYOUT_TRANSITION: goog.getCssName('inputview-extended-transition'),
+  FLOAT_LEFT: goog.getCssName('float-left'),
   FONT: goog.getCssName('inputview-font'),
   FONT_SMALL: goog.getCssName('inputview-font-small'),
   FUNCITONAL_KEY_STICKY: goog.getCssName('inputview-functional-key-sticky'),
@@ -115,6 +120,7 @@
   INDICATOR: goog.getCssName('inputview-indicator'),
   INDICATOR_BACKGROUND: goog.getCssName('inputview-indicator-background'),
   INLINE_DIV: goog.getCssName('inputview-inline-div'),
+  ITALICS_ICON: goog.getCssName('inputview-italics-icon'),
   JP_IME_SWITCH: goog.getCssName('inputview-jp-ime-switch'),
   KEY_HOLD: goog.getCssName('inputview-key-hold'),
   LANDSCAPE: goog.getCssName('inputview-landscape'),
@@ -143,26 +149,42 @@
   MODIFIER_STATE_ICON: goog.getCssName('inputview-modifier-state-icon'),
   PAGE_DOWN_ICON: goog.getCssName('inputview-page-down-icon'),
   PAGE_UP_ICON: goog.getCssName('inputview-page-up-icon'),
+  PASTE_ICON: goog.getCssName('inputview-paste-icon'),
   PINYIN: goog.getCssName('inputview-pinyin'),
   PORTRAIT: goog.getCssName('inputview-portrait'),
+  REDO_ICON: goog.getCssName('inputview-redo-icon'),
   REGULAR_SWITCHER: goog.getCssName('inputview-regular-switcher'),
   RIGHT_KEY: goog.getCssName('inputview-right-key'),
+  SELECT_ALL_ICON: goog.getCssName('inputview-select-all-icon'),
+  SELECT_KNOB_LEFT: goog.getCssName('inputview-select-knob-left'),
+  SELECT_KNOB_RIGHT: goog.getCssName('inputview-select-knob-right'),
   SHIFT_ICON: goog.getCssName('inputview-shift-icon'),
   SHRINK_CANDIDATES_ICON: goog.getCssName('inputview-shrink-candidates-icon'),
   SOFT_KEY: goog.getCssName('inputview-sk'),
   SOFT_KEY_VIEW: goog.getCssName('inputview-skv'),
   SPACE_ICON: goog.getCssName('inputview-space-icon'),
   SPACE_WRAPPER: goog.getCssName('inputview-space-wrapper'),
+  SPACE_GREY_BG: goog.getCssName('inputview-space-grey-bg'),
   SPECIAL_KEY_BG: goog.getCssName('inputview-special-key-bg'),
   SPECIAL_KEY_HIGHLIGHT: goog.getCssName('inputview-special-key-highlight'),
   SPECIAL_KEY_NAME: goog.getCssName('inputview-special-key-name'),
+  SWIPE_KEY: goog.getCssName('inputview-swipe-key'),
+  SWIPE_SEPARATOR: goog.getCssName('inputview-swipe-separator'),
+  SWIPE_VIEW: goog.getCssName('inputview-swipe-view'),
   SWITCHER_CHINESE: goog.getCssName('inputview-switcher-chinese'),
   SWITCHER_ENGLISH: goog.getCssName('inputview-switcher-english'),
+  SWITCHER_KEY_NAME: goog.getCssName('inputview-switcher-key-name'),
   TABLE_CELL: goog.getCssName('inputview-table-cell'),
   TAB_ICON: goog.getCssName('inputview-tab-icon'),
   THREE_CANDIDATES: goog.getCssName('inputview-three-candidates'),
   TITLE: goog.getCssName('inputview-title'),
   TITLE_BAR: goog.getCssName('inputview-title-bar'),
+  TOOLBAR_SEPARATOR: goog.getCssName('inputview-toolbar-separator'),
+  TOOLBAR_BUTTON: goog.getCssName('inputview-toolbar-button'),
+  TOOLBAR_CONTAINER: goog.getCssName('inputview-toolbar-container'),
+  TRACK_COVER: goog.getCssName('inputview-track-cover'),
+  UNDERLINE_ICON: goog.getCssName('inputview-underline-icon'),
+  UNDO_ICON: goog.getCssName('inputview-undo-icon'),
   UP_KEY: goog.getCssName('inputview-up-key'),
   VERTICAL_LAYOUT: goog.getCssName('inputview-vertical'),
   VIEW: goog.getCssName('inputview-view'),
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/backspacekey.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/backspacekey.js
new file mode 100644
index 0000000..c81c3ab
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/backspacekey.js
@@ -0,0 +1,46 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.provide('i18n.input.chrome.inputview.elements.content.BackspaceKey');
+
+goog.require('i18n.input.chrome.inputview.elements.content.FunctionalKey');
+
+
+
+goog.scope(function() {
+
+/**
+ * The backspace key.
+ *
+ * @param {string} id The id.
+ * @param {!i18n.input.chrome.inputview.elements.ElementType} type The element
+ *     type.
+ * @param {string} text The text.
+ * @param {string} iconCssClass The css class for the icon.
+ * @param {goog.events.EventTarget=} opt_eventTarget The event target.
+ * @param {string=} opt_textCssClass The css class for the text.
+ * @constructor
+ * @extends {i18n.input.chrome.inputview.elements.content.FunctionalKey}
+ */
+i18n.input.chrome.inputview.elements.content.BackspaceKey = function(id, type,
+    text, iconCssClass, opt_eventTarget, opt_textCssClass) {
+  goog.base(this, id, type, text, iconCssClass, opt_eventTarget,
+      opt_textCssClass);
+
+  this.pointerConfig.longPressWithPointerUp = true;
+  this.pointerConfig.longPressDelay = 300;
+};
+goog.inherits(i18n.input.chrome.inputview.elements.content.BackspaceKey,
+  i18n.input.chrome.inputview.elements.content.FunctionalKey);
+});  // goog.scope
+
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js
index 84ce75fc..5ccc1e84 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/candidateview.js
@@ -20,10 +20,12 @@
 goog.require('goog.object');
 goog.require('goog.style');
 goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.GlobalFlags');
 goog.require('i18n.input.chrome.inputview.elements.Element');
 goog.require('i18n.input.chrome.inputview.elements.ElementType');
 goog.require('i18n.input.chrome.inputview.elements.content.Candidate');
 goog.require('i18n.input.chrome.inputview.elements.content.CandidateButton');
+goog.require('i18n.input.chrome.inputview.elements.content.ToolbarButton');
 goog.require('i18n.input.chrome.message.Name');
 
 
@@ -66,18 +68,46 @@
    */
   this.iconButtons_ = [];
 
-  this.iconButtons_[CandidateView.IconType.BACK] = new content.CandidateButton(
+  this.iconButtons_[IconType.BACK] = new content.CandidateButton(
       '', ElementType.BACK_BUTTON, '',
       chrome.i18n.getMessage('HANDWRITING_BACK'), this);
-  this.iconButtons_[CandidateView.IconType.SHRINK_CANDIDATES] = new content.
+  this.iconButtons_[IconType.SHRINK_CANDIDATES] = new content.
       CandidateButton('', ElementType.SHRINK_CANDIDATES,
           Css.SHRINK_CANDIDATES_ICON, '', this);
-  this.iconButtons_[CandidateView.IconType.EXPAND_CANDIDATES] = new content.
+
+  this.iconButtons_[IconType.EXPAND_CANDIDATES] = new content.
       CandidateButton('', ElementType.EXPAND_CANDIDATES,
           Css.EXPAND_CANDIDATES_ICON, '', this);
-  this.iconButtons_[CandidateView.IconType.VOICE] = new content.
+
+  this.iconButtons_[IconType.VOICE] = new content.
       CandidateButton('', ElementType.VOICE_BTN, Css.VOICE_MIC_BAR, '', this,
           true);
+
+  /**
+   * Toolbar buttons.
+   *
+   * @private {!Array.<!i18n.input.chrome.inputview.elements.Element>}
+   */
+  this.toolbarButtons_ = [];
+
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.UNDO, Css.UNDO_ICON, '', this, true));
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.REDO, Css.REDO_ICON, '', this, true));
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.BOLD, Css.BOLD_ICON, '', this, true));
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.ITALICS, Css.ITALICS_ICON, '', this, true));
+  this.toolbarButtons_.push(new content.ToolbarButton(
+      '', ElementType.UNDERLINE, Css.UNDERLINE_ICON, '', this, true));
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.CUT, Css.CUT_ICON, '', this));
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.COPY, Css.COPY_ICON, '', this));
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.PASTE, Css.PASTE_ICON, '', this));
+  this.toolbarButtons_.push(new content.
+      ToolbarButton('', ElementType.SELECT_ALL, Css.SELECT_ALL_ICON, '', this));
 };
 goog.inherits(i18n.input.chrome.inputview.elements.content.CandidateView,
     i18n.input.chrome.inputview.elements.Element);
@@ -85,7 +115,7 @@
 
 
 /**
- * The icon type at the right of the candiate view.
+ * The icon type at the right of the candidate view.
  *
  * @enum {number}
  */
@@ -95,6 +125,7 @@
   EXPAND_CANDIDATES: 2,
   VOICE: 3
 };
+var IconType = CandidateView.IconType;
 
 
 /**
@@ -132,7 +163,7 @@
 
 
 /**
- * true if it is showing number row.
+ * True if it is showing number row.
  *
  * @type {boolean}
  */
@@ -140,6 +171,14 @@
 
 
 /**
+ * True if showing the toolbar row.
+ *
+ * @type {boolean}
+ */
+CandidateView.prototype.showingToolbar = false;
+
+
+/**
  * The width for a candidate when showing in THREE_CANDIDATE mode.
  *
  * @type {number}
@@ -158,6 +197,14 @@
 
 
 /**
+ * The width of icons in the toolbar.
+ *
+ * @private {number}
+ */
+CandidateView.TOOLBAR_ICON_WIDTH_ = 40;
+
+
+/**
  * The handwriting keyset code.
  *
  * @private {string}
@@ -187,6 +234,13 @@
 
   var dom = this.getDomHelper();
   var elem = this.getElement();
+
+  for (var i = 0; i < this.toolbarButtons_.length; i++) {
+    var button = this.toolbarButtons_[i];
+    button.render(elem);
+    button.setVisible(false);
+  }
+
   this.interContainer_ = dom.createDom(TagName.DIV,
       Css.CANDIDATE_INTER_CONTAINER);
   dom.appendChild(elem, this.interContainer_);
@@ -196,10 +250,16 @@
     button.render(elem);
     button.setVisible(false);
   }
+
   goog.a11y.aria.setState(/** @type {!Element} */
-      (this.iconButtons_[CandidateView.IconType.VOICE].getElement()),
+      (this.iconButtons_[IconType.SHRINK_CANDIDATES].getElement()),
       goog.a11y.aria.State.LABEL,
-      chrome.i18n.getMessage('VOICE_TURN_ON'));
+      chrome.i18n.getMessage('SHRINK_CANDIDATES'));
+
+  goog.a11y.aria.setState(/** @type {!Element} */
+      (this.iconButtons_[IconType.EXPAND_CANDIDATES].getElement()),
+      goog.a11y.aria.State.LABEL,
+      chrome.i18n.getMessage('EXPAND_CANDIDATES'));
 };
 
 
@@ -248,12 +308,12 @@
   if (candidates.length > 0) {
     if (showThreeCandidates) {
       this.addThreeCandidates_(candidates);
-      // Hide the voice icons.
-      this.switchToIcon(CandidateView.IconType.VOICE, false);
     } else {
       this.addFullCandidates_(candidates);
-      this.switchToIcon(CandidateView.IconType.EXPAND_CANDIDATES,
-          !!opt_expandable && this.candidateCount < candidates.length);
+      if (!this.iconButtons_[IconType.BACK].isVisible()) {
+        this.switchToIcon(IconType.EXPAND_CANDIDATES,
+            !!opt_expandable && this.candidateCount < candidates.length);
+      }
     }
     this.showingCandidates = true;
     this.showingNumberRow = false;
@@ -272,10 +332,13 @@
       i18n.input.chrome.inputview.Css.THREE_CANDIDATES);
   var num = Math.min(3, candidates.length);
   var dom = this.getDomHelper();
+  var width = CandidateView.WIDTH_FOR_THREE_CANDIDATES_;
+  if (this.showingToolbar) {
+    width -= CandidateView.ICON_WIDTH_ / 3;
+  }
   for (var i = 0; i < num; i++) {
     var candidateElem = new Candidate(String(i), candidates[i], Type.CANDIDATE,
-        this.height, i == 1 || num == 1, CandidateView.
-        WIDTH_FOR_THREE_CANDIDATES_, this);
+        this.height, i == 1 || num == 1, width, this);
     candidateElem.render(this.interContainer_);
   }
   this.candidateCount = num;
@@ -352,6 +415,10 @@
     button.resize(CandidateView.ICON_WIDTH_, height);
   }
 
+  for (var i = 0; i < this.toolbarButtons_.length; i++) {
+    var button = this.toolbarButtons_[i];
+    button.resize(CandidateView.TOOLBAR_ICON_WIDTH_, height);
+  }
 
   // Resets the candidates elements visibility.
   if (this.candidateCount > 0) {
@@ -383,16 +450,34 @@
 CandidateView.prototype.switchToIcon = function(type, visible) {
   for (var i = 0; i < this.iconButtons_.length; i++) {
     // Don't enable voice when focus in password box.
-    this.iconButtons_[i].setVisible(visible && type == i &&
-        (type != CandidateView.IconType.VOICE || !this.candidateCount &&
-        this.adapter_.contextType != 'password'));
+    this.iconButtons_[i].setVisible(false);
   }
 
-  // We need make default voice icon showed if the position doesn't show other
-  // icon.
-  if (!visible && this.adapter_.isExperimental &&
+  if (visible) {
+    if (type != IconType.VOICE) {
+      this.iconButtons_[type].setVisible(true);
+    } else if (this.adapter_.isVoiceInputEnabled &&
+        this.adapter_.contextType != 'password') {
+      this.iconButtons_[type].setVisible(true);
+    }
+  } else if (this.adapter_.isVoiceInputEnabled &&
+      type != IconType.VOICE &&
       this.adapter_.contextType != 'password') {
-    this.iconButtons_[CandidateView.IconType.VOICE].setVisible(true);
+    // Default to show voice icon.
+    this.iconButtons_[IconType.VOICE].setVisible(true);
+  }
+};
+
+
+/**
+ * Changes the visibility of the toolbar and it's icons.
+ *
+ * @param {boolean} visible The target visibility.
+ */
+CandidateView.prototype.setToolbarVisible = function(visible) {
+  this.showingToolbar = visible;
+  for (var i = 0; i < this.toolbarButtons_.length; i++) {
+    this.toolbarButtons_[i].setVisible(visible);
   }
 };
 
@@ -406,12 +491,15 @@
  */
 CandidateView.prototype.updateByKeyset = function(
     keyset, isPasswordBox, isRTL) {
-  if (keyset == CandidateView.HANDWRITING_VIEW_CODE_) {
-    this.switchToIcon(CandidateView.IconType.BACK, true);
-  } else if (keyset != CandidateView.EMOJI_VIEW_CODE_ && !this.candidateCount &&
-      this.adapter_.isExperimental) {
-    // If candidates count is greater than 0, don't show voice icon.
-    this.switchToIcon(CandidateView.IconType.VOICE, true);
+  if (!i18n.input.chrome.inputview.GlobalFlags.isQPInputView) {
+    if (keyset == CandidateView.HANDWRITING_VIEW_CODE_ ||
+        keyset == CandidateView.EMOJI_VIEW_CODE_) {
+      this.switchToIcon(IconType.BACK, true);
+    } else {
+      this.switchToIcon(IconType.VOICE,
+          this.adapter_.isVoiceInputEnabled &&
+          this.adapter_.contextType != 'password');
+    }
   }
 
   if (isPasswordBox && keyset.indexOf('compact') != -1) {
@@ -421,4 +509,13 @@
   }
   this.interContainer_.style.direction = isRTL ? 'rtl' : 'ltr';
 };
+
+
+/** @override */
+CandidateView.prototype.disposeInternal = function() {
+  goog.disposeAll(this.toolbarButtons_);
+  goog.disposeAll(this.iconButtons_);
+
+  goog.base(this, 'disposeInternal');
+};
 });  // goog.scope
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/characterkey.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/characterkey.js
index 6e6ec65..2c0c5f909 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/characterkey.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/characterkey.js
@@ -50,6 +50,8 @@
  * @param {boolean} enableShiftRendering Whether renders two letter vertically,
  *     it means show shift letter when in letter state, shows default letter
  *     when in shift state, same as the altgr state.
+ * @param {boolean} isQpInputView Temporary flag to indicate it is in material
+ *     design.
  * @param {goog.events.EventTarget=} opt_eventTarget The event target.
  * @constructor
  * @extends {i18n.input.chrome.inputview.elements.content.SoftKey}
@@ -57,7 +59,7 @@
 i18n.input.chrome.inputview.elements.content.CharacterKey = function(id,
     keyCode, characters, isLetterKey, hasAltGrCharacterInTheKeyset,
     alwaysRenderAltGrCharacter, stateManager, isRTL,
-    enableShiftRendering, opt_eventTarget) {
+    enableShiftRendering, isQpInputView, opt_eventTarget) {
   goog.base(this, id, i18n.input.chrome.inputview.elements.ElementType.
       CHARACTER_KEY, opt_eventTarget);
 
@@ -117,6 +119,9 @@
   /** @private {boolean} */
   this.enableShiftRendering_ = enableShiftRendering;
 
+  /** @private {boolean} */
+  this.isQpInputView_ = isQpInputView;
+
   this.pointerConfig.longPressWithPointerUp = true;
   this.pointerConfig.longPressDelay = 500;
 };
@@ -164,6 +169,7 @@
           CharacterKey.STATE_LIST_[i],
           this.stateManager_,
           this.enableShiftRendering_,
+          this.isQpInputView_,
           this.getCapslockCharacter_(i));
       var character = new Character(this.id + '-' + i, model, this.isRTL_);
       this.addChild(character, true);
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/charactermodel.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/charactermodel.js
index cc1aff0..01479fa 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/charactermodel.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/charactermodel.js
@@ -36,13 +36,14 @@
  * @param {!i18n.input.chrome.inputview.StateManager} stateManager The state
  *     manager.
  * @param {boolean} enableShiftRendering .
+ * @param {boolean} isQpInputView .
  * @param {string=} opt_capslockCharacter .
  * @constructor
  */
 i18n.input.chrome.inputview.elements.content.CharacterModel = function(
     character, belongToLetterKey, hasAltGrCharacterInTheKeyset,
     alwaysRenderAltGrCharacter, stateType, stateManager, enableShiftRendering,
-    opt_capslockCharacter) {
+    isQpInputView, opt_capslockCharacter) {
 
   /**
    * The character.
@@ -101,6 +102,9 @@
 
   /** @private {boolean} */
   this.enableShiftRendering_ = enableShiftRendering;
+
+  /** @private {boolean} */
+  this.isQpInputView_ = isQpInputView;
 };
 var CharacterModel = i18n.input.chrome.inputview.elements.content.
     CharacterModel;
@@ -149,10 +153,13 @@
  * @return {boolean} True if the character is visible.
  */
 CharacterModel.prototype.isVisible = function() {
-  var enableShiftLetter = this.enableShiftRendering_ ||
-      this.stateManager_.hasState(StateType.SHIFT);
-  var enableDefaultLetter = this.enableShiftRendering_ || !this.stateManager_.
-      hasState(StateType.SHIFT);
+  var hasShift = this.stateManager_.hasState(StateType.SHIFT);
+  var enableShiftLetter = !this.belongToLetterKey_ || hasShift;
+  var enableDefaultLetter = !this.belongToLetterKey_ || !hasShift;
+  if (this.isQpInputView_) {
+    enableShiftLetter = this.enableShiftRendering_ || hasShift;
+    enableDefaultLetter = this.enableShiftRendering_ || !hasShift;
+  }
   if (this.stateType_ == StateType.DEFAULT) {
     return !this.stateManager_.hasState(StateType.ALTGR) && enableDefaultLetter;
   }
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js
index 6c9c609e..98d6624 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js
@@ -19,9 +19,11 @@
 goog.require('goog.positioning.Corner');
 goog.require('goog.style');
 goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.GlobalFlags');
 goog.require('i18n.input.chrome.inputview.SpecNodeName');
 goog.require('i18n.input.chrome.inputview.elements.ElementType');
 goog.require('i18n.input.chrome.inputview.elements.content.KeysetView');
+goog.require('i18n.input.chrome.inputview.elements.content.PageIndicator');
 goog.require('i18n.input.chrome.inputview.events.EventType');
 goog.require('i18n.input.chrome.inputview.handler.PointerHandler');
 
@@ -172,6 +174,14 @@
 
 
 /**
+ * The width percent to used inside the emoji panel.
+ *
+ * @private {number}
+ */
+EmojiView.prototype.emojiWidthPercent_ = 1;
+
+
+/**
  * Whether it is a drag event.
  *
  * @private {number}
@@ -260,8 +270,37 @@
 
 
 /** @override */
-EmojiView.prototype.resize = function(outerWidth, outerHeight, opt_force) {
-  goog.base(this, 'resize', outerWidth, outerHeight, opt_force);
+EmojiView.prototype.resize = function(outerWidth, outerHeight, widthPercent,
+    opt_force) {
+  if (i18n.input.chrome.inputview.GlobalFlags.isQPInputView) {
+    if (this.getElement() && (!!opt_force || this.outerHeight != outerHeight ||
+        this.outerWidth != outerWidth ||
+        this.emojiWidthPercent_ != widthPercent)) {
+      this.outerHeight = outerHeight;
+      this.outerWidth = outerWidth;
+      goog.style.setSize(this.getElement(), outerWidth, outerHeight);
+      this.emojiWidthPercent_ = widthPercent;
+      var marginOrPadding = Math.round((outerWidth -
+          outerWidth * widthPercent) / 2);
+      var w = outerWidth - 2 * marginOrPadding;
+      var tabBar = /** @type {!Element} */ (
+          this.getChildViewById('tabBar').getElement());
+      tabBar.style.paddingLeft = tabBar.style.paddingRight =
+          marginOrPadding + 'px';
+      var rowsAndKeys = /** @type {!Element} */ (
+          this.getChildViewById('rowsAndSideKeys').getElement());
+      rowsAndKeys.style.marginLeft = rowsAndKeys.style.marginRight =
+          marginOrPadding + 'px';
+      var spaceRow = /**@type {!Element} */ (
+          this.getChildViewById('emojiSpaceRow').getElement());
+      spaceRow.style.marginLeft = spaceRow.style.marginRight =
+          marginOrPadding + 'px';
+      this.resizeRows(outerWidth, outerHeight);
+    }
+  } else {
+    goog.base(this, 'resize', outerWidth, outerHeight, widthPercent,
+        opt_force);
+  }
   // Reposition must happen before clear because it will set the width.
   this.repositionIndicator_();
   this.clearEmojiStates();
@@ -510,8 +549,10 @@
   var emojiElement = this.emojiSlider_.getElement();
   var elem = this.pageIndicator_.getElement();
   elem.style.width = goog.style.getSize(emojiElement).width + 'px';
+  var rowsAndSideKeys = /** @type {!Element} */ (
+      this.getChildViewById('rowsAndSideKeys').getElement());
   var position = new goog.positioning.AnchoredViewportPosition(
-      this.getElement(), goog.positioning.Corner.BOTTOM_START, true);
+      rowsAndSideKeys, goog.positioning.Corner.BOTTOM_START, true);
   position.reposition(this.pageIndicator_.getElement(),
       goog.positioning.Corner.BOTTOM_START);
 };
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/keysetview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/keysetview.js
index 392cede..0174e0b 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/keysetview.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/keysetview.js
@@ -22,6 +22,7 @@
 goog.require('i18n.input.chrome.inputview.Css');
 goog.require('i18n.input.chrome.inputview.SpecNodeName');
 goog.require('i18n.input.chrome.inputview.elements.ElementType');
+goog.require('i18n.input.chrome.inputview.elements.content.BackspaceKey');
 goog.require('i18n.input.chrome.inputview.elements.content.CandidateButton');
 goog.require('i18n.input.chrome.inputview.elements.content.CanvasView');
 goog.require('i18n.input.chrome.inputview.elements.content.CharacterKey');
@@ -238,19 +239,25 @@
 /**
  * The outer height of the view.
  *
- * @type {number}
- * @private
+ * @protected {number}
  */
-KeysetView.prototype.outerHeight_ = 0;
+KeysetView.prototype.outerHeight = 0;
 
 
 /**
  * The outer width of the view.
  *
- * @type {number}
- * @private
+ * @protected {number}
  */
-KeysetView.prototype.outerWidth_ = 0;
+KeysetView.prototype.outerWidth = 0;
+
+
+/**
+ * The width percentage.
+ *
+ * @private {number}
+ */
+KeysetView.prototype.widthPercent_ = 1;
 
 
 /** @override */
@@ -306,33 +313,65 @@
 
 
 /**
+ * @param {number} outerWidth .
+ * @param {number} outerHeight .
+ * @param {number} widthPercent .
+ * @param {boolean} force .
+ * @return {boolean} .
+ */
+KeysetView.prototype.shouldResize = function(outerWidth, outerHeight,
+    widthPercent, force) {
+  var needResize = force || (this.outerHeight != outerHeight ||
+      this.outerWidth != outerWidth || this.widthPercent_ != widthPercent);
+  return !!this.getElement() && needResize;
+};
+
+
+/**
  * Resizes the view.
  *
  * @param {number} outerWidth The width of the outer space.
  * @param {number} outerHeight The height of the outer space.
+ * @param {number} widthPercent The percentage of the width.
  * @param {boolean=} opt_force Forces to resize the view.
  */
-KeysetView.prototype.resize = function(outerWidth, outerHeight, opt_force) {
-  var needResize = !!opt_force || (this.outerHeight_ != outerHeight ||
-      this.outerWidth_ != outerWidth);
-  if (this.getElement() && needResize) {
-    this.outerHeight_ = outerHeight;
-    this.outerWidth_ = outerWidth;
+KeysetView.prototype.resize = function(outerWidth, outerHeight, widthPercent,
+    opt_force) {
+  if (this.shouldResize(outerWidth, outerHeight, widthPercent, !!opt_force)) {
+    this.outerHeight = outerHeight;
+    this.outerWidth = outerWidth;
+    this.widthPercent_ = widthPercent;
     var elem = this.getElement();
-    goog.style.setSize(elem, outerWidth, outerHeight);
-
-    var weightArray = [];
-    for (var i = 0; i < this.rows_.length; i++) {
-      var row = this.rows_[i];
-      weightArray.push(row.getHeightInWeight());
+    var margin = Math.round((outerWidth - outerWidth * widthPercent) / 2);
+    var w = outerWidth - 2 * margin;
+    if (margin > 0) {
+      elem.style.marginLeft = elem.style.marginRight = margin + 'px';
     }
+    goog.style.setSize(elem, w, outerHeight);
 
-    var splitedHeight = i18n.input.chrome.inputview.util.splitValue(weightArray,
-        outerHeight);
-    for (var i = 0; i < this.rows_.length; i++) {
-      var row = this.rows_[i];
-      row.resize(outerWidth, splitedHeight[i]);
-    }
+    this.resizeRows(w, outerHeight);
+  }
+};
+
+
+/**
+ * Resizes the rows inside the keyset.
+ *
+ * @param {number} width .
+ * @param {number} height .
+ */
+KeysetView.prototype.resizeRows = function(width, height) {
+  var weightArray = [];
+  for (var i = 0; i < this.rows_.length; i++) {
+    var row = this.rows_[i];
+    weightArray.push(row.getHeightInWeight());
+  }
+
+  var splitedHeight = i18n.input.chrome.inputview.util.splitValue(weightArray,
+      height);
+  for (var i = 0; i < this.rows_.length; i++) {
+    var row = this.rows_[i];
+    row.resize(width, splitedHeight[i]);
   }
 };
 
@@ -413,7 +452,7 @@
   }
   this.conditions_[name] = value;
   this.applyConditions(this.conditions_);
-  this.resize(this.outerWidth_, this.outerHeight_, true);
+  this.resize(this.outerWidth, this.outerHeight, this.widthPercent_, true);
   this.update();
 };
 
@@ -552,9 +591,6 @@
   var name = spec[SpecNodeName.NAME];
   var characters = spec[SpecNodeName.CHARACTERS];
   var iconCssClass = spec[SpecNodeName.ICON_CSS_CLASS];
-  if (this.adapter && this.adapter.isQPInputView && iconCssClass) {
-    iconCssClass = iconCssClass.replace(/inputview/, 'm-inputview');
-  }
   var textCssClass = spec[SpecNodeName.TEXT_CSS_CLASS];
   var toKeyset = spec[SpecNodeName.TO_KEYSET];
   var toKeysetName = spec[SpecNodeName.TO_KEYSET_NAME];
@@ -583,6 +619,8 @@
           Css.EN_SWITCHER_ENGLISH);
       break;
     case ElementType.BACKSPACE_KEY:
+      elem = new content.BackspaceKey(id, type, name, iconCssClass);
+      break;
     case ElementType.ENTER_KEY:
     case ElementType.TAB_KEY:
     case ElementType.ARROW_UP:
@@ -591,6 +629,7 @@
     case ElementType.ARROW_RIGHT:
     case ElementType.HIDE_KEYBOARD_KEY:
     case ElementType.GLOBE_KEY:
+    case ElementType.BACK_TO_KEYBOARD:
       elem = new content.FunctionalKey(id, type, name, iconCssClass);
       break;
     case ElementType.TAB_BAR_KEY:
@@ -643,7 +682,8 @@
       var isLetterKey = i18n.input.chrome.inputview.util.isLetterKey(
           characters);
       var enableShiftRendering = false;
-      if (this.adapter && this.adapter.isQPInputView) {
+      var isQpInputView = !!this.adapter && this.adapter.isQPInputView;
+      if (isQpInputView) {
         enableShiftRendering = !!spec[SpecNodeName.ENABLE_SHIFT_RENDERING];
       }
       elem = new content.CharacterKey(id, keyCode || 0,
@@ -651,7 +691,8 @@
           this.dataModel_.settings.alwaysRenderAltGrCharacter,
           this.dataModel_.stateManager,
           goog.i18n.bidi.isRtlLanguage(this.languageCode),
-          enableShiftRendering);
+          enableShiftRendering,
+          isQpInputView);
       break;
 
     case ElementType.BACK_BUTTON:
@@ -732,7 +773,8 @@
  * @return {boolean} .
  */
 KeysetView.prototype.isTabStyle = function() {
-  return this.keyboardCode_ == 'hwt' || this.keyboardCode_ == 'emoji';
+  return !i18n.input.chrome.inputview.GlobalFlags.isQPInputView && (
+      this.keyboardCode_ == 'hwt' || this.keyboardCode_ == 'emoji');
 };
 
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/material/spacekey.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/material/spacekey.js
index 82363f58..a927fd47 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/material/spacekey.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/material/spacekey.js
@@ -71,6 +71,9 @@
    */
   this.stateManager_ = stateManager;
 
+  /** @private {string} */
+  this.iconCss_ = opt_iconCss || '';
+
   // Double click on space key may convert two spaces to a period followed by a
   // space.
   this.pointerConfig.dblClick = true;
@@ -104,7 +107,13 @@
   var dom = this.getDomHelper();
   this.wrapper_ = dom.createDom(goog.dom.TagName.DIV, Css.SPACE_WRAPPER);
   dom.appendChild(this.getElement(), this.wrapper_);
-  goog.dom.setTextContent(this.wrapper_, this.title_);
+  if (this.iconCss_) {
+    var iconElem = dom.createDom(goog.dom.TagName.DIV, this.iconCss_);
+    dom.appendChild(this.wrapper_, iconElem);
+  } else {
+    goog.dom.classlist.add(this.wrapper_, Css.SPACE_GREY_BG);
+    goog.dom.setTextContent(this.wrapper_, this.title_);
+  }
 };
 
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/menuview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/menuview.js
index dd5ed6b3..c332665e 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/menuview.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/menuview.js
@@ -15,6 +15,7 @@
 
 goog.require('goog.a11y.aria');
 goog.require('goog.a11y.aria.State');
+goog.require('goog.array');
 goog.require('goog.dom.TagName');
 goog.require('goog.dom.classlist');
 goog.require('goog.style');
@@ -80,11 +81,20 @@
 
 /**
  * The width of the popup menu.
+ * The total width include padding is 300px, the padding left is 41px.
  *
  * @type {number}
  * @private
  */
-MenuView.WIDTH_ = 300;
+MenuView.width_ = 300;
+
+
+/**
+ * The padding-left of the menu item.
+ *
+ * @private {number}
+ */
+MenuView.paddingLeft_ = 0;
 
 
 /**
@@ -150,6 +160,11 @@
 MenuView.prototype.show = function(key, currentKeysetId, isCompact,
     enableCompactLayout, currentInputMethod, inputMethods, hasHwt,
     enableSettings, hasEmoji) {
+  if (i18n.input.chrome.inputview.GlobalFlags.isQPInputView) {
+    // Temporary overwrites the value for material design.
+    MenuView.width_ = 259;
+    MenuView.paddingLeft_ = 41;
+  }
   var ElementType = i18n.input.chrome.inputview.elements.ElementType;
   var dom = this.getDomHelper();
   if (key.type != ElementType.MENU_KEY) {
@@ -222,7 +237,7 @@
         inputMethod['name'];
     if (currentInputMethod == inputMethod['id']) {
       ariaLabel = chrome.i18n.getMessage('CURRENT_KEYBOARD_PREFIX') +
-        inputMethod['name'];
+          inputMethod['name'];
     }
     var imeItem = new MenuItem(String(i), listItem, MenuItem.Type.LIST_ITEM,
         ariaLabel);
@@ -230,14 +245,16 @@
     if (currentInputMethod == inputMethod['id']) {
       imeItem.check();
     }
-    goog.style.setSize(imeItem.getElement(), MenuView.WIDTH_,
+    goog.style.setSize(imeItem.getElement(),
+        (MenuView.width_ + MenuView.paddingLeft_),
         MenuView.LIST_ITEM_HEIGHT_);
   }
 
   var containerHeight = inputMethods.length > MenuView.MAXIMAL_VISIBLE_IMES_ ?
       MenuView.LIST_ITEM_HEIGHT_ * MenuView.MAXIMAL_VISIBLE_IMES_ :
       MenuView.LIST_ITEM_HEIGHT_ * inputMethods.length;
-  goog.style.setSize(container, MenuView.WIDTH_, containerHeight);
+  goog.style.setSize(container, MenuView.width_ + MenuView.paddingLeft_,
+      containerHeight);
 
   dom.appendChild(this.getElement(), container);
   return containerHeight;
@@ -293,7 +310,7 @@
         chrome.i18n.getMessage('SWITCH_TO_COMPACT_LAYOUT'));
   }
   layoutSwitcherItem.render(this.getElement());
-  goog.style.setSize(layoutSwitcherItem.getElement(), MenuView.WIDTH_,
+  goog.style.setSize(layoutSwitcherItem.getElement(), MenuView.width_,
       MenuView.LIST_ITEM_HEIGHT_);
 
   return MenuView.LIST_ITEM_HEIGHT_;
@@ -347,15 +364,17 @@
   // Sets footer itmes' width.
   var elems = dom.getChildren(footer);
   var len = elems.length;
-  var subWidth = Math.ceil(MenuView.WIDTH_ / len);
+  var subWidth = Math.ceil((MenuView.width_ + MenuView.paddingLeft_) / len);
   var i = 0;
   for (; i < len - 1; i++) {
     elems[i].style.width = subWidth + 'px';
   }
-  elems[i].style.width = (MenuView.WIDTH_ - subWidth * (len - 1)) + 'px';
+  elems[i].style.width = (MenuView.width_ + MenuView.paddingLeft_ -
+      subWidth * (len - 1)) + 'px';
 
   dom.appendChild(this.getElement(), footer);
-  goog.style.setSize(footer, MenuView.WIDTH_, MenuView.LIST_ITEM_HEIGHT_);
+  goog.style.setSize(footer, (MenuView.width_ + MenuView.paddingLeft_),
+      MenuView.LIST_ITEM_HEIGHT_);
 
   return MenuView.LIST_ITEM_HEIGHT_;
 };
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/selectview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/selectview.js
new file mode 100644
index 0000000..50e8f64
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/selectview.js
@@ -0,0 +1,126 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.provide('i18n.input.chrome.inputview.elements.content.SelectView');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classlist');
+goog.require('goog.math.Coordinate');
+goog.require('goog.style');
+goog.require('i18n.input.chrome.inputview.Accents');
+goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.elements.Element');
+goog.require('i18n.input.chrome.inputview.elements.ElementType');
+goog.require('i18n.input.chrome.inputview.util');
+
+
+goog.scope(function() {
+var Css = i18n.input.chrome.inputview.Css;
+var ElementType = i18n.input.chrome.inputview.elements.ElementType;
+var TagName = goog.dom.TagName;
+
+
+/**
+ * The view for triggering select mode.
+ *
+ * @param {goog.events.EventTarget=} opt_eventTarget The parent event target.
+ * @constructor
+ * @extends {i18n.input.chrome.inputview.elements.Element}
+ */
+i18n.input.chrome.inputview.elements.content.SelectView = function(
+    opt_eventTarget) {
+  goog.base(this, '', ElementType.SELECT_VIEW, opt_eventTarget);
+};
+goog.inherits(i18n.input.chrome.inputview.elements.content.SelectView,
+    i18n.input.chrome.inputview.elements.Element);
+var SelectView = i18n.input.chrome.inputview.elements.content.SelectView;
+
+
+/**
+ * The window that shows the left knob.
+ *
+ * @private {!Element}
+ */
+SelectView.prototype.left_;
+
+
+/**
+ * The window that shows the right knob.
+ *
+ * @private {!Element}
+ */
+SelectView.prototype.right_;
+
+
+/**
+ * The distance between finger to track view which will cancel the track
+ * view.
+ *
+ * @private {number}
+ */
+SelectView.WIDTH_ = 25;
+
+
+/** @override */
+SelectView.prototype.createDom = function() {
+  goog.base(this, 'createDom');
+
+  var dom = this.getDomHelper();
+  var elem = this.getElement();
+  var knob = dom.createDom(TagName.DIV, undefined, dom.createTextNode('>'));
+  var knobContainer = dom.createDom(TagName.DIV, undefined, knob);
+  this.left_ = dom.createDom(TagName.DIV, Css.SELECT_KNOB_LEFT, knobContainer);
+  dom.appendChild(this.getElement(), this.left_);
+
+  knob = dom.createDom(TagName.DIV, undefined, dom.createTextNode('<'));
+  knobContainer = dom.createDom(TagName.DIV, undefined, knob);
+  this.right_ =
+      dom.createDom(TagName.DIV, Css.SELECT_KNOB_RIGHT, knobContainer);
+  dom.appendChild(this.getElement(), this.right_);
+};
+
+
+/** @override */
+SelectView.prototype.resize = function(width, height) {
+  goog.base(this, 'resize', width, height);
+  this.left_ && goog.style.setStyle(this.left_, {
+    'height': height + 'px',
+    'width': SelectView.WIDTH_ + 'px'
+  });
+  this.right_ && goog.style.setStyle(this.right_, {
+    'height': height + 'px',
+    'width': SelectView.WIDTH_ + 'px',
+    'left': width - SelectView.WIDTH_ + 'px'
+  });
+
+};
+
+
+/** @override */
+SelectView.prototype.disposeInternal = function() {
+  goog.dispose(this.left_);
+  goog.dispose(this.right_);
+
+  goog.base(this, 'disposeInternal');
+};
+
+
+/** @override */
+SelectView.prototype.setVisible = function(visible) {
+  SelectView.base(this, 'setVisible', visible);
+  goog.style.setElementShown(this.left_, visible);
+  goog.style.setElementShown(this.right_, visible);
+};
+});  // goog.scope
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/swipeview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/swipeview.js
new file mode 100644
index 0000000..903fd21
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/swipeview.js
@@ -0,0 +1,788 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.provide('i18n.input.chrome.inputview.elements.content.SwipeView');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classlist');
+goog.require('goog.events.EventType');
+goog.require('goog.math.Coordinate');
+goog.require('goog.style');
+goog.require('i18n.input.chrome.inputview.Accents');
+goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.SwipeDirection');
+goog.require('i18n.input.chrome.inputview.elements.Element');
+goog.require('i18n.input.chrome.inputview.elements.ElementType');
+goog.require('i18n.input.chrome.inputview.events.EventType');
+goog.require('i18n.input.chrome.inputview.events.KeyCodes');
+goog.require('i18n.input.chrome.inputview.handler.PointerHandler');
+goog.require('i18n.input.chrome.inputview.util');
+goog.require('i18n.input.chrome.message.ContextType');
+
+
+goog.scope(function() {
+var ContextType = i18n.input.chrome.message.ContextType;
+var Css = i18n.input.chrome.inputview.Css;
+var ElementType = i18n.input.chrome.inputview.elements.ElementType;
+var EventType = i18n.input.chrome.inputview.events.EventType;
+var KeyCodes = i18n.input.chrome.inputview.events.KeyCodes;
+var content = i18n.input.chrome.inputview.elements.content;
+var util = i18n.input.chrome.inputview.util;
+
+
+/**
+ * The view for alt data.
+ *
+ * @param {!i18n.input.chrome.inputview.Adapter} adapter .
+ * @param {goog.events.EventTarget=} opt_eventTarget The parent event target.
+ * @constructor
+ * @extends {i18n.input.chrome.inputview.elements.Element}
+ */
+i18n.input.chrome.inputview.elements.content.SwipeView = function(
+    adapter, opt_eventTarget) {
+  i18n.input.chrome.inputview.elements.content.SwipeView.base(
+      this, 'constructor', '', ElementType.SWIPE_VIEW, opt_eventTarget);
+
+  /**
+   * The inputview adapter.
+   *
+   * @private {!i18n.input.chrome.inputview.Adapter}
+   */
+  this.adapter_ = adapter;
+
+
+  /**
+   * The swipe elements.
+   *
+   * @private {!Array.<!Element>}
+   */
+  this.trackElements_ = [];
+
+  /**
+   * The window that shows the swipe field.
+   *
+   * @private {Object}
+   */
+  this.trackWindow_ = null;
+
+  /**
+   * The text before the current focus.
+   *
+   * @private {string}
+   */
+  this.surroundingText_ = '';
+
+  /**
+   * The index of focus in the surrounding text.
+   *
+   * @private {number}
+   */
+  this.surroundingTextFocus_ = 0;
+
+  /**
+   * The index of the anchor in the surrounding text.
+   *
+   * @private {number}
+   */
+  this.surroundingTextAnchor_ = 0;
+
+  /**
+   * Recent words that have been deleted.
+   *
+   * @private {Array.<string>}
+   */
+  this.deletedWords_ = [];
+
+  /**
+   * The pointer handler.
+   *
+   * @type {!i18n.input.chrome.inputview.handler.PointerHandler}
+   * @private
+   */
+  this.pointerHandler_ = new i18n.input.chrome.inputview.handler.
+      PointerHandler();
+
+};
+goog.inherits(i18n.input.chrome.inputview.elements.content.SwipeView,
+    i18n.input.chrome.inputview.elements.Element);
+var SwipeView = i18n.input.chrome.inputview.elements.content.SwipeView;
+
+
+/**
+ * The number of swipe elements.
+ *
+ * @type {number}
+ * @private
+ */
+SwipeView.LENGTH_ = 7;
+
+
+/**
+ * Index of highlighted accent. Use this index to represent no highlighted
+ * accent.
+ *
+ * @type {number}
+ * @private
+ */
+SwipeView.INVALIDINDEX_ = -1;
+
+
+/**
+ * The distance between finger to track view which will cancel the track
+ * view.
+ *
+ * @type {number}
+ * @private
+ */
+SwipeView.FINGER_DISTANCE_TO_CANCEL_SWIPE_ = 20;
+
+
+/**
+ * The cover element.
+ * Note: The reason we use a separate cover element instead of the view is
+ * because of the opacity. We can not reassign the opacity in child element.
+ *
+ * @type {!Element}
+ * @private
+ */
+SwipeView.prototype.coverElement_;
+
+
+/**
+ * The index of the alternative element which is highlighted.
+ *
+ * @type {number}
+ * @private
+ */
+SwipeView.prototype.highlightIndex_ = SwipeView.INVALIDINDEX_;
+
+
+/**
+ * The key which trigger this alternative data view.
+ *
+ * @type {!i18n.input.chrome.inputview.elements.content.SoftKey}
+ */
+SwipeView.prototype.triggeredBy;
+
+
+/**
+ * Whether finger movement is being tracked.
+ *
+ * @type {boolean}
+ * @private
+ */
+SwipeView.prototype.tracking_ = false;
+
+
+/**
+ * Whether to deploy the tracker on swipe events.
+ *
+ * @type {boolean}
+ * @private
+ */
+SwipeView.prototype.armed_ = false;
+
+
+/**
+ * Whether the tracker will be deployed on future swipe events.
+ *
+ * @return {boolean}
+ */
+SwipeView.prototype.isArmed = function() {
+  return this.armed_;
+};
+
+
+/**
+ * Callback when surrounding text is changed.
+ *
+ * @param {!i18n.input.chrome.inputview.events.SurroundingTextChangedEvent} e .
+ * @private
+ */
+SwipeView.prototype.onSurroundingTextChanged_ = function(e) {
+  if (this.adapter_.isPasswordBox()) {
+    this.surroundingText_ = '';
+    this.surroundingTextAnchor_ = this.surroundingTextFocus_ = 0;
+    return;
+  }
+
+  this.surroundingTextAnchor_ = e.anchor;
+  this.surroundingTextFocus_ = e.focus;
+
+  var text = e.text || '';
+  var oldText = this.surroundingText_;
+  var diff = '';
+  if (util.isLetterDelete(oldText, text)) {
+    diff = oldText.slice(-1);
+  } else if (util.isLetterRestore(oldText, text)) {
+    // Letter restore.
+    // Handle blink bug where ctrl+delete deletes a space and inserts
+    // a &nbsp.
+    // Convert &nbsp to ' ' and remove from delete words since blink
+    // did a minirestore for us.
+    var letter = text[text.length - 1];
+    if (letter == String.fromCharCode(160) || letter == ' ') {
+      var lastDelete = this.deletedWords_.pop();
+      var firstChar = lastDelete && lastDelete[0] || '';
+      if (firstChar == String.fromCharCode(160) || firstChar == ' ') {
+        this.deletedWords_.push(lastDelete.slice(1));
+      }
+    }
+  } else if (e.text.length == 100 || oldText.length == 100) {
+    // Check if a word was deleted from oldText.
+      var candidate = oldText.trim().split(' ').pop();
+      if (util.isPossibleDelete(oldText, text, candidate)) {
+        var location = oldText.lastIndexOf(candidate);
+        var intersectingText = oldText.slice(0, location);
+        diff = oldText.slice(location);
+      }
+  } else {
+    diff = oldText.substring(text.length);
+  }
+  if (diff) {
+    this.deletedWords_.push(diff);
+  // Do not reset while swiping.
+  } else if (!this.isVisible()) {
+    this.deletedWords_ = [];
+  }
+  this.surroundingText_ = text;
+};
+
+
+/**
+ * Handles the swipe action.
+ *
+ * @param {!i18n.input.chrome.inputview.events.SwipeEvent} e The swipe event.
+ * @private
+ */
+SwipeView.prototype.handleSwipeAction_ = function(e) {
+  var direction = e.direction;
+  if (this.isVisible()) {
+    if (e.view.type == ElementType.BACKSPACE_KEY) {
+      // Cache whether we were tracking.
+      var alreadyTracking = this.tracking_;
+      var changed = this.highlightItem(e.x, e.y);
+      // Did not move segments.
+      if (!changed) {
+        // First gesture.
+        if (!alreadyTracking) {
+          // All previous deletions count as one now.
+          this.deletedWords_.reverse();
+          var word = this.deletedWords_.join('');
+          this.deletedWords_ = [word];
+          // Swiped right, cancel the deletion.
+          if (direction & i18n.input.chrome.inputview.SwipeDirection.RIGHT) {
+            word = this.deletedWords_.pop();
+              if (word)
+                this.adapter_.commitText(word);
+          }
+        }
+        return;
+      }
+
+      if (direction & i18n.input.chrome.inputview.SwipeDirection.LEFT) {
+        this.adapter_.sendKeyDownAndUpEvent(
+            '\u0008', KeyCodes.BACKSPACE, undefined, undefined, {
+              ctrl: true,
+              shift: false
+        });
+      } else if (direction & i18n.input.chrome.inputview.SwipeDirection.RIGHT) {
+        var word = this.deletedWords_.pop();
+        if (word)
+          this.adapter_.commitText(word);
+        // Restore text we deleted before the track came up, but part of the
+        // same gesture.
+        if (this.isAtOrigin()) {
+          word = this.deletedWords_.pop();
+          if (word)
+            this.adapter_.commitText(word);
+        }
+      }
+      return;
+    }
+    if (e.view.type == ElementType.SELECT_VIEW) {
+      // Cache whether we were tracking as highlight may change this.
+      var alreadyTracking = this.tracking_;
+      var changed = this.highlightItem(e.x, e.y);
+      // First finger movement is onto the blank track. Ignore.
+      if (!alreadyTracking)
+        return;
+      if (!changed)
+        return;
+      var index = this.getTrackIndex();
+      if (index == -1) {
+        console.error('Invalid track index.');
+        return;
+      }
+      var selectWord = index % 2 == 1;
+      var code;
+      if (direction & i18n.input.chrome.inputview.SwipeDirection.LEFT) {
+        code = KeyCodes.ARROW_LEFT;
+      } else if (direction & i18n.input.chrome.inputview.SwipeDirection.RIGHT) {
+        code = KeyCodes.ARROW_RIGHT;
+      } else {
+        return;
+      }
+      // If anchor == focus we are either at the end or the start of the word
+      // and no selection is in place.
+      if (this.surroundingTextAnchor_ == this.surroundingTextFocus_) {
+        // Do not move carat at all, as this will either have no effect or cause
+        // us to splice the word.
+        if (!selectWord) {
+         return;
+        }
+      }
+      this.adapter_.sendKeyDownAndUpEvent(
+          '', code, undefined, undefined, {
+              ctrl: selectWord,
+              shift: selectWord
+      });
+      return;
+    }
+    return;
+  }
+
+  // User swiped on backspace key before swipeview was visible.
+  if (e.view.type == ElementType.BACKSPACE_KEY) {
+    if (!this.armed_) {
+      // Prevents reshowing the track after it is hidden as part of the same
+      // finger movement.
+      return;
+    }
+    if (e.direction & i18n.input.chrome.inputview.SwipeDirection.LEFT) {
+      var key = /** @type {!content.FunctionalKey} */ (e.view);
+      // Equiv to a longpress.
+      this.showDeletionTrack(key);
+    }
+    return;
+  }
+};
+
+
+/**
+ * Handles the pointer action.
+ *
+ * @param {!i18n.input.chrome.inputview.events.PointerEvent} e .
+ * @private
+ */
+SwipeView.prototype.handlePointerAction_ = function(e) {
+  switch (e.view.type) {
+    case ElementType.BACKSPACE_KEY:
+      var key = /** @type {!content.FunctionalKey} */ (e.view);
+      if (e.type == EventType.POINTER_DOWN) {
+        if (this.adapter_.contextType != ContextType.URL) {
+          this.armed_ = true;
+        }
+        this.deletedWords_ = [];
+      } else if (e.type == EventType.POINTER_UP || e.type == EventType.
+          POINTER_OUT) {
+        if (!this.isVisible()) {
+          this.armed_ = false;
+        }
+      } else if (e.type == EventType.LONG_PRESS) {
+        if (this.adapter_.isGestureDeletionEnabled()) {
+          this.showDeletionTrack(key);
+        }
+      }
+      break;
+    case ElementType.SWIPE_VIEW:
+      if (e.type == EventType.POINTER_DOWN &&
+          e.target == this.getCoverElement()) {
+        this.hide();
+      } else if (e.type == EventType.POINTER_UP ||
+                 e.type == EventType.POINTER_OUT) {
+        this.hide();
+        // Reset the deleted words.
+        this.deletedWords_ = [];
+      }
+      break;
+    case ElementType.SELECT_VIEW:
+      if (e.type == EventType.POINTER_DOWN) {
+        this.showSelectionTrack(e.x, e.y);
+      }
+      if (e.type == EventType.POINTER_UP) {
+        this.hide();
+      }
+      break;
+  }
+};
+
+/** @override */
+SwipeView.prototype.createDom = function() {
+  goog.base(this, 'createDom');
+
+  var dom = this.getDomHelper();
+  var elem = this.getElement();
+  goog.dom.classlist.add(elem, i18n.input.chrome.inputview.Css.SWIPE_VIEW);
+  this.coverElement_ = dom.createDom(goog.dom.TagName.DIV,
+      i18n.input.chrome.inputview.Css.TRACK_COVER);
+  dom.appendChild(document.body, this.coverElement_);
+  goog.style.setElementShown(this.coverElement_, false);
+
+  this.coverElement_['view'] = this;
+};
+
+
+/** @override */
+SwipeView.prototype.enterDocument = function() {
+  goog.base(this, 'enterDocument');
+  this.getHandler().
+    listen(this.adapter_,
+        i18n.input.chrome.inputview.events.EventType.
+            SURROUNDING_TEXT_CHANGED,
+        this.onSurroundingTextChanged_).
+    listen(this.pointerHandler_, [
+      EventType.SWIPE], this.handleSwipeAction_).
+    listen(this.pointerHandler_, [
+          EventType.LONG_PRESS,
+          EventType.POINTER_UP,
+          EventType.POINTER_DOWN,
+          EventType.POINTER_OUT], this.handlePointerAction_);
+  goog.style.setElementShown(this.getElement(), false);
+};
+
+
+/**
+ * Shows the swipe tracker.
+ *
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width The width of a key.
+ * @param {number} height The height of a key.
+ * @param {number} firstTrackWidth The width of the first key.
+ * @param {number} firstSegmentWidth The width of the first buffer segment.
+ * @param {string=} opt_character Characters on each key.
+ * @param {Css=} opt_css Optional icon css class.
+ * @private
+ */
+SwipeView.prototype.showDeletionTrack_ = function(x, y, width, height,
+    firstTrackWidth, firstSegmentWidth, opt_character, opt_css) {
+  this.tracking_ = false;
+  goog.style.setElementShown(this.getElement(), true);
+  this.getDomHelper().removeChildren(this.getElement());
+  // Each key except last has a separator.
+  var totalWidth = ((2 * SwipeView.LENGTH_) - 3) * width;
+  totalWidth += firstTrackWidth + firstSegmentWidth;
+
+  this.ltr = true;
+  this.highlightIndex_ = 0;
+  if ((x + totalWidth) > screen.width) {
+    // If not enough space at the right, then make it to the left.
+    x -= totalWidth;
+    this.ltr = false;
+    this.highlightIndex_ = SwipeView.LENGTH_ - 1;
+  }
+  if (firstTrackWidth == 0) {
+    this.highlightIndex_ = SwipeView.INVALIDINDEX_;
+  }
+  var ltr = this.ltr;
+  var isFirstSegment = function(i) {
+    return ltr ? i == 0 : i == SwipeView.LENGTH_ - 2;
+  };
+  var isFirstTrackPiece = function(i) {
+    return ltr ? i == 0 : i == SwipeView.LENGTH_ - 1;
+  };
+  for (var i = 0; i < SwipeView.LENGTH_; i++) {
+    var trackWidth = isFirstTrackPiece(i) ? firstTrackWidth : width;
+    if (trackWidth != 0) {
+      var keyElem = this.addKey_(opt_character, opt_css);
+      goog.style.setSize(keyElem, trackWidth, height);
+      this.trackElements_.push(keyElem);
+    }
+
+    if (i != (SwipeView.LENGTH_ - 1)) {
+      var segmentWidth = isFirstSegment(i) ? firstSegmentWidth : width;
+      this.addSeparator_(segmentWidth, height);
+    }
+  }
+  goog.style.setPosition(this.getElement(), x, y);
+  // Highlight selected element if it's index is valid.
+  if (this.highlightIndex_ != SwipeView.INVALIDINDEX_) {
+    var elem = this.trackElements_[this.highlightIndex_];
+    this.setElementBackground_(elem, true);
+  }
+  goog.style.setElementShown(this.coverElement_, true);
+  this.triggeredBy && this.triggeredBy.setHighlighted(true);
+};
+
+
+/**
+ *
+ * Shows the swipe tracker.
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width The width of a key.
+ * @param {number} height The height of a key.
+ * @param {string} character Characters on each key.
+ * @private
+ */
+SwipeView.prototype.showSelectionTrack_ = function(x, y, width, height,
+    character) {
+  this.tracking_ = false;
+  goog.style.setElementShown(this.getElement(), true);
+  this.getDomHelper().removeChildren(this.getElement());
+  // Each key has a separator.
+  var totalWidth = ((2 * SwipeView.LENGTH_)) * width;
+
+  this.ltr = true;
+  this.highlightIndex_ = SwipeView.INVALIDINDEX_;
+  if ((x + totalWidth) > screen.width) {
+    // If not enough space at the right, then make it to the left.
+    x -= totalWidth;
+    this.ltr = false;
+  }
+
+  for (var i = 0; i < SwipeView.LENGTH_; i++) {
+    var keyElem;
+    if (!this.ltr) {
+      keyElem = this.addKey_(character);
+      goog.style.setSize(keyElem, width, height);
+      this.trackElements_.push(keyElem);
+    }
+
+    keyElem = this.addSeparator_(width, height);
+    goog.style.setSize(keyElem, width, height);
+    this.trackElements_.push(keyElem);
+
+    if (this.ltr) {
+      keyElem = this.addKey_(character);
+      goog.style.setSize(keyElem, width, height);
+      this.trackElements_.push(keyElem);
+    }
+  }
+  goog.style.setPosition(this.getElement(), x, y);
+  goog.style.setElementShown(this.coverElement_, true);
+  this.triggeredBy && this.triggeredBy.setHighlighted(true);
+};
+
+
+/**
+ * Shows the alt data view.
+ *
+ * @param {!i18n.input.chrome.inputview.elements.content.SoftKey} key
+ *   The key triggered this track view.
+ */
+SwipeView.prototype.showDeletionTrack = function(key) {
+  this.triggeredBy = key;
+  var coordinate = goog.style.getClientPosition(key.getElement());
+  if (key.type == ElementType.BACKSPACE_KEY) {
+    this.showDeletionTrack_(
+      coordinate.x + key.availableWidth,
+      coordinate.y,
+      70,
+      key.availableHeight,
+      key.availableWidth,
+      100,
+      undefined,
+      Css.BACKSPACE_ICON);
+  }
+};
+
+
+/**
+ * Shows the selection track.
+ *
+ * @param {number} x
+ * @param {number} y
+ */
+SwipeView.prototype.showSelectionTrack = function(x, y) {
+  var ltr = x <= (screen.width / 2);
+
+  this.showSelectionTrack_(
+    ltr ? 0 : screen.width,
+    Math.max(y - 35, 35), // Center track on finger press but force containment.
+    70,
+    70,
+    x > (screen.width / 2) ? '<' : '>');
+};
+
+
+/**
+ * Hides the alt data view.
+ */
+SwipeView.prototype.hide = function() {
+  this.armed_ = false;
+  this.trackElements_ = [];
+  this.tracking_ = false;
+  if (this.triggeredBy)
+    this.triggeredBy.setHighlighted(false);
+  goog.style.setElementShown(this.getElement(), false);
+  goog.style.setElementShown(this.coverElement_, false);
+  this.highlightIndex_ = SwipeView.INVALIDINDEX_;
+};
+
+
+/**
+ * Whether the current track counter is at the first element.
+ *
+ * @return {boolean}
+ */
+SwipeView.prototype.isAtOrigin = function() {
+  return this.ltr ? this.highlightIndex_ == 0 :
+      this.highlightIndex_ == SwipeView.LENGTH_ - 1;
+};
+
+
+/**
+ * Highlights the item according to the current coordinate of the finger.
+ *
+ * @param {number} x .
+ * @param {number} y .
+ * @return {boolean} Whether it passed into a new segment.
+ */
+SwipeView.prototype.highlightItem = function(x, y) {
+  var previousIndex = this.highlightIndex_;
+  for (var i = 0; i < this.trackElements_.length; i++) {
+    var elem = this.trackElements_[i];
+    var coordinate = goog.style.getClientPosition(elem);
+    var size = goog.style.getSize(elem);
+    if (coordinate.x < x && (coordinate.x + size.width) > x) {
+      this.highlightIndex_ = i;
+      this.clearAllHighlights_();
+      this.setElementBackground_(elem, true);
+    }
+  }
+  this.tracking_ = this.tracking_ || (previousIndex != this.highlightIndex_);
+  return (previousIndex != this.highlightIndex_);
+};
+
+
+/**
+ * Clears all the highlights.
+ *
+ * @private
+ */
+SwipeView.prototype.clearAllHighlights_ =
+    function() {
+  for (var i = 0; i < this.trackElements_.length; i++) {
+    this.setElementBackground_(this.trackElements_[i], false);
+  }
+};
+
+
+/**
+ * Sets the background style of the element.
+ *
+ * @param {!Element} element The element.
+ * @param {boolean} highlight True to highlight the element.
+ * @private
+ */
+SwipeView.prototype.setElementBackground_ =
+    function(element, highlight) {
+  if (highlight) {
+    goog.dom.classlist.add(element, i18n.input.chrome.inputview.Css.
+        ELEMENT_HIGHLIGHT);
+  } else {
+    goog.dom.classlist.remove(element, i18n.input.chrome.inputview.Css.
+        ELEMENT_HIGHLIGHT);
+  }
+};
+
+
+/**
+ * Adds a alt data key into the view.
+ *
+ * @param {string=} opt_character The character.
+ * @param {Css=} opt_icon_css
+ * @return {!Element} The create key element.
+ * @private
+ */
+SwipeView.prototype.addKey_ = function(opt_character, opt_icon_css) {
+  var dom = this.getDomHelper();
+  var character = opt_character &&
+      i18n.input.chrome.inputview.util.getVisibleCharacter(opt_character);
+  var keyElem;
+  if (character)
+    keyElem = dom.createDom(goog.dom.TagName.DIV, Css.SWIPE_KEY, character);
+  else
+    keyElem = dom.createDom(goog.dom.TagName.DIV, Css.SWIPE_KEY);
+  if (opt_icon_css) {
+    var child = dom.createDom(goog.dom.TagName.DIV, opt_icon_css);
+    dom.appendChild(keyElem, child);
+  }
+  dom.appendChild(this.getElement(), keyElem);
+  return keyElem;
+};
+
+
+/**
+ * Adds a separator.
+ *
+ * @param {number} width .
+ * @param {number} height .
+ * @return {Element}
+ * @private
+ */
+SwipeView.prototype.addSeparator_ = function(width, height) {
+  var dom = this.getDomHelper();
+  var tableCell = dom.createDom(goog.dom.TagName.DIV,
+      i18n.input.chrome.inputview.Css.TABLE_CELL);
+  goog.style.setSize(tableCell, width + 'px', height + 'px');
+  goog.dom.classlist.add(tableCell, Css.SWIPE_SEPARATOR);
+  dom.appendChild(this.getElement(), tableCell);
+  return tableCell;
+};
+
+
+/**
+ * Gets the cover element.
+ *
+ * @return {!Element} The cover element.
+ */
+SwipeView.prototype.getCoverElement = function() {
+  return this.coverElement_;
+};
+
+
+/**
+ * The current index.
+ * @return {number}
+ */
+SwipeView.prototype.getTrackIndex = function() {
+  if (this.highlightIndex_ == SwipeView.INVALIDINDEX_)
+    return SwipeView.INVALIDINDEX_;
+  if (this.ltr)
+    return this.highlightIndex_;
+  return this.trackElements_.length - this.highlightIndex_ - 1;
+};
+
+
+/** @override */
+SwipeView.prototype.resize = function(width, height) {
+  goog.base(this, 'resize', width, height);
+
+  goog.style.setSize(this.coverElement_, width, height);
+};
+
+
+/**
+ * Resets the swipeview.
+ *
+ */
+SwipeView.prototype.reset = function() {
+  this.deletedWords_ = [];
+  this.surroundingText_ = '';
+  this.hide();
+};
+
+
+/** @override */
+SwipeView.prototype.disposeInternal = function() {
+  goog.dispose(this.pointerHandler_);
+
+  goog.base(this, 'disposeInternal');
+};
+
+});  // goog.scope
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/switcherkey.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/switcherkey.js
index 978887e..9aa0fedc 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/switcherkey.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/switcherkey.js
@@ -13,12 +13,14 @@
 //
 goog.provide('i18n.input.chrome.inputview.elements.content.SwitcherKey');
 
+goog.require('goog.dom.classlist');
+goog.require('i18n.input.chrome.inputview.Css');
 goog.require('i18n.input.chrome.inputview.elements.content.FunctionalKey');
 
 
-
 goog.scope(function() {
 var FunctionalKey = i18n.input.chrome.inputview.elements.content.FunctionalKey;
+var Css = i18n.input.chrome.inputview.Css;
 
 
 
@@ -72,6 +74,10 @@
   goog.base(this, 'createDom');
 
   this.setAriaLabel(this.getChromeVoxMessage());
+
+  if (this.textElem) {
+    goog.dom.classlist.add(this.getElement(), Css.SWITCHER_KEY_NAME);
+  }
 };
 
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/tabbarkey.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/tabbarkey.js
index 4ee6846..84bb0b8 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/tabbarkey.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/tabbarkey.js
@@ -91,7 +91,9 @@
   goog.dom.classlist.remove(this.bgElem, Css.SPECIAL_KEY_BG);
   goog.dom.classlist.add(this.bgElem, Css.EMOJI_TABBAR_KEY);
   goog.dom.classlist.add(this.iconElem, Css.EMOJI_SWITCH);
-  this.createSeparator_();
+  if (!i18n.input.chrome.inputview.GlobalFlags.isQPInputView) {
+    this.createSeparator_();
+  }
 
   // Sets aria label.
   var ariaLabel = '';
@@ -133,9 +135,11 @@
   this.tableCell.style.width = this.availableWidth + 'px';
   this.tableCell.style.height = this.availableHeight -
       this.BORDER_HEIGHT_ + 'px';
-  this.sepTableCell.style.height = this.availableHeight -
-      this.BORDER_HEIGHT_ + 'px';
-  this.separator.style.height = this.availableHeight * 0.32 + 'px';
+  if (!i18n.input.chrome.inputview.GlobalFlags.isQPInputView) {
+    this.sepTableCell.style.height = this.availableHeight -
+        this.BORDER_HEIGHT_ + 'px';
+    this.separator.style.height = this.availableHeight * 0.32 + 'px';
+  }
 };
 
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/toolbarbutton.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/toolbarbutton.js
new file mode 100644
index 0000000..dec8bb2b
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/toolbarbutton.js
@@ -0,0 +1,108 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.provide('i18n.input.chrome.inputview.elements.content.ToolbarButton');
+
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classlist');
+goog.require('goog.style');
+goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.elements.Element');
+
+
+
+goog.scope(function() {
+var ElementType = i18n.input.chrome.inputview.elements.ElementType;
+var Css = i18n.input.chrome.inputview.Css;
+
+
+
+/**
+ * The icon button in the Toolbar view.
+ *
+ * @param {string} id .
+ * @param {ElementType} type .
+ * @param {string} iconCss .
+ * @param {string} text .
+ * @param {!goog.events.EventTarget=} opt_eventTarget .
+ * @param {boolean=} opt_alignLeft .
+ * @constructor
+ * @extends {i18n.input.chrome.inputview.elements.Element}
+ */
+i18n.input.chrome.inputview.elements.content.ToolbarButton = function(
+    id, type, iconCss, text, opt_eventTarget, opt_alignLeft) {
+  goog.base(this, id, type, opt_eventTarget);
+
+  /** @type {string} */
+  this.text = text;
+
+  /** @type {string} */
+  this.iconCss = iconCss;
+
+  this.alignLeft = opt_alignLeft || false;
+};
+var ToolbarButton = i18n.input.chrome.inputview.elements.content.
+    ToolbarButton;
+goog.inherits(ToolbarButton, i18n.input.chrome.inputview.elements.Element);
+
+
+/** @type {!Element} */
+ToolbarButton.prototype.iconCell;
+
+
+/** @override */
+ToolbarButton.prototype.createDom = function() {
+  goog.base(this, 'createDom');
+
+  var dom = this.getDomHelper();
+  var elem = this.getElement();
+  var css = [Css.CANDIDATE_INTER_CONTAINER,
+    Css.TOOLBAR_BUTTON];
+  if (this.alignLeft) {
+    css.push(Css.FLOAT_LEFT);
+  }
+  goog.dom.classlist.addAll(elem, css);
+
+  this.iconCell = dom.createDom(goog.dom.TagName.DIV, Css.TABLE_CELL);
+  dom.appendChild(elem, this.iconCell);
+
+  var iconElem = dom.createDom(goog.dom.TagName.DIV, Css.INLINE_DIV);
+  if (this.iconCss) {
+    goog.dom.classlist.add(iconElem, this.iconCss);
+  }
+  if (this.text) {
+    dom.setTextContent(iconElem, this.text);
+  }
+  dom.appendChild(this.iconCell, iconElem);
+};
+
+/** @override */
+ToolbarButton.prototype.setHighlighted = function(highlight) {
+  if (highlight) {
+    goog.dom.classlist.add(this.getElement(), Css.CANDIDATE_HIGHLIGHT);
+  } else {
+    goog.dom.classlist.remove(this.getElement(), Css.CANDIDATE_HIGHLIGHT);
+  }
+};
+
+
+/** @override */
+ToolbarButton.prototype.resize = function(width, height) {
+  goog.style.setSize(this.iconCell, width, height);
+
+  goog.base(this, 'resize', width, height);
+};
+
+
+});  // goog.scope
+
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/voiceview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/voiceview.js
index 14a63a8..4681268 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/voiceview.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/voiceview.js
@@ -13,16 +13,13 @@
 //
 goog.provide('i18n.input.chrome.inputview.elements.content.VoiceView');
 
-goog.require('goog.a11y.aria');
-goog.require('goog.a11y.aria.Announcer');
-goog.require('goog.a11y.aria.LivePriority');
-goog.require('goog.a11y.aria.State');
 goog.require('goog.asserts');
 goog.require('goog.async.Delay');
 goog.require('goog.dom.TagName');
 goog.require('goog.dom.classlist');
 goog.require('goog.style');
 goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.Sounds');
 goog.require('i18n.input.chrome.inputview.elements.Element');
 goog.require('i18n.input.chrome.inputview.elements.ElementType');
 goog.require('i18n.input.chrome.inputview.elements.content.FunctionalKey');
@@ -31,12 +28,11 @@
 
 
 goog.scope(function() {
-var Announcer = goog.a11y.aria.Announcer;
 var Css = i18n.input.chrome.inputview.Css;
-var EventType = goog.events.EventType;
 var ElementType = i18n.input.chrome.inputview.elements.ElementType;
 var FunctionalKey = i18n.input.chrome.inputview.elements.content.FunctionalKey;
 var Name = i18n.input.chrome.message.Name;
+var Sounds = i18n.input.chrome.inputview.Sounds;
 var TagName = goog.dom.TagName;
 var Type = i18n.input.chrome.message.Type;
 
@@ -47,11 +43,12 @@
  *
  * @param {goog.events.EventTarget=} opt_eventTarget The parent event target.
  * @param {i18n.input.chrome.inputview.Adapter=} opt_adapter .
+ * @param {i18n.input.chrome.SoundController=} opt_soundController .
  * @constructor
  * @extends {i18n.input.chrome.inputview.elements.Element}
  */
 i18n.input.chrome.inputview.elements.content.VoiceView =
-    function(opt_eventTarget, opt_adapter) {
+    function(opt_eventTarget, opt_adapter, opt_soundController) {
   VoiceView.base(this, 'constructor', '', ElementType.VOICE_VIEW,
       opt_eventTarget);
 
@@ -62,11 +59,15 @@
    */
   this.adapter_ = goog.asserts.assertObject(opt_adapter);
 
+  /**
+   * The sound controller.
+   *
+   * @private {!i18n.input.chrome.SoundController}
+   */
+  this.soundController_ = goog.asserts.assertObject(opt_soundController);
+
   /** @private {!goog.async.Delay} */
   this.animator_ = new goog.async.Delay(this.animateMicrophoneLevel_, 0, this);
-
-  /** @private {!Announcer} */
-  this.announcer_ = new Announcer();
 };
 var VoiceView = i18n.input.chrome.inputview.elements.content.VoiceView;
 goog.inherits(VoiceView, i18n.input.chrome.inputview.elements.Element);
@@ -120,23 +121,22 @@
   var elem = this.getElement();
   goog.dom.classlist.add(elem, Css.VOICE_VIEW);
   this.voicePanel_ = dom.createDom(TagName.DIV, Css.VOICE_PANEL);
-  this.voiceMicElem_ = dom.createDom(goog.dom.TagName.DIV,
+  this.voiceMicElem_ = dom.createDom(TagName.DIV,
       Css.VOICE_OPACITY + ' ' + Css.VOICE_MIC_ING);
+
   this.levelElement_ = dom.createDom(
-      goog.dom.TagName.DIV, Css.VOICE_LEVEL);
+      TagName.DIV, Css.VOICE_LEVEL);
   dom.append(/** @type {!Node} */ (this.voicePanel_),
       this.voiceMicElem_, this.levelElement_);
-  goog.a11y.aria.setState(this.voiceMicElem_, goog.a11y.aria.State.LABEL,
-      chrome.i18n.getMessage('VOICE_TURN_OFF'));
 
   this.maskElem_ = dom.createDom(TagName.DIV,
       [Css.VOICE_MASK, Css.VOICE_OPACITY_NONE]);
   dom.append(/** @type {!Node} */ (elem), this.maskElem_, this.voicePanel_);
 
-  this.privacyDiv_ = dom.createDom(goog.dom.TagName.DIV,
+  this.privacyDiv_ = dom.createDom(TagName.DIV,
       Css.VOICE_PRIVACY_INFO);
 
-  var textDiv = dom.createDom(goog.dom.TagName.DIV, Css.VOICE_PRIVACY_TEXT);
+  var textDiv = dom.createDom(TagName.DIV, Css.VOICE_PRIVACY_TEXT);
   dom.setTextContent(textDiv,
       chrome.i18n.getMessage('VOICE_PRIVACY_INFO'));
   dom.appendChild(this.privacyDiv_, textDiv);
@@ -169,11 +169,13 @@
  * Start recognition.
  */
 VoiceView.prototype.start = function() {
+  // visible -> invisible
+  if (!this.isVisible()) {
+    this.soundController_.playSound(Sounds.VOICE_RECOG_START, true);
+  }
   if (this.isPrivacyAllowed_) {
     this.adapter_.sendVoiceViewStateChange(true);
     this.animator_.start();
-    this.announcer_.say(chrome.i18n.getMessage('VOICE_TURN_ON'),
-        goog.a11y.aria.LivePriority.ASSERTIVE);
   }
   this.setVisible(true);
 };
@@ -183,15 +185,18 @@
  * Stop recognition.
  */
 VoiceView.prototype.stop = function() {
+  // invisible -> visible
+  if (this.isVisible()) {
+    this.soundController_.playSound(Sounds.VOICE_RECOG_END, true);
+  }
   this.animator_.stop();
-  this.announcer_.say(chrome.i18n.getMessage('VOICE_TURN_OFF'),
-      goog.a11y.aria.LivePriority.ASSERTIVE);
   this.setVisible(false);
 };
 
 
 /** @override */
 VoiceView.prototype.setVisible = function(visible) {
+  VoiceView.base(this, 'setVisible', visible);
   if (visible) {
     goog.style.setElementShown(this.voicePanel_, true);
     goog.dom.classlist.add(this.maskElem_, Css.VOICE_MASK_OPACITY);
@@ -246,8 +251,7 @@
   this.isPrivacyAllowed_ = true;
   this.adapter_.sendVoiceViewStateChange(true);
   this.animator_.start();
-  this.announcer_.say(chrome.i18n.getMessage('VOICE_TURN_ON'),
-      goog.a11y.aria.LivePriority.ASSERTIVE);
+  this.soundController_.playSound(Sounds.VOICE_RECOG_START, true);
   goog.dom.classlist.add(this.privacyDiv_, Css.HANDWRITING_PRIVACY_INFO_HIDDEN);
   goog.dom.classlist.remove(this.maskElem_, Css.VOICE_OPACITY_NONE);
 };
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/elementtype.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/elementtype.js
index fdb6f37..035bfd98 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/elementtype.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/elementtype.js
@@ -65,6 +65,18 @@
   EN_SWITCHER: 42,
   VOICE_BTN: 43,
   VOICE_VIEW: 44,
-  VOICE_PRIVACY_GOT_IT: 45
+  VOICE_PRIVACY_GOT_IT: 45,
+  BACK_TO_KEYBOARD: 46,
+  BOLD: 47,
+  ITALICS: 48,
+  UNDERLINE: 49,
+  COPY: 50,
+  PASTE: 51,
+  CUT: 52,
+  SELECT_ALL: 53,
+  REDO: 54,
+  UNDO: 55,
+  SWIPE_VIEW: 56,
+  SELECT_VIEW: 57
 };
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/extendedlayout.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/extendedlayout.js
index f13da37..b8aeac35 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/extendedlayout.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/extendedlayout.js
@@ -143,7 +143,7 @@
     if (this.heightInWeight_ < child.getHeightInWeight()) {
       this.heightInWeight_ = child.getHeightInWeight();
     }
-    this.widthInWeight_ += child.getWidthInWeight();
+    this.widthInWeight_ = child.getWidthInWeight();
   }
 };
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/handwritinglayout.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/handwritinglayout.js
index eb24e72..1024ff61 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/handwritinglayout.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/handwritinglayout.js
@@ -15,6 +15,7 @@
 
 goog.require('goog.dom.classlist');
 goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.GlobalFlags');
 goog.require('i18n.input.chrome.inputview.elements.Element');
 goog.require('i18n.input.chrome.inputview.elements.ElementType');
 goog.require('i18n.input.chrome.inputview.elements.Weightable');
@@ -113,9 +114,11 @@
     child.resize(
         Math.ceil(width * child.getWidthInWeight() / this.widthInWeight_),
         Math.ceil(height * child.getHeightInWeight() / this.heightInWeight_));
-    // 85/140 = 0.6
-    child.getElement().style.top =
-        Math.ceil(height * 0.6 / this.heightInWeight_);
+    if (!i18n.input.chrome.inputview.GlobalFlags.isQPInputView) {
+      // 85/140 = 0.6
+      child.getElement().style.top =
+          Math.ceil(height * 0.6 / this.heightInWeight_);
+    }
   }
 };
 });  // goog.scope
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/linearlayout.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/linearlayout.js
index f583c8e..ebcfebd 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/linearlayout.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/layout/linearlayout.js
@@ -119,6 +119,12 @@
 LinearLayout.prototype.resize = function(width, height) {
   goog.base(this, 'resize', width, height);
 
+  var elem = this.getElement();
+  var borderBox = goog.style.getBorderBox(elem);
+  var paddingBox = goog.style.getPaddingBox(elem);
+  var marginBox = goog.style.getMarginBox(elem);
+  var w = width - borderBox.left - borderBox.right - paddingBox.left -
+      paddingBox.right - marginBox.left - marginBox.right;
   var weightArray = [];
   for (var i = 0; i < this.getChildCount(); i++) {
     var child = /** @type {i18n.input.chrome.inputview.elements.Weightable} */ (
@@ -126,7 +132,7 @@
     weightArray.push(child.getWidthInWeight());
   }
   var splitedWidth = i18n.input.chrome.inputview.util.splitValue(weightArray,
-      width);
+      w);
   for (var i = 0; i < this.getChildCount(); i++) {
     var child = /** @type {i18n.input.chrome.inputview.elements.Element} */ (
         this.getChildAt(i));
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/events.js b/third_party/google_input_tools/src/chrome/os/inputview/events.js
index 558b60d..01dccb2 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/events.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/events.js
@@ -44,8 +44,9 @@
   LONG_PRESS_END: goog.events.getUniqueId('lpe'),
   POINTER_DOWN: goog.events.getUniqueId('pd'),
   POINTER_UP: goog.events.getUniqueId('pu'),
-  POINTER_OVER: goog.events.getUniqueId('po'),
+  POINTER_OVER: goog.events.getUniqueId('pv'),
   POINTER_OUT: goog.events.getUniqueId('po'),
+  REFRESH: goog.events.getUniqueId('rf'),
   SETTINGS_READY: goog.events.getUniqueId('sr'),
   SURROUNDING_TEXT_CHANGED: goog.events.getUniqueId('stc'),
   SWIPE: goog.events.getUniqueId('s'),
@@ -53,7 +54,8 @@
   CONTEXT_FOCUS: goog.events.getUniqueId('cf'),
   CONTEXT_BLUR: goog.events.getUniqueId('cb'),
   VISIBILITY_CHANGE: goog.events.getUniqueId('vc'),
-  MODEL_UPDATE: goog.events.getUniqueId('mu')
+  MODEL_UPDATE: goog.events.getUniqueId('mu'),
+  URL_CHANGED: goog.events.getUniqueId('uc')
 };
 
 
@@ -218,14 +220,20 @@
  * The event when the surrounding text is changed.
  *
  * @param {string} text The surrounding text.
+ * @param {number} anchor .
+ * @param {number} focus .
  * @constructor
  * @extends {goog.events.Event}
  */
-events.SurroundingTextChangedEvent = function(text) {
+events.SurroundingTextChangedEvent = function(text, anchor, focus) {
   goog.base(this, events.EventType.SURROUNDING_TEXT_CHANGED);
 
   /** @type {string} */
   this.text = text;
+  /** @type {number} */
+  this.anchor = anchor;
+  /** @type {number} */
+  this.focus = focus;
 };
 goog.inherits(events.SurroundingTextChangedEvent, goog.events.Event);
 
diff --git a/third_party/google_input_tools/src/chrome/os/message/contenttype.js b/third_party/google_input_tools/src/chrome/os/inputview/globalflags.js
similarity index 64%
rename from third_party/google_input_tools/src/chrome/os/message/contenttype.js
rename to third_party/google_input_tools/src/chrome/os/inputview/globalflags.js
index ff20b05..b6e58765 100644
--- a/third_party/google_input_tools/src/chrome/os/message/contenttype.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/globalflags.js
@@ -1,4 +1,4 @@
-// Copyright 2014 The ChromeOS IME Authors. All Rights Reserved.
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
 // limitations under the License.
 // See the License for the specific language governing permissions and
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -11,22 +11,12 @@
 // you may not use this file except in compliance with the License.
 // Licensed under the Apache License, Version 2.0 (the "License");
 //
-goog.provide('i18n.input.chrome.message.ContextType');
+goog.provide('i18n.input.chrome.inputview.GlobalFlags');
 
 
 /**
- * The message type.
+ * Whether input view keyboards of material design is enabled.
  *
- * @enum {string}
+ * @type {boolean}
  */
-i18n.input.chrome.message.ContextType = {
-  DEFAULT: 'text',
-  EMAIL: 'email',
-  PASSWORD: 'password',
-  URL: 'url',
-  NUMBER: 'number',
-  PHONE: 'tel'
-};
-
-
-
+i18n.input.chrome.inputview.GlobalFlags.isQPInputView = false;
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/handler/pointerhandler.js b/third_party/google_input_tools/src/chrome/os/inputview/handler/pointerhandler.js
index c89434e2..b2fceab 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/handler/pointerhandler.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/handler/pointerhandler.js
@@ -18,6 +18,7 @@
 goog.require('goog.events.EventTarget');
 goog.require('goog.events.EventType');
 goog.require('goog.math.Coordinate');
+goog.require('i18n.input.chrome.inputview.events.PointerEvent');
 goog.require('i18n.input.chrome.inputview.handler.PointerActionBundle');
 
 goog.scope(function() {
@@ -184,8 +185,8 @@
     if (pointerActionBundle) {
       pointerActionBundle.handlePointerUp(e);
     }
+    e.preventDefault();
   }
-  e.preventDefault();
   if (pointerActionBundle && pointerActionBundle.view &&
       pointerActionBundle.view.pointerConfig.stopEventPropagation) {
     e.stopPropagation();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/bold.png b/third_party/google_input_tools/src/chrome/os/inputview/images/bold.png
new file mode 100644
index 0000000..8753bbd
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/bold.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/copy.png b/third_party/google_input_tools/src/chrome/os/inputview/images/copy.png
new file mode 100644
index 0000000..074ea88
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/copy.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/cut.png b/third_party/google_input_tools/src/chrome/os/inputview/images/cut.png
new file mode 100644
index 0000000..cd27ee1
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/cut.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/italic.png b/third_party/google_input_tools/src/chrome/os/inputview/images/italic.png
new file mode 100644
index 0000000..38bc789
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/italic.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/material/arrow_down_for_floating.png b/third_party/google_input_tools/src/chrome/os/inputview/images/material/arrow_down_for_floating.png
index b559e46e..3c0ccb2 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/images/material/arrow_down_for_floating.png
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/material/arrow_down_for_floating.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/paste.png b/third_party/google_input_tools/src/chrome/os/inputview/images/paste.png
new file mode 100644
index 0000000..3014ad66
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/paste.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/redo.png b/third_party/google_input_tools/src/chrome/os/inputview/images/redo.png
new file mode 100644
index 0000000..6534b7b
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/redo.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/select_all.png b/third_party/google_input_tools/src/chrome/os/inputview/images/select_all.png
new file mode 100644
index 0000000..02a62e46
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/select_all.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/underline.png b/third_party/google_input_tools/src/chrome/os/inputview/images/underline.png
new file mode 100644
index 0000000..4a0e00f4
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/underline.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/images/undo.png b/third_party/google_input_tools/src/chrome/os/inputview/images/undo.png
new file mode 100644
index 0000000..818191c
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/images/undo.png
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/keyboardcontainer.js b/third_party/google_input_tools/src/chrome/os/inputview/keyboardcontainer.js
index b7bc0fa0..f66841b 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/keyboardcontainer.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/keyboardcontainer.js
@@ -18,6 +18,7 @@
 goog.require('goog.i18n.bidi');
 goog.require('goog.ui.Container');
 goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.GlobalFlags');
 goog.require('i18n.input.chrome.inputview.elements.content.AltDataView');
 goog.require('i18n.input.chrome.inputview.elements.content.CandidateView');
 goog.require('i18n.input.chrome.inputview.elements.content.EmojiView');
@@ -25,6 +26,8 @@
 goog.require('i18n.input.chrome.inputview.elements.content.HandwritingView');
 goog.require('i18n.input.chrome.inputview.elements.content.KeysetView');
 goog.require('i18n.input.chrome.inputview.elements.content.MenuView');
+goog.require('i18n.input.chrome.inputview.elements.content.SelectView');
+goog.require('i18n.input.chrome.inputview.elements.content.SwipeView');
 goog.require('i18n.input.chrome.inputview.elements.content.VoiceView');
 
 
@@ -44,10 +47,12 @@
  * The keyboard container.
  *
  * @param {!i18n.input.chrome.inputview.Adapter} adapter .
+ * @param {!i18n.input.chrome.SoundController} soundController .
  * @constructor
  * @extends {goog.ui.Container}
  */
-i18n.input.chrome.inputview.KeyboardContainer = function(adapter) {
+i18n.input.chrome.inputview.KeyboardContainer =
+    function(adapter, soundController) {
   goog.base(this);
 
   /** @type {!content.CandidateView} */
@@ -57,11 +62,17 @@
   /** @type {!content.AltDataView} */
   this.altDataView = new content.AltDataView(this);
 
+  /** @type {!content.SwipeView} */
+  this.swipeView = new content.SwipeView(adapter, this);
+
+  /** @type {!content.SelectView} */
+  this.selectView = new content.SelectView(this);
+
   /** @type {!content.MenuView} */
   this.menuView = new content.MenuView(this);
 
   /** @type {!content.VoiceView} */
-  this.voiceView = new content.VoiceView(this, adapter);
+  this.voiceView = new content.VoiceView(this, adapter, soundController);
 
   /** @type {!content.ExpandedCandidateView} */
   this.expandedCandidateView = new content.ExpandedCandidateView(this);
@@ -126,6 +137,8 @@
   this.candidateView.render(this.wrapperDiv_);
   this.getDomHelper().appendChild(elem, this.wrapperDiv_);
   this.altDataView.render();
+  this.swipeView.render();
+  this.selectView.render();
   this.menuView.render();
   this.voiceView.render();
   this.voiceView.setVisible(false);
@@ -276,15 +289,20 @@
 
   this.candidateView.setWidthInWeight(
       this.currentKeysetView.getWidthInWeight());
-  var candidateElem = this.candidateView.getElement();
-  candidateElem.style.paddingLeft = candidateElem.style.paddingRight =
-      padding + 'px';
   this.candidateView.resize(w, candidateViewHeight);
-  this.currentKeysetView.resize(w, h);
-  var currentKeysetViewElem = this.currentKeysetView.getElement();
-  currentKeysetViewElem.style.paddingLeft = currentKeysetViewElem.style.
-      paddingRight = padding + 'px';
   this.expandedCandidateView.resize(w, h);
+  if (i18n.input.chrome.inputview.GlobalFlags.isQPInputView) {
+    var candidateElem = this.candidateView.getElement();
+    candidateElem.style.paddingLeft = candidateElem.style.paddingRight =
+        padding + 'px';
+    this.currentKeysetView.resize(width, h, widthPercent);
+    var expandViewElem = this.expandedCandidateView.getElement();
+    expandViewElem.style.marginLeft = expandViewElem.style.marginRight =
+        padding + 'px';
+  } else {
+    this.currentKeysetView.resize(w, h, 1);
+    elem.style.paddingLeft = elem.style.paddingRight = padding + 'px';
+  }
   if (this.expandedCandidateView.isVisible()) {
     // Closes the expanded candidate view if it's visible.
     // This is to avoid mis-layout issue for the expanded candidate when screen
@@ -296,6 +314,8 @@
     this.currentKeysetView.setVisible(true);
   }
   this.altDataView.resize(screen.width, height);
+  this.swipeView.resize(screen.width, height);
+  this.selectView.resize(screen.width, height);
   this.menuView.resize(screen.width, height);
   this.voiceView.resize(w + padding, height);
 };
@@ -305,6 +325,8 @@
 KeyboardContainer.prototype.disposeInternal = function() {
   goog.dispose(this.candidateView);
   goog.dispose(this.altDataView);
+  goog.dispose(this.swipeView);
+  goog.dispose(this.selectView);
   goog.dispose(this.menuView);
   goog.dispose(this.voiceView);
   for (var key in this.keysetViewMap) {
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/emoji_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/emoji_layout.js
index 6bb6482..6b83866 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/layouts/emoji_layout.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/emoji_layout.js
@@ -96,17 +96,13 @@
   });
 
   keySpec = {
-    'widthInWeight': 42,
-    'heightInWeight': 14
-  };
-  baseSpec = {
-    'widthInWeight': 42,
+    'widthInWeight': 1.42,
     'heightInWeight': 14
   };
   var sideKeys = util.createVerticalLayout({
     'id': 'sideKeys',
     'children': [util.createKey(keySpec), util.createKey(keySpec),
-      util.createKey(baseSpec)]
+      util.createKey(keySpec)]
   });
 
   var rowsAndSideKeys = util.createLinearLayout({
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/handwriting_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/handwriting_layout.js
index 53b8f72..1bb0753b 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/layouts/handwriting_layout.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/handwriting_layout.js
@@ -11,7 +11,6 @@
 // you may not use this file except in compliance with the License.
 // Licensed under the Apache License, Version 2.0 (the "License");
 //
-goog.require('i18n.input.chrome.inputview.layouts.SpaceRow');
 goog.require('i18n.input.chrome.inputview.layouts.util');
 
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/101kbd_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/101kbd_layout.js
index a5111ef..ece6e699 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/101kbd_layout.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/101kbd_layout.js
@@ -40,7 +40,7 @@
       });
 
   var data = {
-    'layoutID': '101kbd',
+    'layoutID': 'm-101kbd',
     'widthInWeight': 15,
     'children': [keyboardContainer]
   };
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/102kbd_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/102kbd_layout.js
index 8c9d914..e980db2 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/102kbd_layout.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/102kbd_layout.js
@@ -40,7 +40,7 @@
       });
 
   var data = {
-    'layoutID': '102kbd',
+    'layoutID': 'm-102kbd',
     'widthInWeight': 15,
     'children': [keyboardContainer]
   };
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_azerty_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_azerty_layout.js
new file mode 100644
index 0000000..ba2d726
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_azerty_layout.js
@@ -0,0 +1,49 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.layouts.CompactSpaceRow');
+goog.require('i18n.input.chrome.inputview.layouts.RowsOfCompactAzerty');
+goog.require('i18n.input.chrome.inputview.layouts.util');
+
+
+(function() {
+  i18n.input.chrome.inputview.layouts.util.setPrefix('compactkbd-k-');
+
+  var topThreeRows =
+      i18n.input.chrome.inputview.layouts.RowsOfCompactAzerty.create();
+  var spaceRow =
+      i18n.input.chrome.inputview.layouts.CompactSpaceRow.create(false);
+
+  // Keyboard view.
+  var keyboardView = i18n.input.chrome.inputview.layouts.util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [topThreeRows, spaceRow],
+    'widthPercent': 100,
+    'heightPercent': 100
+  });
+
+  var keyboardContainer = i18n.input.chrome.inputview.layouts.util.
+      createLinearLayout({
+        'id': 'keyboardContainer',
+        'children': [keyboardView]
+      });
+
+  var data = {
+    'layoutID': 'm-compactkbd-azerty',
+    'widthInWeight': 15,
+    'children': [keyboardContainer]
+  };
+
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_nordic_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_nordic_layout.js
new file mode 100644
index 0000000..586e920
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_nordic_layout.js
@@ -0,0 +1,49 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.layouts.CompactSpaceRow');
+goog.require('i18n.input.chrome.inputview.layouts.RowsOfCompactNordic');
+goog.require('i18n.input.chrome.inputview.layouts.util');
+
+
+(function() {
+  i18n.input.chrome.inputview.layouts.util.setPrefix('compactkbd-k-');
+
+  var topThreeRows =
+      i18n.input.chrome.inputview.layouts.RowsOfCompactNordic.create();
+  var spaceRow =
+      i18n.input.chrome.inputview.layouts.CompactSpaceRow.create(true);
+
+  // Keyboard view.
+  var keyboardView = i18n.input.chrome.inputview.layouts.util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [topThreeRows, spaceRow],
+    'widthPercent': 100,
+    'heightPercent': 100
+  });
+
+  var keyboardContainer = i18n.input.chrome.inputview.layouts.util.
+      createLinearLayout({
+        'id': 'keyboardContainer',
+        'children': [keyboardView]
+      });
+
+  var data = {
+    'layoutID': 'm-compactkbd-nordic',
+    'widthInWeight': 15,
+    'children': [keyboardContainer]
+  };
+
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_numberpad_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_numberpad_layout.js
new file mode 100644
index 0000000..503aecb
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_numberpad_layout.js
@@ -0,0 +1,51 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.layouts.RowsOfNumberpad');
+goog.require('i18n.input.chrome.inputview.layouts.util');
+
+
+(function() {
+  i18n.input.chrome.inputview.layouts.util.keyIdPrefix = 'compactkbd-k-';
+
+  var rows = i18n.input.chrome.inputview.layouts.RowsOfNumberpad.create();
+
+  // Keyboard view.
+  var keyboardView = i18n.input.chrome.inputview.layouts.util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [rows],
+    'widthPercent': 50,
+    'heightPercent': 100
+  });
+
+  var keyboardContainer = i18n.input.chrome.inputview.layouts.util.
+      createLinearLayout({
+        'id': 'keyboardContainer',
+        'children': [keyboardView]
+      });
+
+  var data = {
+    'layoutID': 'm-compactkbd-numberpad',
+    'widthInWeight': 6.45,
+    'children': [keyboardContainer],
+    'disableCandidateView': true,
+    'disableLongpress': true,
+    'widthPercent' : {
+      'LANDSCAPE' : 0.56,
+      'PORTRAIT' : 0.56,
+      'LANDSCAPE_WIDE_SCREEN': 0.56
+    }};
+
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_zhuyin_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_zhuyin_layout.js
new file mode 100644
index 0000000..12f93942
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/compactkbd_zhuyin_layout.js
@@ -0,0 +1,93 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.layouts.CompactSpaceRow');
+goog.require('i18n.input.chrome.inputview.layouts.RowsOfCompact');
+goog.require('i18n.input.chrome.inputview.layouts.util');
+
+
+(function() {
+  i18n.input.chrome.inputview.layouts.util.setPrefix('compactkbd-k-');
+
+  var topRows =
+      i18n.input.chrome.inputview.layouts.RowsOfCompactZhuyin.create();
+
+  var digitSwitcher = i18n.input.chrome.inputview.layouts.util.createKey({
+    'widthInWeight': 1.1,
+    'heightInWeight': 4
+  });
+  var globeOrSymbolKey = i18n.input.chrome.inputview.layouts.util.createKey({
+    'condition': i18n.input.chrome.inputview.ConditionName.SHOW_GLOBE_OR_SYMBOL,
+    'widthInWeight': 1,
+    'heightInWeight': 4
+  });
+  var menuKey = i18n.input.chrome.inputview.layouts.util.createKey({
+    'condition': i18n.input.chrome.inputview.ConditionName.SHOW_MENU,
+    'widthInWeight': 1,
+    'heightInWeight': 4
+  });
+  var comma = i18n.input.chrome.inputview.layouts.util.createKey({
+    'widthInWeight': 1,
+    'heightInWeight': 4
+  });
+  var space = i18n.input.chrome.inputview.layouts.util.createKey({
+    'widthInWeight': 3,
+    'heightInWeight': 4
+  });
+  var character = i18n.input.chrome.inputview.layouts.util.createKey({
+    'widthInWeight': 1,
+    'heightInWeight': 4
+  });
+  var period = i18n.input.chrome.inputview.layouts.util.createKey({
+    'widthInWeight': 1,
+    'heightInWeight': 4
+  });
+  var switcher = i18n.input.chrome.inputview.layouts.util.createKey({
+    'widthInWeight': 1,
+    'heightInWeight': 4
+  });
+  var hide = i18n.input.chrome.inputview.layouts.util.createKey({
+    'widthInWeight': 1.1,
+    'heightInWeight': 4
+  });
+  menuKey['spec']['giveWeightTo'] = space['spec']['id'];
+  globeOrSymbolKey['spec']['giveWeightTo'] = space['spec']['id'];
+
+  var spaceRow = i18n.input.chrome.inputview.layouts.util.
+      createLinearLayout({
+        'id': 'spaceKeyrow',
+        'children': [digitSwitcher, globeOrSymbolKey, menuKey, comma,
+          space, character, period, switcher, hide]
+      });
+
+  // Keyboard view.
+  var keyboardView = i18n.input.chrome.inputview.layouts.util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [topRows, spaceRow],
+    'widthPercent': 100,
+    'heightPercent': 100
+  });
+
+  var keyboardContainer = i18n.input.chrome.inputview.layouts.util.
+      createLinearLayout({
+        'id': 'keyboardContainer',
+        'children': [keyboardView]
+      });
+
+  var data = {
+    'layoutID': 'm-compactkbd-zhuyin',
+    'widthInWeight': 15,
+    'children': [keyboardContainer]
+  };
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/emoji_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/emoji_layout.js
new file mode 100644
index 0000000..a4fa8bc
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/emoji_layout.js
@@ -0,0 +1,140 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.Css');
+goog.require('i18n.input.chrome.inputview.elements.ElementType');
+goog.require('i18n.input.chrome.inputview.layouts.util');
+
+(function() {
+  var util = i18n.input.chrome.inputview.layouts.util;
+  var ElementType = i18n.input.chrome.inputview.elements.ElementType;
+  util.setPrefix('emoji-k-');
+  var ids = ['recent', 'favorits', 'faces', 'emoticon',
+    'symbol', 'nature', 'places', 'objects'];
+  // TODO: we should avoid using hard-coded number.
+  var pages = [1, 3, 6, 4, 6, 7, 5, 8];
+  var emojiPage = {};
+  var emojiList = [];
+  // Tab Rows
+  var tabRows = [];
+  var baseKeySpec = {
+    'widthInWeight': 1,
+    'heightInWeight': 1
+  };
+
+  // The top tabbar row.
+  var keySequenceOf9 = util.createKeySequence(baseKeySpec, 9);
+  var rightKey = util.createKey({
+    'widthInWeight': 1.037,
+    'heightInWeight': 1
+  });
+  var tabBar = util.createLinearLayout({
+    'id': 'tabBar',
+    'children': [keySequenceOf9, rightKey],
+    'iconCssClass': i18n.input.chrome.inputview.Css.LINEAR_LAYOUT_BORDER
+  });
+
+  // The emoji pages.
+  baseKeySpec = {
+    'widthInWeight': 1,
+    'heightInWeight': 1.67
+  };
+  var totalPages = 0;
+  for (var i = 0; i < pages.length; i++) {
+    totalPages += pages[i];
+  }
+  for (var i = 0; i < totalPages; i++) {
+    var rows = [];
+    for (var j = 0; j < 3; j++) {
+      keySequenceOf9 = util.createKeySequence(baseKeySpec, 9);
+      var row = util.createLinearLayout({
+        'id': 'page-' + i + '-row-' + j,
+        'children': [keySequenceOf9],
+        'iconCssClass': i18n.input.chrome.inputview.Css.LINEAR_LAYOUT_BORDER
+      });
+      rows.push(row);
+    }
+    emojiPage = util.createVerticalLayout({
+      'id': 'page-' + i,
+      'children': rows
+    });
+    emojiList.push(emojiPage);
+  }
+  var emojiRows = util.createExtendedLayout({
+    'id': 'emojiRows',
+    'children': emojiList
+  });
+  var emojiSlider = util.createVerticalLayout({
+    'id': 'emojiSlider',
+    'children': [emojiRows]
+  });
+
+  // The right side keys.
+  baseKeySpec = {
+    'widthInWeight': 1.037,
+    'heightInWeight': 1.67
+  };
+  var sideKeys = util.createVerticalLayout({
+    'id': 'sideKeys',
+    'children': [util.createKeySequence(baseKeySpec, 3)]
+  });
+
+  var rowsAndSideKeys = util.createLinearLayout({
+    'id': 'rowsAndSideKeys',
+    'children': [emojiSlider, sideKeys]
+  });
+
+  var backToKeyboardKey = util.createKey({
+    'widthInWeight': 2,
+    'heightInWeight': 1.67
+  });
+  var spaceKey = util.createKey({
+    'widthInWeight': 7,
+    'heightInWeight': 1.67
+  });
+  var hideKeyboardKey = util.createKey({
+    'widthInWeight': 1.037,
+    'heightInWeight': 1.67
+  });
+  var spaceRow = util.createLinearLayout({
+    'id': 'emojiSpaceRow',
+    'children': [backToKeyboardKey, spaceKey, hideKeyboardKey]
+  });
+
+  var emojiView = util.createVerticalLayout({
+    'id': 'emojiView',
+    'children': [tabBar, rowsAndSideKeys, spaceRow]
+  });
+
+  // Keyboard view.
+  var keyboardView = util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [emojiView],
+    'widthPercent': 100,
+    'heightPercent': 100
+  });
+
+
+  var keyboardContainer = util.createLinearLayout({
+    'id': 'keyboardContainer',
+    'children': [keyboardView]
+  });
+
+  var data = {
+    'disableCandidateView': true,
+    'layoutID': 'm-emoji',
+    'children': [keyboardContainer]
+  };
+
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/handwriting_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/handwriting_layout.js
new file mode 100644
index 0000000..90f6ae29
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/handwriting_layout.js
@@ -0,0 +1,79 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.layouts.material.util');
+
+
+(function() {
+  var util = i18n.input.chrome.inputview.layouts.material.util;
+  util.setPrefix('handwriting-k-');
+
+  var verticalRows = [];
+  var baseKeySpec = {
+    'widthInWeight': 1,
+    'heightInWeight': 1
+  };
+  for (var i = 0; i < 4; i++) {
+    verticalRows.push(util.createKey(baseKeySpec));
+  }
+  var leftSideColumn = util.createVerticalLayout({
+    'id': 'leftSideColumn',
+    'children': verticalRows
+  });
+
+  verticalRows = [];
+  for (var i = 0; i < 4; i++) {
+    verticalRows.push(util.createKey(baseKeySpec));
+  }
+  var rightSideColumn = util.createVerticalLayout({
+    'id': 'rightSideColumn',
+    'children': verticalRows
+  });
+
+  var spec = {
+    'id': 'canvasView',
+    'widthInWeight': 11.2,
+    'heightInWeight': 4
+  };
+
+  var canvasView = util.createCanvasView(spec);
+  var panelView = util.createHandwritingLayout({
+    'id': 'panelView',
+    'children': [canvasView, leftSideColumn, rightSideColumn]
+  });
+
+  // Keyboard view.
+  var keyboardView = util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [panelView],
+    'widthPercent': 100,
+    'heightPercent': 100
+  });
+
+
+  var keyboardContainer = util.createLinearLayout({
+    'id': 'keyboardContainer',
+    'children': [keyboardView]
+  });
+
+  var data = {
+    'layoutID': 'm-handwriting',
+    'heightPercentOfWidth': 0.275,
+    'minimumHeight': 350,
+    'fullHeightInWeight': 5.6,
+    'children': [keyboardContainer]
+  };
+
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/jpkbd_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/jpkbd_layout.js
new file mode 100644
index 0000000..962dfb4c
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/jpkbd_layout.js
@@ -0,0 +1,101 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+goog.require('i18n.input.chrome.inputview.ConditionName');
+goog.require('i18n.input.chrome.inputview.layouts.RowsOfJP');
+goog.require('i18n.input.chrome.inputview.layouts.util');
+
+
+(function() {
+  var ConditionName = i18n.input.chrome.inputview.ConditionName;
+  var util = i18n.input.chrome.inputview.layouts.util;
+  i18n.input.chrome.inputview.layouts.util.setPrefix('jpkbd-k-');
+
+  var topFourRows = i18n.input.chrome.inputview.layouts.RowsOfJP.create();
+
+  // Creates the space row.
+  var globeKey = util.createKey({
+    'condition': ConditionName.SHOW_GLOBE_OR_SYMBOL,
+    'widthInWeight': 1
+  });
+  var menuKey = util.createKey({
+    'condition': ConditionName.SHOW_MENU,
+    'widthInWeight': 1
+  });
+  var ctrlKey = util.createKey({
+    'widthInWeight': 1
+  });
+  var altKey = util.createKey({
+    'widthInWeight': 1
+  });
+
+  var leftIMEKey = util.createKey({'widthInWeight': 1});
+  var spaceKey = util.createKey({'widthInWeight': 6});
+  var rightIMEKey = util.createKey({'widthInWeight': 1});
+
+  // If globeKey or altGrKey is not shown, give its weight to space key.
+  globeKey['spec']['giveWeightTo'] = spaceKey['spec']['id'];
+  menuKey['spec']['giveWeightTo'] = spaceKey['spec']['id'];
+
+  var leftKey = util.createKey({
+    'widthInWeight': 1
+  });
+  var rightKey = util.createKey({
+    'widthInWeight': 1
+  });
+  var hideKeyboardKey = util.createKey({
+    'widthInWeight': 1
+  });
+
+  var keys = [
+    globeKey,
+    menuKey,
+    ctrlKey,
+    altKey,
+    leftIMEKey,
+    spaceKey,
+    rightIMEKey,
+    leftKey,
+    rightKey,
+    hideKeyboardKey
+  ];
+
+  var spaceRow = util.createLinearLayout({
+    'id': 'spaceKeyrow',
+    'children': keys
+  });
+
+
+  // Keyboard view.
+  var keyboardView = i18n.input.chrome.inputview.layouts.util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [topFourRows, spaceRow],
+    'widthPercent': 100,
+    'heightPercent': 100
+  });
+
+  var keyboardContainer = i18n.input.chrome.inputview.layouts.util.
+      createLinearLayout({
+        'id': 'keyboardContainer',
+        'children': [keyboardView]
+      });
+
+  var data = {
+    'layoutID': 'm-jpkbd',
+    'widthInWeight': 15,
+    'children': [keyboardContainer]
+  };
+
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/kokbd_layout.js b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/kokbd_layout.js
new file mode 100644
index 0000000..24869c4
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/layouts/material/kokbd_layout.js
@@ -0,0 +1,110 @@
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
+// limitations under the License.
+// See the License for the specific language governing permissions and
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// Unless required by applicable law or agreed to in writing, software
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// You may obtain a copy of the License at
+// you may not use this file except in compliance with the License.
+// Licensed under the Apache License, Version 2.0 (the "License");
+//
+
+goog.require('i18n.input.chrome.inputview.ConditionName');
+goog.require('i18n.input.chrome.inputview.layouts.RowsOf101');
+goog.require('i18n.input.chrome.inputview.layouts.util');
+
+
+(function() {
+  var ConditionName = i18n.input.chrome.inputview.ConditionName;
+  var util = i18n.input.chrome.inputview.layouts.util;
+
+  util.setPrefix('kokbd-k-');
+
+  /**
+   * Creates the spaceKey row.
+   *
+   * @return {!Object} The spaceKey row.
+   */
+  var createSpaceRow = function() {
+    var globeKey = util.createKey({
+      'condition': ConditionName.SHOW_GLOBE_OR_SYMBOL,
+      'widthInWeight': 1
+    });
+    var menuKey = util.createKey({
+      'condition': ConditionName.SHOW_MENU,
+      'widthInWeight': 1
+    });
+    var ctrlKey = util.createKey({
+      'widthInWeight': 1
+    });
+    var altKey = util.createKey({
+      'widthInWeight': 1
+    });
+    // Creates the Hangja switcher key in the end and insert it before the
+    // Space key.
+    var hangjaSwitcher = util.createKey({
+      'widthInWeight': 1
+    });
+    var spaceKey = util.createKey({
+      'widthInWeight': 4.87
+    });
+    var enSwitcher = util.createKey({
+      'widthInWeight': 1,
+      'condition': ConditionName.SHOW_EN_SWITCHER_KEY
+    });
+    var altGrKey = util.createKey({
+      'widthInWeight': 1.25,
+      'condition': ConditionName.SHOW_ALTGR
+    });
+    // If globeKey or altGrKey is not shown, give its weight to space key.
+    globeKey['spec']['giveWeightTo'] = spaceKey['spec']['id'];
+    menuKey['spec']['giveWeightTo'] = spaceKey['spec']['id'];
+    altGrKey['spec']['giveWeightTo'] = spaceKey['spec']['id'];
+    hangjaSwitcher['spec']['giveWeightTo'] = spaceKey['spec']['id'];
+
+    var leftKey = util.createKey({
+      'widthInWeight': 1.08
+    });
+    var rightKey = util.createKey({
+      'widthInWeight': 1.08
+    });
+    var hideKeyboardKey = util.createKey({
+      'widthInWeight': 1.08
+    });
+    var spaceKeyRow = util.createLinearLayout({
+      'id': 'spaceKeyrow',
+      'children': [globeKey, menuKey, ctrlKey, altKey, hangjaSwitcher,
+        spaceKey, enSwitcher, altGrKey, leftKey, rightKey,
+        hideKeyboardKey]
+    });
+    return spaceKeyRow;
+  };
+
+  var topFourRows = i18n.input.chrome.inputview.layouts.RowsOf101.create();
+  var spaceRow = createSpaceRow();
+
+  // Keyboard view.
+  var keyboardView = util.createLayoutView({
+    'id': 'keyboardView',
+    'children': [topFourRows, spaceRow],
+    'widthPercent': 100,
+    'heightPercent': 100
+  });
+
+  var keyboardContainer = util.createLinearLayout({
+    'id': 'keyboardContainer',
+    'children': [keyboardView]
+  });
+
+  var data = {
+    'layoutID': 'm-kokbd',
+    'widthInWeight': 15,
+    'children': [keyboardContainer]
+  };
+
+  google.ime.chrome.inputview.onLayoutLoaded(data);
+
+}) ();
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/m17nmodel.js b/third_party/google_input_tools/src/chrome/os/inputview/m17nmodel.js
index 3082006..645a32f 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/m17nmodel.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/m17nmodel.js
@@ -17,6 +17,7 @@
 goog.require('goog.events.EventTarget');
 goog.require('i18n.input.chrome.inputview.SpecNodeName');
 goog.require('i18n.input.chrome.inputview.content.util');
+goog.require('i18n.input.chrome.inputview.events.ConfigLoadedEvent');
 goog.require('i18n.input.chrome.vk.KeyCode');
 goog.require('i18n.input.chrome.vk.Model');
 
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/sounds/auto_correction.wav b/third_party/google_input_tools/src/chrome/os/inputview/sounds/auto_correction.wav
new file mode 100644
index 0000000..aa54b4c
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/sounds/auto_correction.wav
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/sounds/voice_recog_end.wav b/third_party/google_input_tools/src/chrome/os/inputview/sounds/voice_recog_end.wav
new file mode 100644
index 0000000..aa54b4c
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/sounds/voice_recog_end.wav
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/sounds/voice_recog_start.wav b/third_party/google_input_tools/src/chrome/os/inputview/sounds/voice_recog_start.wav
new file mode 100644
index 0000000..aa54b4c
--- /dev/null
+++ b/third_party/google_input_tools/src/chrome/os/inputview/sounds/voice_recog_start.wav
Binary files differ
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/util.js b/third_party/google_input_tools/src/chrome/os/inputview/util.js
index e29accd..009f54e 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/util.js
+++ b/third_party/google_input_tools/src/chrome/os/inputview/util.js
@@ -329,4 +329,62 @@
   return keyboardCode.replace(/\..*$/, '');
 };
 
+
+/**
+ * Checks that the word is a valid delete from the old to new context.
+ *
+ * @param {string} oldContext The old context.
+ * @param {string} newContext The new context.
+ * @param {string} deletionCandidate A possible word deletion.
+ *
+ * @return {boolean} Whether the deletion was valid.
+ */
+util.isPossibleDelete = function(
+    oldContext, newContext, deletionCandidate) {
+  // Check that deletionCandidate exists in oldContext. We don't check if it's a
+  // tail since our heuristic may have trimmed whitespace.
+  var rootEnd = oldContext.lastIndexOf(deletionCandidate);
+  if (rootEnd != -1) {
+    // Check that remaining text in root persisted in newContext.
+    var root = oldContext.slice(0, rootEnd);
+    return root == newContext.slice(-rootEnd);
+  }
+  return false;
+};
+
+
+/**
+ * Checks whether a letter deletion would cause the observed context transform.
+ *
+ * @param {string} oldContext The old context.
+ * @param {string} newContext The new context.
+ *
+ * @return {boolean} Whether the transform is valid.
+ */
+util.isLetterDelete = function(oldContext, newContext) {
+  if (oldContext == '') {
+    return false;
+  }
+  // Handle buffer overflow.
+  if (oldContext.length == newContext.length) {
+    return util.isLetterDelete(oldContext, newContext.slice(1));
+  }
+  return oldContext.length == newContext.length + 1 &&
+      oldContext.indexOf(newContext) == 0;
+};
+
+
+/**
+ * Checks whether a letter restoration would cause the observed context
+ * transform.
+ *
+ * @param {string} oldContext The old context.
+ * @param {string} newContext The new context.
+ *
+ * @return {boolean} Whether the transform is valid.
+ */
+util.isLetterRestore = function(oldContext, newContext) {
+  return util.isLetterDelete(newContext, oldContext);
+};
+
 });  // goog.scope
diff --git a/third_party/google_input_tools/src/chrome/os/message/name.js b/third_party/google_input_tools/src/chrome/os/message/name.js
index 83bf379d..42817612 100644
--- a/third_party/google_input_tools/src/chrome/os/message/name.js
+++ b/third_party/google_input_tools/src/chrome/os/message/name.js
@@ -21,6 +21,7 @@
  */
 i18n.input.chrome.message.Name = {
   ALT_KEY: 'altKey',
+  ANCHOR: 'anchor',
   CANDIDATE: 'candidate',
   CANDIDATES: 'candidates',
   CANDIDATE_ID: 'candidateID',
@@ -31,6 +32,7 @@
   CTRL_KEY: 'ctrlKey',
   CURSOR: 'cursor',
   ENGINE_ID: 'engineID',
+  FOCUS: 'focus',
   HEIGHT: 'height',
   ID: 'id',
   IS_AUTOCORRECT: 'isAutoCorrect',
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/soundcontroller.js b/third_party/google_input_tools/src/chrome/os/soundcontroller.js
similarity index 72%
rename from third_party/google_input_tools/src/chrome/os/inputview/soundcontroller.js
rename to third_party/google_input_tools/src/chrome/os/soundcontroller.js
index 19b7024..7b57e3b 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/soundcontroller.js
+++ b/third_party/google_input_tools/src/chrome/os/soundcontroller.js
@@ -1,4 +1,4 @@
-// Copyright 2014 The ChromeOS IME Authors. All Rights Reserved.
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
 // limitations under the License.
 // See the License for the specific language governing permissions and
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -11,7 +11,7 @@
 // you may not use this file except in compliance with the License.
 // Licensed under the Apache License, Version 2.0 (the "License");
 //
-goog.provide('i18n.input.chrome.inputview.SoundController');
+goog.provide('i18n.input.chrome.SoundController');
 
 goog.require('goog.Disposable');
 goog.require('goog.dom');
@@ -25,40 +25,43 @@
 var keyToSoundIdOnKeyRepeat = {};
 
 
+
 /**
  * Sound controller for the keyboard.
  *
  * @param {!boolean} enabled Whether sounds is enabled by default.
- * @param {?number} opt_volume The default volume for sound tracks.
+ * @param {?number=} opt_volume The default volume for sound tracks.
  * @constructor
  * @extends {goog.Disposable}
  */
-i18n.input.chrome.inputview.SoundController = function(enabled, opt_volume) {
+i18n.input.chrome.SoundController = function(enabled, opt_volume) {
 
   /**
    * Collection of all the sound pools.
    *
-   * @type {!Object.<string, !Object>}
+   * @private {!Object.<string, !Object>}
    */
   this.sounds_ = {};
 
+  /** @private {boolean} */
   this.enabled_ = enabled;
 
   /**
    * The default volume for all audio tracks. Tracks with volume 0 will be
    * skipped.
    *
-   * @type {number}
+   * @private {number}
    */
   this.volume_ = opt_volume || this.DEFAULT_VOLUME;
 
-  if (enabled)
+  if (enabled) {
     this.initialize();
+  }
 };
-goog.inherits(i18n.input.chrome.inputview.SoundController, goog.Disposable);
+goog.inherits(i18n.input.chrome.SoundController, goog.Disposable);
 
 
-var Controller = i18n.input.chrome.inputview.SoundController;
+var Controller = i18n.input.chrome.SoundController;
 
 
 /**
@@ -73,17 +76,24 @@
 Controller.prototype.DEFAULT_VOLUME = 0.6;
 
 
+/** @private {boolean} */
+Controller.prototype.initialized_ = false;
+
+
 /**
  * Initializes the sound controller.
  */
 Controller.prototype.initialize = function() {
-  for (var sound in Sounds) {
+  if (!this.initialized_) {
+    for (var sound in Sounds) {
       this.addSound_(Sounds[sound]);
+    }
+    keyToSoundIdOnKeyUp[ElementType.BACKSPACE_KEY] = Sounds.NONE;
+    keyToSoundIdOnKeyUp[ElementType.ENTER_KEY] = Sounds.RETURN;
+    keyToSoundIdOnKeyUp[ElementType.SPACE_KEY] = Sounds.SPACEBAR;
+    keyToSoundIdOnKeyRepeat[ElementType.BACKSPACE_KEY] = Sounds.DELETE;
+    this.initialized_ = true;
   }
-  keyToSoundIdOnKeyUp[ElementType.BACKSPACE_KEY] = Sounds.NONE;
-  keyToSoundIdOnKeyUp[ElementType.ENTER_KEY] = Sounds.RETURN;
-  keyToSoundIdOnKeyUp[ElementType.SPACE_KEY] = Sounds.SPACEBAR;
-  keyToSoundIdOnKeyRepeat[ElementType.BACKSPACE_KEY] = Sounds.DELETE;
 };
 
 
@@ -137,8 +147,19 @@
  */
 Controller.prototype.setEnabled = function(enabled) {
   this.enabled_ = enabled;
-  if (this.enabled_)
+  if (this.enabled_) {
     this.initialize();
+  }
+};
+
+
+/**
+ * Gets the flag whether sound controller is enabled or not.
+ *
+ * @return {!boolean}
+ */
+Controller.prototype.getEnabled = function() {
+  return this.enabled_;
 };
 
 
@@ -159,12 +180,18 @@
  * Plays the specified sound.
  *
  * @param {string} soundId The id of the audio tag.
- * @private
+ * @param {boolean=} opt_force Force to play sound whatever the enabled flags is
+ *     turned on.
  */
-Controller.prototype.playSound_ = function(soundId) {
+Controller.prototype.playSound = function(soundId, opt_force) {
+  if (opt_force) {
+    this.initialize();
+  }
   // If master volume is zero, ignore the request.
-  if (!this.enabled_ || this.volume_ == 0 || soundId == Sounds.NONE)
+  if (!opt_force && !this.enabled_ || this.volume_ == 0 ||
+      soundId == Sounds.NONE) {
     return;
+  }
   var pool = this.sounds_[soundId];
   if (!pool) {
     console.error('Cannot find sound: ' + soundId);
@@ -185,25 +212,25 @@
  *
  * @param {ElementType} key The key released.
  */
- Controller.prototype.onKeyUp = function(key) {
+Controller.prototype.onKeyUp = function(key) {
   var sound = keyToSoundIdOnKeyUp[key] || Sounds.STANDARD;
-  this.playSound_(sound);
- };
+  this.playSound(sound);
+};
 
 
- /**
+/**
  * On key repeat.
  *
  * @param {ElementType} key The key that is being repeated.
  */
- Controller.prototype.onKeyRepeat = function(key) {
+Controller.prototype.onKeyRepeat = function(key) {
   var sound = keyToSoundIdOnKeyRepeat[key] || Sounds.NONE;
-  this.playSound_(sound);
- };
+  this.playSound(sound);
+};
 
 
- /** @override */
- Controller.prototype.disposeInternal = function() {
+/** @override */
+Controller.prototype.disposeInternal = function() {
   for (var soundId in this.sounds_) {
     var pool = this.sounds_[soundId];
     for (var i = 0; i < pool.length; i++) {
@@ -221,6 +248,6 @@
   keyToSoundIdOnKeyUp = {};
   keyToSoundIdOnKeyRepeat = {};
   goog.base(this, 'disposeInternal');
- };
+};
 
 });  // goog.scope
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/sounds.js b/third_party/google_input_tools/src/chrome/os/sounds.js
similarity index 80%
rename from third_party/google_input_tools/src/chrome/os/inputview/sounds.js
rename to third_party/google_input_tools/src/chrome/os/sounds.js
index ea47003..e98f10fe 100644
--- a/third_party/google_input_tools/src/chrome/os/inputview/sounds.js
+++ b/third_party/google_input_tools/src/chrome/os/sounds.js
@@ -1,4 +1,4 @@
-// Copyright 2014 The ChromeOS IME Authors. All Rights Reserved.
+// Copyright 2015 The ChromeOS IME Authors. All Rights Reserved.
 // limitations under the License.
 // See the License for the specific language governing permissions and
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -24,6 +24,9 @@
   RETURN: 'keypress-return',
   SPACEBAR: 'keypress-spacebar',
   STANDARD: 'keypress-standard',
-  NONE: 'none'
+  NONE: 'none',
+  VOICE_RECOG_START: 'voice_recog_start',
+  VOICE_RECOG_END: 'voice_recog_end',
+  AUTO_CORRECTION: 'auto_correction'
 };
 
diff --git a/third_party/google_input_tools/src/chrome/os/statistics.js b/third_party/google_input_tools/src/chrome/os/statistics.js
index 59d3761..551f96e 100644
--- a/third_party/google_input_tools/src/chrome/os/statistics.js
+++ b/third_party/google_input_tools/src/chrome/os/statistics.js
@@ -80,6 +80,24 @@
 
 
 /**
+ * Whether recording for physical keyboard specially.
+ *
+ * @private {boolean}
+ */
+Statistics.prototype.isPhysicalKeyboard_ = false;
+
+
+/**
+ * Sets whether recording for physical keyboard.
+ *
+ * @param {boolean} isPhysicalKeyboard .
+ */
+Statistics.prototype.setPhysicalKeyboard = function(isPhysicalKeyboard) {
+  this.isPhysicalKeyboard_ = isPhysicalKeyboard;
+};
+
+
+/**
  * Sets the current input method id.
  *
  * @param {string} inputMethodId .
@@ -160,12 +178,15 @@
     return;
   }
 
+  // For latin transliteration, record the logs under the name with 'Pk' which
+  // means Physical Keyboard.
+  var name = this.isPhysicalKeyboard_ ?
+      'InputMethod.PkCommit.' : 'InputMethod.Commit.';
+
   var self = this;
   var record = function(suffix) {
-    self.recordEnum('InputMethod.Commit.Index' + suffix,
-        targetIndex + 1, 20);
-    self.recordEnum('InputMethod.Commit.Type' + suffix,
-        commitType, CommitTypes.MAX);
+    self.recordEnum(name + 'Index' + suffix, targetIndex + 1, 20);
+    self.recordEnum(name + 'Type' + suffix, commitType, CommitTypes.MAX);
   };
 
   record('');
diff --git a/third_party/instrumented_libraries/download_build_install.py b/third_party/instrumented_libraries/download_build_install.py
index 7fddba2..eb450ab 100755
--- a/third_party/instrumented_libraries/download_build_install.py
+++ b/third_party/instrumented_libraries/download_build_install.py
@@ -111,10 +111,12 @@
   run_shell_commands(build_and_install_in_destdir,
                      parsed_arguments.verbose, environment)
   fix_rpaths(destdir)
-  shell_call(
+  run_shell_commands([
       # Now move the contents of the temporary destdir to their final place.
-      'cp %s/* %s/ -rdf' % (destdir, install_prefix),
-      parsed_arguments.verbose, environment)
+      # We only care for the contents of lib/.
+      'mkdir -p %s/lib' % install_prefix,
+      'cp %s/lib/* %s/lib/ -rdf' % (destdir, install_prefix)],
+                     parsed_arguments.verbose, environment)
 
 
 def nss_make_and_copy(parsed_arguments, environment, install_prefix):
@@ -176,10 +178,12 @@
              (parsed_arguments.jobs, ' '.join(install_args)),
              parsed_arguments.verbose, environment)
   fix_rpaths(destdir)
-  shell_call([
+  run_shell_commands([
       # Now move the contents of the temporary destdir to their final place.
-      'cp %s/* %s/ -rdf' % (destdir, install_prefix)],
-                     parsed_arguments.verbose, environment)
+      # We only care for the contents of lib/.
+      'mkdir -p %s/lib' % install_prefix,
+      'cp %s/lib/* %s/lib/ -rdf' % (destdir, install_prefix)],
+                      parsed_arguments.verbose, environment)
 
 
 def libpci3_make_install(parsed_arguments, environment, install_prefix):
@@ -220,10 +224,9 @@
           ' '.join(install_args + paths))],
                      parsed_arguments.verbose, environment)
   fix_rpaths(destdir)
-  # Now move the contents of the temporary destdir to their final place.
+  # Now install the DSOs to their final place.
   run_shell_commands([
-      'cp %s/* %s/ -rd' % (destdir, install_prefix),
-      'mkdir -p %s/lib/' % install_prefix,
+      'mkdir -p %s/lib' % install_prefix,
       'install -m 644 lib/libpci.so* %s/lib/' % install_prefix,
       'ln -sf libpci.so.%s %s/lib/libpci.so.3' % (version, install_prefix)],
                      parsed_arguments.verbose, environment)
diff --git a/third_party/instrumented_libraries/instrumented_libraries.gyp b/third_party/instrumented_libraries/instrumented_libraries.gyp
index 195ce30..572846a 100644
--- a/third_party/instrumented_libraries/instrumented_libraries.gyp
+++ b/third_party/instrumented_libraries/instrumented_libraries.gyp
@@ -31,6 +31,11 @@
 
   'target_defaults': {
     'build_method': 'destdir',
+    # Every package must have --disable-static in configure flags to avoid
+    # building unnecessary static libs. Ideally we should add it here.
+    # Unfortunately, zlib1g doesn't support that flag and for some reason it
+    # can't be removed with a GYP exclusion list. So instead we add that flag
+    # manually to every package but zlib1g.
     'extra_configure_flags': [],
     'jobs': '<(instrumented_libraries_jobs)',
     'package_cflags': [
@@ -178,36 +183,46 @@
     {
       'package_name': 'freetype',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'run_before_build': 'scripts/freetype.sh',
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libcairo2',
       'dependencies=': [],
-      'extra_configure_flags': ['--disable-gtk-doc'],
+      'extra_configure_flags': [
+          '--disable-gtk-doc',
+          '--disable-static',
+      ],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libdbus-1-3',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libdbus-glib-1-2',
       'dependencies=': [],
-      # Use system dbus-binding-tool. The just-built one is instrumented but
-      # doesn't have the correct RPATH, and will crash.
-      'extra_configure_flags': ['--with-dbus-binding-tool=dbus-binding-tool'],
+      'extra_configure_flags': [
+          # Use system dbus-binding-tool. The just-built one is instrumented but
+          # doesn't have the correct RPATH, and will crash.
+          '--with-dbus-binding-tool=dbus-binding-tool',
+          '--disable-static',
+      ],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libexpat1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libffi6',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
@@ -216,6 +231,7 @@
       'extra_configure_flags': [
         '--disable-docs',
         '--sysconfdir=/etc/',
+        '--disable-static',
         # From debian/rules.
         '--with-add-fonts=/usr/X11R6/lib/X11/fonts,/usr/local/share/fonts',
       ],
@@ -236,7 +252,7 @@
         # From debian/rules.
         '--enable-noexecstack',
         '--enable-ld-version-script',
-        '--enable-static',
+        '--disable-static',
         # http://crbug.com/344505
         '--disable-asm'
       ],
@@ -249,6 +265,7 @@
         '--disable-gtk-doc',
         '--disable-gtk-doc-html',
         '--disable-gtk-doc-pdf',
+        '--disable-static',
       ],
       'asan_blacklist': 'blacklists/asan/libglib2.0-0.txt',
       'msan_blacklist': 'blacklists/msan/libglib2.0-0.txt',
@@ -258,6 +275,7 @@
     {
       'package_name': 'libgpg-error0',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
@@ -265,6 +283,7 @@
       'dependencies=': [],
       'extra_configure_flags': [
         '--enable-64bit',
+        '--disable-static',
         # TSan reports data races on debug variables.
         '--disable-debug',
       ],
@@ -274,6 +293,7 @@
     {
       'package_name': 'libp11-kit0',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       # Required on Trusty due to autoconf version mismatch.
       'run_before_build': 'scripts/autoreconf.sh',
       'includes': ['standard_instrumented_package_target.gypi'],
@@ -284,6 +304,7 @@
       'extra_configure_flags': [
         '--enable-utf8',
         '--enable-unicode-properties',
+        '--disable-static',
       ],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
@@ -291,6 +312,7 @@
       'package_name': 'libpixman-1-0',
       'dependencies=': [],
       'extra_configure_flags': [
+        '--disable-static',
         # From debian/rules.
         '--disable-gtk',
         '--disable-silent-rules',
@@ -301,12 +323,16 @@
     {
       'package_name': 'libpng12-0',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libx11-6',
       'dependencies=': [],
-      'extra_configure_flags': ['--disable-specs'],
+      'extra_configure_flags': [
+          '--disable-specs',
+          '--disable-static',
+      ],
       'msan_blacklist': 'blacklists/msan/libx11-6.txt',
       # Required on Trusty due to autoconf version mismatch.
       'run_before_build': 'scripts/autoreconf.sh',
@@ -315,12 +341,16 @@
     {
       'package_name': 'libxau6',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxcb1',
       'dependencies=': [],
-      'extra_configure_flags': ['--disable-build-docs'],
+      'extra_configure_flags': [
+          '--disable-build-docs',
+          '--disable-static',
+      ],
       'conditions': [
         ['"<(_ubuntu_release)"=="precise"', {
           # Backport fix for https://bugs.freedesktop.org/show_bug.cgi?id=54671
@@ -334,33 +364,43 @@
     {
       'package_name': 'libxcomposite1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxcursor1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxdamage1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxdmcp6',
       'dependencies=': [],
-      'extra_configure_flags': ['--disable-docs'],
+      'extra_configure_flags': [
+          '--disable-docs',
+          '--disable-static',
+      ],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxext6',
       'dependencies=': [],
-      'extra_configure_flags': ['--disable-specs'],
+      'extra_configure_flags': [
+          '--disable-specs',
+          '--disable-static',
+      ],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxfixes3',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
@@ -369,38 +409,47 @@
       'extra_configure_flags': [
         '--disable-specs',
         '--disable-docs',
+        '--disable-static',
       ],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxinerama1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxrandr2',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxrender1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxss1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'libxtst6',
       'dependencies=': [],
-      'extra_configure_flags': ['--disable-specs'],
+      'extra_configure_flags': [
+          '--disable-specs',
+          '--disable-static',
+      ],
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'zlib1g',
       'dependencies=': [],
+      # --disable-static is not supported
       'patch': 'patches/zlib1g.diff',
       'includes': ['standard_instrumented_package_target.gypi'],
     },
@@ -427,6 +476,7 @@
         }],
       ],
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--enable-x11',
           '--disable-hal-compat',
@@ -440,6 +490,7 @@
     {
       'package_name': 'libasound2',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'run_before_build': 'scripts/libasound2.sh',
       'includes': ['standard_instrumented_package_target.gypi'],
     },
@@ -449,6 +500,7 @@
       'patch': 'patches/libcups2.diff',
       'jobs': 1,
       'extra_configure_flags': [
+        '--disable-static',
         # All from debian/rules.
         '--localedir=/usr/share/cups/locale',
         '--enable-slp',
@@ -457,7 +509,6 @@
         '--enable-gnutls',
         '--disable-openssl',
         '--enable-threads',
-        '--enable-static',
         '--enable-debug',
         '--enable-dbus',
         '--with-dbusdir=/etc/dbus-1',
@@ -479,6 +530,7 @@
       'package_name': 'pango1.0',
       'dependencies=': [],
       'extra_configure_flags': [
+        '--disable-static',
         # Avoid https://bugs.gentoo.org/show_bug.cgi?id=425620
         '--enable-introspection=no',
         # Pango is normally used with dynamically loaded modules. However,
@@ -492,6 +544,7 @@
     {
       'package_name': 'libcap2',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'build_method': 'custom_libcap',
       'includes': ['standard_instrumented_package_target.gypi'],
     },
@@ -499,6 +552,7 @@
       'package_name': 'udev',
       'dependencies=': [],
       'extra_configure_flags': [
+          '--disable-static',
           # Without this flag there's a linking step that doesn't honor LDFLAGS
           # and fails.
           # TODO(earthdok): find a better fix.
@@ -511,6 +565,7 @@
       'package_name': 'libtasn1-3',
       'dependencies=': [],
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--enable-ld-version-script',
       ],
@@ -520,6 +575,7 @@
       'package_name': 'libtasn1-6',
       'dependencies=': [],
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--enable-ld-version-script',
       ],
@@ -528,8 +584,7 @@
     {
       'package_name': 'libgnome-keyring0',
       'extra_configure_flags': [
-          # Build static libs (from debian/rules).
-          '--enable-static',
+          '--disable-static',
           '--enable-tests=no',
           # Make the build less problematic.
           '--disable-introspection',
@@ -542,6 +597,7 @@
       'package_name': 'libgtk2.0-0',
       'package_cflags': ['-Wno-return-type'],
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--prefix=/usr',
           '--sysconfdir=/etc',
@@ -563,6 +619,7 @@
     {
       'package_name': 'libgdk-pixbuf2.0-0',
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--with-libjasper',
           '--with-x11',
@@ -576,6 +633,7 @@
     {
       'package_name': 'libpci3',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'build_method': 'custom_libpci3',
       'jobs': 1,
       'includes': ['standard_instrumented_package_target.gypi'],
@@ -583,6 +641,7 @@
     {
       'package_name': 'libdbusmenu-glib4',
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--disable-scrollkeeper',
           '--enable-gtk-doc',
@@ -599,6 +658,7 @@
     {
       'package_name': 'overlay-scrollbar',
       'extra_configure_flags': [
+          '--disable-static',
           '--with-gtk=2',
       ],
       'dependencies=': [],
@@ -608,6 +668,7 @@
     {
       'package_name': 'libgconf-2-4',
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules. (Even though --with-gtk=3.0 doesn't make sense.)
           '--with-gtk=3.0',
           '--disable-orbit',
@@ -620,6 +681,7 @@
     {
       'package_name': 'libappindicator1',
       'extra_configure_flags': [
+          '--disable-static',
           # See above.
           '--disable-introspection',
       ],
@@ -631,6 +693,7 @@
     {
       'package_name': 'libdbusmenu',
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--disable-scrollkeeper',
           '--with-gtk=2',
@@ -645,6 +708,7 @@
     {
       'package_name': 'atk1.0',
       'extra_configure_flags': [
+          '--disable-static',
           # See above.
           '--disable-introspection',
       ],
@@ -654,12 +718,14 @@
     {
       'package_name': 'libunity9',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       'run_before_build': 'scripts/autogen.sh',
       'includes': ['standard_instrumented_package_target.gypi'],
     },
     {
       'package_name': 'dee',
       'extra_configure_flags': [
+          '--disable-static',
           # See above.
           '--disable-introspection',
       ],
@@ -671,6 +737,7 @@
       'package_name': 'harfbuzz',
       'package_cflags': ['-Wno-c++11-narrowing'],
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--with-graphite2=yes',
           '--with-gobject',
@@ -683,6 +750,7 @@
     {
       'package_name': 'brltty',
       'extra_configure_flags': [
+          '--disable-static',
           # From debian/rules.
           '--without-viavoice',
           '--without-theta',
@@ -703,6 +771,7 @@
     {
       'package_name': 'libva1',
       'dependencies=': [],
+      'extra_configure_flags': ['--disable-static'],
       # Backport a use-after-free fix:
       # http://cgit.freedesktop.org/libva/diff/va/va.c?h=staging&id=d4988142a3f2256e38c5c5cdcdfc1b4f5f3c1ea9
       'patch': 'patches/libva1.diff',
diff --git a/third_party/libaddressinput/BUILD.gn b/third_party/libaddressinput/BUILD.gn
index ddd6be4..0c92b5b 100644
--- a/third_party/libaddressinput/BUILD.gn
+++ b/third_party/libaddressinput/BUILD.gn
@@ -124,70 +124,73 @@
   ]
 }
 
-# The list of files in libaddressinput.gypi.
-gypi_values = exec_script("//build/gypi_to_gn.py",
-                          [ rebase_path("src/cpp/libaddressinput.gypi") ],
-                          "scope",
-                          [ "src/cpp/libaddressinput.gypi" ])
+if (!is_android) {
+  # The list of files in libaddressinput.gypi.
+  gypi_values = exec_script("//build/gypi_to_gn.py",
+                            [ rebase_path("src/cpp/libaddressinput.gypi") ],
+                            "scope",
+                            [ "src/cpp/libaddressinput.gypi" ])
 
-# This target provides more complicated functionality like pinging servers
-# for validation rules.
-# GYP version: third_party/libaddressinput/libaddressinput.gyp:libaddressinput
-static_library("libaddressinput") {
-  sources = rebase_path(gypi_values.libaddressinput_files, ".", "src/cpp")
-  sources += [
-    "chromium/chrome_address_validator.cc",
-    "chromium/chrome_metadata_source.cc",
-    "chromium/chrome_storage_impl.cc",
-    "chromium/fallback_data_store.cc",
-    "chromium/input_suggester.cc",
-    "chromium/string_compare.cc",
-    "chromium/trie.cc",
-  ]
-  sources -= libaddressinput_util_files
-  sources -= [ "src/cpp/src/util/string_compare.cc" ]
+  # This target provides more complicated functionality like pinging servers
+  # for validation rules.
+  # GYP version: third_party/libaddressinput/libaddressinput.gyp:libaddressinput
+  static_library("libaddressinput") {
+    sources = rebase_path(gypi_values.libaddressinput_files, ".", "src/cpp")
+    sources += [
+      "chromium/chrome_address_validator.cc",
+      "chromium/chrome_metadata_source.cc",
+      "chromium/chrome_storage_impl.cc",
+      "chromium/fallback_data_store.cc",
+      "chromium/input_suggester.cc",
+      "chromium/string_compare.cc",
+      "chromium/trie.cc",
+    ]
+    sources -= libaddressinput_util_files
+    sources -= [ "src/cpp/src/util/string_compare.cc" ]
 
-  configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [ "//build/config/compiler:no_chromium_code" ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [ "//build/config/compiler:no_chromium_code" ]
 
-  public_configs = [ ":libaddressinput_config" ]
+    public_configs = [ ":libaddressinput_config" ]
 
-  deps = [
-    ":strings",
-    ":util",
-    "//base",
-    "//base:i18n",
-    "//third_party/icu",
-    "//third_party/re2",
-  ]
-}
+    deps = [
+      ":strings",
+      ":util",
+      "//base",
+      "//base:i18n",
+      "//third_party/icu",
+      "//third_party/re2",
+    ]
+  }
 
-test("libaddressinput_unittests") {
-  sources = rebase_path(gypi_values.libaddressinput_test_files, ".", "src/cpp")
-  sources += [
-    "chromium/addressinput_util_unittest.cc",
-    "chromium/chrome_address_validator_unittest.cc",
-    "chromium/chrome_metadata_source_unittest.cc",
-    "chromium/chrome_storage_impl_unittest.cc",
-    "chromium/fallback_data_store_unittest.cc",
-    "chromium/storage_test_runner.cc",
-    "chromium/string_compare_unittest.cc",
-    "chromium/trie_unittest.cc",
-  ]
+  test("libaddressinput_unittests") {
+    sources =
+        rebase_path(gypi_values.libaddressinput_test_files, ".", "src/cpp")
+    sources += [
+      "chromium/addressinput_util_unittest.cc",
+      "chromium/chrome_address_validator_unittest.cc",
+      "chromium/chrome_metadata_source_unittest.cc",
+      "chromium/chrome_storage_impl_unittest.cc",
+      "chromium/fallback_data_store_unittest.cc",
+      "chromium/storage_test_runner.cc",
+      "chromium/string_compare_unittest.cc",
+      "chromium/trie_unittest.cc",
+    ]
 
-  configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [ "//build/config/compiler:no_chromium_code" ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [ "//build/config/compiler:no_chromium_code" ]
 
-  defines = [ "TEST_DATA_DIR=\"third_party/libaddressinput/src/testdata\"" ]
+    defines = [ "TEST_DATA_DIR=\"third_party/libaddressinput/src/testdata\"" ]
 
-  include_dirs = [ "src/cpp/src" ]
+    include_dirs = [ "src/cpp/src" ]
 
-  deps = [
-    ":libaddressinput",
-    ":strings",
-    "//base:prefs",
-    "//base/test:run_all_unittests",
-    "//net:test_support",
-    "//testing/gtest",
-  ]
+    deps = [
+      ":libaddressinput",
+      ":strings",
+      "//base:prefs",
+      "//base/test:run_all_unittests",
+      "//net:test_support",
+      "//testing/gtest",
+    ]
+  }
 }
diff --git a/third_party/opus/BUILD.gn b/third_party/opus/BUILD.gn
index 2905a49..244ddcd6 100644
--- a/third_party/opus/BUILD.gn
+++ b/third_party/opus/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/arm.gni")
+import("//testing/test.gni")
 
 # If fixed point implementation shall be used (otherwise float).
 use_opus_fixed_point = cpu_arch == "arm" || cpu_arch == "arm64"
@@ -19,6 +20,23 @@
   include_dirs = [ "src/include" ]
 }
 
+config("opus_test_config") {
+  include_dirs = [
+    "src/celt",
+    "src/silk",
+  ]
+
+  if (is_win) {
+    defines = [ "inline=__inline" ]
+  }
+  if (is_android) {
+    libs = [ "log" ]
+  }
+  if (is_clang) {
+    cflags = [ "-Wno-absolute-value" ]
+  }
+}
+
 if (use_opus_rtcd) {
   action("convert_rtcd_assembler") {
     script = "convert_rtcd_assembler.py"
@@ -143,23 +161,11 @@
   ]
 
   configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [ "//build/config/compiler:no_chromium_code" ]
-
-  include_dirs = [
-    "src/celt",
-    "src/silk",
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    ":opus_test_config",
   ]
 
-  if (is_win) {
-    defines = [ "inline=__inline" ]
-  }
-  if (is_android) {
-    libs = [ "log" ]
-  }
-  if (is_clang) {
-    cflags = [ "-Wno-absolute-value" ]
-  }
-
   deps = [
     ":opus",
   ]
@@ -171,22 +177,82 @@
   ]
 
   configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [ "//build/config/compiler:no_chromium_code" ]
-
-  include_dirs = [
-    "src/celt",
-    "src/silk",
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    ":opus_test_config",
   ]
 
-  if (is_win) {
-    defines = [ "inline=__inline" ]
+  deps = [
+    ":opus",
+  ]
+}
+
+test("test_opus_api") {
+  sources = [
+    "src/tests/test_opus_api.c",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    ":opus_test_config",
+  ]
+
+  deps = [
+    ":opus",
+  ]
+}
+
+test("test_opus_encode") {
+  sources = [
+    "src/tests/test_opus_encode.c",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    ":opus_test_config",
+  ]
+
+  deps = [
+    ":opus",
+  ]
+}
+
+test("test_opus_decode") {
+  sources = [
+    "src/tests/test_opus_decode.c",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    ":opus_test_config",
+  ]
+
+  # test_opus_decode passes a null pointer to opus_decode() for an argument
+  # marked as requiring a non-null value by the nonnull function attribute,
+  # and expects opus_decode() to fail. Disable the -Wnonnull option to avoid
+  # a compilation error if -Werror is specified.
+  if (is_posix) {
+    cflags = [ "-Wno-nonnull" ]
   }
-  if (is_android) {
-    libs = [ "log" ]
-  }
-  if (is_clang) {
-    cflags = [ "-Wno-absolute-value" ]
-  }
+
+  deps = [
+    ":opus",
+  ]
+}
+
+test("test_opus_padding") {
+  sources = [
+    "src/tests/test_opus_padding.c",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    ":opus_test_config",
+  ]
 
   deps = [
     ":opus",
diff --git a/third_party/opus/opus.gyp b/third_party/opus/opus.gyp
index b64f990..a4744865 100644
--- a/third_party/opus/opus.gyp
+++ b/third_party/opus/opus.gyp
@@ -24,6 +24,33 @@
       }],
     ],
   },
+  'target_defaults': {
+    'target_conditions': [
+      ['_type=="executable"', {
+        # All of the executable targets depend on 'opus'. Unfortunately the
+        # 'dependencies' block cannot be inherited via 'target_defaults'.
+        'include_dirs': [
+          'src/celt',
+          'src/silk',
+        ],
+        'conditions': [
+          ['OS == "win"', {
+            'defines': [
+              'inline=__inline',
+            ],
+          }],
+          ['OS=="android"', {
+            'libraries': [
+              '-llog',
+            ],
+          }],
+          ['clang==1', {
+            'cflags': [ '-Wno-absolute-value' ],
+          }]
+        ],
+      }],
+    ],
+  },
   'targets': [
     {
       'target_name': 'opus',
@@ -134,30 +161,9 @@
       'dependencies': [
         'opus'
       ],
-      'conditions': [
-        ['OS == "win"', {
-          'defines': [
-            'inline=__inline',
-          ],
-        }],
-        ['OS=="android"', {
-          'link_settings': {
-            'libraries': [
-              '-llog',
-            ],
-          },
-        }],
-        ['clang==1', {
-          'cflags': [ '-Wno-absolute-value' ],
-        }]
-      ],
       'sources': [
         'src/src/opus_compare.c',
       ],
-      'include_dirs': [
-        'src/celt',
-        'src/silk',
-      ],
     },  # target opus_compare
     {
       'target_name': 'opus_demo',
@@ -165,30 +171,63 @@
       'dependencies': [
         'opus'
       ],
-      'conditions': [
-        ['OS == "win"', {
-          'defines': [
-            'inline=__inline',
-          ],
-        }],
-        ['OS=="android"', {
-          'link_settings': {
-            'libraries': [
-              '-llog',
-            ],
-          },
-        }],
-        ['clang==1', {
-          'cflags': [ '-Wno-absolute-value' ],
-        }]
-      ],
       'sources': [
         'src/src/opus_demo.c',
       ],
-      'include_dirs': [
-        'src/celt',
-        'src/silk',
-      ],
     },  # target opus_demo
+    {
+      'target_name': 'test_opus_api',
+      'type': 'executable',
+      'dependencies': [
+        'opus'
+      ],
+      'sources': [
+        'src/tests/test_opus_api.c',
+      ],
+    },  # target test_opus_api
+    {
+      'target_name': 'test_opus_encode',
+      'type': 'executable',
+      'dependencies': [
+        'opus'
+      ],
+      'sources': [
+        'src/tests/test_opus_encode.c',
+      ],
+    },  # target test_opus_encode
+    {
+      'target_name': 'test_opus_decode',
+      'type': 'executable',
+      'dependencies': [
+        'opus'
+      ],
+      'sources': [
+        'src/tests/test_opus_decode.c',
+      ],
+      # test_opus_decode passes a null pointer to opus_decode() for an argument
+      # marked as requiring a non-null value by the nonnull function attribute,
+      # and expects opus_decode() to fail. Disable the -Wnonnull option to avoid
+      # a compilation error if -Werror is specified.
+      'conditions': [
+        ['os_posix==1 and OS!="mac" and OS!="ios"', {
+          'cflags': ['-Wno-nonnull'],
+        }],
+        ['OS=="mac" or OS=="ios"', {
+          'xcode_settings': {
+            'WARNING_CFLAGS': ['-Wno-nonnull'],
+          },
+        }],
+      ],
+    },  # target test_opus_decode
+    {
+      'target_name': 'test_opus_padding',
+      'type': 'executable',
+      'dependencies': [
+        'opus'
+      ],
+      'sources': [
+        'src/tests/test_opus_padding.c',
+      ],
+    },  # target test_opus_padding
   ]
 }
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium
index fdf3394..8fb3768 100644
--- a/third_party/qcms/README.chromium
+++ b/third_party/qcms/README.chromium
@@ -51,5 +51,7 @@
    - https://code.google.com/p/chromium/issues/detail?id=401971
  - Minor variable name change: description -> description_offset
    - https://code.google.com/p/chromium/issues/detail?id=401971
+ - Avoid divisions creating sample points in the float cube LUT builder
+   - https://code.google.com/p/chromium/issues/detail?id=443863
 To regenerate google.patch:
   git diff b8456f38 src > google.patch
diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c
index 08db142b..9fd82389 100644
--- a/third_party/qcms/src/transform.c
+++ b/third_party/qcms/src/transform.c
@@ -1118,28 +1118,31 @@
 	float* src = NULL;
 	float* dest = NULL;
 	float* lut = NULL;
+	float inverse;
 
 	src = malloc(lutSize*sizeof(float));
 	dest = malloc(lutSize*sizeof(float));
 
 	if (src && dest) {
-		/* Prepare a list of points we want to sample */
+		/* Prepare a list of points we want to sample: x, y, z order */
 		l = 0;
+		inverse = 1 / (float)(samples-1);
 		for (x = 0; x < samples; x++) {
 			for (y = 0; y < samples; y++) {
 				for (z = 0; z < samples; z++) {
-					src[l++] = x / (float)(samples-1);
-					src[l++] = y / (float)(samples-1);
-					src[l++] = z / (float)(samples-1);
+					src[l++] = x * inverse; // r
+					src[l++] = y * inverse; // g
+					src[l++] = z * inverse; // b
 				}
 			}
 		}
 
 		lut = qcms_chain_transform(in, out, src, dest, lutSize);
+
 		if (lut) {
-			transform->r_clut = &lut[0];
-			transform->g_clut = &lut[1];
-			transform->b_clut = &lut[2];
+			transform->r_clut = &lut[0]; // r
+			transform->g_clut = &lut[1]; // g
+			transform->b_clut = &lut[2]; // b
 			transform->grid_size = samples;
 			if (in_type == QCMS_DATA_RGBA_8) {
 				transform->transform_fn = qcms_transform_data_tetra_clut_rgba;
@@ -1149,8 +1152,8 @@
 		}
 	}
 
-
-	//XXX: qcms_modular_transform_data may return either the src or dest buffer. If so it must not be free-ed
+	// XXX: qcms_modular_transform_data may return the lut in either the src or the
+	// dest buffer. If so, it must not be free-ed.
 	if (src && lut != src) {
 		free(src);
 	}
diff --git a/tools/chrome_proxy/OWNERS b/tools/chrome_proxy/OWNERS
index f5c2303..b4ac2d2 100644
--- a/tools/chrome_proxy/OWNERS
+++ b/tools/chrome_proxy/OWNERS
@@ -3,3 +3,4 @@
 kundaji@chromium.org
 marq@chromium.org
 megjablon@chromium.org
+sclittle@chromium.org
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
index 43d9397..10ed99b 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
@@ -311,7 +311,7 @@
     tab.WaitForJavaScriptExpression('performance.timing.loadEventStart', 300)
 
   def AddResults(self, tab, results):
-    self._metrics.AddResultsForHTTPToDirectFallback(tab, results)
+    self._metrics.AddResultsForHTTPToDirectFallback(tab, results, _TEST_SERVER)
 
 
 class ChromeProxyReenableAfterBypass(ChromeProxyValidation):
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py
index 63773da..f856f5ba 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py
@@ -307,36 +307,46 @@
     results.AddValue(scalar.ScalarValue(
         results.current_page, 'via_fallback', 'count', via_fallback_count))
 
-  def AddResultsForHTTPToDirectFallback(self, tab, results):
+  def AddResultsForHTTPToDirectFallback(self, tab, results,
+                                        fallback_response_host):
     via_fallback_count = 0
     bypass_count = 0
     responses = self.IterResponses(tab)
 
-    # The very first response should be through the HTTP fallback proxy.
-    fallback_resp = next(responses, None)
-    if not fallback_resp:
-      raise ChromeProxyMetricException, 'There should be at least one response.'
-    elif (not fallback_resp.HasChromeProxyViaHeader() or
-          fallback_resp.remote_port != 80):
-      r = fallback_resp.response
-      raise ChromeProxyMetricException, (
-          'Response for %s should have come through the fallback proxy.\n'
-          'Reponse: remote_port=%s status=(%d, %s)\nHeaders:\n %s' % (
-              r.url, str(fallback_resp.remote_port), r.status, r.status_text,
-              r.headers))
-    else:
-      via_fallback_count += 1
+    # The first response(s) coming from fallback_response_host should be
+    # through the HTTP fallback proxy.
+    resp = next(responses, None)
+    while resp and fallback_response_host in resp.response.url:
+      if fallback_response_host in resp.response.url:
+        if (not resp.HasChromeProxyViaHeader() or resp.remote_port != 80):
+          r = resp.response
+          raise ChromeProxyMetricException, (
+              'Response for %s should have come through the fallback proxy.\n'
+              'Response: remote_port=%s status=(%d, %s)\nHeaders:\n %s' % (
+                r.url, str(fallback_resp.remote_port), r.status, r.status_text,
+                r.headers))
+        else:
+          via_fallback_count += 1
+      resp = next(responses, None)
 
-    # All other responses should have been bypassed.
-    for resp in responses:
+    # All other responses should be bypassed.
+    while resp:
       if resp.HasChromeProxyViaHeader():
         r = resp.response
         raise ChromeProxyMetricException, (
             'Response for %s should not have via header.\n'
-            'Reponse: status=(%d, %s)\nHeaders:\n %s' % (
+            'Response: status=(%d, %s)\nHeaders:\n %s' % (
                 r.url, r.status, r.status_text, r.headers))
       else:
         bypass_count += 1
+      resp = next(responses, None)
+
+    # At least one response should go through the http proxy and be bypassed.
+    if via_fallback_count == 0 or bypass_count == 0:
+      raise ChromeProxyMetricException(
+          'There should be at least one response through the fallback proxy '
+          '(actual %s) and at least one bypassed response (actual %s)' %
+          (via_fallback_count, bypass_count))
 
     results.AddValue(scalar.ScalarValue(
         results.current_page, 'via_fallback', 'count', via_fallback_count))
diff --git a/tools/cr/cr-bash-helpers.sh b/tools/cr/cr-bash-helpers.sh
index e7e7593..3fa6a8aa 100755
--- a/tools/cr/cr-bash-helpers.sh
+++ b/tools/cr/cr-bash-helpers.sh
@@ -19,7 +19,12 @@
   READLINK_e=("greadlink" "-e")
 fi
 
-cr_base_dir=$(dirname $(${READLINK_e[@]} "${BASH_SOURCE:-$0}"))
+if [[ $(uname) == "Darwin" ]]; then
+  cr_base_dir=$(dirname "${BASH_SOURCE:-$0}")
+else
+  cr_base_dir=$(dirname $(${READLINK_e[@]} "${BASH_SOURCE:-$0}"))
+fi
+
 cr_main="${cr_base_dir}/main.py"
 cr_exec=("PYTHONDONTWRITEBYTECODE=1" "python" "${cr_main}")
 
diff --git a/tools/cr/cr/base/mac.py b/tools/cr/cr/base/mac.py
new file mode 100644
index 0000000..5bf2276
--- /dev/null
+++ b/tools/cr/cr/base/mac.py
@@ -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.
+
+"""The mac specific host and platform implementation module."""
+
+import os
+
+import cr
+
+
+class MacHost(cr.Host):
+  """The implementation of Host for mac."""
+
+  ACTIVE = cr.Config.From(
+      GOOGLE_CODE='/usr/local/google/code',
+  )
+
+  def __init__(self):
+    super(MacHost, self).__init__()
+
+  def Matches(self):
+    return cr.Platform.System() == 'Darwin'
+
+
+class MacPlatform(cr.Platform):
+  """The implementation of Platform for the mac target."""
+
+  ACTIVE = cr.Config.From(
+      CR_BINARY=os.path.join('{CR_BUILD_DIR}', '{CR_BUILD_TARGET}'),
+      CHROME_DEVEL_SANDBOX='/usr/local/sbin/chrome-devel-sandbox',
+  )
+
+  @property
+  def enabled(self):
+    return cr.Platform.System() == 'Darwin'
+
+  @property
+  def priority(self):
+    return 2
+
+  @property
+  def paths(self):
+    return ['{GOMA_DIR}']
diff --git a/tools/gn/command_args.cc b/tools/gn/command_args.cc
index 50bdbe91..75d5fce 100644
--- a/tools/gn/command_args.cc
+++ b/tools/gn/command_args.cc
@@ -245,7 +245,7 @@
           "# Build arguments go here. Examples:\n"
           "#   is_component_build = true\n"
           "#   is_debug = false\n"
-          "# See \"gn args <dir_name> --list\" for available build "
+          "# See \"gn args <out_dir> --list\" for available build "
           "arguments.\n";
 #if defined(OS_WIN)
       // Use Windows lineendings for this file since it will often open in
@@ -275,13 +275,13 @@
 extern const char kArgs_HelpShort[] =
     "args: Display or configure arguments declared by the build.";
 extern const char kArgs_Help[] =
-    "gn args [arg name]\n"
+    "gn args <out_dir> [--list] [--short] [--args]\n"
     "\n"
     "  See also \"gn help buildargs\" for a more high-level overview of how\n"
     "  build arguments work.\n"
     "\n"
     "Usage\n"
-    "  gn args <dir_name>\n"
+    "  gn args <out_dir>\n"
     "      Open the arguments for the given build directory in an editor\n"
     "      (as specified by the EDITOR environment variable). If the given\n"
     "      build directory doesn't exist, it will be created and an empty\n"
@@ -292,9 +292,9 @@
     "\n"
     "      Note: you can edit the build args manually by editing the file\n"
     "      \"args.gn\" in the build directory and then running\n"
-    "      \"gn gen <build_dir>\".\n"
+    "      \"gn gen <out_dir>\".\n"
     "\n"
-    "  gn args <dir_name> --list[=<exact_arg>] [--short]\n"
+    "  gn args <out_dir> --list[=<exact_arg>] [--short]\n"
     "      Lists all build arguments available in the current configuration,\n"
     "      or, if an exact_arg is specified for the list flag, just that one\n"
     "      build argument.\n"
@@ -303,14 +303,14 @@
     "      comment preceeding the declaration. If --short is specified,\n"
     "      only the names and values will be printed.\n"
     "\n"
-    "      If the dir_name is specified, the build configuration will be\n"
+    "      If the out_dir is specified, the build configuration will be\n"
     "      taken from that build directory. The reason this is needed is that\n"
     "      the definition of some arguments is dependent on the build\n"
     "      configuration, so setting some values might add, remove, or change\n"
     "      the default values for other arguments. Specifying your exact\n"
     "      configuration allows the proper arguments to be displayed.\n"
     "\n"
-    "      Instead of specifying the dir_name, you can also use the\n"
+    "      Instead of specifying the out_dir, you can also use the\n"
     "      command-line flag to specify the build configuration:\n"
     "        --args=<exact list of args to use>\n"
     "\n"
@@ -334,7 +334,7 @@
 int RunArgs(const std::vector<std::string>& args) {
   if (args.size() != 1) {
     Err(Location(), "Exactly one build dir needed.",
-        "Usage: \"gn args <build_dir>\"\n"
+        "Usage: \"gn args <out_dir>\"\n"
         "Or see \"gn help args\" for more variants.").PrintToStdout();
     return 1;
   }
diff --git a/tools/gn/command_gen.cc b/tools/gn/command_gen.cc
index cacab84..5c0a5a9 100644
--- a/tools/gn/command_gen.cc
+++ b/tools/gn/command_gen.cc
@@ -51,7 +51,7 @@
 const char kGen_Help[] =
     "gn gen: Generate ninja files.\n"
     "\n"
-    "  gn gen <output_directory>\n"
+    "  gn gen <out_dir>\n"
     "\n"
     "  Generates ninja files from the current tree and puts them in the given\n"
     "  output directory.\n"
diff --git a/tools/gn/command_ls.cc b/tools/gn/command_ls.cc
index 8aefa76..a2dc38c 100644
--- a/tools/gn/command_ls.cc
+++ b/tools/gn/command_ls.cc
@@ -18,7 +18,7 @@
 const char kLs_HelpShort[] =
     "ls: List matching targets.";
 const char kLs_Help[] =
-    "gn ls <build dir> [<label_pattern>] [--out] [--all-toolchains]\n"
+    "gn ls <out_dir> [<label_pattern>] [--out] [--all-toolchains]\n"
     "\n"
     "  Lists all targets matching the given pattern for the given builn\n"
     "  directory. By default, only targets in the default toolchain will\n"
diff --git a/tools/gn/command_refs.cc b/tools/gn/command_refs.cc
index 39f8c10f..d75ca50 100644
--- a/tools/gn/command_refs.cc
+++ b/tools/gn/command_refs.cc
@@ -204,7 +204,7 @@
 const char kRefs_HelpShort[] =
     "refs: Find stuff referencing a target or file.";
 const char kRefs_Help[] =
-    "gn refs <build_dir> (<label_pattern>|<file>) [--files] [--tree] [--all]\n"
+    "gn refs <out_dir> (<label_pattern>|<file>) [--files] [--tree] [--all]\n"
     "        [--all-toolchains]\n"
     "\n"
     "  Finds reverse dependencies (which targets reference something). The\n"
@@ -282,7 +282,7 @@
 int RunRefs(const std::vector<std::string>& args) {
   if (args.size() != 2) {
     Err(Location(), "You're holding it wrong.",
-        "Usage: \"gn refs <build_dir> (<label_pattern>|<file>)\"")
+        "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)\"")
         .PrintToStdout();
     return 1;
   }
diff --git a/tools/memory_inspector/chrome_app/template/manifest.json b/tools/memory_inspector/chrome_app/template/manifest.json
index b797fc0..f8bc06a 100644
--- a/tools/memory_inspector/chrome_app/template/manifest.json
+++ b/tools/memory_inspector/chrome_app/template/manifest.json
@@ -1,7 +1,7 @@
 {
   "name": "Memory Inspector",
   "description": "Memory inspector tool for Android",
-  "version": "0.1.2",
+  "version": "0.1.3",
   "manifest_version": 2,
   "icons": {
     "16": "images/icon_16.png",
diff --git a/tools/memory_inspector/memory_inspector/backends/android_backend.py b/tools/memory_inspector/memory_inspector/backends/android_backend.py
index 2c4ce7cd..b80480533 100644
--- a/tools/memory_inspector/memory_inspector/backends/android_backend.py
+++ b/tools/memory_inspector/memory_inspector/backends/android_backend.py
@@ -27,8 +27,8 @@
 from memory_inspector.core import symbol
 
 
-_SUPPORTED_32BIT_ABIS = {'armeabi': 'arm', 'armeabi-v7a': 'arm'}
-_SUPPORTED_64BIT_ABIS = {'arm64-v8a': 'arm64'}
+_SUPPORTED_32BIT_ABIS = {'armeabi': 'arm', 'armeabi-v7a': 'arm', 'x86': 'x86'}
+_SUPPORTED_64BIT_ABIS = {'arm64-v8a': 'arm64', 'x86_64': 'x86_64'}
 _MEMDUMP_PREBUILT_PATH = os.path.join(constants.PREBUILTS_PATH,
                                       'memdump-android-%(arch)s')
 _MEMDUMP_PATH_ON_DEVICE = '/data/local/tmp/memdump'
diff --git a/tools/memory_inspector/memory_inspector/frontends/www_server.py b/tools/memory_inspector/memory_inspector/frontends/www_server.py
index d75c973..27b8484 100644
--- a/tools/memory_inspector/memory_inspector/frontends/www_server.py
+++ b/tools/memory_inspector/memory_inspector/frontends/www_server.py
@@ -141,7 +141,7 @@
   return _HTTP_OK, [], resp
 
 
-@AjaxHandler(r'/ajax/dump/mmap/(\w+)/(\w+)/(\d+)')
+@AjaxHandler(r'/ajax/dump/mmap/([^/]+)/([^/]+)/(\d+)')
 def _DumpMmapsForProcess(args, req_vars):  # pylint: disable=W0613
   """Dumps memory maps for a process.
 
@@ -158,7 +158,7 @@
   return _HTTP_OK, [], {'table': table, 'id': cache_id}
 
 
-@AjaxHandler('/ajax/initialize/(\w+)/(\w+)$', 'POST')
+@AjaxHandler('/ajax/initialize/([^/]+)/([^/]+)$', 'POST')
 def _InitializeDevice(args, req_vars):  # pylint: disable=W0613
   device = _GetDevice(args)
   if not device:
@@ -258,7 +258,7 @@
                         'rootBucket': first_snapshot.total.name + '/'}
 
 
-@AjaxHandler(r'/ajax/profile/(\w+)/tree/(\d+)/(\d+)')
+@AjaxHandler(r'/ajax/profile/([^/]+)/tree/(\d+)/(\d+)')
 def _GetProfileTreeDataForSnapshot(args, req_vars):  # pylint: disable=W0613
   """Gets the data for the tree chart for a given time and metric.
 
@@ -296,7 +296,7 @@
   return _HTTP_OK, [], resp
 
 
-@AjaxHandler(r'/ajax/profile/(\w+)/time_serie/(\d+)/(.*)$')
+@AjaxHandler(r'/ajax/profile/([^/]+)/time_serie/(\d+)/(.*)$')
 def _GetTimeSerieForSnapshot(args, req_vars):  # pylint: disable=W0613
   """Gets the data for the area chart for a given metric and bucket.
 
@@ -362,7 +362,7 @@
   return _HTTP_OK, [], resp
 
 
-@AjaxHandler(r'/ajax/ps/(\w+)/(\w+)$')  # /ajax/ps/Android/a0b1c2[?all=1]
+@AjaxHandler(r'/ajax/ps/([^/]+)/([^/]+)$')  # /ajax/ps/Android/a0b1c2[?all=1]
 def _ListProcesses(args, req_vars):  # pylint: disable=W0613
   """Lists processes and their CPU / mem stats.
 
@@ -395,7 +395,7 @@
   return _HTTP_OK, [], resp
 
 
-@AjaxHandler(r'/ajax/stats/(\w+)/(\w+)$')  # /ajax/stats/Android/a0b1c2
+@AjaxHandler(r'/ajax/stats/([^/]+)/([^/]+)$')  # /ajax/stats/Android/a0b1c2
 def _GetDeviceStats(args, req_vars):  # pylint: disable=W0613
   """Lists device CPU / mem stats.
 
@@ -440,7 +440,7 @@
   return _HTTP_OK, [], {'cpu': cpu_stats, 'mem': mem_stats}
 
 
-@AjaxHandler(r'/ajax/stats/(\w+)/(\w+)/(\d+)$')  # /ajax/stats/Android/a0b1c2/42
+@AjaxHandler(r'/ajax/stats/([^/]+)/([^/]+)/(\d+)$')  # /ajax/stats/Android/a0/3
 def _GetProcessStats(args, req_vars):  # pylint: disable=W0613
   """Lists CPU / mem stats for a given process (and keeps history).
 
@@ -490,7 +490,7 @@
   return _HTTP_OK, [], {'cpu': cpu_stats, 'mem': mem_stats}
 
 
-@AjaxHandler(r'/ajax/settings/(\w+)/?(\w+)?$')  # /ajax/settings/Android[/id]
+@AjaxHandler(r'/ajax/settings/([^/]+)/?(\w+)?$')  # /ajax/settings/Android[/id]
 def _GetDeviceOrBackendSettings(args, req_vars):  # pylint: disable=W0613
   backend = backends.GetBackend(args[0])
   if not backend:
@@ -511,7 +511,7 @@
   return _HTTP_OK, [], resp
 
 
-@AjaxHandler(r'/ajax/settings/(\w+)/?(\w+)?$', 'POST')
+@AjaxHandler(r'/ajax/settings/([^/]+)/?(\w+)?$', 'POST')
 def _SetDeviceOrBackendSettings(args, req_vars):  # pylint: disable=W0613
   backend = backends.GetBackend(args[0])
   if not backend:
@@ -617,7 +617,7 @@
 
 
 # /ajax/tracer/start/Android/device-id/pid
-@AjaxHandler(r'/ajax/tracer/start/(\w+)/(\w+)/(\d+)', 'POST')
+@AjaxHandler(r'/ajax/tracer/start/([^/]+)/([^/]+)/(\d+)', 'POST')
 def _StartTracer(args, req_vars):
   for arg in 'interval', 'count', 'traceNativeHeap':
     assert(arg in req_vars), 'Expecting %s argument in POST data' % arg
diff --git a/tools/memory_inspector/prebuilts/heap_dump-android-x86.sha1 b/tools/memory_inspector/prebuilts/heap_dump-android-x86.sha1
new file mode 100644
index 0000000..42039d8
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/heap_dump-android-x86.sha1
@@ -0,0 +1 @@
+13cfc6bf8d706c2faba9d38b0fb38e98a059d1e3
\ No newline at end of file
diff --git a/tools/memory_inspector/prebuilts/heap_dump-android-x86_64.sha1 b/tools/memory_inspector/prebuilts/heap_dump-android-x86_64.sha1
new file mode 100644
index 0000000..3590ca2
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/heap_dump-android-x86_64.sha1
@@ -0,0 +1 @@
+56847334a1a2433ae42a31bcbb0d5f962f2d5a34
\ No newline at end of file
diff --git a/tools/memory_inspector/prebuilts/libheap_profiler-android-x86.sha1 b/tools/memory_inspector/prebuilts/libheap_profiler-android-x86.sha1
new file mode 100644
index 0000000..edb828b
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/libheap_profiler-android-x86.sha1
@@ -0,0 +1 @@
+efa81d9b76f78e01936e760f3c6627361791e485
\ No newline at end of file
diff --git a/tools/memory_inspector/prebuilts/libheap_profiler-android-x86_64.sha1 b/tools/memory_inspector/prebuilts/libheap_profiler-android-x86_64.sha1
new file mode 100644
index 0000000..45e82e1
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/libheap_profiler-android-x86_64.sha1
@@ -0,0 +1 @@
+28c7fc4438a22086f1fb62e214b459ae2e7406a8
\ No newline at end of file
diff --git a/tools/memory_inspector/prebuilts/memdump-android-x86.sha1 b/tools/memory_inspector/prebuilts/memdump-android-x86.sha1
new file mode 100644
index 0000000..528000a
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/memdump-android-x86.sha1
@@ -0,0 +1 @@
+d286590ab11556d044bb1c82b960ef590b427fec
\ No newline at end of file
diff --git a/tools/memory_inspector/prebuilts/memdump-android-x86_64.sha1 b/tools/memory_inspector/prebuilts/memdump-android-x86_64.sha1
new file mode 100644
index 0000000..6f35e5d
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/memdump-android-x86_64.sha1
@@ -0,0 +1 @@
+a8bd66274b5a8e0dc486a3ce554804dbf331e791
\ No newline at end of file
diff --git a/tools/memory_inspector/prebuilts/ps_ext-android-x86.sha1 b/tools/memory_inspector/prebuilts/ps_ext-android-x86.sha1
new file mode 100644
index 0000000..41f7a65d
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/ps_ext-android-x86.sha1
@@ -0,0 +1 @@
+9ba72bd7ebb8626bf4dc130a4a777141ba204358
\ No newline at end of file
diff --git a/tools/memory_inspector/prebuilts/ps_ext-android-x86_64.sha1 b/tools/memory_inspector/prebuilts/ps_ext-android-x86_64.sha1
new file mode 100644
index 0000000..fe0d476
--- /dev/null
+++ b/tools/memory_inspector/prebuilts/ps_ext-android-x86_64.sha1
@@ -0,0 +1 @@
+d328cded2aae293c9faf1d87599dbbadcc415dd2
\ No newline at end of file
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 8d2b76c..3cd2f7f6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -9016,6 +9016,13 @@
   <summary>Time taken to unpack an extension, when the unpack fails.</summary>
 </histogram>
 
+<histogram name="Extensions.SandboxUnpackHashCheck" enum="BooleanValidHashSum">
+  <owner>ginkage@chromium.org</owner>
+  <summary>
+    Whether a CRX file hash sum was the same as in an updater manifest.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.SandboxUnpackInitialCrxPathLength">
   <owner>asargent@chromium.org</owner>
   <summary>Length of the initial path to the CRX to be unpacked.</summary>
@@ -23283,6 +23290,13 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordHash.CreateTime">
+  <owner>mlerman@chromium.org</owner>
+  <summary>
+    Time required to create the local hash of the user's GAIA password.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.AccountsPerSite">
   <owner>gcasto@chromium.org</owner>
   <owner>vabr@chromium.org</owner>
@@ -28811,6 +28825,13 @@
   </summary>
 </histogram>
 
+<histogram name="Renderer.LineLayoutMs" units="milliseconds">
+  <owner>benjhayden@chromium.org</owner>
+  <summary>
+    Amount of time spent doing line layout during FrameView::performLayout.
+  </summary>
+</histogram>
+
 <histogram name="Renderer.PixelIncreaseFromTransitions">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>
@@ -39942,7 +39963,7 @@
   <summary>Time spent in V8 compiler (full codegen).</summary>
 </histogram>
 
-<histogram name="V8.CompileCacheableMicroseconds" units="microseconds">
+<histogram name="V8.CompileCacheableMicroSeconds" units="microseconds">
   <owner>yangguo@chromium.org</owner>
   <summary>
     Time spent compiling a script that may be subject to caching.
@@ -43675,6 +43696,11 @@
   <int value="1" label="Valid"/>
 </enum>
 
+<enum name="BooleanValidHashSum" type="int">
+  <int value="0" label="Invalid hash sum"/>
+  <int value="1" label="Valid hash sum"/>
+</enum>
+
 <enum name="BooleanValidKeyExists" type="int">
   <int value="0" label="No Valid Cached Key Found"/>
   <int value="1" label="Valid Cached Key Found"/>
@@ -47250,9 +47276,9 @@
   <int value="934" label="AUTOTESTPRIVATE_SETNATURALSCROLL"/>
   <int value="935" label="AUTOTESTPRIVATE_SETMOUSESENSITIVITY"/>
   <int value="936" label="AUTOTESTPRIVATE_SETPRIMARYBUTTONRIGHT"/>
-  <int value="937" label="COPRESENCEENDPOINTS_CREATELOCALENDPOINT"/>
-  <int value="938" label="COPRESENCEENDPOINTS_DESTROYLOCALENDPOINT"/>
-  <int value="939" label="COPRESENCEENDPOINTS_SEND"/>
+  <int value="937" label="DELETED_COPRESENCEENDPOINTS_CREATELOCALENDPOINT"/>
+  <int value="938" label="DELETED_COPRESENCEENDPOINTS_DESTROYLOCALENDPOINT"/>
+  <int value="939" label="DELETED_COPRESENCEENDPOINTS_SEND"/>
   <int value="940" label="INLINE_INSTALL_PRIVATE_INSTALL"/>
   <int value="941" label="LAUNCHERPAGE_SETENABLED"/>
   <int value="942" label="CRYPTOTOKENPRIVATE_REQUESTPERMISSION"/>
@@ -47515,6 +47541,7 @@
   <int value="30" label="INVALID_PATH_FOR_CATALOG"/>
   <int value="31" label="ERROR_SERIALIZING_CATALOG"/>
   <int value="32" label="ERROR_SAVING_CATALOG"/>
+  <int value="33" label="CRX_HASH_VERIFICATION_FAILED"/>
 </enum>
 
 <enum name="ExternalDeviceAction" type="int">
@@ -48263,6 +48290,7 @@
   <int value="675" label="Fetch"/>
   <int value="676" label="FetchBodyStream"/>
   <int value="677" label="XMLHttpRequestAsynchronous"/>
+  <int value="678" label="AudioBufferSourceBufferOnce"/>
 </enum>
 
 <enum name="FFmpegCodecs" type="int">
@@ -50713,6 +50741,7 @@
   <int value="-2008272679" label="disable-webrtc-hw-encoding"/>
   <int value="-2003354337"
       label="enable-search-button-in-omnibox-for-str-or-iip"/>
+  <int value="-1998927516" label="enable-md-settings"/>
   <int value="-1985025593" label="file-manager-enable-new-gallery"/>
   <int value="-1972383451" label="disable-pinch"/>
   <int value="-1940806558" label="enable-syncfs-directory-operation"/>
@@ -50864,6 +50893,7 @@
   <int value="-158549277" label="enable-embeddedsearch-api"/>
   <int value="-158197254" label="enable-credential-manager-api"/>
   <int value="-147283486" label="enable-network-portal-notification"/>
+  <int value="-146552997" label="enable-affiliation-based-matching"/>
   <int value="-102537270" label="extension-content-verification"/>
   <int value="-99781021" label="disable-roboto-font-ui"/>
   <int value="-88822940" label="ssl-version-min"/>
@@ -50881,6 +50911,7 @@
     Command-line flag doesn't start with two dashes.
   </int>
   <int value="27507364" label="apps-keep-chrome-alive"/>
+  <int value="37024318" label="disable-affiliation-based-matching"/>
   <int value="48159177" label="reduced-referrer-granularity"/>
   <int value="61205887" label="enable-text-input-focus-manager"/>
   <int value="79503461" label="disable-account-consistency"/>
@@ -50979,6 +51010,7 @@
   <int value="1221559505" label="enable-spelling-feedback-field-trial"/>
   <int value="1237297772" label="no-pings"/>
   <int value="1245889469" label="enable-surface-worker"/>
+  <int value="1250071868" label="disable-timezone-tracking-option"/>
   <int value="1257980502" label="disable-accelerated-video-decode"/>
   <int value="1268470658" label="disable-android-password-link"/>
   <int value="1279584261" label="enable-carrier-switching"/>
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml
index 7fbe8ba..2f7cac2 100644
--- a/tools/metrics/rappor/rappor.xml
+++ b/tools/metrics/rappor/rappor.xml
@@ -140,6 +140,38 @@
   </summary>
 </rappor-metric>
 
+<rappor-metric name="interstitial.malware.domain" type="COARSE_RAPPOR_TYPE">
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    The domain+registry of a URL that triggered a safe-browsing malware
+    interstitial.
+  </summary>
+</rappor-metric>
+
+<rappor-metric name="interstitial.phishing.domain" type="COARSE_RAPPOR_TYPE">
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    The domain+registry of a URL that triggered a safe-browsing phishing
+    interstitial.
+  </summary>
+</rappor-metric>
+
+<rappor-metric name="interstitial.harmful.domain" type="COARSE_RAPPOR_TYPE">
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    The domain+registry of a URL that triggered a safe-browsing UWS
+    interstitial.
+  </summary>
+</rappor-metric>
+
+<rappor-metric name="interstitial.ssl.domain" type="COARSE_RAPPOR_TYPE">
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    The domain+registry of a URL that triggered an SSL interstitial.
+    Domains for bad-clock warnings are not reported.
+  </summary>
+</rappor-metric>
+
 </rappor-metrics>
 
 </rappor-configuration>
diff --git a/tools/perf/benchmarks/gpu_times.py b/tools/perf/benchmarks/gpu_times.py
index 3085e0a..eaeb972 100644
--- a/tools/perf/benchmarks/gpu_times.py
+++ b/tools/perf/benchmarks/gpu_times.py
@@ -27,7 +27,7 @@
         get_metrics_from_flags_callback=_GetGPUTimelineMetric)
 
 
-@benchmark.Enabled('android')
+@benchmark.Disabled
 class GPUTimesKeyMobileSites(_GPUTimes):
   """Measures GPU timeline metric on key mobile sites."""
   page_set = page_sets.KeyMobileSitesSmoothPageSet
@@ -36,7 +36,7 @@
   def Name(cls):
     return 'gpu_times.key_mobile_sites_smooth'
 
-@benchmark.Enabled('android')
+@benchmark.Disabled
 class GPUTimesGpuRasterizationKeyMobileSites(_GPUTimes):
   """Measures GPU timeline metric on key mobile sites with GPU rasterization.
   """
diff --git a/tools/perf_expectations/perf_expectations.json b/tools/perf_expectations/perf_expectations.json
index 5a455c78..c479ba8c 100644
--- a/tools/perf_expectations/perf_expectations.json
+++ b/tools/perf_expectations/perf_expectations.json
@@ -1,8 +1,8 @@
 {"linux-release-64/sizes/chrome-bss/bss": {"reva": 311086, "revb": 311132, "type": "absolute", "better": "lower", "improve": 453296, "regress": 501029, "sha1": "d69fb86b"},
  "linux-release-64/sizes/chrome-data/data": {"reva": 295451, "revb": 295513, "type": "absolute", "better": "lower", "improve": 4337320, "regress": 4794006, "sha1": "04b10278"},
  "linux-release-64/sizes/chrome-si/initializers": {"reva": 281711, "revb": 281711, "type": "absolute", "better": "lower", "improve": 7, "regress": 7, "tolerance": 0, "sha1": "b11fc43a"},
- "linux-release-64/sizes/chrome-text/text": {"reva": 310080, "revb": 310080, "type": "absolute", "better": "lower", "improve": 94693532, "regress": 104661274, "sha1": "837f5b77"},
- "linux-release-64/sizes/chrome/chrome": {"reva": 295451, "revb": 295484, "type": "absolute", "better": "lower", "improve": 134684000, "regress": 148870193, "sha1": "6144f224"},
+ "linux-release-64/sizes/chrome-text/text": {"reva": 314576, "revb": 314597, "type": "absolute", "better": "lower", "improve": 99684402, "regress": 110179552, "sha1": "dd896f5d"},
+ "linux-release-64/sizes/chrome/chrome": {"reva": 314576, "revb": 314597, "type": "absolute", "better": "lower", "improve": 144357447, "regress": 159558118, "sha1": "dd048ccd"},
  "linux-release-64/sizes/nacl_helper-bss/bss": {"reva": 282247, "revb": 282247, "type": "absolute", "better": "lower", "improve": 257670, "regress": 284794, "sha1": "4baf0f5e"},
  "linux-release-64/sizes/nacl_helper-data/data": {"reva": 299377, "revb": 299377, "type": "absolute", "better": "lower", "improve": 209098, "regress": 231110, "sha1": "9d7262fa"},
  "linux-release-64/sizes/nacl_helper-si/initializers": {"reva": 271321, "revb": 271321, "type": "absolute", "better": "lower", "improve": 5, "regress": 7, "sha1": "f29296a1"},
@@ -365,9 +365,9 @@
  "linux-release/sizes/chrome-bss/bss": {"reva": 311086, "revb": 311132, "type": "absolute", "better": "lower", "improve": 318223, "regress": 351738, "sha1": "a1baf698"},
  "linux-release/sizes/chrome-data/data": {"reva": 292870, "revb": 292920, "type": "absolute", "better": "lower", "improve": 2299296, "regress": 2560522, "sha1": "1ed32136"},
  "linux-release/sizes/chrome-si/initializers": {"reva": 281717, "revb": 281717, "type": "absolute", "better": "lower", "improve": 8, "regress": 8, "tolerance": 0, "sha1": "b639bbc4"},
- "linux-release/sizes/chrome-text/text": {"reva": 298898, "revb": 298929, "type": "absolute", "better": "lower", "improve": 95627212, "regress": 105825515, "sha1": "39f276a0"},
+ "linux-release/sizes/chrome-text/text": {"reva": 314576, "revb": 314590, "type": "absolute", "better": "lower", "improve": 102025091, "regress": 112765474, "sha1": "323b5a75"},
  "linux-release/sizes/chrome-textrel/textrel": {"reva": 234134, "revb": 234142, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "61db9eaf"},
- "linux-release/sizes/chrome/chrome": {"reva": 298898, "revb": 298929, "type": "absolute", "better": "lower", "improve": 130581651, "regress": 144461771, "sha1": "efac9219"},
+ "linux-release/sizes/chrome/chrome": {"reva": 314576, "revb": 314590, "type": "absolute", "better": "lower", "improve": 138826666, "regress": 153444353, "sha1": "943c4b9d"},
  "linux-release/sizes/libffmpegsumo.so-textrel/textrel": {"reva": 200467, "revb": 203456, "type": "absolute", "better": "lower", "improve": 1075, "regress": 1189, "sha1": "a10d4ea4"},
  "linux-release/sizes/nacl_helper-bss/bss": {"reva": 282247, "revb": 282247, "type": "absolute", "better": "lower", "improve": 143640, "regress": 158760, "sha1": "95c4c516"},
  "linux-release/sizes/nacl_helper-data/data": {"reva": 299377, "revb": 299377, "type": "absolute", "better": "lower", "improve": 107384, "regress": 118688, "sha1": "2e0b5d0c"},
@@ -383,7 +383,7 @@
  "linux-release/sizes/totals-textrel/textrel": {"reva": 205083, "revb": 206071, "type": "absolute", "better": "lower", "improve": 1075, "regress": 1189, "sha1": "69d07fda"},
  "mac-release/sizes/Chromium.app/Chromium.app": {"reva": 305049, "revb": 305099, "type": "absolute", "better": "lower", "improve": 150118604, "regress": 165929165, "sha1": "6133e499"},
  "mac-release/sizes/Chromium/Chromium": {"reva": 165473, "revb": 165473, "type": "absolute", "better": "lower", "improve": 8132, "regress": 8988, "sha1": "8e448691"},
- "mac-release/sizes/ChromiumFramework/ChromiumFramework": {"reva": 305049, "revb": 305099, "type": "absolute", "better": "lower", "improve": 90343214, "regress": 99857361, "sha1": "d3a8505a"},
+ "mac-release/sizes/ChromiumFramework/ChromiumFramework": {"reva": 314575, "revb": 314597, "type": "absolute", "better": "lower", "improve": 96029781, "regress": 106138196, "sha1": "e601ccfe"},
  "mac-release/sizes/chrome-si/initializers": {"reva": 281731, "revb": 281731, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "tolerance": 0, "sha1": "01759b7f"},
  "win-release/media_tests_av_perf/audio_latency/latency": {"reva": 199840, "revb": 201303, "type": "absolute", "better": "lower", "improve": 57, "regress": 69, "sha1": "169d47dd"},
  "win-release/media_tests_av_perf/audio_latency/latency_bg_clip": {"reva": 199840, "revb": 201303, "type": "absolute", "better": "lower", "improve": 66, "regress": 78, "sha1": "708a71af"},
@@ -737,7 +737,7 @@
  "win-release/media_tests_av_perf/ttp/Wifi_roller.webm": {"reva": 175328, "revb": 176157, "type": "absolute", "better": "lower", "improve": 906.775, "regress": 1184.925, "sha1": "d49e638f"},
  "xp-release/sizes/chrome.dll/chrome.dll": {"reva": 309071, "revb": 309081, "type": "absolute", "better": "lower", "improve": 36382233, "regress": 40213018, "sha1": "af511cf1"},
  "xp-release/sizes/chrome.exe/chrome.exe": {"reva": 309071, "revb": 309081, "type": "absolute", "better": "lower", "improve": 612377, "regress": 676839, "sha1": "63dbfdc5"},
- "xp-release/sizes/chrome_child.dll/chrome_child.dll": {"reva": 309071, "revb": 309220, "type": "absolute", "better": "lower", "improve": 36496051, "regress": 40345268, "sha1": "5e748540"},
+ "xp-release/sizes/chrome_child.dll/chrome_child.dll": {"reva": 314576, "revb": 314588, "type": "absolute", "better": "lower", "improve": 39555993, "regress": 43720858, "sha1": "46896665"},
  "xp-release/sizes/mini_installer.exe/mini_installer.exe": {"reva": 296771, "revb": 296791, "type": "absolute", "better": "lower", "improve": 32967219, "regress": 36469709, "sha1": "f4744be2"},
  "xp-release/sizes/setup.exe/setup.exe": {"reva": 309071, "revb": 309081, "type": "absolute", "better": "lower", "improve": 933888, "regress": 1032192, "sha1": "a257fcad"},
  "load": true
diff --git a/tools/profile_chrome/chrome_controller.py b/tools/profile_chrome/chrome_controller.py
index 9f52263..d8cff46 100644
--- a/tools/profile_chrome/chrome_controller.py
+++ b/tools/profile_chrome/chrome_controller.py
@@ -9,7 +9,7 @@
 
 from profile_chrome import controllers
 
-from pylib import pexpect
+from pylib.device import device_errors
 from pylib.device import intent
 
 
@@ -23,6 +23,7 @@
     self._package_info = package_info
     self._categories = categories
     self._ring_buffer = ring_buffer
+    self._logcat_monitor = self._device.GetLogcatMonitor()
     self._trace_file = None
     self._trace_interval = None
     self._trace_memory = trace_memory
@@ -31,21 +32,21 @@
        re.compile(r'Logging performance trace to file')
     self._trace_finish_re = \
        re.compile(r'Profiler finished[.] Results are in (.*)[.]')
-    self._device.old_interface.StartMonitoringLogcat(clear=False)
 
   def __repr__(self):
     return 'chrome trace'
 
   @staticmethod
   def GetCategories(device, package_info):
-    device.BroadcastIntent(intent.Intent(
-        action='%s.GPU_PROFILER_LIST_CATEGORIES' % package_info.package))
-    try:
-      json_category_list = device.old_interface.WaitForLogMatch(
-          re.compile(r'{"traceCategoriesList(.*)'), None, timeout=5).group(0)
-    except pexpect.TIMEOUT:
-      raise RuntimeError('Performance trace category list marker not found. '
-                         'Is the correct version of the browser running?')
+    with device.GetLogcatMonitor() as logmon:
+      device.BroadcastIntent(intent.Intent(
+          action='%s.GPU_PROFILER_LIST_CATEGORIES' % package_info.package))
+      try:
+        json_category_list = logmon.WaitFor(
+            re.compile(r'{"traceCategoriesList(.*)'), timeout=5).group(0)
+      except device_errors.CommandTimeoutError:
+        raise RuntimeError('Performance trace category list marker not found. '
+                           'Is the correct version of the browser running?')
 
     record_categories = set()
     disabled_by_default_categories = set()
@@ -61,7 +62,7 @@
 
   def StartTracing(self, interval):
     self._trace_interval = interval
-    self._device.old_interface.SyncLogCat()
+    self._logcat_monitor.Start()
     start_extras = {'categories': ','.join(self._categories)}
     if self._ring_buffer:
       start_extras['continuous'] = None
@@ -70,7 +71,7 @@
         extras=start_extras))
 
     if self._trace_memory:
-      self._device.old_interface.EnableAdbRoot()
+      self._device.EnableRoot()
       self._device.SetProp(_HEAP_PROFILE_MMAP_PROPERTY, 1)
 
     # Chrome logs two different messages related to tracing:
@@ -81,10 +82,9 @@
     # The first one is printed when tracing starts and the second one indicates
     # that the trace file is ready to be pulled.
     try:
-      self._device.old_interface.WaitForLogMatch(
-          self._trace_start_re, None, timeout=5)
+      self._logcat_monitor.WaitFor(self._trace_start_re, timeout=5)
       self._is_tracing = True
-    except pexpect.TIMEOUT:
+    except device_errors.CommandTimeoutError:
       raise RuntimeError('Trace start marker not found. Is the correct version '
                          'of the browser running?')
 
@@ -92,8 +92,8 @@
     if self._is_tracing:
       self._device.BroadcastIntent(intent.Intent(
           action='%s.GPU_PROFILER_STOP' % self._package_info.package))
-      self._trace_file = self._device.old_interface.WaitForLogMatch(
-          self._trace_finish_re, None, timeout=120).group(1)
+      self._trace_file = self._logcat_monitor.WaitFor(
+          self._trace_finish_re, timeout=120).group(1)
       self._is_tracing = False
     if self._trace_memory:
       self._device.SetProp(_HEAP_PROFILE_MMAP_PROPERTY, 0)
diff --git a/tools/profile_chrome/chrome_startup_controller.py b/tools/profile_chrome/chrome_startup_controller.py
index 8852cfe6..d685502 100644
--- a/tools/profile_chrome/chrome_startup_controller.py
+++ b/tools/profile_chrome/chrome_startup_controller.py
@@ -16,10 +16,10 @@
     self._device = device
     self._package_info = package_info
     self._cold = cold
+    self._logcat_monitor = self._device.GetLogcatMonitor()
     self._url = url
     self._trace_file = None
     self._trace_finish_re = re.compile(r' Completed startup tracing to (.*)')
-    self._device.old_interface.StartMonitoringLogcat(clear=False)
 
   def __repr__(self):
     return 'Browser Startup Trace'
@@ -30,15 +30,16 @@
     changer = flag_changer.FlagChanger(
         self._device, self._package_info.cmdline_file)
     changer.AddFlags(['--trace-startup'])
-    self._device.old_interface.CloseApplication(self._package_info.package)
+    self._device.ForceStop(self._package_info.package)
     if self._cold:
-      self._device.old_interface.EnableAdbRoot()
+      self._device.EnableRoot()
       cache_control.CacheControl(self._device).DropRamCaches()
-    self._device.old_interface.StartActivity(
-        package=self._package_info.package,
-        activity=self._package_info.activity,
-        data=self._url,
-        extras={'create_new_tab' : True})
+    self._device.StartActivity(
+        intent.Intent(
+            package=self._package_info.package,
+            activity=self._package_info.activity,
+            data=self._url,
+            extras={'create_new_tab' : True}))
 
   def _TearDownTracing(self):
     changer = flag_changer.FlagChanger(
@@ -47,12 +48,12 @@
 
   def StartTracing(self, interval):
     self._SetupTracing()
-    self._device.old_interface.SyncLogCat()
+    self._logcat_monitor.Start()
 
   def StopTracing(self):
     try:
-      self._trace_file = self._device.old_interface.WaitForLogMatch(
-          self._trace_finish_re, None, timeout=10).group(1)
+      self._trace_file = self._logcat_monitor.WaitFor(
+          self._trace_finish_re).group(1)
     finally:
       self._TearDownTracing()
 
diff --git a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py
index 40e84ff..4a06c12 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/android_browser_finder.py
@@ -200,14 +200,13 @@
   return possible_browsers
 
 
-def FindAllAvailableBrowsers(finder_options):
+def FindAllAvailableBrowsers(finder_options, device):
   """Finds all the possible browsers on one device.
 
   The device is either the only device on the host platform,
   or |finder_options| specifies a particular device.
   """
-  device = android_device.GetDevice(finder_options)
-  if not device:
+  if not isinstance(device, android_device.AndroidDevice):
     return []
   android_platform = platform.GetPlatformForDevice(device, finder_options)
   return _FindAllPossibleBrowsers(finder_options, android_platform)
diff --git a/tools/telemetry/telemetry/core/backends/chrome/cros_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/cros_browser_finder.py
index 6c57c975..7acc298 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/cros_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/cros_browser_finder.py
@@ -16,10 +16,6 @@
 from telemetry.core.backends.chrome import cros_browser_with_oobe
 
 
-def _IsRunningOnCrOS():
-  return platform_module.GetHostPlatform().GetOSName() == 'chromeos'
-
-
 class PossibleCrOSBrowser(possible_browser.PossibleBrowser):
   """A launchable CrOS browser instance."""
   def __init__(self, browser_type, finder_options, cros_platform, is_guest):
@@ -65,14 +61,14 @@
     pass
 
 def SelectDefaultBrowser(possible_browsers):
-  if _IsRunningOnCrOS():
+  if cros_device.IsRunningOnCrOS():
     for b in possible_browsers:
       if b.browser_type == 'system':
         return b
   return None
 
 def CanFindAvailableBrowsers(finder_options):
-  return (_IsRunningOnCrOS() or
+  return (cros_device.IsRunningOnCrOS() or
           finder_options.cros_remote or
           cros_interface.HasSSH())
 
@@ -84,9 +80,12 @@
       'system-guest',
   ]
 
-def FindAllAvailableBrowsers(finder_options):
+def FindAllAvailableBrowsers(finder_options, device):
   """Finds all available CrOS browsers, locally and remotely."""
-  if _IsRunningOnCrOS():
+  if not isinstance(device, cros_device.CrOSDevice):
+    return []
+
+  if cros_device.IsRunningOnCrOS():
     return [PossibleCrOSBrowser('system', finder_options,
                                 platform_module.GetHostPlatform(),
                                 is_guest=False),
@@ -94,16 +93,6 @@
                                 platform_module.GetHostPlatform(),
                                 is_guest=True)]
 
-  if finder_options.cros_remote == None:
-    logging.debug('No --remote specified, will not probe for CrOS.')
-    return []
-
-  if not cros_interface.HasSSH():
-    logging.debug('ssh not found. Cannot talk to CrOS devices.')
-    return []
-  device = cros_device.CrOSDevice(
-      finder_options.cros_remote, finder_options.cros_remote_ssh_port,
-      finder_options.cros_ssh_identity)
   # Check ssh
   try:
     platform = platform_module.GetPlatformForDevice(device, finder_options)
diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py
index e396081..e2fba9e 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder.py
@@ -13,6 +13,7 @@
 from telemetry.core import exceptions
 from telemetry.core import possible_browser
 from telemetry.core.backends.chrome import desktop_browser_backend
+from telemetry.core.platform import desktop_device
 from telemetry.util import path
 
 
@@ -113,8 +114,11 @@
       'content-shell-release_x64',
       'system']
 
-def FindAllAvailableBrowsers(finder_options):
+def FindAllAvailableBrowsers(finder_options, device):
   """Finds all the desktop browsers available on this machine."""
+  if not isinstance(device, desktop_device.DesktopDevice):
+    return []
+
   browsers = []
 
   if not CanFindAvailableBrowsers():
diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder_unittest.py
index 8f8dc1f2..14abe60 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_finder_unittest.py
@@ -5,6 +5,7 @@
 
 from telemetry.core import browser_options
 from telemetry.core.backends.chrome import desktop_browser_finder
+from telemetry.core.platform import desktop_device
 from telemetry.unittest_util import system_stub
 
 
@@ -32,7 +33,8 @@
     return self._path_stubs.os.path.files
 
   def DoFindAll(self):
-    return desktop_browser_finder.FindAllAvailableBrowsers(self._finder_options)
+    return desktop_browser_finder.FindAllAvailableBrowsers(
+      self._finder_options, desktop_device.DesktopDevice())
 
   def DoFindAllTypes(self):
     browsers = self.DoFindAll()
diff --git a/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder.py b/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder.py
index f8dd74e..771fd5eb 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder.py
@@ -14,6 +14,7 @@
 from telemetry.core import possible_browser
 from telemetry.core.backends.chrome_inspector import inspector_backend
 from telemetry.core.backends.chrome import ios_browser_backend
+from telemetry.core.platform import ios_device
 from telemetry.core.platform import ios_platform_backend
 
 
@@ -66,21 +67,12 @@
   return IOS_BROWSERS.values()
 
 
-@decorators.Cache
-def _IsIosDeviceAttached():
-  devices = subprocess.check_output('system_profiler SPUSBDataType', shell=True)
-  for line in devices.split('\n'):
-    if line and re.match(r'\s*(iPod|iPhone|iPad):', line):
-      return True
-  return False
-
-
-def FindAllAvailableBrowsers(finder_options):
+def FindAllAvailableBrowsers(finder_options, device):
   """Find all running iOS browsers on connected devices."""
-  if not CanFindAvailableBrowsers():
+  if not isinstance(device, ios_device.IOSDevice):
     return []
 
-  if not _IsIosDeviceAttached():
+  if not CanFindAvailableBrowsers():
     return []
 
   options = finder_options.browser_options
diff --git a/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder_unittest.py b/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder_unittest.py
index e9e9042..e0e783fb 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/ios_browser_finder_unittest.py
@@ -6,6 +6,7 @@
 from telemetry import decorators
 from telemetry.core import browser_options
 from telemetry.core.backends.chrome import ios_browser_finder
+from telemetry.core.platform import ios_device
 
 
 class IosBrowserFinderUnitTest(unittest.TestCase):
@@ -15,7 +16,8 @@
   @decorators.Enabled('ios')
   def testFindIosChrome(self):
     finder_options = browser_options.BrowserFinderOptions()
-    browsers = ios_browser_finder.FindAllAvailableBrowsers(finder_options)
+    browsers = ios_browser_finder.FindAllAvailableBrowsers(
+      finder_options, ios_device.IOSDevice())
     self.assertTrue(browsers)
     for browser in browsers:
       self.assertEqual('ios-chrome', browser.browser_type)
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_network_unittest.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_network_unittest.py
index 44c29a66..7b7bd9d 100644
--- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_network_unittest.py
+++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_network_unittest.py
@@ -32,7 +32,8 @@
     self.assertTrue(self._tab.timeline_model)
     return self._tab.timeline_model.GetAllEventsOfName('HTTPResponse')
 
-  @decorators.Disabled('mac', 'android')  # crbug.com/449979, crbug.com/452279
+  # crbug.com/449979, crbug.com/452279, crbug.com/455269
+  @decorators.Disabled('mac', 'android', 'win')
   def testHTTPResponseTimelineRecorder(self):
     tests = {
         'blank.html': InspectorNetworkTabTest.TestCase(),
diff --git a/tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py b/tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py
index 2e240c9..ea7143ca 100644
--- a/tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/remote/trybot_browser_finder.py
@@ -15,12 +15,14 @@
 from telemetry import decorators
 from telemetry.core import platform
 from telemetry.core import possible_browser
+from telemetry.core.platform import trybot_device
 
 CHROMIUM_CONFIG_FILENAME = 'tools/run-perf-test.cfg'
 BLINK_CONFIG_FILENAME = 'Tools/run-perf-test.cfg'
 SUCCESS, NO_CHANGES, ERROR = range(3)
 
 
+
 class PossibleTrybotBrowser(possible_browser.PossibleBrowser):
   """A script that sends a job to a trybot."""
 
@@ -34,7 +36,7 @@
     raise NotImplementedError()
 
   def SupportsOptions(self, finder_options):
-    if (finder_options.android_device or
+    if ((finder_options.device and finder_options.device != 'trybot') or
         finder_options.chrome_root or
         finder_options.cros_remote or
         finder_options.extensions_to_load or
@@ -250,7 +252,10 @@
   return []
 
 
-def FindAllAvailableBrowsers(finder_options):
+def FindAllAvailableBrowsers(finder_options, device):
   """Find all perf trybots on tryserver.chromium.perf."""
+  if not isinstance(device, trybot_device.TrybotDevice):
+    return []
+
   return [PossibleTrybotBrowser(b, finder_options) for b in
           FindAllBrowserTypes(finder_options)]
diff --git a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_desktop_browser_finder.py b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_desktop_browser_finder.py
index 66b4aec..0373e1c 100644
--- a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_desktop_browser_finder.py
+++ b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_desktop_browser_finder.py
@@ -12,6 +12,7 @@
 from telemetry.core import possible_browser
 from telemetry.core import util
 from telemetry.core.backends.webdriver import webdriver_ie_backend
+from telemetry.core.platform import desktop_device
 from telemetry.util import support_binaries
 
 # Try to import the selenium python lib which may be not available.
@@ -96,8 +97,11 @@
                     'https://code.google.com/p/selenium/wiki/PythonBindings.')
   return []
 
-def FindAllAvailableBrowsers(finder_options):
+def FindAllAvailableBrowsers(finder_options, device):
   """Finds all the desktop browsers available on this machine."""
+  if not isinstance(device, desktop_device.DesktopDevice):
+    return []
+
   browsers = []
   if not webdriver:
     return browsers
diff --git a/tools/telemetry/telemetry/core/browser_finder.py b/tools/telemetry/telemetry/core/browser_finder.py
index eb189af..f98317b3 100644
--- a/tools/telemetry/telemetry/core/browser_finder.py
+++ b/tools/telemetry/telemetry/core/browser_finder.py
@@ -9,6 +9,7 @@
 
 from telemetry import decorators
 from telemetry.core import browser_finder_exceptions
+from telemetry.core import device_finder
 from telemetry.core.backends.chrome import android_browser_finder
 from telemetry.core.backends.chrome import cros_browser_finder
 from telemetry.core.backends.chrome import desktop_browser_finder
@@ -60,17 +61,24 @@
     raise browser_finder_exceptions.BrowserFinderException(
         '--remote requires --browser=cros-chrome or cros-chrome-guest.')
 
+  devices = []
+  if options.device and options.device != 'list':
+    devices = device_finder.GetSpecifiedDevices(options)
+  else:
+    devices = device_finder.GetAllAvailableDevices(options)
+
   browsers = []
   default_browsers = []
-  for finder in BROWSER_FINDERS:
-    if(options.browser_type and options.browser_type != 'any' and
-       options.browser_type not in finder.FindAllBrowserTypes(options)):
-      continue
-    curr_browsers = finder.FindAllAvailableBrowsers(options)
-    new_default_browser = finder.SelectDefaultBrowser(curr_browsers)
-    if new_default_browser:
-      default_browsers.append(new_default_browser)
-    browsers.extend(curr_browsers)
+  for device in devices:
+    for finder in BROWSER_FINDERS:
+      if(options.browser_type and options.browser_type != 'any' and
+         options.browser_type not in finder.FindAllBrowserTypes(options)):
+        continue
+      curr_browsers = finder.FindAllAvailableBrowsers(options, device)
+      new_default_browser = finder.SelectDefaultBrowser(curr_browsers)
+      if new_default_browser:
+        default_browsers.append(new_default_browser)
+      browsers.extend(curr_browsers)
 
   if options.browser_type == None:
     if default_browsers:
@@ -125,6 +133,29 @@
 
 
 @decorators.Cache
+def GetAllAvailableBrowsers(options, device):
+  """Returns a list of available browsers on the device.
+
+  Args:
+    options: A BrowserOptions object.
+    device: The target device, which can be None.
+
+  Returns:
+    A list of browser instances.
+
+  Raises:
+    BrowserFinderException: Options are improperly set, or an error occurred.
+  """
+  if not device:
+    return []
+  possible_browsers = []
+  for browser_finder in BROWSER_FINDERS:
+    possible_browsers.extend(
+      browser_finder.FindAllAvailableBrowsers(options, device))
+  return possible_browsers
+
+
+@decorators.Cache
 def GetAllAvailableBrowserTypes(options):
   """Returns a list of available browser types.
 
@@ -137,11 +168,11 @@
   Raises:
     BrowserFinderException: Options are improperly set, or an error occurred.
   """
-  browsers = []
-  for finder in BROWSER_FINDERS:
-    browsers.extend(finder.FindAllAvailableBrowsers(options))
-
-  type_list = set([browser.browser_type for browser in browsers])
+  devices = device_finder.GetAllAvailableDevices(options)
+  possible_browsers = []
+  for device in devices:
+    possible_browsers.extend(GetAllAvailableBrowsers(options, device))
+  type_list = set([browser.browser_type for browser in possible_browsers])
   type_list = list(type_list)
   type_list.sort()
   return type_list
diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py
index 43e5793..3a790386 100644
--- a/tools/telemetry/telemetry/core/browser_options.py
+++ b/tools/telemetry/telemetry/core/browser_options.py
@@ -12,6 +12,7 @@
 
 from telemetry.core import browser_finder
 from telemetry.core import browser_finder_exceptions
+from telemetry.core import device_finder
 from telemetry.core import platform
 from telemetry.core import profile_types
 from telemetry.core import util
@@ -32,7 +33,7 @@
     self.browser_type = browser_type
     self.browser_executable = None
     self.chrome_root = None
-    self.android_device = None
+    self.device = None
     self.cros_ssh_identity = None
 
     self.extensions_to_load = []
@@ -76,8 +77,8 @@
         help='Where to look for chrome builds.'
              'Defaults to searching parent dirs by default.')
     group.add_option('--device',
-        dest='android_device',
-        help='The android device ID to use'
+        dest='device',
+        help='The device ID to use.'
              'If not specified, only 0 or 1 connected devices are supported.')
     group.add_option('--target-arch',
         dest='target_arch',
@@ -159,16 +160,40 @@
       else:
         logging.getLogger().setLevel(logging.WARNING)
 
+      if self.device == 'list':
+        devices = device_finder.GetAllAvailableDeviceNames(self)
+        print 'Available devices:'
+        for device in devices:
+          print ' ', device
+        sys.exit(0)
+
       if self.browser_executable and not self.browser_type:
         self.browser_type = 'exact'
       if self.browser_type == 'list':
-        try:
-          types = browser_finder.GetAllAvailableBrowserTypes(self)
-        except browser_finder_exceptions.BrowserFinderException, ex:
-          sys.stderr.write('ERROR: ' + str(ex))
-          sys.exit(1)
-        sys.stdout.write('Available browsers:\n')
-        sys.stdout.write('  %s\n' % '\n  '.join(types))
+        devices = []
+        if self.device and self.device != 'list':
+          devices = device_finder.GetSpecifiedDevices(self)
+        else:
+          devices = device_finder.GetAllAvailableDevices(self)
+        if not devices:
+          sys.exit(0)
+        browser_types = {}
+        for device in devices:
+          try:
+            possible_browsers = browser_finder.GetAllAvailableBrowsers(self,
+                                                                       device)
+            browser_types[device.name] = sorted(
+              [browser.browser_type for browser in possible_browsers])
+          except browser_finder_exceptions.BrowserFinderException as ex:
+            print >> sys.stderr, 'ERROR: ', ex
+            sys.exit(1)
+        print 'Available browsers:'
+        if len(browser_types) == 0:
+          print '  No devices were found.'
+        for device_name in sorted(browser_types.keys()):
+          print '  ', device_name
+          for browser_type in browser_types[device_name]:
+            print '    ', browser_type
         sys.exit(0)
 
       # Parse browser options.
diff --git a/tools/telemetry/telemetry/core/device_finder.py b/tools/telemetry/telemetry/core/device_finder.py
new file mode 100644
index 0000000..dbe0115
--- /dev/null
+++ b/tools/telemetry/telemetry/core/device_finder.py
@@ -0,0 +1,45 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Finds devices that can be controlled by telemetry."""
+
+import logging
+
+from telemetry.core.platform import android_device
+from telemetry.core.platform import cros_device
+from telemetry.core.platform import desktop_device
+from telemetry.core.platform import ios_device
+from telemetry.core.platform import trybot_device
+
+DEVICES = [
+  android_device,
+  cros_device,
+  desktop_device,
+  ios_device,
+  trybot_device,
+]
+
+
+def GetAllAvailableDevices(options):
+  """Returns a list of all available devices."""
+  devices = []
+  for device in DEVICES:
+    devices.extend(device.FindAllAvailableDevices(options))
+  devices.sort(key=lambda device: device.name)
+  return devices
+
+
+def GetAllAvailableDeviceNames(options):
+  """Returns a list of all available device names."""
+  devices = GetAllAvailableDevices(options)
+  device_names = [device.name for device in devices]
+  return device_names
+
+
+def GetSpecifiedDevices(options):
+  """Returns the specified devices."""
+  assert options.device and options.device != 'list'
+  devices = GetAllAvailableDevices(options)
+  devices = [d for d in devices if d.guid == options.device]
+  return devices
diff --git a/tools/telemetry/telemetry/core/platform/android_action_runner.py b/tools/telemetry/telemetry/core/platform/android_action_runner.py
new file mode 100644
index 0000000..aa8eda6
--- /dev/null
+++ b/tools/telemetry/telemetry/core/platform/android_action_runner.py
@@ -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.
+
+import time
+
+
+class ActionNotSupported(Exception):
+  pass
+
+
+class AndroidActionRunner(object):
+  """Provides an API for interacting with an android device.
+
+  This makes use of functionality provided by the android input command. None
+  of the gestures here are guaranteed to be performant for telemetry tests and
+  there is no official support for this API.
+
+  TODO(ariblue): Replace this API with a better implementation for interacting
+  with native components.
+  """
+
+  def __init__(self, platform_backend):
+    self._platform_backend = platform_backend
+
+  def SmoothScrollBy(self, left_start_coord, top_start_coord, direction,
+                     scroll_distance):
+    """Perfrom gesture to scroll down on the android device.
+    """
+    if direction not in ['down', 'up', 'left', 'right']:
+      raise ActionNotSupported('Invalid scroll direction: %s' % direction)
+
+    # This velocity is slower so that the exact distance we specify is the
+    # distance the page travels.
+    duration = scroll_distance
+
+    # Note that the default behavior is swiping up for scrolling down.
+    if direction == 'down':
+      left_end_coord = left_start_coord
+      top_end_coord = top_start_coord - scroll_distance
+    elif direction == 'up':
+      left_end_coord = left_start_coord
+      top_end_coord = top_start_coord + scroll_distance
+    elif direction == 'right':
+      left_end_coord = left_start_coord - scroll_distance
+      top_end_coord = top_start_coord
+    elif direction == 'left':
+      left_end_coord = left_start_coord + scroll_distance
+      top_end_coord = top_start_coord
+
+    self.InputSwipe(left_start_coord, top_start_coord, left_end_coord,
+                    top_end_coord, duration)
+
+  def Wait(self, seconds):
+    """Wait for the number of seconds specified.
+
+    Args:
+      seconds: The number of seconds to wait.
+    """
+    time.sleep(seconds)
+
+  def InputText(self, string):
+    """Convert the characters of the string into key events and send to device.
+
+    Args:
+      string: The string to send to the device.
+    """
+    self._platform_backend.adb.RunShellCommand('input text %s' % string)
+
+  def InputKeyEvent(self, key):
+    """Send a single key input to the device.
+
+    Args:
+      key: A key code number or name that will be sent to the device
+    """
+    self._platform_backend.adb.RunShellCommand('input keyevent %s' % key)
+
+  def InputTap(self, x_coord, y_coord):
+    """Perform a tap input at the given coordinates.
+
+    Args:
+      x_coord: The x coordinate of the tap event.
+      y_coord: The y coordinate of the tap event.
+    """
+    self._platform_backend.adb.RunShellCommand('input tap %s %s' % (x_coord,
+                                                                    y_coord))
+
+  def InputSwipe(self, left_start_coord, top_start_coord, left_end_coord,
+                 top_end_coord, duration):
+    """Perform a swipe input.
+
+    Args:
+      left_start_coord: The horizontal starting coordinate of the gesture
+      top_start_coord: The vertical starting coordinate of the gesture
+      left_end_coord: The horizontal ending coordinate of the gesture
+      top_end_coord: The vertical ending coordinate of the gesture
+      duration: The length of time of the swipe in milliseconds
+    """
+    self._platform_backend.adb.RunShellCommand(
+        'input swipe %s %s %s %s %s' % (left_start_coord, top_start_coord,
+                                        left_end_coord, top_end_coord,
+                                        duration))
+
+  def InputPress(self):
+    """Perform a press input."""
+    self._platform_backend.adb.RunShellCommand('input press')
+
+  def InputRoll(self, dx, dy):
+    """Perform a roll input. This sends a simple zero-pressure move event.
+
+    Args:
+      dx: Change in the x coordinate due to move.
+      dy: Change in the y coordinate due to move.
+    """
+    self._platform_backend.adb.RunShellCommand('input roll %s %s' % (dx, dy))
diff --git a/tools/telemetry/telemetry/core/platform/android_device.py b/tools/telemetry/telemetry/core/platform/android_device.py
index 73fad60..e04f2e0 100644
--- a/tools/telemetry/telemetry/core/platform/android_device.py
+++ b/tools/telemetry/telemetry/core/platform/android_device.py
@@ -31,31 +31,7 @@
 
   @classmethod
   def GetAllConnectedDevices(cls):
-    device_serials = adb_commands.GetAttachedDevices()
-    # The monsoon provides power for the device, so for devices with no
-    # real battery, we need to turn them on after the monsoon enables voltage
-    # output to the device.
-    if not device_serials:
-      try:
-        m = monsoon.Monsoon(wait=False)
-        m.SetUsbPassthrough(1)
-        m.SetVoltage(3.8)
-        m.SetMaxCurrent(8)
-        logging.warn("""
-Monsoon power monitor detected, but no Android devices.
-
-The Monsoon's power output has been enabled. Please now ensure that:
-
-  1. The Monsoon's front and back USB are connected to the host.
-  2. The device is connected to the Monsoon's main and USB channels.
-  3. The device is turned on.
-
-Waiting for device...
-""")
-        util.WaitFor(adb_commands.GetAttachedDevices, 600)
-        device_serials = adb_commands.GetAttachedDevices()
-      except IOError:
-        return []
+    device_serials = GetDeviceSerials()
     return [cls(s) for s in device_serials]
 
   @property
@@ -67,6 +43,35 @@
     return self._enable_performance_mode
 
 
+def GetDeviceSerials():
+  device_serials = adb_commands.GetAttachedDevices()
+  # The monsoon provides power for the device, so for devices with no
+  # real battery, we need to turn them on after the monsoon enables voltage
+  # output to the device.
+  if not device_serials:
+    try:
+      m = monsoon.Monsoon(wait=False)
+      m.SetUsbPassthrough(1)
+      m.SetVoltage(3.8)
+      m.SetMaxCurrent(8)
+      logging.warn("""
+Monsoon power monitor detected, but no Android devices.
+
+The Monsoon's power output has been enabled. Please now ensure that:
+
+  1. The Monsoon's front and back USB are connected to the host.
+  2. The device is connected to the Monsoon's main and USB channels.
+  3. The device is turned on.
+
+Waiting for device...
+""")
+      util.WaitFor(adb_commands.GetAttachedDevices, 600)
+      device_serials = adb_commands.GetAttachedDevices()
+    except IOError:
+      return []
+  return device_serials
+
+
 def GetDevice(finder_options):
   """Return a Platform instance for the device specified by |finder_options|."""
   if not CanDiscoverDevices():
@@ -74,9 +79,9 @@
         'No adb command found. Will not try searching for Android browsers.')
     return None
 
-  if finder_options.android_device:
+  if finder_options.device and finder_options.device in GetDeviceSerials():
     return AndroidDevice(
-        finder_options.android_device,
+        finder_options.device,
         enable_performance_mode=not finder_options.no_performance_mode)
 
   devices = AndroidDevice.GetAllConnectedDevices()
@@ -121,3 +126,11 @@
     return True
   return False
 
+
+def FindAllAvailableDevices(_):
+  """Returns a list of available devices.
+  """
+  if not CanDiscoverDevices():
+    return []
+  else:
+    return AndroidDevice.GetAllConnectedDevices()
diff --git a/tools/telemetry/telemetry/core/platform/android_device_unittest.py b/tools/telemetry/telemetry/core/platform/android_device_unittest.py
index ed7707a..6e7609b 100644
--- a/tools/telemetry/telemetry/core/platform/android_device_unittest.py
+++ b/tools/telemetry/telemetry/core/platform/android_device_unittest.py
@@ -83,7 +83,7 @@
 
   def testAdbPickOneDeviceReturnsDeviceInstance(self):
     finder_options = browser_options.BrowserFinderOptions()
-    finder_options.android_device = '555d14fecddddddd'  # pick one
+    finder_options.device = '555d14fecddddddd'  # pick one
     self._android_device_stub.adb_commands.attached_devices = [
         '015d14fec128220c', '555d14fecddddddd']
     device = android_device.GetDevice(finder_options)
@@ -97,3 +97,44 @@
     device = android_device.GetDevice(finder_options)
     self.assertEquals([], self._android_device_stub.logging.warnings)
     self.assertEquals('015d14fec128220c', device.device_id)
+
+
+class FindAllAvailableDevicesTest(unittest.TestCase):
+  def setUp(self):
+    self._android_device_stub = system_stub.Override(
+        android_device, ['adb_commands', 'os', 'subprocess', 'logging'])
+    self._apb_stub = system_stub.Override(
+        android_platform_backend, ['adb_commands'])
+
+  def tearDown(self):
+    self._android_device_stub.Restore()
+    self._apb_stub.Restore()
+
+  def testAdbNoDeviceReturnsEmptyList(self):
+    finder_options = browser_options.BrowserFinderOptions()
+    devices = android_device.FindAllAvailableDevices(finder_options)
+    self.assertEquals([], self._android_device_stub.logging.warnings)
+    self.assertIsNotNone(devices)
+    self.assertEquals(len(devices), 0)
+
+  def testAdbOneDeviceReturnsListWithOneDeviceInstance(self):
+    finder_options = browser_options.BrowserFinderOptions()
+    self._android_device_stub.adb_commands.attached_devices = (
+        ['015d14fec128220c'])
+    devices = android_device.FindAllAvailableDevices(finder_options)
+    self.assertEquals([], self._android_device_stub.logging.warnings)
+    self.assertIsNotNone(devices)
+    self.assertEquals(len(devices), 1)
+    self.assertEquals('015d14fec128220c', devices[0].device_id)
+
+  def testAdbMultipleDevicesReturnsListWithAllDeviceInstances(self):
+    finder_options = browser_options.BrowserFinderOptions()
+    self._android_device_stub.adb_commands.attached_devices = [
+        '015d14fec128220c', '015d14fec128220d', '015d14fec128220e']
+    devices = android_device.FindAllAvailableDevices(finder_options)
+    self.assertEquals([], self._android_device_stub.logging.warnings)
+    self.assertIsNotNone(devices)
+    self.assertEquals(len(devices), 3)
+    self.assertEquals(devices[0].guid, '015d14fec128220c')
+    self.assertEquals(devices[1].guid, '015d14fec128220d')
+    self.assertEquals(devices[2].guid, '015d14fec128220e')
diff --git a/tools/telemetry/telemetry/core/platform/android_platform.py b/tools/telemetry/telemetry/core/platform/android_platform.py
index 6d22a7d..a5d40b7 100644
--- a/tools/telemetry/telemetry/core/platform/android_platform.py
+++ b/tools/telemetry/telemetry/core/platform/android_platform.py
@@ -6,11 +6,18 @@
 from telemetry.core import android_app
 from telemetry.core import platform
 from telemetry.core.backends import android_app_backend
+from telemetry.core.platform import android_action_runner
 
 class AndroidPlatform(platform.Platform):
 
   def __init__(self, platform_backend):
     super(AndroidPlatform, self).__init__(platform_backend)
+    self._android_action_runner = android_action_runner.AndroidActionRunner(
+        platform_backend)
+
+  @property
+  def android_action_runner(self):
+    return self._android_action_runner
 
   def LaunchAndroidApplication(self, start_intent, is_app_ready_predicate=None):
     """Launches an Android application given the intent.
diff --git a/tools/telemetry/telemetry/core/platform/cros_device.py b/tools/telemetry/telemetry/core/platform/cros_device.py
index 4bb49ad..b4a09ac 100644
--- a/tools/telemetry/telemetry/core/platform/cros_device.py
+++ b/tools/telemetry/telemetry/core/platform/cros_device.py
@@ -1,6 +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.
+import logging
+
+from telemetry.core import platform
+from telemetry.core.platform import cros_interface
 from telemetry.core.platform import device
 
 
@@ -29,3 +33,25 @@
   @property
   def ssh_identity(self):
     return self._ssh_identity
+
+
+def IsRunningOnCrOS():
+  return platform.GetHostPlatform().GetOSName() == 'chromeos'
+
+
+def FindAllAvailableDevices(options):
+  """Returns a list of available device types.
+  """
+  if IsRunningOnCrOS():
+    return [CrOSDevice('localhost', -1)]
+
+  if options.cros_remote == None:
+    logging.debug('No --remote specified, will not probe for CrOS.')
+    return []
+
+  if not cros_interface.HasSSH():
+    logging.debug('ssh not found. Cannot talk to CrOS devices.')
+    return []
+
+  return [CrOSDevice(options.cros_remote, options.cros_remote_ssh_port,
+                     options.cros_ssh_identity)]
diff --git a/tools/telemetry/telemetry/core/platform/desktop_device.py b/tools/telemetry/telemetry/core/platform/desktop_device.py
new file mode 100644
index 0000000..4d68863
--- /dev/null
+++ b/tools/telemetry/telemetry/core/platform/desktop_device.py
@@ -0,0 +1,24 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from telemetry.core import platform
+from telemetry.core.platform import device
+
+
+class DesktopDevice(device.Device):
+  def __init__(self):
+    super(DesktopDevice, self).__init__(name='desktop', guid='desktop')
+
+  @classmethod
+  def GetAllConnectedDevices(cls):
+    return []
+
+
+def FindAllAvailableDevices(_):
+  """Returns a list of available devices.
+  """
+  # If the host platform is Chrome OS, the device is also considered as cros.
+  if platform.GetHostPlatform().GetOSName() == 'chromeos':
+    return []
+  return [DesktopDevice()]
\ No newline at end of file
diff --git a/tools/telemetry/telemetry/core/platform/ios_device.py b/tools/telemetry/telemetry/core/platform/ios_device.py
new file mode 100644
index 0000000..0cec05e
--- /dev/null
+++ b/tools/telemetry/telemetry/core/platform/ios_device.py
@@ -0,0 +1,40 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import re
+import subprocess
+
+from telemetry.core import platform
+from telemetry.core.platform import device
+
+
+class IOSDevice(device.Device):
+  def __init__(self):
+    super(IOSDevice, self).__init__(name='ios', guid='ios')
+
+  @classmethod
+  def GetAllConnectedDevices(cls):
+    return []
+
+
+def _IsIosDeviceAttached():
+  devices = subprocess.check_output('system_profiler SPUSBDataType', shell=True)
+  for line in devices.split('\n'):
+    if line and re.match(r'\s*(iPod|iPhone|iPad):', line):
+      return True
+  return False
+
+
+def FindAllAvailableDevices(_):
+  """Returns a list of available devices.
+  """
+  # TODO(baxley): Add support for all platforms possible. Probably Linux,
+  # probably not Windows.
+  if platform.GetHostPlatform().GetOSName() != 'mac':
+    return []
+
+  if not _IsIosDeviceAttached():
+    return []
+
+  return [IOSDevice()]
\ No newline at end of file
diff --git a/tools/telemetry/telemetry/core/platform/trybot_device.py b/tools/telemetry/telemetry/core/platform/trybot_device.py
new file mode 100644
index 0000000..cdb904f4
--- /dev/null
+++ b/tools/telemetry/telemetry/core/platform/trybot_device.py
@@ -0,0 +1,20 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from telemetry.core.platform import device
+
+
+class TrybotDevice(device.Device):
+  def __init__(self):
+    super(TrybotDevice, self).__init__(name='trybot', guid='trybot')
+
+  @classmethod
+  def GetAllConnectedDevices(cls):
+    return []
+
+
+def FindAllAvailableDevices(_):
+  """Returns a list of available devices.
+  """
+  return [TrybotDevice()]
\ No newline at end of file
diff --git a/tools/telemetry/telemetry/page/actions/action_runner.py b/tools/telemetry/telemetry/page/actions/action_runner.py
index 090370d..140deab93 100644
--- a/tools/telemetry/telemetry/page/actions/action_runner.py
+++ b/tools/telemetry/telemetry/page/actions/action_runner.py
@@ -130,8 +130,14 @@
         timeout_in_seconds=timeout_in_seconds))
 
   def WaitForNavigate(self, timeout_in_seconds_seconds=60):
+    start_time = time.time()
     self._tab.WaitForNavigate(timeout_in_seconds_seconds)
-    self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+
+    time_left_in_seconds = (start_time + timeout_in_seconds_seconds
+        - time.time())
+    time_left_in_seconds = max(0, time_left_in_seconds)
+    self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter(
+        time_left_in_seconds)
 
   def ReloadPage(self):
     """Reloads the page."""
diff --git a/tools/telemetry/telemetry/page/actions/navigate.py b/tools/telemetry/telemetry/page/actions/navigate.py
index cc4a0a4..a1ecb4d 100644
--- a/tools/telemetry/telemetry/page/actions/navigate.py
+++ b/tools/telemetry/telemetry/page/actions/navigate.py
@@ -1,6 +1,9 @@
 # Copyright 2013 The Chromium 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 time
+
 from telemetry.page.actions import page_action
 
 
@@ -14,7 +17,13 @@
     self._timeout_in_seconds = timeout_in_seconds
 
   def RunAction(self, tab):
+    start_time = time.time()
     tab.Navigate(self._url,
                  self._script_to_evaluate_on_commit,
                  self._timeout_in_seconds)
-    tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+
+    time_left_in_seconds = (start_time + self._timeout_in_seconds
+        - time.time())
+    time_left_in_seconds = max(0, time_left_in_seconds)
+    tab.WaitForDocumentReadyStateToBeInteractiveOrBetter(
+        time_left_in_seconds)
diff --git a/tools/ubsan/blacklist.txt b/tools/ubsan/blacklist.txt
index b9ab7824..5b4751fe 100644
--- a/tools/ubsan/blacklist.txt
+++ b/tools/ubsan/blacklist.txt
@@ -89,6 +89,9 @@
 # obj/third_party/libwebm/libwebm.a(obj/third_party/libwebm/source/libwebm.mkvmuxer.o)(.data.rel..L__unnamed_2+0x18): error: undefined reference to 'typeinfo for mkvparser::IMkvReader'
 src:*/third_party/libwebm/source/mkvmuxer.cpp
 
+# obj/content/libcontent_renderer.a(obj/content/renderer/scheduler/content_renderer.renderer_scheduler_impl.o)(.data.rel..L__unnamed_399+0x18): error: undefined reference to '  typeinfo for cc::TestNowSource'
+type:*TestNowSource*
+
 #############################################################################
 # UBSan seems to be emit false positives when virtual base classes are
 # involved, see e.g. chromium:448102
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 876d6f7..fb1861f 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -461,11 +461,12 @@
 name=http://crbug.com/371348
 system call NtCreateSection
 KERNELBASE.dll!CreateFileMappingW
-base.dll!base::SharedMemory::Create
-base.dll!base::SharedMemory::CreateAnonymous
-content.dll!content::ChildThread::AllocateSharedMemory
-content.dll!content::ChildSharedBitmapManager::AllocateSharedBitmap
-cc.dll!cc::ResourceProvider::CreateBitmap
+*!base::SharedMemory::Create
+*!base::SharedMemory::CreateAnonymous
+*!content::ChildThreadImpl::AllocateSharedMemory
+...
+*!content::ChildSharedBitmapManager::AllocateSharedBitmap
+*!cc::ResourceProvider::CreateBitmap
 
 HANDLE LEAK
 name=http://crbug.com/371357
@@ -711,3 +712,20 @@
 KERNELBASE.dll!OpenProcess
 base.dll!base::Process::OpenWithExtraPriviles
 content.dll!content::BrowserMessageFilter::Internal::OnChannelConnected
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/455060
+*!content::FrameAccessibility::GetParent
+*!content::RenderFrameHostImpl::AccessibilityGetParentFrame
+*!content::BrowserAccessibilityManager::GetDelegateFromRootManager
+*!content::BrowserAccessibilityManager::OnWindowBlurred
+...
+*!content::RenderWidgetHostViewAura::Destroy
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/455066
+system call NtReadFile parameter #4
+KERNELBASE.dll!ReadFile
+KERNEL32.dll!ReadFile
+*!net::FileStream::Context::ReadAsync
+*!base::internal::RunnableAdapter<>::Run
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index 2036d21..beb52f8 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1890,10 +1890,5 @@
 *!testing::internal::HandleExceptionsInMethodIfSupported<>
 
 UNINITIALIZED READ
-name=bug_446256
-*!`anonymous namespace'::GraphicsContextTest_trackDisplayListRecording_Test::TestBody
-*!testing::internal::HandleExceptionsInMethodIfSupported<>
-
-UNINITIALIZED READ
 name=bug_399842
 skia.dll!S32A_Opaque_BlitRow32_SSE4
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
index 5a8f1bc..a43a673 100644
--- a/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
+++ b/tools/valgrind/gtest_exclude/unit_tests.gtest_linux.txt
@@ -32,6 +32,3 @@
 
 # http://crbug.com/403533
 ExtensionPathUtilTest.BasicPrettifyPathTest
-
-# http://crbug.com/452071
-SupervisedUserServiceExtensionTest.InstallContentPacks
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 579b481..fea7c3b 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -3401,10 +3401,10 @@
    bug_431213
    Memcheck:Leak
    fun:_Znw*
-   fun:_ZN3gin22CreateFunctionTemplateIFSsPN4mojo2js13HandleWrapperEEEEN2v85LocalINS6_16FunctionTemplateEEEPNS6_7IsolateEN4base8CallbackIT_EEi
-   fun:_ZN3gin12_GLOBAL__N_114CallbackTraitsIMN4mojo2js13HandleWrapperEFSsvEvE14CreateTemplateEPN2v87IsolateES6_
-   fun:_ZN3gin21ObjectTemplateBuilder9SetMethodIMN4mojo2js13HandleWrapperEFSsvEEERS0_RKN4base16BasicStringPieceISsEERKT_
-   fun:_ZN4mojo2js13HandleWrapper24GetObjectTemplateBuilderEPN2v87IsolateE
+   fun:_ZN3gin22CreateFunctionTemplateIF*LocalINS6_16FunctionTemplateEEEPNS6_7IsolateEN4base8CallbackIT_EEi
+   fun:_ZN3gin12_GLOBAL__N_114CallbackTraitsIMN*CreateTemplateEPN2v87IsolateES6_
+   fun:_ZN3gin21ObjectTemplateBuilder9SetMethodIMN*0_RKN4base16BasicStringPieceISsEERKT_
+   fun:_ZN*24GetObjectTemplateBuilderEPN2v87IsolateE
 }
 {
    bug_436110
diff --git a/ui/accelerometer/BUILD.gn b/ui/accelerometer/BUILD.gn
deleted file mode 100644
index 4af13da..0000000
--- a/ui/accelerometer/BUILD.gn
+++ /dev/null
@@ -1,21 +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("//build/config/ui.gni")
-
-component("accelerometer") {
-  output_name = "ui_accelerometer"
-  sources = [
-    "accelerometer_types.cc",
-    "accelerometer_types.h",
-    "ui_accelerometer_export.h",
-  ]
-
-  defines = [ "UI_ACCELEROMETER_IMPLEMENTATION" ]
-
-  deps = [
-    "//base",
-    "//ui/gfx/geometry",
-  ]
-}
diff --git a/ui/accelerometer/DEPS b/ui/accelerometer/DEPS
deleted file mode 100644
index 3490ab2..0000000
--- a/ui/accelerometer/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+ui/gfx/geometry/vector3d_f.h"
-]
diff --git a/ui/accelerometer/ui_accelerometer.gyp b/ui/accelerometer/ui_accelerometer.gyp
deleted file mode 100644
index 94fc4377..0000000
--- a/ui/accelerometer/ui_accelerometer.gyp
+++ /dev/null
@@ -1,30 +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.
-
-{
-  'variables': {
-    'chromium_code': 1,
-  },
-  'targets': [
-    {
-      # GN version: //ui/accelerometer
-      'target_name': 'ui_accelerometer',
-      'type': '<(component)',
-      'dependencies': [
-        '../gfx/gfx.gyp:gfx_geometry',
-      ],
-      'defines': [
-        'UI_ACCELEROMETER_IMPLEMENTATION',
-      ],
-      'sources' : [
-        'accelerometer_types.cc',
-        'accelerometer_types.h',
-        'ui_accelerometer_export.h',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-    },
-  ],
-}
diff --git a/ui/accelerometer/ui_accelerometer_export.h b/ui/accelerometer/ui_accelerometer_export.h
deleted file mode 100644
index 97727f5f..0000000
--- a/ui/accelerometer/ui_accelerometer_export.h
+++ /dev/null
@@ -1,37 +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.
-
-#ifndef UI_ACCELEROMETER_UI_ACCELEROMETER_EXPORT_H_
-#define UI_ACCELEROMETER_UI_ACCELEROMETER_EXPORT_H_
-
-// Defines UI_ACCELEROMETER_EXPORT so that functionality implemented by the UI
-// accelerometer module can be exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-
-#if defined(WIN32)
-
-#if defined(UI_ACCELEROMETER_IMPLEMENTATION)
-#define UI_ACCELEROMETER_EXPORT __declspec(dllexport)
-#else
-#define UI_ACCELEROMETER_EXPORT __declspec(dllimport)
-#endif
-
-#else  // !defined(WIN32)
-
-#if defined(UI_ACCELEROMETER_IMPLEMENTATION)
-#define UI_ACCELEROMETER_EXPORT __attribute__((visibility("default")))
-#else
-#define UI_ACCELEROMETER_EXPORT
-#endif
-
-#endif
-
-#else  // !defined(COMPONENT_BUILD)
-
-#define UI_ACCELEROMETER_EXPORT
-
-#endif
-
-#endif  // UI_ACCELEROMETER_UI_ACCELEROMETER_EXPORT_H_
diff --git a/ui/app_list/DEPS b/ui/app_list/DEPS
index 184859b..ec495840 100644
--- a/ui/app_list/DEPS
+++ b/ui/app_list/DEPS
@@ -13,4 +13,5 @@
   "+ui/resources/grit/ui_resources.h",
   "+ui/strings/grit/ui_strings.h",
   "+ui/views",
+  "+ui/wm/core",
 ]
diff --git a/ui/app_list/app_list_unittests.isolate b/ui/app_list/app_list_unittests.isolate
index 4ceb64d..b6576867 100644
--- a/ui/app_list/app_list_unittests.isolate
+++ b/ui/app_list/app_list_unittests.isolate
@@ -22,6 +22,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../../testing/xvfb.py',
@@ -59,6 +61,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index e2d3e09..f2083749 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -45,6 +45,7 @@
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/views/bubble/bubble_window_targeter.h"
+#include "ui/wm/core/masked_window_targeter.h"
 #if defined(OS_WIN)
 #include "ui/base/win/shell.h"
 #endif
@@ -109,6 +110,29 @@
   DISALLOW_COPY_AND_ASSIGN(AppListOverlayView);
 };
 
+#if defined(USE_AURA)
+// An event targeter for the search box widget which will ignore events that
+// are on the search box's shadow.
+class SearchBoxWindowTargeter : public wm::MaskedWindowTargeter {
+ public:
+  explicit SearchBoxWindowTargeter(views::View* search_box)
+      : wm::MaskedWindowTargeter(search_box->GetWidget()->GetNativeWindow()),
+        search_box_(search_box) {}
+  ~SearchBoxWindowTargeter() override {}
+
+ private:
+  // wm::MaskedWindowTargeter:
+  bool GetHitTestMask(aura::Window* window, gfx::Path* mask) const override {
+    mask->addRect(gfx::RectToSkRect(search_box_->GetContentsBounds()));
+    return true;
+  }
+
+  views::View* search_box_;
+
+  DISALLOW_COPY_AND_ASSIGN(SearchBoxWindowTargeter);
+};
+#endif
+
 }  // namespace
 
 // An animation observer to hide the view at the end of the animation.
@@ -426,6 +450,13 @@
   search_box_widget_->Init(search_box_widget_params);
   search_box_widget_->SetContentsView(search_box_view_);
 
+#if defined(USE_AURA)
+  // Mouse events on the search box shadow should not be captured.
+  aura::Window* window = search_box_widget_->GetNativeWindow();
+  window->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
+      new SearchBoxWindowTargeter(search_box_view_)));
+#endif
+
   app_list_main_view_->contents_view()->Layout();
 }
 
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc
index 8c5c73a..dbb948a 100644
--- a/ui/app_list/views/app_list_view_unittest.cc
+++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -273,10 +273,15 @@
 
 bool AppListViewTestContext::CheckSearchBoxWidget(const gfx::Rect& expected) {
   ContentsView* contents_view = view_->app_list_main_view()->contents_view();
-  gfx::Point point = expected.origin();
+  // Adjust for the search box view's shadow.
+  gfx::Rect expected_with_shadow =
+      view_->app_list_main_view()
+          ->search_box_view()
+          ->GetViewBoundsForSearchBoxContentsBounds(expected);
+  gfx::Point point = expected_with_shadow.origin();
   views::View::ConvertPointToScreen(contents_view, &point);
 
-  return gfx::Rect(point, expected.size()) ==
+  return gfx::Rect(point, expected_with_shadow.size()) ==
          view_->search_box_widget()->GetWindowBoundsInScreen();
 }
 
diff --git a/ui/app_list/views/contents_animator.cc b/ui/app_list/views/contents_animator.cc
index f4fe3986..97d3c502 100644
--- a/ui/app_list/views/contents_animator.cc
+++ b/ui/app_list/views/contents_animator.cc
@@ -95,9 +95,9 @@
   gfx::Rect search_box_rect =
       gfx::Tween::RectValueBetween(progress, search_box_from, search_box_to);
 
-  views::View* search_box = contents_view()->GetSearchBoxView();
-  search_box->GetWidget()->SetBounds(
-      contents_view()->ConvertRectToWidget(search_box_rect));
+  SearchBoxView* search_box = contents_view()->GetSearchBoxView();
+  search_box->GetWidget()->SetBounds(contents_view()->ConvertRectToWidget(
+      search_box->GetViewBoundsForSearchBoxContentsBounds(search_box_rect)));
 }
 
 void ContentsAnimator::ClipSearchResultsPageToOnscreenBounds(
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index 069afa0..3de1018 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -469,8 +469,10 @@
   // same as the app list widget so don't move it.
   views::Widget* search_box_widget = GetSearchBoxView()->GetWidget();
   if (search_box_widget && search_box_widget != GetWidget()) {
-    search_box_widget->SetBounds(
-        ConvertRectToWidget(GetSearchBoxBoundsForState(GetActiveState())));
+    gfx::Rect search_box_bounds = GetSearchBoxBoundsForState(GetActiveState());
+    search_box_widget->SetBounds(ConvertRectToWidget(
+        GetSearchBoxView()->GetViewBoundsForSearchBoxContentsBounds(
+            search_box_bounds)));
   }
 
   // Immediately finish all current animations.
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 4126f0d7..b23e5dd 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -24,6 +24,8 @@
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/shadow_border.h"
 
 namespace app_list {
 
@@ -39,11 +41,11 @@
 const int kMenuYOffsetFromButton = -4;
 const int kMenuXOffsetFromButton = -7;
 
-const int kBackgroundBorderWidth = 1;
-const int kBackgroundBorderBottomWidth = 1;
 const int kBackgroundBorderCornerRadius = 2;
-const SkColor kBackgroundBorderColor = SkColorSetRGB(0xEE, 0xEE, 0xEE);
-const SkColor kBackgroundBorderBottomColor = SkColorSetRGB(0xCC, 0xCC, 0xCC);
+
+const int kShadowBlur = 4;
+const int kShadowYOffset = 2;
+const SkColor kShadowColor = SkColorSetARGB(0x33, 0, 0, 0);
 
 // A background that paints a solid white rounded rect with a thin grey border.
 class ExperimentalSearchBoxBackground : public views::Background {
@@ -58,15 +60,6 @@
 
     SkPaint paint;
     paint.setFlags(SkPaint::kAntiAlias_Flag);
-    paint.setColor(kBackgroundBorderColor);
-    canvas->DrawRoundRect(bounds, kBackgroundBorderCornerRadius, paint);
-    bounds.Inset(kBackgroundBorderWidth,
-                 kBackgroundBorderWidth,
-                 kBackgroundBorderWidth,
-                 0);
-    paint.setColor(kBackgroundBorderBottomColor);
-    canvas->DrawRoundRect(bounds, kBackgroundBorderCornerRadius, paint);
-    bounds.Inset(0, 0, 0, kBackgroundBorderBottomWidth);
     paint.setColor(kSearchBoxBackground);
     canvas->DrawRoundRect(bounds, kBackgroundBorderCornerRadius, paint);
   }
@@ -81,13 +74,19 @@
     : delegate_(delegate),
       view_delegate_(view_delegate),
       model_(NULL),
+      content_container_(new views::View),
       icon_view_(NULL),
       back_button_(NULL),
       speech_button_(NULL),
       menu_button_(NULL),
       search_box_(new views::Textfield),
       contents_view_(NULL) {
+  SetLayoutManager(new views::FillLayout);
+  AddChildView(content_container_);
+
   if (switches::IsExperimentalAppListEnabled()) {
+    SetBorder(make_scoped_ptr(
+        new views::ShadowBorder(kShadowBlur, kShadowColor, kShadowYOffset, 0)));
     back_button_ = new views::ImageButton(this);
     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     back_button_->SetImage(
@@ -95,16 +94,16 @@
         rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL));
     back_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                                     views::ImageButton::ALIGN_MIDDLE);
-    AddChildView(back_button_);
+    content_container_->AddChildView(back_button_);
 
-    set_background(new ExperimentalSearchBoxBackground());
+    content_container_->set_background(new ExperimentalSearchBoxBackground());
   } else {
     set_background(
         views::Background::CreateSolidBackground(kSearchBoxBackground));
     SetBorder(
         views::Border::CreateSolidSidedBorder(0, 0, 1, 0, kTopSeparatorColor));
     icon_view_ = new views::ImageView;
-    AddChildView(icon_view_);
+    content_container_->AddChildView(icon_view_);
   }
 
   views::BoxLayout* layout =
@@ -112,7 +111,7 @@
                            kPadding,
                            0,
                            kPadding - views::Textfield::kTextPadding);
-  SetLayoutManager(layout);
+  content_container_->SetLayoutManager(layout);
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
   layout->set_minimum_cross_axis_size(kPreferredHeight);
@@ -123,7 +122,7 @@
   search_box_->SetFontList(rb.GetFontList(ui::ResourceBundle::MediumFont));
   search_box_->set_placeholder_text_color(kHintTextColor);
   search_box_->set_controller(this);
-  AddChildView(search_box_);
+  content_container_->AddChildView(search_box_);
   layout->SetFlexForView(search_box_, 1);
 
 #if !defined(OS_CHROMEOS)
@@ -135,7 +134,7 @@
                          *rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_HOVER));
   menu_button_->SetImage(views::Button::STATE_PRESSED,
                          *rb.GetImageSkiaNamed(IDR_APP_LIST_TOOLS_PRESSED));
-  AddChildView(menu_button_);
+  content_container_->AddChildView(menu_button_);
 #endif
 
   view_delegate_->GetSpeechUI()->AddObserver(this);
@@ -176,6 +175,13 @@
   menu_.reset();
 }
 
+gfx::Rect SearchBoxView::GetViewBoundsForSearchBoxContentsBounds(
+    const gfx::Rect& rect) const {
+  gfx::Rect view_bounds = rect;
+  view_bounds.Inset(GetInsets().Scale(-1));
+  return view_bounds;
+}
+
 gfx::Size SearchBoxView::GetPreferredSize() const {
   return gfx::Size(kPreferredWidth, kPreferredHeight);
 }
@@ -221,13 +227,6 @@
   if (contents_view_ && contents_view_->visible())
     handled = contents_view_->OnKeyPressed(key_event);
 
-  // Prevent Shift+Tab from locking up the whole chrome browser process.
-  // Explicitly capturing the Shift+Tab event here compensates for a focus
-  // search issue. We get away with this because there are no other focus
-  // targets. See http://crbug.com/438425 for details.
-  if (key_event.key_code() == ui::VKEY_TAB && key_event.IsShiftDown())
-    handled = true;
-
   return handled;
 }
 
@@ -262,7 +261,7 @@
   if (speech_button_prop) {
     if (!speech_button_) {
       speech_button_ = new views::ImageButton(this);
-      AddChildView(speech_button_);
+      content_container_->AddChildView(speech_button_);
     }
 
     if (view_delegate_->GetSpeechUI()->state() ==
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index f246d7d..b141da6 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -48,6 +48,11 @@
   void ClearSearch();
   void InvalidateMenu();
 
+  // Returns the bounds to use for the view (including the shadow) given the
+  // desired bounds of the search box contents.
+  gfx::Rect GetViewBoundsForSearchBoxContentsBounds(
+      const gfx::Rect& rect) const;
+
   views::ImageButton* back_button() { return back_button_; }
   views::Textfield* search_box() { return search_box_; }
 
@@ -96,6 +101,7 @@
 
   scoped_ptr<AppListMenuViews> menu_;
 
+  views::View* content_container_;     // Owned by views hierarchy.
   views::ImageView* icon_view_;  // Owned by views hierarchy.
   views::ImageButton* back_button_;    // Owned by views hierarchy.
   views::ImageButton* speech_button_;  // Owned by views hierarchy.
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc
index 6aec25b..01ea2d60 100644
--- a/ui/app_list/views/start_page_view.cc
+++ b/ui/app_list/views/start_page_view.cc
@@ -30,14 +30,13 @@
 namespace {
 
 // Layout constants.
-const int kTopMargin = 84;
 const int kInstantContainerSpacing = 11;
 const int kSearchBoxAndTilesSpacing = 40;
 const int kStartPageSearchBoxWidth = 480;
 
 // WebView constants.
-const int kWebViewWidth = 500;
-const int kWebViewHeight = 105;
+const int kWebViewWidth = 700;
+const int kWebViewHeight = 189;
 
 // Tile container constants.
 const size_t kNumStartPageTiles = 4;
@@ -91,7 +90,7 @@
   views::BoxLayout* instant_layout_manager = new views::BoxLayout(
       views::BoxLayout::kVertical, 0, 0, kInstantContainerSpacing);
   instant_layout_manager->set_inside_border_insets(
-      gfx::Insets(kTopMargin, 0, kSearchBoxAndTilesSpacing, 0));
+      gfx::Insets(0, 0, kSearchBoxAndTilesSpacing, 0));
   instant_layout_manager->set_main_axis_alignment(
       views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
   instant_layout_manager->set_cross_axis_alignment(
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 78f12d03..edab4926 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -206,6 +206,10 @@
 
     deps += [ "//ui/gfx/x" ]
   }
+
+  if (use_ozone) {
+    sources += [ "test/ui_controls_factory_ozone.cc" ]
+  }
 }
 
 executable("demo") {
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index c5f3382..b16f5a50 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -531,6 +531,7 @@
   }
 
   if (is_chromeos) {
+    deps += [ "//chromeos" ]
     sources -= [ "idle/idle_linux.cc" ]
   }
 
diff --git a/ui/base/cocoa/nsview_additions.h b/ui/base/cocoa/nsview_additions.h
index 962d89b..a919b3b 100644
--- a/ui/base/cocoa/nsview_additions.h
+++ b/ui/base/cocoa/nsview_additions.h
@@ -29,6 +29,9 @@
 // Return best color for keyboard focus ring.
 - (NSColor*)cr_keyboardFocusIndicatorColor;
 
+// Invoke |block| on this view and all descendants.
+- (void)cr_recursivelyInvokeBlock:(void (^)(id view))block;
+
 // Set needsDisplay for this view and all descendants.
 - (void)cr_recursivelySetNeedsDisplay:(BOOL)flag;
 
diff --git a/ui/base/cocoa/nsview_additions.mm b/ui/base/cocoa/nsview_additions.mm
index fc24039..f111b14 100644
--- a/ui/base/cocoa/nsview_additions.mm
+++ b/ui/base/cocoa/nsview_additions.mm
@@ -60,6 +60,12 @@
       colorWithAlphaComponent:0.5 / [self cr_lineWidth]];
 }
 
+- (void)cr_recursivelyInvokeBlock:(void (^)(id view))block {
+  block(self);
+  for (NSView* subview in [self subviews])
+    [subview cr_recursivelyInvokeBlock:block];
+}
+
 - (void)cr_recursivelySetNeedsDisplay:(BOOL)flag {
   [self setNeedsDisplay:YES];
   for (NSView* child in [self subviews])
diff --git a/ui/base/ui_base_unittests.isolate b/ui/base/ui_base_unittests.isolate
index 16f6dd5f..7bc59c4 100644
--- a/ui/base/ui_base_unittests.isolate
+++ b/ui/base/ui_base_unittests.isolate
@@ -31,6 +31,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../../testing/xvfb.py',
@@ -69,6 +71,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/ui/chromeos/BUILD.gn b/ui/chromeos/BUILD.gn
index ea2fc20..7cd2171 100644
--- a/ui/chromeos/BUILD.gn
+++ b/ui/chromeos/BUILD.gn
@@ -6,6 +6,8 @@
 
 component("ui_chromeos") {
   sources = [
+    "accelerometer/accelerometer_util.cc",
+    "accelerometer/accelerometer_util.h",
     "accessibility_types.h",
     "ime/candidate_view.cc",
     "ime/candidate_view.h",
diff --git a/ui/chromeos/accelerometer/accelerometer_util.cc b/ui/chromeos/accelerometer/accelerometer_util.cc
new file mode 100644
index 0000000..9368b81
--- /dev/null
+++ b/ui/chromeos/accelerometer/accelerometer_util.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 "ui/chromeos/accelerometer/accelerometer_util.h"
+
+#include <cmath>
+
+#include "chromeos/accelerometer/accelerometer_types.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace {
+
+// The maximum deviation from the acceleration expected due to gravity for which
+// the device will be considered stable: 1g.
+const float kDeviationFromGravityThreshold = 1.0f;
+
+// The mean acceleration due to gravity on Earth in m/s^2.
+const float kMeanGravity = 9.80665f;
+
+}  // namespace
+
+namespace ui {
+
+const gfx::Vector3dF ConvertAccelerometerReadingToVector3dF(
+    const chromeos::AccelerometerReading& reading) {
+  return gfx::Vector3dF(reading.x, reading.y, reading.z);
+}
+
+bool IsAccelerometerReadingStable(const chromeos::AccelerometerUpdate& update,
+                                  chromeos::AccelerometerSource source) {
+  return update.has(source) &&
+         std::abs(ConvertAccelerometerReadingToVector3dF(update.get(source))
+                      .Length() -
+                  kMeanGravity) <= kDeviationFromGravityThreshold;
+}
+
+}  // namespace ui
diff --git a/ui/chromeos/accelerometer/accelerometer_util.h b/ui/chromeos/accelerometer/accelerometer_util.h
new file mode 100644
index 0000000..974fceb
--- /dev/null
+++ b/ui/chromeos/accelerometer/accelerometer_util.h
@@ -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.
+
+#ifndef UI_CHROMEOS_ACCELEROMETER_ACCELEROMETER_UTIL_H_
+#define UI_CHROMEOS_ACCELEROMETER_ACCELEROMETER_UTIL_H_
+
+#include "chromeos/accelerometer/accelerometer_types.h"
+#include "ui/chromeos/ui_chromeos_export.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace ui {
+
+// Converts the acceleration data in |reading| into a gfx::Vector3dF.
+UI_CHROMEOS_EXPORT const gfx::Vector3dF ConvertAccelerometerReadingToVector3dF(
+    const chromeos::AccelerometerReading& reading);
+
+// A reading is considered stable if its deviation from gravity is small. This
+// returns false if the deviation is too high, or if |source| is not present
+// in the update.
+UI_CHROMEOS_EXPORT bool IsAccelerometerReadingStable(
+    const chromeos::AccelerometerUpdate& update,
+    chromeos::AccelerometerSource source);
+
+}  // namespace ui
+
+#endif  // UI_CHROMEOS_ACCELEROMETER_ACCELEROMETER_UTIL_H_
diff --git a/ui/chromeos/ui_chromeos.gyp b/ui/chromeos/ui_chromeos.gyp
index 943f9d8a..7c5fcba 100644
--- a/ui/chromeos/ui_chromeos.gyp
+++ b/ui/chromeos/ui_chromeos.gyp
@@ -66,6 +66,8 @@
         'UI_CHROMEOS_IMPLEMENTATION',
       ],
       'sources': [
+        'accelerometer/accelerometer_util.cc',
+        'accelerometer/accelerometer_util.h',
         'accessibility_types.h',
         'ime/candidate_view.cc',
         'ime/candidate_view.h',
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index ded29924..ec36a0a 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -240,7 +240,7 @@
   void OnSwapBuffersAborted();
 
   // LayerTreeHostClient implementation.
-  void WillBeginMainFrame(int frame_id) override {}
+  void WillBeginMainFrame() override {}
   void DidBeginMainFrame() override {}
   void BeginMainFrame(const cc::BeginFrameArgs& args) override;
   void Layout() override;
diff --git a/ui/display/chromeos/display_configurator.cc b/ui/display/chromeos/display_configurator.cc
index e6a379c1..bcfc46a 100644
--- a/ui/display/chromeos/display_configurator.cc
+++ b/ui/display/chromeos/display_configurator.cc
@@ -456,6 +456,7 @@
       force_configure_(false),
       next_display_protection_client_id_(1),
       display_externally_controlled_(false),
+      displays_suspended_(false),
       layout_manager_(new DisplayLayoutManagerImpl(this)),
       weak_ptr_factory_(this) {
 }
@@ -856,9 +857,13 @@
     // racing with the HandleSuspendReadiness message.
     native_display_delegate_->SyncWithServer();
   }
+
+  displays_suspended_ = true;
 }
 
 void DisplayConfigurator::ResumeDisplays() {
+  displays_suspended_ = false;
+
   configure_timer_.Start(
       FROM_HERE,
       base::TimeDelta::FromMilliseconds(kResumeDelayMs),
@@ -875,6 +880,14 @@
 }
 
 void DisplayConfigurator::RunPendingConfiguration() {
+  // Don't do anything if the displays are currently suspended.  Instead we will
+  // probe and reconfigure the displays if necessary in ResumeDisplays().
+  if (displays_suspended_) {
+    VLOG(1) << "Displays are currently suspended.  Not attempting to "
+            << "reconfigure them.";
+    return;
+  }
+
   // Configuration task is currently running. Do not start a second
   // configuration.
   if (configuration_task_)
diff --git a/ui/display/chromeos/display_configurator.h b/ui/display/chromeos/display_configurator.h
index 62afdeeb..c77b96a 100644
--- a/ui/display/chromeos/display_configurator.h
+++ b/ui/display/chromeos/display_configurator.h
@@ -414,6 +414,9 @@
   // Display controlled by an external entity.
   bool display_externally_controlled_;
 
+  // Whether the displays are currently suspended.
+  bool displays_suspended_;
+
   scoped_ptr<DisplayLayoutManager> layout_manager_;
 
   scoped_ptr<UpdateDisplayConfigurationTask> configuration_task_;
diff --git a/ui/display/chromeos/display_configurator_unittest.cc b/ui/display/chromeos/display_configurator_unittest.cc
index 96257b62..86b1473 100644
--- a/ui/display/chromeos/display_configurator_unittest.cc
+++ b/ui/display/chromeos/display_configurator_unittest.cc
@@ -965,6 +965,54 @@
             log_->GetActionsAndClear());
 }
 
+TEST_F(DisplayConfiguratorTest, DoNotConfigureWithSuspendedDisplays) {
+  InitWithSingleOutput();
+
+  // The DisplayConfigurator may occasionally receive OnConfigurationChanged()
+  // after the displays have been suspended.  This event should be ignored since
+  // the DisplayConfigurator will force a probe and reconfiguration of displays
+  // at resume time.
+  configurator_.SuspendDisplays();
+  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
+
+  configurator_.OnConfigurationChanged();
+  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
+
+  configurator_.ResumeDisplays();
+  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(
+      JoinActions(
+          kGrab,
+          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
+          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
+          kForceDPMS,
+          kUngrab,
+          NULL),
+      log_->GetActionsAndClear());
+
+  // If a configuration task is pending when the displays are suspended, that
+  // task should not run either.
+  configurator_.OnConfigurationChanged();
+  configurator_.SuspendDisplays();
+  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
+
+  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
+
+  configurator_.ResumeDisplays();
+  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(
+      JoinActions(
+          kGrab,
+          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
+          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
+          kForceDPMS,
+          kUngrab,
+          NULL),
+      log_->GetActionsAndClear());
+}
+
 TEST_F(DisplayConfiguratorTest, ContentProtectionTwoClients) {
   DisplayConfigurator::ContentProtectionClientId client1 =
       configurator_.RegisterContentProtectionClient();
diff --git a/ui/events/cocoa/events_mac.mm b/ui/events/cocoa/events_mac.mm
index fcc8cc9a..d21184cc 100644
--- a/ui/events/cocoa/events_mac.mm
+++ b/ui/events/cocoa/events_mac.mm
@@ -160,10 +160,6 @@
   [event release];
 }
 
-void IncrementTouchIdRefCount(const base::NativeEvent& native_event) {
-  NOTIMPLEMENTED();
-}
-
 void ClearTouchIdIfReleased(const base::NativeEvent& native_event) {
   NOTIMPLEMENTED();
 }
diff --git a/ui/events/devices/device_data_manager.cc b/ui/events/devices/device_data_manager.cc
index 0977395e..eb96c46 100644
--- a/ui/events/devices/device_data_manager.cc
+++ b/ui/events/devices/device_data_manager.cc
@@ -149,6 +149,20 @@
                     OnKeyboardDeviceConfigurationChanged());
 }
 
+void DeviceDataManager::OnMouseDevicesUpdated(
+    const std::vector<InputDevice>& devices) {
+  FOR_EACH_OBSERVER(InputDeviceEventObserver,
+                    observers_,
+                    OnMouseDeviceConfigurationChanged());
+}
+
+void DeviceDataManager::OnTouchpadDevicesUpdated(
+    const std::vector<InputDevice>& devices) {
+  FOR_EACH_OBSERVER(InputDeviceEventObserver,
+                    observers_,
+                    OnTouchpadDeviceConfigurationChanged());
+}
+
 void DeviceDataManager::AddObserver(InputDeviceEventObserver* observer) {
   observers_.AddObserver(observer);
 }
diff --git a/ui/events/devices/device_data_manager.h b/ui/events/devices/device_data_manager.h
index 7d7a0094..4896ad86 100644
--- a/ui/events/devices/device_data_manager.h
+++ b/ui/events/devices/device_data_manager.h
@@ -64,6 +64,10 @@
       const std::vector<TouchscreenDevice>& devices) override;
   void OnKeyboardDevicesUpdated(
       const std::vector<KeyboardDevice>& devices) override;
+  void OnMouseDevicesUpdated(
+      const std::vector<InputDevice>& devices) override;
+  void OnTouchpadDevicesUpdated(
+      const std::vector<InputDevice>& devices) override;
 
  private:
   static DeviceDataManager* instance_;
diff --git a/ui/events/devices/device_hotplug_event_observer.h b/ui/events/devices/device_hotplug_event_observer.h
index 7219c5e..5bf5892 100644
--- a/ui/events/devices/device_hotplug_event_observer.h
+++ b/ui/events/devices/device_hotplug_event_observer.h
@@ -11,6 +11,7 @@
 
 namespace ui {
 
+struct InputDevice;
 struct KeyboardDevice;
 struct TouchscreenDevice;
 
@@ -20,14 +21,24 @@
   virtual ~DeviceHotplugEventObserver() {}
 
   // On a hotplug event this is called with the list of available touchscreen
-  // devices. The set of touchscreen devices may not necessarily have changed.
+  // devices. The set of touchscreen devices may not have changed.
   virtual void OnTouchscreenDevicesUpdated(
       const std::vector<TouchscreenDevice>& devices) = 0;
 
   // On a hotplug event this is called with the list of available keyboard
-  // devices. The set of keyboard devices may not necessarily have changed.
+  // devices. The set of keyboard devices may not have changed.
   virtual void OnKeyboardDevicesUpdated(
       const std::vector<KeyboardDevice>& devices) = 0;
+
+  // On a hotplug event this is called with the list of available mice. The set
+  // of mice may not have changed.
+  virtual void OnMouseDevicesUpdated(
+      const std::vector<InputDevice>& devices) = 0;
+
+  // On a hotplug event this is called with the list of available touchpads. The
+  // set of touchpads may not have changed.
+  virtual void OnTouchpadDevicesUpdated(
+      const std::vector<InputDevice>& devices) = 0;
 };
 
 }  // namespace ui
diff --git a/ui/events/devices/input_device_event_observer.h b/ui/events/devices/input_device_event_observer.h
index 6cee8e8..707fea2 100644
--- a/ui/events/devices/input_device_event_observer.h
+++ b/ui/events/devices/input_device_event_observer.h
@@ -16,6 +16,8 @@
 
   virtual void OnKeyboardDeviceConfigurationChanged() = 0;
   virtual void OnTouchscreenDeviceConfigurationChanged() = 0;
+  virtual void OnMouseDeviceConfigurationChanged() = 0;
+  virtual void OnTouchpadDeviceConfigurationChanged() = 0;
 };
 
 }  // namespace ui
diff --git a/ui/events/devices/x11/device_data_manager_x11.cc b/ui/events/devices/x11/device_data_manager_x11.cc
index 68fdb2c..85c697a 100644
--- a/ui/events/devices/x11/device_data_manager_x11.cc
+++ b/ui/events/devices/x11/device_data_manager_x11.cc
@@ -202,6 +202,7 @@
 void DeviceDataManagerX11::UpdateDeviceList(Display* display) {
   cmt_devices_.reset();
   touchpads_.reset();
+  master_pointers_.clear();
   for (int i = 0; i < kMaxDeviceNum; ++i) {
     valuator_count_[i] = 0;
     valuator_lookup_[i].clear();
@@ -233,6 +234,9 @@
   for (int i = 0; i < info_list.count; ++i) {
     XIDeviceInfo* info = info_list.devices + i;
 
+    if (info->use == XIMasterPointer)
+      master_pointers_.push_back(info->deviceid);
+
     // We currently handle only slave, non-keyboard devices
     if (info->use != XISlavePointer && info->use != XIFloatingSlave)
       continue;
diff --git a/ui/events/devices/x11/device_data_manager_x11.h b/ui/events/devices/x11/device_data_manager_x11.h
index ec580cbd..bb5fa15 100644
--- a/ui/events/devices/x11/device_data_manager_x11.h
+++ b/ui/events/devices/x11/device_data_manager_x11.h
@@ -239,6 +239,10 @@
   // Returns true if |native_event| should be blocked.
   bool IsEventBlocked(const base::NativeEvent& native_event);
 
+  const std::vector<int>& master_pointers() const {
+    return master_pointers_;
+  }
+
  protected:
   // DeviceHotplugEventObserver:
   void OnKeyboardDevicesUpdated(
@@ -274,6 +278,9 @@
   std::bitset<kMaxDeviceNum> cmt_devices_;
   std::bitset<kMaxDeviceNum> touchpads_;
 
+  // List of the master pointer devices.
+  std::vector<int> master_pointers_;
+
   // A quick lookup table for determining if events from the XI device
   // should be blocked.
   std::bitset<kMaxDeviceNum> blocked_devices_;
diff --git a/ui/events/devices/x11/device_data_manager_x11_unittest.cc b/ui/events/devices/x11/device_data_manager_x11_unittest.cc
index 22ae224..8149111 100644
--- a/ui/events/devices/x11/device_data_manager_x11_unittest.cc
+++ b/ui/events/devices/x11/device_data_manager_x11_unittest.cc
@@ -39,6 +39,8 @@
   void OnKeyboardDeviceConfigurationChanged() override {
     change_notified_ = true;
   }
+  void OnMouseDeviceConfigurationChanged() override {}
+  void OnTouchpadDeviceConfigurationChanged() override {}
 
   int change_notified() const { return change_notified_; }
   void Reset() { change_notified_ = false; }
diff --git a/ui/events/devices/x11/touch_factory_x11.cc b/ui/events/devices/x11/touch_factory_x11.cc
index 1dce504..4201fa04 100644
--- a/ui/events/devices/x11/touch_factory_x11.cc
+++ b/ui/events/devices/x11/touch_factory_x11.cc
@@ -201,6 +201,8 @@
   XISetMask(mask, XI_ButtonRelease);
   XISetMask(mask, XI_Motion);
 #if defined(OS_CHROMEOS)
+  // XGrabKey() must be replaced with XI2 keyboard grab if XI2 key events are
+  // enabled on desktop Linux.
   if (base::SysInfo::IsRunningOnChromeOS()) {
     XISetMask(mask, XI_KeyPress);
     XISetMask(mask, XI_KeyRelease);
@@ -250,14 +252,8 @@
   return id_generator_.GetGeneratedID(tracking_id);
 }
 
-void TouchFactory::AcquireSlotForTrackingID(uint32 tracking_id) {
-  tracking_id_refcounts_[tracking_id]++;
-}
-
 void TouchFactory::ReleaseSlotForTrackingID(uint32 tracking_id) {
-  tracking_id_refcounts_[tracking_id]--;
-  if (tracking_id_refcounts_[tracking_id] == 0)
-    id_generator_.ReleaseNumber(tracking_id);
+  id_generator_.ReleaseNumber(tracking_id);
 }
 
 bool TouchFactory::IsTouchDevicePresent() {
@@ -270,7 +266,6 @@
   touch_events_disabled_ = false;
   touch_device_list_.clear();
   touchscreen_ids_.clear();
-  tracking_id_refcounts_.clear();
   id_generator_.ResetForTest();
 }
 
diff --git a/ui/events/devices/x11/touch_factory_x11.h b/ui/events/devices/x11/touch_factory_x11.h
index cbec35f8..775b4966 100644
--- a/ui/events/devices/x11/touch_factory_x11.h
+++ b/ui/events/devices/x11/touch_factory_x11.h
@@ -67,10 +67,6 @@
   // isn't one already, allocates a new slot ID and sets up the mapping.
   int GetSlotForTrackingID(uint32 tracking_id);
 
-  // Increases the number of times |ReleaseSlotForTrackingID| needs to be called
-  // on a given tracking id before it will actually be released.
-  void AcquireSlotForTrackingID(uint32 tracking_id);
-
   // Releases the slot ID mapping to tracking ID.
   void ReleaseSlotForTrackingID(uint32 tracking_id);
 
@@ -130,10 +126,6 @@
   // Touch screen <vid, pid>s.
   std::set<std::pair<int, int> > touchscreen_ids_;
 
-  // Maps from a tracking id to the number of times |ReleaseSlotForTrackingID|
-  // must be called before the tracking id is released.
-  std::map<uint32, int> tracking_id_refcounts_;
-
   // Device ID of the virtual core keyboard.
   int virtual_core_keyboard_device_;
 
diff --git a/ui/events/event.cc b/ui/events/event.cc
index d0966da..f8480e9 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -526,19 +526,16 @@
       radius_y_(GetTouchRadiusY(native_event)),
       rotation_angle_(GetTouchAngle(native_event)),
       force_(GetTouchForce(native_event)),
-      may_cause_scrolling_(false) {
+      may_cause_scrolling_(false),
+      should_remove_native_touch_id_mapping_(false) {
   latency()->AddLatencyNumberWithTimestamp(
-      INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
-      0,
-      0,
-      base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()),
-      1);
-
+      INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0,
+      base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 1);
   latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
-  fixRotationAngle();
 
-  if (type() == ET_TOUCH_PRESSED)
-    IncrementTouchIdRefCount(native_event);
+  FixRotationAngle();
+  if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
+    should_remove_native_touch_id_mapping_ = true;
 }
 
 TouchEvent::TouchEvent(EventType type,
@@ -552,7 +549,8 @@
       radius_y_(0.0f),
       rotation_angle_(0.0f),
       force_(0.0f),
-      may_cause_scrolling_(false) {
+      may_cause_scrolling_(false),
+      should_remove_native_touch_id_mapping_(false) {
   latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
 }
 
@@ -572,17 +570,21 @@
       radius_y_(radius_y),
       rotation_angle_(angle),
       force_(force),
-      may_cause_scrolling_(false) {
+      may_cause_scrolling_(false),
+      should_remove_native_touch_id_mapping_(false) {
   latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
-  fixRotationAngle();
+  FixRotationAngle();
 }
 
 TouchEvent::~TouchEvent() {
   // In ctor TouchEvent(native_event) we call GetTouchId() which in X11
   // platform setups the tracking_id to slot mapping. So in dtor here,
   // if this touch event is a release event, we clear the mapping accordingly.
-  if (HasNativeEvent())
-    ClearTouchIdIfReleased(native_event());
+  if (should_remove_native_touch_id_mapping_) {
+    DCHECK(type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED);
+    if (type() == ET_TOUCH_RELEASED || type() == ET_TOUCH_CANCELLED)
+      ClearTouchIdIfReleased(native_event());
+  }
 }
 
 void TouchEvent::UpdateForRootTransform(
@@ -603,7 +605,7 @@
       static_cast<EventResult>(result() | ER_DISABLE_SYNC_HANDLING));
 }
 
-void TouchEvent::fixRotationAngle() {
+void TouchEvent::FixRotationAngle() {
   while (rotation_angle_ < 0)
     rotation_angle_ += 180;
   while (rotation_angle_ >= 180)
diff --git a/ui/events/event.h b/ui/events/event.h
index e32e77c..4f585e9 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -212,7 +212,7 @@
   void StopPropagation();
   bool stopped_propagation() const { return !!(result_ & ER_CONSUMED); }
 
-
+  // Marks the event as having been handled. A handled event does not reach the
   // next event phase. For example, if an event is handled during the pre-target
   // phase, then the event is dispatched to all pre-target handlers, but not to
   // the target or post-target handlers.
@@ -225,9 +225,6 @@
   Event(const base::NativeEvent& native_event, EventType type, int flags);
   Event(const Event& copy);
   void SetType(EventType type);
-  void set_delete_native_event(bool delete_native_event) {
-    delete_native_event_ = delete_native_event;
-  }
   void set_cancelable(bool cancelable) { cancelable_ = cancelable; }
 
   void set_time_stamp(const base::TimeDelta& time_stamp) {
@@ -495,7 +492,8 @@
         radius_y_(model.radius_y_),
         rotation_angle_(model.rotation_angle_),
         force_(model.force_),
-        may_cause_scrolling_(model.may_cause_scrolling_) {}
+        may_cause_scrolling_(model.may_cause_scrolling_),
+        should_remove_native_touch_id_mapping_(false) {}
 
   TouchEvent(EventType type,
              const gfx::PointF& location,
@@ -532,6 +530,12 @@
   void set_radius_x(const float r) { radius_x_ = r; }
   void set_radius_y(const float r) { radius_y_ = r; }
 
+  void set_should_remove_native_touch_id_mapping(
+      bool should_remove_native_touch_id_mapping) {
+    should_remove_native_touch_id_mapping_ =
+        should_remove_native_touch_id_mapping;
+  }
+
   // Overridden from LocatedEvent.
   void UpdateForRootTransform(
       const gfx::Transform& inverted_root_transform) override;
@@ -544,7 +548,7 @@
 
  private:
   // Adjusts rotation_angle_ to within the acceptable range.
-  void fixRotationAngle();
+  void FixRotationAngle();
 
   // The identity (typically finger) of the touch starting at 0 and incrementing
   // for each separable additional touch that the hardware can detect.
@@ -570,6 +574,12 @@
   // touchmove that exceeds the platform slop region, or a touchend that
   // causes a fling). Defaults to false.
   bool may_cause_scrolling_;
+
+  // True if this event should remove the mapping between the native
+  // event id and the touch_id_. This should only be the case for
+  // release and cancel events where the associated touch press event
+  // created a mapping between the native id and the touch_id_.
+  bool should_remove_native_touch_id_mapping_;
 };
 
 // An interface that individual platforms can use to store additional data on
diff --git a/ui/events/event_utils.h b/ui/events/event_utils.h
index 2a0e699..1649bd7 100644
--- a/ui/events/event_utils.h
+++ b/ui/events/event_utils.h
@@ -116,11 +116,6 @@
 // Gets the touch id from a native event.
 EVENTS_EXPORT int GetTouchId(const base::NativeEvent& native_event);
 
-// Increases the number of times |ClearTouchIdIfReleased| needs to be called on
-// an event with a given touch id before it will actually be cleared.
-EVENTS_EXPORT void IncrementTouchIdRefCount(
-    const base::NativeEvent& native_event);
-
 // Clear the touch id from bookkeeping if it is a release/cancel event.
 EVENTS_EXPORT void ClearTouchIdIfReleased(
     const base::NativeEvent& native_event);
diff --git a/ui/events/events_stub.cc b/ui/events/events_stub.cc
index 05b4b7f..a5a4fbd 100644
--- a/ui/events/events_stub.cc
+++ b/ui/events/events_stub.cc
@@ -70,10 +70,6 @@
 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
 }
 
-void IncrementTouchIdRefCount(const base::NativeEvent& native_event) {
-  NOTIMPLEMENTED();
-}
-
 void ClearTouchIdIfReleased(const base::NativeEvent& native_event) {
   NOTIMPLEMENTED();
 }
diff --git a/ui/events/events_unittests.isolate b/ui/events/events_unittests.isolate
index 024de78..c2418cbf 100644
--- a/ui/events/events_unittests.isolate
+++ b/ui/events/events_unittests.isolate
@@ -21,6 +21,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../../testing/xvfb.py',
@@ -58,6 +60,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn
index 8655ef4..3945e5d 100644
--- a/ui/events/ozone/BUILD.gn
+++ b/ui/events/ozone/BUILD.gn
@@ -36,6 +36,8 @@
   deps = [
     "//base",
     "//base/third_party/dynamic_annotations",
+    "//ui/events",
+    "//ui/events:events_base",
   ]
 
   defines = [ "EVENTS_OZONE_IMPLEMENTATION" ]
@@ -80,8 +82,8 @@
     "evdev/input_controller_evdev.cc",
     "evdev/input_controller_evdev.h",
     "evdev/input_device_factory_evdev.cc",
-    "evdev/input_device_factory_evdev.cc",
-    "evdev/input_device_factory_evdev_proxy.h",
+    "evdev/input_device_factory_evdev.h",
+    "evdev/input_device_factory_evdev_proxy.cc",
     "evdev/input_device_factory_evdev_proxy.h",
     "evdev/input_injector_evdev.cc",
     "evdev/input_injector_evdev.h",
@@ -103,7 +105,9 @@
     ":events_ozone",
     ":events_ozone_layout",
     "//base",
+    "//ui/events",
     "//ui/events:dom4_keycode_converter",
+    "//ui/events:events_base",
     "//ui/events/devices",
     "//ui/events/platform",
     "//ui/gfx",
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
index 003da67..c401028 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -96,6 +96,8 @@
         ConvertMouseMoveEvent(input);
         break;
       case EV_SYN:
+        if (input.code == SYN_DROPPED)
+          LOG(WARNING) << "kernel dropped input events";
         FlushEvents();
         break;
     }
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc
index ed201d3..11ede97 100644
--- a/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -254,12 +254,16 @@
     const std::vector<InputDevice>& devices) {
   // There's no list of mice in DeviceDataManager.
   input_controller_.set_has_mouse(devices.size() != 0);
+  DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance();
+  observer->OnMouseDevicesUpdated(devices);
 }
 
 void EventFactoryEvdev::DispatchTouchpadDevicesUpdated(
     const std::vector<InputDevice>& devices) {
   // There's no list of touchpads in DeviceDataManager.
   input_controller_.set_has_touchpad(devices.size() != 0);
+  DeviceHotplugEventObserver* observer = DeviceDataManager::GetInstance();
+  observer->OnTouchpadDevicesUpdated(devices);
 }
 
 
diff --git a/ui/events/ozone/evdev/event_thread_evdev.cc b/ui/events/ozone/evdev/event_thread_evdev.cc
index 4666761..d6c5ffc 100644
--- a/ui/events/ozone/evdev/event_thread_evdev.cc
+++ b/ui/events/ozone/evdev/event_thread_evdev.cc
@@ -6,10 +6,10 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
+#include "base/trace_event/trace_event.h"
 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
 #include "ui/events/ozone/evdev/input_device_factory_evdev.h"
 #include "ui/events/ozone/evdev/input_device_factory_evdev_proxy.h"
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
index f215cd7..daaaa267 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -430,7 +430,7 @@
     NotifyMouseDevicesUpdated();
 
   if (converter.HasTouchpad())
-    NotifyMouseDevicesUpdated();
+    NotifyTouchpadDevicesUpdated();
 }
 
 void InputDeviceFactoryEvdev::NotifyTouchscreensUpdated() {
diff --git a/ui/events/ozone/events_ozone.cc b/ui/events/ozone/events_ozone.cc
index 932600d..d29f9da0 100644
--- a/ui/events/ozone/events_ozone.cc
+++ b/ui/events/ozone/events_ozone.cc
@@ -86,9 +86,6 @@
 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
 }
 
-void IncrementTouchIdRefCount(const base::NativeEvent& event) {
-}
-
 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
 }
 
diff --git a/ui/events/ozone/events_ozone.gyp b/ui/events/ozone/events_ozone.gyp
index 453379b..3094b75 100644
--- a/ui/events/ozone/events_ozone.gyp
+++ b/ui/events/ozone/events_ozone.gyp
@@ -51,6 +51,8 @@
       '../../ozone/ozone.gyp:ozone_base',
       '../devices/events_devices.gyp:events_devices',
       '../events.gyp:dom4_keycode_converter',
+      '../events.gyp:events',
+      '../events.gyp:events_base',
       '../platform/events_platform.gyp:events_platform',
       'events_ozone',
       'events_ozone_layout',
diff --git a/ui/events/platform/x11/x11_hotplug_event_handler.cc b/ui/events/platform/x11/x11_hotplug_event_handler.cc
index 78ecf35..6b54e58 100644
--- a/ui/events/platform/x11/x11_hotplug_event_handler.cc
+++ b/ui/events/platform/x11/x11_hotplug_event_handler.cc
@@ -340,6 +340,8 @@
   UiCallbacks callbacks;
   callbacks.keyboard_callback = base::Bind(&OnKeyboardDevices);
   callbacks.touchscreen_callback = base::Bind(&OnTouchscreenDevices);
+  // TODO(pkotwicz): Compute the lists of mice and touchpads and send the new
+  // lists to DeviceHotplugEventObserver.
 
   // Parsing the device information may block, so delegate the operation to a
   // worker thread. Once the device information is extracted the parsed devices
diff --git a/ui/events/win/events_win.cc b/ui/events/win/events_win.cc
index 98f4775..6960f46 100644
--- a/ui/events/win/events_win.cc
+++ b/ui/events/win/events_win.cc
@@ -303,10 +303,6 @@
 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
 }
 
-void IncrementTouchIdRefCount(const base::NativeEvent& event) {
-  NOTIMPLEMENTED();
-}
-
 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
   NOTIMPLEMENTED();
 }
diff --git a/ui/events/x/events_x.cc b/ui/events/x/events_x.cc
index 6678f01..6c83976 100644
--- a/ui/events/x/events_x.cc
+++ b/ui/events/x/events_x.cc
@@ -739,18 +739,6 @@
   delete event;
 }
 
-void IncrementTouchIdRefCount(const base::NativeEvent& xev) {
-  ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
-  double tracking_id;
-  if (!manager->GetEventData(
-          *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
-    return;
-  }
-
-  ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
-  factory->AcquireSlotForTrackingID(tracking_id);
-}
-
 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
   ui::EventType type = ui::EventTypeFromNative(xev);
   if (type == ui::ET_TOUCH_CANCELLED ||
diff --git a/ui/events/x/events_x_unittest.cc b/ui/events/x/events_x_unittest.cc
index fb74424..554590a0 100644
--- a/ui/events/x/events_x_unittest.cc
+++ b/ui/events/x/events_x_unittest.cc
@@ -300,54 +300,47 @@
   return -1;
 }
 
-TEST_F(EventsXTest, TouchEventIdRefcounting) {
+TEST_F(EventsXTest, TouchEventNotRemovingFromNativeMapping) {
   std::vector<unsigned int> devices;
   devices.push_back(0);
   ui::SetUpTouchDevicesForTest(devices);
   std::vector<Valuator> valuators;
 
-  const int kTrackingId0 = 5;
-  const int kTrackingId1 = 7;
+  const int kTrackingId = 5;
 
-  // Increment ref count once for first touch.
+  // Two touch presses with the same tracking id.
   ui::ScopedXI2Event xpress0;
   xpress0.InitTouchEvent(
-      0, XI_TouchBegin, kTrackingId0, gfx::Point(10, 10), valuators);
+      0, XI_TouchBegin, kTrackingId, gfx::Point(10, 10), valuators);
   scoped_ptr<ui::TouchEvent> upress0(new ui::TouchEvent(xpress0));
-  EXPECT_EQ(0, GetTouchIdForTrackingId(kTrackingId0));
+  EXPECT_EQ(0, GetTouchIdForTrackingId(kTrackingId));
 
-  // Increment ref count 4 times for second touch.
   ui::ScopedXI2Event xpress1;
   xpress1.InitTouchEvent(
-      0, XI_TouchBegin, kTrackingId1, gfx::Point(20, 20), valuators);
+      0, XI_TouchBegin, kTrackingId, gfx::Point(20, 20), valuators);
+  ui::TouchEvent upress1(xpress1);
+  EXPECT_EQ(0, GetTouchIdForTrackingId(kTrackingId));
 
-  for (int i = 0; i < 4; ++i) {
-    ui::TouchEvent upress1(xpress1);
-    EXPECT_EQ(1, GetTouchIdForTrackingId(kTrackingId1));
-  }
-
-  ui::ScopedXI2Event xrelease1;
-  xrelease1.InitTouchEvent(
-      0, XI_TouchEnd, kTrackingId1, gfx::Point(10, 10), valuators);
-
-  // Decrement ref count 3 times for second touch.
-  for (int i = 0; i < 3; ++i) {
-    ui::TouchEvent urelease1(xrelease1);
-    EXPECT_EQ(1, GetTouchIdForTrackingId(kTrackingId1));
-  }
-
-  // This should clear the touch id of the second touch.
-  scoped_ptr<ui::TouchEvent> urelease1(new ui::TouchEvent(xrelease1));
-  urelease1.reset();
-  EXPECT_EQ(-1, GetTouchIdForTrackingId(kTrackingId1));
-
-  // This should clear the touch id of the first touch.
+  // The first touch release shouldn't clear the mapping from the
+  // tracking id.
   ui::ScopedXI2Event xrelease0;
   xrelease0.InitTouchEvent(
-      0, XI_TouchEnd, kTrackingId0, gfx::Point(10, 10), valuators);
-  scoped_ptr<ui::TouchEvent> urelease0(new ui::TouchEvent(xrelease0));
-  urelease0.reset();
-  EXPECT_EQ(-1, GetTouchIdForTrackingId(kTrackingId0));
+      0, XI_TouchEnd, kTrackingId, gfx::Point(10, 10), valuators);
+  {
+    ui::TouchEvent urelease0(xrelease0);
+    urelease0.set_should_remove_native_touch_id_mapping(false);
+  }
+  EXPECT_EQ(0, GetTouchIdForTrackingId(kTrackingId));
+
+  // The second touch release should clear the mapping from the
+  // tracking id.
+  ui::ScopedXI2Event xrelease1;
+  xrelease1.InitTouchEvent(
+      0, XI_TouchEnd, kTrackingId, gfx::Point(10, 10), valuators);
+  {
+    ui::TouchEvent urelease1(xrelease1);
+  }
+  EXPECT_EQ(-1, GetTouchIdForTrackingId(kTrackingId));
 }
 
 TEST_F(EventsXTest, NumpadKeyEvents) {
diff --git a/ui/file_manager/file_manager/background/js/background.js b/ui/file_manager/file_manager/background/js/background.js
index 6153ead..6f7c2e6 100644
--- a/ui/file_manager/file_manager/background/js/background.js
+++ b/ui/file_manager/file_manager/background/js/background.js
@@ -326,17 +326,20 @@
  * @type {Object}
  * @const
  */
-var FILE_MANAGER_WINDOW_CREATE_OPTIONS = Object.freeze({
-  bounds: Object.freeze({
+var FILE_MANAGER_WINDOW_CREATE_OPTIONS = {
+  bounds: {
     left: Math.round(window.screen.availWidth * 0.1),
     top: Math.round(window.screen.availHeight * 0.1),
     width: Math.round(window.screen.availWidth * 0.8),
     height: Math.round(window.screen.availHeight * 0.8)
-  }),
+  },
+  frame: {
+    color: '#1687d0'
+  },
   minWidth: 480,
   minHeight: 300,
   hidden: true
-});
+};
 
 /**
  * @param {Object=} opt_appState App state.
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
index d09cf7ba..2230324 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -85,6 +85,8 @@
           './gear_menu_controller.js',
           './import_controller.js',
           './launch_param.js',
+          './metadata/content_metadata_provider.js',
+          './metadata/external_metadata_provider.js',
           './metadata/file_system_metadata_provider.js',
           './metadata/metadata_cache.js',
           './metadata/metadata_cache_item.js',
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 7f035d2..662c39f9 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -276,8 +276,11 @@
  * @private
  */
 CommandHandler.prototype.shouldIgnoreEvents_ = function() {
-  // Do not handle commands, when a dialog is shown.
-  if (this.fileManager_.document.querySelector('.cr-dialog-container.shown'))
+  // Do not handle commands, when a dialog is shown. Do not use querySelector
+  // as it's much slower, and this method is executed often.
+  var dialogs = this.fileManager_.document.getElementsByClassName(
+      'cr-dialog-container');
+  if (dialogs.length !== 0 && dialogs[0].classList.contains('shown'))
     return true;
 
   return false;  // Do not ignore.
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
index 517f65b..ca75009 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
@@ -86,7 +86,7 @@
   this.endIndex_ = 0;
 
   /**
-   * Cursor begins from 0, and the origin in the list is beginIndex_.
+   * Cursor.
    * @type {number}
    * @private
    */
@@ -118,7 +118,7 @@
       delete this.cache_[removedItem.toURL()];
   }
 
-  this.cursor_ = 0;
+  this.cursor_ = this.beginIndex_;
   this.continue_();
 }
 
@@ -135,7 +135,7 @@
 
   this.beginIndex_ = beginIndex;
   this.endIndex_ = endIndex;
-  this.cursor_ = 0;
+  this.cursor_ = this.beginIndex_;
 
   this.continue_();
 }
@@ -143,7 +143,7 @@
 /**
  * Returns a thumbnail of an entry if it is in cache.
  *
- * @return {!Object} If the thumbnail is not in cache, this returns null.
+ * @return {Object} If the thumbnail is not in cache, this returns null.
  */
 ListThumbnailLoader.prototype.getThumbnailFromCache = function(entry) {
   return this.cache_[entry.toURL()] || null;
@@ -160,10 +160,7 @@
     return;
   }
 
-  var index = (this.beginIndex_ + this.cursor_) % this.dataModel_.length;
-  this.cursor_ += 1;
-
-  var entry = /** @type {Entry} */ (this.dataModel_.item(index));
+  var entry = /** @type {Entry} */ (this.dataModel_.item(this.cursor_++));
 
   // If the entry is a directory, already in cache or fetching, skip it.
   if (entry.isDirectory ||
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.html b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.html
index d282aa9..ec8bb367 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.html
@@ -4,6 +4,7 @@
   -- found in the LICENSE file.
   -->
 
+<script src="../../../../webui/resources/js/assert.js"></script>
 <script src="../../../../webui/resources/js/cr.js"></script>
 <script src="../../../../webui/resources/js/cr/event_target.js"></script>
 <script src="../../../../webui/resources/js/cr/ui.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
index 5c288ce4..8392ab1 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
@@ -41,37 +41,50 @@
   return canvas.toDataURL('image/jpeg', 0.5);
 }
 
-/**
- * Story test for list thumbnail loader.
- */
-function testStory(callback) {
+var listThumbnailLoader;
+var getOneCallbacks;
+var thumbnailLoadedEvents;
+var fileListModel;
+var fileSystem = new MockFileSystem('volume-id');
+var directory1 = new MockDirectoryEntry(fileSystem, '/TestDirectory');
+var entry1 = new MockEntry(fileSystem, '/Test1.jpg');
+var entry2 = new MockEntry(fileSystem, '/Test2.jpg');
+var entry3 = new MockEntry(fileSystem, '/Test3.jpg');
+var entry4 = new MockEntry(fileSystem, '/Test4.jpg');
+var entry5 = new MockEntry(fileSystem, '/Test5.jpg');
+
+function setUp() {
   ListThumbnailLoader.NUM_OF_MAX_ACTIVE_TASKS = 2;
   MockThumbnailLoader.setTestImageDataUrl(generateSampleImageDataUrl(document));
 
-  var getOneCallbacks = {};
+  getOneCallbacks = {};
   var metadataCache = {
     getOne: function(entry, type, callback) {
       getOneCallbacks[entry.toURL()] = callback;
     }
   };
 
-  var fileListModel = new FileListModel(metadataCache);
+  fileListModel = new FileListModel(metadataCache);
 
-  var listThumbnailLoader = new ListThumbnailLoader(fileListModel,
-      metadataCache, document, MockThumbnailLoader);
-  var thumbnailLoadedEvents = [];
+  listThumbnailLoader = new ListThumbnailLoader(fileListModel, metadataCache,
+      document, MockThumbnailLoader);
+
+  thumbnailLoadedEvents = [];
   listThumbnailLoader.addEventListener('thumbnailLoaded', function(event) {
     thumbnailLoadedEvents.push(event);
   });
+}
 
-  // Add 1 directory and 5 entries.
-  var fileSystem = new MockFileSystem('volume-id');
-  var directory1 = new MockDirectoryEntry(fileSystem, '/TestDirectory');
-  var entry1 = new MockEntry(fileSystem, '/Test1.jpg');
-  var entry2 = new MockEntry(fileSystem, '/Test2.jpg');
-  var entry3 = new MockEntry(fileSystem, '/Test3.jpg');
-  var entry4 = new MockEntry(fileSystem, '/Test4.jpg');
-  var entry5 = new MockEntry(fileSystem, '/Test5.jpg');
+function resolveGetOneCallback(url) {
+  assert(getOneCallbacks[url]);
+  getOneCallbacks[url]();
+  delete getOneCallbacks[url];
+}
+
+/**
+ * Story test for list thumbnail loader.
+ */
+function testStory(callback) {
   fileListModel.push(directory1, entry1, entry2, entry3, entry4, entry5);
 
   // Set high priority range to 0 - 2.
@@ -91,9 +104,7 @@
   assertArrayEquals([entry1.toURL(), entry2.toURL()],
       Object.keys(getOneCallbacks));
 
-  // Resolve metadataCache.getOne for Test2.jpg.
-  getOneCallbacks[entry2.toURL()]();
-  delete getOneCallbacks[entry2.toURL()];
+  resolveGetOneCallback(entry2.toURL());
 
   reportPromise(waitUntil(function() {
     // Assert that thumbnailLoaded event is fired for Test2.jpg.
@@ -123,9 +134,7 @@
     // Set high priority range to 2 - 4.
     listThumbnailLoader.setHighPriorityRange(2, 4);
 
-    // Resolve metadataCache.getOne for Test1.jpg.
-    getOneCallbacks[entry1.toURL()]();
-    delete getOneCallbacks[entry1.toURL()];
+    resolveGetOneCallback(entry1.toURL());
 
     // Assert that task for (Test3.jpg) is enqueued.
     return waitUntil(function() {
@@ -143,3 +152,18 @@
     });
   }), callback);
 }
+
+/**
+ * Do not enqueue prefetch task when high priority range is at the end of list.
+ */
+function testRangeIsAtTheEndOfList() {
+  // Set high priority range to 5 - 6.
+  listThumbnailLoader.setHighPriorityRange(5, 6);
+
+  fileListModel.push(directory1, entry1, entry2, entry3, entry4, entry5);
+
+  // Assert that a task is enqueued for entry5.
+  assertEquals(1, Object.keys(getOneCallbacks).length);
+  assertEquals('filesystem:volume-id/Test5.jpg',
+      Object.keys(getOneCallbacks)[0]);
+}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
new file mode 100644
index 0000000..c624065
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
@@ -0,0 +1,205 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @typedef {{
+ *   thumbnailURL:(string|undefined),
+ *   thumbnailTransform: (string|undefined)
+ * }}
+ */
+var ContentMetadata;
+
+/**
+ * @param {!MetadataProviderCache} cache
+ * @param {!MessagePort=} opt_messagePort Message port overriding the default
+ *     worker port.
+ * @extends {NewMetadataProvider<!ContentMetadata>}
+ * @constructor
+ * @struct
+ */
+function ContentMetadataProvider(cache, opt_messagePort) {
+  NewMetadataProvider.call(this, cache, ['thumbnailURL', 'thumbnailTransform']);
+
+  /**
+   * Pass all URLs to the metadata reader until we have a correct filter.
+   * @private {RegExp}
+   */
+  this.urlFilter_ = /.*/;
+
+  /**
+   * @private {!MessagePort}
+   * @const
+   */
+  this.dispatcher_ = opt_messagePort ?
+      opt_messagePort :
+      new SharedWorker(ContentMetadataProvider.WORKER_SCRIPT).port;
+  this.dispatcher_.onmessage = this.onMessage_.bind(this);
+  this.dispatcher_.postMessage({verb: 'init'});
+  this.dispatcher_.start();
+
+  /**
+   * Initialization is not complete until the Worker sends back the
+   * 'initialized' message.  See below.
+   * @private {boolean}
+   */
+  this.initialized_ = false;
+
+  /**
+   * Map from Entry.toURL() to callback.
+   * Note that simultaneous requests for same url are handled in MetadataCache.
+   * @private {!Object<!string, !Array<function(Object)>>}
+   * @const
+   */
+  this.callbacks_ = {};
+}
+
+/**
+ * Path of a worker script.
+ * @const {string}
+ */
+ContentMetadataProvider.WORKER_SCRIPT =
+    'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/' +
+    'foreground/js/metadata/metadata_dispatcher.js';
+
+/**
+ * Converts content metadata from parsers to the internal format.
+ * @param {Object} metadata The content metadata.
+ * @return {!ContentMetadata} Converted metadata.
+ */
+ContentMetadataProvider.convertContentMetadata = function(metadata) {
+  return {
+    thumbnailURL: metadata.thumbnailURL,
+    thumbnailTransform: metadata.thumbnailTransform
+  };
+};
+
+ContentMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
+
+/**
+ * @override
+ */
+ContentMetadataProvider.prototype.getImpl = function(requests) {
+  var promises = [];
+  for (var i = 0; i < requests.length; i++) {
+    promises.push(new Promise(function(request, fulfill, reject) {
+      this.fetch(request.entry, request.names, function(metadata) {
+        if (metadata)
+          fulfill(metadata);
+        else
+          reject();
+      });
+    }.bind(this, requests[i])));
+  }
+  return Promise.all(promises);
+};
+
+/**
+ * Fetches the metadata.
+ * @param {Entry} entry File entry.
+ * @param {!Array<string>} names Requested metadata type.
+ * @param {function(Object)} callback Callback expects a map from metadata type
+ *     to metadata value. This callback is called asynchronously.
+ */
+ContentMetadataProvider.prototype.fetch = function(entry, names, callback) {
+  if (entry.isDirectory) {
+    setTimeout(callback.bind(null, {}), 0);
+    return;
+  }
+  var url = entry.toURL();
+  if (this.callbacks_[url]) {
+    this.callbacks_[url].push(callback);
+  } else {
+    this.callbacks_[url] = [callback];
+    this.dispatcher_.postMessage({verb: 'request', arguments: [url]});
+  }
+};
+
+/**
+ * Dispatch a message from a metadata reader to the appropriate on* method.
+ * @param {Object} event The event.
+ * @private
+ */
+ContentMetadataProvider.prototype.onMessage_ = function(event) {
+  var data = event.data;
+  switch (data.verb) {
+    case 'initialized':
+      this.onInitialized_(data.arguments[0]);
+      break;
+    case 'result':
+      this.onResult_(data.arguments[0], data.arguments[1]);
+      break;
+    case 'error':
+      this.onError_(
+          data.arguments[0],
+          data.arguments[1],
+          data.arguments[2],
+          data.arguments[3]);
+      break;
+    case 'log':
+      this.onLog_(data.arguments[0]);
+      break;
+    default:
+      assertNotReached();
+      break;
+  }
+};
+
+/**
+ * Handles the 'initialized' message from the metadata reader Worker.
+ * @param {Object} regexp Regexp of supported urls.
+ * @private
+ */
+ContentMetadataProvider.prototype.onInitialized_ = function(regexp) {
+  this.urlFilter_ = regexp;
+
+  // Tests can monitor for this state with
+  // ExtensionTestMessageListener listener("worker-initialized");
+  // ASSERT_TRUE(listener.WaitUntilSatisfied());
+  // Automated tests need to wait for this, otherwise we crash in
+  // browser_test cleanup because the worker process still has
+  // URL requests in-flight.
+  util.testSendMessage('worker-initialized');
+  this.initialized_ = true;
+};
+
+/**
+ * Handles the 'result' message from the worker.
+ * @param {string} url File url.
+ * @param {Object} metadata The metadata.
+ * @private
+ */
+ContentMetadataProvider.prototype.onResult_ = function(url, metadata) {
+  var callbacks = this.callbacks_[url];
+  delete this.callbacks_[url];
+  for (var i = 0; i < callbacks.length; i++) {
+    callbacks[i](
+        metadata ?
+        ContentMetadataProvider.convertContentMetadata(metadata) : null);
+  }
+};
+
+/**
+ * Handles the 'error' message from the worker.
+ * @param {string} url File entry.
+ * @param {string} step Step failed.
+ * @param {string} error Error description.
+ * @param {Object?} metadata The metadata, if available.
+ * @private
+ */
+ContentMetadataProvider.prototype.onError_ =
+    function(url, step, error, metadata) {
+  if (MetadataCache.log)  // Avoid log spam by default.
+    console.warn('metadata: ' + url + ': ' + step + ': ' + error);
+  this.onResult_(url, null);
+};
+
+/**
+ * Handles the 'log' message from the worker.
+ * @param {Array.<*>} arglist Log arguments.
+ * @private
+ */
+ContentMetadataProvider.prototype.onLog_ = function(arglist) {
+  if (MetadataCache.log)  // Avoid log spam by default.
+    console.log.apply(console, ['metadata:'].concat(arglist));
+};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.html
new file mode 100644
index 0000000..8055430
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<!-- Copyright 2015 The Chromium 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 classes -->
+<script src="metadata_cache_set.js"></script>
+<script src="new_metadata_provider.js"></script>
+
+<!-- Others -->
+<script src="../../../../../../ui/webui/resources/js/assert.js"></script>
+<script src="../../../common/js/lru_cache.js"></script>
+<script src="../../../common/js/unittest_util.js"></script>
+<script src="metadata_cache_item.js"></script>
+<script src="content_metadata_provider.js"></script>
+
+<script src="content_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js
new file mode 100644
index 0000000..06c9b3f
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js
@@ -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.
+
+var entryA = {
+  toURL: function() { return "filesystem://A"; }
+};
+
+var entryB = {
+  toURL: function() { return "filesystem://B"; }
+};
+
+function testExternalMetadataProviderBasic(callback) {
+  // Mocking SharedWorker's port.
+  var port = {
+    postMessage: function(message) {
+      if (message.verb === 'request') {
+        this.onmessage({
+          data: {
+            verb: 'result',
+            arguments: [
+              message.arguments[0],
+              {
+                thumbnailURL: message.arguments[0] + ',url',
+                thumbnailTransform: message.arguments[0] + ',transform'
+              }
+            ]
+          }
+        });
+      }
+    },
+    start: function() {}
+  };
+  var cache = new MetadataProviderCache();
+  var provider = new ContentMetadataProvider(cache, port);
+  reportPromise(provider.get(
+      [entryA, entryB],
+      ['thumbnailURL', 'thumbnailTransform']).then(
+          function(results) {
+            assertEquals(2, results.length);
+            assertEquals('filesystem://A,url', results[0].thumbnailURL);
+            assertEquals(
+                'filesystem://A,transform', results[0].thumbnailTransform);
+            assertEquals('filesystem://B,url', results[1].thumbnailURL);
+            assertEquals(
+                'filesystem://B,transform', results[1].thumbnailTransform);
+          }), callback);
+}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
new file mode 100644
index 0000000..f2473b5
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
@@ -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.
+
+/**
+ * @typedef {{
+ *   size: number,
+ *   shared: (boolean|undefined),
+ *   modificationTime: Date,
+ *   thumbnailUrl: (string|undefined),
+ *   externalFileUrl: (string|undefined),
+ *   imageWidth: (number|undefined),
+ *   imageHeight: (number|undefined),
+ *   imageRotation: (number|undefined),
+ *   pinned: (boolean|undefined),
+ *   present: (boolean|undefined),
+ *   hosted: (boolean|undefined),
+ *   dirty: (boolean|undefined),
+ *   availableOffline: (boolean|undefined),
+ *   availableWhenMetered: (boolean|undefined),
+ *   customIconUrl: string,
+ *   contentMimeType: string,
+ *   sharedWithMe: (boolean|undefined)
+ * }}
+ */
+var ExternalMetadata;
+
+/**
+ * Metadata provider for FileEntry#getMetadata.
+ *
+ * @param {!MetadataProviderCache} cache
+ * @constructor
+ * @extends {NewMetadataProvider<!ExternalMetadata>}
+ * @struct
+ */
+function ExternalMetadataProvider(cache) {
+  NewMetadataProvider.call(this, cache, [
+    'availableOffline',
+    'availableWhenMetered',
+    'contentMimeType',
+    'customIconUrl',
+    'dirty',
+    'externalFileUrl',
+    'hosted',
+    'imageHeight',
+    'imageRotation',
+    'imageWidth',
+    'modificationTime',
+    'pinned',
+    'present',
+    'shared',
+    'sharedWithMe',
+    'size',
+    'thumbnailUrl'
+  ]);
+}
+
+ExternalMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
+
+/**
+ * @override
+ */
+ExternalMetadataProvider.prototype.getImpl = function(requests) {
+  return new Promise(function(fulfill, reject) {
+    var urls = [];
+    for (var i = 0; i < requests.length; i++) {
+      urls.push(requests[i].entry.toURL());
+    }
+    chrome.fileManagerPrivate.getEntryProperties(
+        urls,
+        function(results) {
+          if (!chrome.runtime.lastError)
+            fulfill(this.convertResults_(requests, results));
+          else
+            reject(chrome.runtime.lastError);
+        }.bind(this));
+  }.bind(this));
+};
+
+/**
+ * @param {!Array<!MetadataRequest>} requests
+ * @param {!Array<!EntryProperties>} propertiesList
+ * @return {!Array<!ExternalMetadata>}
+ */
+ExternalMetadataProvider.prototype.convertResults_ =
+    function(requests, propertiesList) {
+  var results = [];
+  for (var i = 0; i < propertiesList.length; i++) {
+    var properties = propertiesList[i];
+    results.push({
+      availableOffline: properties.isAvailableOffline,
+      availableWhenMetered: properties.isAvailableWhenMetered,
+      contentMimeType: properties.contentMimeType || '',
+      customIconUrl: properties.customIconUrl || '',
+      dirty: properties.isDirty,
+      externalFileUrl: properties.externalFileUrl,
+      hosted: properties.isHosted,
+      imageHeight: properties.imageHeight,
+      imageRotation: properties.imageRotation,
+      imageWidth: properties.imageWidth,
+      modificationTime: new Date(properties.lastModifiedTime),
+      pinned: properties.isPinned,
+      present: properties.isPresent,
+      shared: properties.shared,
+      sharedWithMe: properties.sharedWithMe,
+      size: requests[i].entry.isFile ? (properties.fileSize || 0) : -1,
+      thumbnailUrl: properties.thumbnailUrl
+    });
+  }
+  return results;
+};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html
new file mode 100644
index 0000000..c03656c
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<!-- Copyright 2015 The Chromium 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 classes -->
+<script src="metadata_cache_set.js"></script>
+<script src="new_metadata_provider.js"></script>
+
+<!-- Others -->
+<script src="../../../../../../ui/webui/resources/js/assert.js"></script>
+<script src="../../../common/js/lru_cache.js"></script>
+<script src="../../../common/js/unittest_util.js"></script>
+<script src="metadata_cache_item.js"></script>
+<script src="external_metadata_provider.js"></script>
+
+<script src="external_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js
new file mode 100644
index 0000000..2cb8e7a
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var entryA = {
+  toURL: function() { return "filesystem://A"; },
+  isFile: true
+};
+
+var entryB = {
+  toURL: function() { return "filesystem://B"; },
+  isFile: true
+};
+
+function testExternalMetadataProviderBasic(callback) {
+  // Mocking chrome API.
+  window.chrome = {
+    fileManagerPrivate: {
+      getEntryProperties: function(urls, callback) {
+        assertEquals('filesystem://A', urls[0]);
+        assertEquals('filesystem://B', urls[1]);
+        callback([{
+          lastModifiedTime: new Date(2015, 0, 1).getTime(),
+          fileSize: 1024
+        }, {
+          lastModifiedTime: new Date(2015, 1, 2).getTime(),
+          fileSize: 2048
+        }]);
+      }
+    },
+    runtime: {lastError: null}
+  };
+  var cache = new MetadataProviderCache();
+  var provider = new ExternalMetadataProvider(cache);
+  reportPromise(provider.get(
+      [entryA, entryB],
+      ['modificationTime', 'size']).then(
+          function(results) {
+            assertEquals(2, results.length);
+            assertEquals(
+                new Date(2015, 0, 1).toString(),
+                results[0].modificationTime.toString());
+            assertEquals(1024, results[0].size);
+            assertEquals(
+                new Date(2015, 1, 2).toString(),
+                results[1].modificationTime.toString());
+            assertEquals(2048, results[1].size);
+          }), callback);
+}
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
index 0580e1d..83d3b39 100644
--- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
+++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
@@ -54,7 +54,7 @@
       case ThumbnailLoader.LoadTarget.CONTENT_METADATA:
         if (opt_metadata.thumbnail && opt_metadata.thumbnail.url) {
           this.thumbnailUrl_ = opt_metadata.thumbnail.url;
-          this.thumbnailTransform =
+          this.transform_ =
               opt_metadata.thumbnail && opt_metadata.thumbnail.transform;
           this.loadTarget_ = ThumbnailLoader.LoadTarget.CONTENT_METADATA;
         }
@@ -241,6 +241,101 @@
 };
 
 /**
+ * Loads thumbnail as data url. If data url of thumbnail can be fetched from
+ * metadata, this fetches it from it. Otherwise, this tries to load it from
+ * thumbnail loader.
+ * Compared with ThumbnailLoader.load, this method does not provide a
+ * functionality to fit image to a box. This method is responsible for rotating
+ * and flipping a thumbnail.
+ *
+ * @return {!Promise<{data:string, width:number, height:number}>} A promise
+ *     which is resolved when data url is fetched.
+ */
+ThumbnailLoader.prototype.loadAsDataUrl = function() {
+  return new Promise(function(resolve) {
+    // Load by using ImageLoaderClient.
+    var modificationTime = this.metadata_ &&
+                           this.metadata_.filesystem &&
+                           this.metadata_.filesystem.modificationTime &&
+                           this.metadata_.filesystem.modificationTime.getTime();
+    ImageLoaderClient.getInstance().load(
+        this.thumbnailUrl_,
+        resolve,
+        {
+          maxWidth: ThumbnailLoader.THUMBNAIL_MAX_WIDTH,
+          maxHeight: ThumbnailLoader.THUMBNAIL_MAX_HEIGHT,
+          cache: true,
+          priority: this.priority_,
+          timestamp: modificationTime
+        });
+  }.bind(this)).then(function(result) {
+    if (!this.transform_)
+      return result;
+    else
+      return this.applyTransformToDataUrl_(
+          this.transform_, result.data, result.width, result.height);
+  }.bind(this));
+};
+
+/**
+ * Applies transform to data url.
+ *
+ * @param {{scaleX:number, scaleY:number, rotate90: number}} transform
+ *     Transform.
+ * @param {string} dataUrl Data url.
+ * @param {number} width Width.
+ * @param {number} height Height.
+ * @return {!Promise<{data:string, width:number, height:number}>} A promise
+ *     which is resolved with dataUrl and its width and height.
+ * @private
+ */
+ThumbnailLoader.prototype.applyTransformToDataUrl_ = function(
+    transform, dataUrl, width, height) {
+  var image = new Image();
+  var scaleX = this.transform_.scaleX;
+  var scaleY = this.transform_.scaleY;
+  var rotate90 = this.transform_.rotate90;
+
+  assert(scaleX === 1 || scaleX === -1);
+  assert(scaleY === 1 || scaleY === -1);
+  assert(rotate90 === 0 || rotate90 === 1);
+
+  return new Promise(function(resolve, reject) {
+    // Decode image for transformation.
+    image.onload = resolve;
+    image.onerror = reject;
+    image.src = dataUrl;
+  }).then(function() {
+    // Apply transform. Scale transformation should be applied before rotate
+    // transformation. i.e. When matrices for scale and rotate are A and B,
+    // transformation matrix should be BA.
+    var canvas = document.createElement('canvas');
+    var context = canvas.getContext('2d');
+
+    canvas.width = rotate90 === 1 ? height : width;
+    canvas.height = rotate90 === 1 ? width : height;
+
+    // Rotate 90 degree at center.
+    if (rotate90 === 1) {
+      context.translate(height, 0);
+      context.rotate(Math.PI / 2);
+    }
+
+    // Flip X and Y.
+    context.translate(scaleX === -1 ? width : 0, scaleY === -1 ? height : 0);
+    context.scale(scaleX, scaleY);
+
+    context.drawImage(image, 0, 0);
+
+    return {
+      data: canvas.toDataURL('image/png'),
+      width: canvas.width,
+      height: canvas.height
+    };
+  }.bind(this));
+}
+
+/**
  * Cancels loading the current image.
  */
 ThumbnailLoader.prototype.cancel = function() {
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.html b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.html
index 76374c6..a8e2aec 100644
--- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.html
@@ -3,7 +3,10 @@
   -- Use of this source code is governed by a BSD-style license that can be
   -- found in the LICENSE file.
   -->
+<script src="../../../../webui/resources/js/assert.js"></script>
 <script src="../../common/js/file_type.js"></script>
 <script src="../../common/js/mock_entry.js"></script>
+<script src="../../common/js/unittest_util.js"></script>
+<script src="../../../image_loader/image_loader_client.js"></script>
 <script src="thumbnail_loader.js"></script>
 <script src="thumbnail_loader_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js
index b306b66..e9f0d04c 100644
--- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js
@@ -6,6 +6,26 @@
   return new ThumbnailLoader(entry, null, metadata).getLoadTarget();
 }
 
+/**
+ * Generates a data url of a sample image for testing.
+ *
+ * @param {number} width Width.
+ * @param {number} height Height.
+ * @return {string} Data url of a sample image.
+ */
+function generateSampleImageDataUrl(width, height) {
+  var canvas = document.createElement('canvas');
+  canvas.width = width;
+  canvas.height = height;
+
+  var context = canvas.getContext('2d');
+  context.fillStyle = 'black';
+  context.fillRect(0, 0, width / 2, height / 2);
+  context.fillRect(width / 2, height / 2, width / 2, height / 2);
+
+  return canvas.toDataURL('image/png');
+}
+
 function testShouldUseMetadataThumbnail() {
   var mockFileSystem = new MockFileSystem('volumeId');
   var imageEntry = new MockEntry(mockFileSystem, '/test.jpg');
@@ -33,3 +53,108 @@
       getLoadTarget(
           pdfEntry, {external: {thumbnailUrl: 'url', dirty: true}}));
 }
+
+function testLoadAsDataUrlFromImageClient(callback) {
+  ImageLoaderClient.getInstance = function() {
+    return {
+      load: function(url, callback, opt_option) {
+        callback({
+          status: 'success', data: 'imageDataUrl', width: 32, height: 32});
+      }
+    };
+  };
+
+  var fileSystem = new MockFileSystem('volume-id');
+  var entry = new MockEntry(fileSystem, '/Test1.jpg');
+  var thumbnailLoader = new ThumbnailLoader(entry);
+  reportPromise(thumbnailLoader.loadAsDataUrl().then(function(result) {
+    assertEquals('imageDataUrl', result.data);
+  }), callback);
+}
+
+function testLoadAsDataUrlFromExifThumbnail(callback) {
+  ImageLoaderClient.getInstance = function() {
+    return {
+      load: function(url, callback, opt_option) {
+        // Assert that data url is passed.
+        assertTrue(/^data:/i.test(url));
+        callback({status: 'success', data: url, width: 32, height: 32});
+      }
+    };
+  };
+
+  var metadata = {
+    thumbnail: {
+      url: generateSampleImageDataUrl(32, 32)
+    }
+  };
+
+  var fileSystem = new MockFileSystem('volume-id');
+  var entry = new MockEntry(fileSystem, '/Test1.jpg');
+  var thumbnailLoader = new ThumbnailLoader(entry, undefined, metadata);
+  reportPromise(thumbnailLoader.loadAsDataUrl().then(function(result) {
+    assertEquals(metadata.thumbnail.url, result.data);
+  }), callback);
+}
+
+function testLoadAsDataUrlFromExifThumbnailRotate(callback) {
+  ImageLoaderClient.getInstance = function() {
+    return {
+      load: function(url, callback, opt_option) {
+        // Assert that data url is passed.
+        assertTrue(/^data:/i.test(url));
+        callback({status: 'success', data: url, width: 64, height: 32});
+      }
+    };
+  };
+
+  var metadata = {
+    thumbnail: {
+      url: generateSampleImageDataUrl(64, 32),
+      transform: {
+        rotate90: 1,
+        scaleX: 1,
+        scaleY: -1,
+      }
+    }
+  };
+
+  var fileSystem = new MockFileSystem('volume-id');
+  var entry = new MockEntry(fileSystem, '/Test1.jpg');
+  var thumbnailLoader = new ThumbnailLoader(entry, undefined, metadata);
+  reportPromise(thumbnailLoader.loadAsDataUrl().then(function(result) {
+    assertEquals(32, result.width);
+    assertEquals(64, result.height);
+    // For test image, transformed image should become equal to the following
+    // generated sample image.
+    assertEquals(generateSampleImageDataUrl(32, 64), result.data);
+  }), callback);
+}
+
+function testLoadAsDataUrlFromExternal(callback) {
+  var externalThumbnailUrl = 'https://external-thumbnail-url/';
+  var externalThumbnailDataUrl = generateSampleImageDataUrl(32, 32);
+
+  ImageLoaderClient.getInstance = function() {
+    return {
+      load: function(url, callback, opt_option) {
+        assertEquals(externalThumbnailUrl, url);
+        callback({status: 'success', data: externalThumbnailDataUrl,
+          width: 32, height: 32});
+      }
+    };
+  };
+
+  var metadata = {
+    external: {
+      thumbnailUrl: externalThumbnailUrl
+    }
+  }
+
+  var fileSystem = new MockFileSystem('volume-id');
+  var entry = new MockEntry(fileSystem, '/Test1.jpg');
+  var thumbnailLoader = new ThumbnailLoader(entry, undefined, metadata);
+  reportPromise(thumbnailLoader.loadAsDataUrl().then(function(result) {
+    assertEquals(externalThumbnailDataUrl, result.data);
+  }), callback);
+}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/dialog_footer.js b/ui/file_manager/file_manager/foreground/js/ui/dialog_footer.js
index 36a95dc..34515b2 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/dialog_footer.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/dialog_footer.js
@@ -71,7 +71,9 @@
 
 DialogFooter.prototype = {
   /**
-   * @return {number} Selected filter index.
+   * @return {number} Selected filter index. The index is 1 based and 0 means
+   *     'any file types'. Keep the meaniing consistent with the index passed to
+   *     chrome.fileManagerPrivate.selectFile.
    */
   get selectedFilterIndex() {
     return ~~this.fileTypeSelector.value;
@@ -129,13 +131,6 @@
  */
 DialogFooter.prototype.initFileTypeFilter = function(
     fileTypes, includeAllFiles) {
-  if (includeAllFiles) {
-    var option = document.createElement('option');
-    option.innerText = str('ALL_FILES_FILTER');
-    option.value = 0;
-    this.fileTypeSelector.appendChild(option);
-  }
-
   for (var i = 0; i < fileTypes.length; i++) {
     var fileType = fileTypes[i];
     var option = document.createElement('option');
@@ -171,6 +166,13 @@
     this.fileTypeSelector.appendChild(option);
   }
 
+  if (includeAllFiles) {
+    var option = document.createElement('option');
+    option.innerText = str('ALL_FILES_FILTER');
+    option.value = 0;
+    this.fileTypeSelector.appendChild(option);
+  }
+
   var options = this.fileTypeSelector.querySelectorAll('option');
   if (options.length >= 2) {
     // There is in fact no choice, show the selector.
diff --git a/ui/file_manager/integration_tests/file_manager/tasks.js b/ui/file_manager/integration_tests/file_manager/tasks.js
index 9e444f2..4e081ed 100644
--- a/ui/file_manager/integration_tests/file_manager/tasks.js
+++ b/ui/file_manager/integration_tests/file_manager/tasks.js
@@ -178,8 +178,8 @@
 
   // Wait for the dialog hidden, and the task is executed.
   var dialogHiddenPromise = itemClickedPromise.then(function() {
-    return remoteCall.waitForElement.bind(
-        remoteCall, windowId, '#default-action-dialog', null);
+    return remoteCall.waitForElementLost(
+        windowId, '#default-action-dialog', null);
   });
 
   // Execute the new default task.
diff --git a/ui/gfx/screen.h b/ui/gfx/screen.h
index 65d78fe..28652746 100644
--- a/ui/gfx/screen.h
+++ b/ui/gfx/screen.h
@@ -76,7 +76,7 @@
   // return the primary display.
   virtual gfx::Display GetDisplayNearestWindow(NativeView view) const = 0;
 
-  // Returns the display nearest the specified point.
+  // Returns the display nearest the specified point. |point| should be in DIPs.
   virtual gfx::Display GetDisplayNearestPoint(
       const gfx::Point& point) const = 0;
 
diff --git a/ui/gfx/screen_win.cc b/ui/gfx/screen_win.cc
index d5ad22b..9210971 100644
--- a/ui/gfx/screen_win.cc
+++ b/ui/gfx/screen_win.cc
@@ -136,7 +136,8 @@
 }
 
 gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const {
-  POINT initial_loc = { point.x(), point.y() };
+  gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point);
+  POINT initial_loc = { point_in_pixels.x(), point_in_pixels.y() };
   HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST);
   MONITORINFOEX mi;
   ZeroMemory(&mi, sizeof(MONITORINFOEX));
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 5943bb6a..cd25b04 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -817,18 +817,6 @@
 { 'return_type': 'void',
   'names': ['glReleaseShaderCompiler'],
   'arguments': 'void', },
-# Multisampling API is different in different GL versions, some require an
-# explicit resolve step for renderbuffers and/or FBO texture attachments and
-# some do not. Multiple alternatives might be present in a single
-# implementation, which require different use of the API and may have
-# different performance (explicit resolve performing worse, for example).
-# So even though the function signature is the same across versions, we split
-# their definitions so that the function to use can be chosen correctly at a
-# higher level.
-# TODO(oetuaho@nvidia.com): Some of these might still be possible to combine.
-# This could also fix weirdness in the mock bindings that's caused by the same
-# function name appearing multiple times.
-# This is the ES3 function, which requires explicit resolve:
 { 'return_type': 'void',
   'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'],
   'arguments':
@@ -838,18 +826,11 @@
   'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
                'GLsizei width, GLsizei height', },
 { 'return_type': 'void',
-  'names': ['glRenderbufferStorageMultisampleANGLE',
-            'glRenderbufferStorageMultisample'],
+  'names': ['glRenderbufferStorageMultisampleANGLE'],
   'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
                'GLsizei width, GLsizei height', },
-# In desktop GL, EXT and core versions both have an explicit resolve step,
-# though desktop core GL implicitly resolves when drawing to a window.
-# TODO(oetuaho@nvidia.com): Right now this function also doubles as ES2 EXT
-# function, which has implicit resolve, and for which the fallback is wrong.
-# Fix this.
 { 'return_type': 'void',
-  'names': ['glRenderbufferStorageMultisampleEXT',
-            'glRenderbufferStorageMultisample'],
+  'names': ['glRenderbufferStorageMultisampleEXT'],
   'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
                'GLsizei width, GLsizei height', },
 { 'return_type': 'void',
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index 642190c..11383b1 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -1692,12 +1692,7 @@
   }
 
   debug_fn.glRenderbufferStorageMultisampleANGLEFn = 0;
-  if (ver->IsAtLeastGL(3u, 0u) || ver->IsAtLeastGLES(3u, 0u)) {
-    fn.glRenderbufferStorageMultisampleANGLEFn =
-        reinterpret_cast<glRenderbufferStorageMultisampleANGLEProc>(
-            GetGLProcAddress("glRenderbufferStorageMultisample"));
-    DCHECK(fn.glRenderbufferStorageMultisampleANGLEFn);
-  } else if (ext.b_GL_ANGLE_framebuffer_multisample) {
+  if (ext.b_GL_ANGLE_framebuffer_multisample) {
     fn.glRenderbufferStorageMultisampleANGLEFn =
         reinterpret_cast<glRenderbufferStorageMultisampleANGLEProc>(
             GetGLProcAddress("glRenderbufferStorageMultisampleANGLE"));
@@ -1705,13 +1700,8 @@
   }
 
   debug_fn.glRenderbufferStorageMultisampleEXTFn = 0;
-  if (ver->IsAtLeastGL(3u, 0u) || ver->IsAtLeastGLES(3u, 0u)) {
-    fn.glRenderbufferStorageMultisampleEXTFn =
-        reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
-            GetGLProcAddress("glRenderbufferStorageMultisample"));
-    DCHECK(fn.glRenderbufferStorageMultisampleEXTFn);
-  } else if (ext.b_GL_EXT_multisampled_render_to_texture ||
-             ext.b_GL_EXT_framebuffer_multisample) {
+  if (ext.b_GL_EXT_multisampled_render_to_texture ||
+      ext.b_GL_EXT_framebuffer_multisample) {
     fn.glRenderbufferStorageMultisampleEXTFn =
         reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
             GetGLProcAddress("glRenderbufferStorageMultisampleEXT"));
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index 185d80964..8e84aa3 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -1829,8 +1829,8 @@
                                                        GLsizei width,
                                                        GLsizei height) {
   MakeFunctionUnique("glRenderbufferStorageMultisample");
-  interface_->RenderbufferStorageMultisampleEXT(target, samples, internalformat,
-                                                width, height);
+  interface_->RenderbufferStorageMultisample(target, samples, internalformat,
+                                             width, height);
 }
 
 void GL_BINDING_CALL
diff --git a/ui/keyboard/resources/keyboard_mojo.js b/ui/keyboard/resources/keyboard_mojo.js
index 27190fa..13f02421c 100644
--- a/ui/keyboard/resources/keyboard_mojo.js
+++ b/ui/keyboard/resources/keyboard_mojo.js
@@ -12,16 +12,19 @@
       'content/public/renderer/service_provider',
   ], function(connector, keyboard, serviceProvider) {
     'use strict';
-    function KeyboardImpl(kbd) {
-      console.log('Creating KeyboardImpl');
+    function TextInputTypeObserverImpl(kbd) {
+      console.log('Creating TextInputTypeObserverImpl');
       this.keyboard_ = kbd;
       mojo_api = this;
+      mojo_api.setTextInputTypeObserver(
+          connection.bindImpl(this, keyboard.TextInputTypeObserver));
     }
 
-    KeyboardImpl.prototype = Object.create(
+    TextInputTypeObserverImpl.prototype = Object.create(
         keyboard.KeyboardAPI.stubClass.prototype);
 
-    KeyboardImpl.prototype.onTextInputTypeChanged = function(input_type) {
+    TextInputTypeObserverImpl.prototype.onTextInputTypeChanged =
+        function(input_type) {
       console.log('Text input changed: ' + input_type);
       input_focused_event.forEach(function(listener) {
         listener({type: input_type});
@@ -29,11 +32,10 @@
     };
 
     return function() {
-      connection = new connector.Connection(
-          serviceProvider.connectToService(
-              keyboard.KeyboardUIHandlerMojo.name),
-          KeyboardImpl,
-          keyboard.KeyboardUIHandlerMojo.proxyClass);
+      const KBDApi = keyboard.KeyboardUIHandlerMojo;
+      new TextInputObserverImpl(connection.bindHandleToProxy(
+            serviceProvider.connectToService(KBDApi.name),
+            KBDApi));
     };
   });
 
diff --git a/ui/keyboard/webui/keyboard.mojom b/ui/keyboard/webui/keyboard.mojom
index 83e626b..889f75c 100644
--- a/ui/keyboard/webui/keyboard.mojom
+++ b/ui/keyboard/webui/keyboard.mojom
@@ -1,5 +1,12 @@
-[Client=KeyboardAPI]
+// Copyright 2015 The Chromium 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 keyboard;
+
 interface KeyboardUIHandlerMojo {
+  SetTextInputTypeObserver(TextInputTypeObserver observer);
+
   SendKeyEvent(string? event_type,
                int32 char_value,
                int32 key_code,
@@ -9,6 +16,6 @@
   HideKeyboard();
 };
 
-interface KeyboardAPI {
+interface TextInputTypeObserver {
   OnTextInputTypeChanged(string? input_type);
 };
diff --git a/ui/keyboard/webui/vk_mojo_handler.cc b/ui/keyboard/webui/vk_mojo_handler.cc
index 5efe763e..f40e9dbd 100644
--- a/ui/keyboard/webui/vk_mojo_handler.cc
+++ b/ui/keyboard/webui/vk_mojo_handler.cc
@@ -29,6 +29,11 @@
   return KeyboardController::GetInstance()->proxy()->GetInputMethod();
 }
 
+void VKMojoHandler::SetTextInputTypeObserver(
+    TextInputTypeObserverPtr observer) {
+  text_input_type_observer_ = observer.Pass();
+}
+
 void VKMojoHandler::SendKeyEvent(const mojo::String& event_type,
                                  int32_t char_value,
                                  int32_t key_code,
@@ -61,6 +66,9 @@
 
 void VKMojoHandler::OnTextInputStateChanged(
     const ui::TextInputClient* text_client) {
+  if (!text_input_type_observer_)
+    return;
+
   ui::TextInputType type =
       text_client ? text_client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
   std::string type_name = "none";
@@ -106,7 +114,7 @@
       type_name = "text";
       break;
   }
-  binding_.client()->OnTextInputTypeChanged(type_name);
+  text_input_type_observer_->OnTextInputTypeChanged(type_name);
 }
 
 void VKMojoHandler::OnInputMethodDestroyed(
diff --git a/ui/keyboard/webui/vk_mojo_handler.h b/ui/keyboard/webui/vk_mojo_handler.h
index 750120d..4afb1e1 100644
--- a/ui/keyboard/webui/vk_mojo_handler.h
+++ b/ui/keyboard/webui/vk_mojo_handler.h
@@ -22,6 +22,7 @@
   ui::InputMethod* GetInputMethod();
 
   // KeyboardUIHandlerMojo:
+  void SetTextInputTypeObserver(TextInputTypeObserverPtr observer) override;
   void SendKeyEvent(const mojo::String& event_type,
                     int32_t char_value,
                     int32_t key_code,
@@ -38,6 +39,7 @@
   void OnInputMethodDestroyed(const ui::InputMethod* input_method) override;
   void OnShowImeIfNeeded() override;
 
+  TextInputTypeObserverPtr text_input_type_observer_;
   mojo::Binding<KeyboardUIHandlerMojo> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(VKMojoHandler);
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index 96f6e24..0f4a274c 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -1033,9 +1033,9 @@
     },
 
     customizeUserPodPerUserType: function() {
-      if (this.user_.isChildUser && !this.user_.isDesktopUser) {
+      if (this.user_.childUser && !this.user_.isDesktopUser) {
         this.setUserPodIconType('child');
-      } else if (this.user_.isSupervisedUser && !this.user_.isDesktopUser) {
+      } else if (this.user_.supervisedUser && !this.user_.isDesktopUser) {
         this.setUserPodIconType('supervised');
       } else if (this.multiProfilesPolicyApplied) {
         // Mark user pod as not focusable which in addition to the grayed out
@@ -1931,9 +1931,8 @@
       this.nameElement.textContent = this.user.displayName;
 
       var isLockedUser = this.user.needsSignin;
-      var isSupervisedUser = this.user.supervisedUser;
+      var isLegacySupervisedUser = this.user.supervisedUser;
       var isChildUser = this.user.childUser;
-      var isLegacySupervisedUser = isSupervisedUser && !isChildUser;
       this.classList.toggle('locked', isLockedUser);
       this.classList.toggle('legacy-supervised', isLegacySupervisedUser);
       this.classList.toggle('child', isChildUser);
diff --git a/ui/message_center/message_center_unittests.isolate b/ui/message_center/message_center_unittests.isolate
index 7ad8cc3c..74c1057b 100644
--- a/ui/message_center/message_center_unittests.isolate
+++ b/ui/message_center/message_center_unittests.isolate
@@ -22,6 +22,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../../testing/xvfb.py',
@@ -59,6 +61,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index 09041824..6eedae3 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -178,5 +178,6 @@
   deps = [
            "//base/test:test_support",
            "//testing/gtest",
+           "//ui/gfx/geometry",
          ] + ozone_platform_test_deps
 }
diff --git a/ui/ozone/demo/BUILD.gn b/ui/ozone/demo/BUILD.gn
index 8e33185..fd9bfbb 100644
--- a/ui/ozone/demo/BUILD.gn
+++ b/ui/ozone/demo/BUILD.gn
@@ -30,5 +30,6 @@
     "//ui/gl",
     "//ui/ozone",
     "//ui/ozone/gpu",
+    "//ui/ozone:ozone_base",
   ]
 }
diff --git a/ui/ozone/gpu/BUILD.gn b/ui/ozone/gpu/BUILD.gn
index 3906c43..b59bf374 100644
--- a/ui/ozone/gpu/BUILD.gn
+++ b/ui/ozone/gpu/BUILD.gn
@@ -17,5 +17,6 @@
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gl",
+    "//ui/ozone:ozone_base",
   ]
 }
diff --git a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
index 263fdc34..9b463b9 100644
--- a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
+++ b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
@@ -161,10 +161,19 @@
     }
     pixmap = it->second.get();
   }
+  return CreateImageForPixmap(pixmap, size, format, internalformat);
+}
+
+scoped_refptr<gfx::GLImage>
+GpuMemoryBufferFactoryOzoneNativeBuffer::CreateImageForPixmap(
+    scoped_refptr<NativePixmap> pixmap,
+    const gfx::Size& size,
+    gfx::GpuMemoryBuffer::Format format,
+    unsigned internalformat) {
   if (pixmap->GetEGLClientBuffer()) {
     scoped_refptr<GLImageOzoneNativePixmap> image =
         new GLImageOzoneNativePixmap(size);
-    if (!image->Initialize(pixmap)) {
+    if (!image->Initialize(pixmap.get())) {
       return scoped_refptr<gfx::GLImage>();
     }
     return image;
@@ -172,7 +181,7 @@
   if (pixmap->GetDmaBufFd() > 0) {
     scoped_refptr<GLImageOzoneNativePixmapDmaBuf> image =
         new GLImageOzoneNativePixmapDmaBuf(size, internalformat);
-    if (!image->Initialize(pixmap, format)) {
+    if (!image->Initialize(pixmap.get(), format)) {
       return scoped_refptr<gfx::GLImage>();
     }
     return image;
diff --git a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h
index bf98786..006a4a54 100644
--- a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h
+++ b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h
@@ -13,6 +13,7 @@
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/gpu/ozone_gpu_export.h"
+#include "ui/ozone/public/native_pixmap.h"
 
 namespace gfx {
 class GLImage;
@@ -48,6 +49,12 @@
       unsigned internalformat,
       int client_id);
 
+  static scoped_refptr<gfx::GLImage> CreateImageForPixmap(
+      scoped_refptr<NativePixmap> pixmap,
+      const gfx::Size& size,
+      gfx::GpuMemoryBuffer::Format format,
+      unsigned internalformat);
+
  private:
   BufferToPixmapMap native_pixmap_map_;
   base::Lock native_pixmap_map_lock_;
diff --git a/ui/ozone/gpu/ozone_gpu.gyp b/ui/ozone/gpu/ozone_gpu.gyp
index 72bf156..cbc895d 100644
--- a/ui/ozone/gpu/ozone_gpu.gyp
+++ b/ui/ozone/gpu/ozone_gpu.gyp
@@ -15,6 +15,7 @@
         '../../gfx/gfx.gyp:gfx',
         '../../gfx/gfx.gyp:gfx_geometry',
         '../../gl/gl.gyp:gl',
+        '../ozone.gyp:ozone_base',
       ],
       'defines': [
         'OZONE_GPU_IMPLEMENTATION',
diff --git a/ui/ozone/ozone.gyp b/ui/ozone/ozone.gyp
index ce55e3f..4869a9e 100644
--- a/ui/ozone/ozone.gyp
+++ b/ui/ozone/ozone.gyp
@@ -183,6 +183,7 @@
         '../../base/base.gyp:base',
         '../../base/base.gyp:test_support_base',
         '../../testing/gtest.gyp:gtest',
+        '../gfx/gfx.gyp:gfx_geometry',
         '<@(external_ozone_platform_unittest_deps)',
         '<@(internal_ozone_platform_unittest_deps)',
       ],
diff --git a/ui/ozone/platform/caca/BUILD.gn b/ui/ozone/platform/caca/BUILD.gn
index 3f0eb53..fd164f8 100644
--- a/ui/ozone/platform/caca/BUILD.gn
+++ b/ui/ozone/platform/caca/BUILD.gn
@@ -22,6 +22,7 @@
     "//base",
     "//skia",
     "//ui/events/ozone:events_ozone_layout",
+    "//ui/events/platform",
     "//ui/gfx/geometry",
   ]
 
diff --git a/ui/ozone/platform/caca/caca.gypi b/ui/ozone/platform/caca/caca.gypi
index 7aa0d2ab..611d40b8 100644
--- a/ui/ozone/platform/caca/caca.gypi
+++ b/ui/ozone/platform/caca/caca.gypi
@@ -23,6 +23,7 @@
         '../../skia/skia.gyp:skia',
         '../events/events.gyp:events',
         '../events/ozone/events_ozone.gyp:events_ozone_layout',
+        '../events/platform/events_platform.gyp:events_platform',
         '../gfx/gfx.gyp:gfx',
         '../gfx/gfx.gyp:gfx_geometry',
       ],
diff --git a/ui/ozone/platform/dri/BUILD.gn b/ui/ozone/platform/dri/BUILD.gn
index 3a491677..f1fd02ca 100644
--- a/ui/ozone/platform/dri/BUILD.gn
+++ b/ui/ozone/platform/dri/BUILD.gn
@@ -35,8 +35,6 @@
     "dri_gpu_platform_support_.h",
     "dri_gpu_platform_support_host.cc",
     "dri_gpu_platform_support_host.h",
-    "dri_helper_thread.cc",
-    "dri_helper_thread.h",
     "dri_surface.cc",
     "dri_surface.h",
     "dri_surface_factory.cc",
@@ -77,6 +75,8 @@
     "scanout_buffer.h",
   ]
 
+  defines = [ "OZONE_IMPLEMENTATION" ]
+
   deps = [
     "//base",
     "//skia",
@@ -85,8 +85,10 @@
     "//ui/display/types",
     "//ui/display/util",
     "//ui/events",
+    "//ui/events/devices",
     "//ui/events/ozone:events_ozone_evdev",
     "//ui/events/ozone:events_ozone_layout",
+    "//ui/events/platform",
     "//ui/gfx",
     "//ui/gfx/geometry",
   ]
@@ -116,17 +118,19 @@
       "dri_surface_unittest.cc",
       "dri_window_delegate_impl_unittest.cc",
       "hardware_display_controller_unittest.cc",
-      "hardware_display_manager_unittest.cc",
+      "hardware_display_plane_manager_unittest.cc",
       "screen_manager_unittest.cc",
       "test/mock_dri_wrapper.cc",
       "test/mock_dri_wrapper.h",
     ]
 
     deps = [
-      ":dri_common",
       "//skia",
       "//testing/gtest",
+      "//ui/ozone",
     ]
+
+    public_configs = [ ":libdrm" ]
   }
 }
 
diff --git a/ui/ozone/platform/dri/crtc_controller.h b/ui/ozone/platform/dri/crtc_controller.h
index d9e26bc..d814ba67 100644
--- a/ui/ozone/platform/dri/crtc_controller.h
+++ b/ui/ozone/platform/dri/crtc_controller.h
@@ -11,6 +11,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/hardware_display_plane_manager.h"
 #include "ui/ozone/platform/dri/overlay_plane.h"
 #include "ui/ozone/platform/dri/scoped_drm_types.h"
@@ -25,7 +26,8 @@
 // One CRTC can be paired up with one or more connectors. The simplest
 // configuration represents one CRTC driving one monitor, while pairing up a
 // CRTC with multiple connectors results in hardware mirroring.
-class CrtcController : public base::SupportsWeakPtr<CrtcController> {
+class OZONE_EXPORT CrtcController
+    : public base::SupportsWeakPtr<CrtcController> {
  public:
   CrtcController(DriWrapper* drm, uint32_t crtc, uint32_t connector);
   ~CrtcController();
diff --git a/ui/ozone/platform/dri/dri.gypi b/ui/ozone/platform/dri/dri.gypi
index 0048f14c..96e5fc2c 100644
--- a/ui/ozone/platform/dri/dri.gypi
+++ b/ui/ozone/platform/dri/dri.gypi
@@ -25,9 +25,11 @@
         '../base/ui_base.gyp:ui_base',
         '../display/display.gyp:display_types',
         '../display/display.gyp:display_util',
+        '../events/devices/events_devices.gyp:events_devices',
         '../events/events.gyp:events',
         '../events/ozone/events_ozone.gyp:events_ozone_evdev',
         '../events/ozone/events_ozone.gyp:events_ozone_layout',
+        '../events/platform/events_platform.gyp:events_platform',
         '../gfx/gfx.gyp:gfx',
         '../gfx/gfx.gyp:gfx_geometry',
       ],
@@ -55,8 +57,6 @@
         'dri_gpu_platform_support.h',
         'dri_gpu_platform_support_host.cc',
         'dri_gpu_platform_support_host.h',
-        'dri_helper_thread.cc',
-        'dri_helper_thread.h',
         'dri_surface.cc',
         'dri_surface.h',
         'dri_surface_factory.cc',
@@ -106,7 +106,7 @@
         '../../build/linux/system.gyp:libdrm',
         '../../skia/skia.gyp:skia',
         '../gfx/gfx.gyp:gfx_geometry',
-        'ozone_platform_dri',
+        'ozone.gyp:ozone',
       ],
       'export_dependent_settings': [
         '../../build/linux/system.gyp:libdrm',
diff --git a/ui/ozone/platform/dri/dri_buffer.h b/ui/ozone/platform/dri/dri_buffer.h
index d20a1f9..9b22e751 100644
--- a/ui/ozone/platform/dri/dri_buffer.h
+++ b/ui/ozone/platform/dri/dri_buffer.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
 
 namespace ui {
@@ -17,7 +18,7 @@
 // Wrapper for a DRM allocated buffer. Keeps track of the native properties of
 // the buffer and wraps the pixel memory into a SkSurface which can be used to
 // draw into using Skia.
-class DriBuffer : public ScanoutBuffer {
+class OZONE_EXPORT DriBuffer : public ScanoutBuffer {
  public:
   DriBuffer(DriWrapper* dri);
 
@@ -53,7 +54,7 @@
   DISALLOW_COPY_AND_ASSIGN(DriBuffer);
 };
 
-class DriBufferGenerator : public ScanoutBufferGenerator {
+class OZONE_EXPORT DriBufferGenerator : public ScanoutBufferGenerator {
  public:
   DriBufferGenerator();
   ~DriBufferGenerator() override;
diff --git a/ui/ozone/platform/dri/dri_gpu_platform_support.cc b/ui/ozone/platform/dri/dri_gpu_platform_support.cc
index fa0923f..af7ed4df 100644
--- a/ui/ozone/platform/dri/dri_gpu_platform_support.cc
+++ b/ui/ozone/platform/dri/dri_gpu_platform_support.cc
@@ -13,7 +13,6 @@
 #include "ui/ozone/common/display_util.h"
 #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
 #include "ui/ozone/common/gpu/ozone_gpu_messages.h"
-#include "ui/ozone/platform/dri/dri_helper_thread.h"
 #include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
 #include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
 #include "ui/ozone/platform/dri/dri_wrapper.h"
@@ -32,9 +31,13 @@
 
 class DriGpuPlatformSupportMessageFilter : public IPC::MessageFilter {
  public:
+  typedef base::Callback<void(
+      const scoped_refptr<base::SingleThreadTaskRunner>&)>
+      OnFilterAddedCallback;
+
   DriGpuPlatformSupportMessageFilter(
       DriWindowDelegateManager* window_manager,
-      const base::Closure& on_filter_added_callback,
+      const OnFilterAddedCallback& on_filter_added_callback,
       IPC::Listener* main_thread_listener)
       : window_manager_(window_manager),
         on_filter_added_callback_(on_filter_added_callback),
@@ -45,7 +48,9 @@
 
   void OnFilterAdded(IPC::Sender* sender) override {
     io_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
-    main_thread_task_runner_->PostTask(FROM_HERE, on_filter_added_callback_);
+    main_thread_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(on_filter_added_callback_, io_thread_task_runner_));
   }
 
   // This code is meant to be very temporary and only as a special case to fix
@@ -154,7 +159,7 @@
   }
 
   DriWindowDelegateManager* window_manager_;
-  base::Closure on_filter_added_callback_;
+  OnFilterAddedCallback on_filter_added_callback_;
   IPC::Listener* main_thread_listener_;
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
@@ -174,8 +179,8 @@
       screen_manager_(screen_manager),
       ndd_(ndd.Pass()) {
   filter_ = new DriGpuPlatformSupportMessageFilter(
-      window_manager,
-      base::Bind(&DriGpuPlatformSupport::OnFilterAdded, base::Unretained(this)),
+      window_manager, base::Bind(&DriGpuPlatformSupport::SetIOTaskRunner,
+                                 base::Unretained(this)),
       this);
 }
 
@@ -352,14 +357,13 @@
   callback.Run();
 }
 
-void DriGpuPlatformSupport::OnFilterAdded() {
+void DriGpuPlatformSupport::SetIOTaskRunner(
+    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) {
+  io_task_runner_ = io_task_runner;
   base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
-  // Only surfaceless path supports async page flips. So we only initialize the
-  // helper thread if we're using async page flips.
-  if (!helper_thread_.IsRunning() &&
-      cmd->HasSwitch(switches::kOzoneUseSurfaceless)) {
-    helper_thread_.Initialize();
-    drm_->InitializeTaskRunner(helper_thread_.task_runner());
+  // Only surfaceless path supports async page flips.
+  if (cmd->HasSwitch(switches::kOzoneUseSurfaceless)) {
+    drm_->InitializeTaskRunner(io_task_runner_);
   }
 }
 
diff --git a/ui/ozone/platform/dri/dri_gpu_platform_support.h b/ui/ozone/platform/dri/dri_gpu_platform_support.h
index daae2ec..23257bf 100644
--- a/ui/ozone/platform/dri/dri_gpu_platform_support.h
+++ b/ui/ozone/platform/dri/dri_gpu_platform_support.h
@@ -10,13 +10,13 @@
 #include "base/memory/scoped_vector.h"
 #include "ipc/message_filter.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/platform/dri/dri_helper_thread.h"
 #include "ui/ozone/public/gpu_platform_support.h"
 
 class SkBitmap;
 
 namespace base {
 class FilePath;
+class SingleThreadTaskRunner;
 }
 
 namespace gfx {
@@ -77,17 +77,18 @@
   void OnAddGraphicsDevice(const base::FilePath& path);
   void OnRemoveGraphicsDevice(const base::FilePath& path);
 
-  void OnFilterAdded();
+  void SetIOTaskRunner(
+      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
 
   IPC::Sender* sender_;                       // Not owned.
   DriWrapper* drm_;                           // Not owned.
   DriWindowDelegateManager* window_manager_;  // Not owned.
   ScreenManager* screen_manager_;             // Not owned.
 
-  DriHelperThread helper_thread_;
   scoped_ptr<NativeDisplayDelegateDri> ndd_;
   ScopedVector<GpuPlatformSupport> handlers_;
   scoped_refptr<IPC::MessageFilter> filter_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/dri/dri_helper_thread.cc b/ui/ozone/platform/dri/dri_helper_thread.cc
deleted file mode 100644
index 4ca33017..0000000
--- a/ui/ozone/platform/dri/dri_helper_thread.cc
+++ /dev/null
@@ -1,23 +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 "ui/ozone/platform/dri/dri_helper_thread.h"
-
-namespace ui {
-
-DriHelperThread::DriHelperThread() : Thread("DriHelperThread") {
-}
-
-DriHelperThread::~DriHelperThread() {
-  Stop();
-}
-
-void DriHelperThread::Initialize() {
-  DCHECK(!IsRunning());
-
-  if (!StartWithOptions(base::Thread::Options(base::MessageLoop::TYPE_IO, 0)))
-    LOG(FATAL) << "Failed to start the IO helper thread";
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/dri/dri_helper_thread.h b/ui/ozone/platform/dri/dri_helper_thread.h
deleted file mode 100644
index fea01d9..0000000
--- a/ui/ozone/platform/dri/dri_helper_thread.h
+++ /dev/null
@@ -1,27 +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.
-
-#ifndef UI_OZONE_PLATFORM_DRI_DRI_HELPER_THREAD_H_
-#define UI_OZONE_PLATFORM_DRI_DRI_HELPER_THREAD_H_
-
-#include "base/threading/thread.h"
-
-namespace ui {
-
-class DriHelperThread : public base::Thread {
- public:
-  DriHelperThread();
-  ~DriHelperThread() override;
-
-  // Call to start the thread. This needs to be called after the GPU entered the
-  // sandbox.
-  void Initialize();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DriHelperThread);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRI_DRI_HELPER_THREAD_H_
diff --git a/ui/ozone/platform/dri/dri_surface.h b/ui/ozone/platform/dri/dri_surface.h
index 9c439e3..6ba581e 100644
--- a/ui/ozone/platform/dri/dri_surface.h
+++ b/ui/ozone/platform/dri/dri_surface.h
@@ -9,6 +9,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
 class SkSurface;
@@ -20,7 +21,7 @@
 class DriWrapper;
 class HardwareDisplayController;
 
-class DriSurface : public SurfaceOzoneCanvas {
+class OZONE_EXPORT DriSurface : public SurfaceOzoneCanvas {
  public:
   DriSurface(DriWindowDelegate* window_delegate, DriWrapper* dri);
   ~DriSurface() override;
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl.h b/ui/ozone/platform/dri/dri_window_delegate_impl.h
index 445cc4c..89de303 100644
--- a/ui/ozone/platform/dri/dri_window_delegate_impl.h
+++ b/ui/ozone/platform/dri/dri_window_delegate_impl.h
@@ -9,6 +9,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/display_change_observer.h"
 #include "ui/ozone/platform/dri/dri_window_delegate.h"
 
@@ -20,8 +21,8 @@
 class HardwareDisplayController;
 class ScreenManager;
 
-class DriWindowDelegateImpl : public DriWindowDelegate,
-                              public DisplayChangeObserver {
+class OZONE_EXPORT DriWindowDelegateImpl : public DriWindowDelegate,
+                                           public DisplayChangeObserver {
  public:
   DriWindowDelegateImpl(gfx::AcceleratedWidget widget,
                         DriWrapper* drm,
diff --git a/ui/ozone/platform/dri/dri_window_delegate_manager.h b/ui/ozone/platform/dri/dri_window_delegate_manager.h
index eb4f7b9..5a4ed27 100644
--- a/ui/ozone/platform/dri/dri_window_delegate_manager.h
+++ b/ui/ozone/platform/dri/dri_window_delegate_manager.h
@@ -7,12 +7,13 @@
 
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/ozone_export.h"
 
 namespace ui {
 
 class DriWindowDelegate;
 
-class DriWindowDelegateManager {
+class OZONE_EXPORT DriWindowDelegateManager {
  public:
   DriWindowDelegateManager();
   ~DriWindowDelegateManager();
diff --git a/ui/ozone/platform/dri/dri_wrapper.h b/ui/ozone/platform/dri/dri_wrapper.h
index 381459e..484174d 100644
--- a/ui/ozone/platform/dri/dri_wrapper.h
+++ b/ui/ozone/platform/dri/dri_wrapper.h
@@ -15,6 +15,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/overlay_transform.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/hardware_display_plane_manager.h"
 #include "ui/ozone/platform/dri/scoped_drm_types.h"
 
@@ -34,7 +35,7 @@
 // Wraps DRM calls into a nice interface. Used to provide different
 // implementations of the DRM calls. For the actual implementation the DRM API
 // would be called. In unit tests this interface would be stubbed.
-class DriWrapper {
+class OZONE_EXPORT DriWrapper {
  public:
   typedef base::Callback<void(unsigned int /* frame */,
                               unsigned int /* seconds */,
diff --git a/ui/ozone/platform/dri/hardware_display_controller.h b/ui/ozone/platform/dri/hardware_display_controller.h
index 0c09fce7..46254f5 100644
--- a/ui/ozone/platform/dri/hardware_display_controller.h
+++ b/ui/ozone/platform/dri/hardware_display_controller.h
@@ -18,6 +18,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/hardware_display_plane_manager.h"
 #include "ui/ozone/platform/dri/overlay_plane.h"
 #include "ui/ozone/platform/dri/page_flip_observer.h"
@@ -86,7 +87,7 @@
 // only a subset of connectors can be active independently, showing different
 // framebuffers. Though, in this case, it would be possible to have all
 // connectors active if some use the same CRTC to mirror the display.
-class HardwareDisplayController
+class OZONE_EXPORT HardwareDisplayController
     : public base::SupportsWeakPtr<HardwareDisplayController>,
       public PageFlipObserver {
  public:
diff --git a/ui/ozone/platform/dri/hardware_display_plane.h b/ui/ozone/platform/dri/hardware_display_plane.h
index 7ea4f95..e8589317 100644
--- a/ui/ozone/platform/dri/hardware_display_plane.h
+++ b/ui/ozone/platform/dri/hardware_display_plane.h
@@ -9,6 +9,7 @@
 #include <stdint.h>
 
 #include "base/basictypes.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/scoped_drm_types.h"
 
 namespace gfx {
@@ -19,7 +20,7 @@
 
 class DriWrapper;
 
-class HardwareDisplayPlane {
+class OZONE_EXPORT HardwareDisplayPlane {
  public:
   HardwareDisplayPlane(ScopedDrmPlanePtr plane);
   HardwareDisplayPlane(uint32_t plane_id, uint32_t possible_crtcs);
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager.h b/ui/ozone/platform/dri/hardware_display_plane_manager.h
index d45c7b7..9839b72 100644
--- a/ui/ozone/platform/dri/hardware_display_plane_manager.h
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager.h
@@ -12,6 +12,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_vector.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/hardware_display_plane.h"
 #include "ui/ozone/platform/dri/overlay_plane.h"
 #include "ui/ozone/platform/dri/scoped_drm_types.h"
@@ -27,7 +28,7 @@
 
 // This contains the list of planes controlled by one HDC on a given DRM fd.
 // It is owned by the HDC and filled by the CrtcController.
-struct HardwareDisplayPlaneList {
+struct OZONE_EXPORT HardwareDisplayPlaneList {
   HardwareDisplayPlaneList();
   ~HardwareDisplayPlaneList();
 
@@ -69,7 +70,7 @@
   bool committed;
 };
 
-class HardwareDisplayPlaneManager {
+class OZONE_EXPORT HardwareDisplayPlaneManager {
  public:
   HardwareDisplayPlaneManager();
   virtual ~HardwareDisplayPlaneManager();
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h b/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h
index a9cdf648..07d05c4 100644
--- a/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h
@@ -5,11 +5,13 @@
 #ifndef UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_PLANE_MANAGER_ATOMIC_H_
 #define UI_OZONE_PLATFORM_DRI_HARDWARE_DISPLAY_PLANE_MANAGER_ATOMIC_H_
 
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/hardware_display_plane_manager.h"
 
 namespace ui {
 
-class HardwareDisplayPlaneManagerLegacy : public HardwareDisplayPlaneManager {
+class OZONE_EXPORT HardwareDisplayPlaneManagerLegacy
+    : public HardwareDisplayPlaneManager {
  public:
   HardwareDisplayPlaneManagerLegacy();
   ~HardwareDisplayPlaneManagerLegacy() override;
diff --git a/ui/ozone/platform/dri/overlay_plane.h b/ui/ozone/platform/dri/overlay_plane.h
index 7e8e1d5..9b566ac 100644
--- a/ui/ozone/platform/dri/overlay_plane.h
+++ b/ui/ozone/platform/dri/overlay_plane.h
@@ -10,6 +10,7 @@
 #include "base/memory/ref_counted.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/overlay_transform.h"
+#include "ui/ozone/ozone_export.h"
 
 namespace ui {
 
@@ -18,7 +19,7 @@
 struct OverlayPlane;
 typedef std::vector<OverlayPlane> OverlayPlaneList;
 
-struct OverlayPlane {
+struct OZONE_EXPORT OverlayPlane {
   // Simpler constructor for the primary plane.
   explicit OverlayPlane(scoped_refptr<ScanoutBuffer> buffer);
 
diff --git a/ui/ozone/platform/dri/scoped_drm_types.h b/ui/ozone/platform/dri/scoped_drm_types.h
index e651232..bd8b4bc 100644
--- a/ui/ozone/platform/dri/scoped_drm_types.h
+++ b/ui/ozone/platform/dri/scoped_drm_types.h
@@ -6,6 +6,7 @@
 #define UI_OZONE_PLATFORM_DRI_SCOPED_DRM_TYPES_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "ui/ozone/ozone_export.h"
 
 typedef struct _drmModeConnector drmModeConnector;
 typedef struct _drmModeCrtc drmModeCrtc;
@@ -20,34 +21,34 @@
 
 namespace ui {
 
-struct DrmResourcesDeleter {
+struct OZONE_EXPORT DrmResourcesDeleter {
   void operator()(drmModeRes* resources) const;
 };
-struct DrmConnectorDeleter {
+struct OZONE_EXPORT DrmConnectorDeleter {
   void operator()(drmModeConnector* connector) const;
 };
-struct DrmCrtcDeleter {
+struct OZONE_EXPORT DrmCrtcDeleter {
   void operator()(drmModeCrtc* crtc) const;
 };
-struct DrmEncoderDeleter {
+struct OZONE_EXPORT DrmEncoderDeleter {
   void operator()(drmModeEncoder* encoder) const;
 };
-struct DrmObjectPropertiesDeleter {
+struct OZONE_EXPORT DrmObjectPropertiesDeleter {
   void operator()(drmModeObjectProperties* properties) const;
 };
-struct DrmPlaneDeleter {
+struct OZONE_EXPORT DrmPlaneDeleter {
   void operator()(drmModePlane* plane) const;
 };
-struct DrmPlaneResDeleter {
+struct OZONE_EXPORT DrmPlaneResDeleter {
   void operator()(drmModePlaneRes* plane_res) const;
 };
-struct DrmPropertyDeleter {
+struct OZONE_EXPORT DrmPropertyDeleter {
   void operator()(drmModePropertyRes* property) const;
 };
-struct DrmPropertyBlobDeleter {
+struct OZONE_EXPORT DrmPropertyBlobDeleter {
   void operator()(drmModePropertyBlobRes* property) const;
 };
-struct DrmFramebufferDeleter {
+struct OZONE_EXPORT DrmFramebufferDeleter {
   void operator()(drmModeFB* framebuffer) const;
 };
 
diff --git a/ui/ozone/platform/dri/screen_manager.h b/ui/ozone/platform/dri/screen_manager.h
index 5eaae1a..22ea14a9 100644
--- a/ui/ozone/platform/dri/screen_manager.h
+++ b/ui/ozone/platform/dri/screen_manager.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
+#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/dri/display_change_observer.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 
@@ -25,7 +26,7 @@
 class ScanoutBufferGenerator;
 
 // Responsible for keeping track of active displays and configuring them.
-class ScreenManager {
+class OZONE_EXPORT ScreenManager {
  public:
   ScreenManager(DriWrapper* dri, ScanoutBufferGenerator* surface_generator);
   virtual ~ScreenManager();
diff --git a/ui/ozone/platform/egltest/BUILD.gn b/ui/ozone/platform/egltest/BUILD.gn
index 402794af..8acf85b 100644
--- a/ui/ozone/platform/egltest/BUILD.gn
+++ b/ui/ozone/platform/egltest/BUILD.gn
@@ -13,8 +13,10 @@
   deps = [
     ":eglplatform_shim",
     "//base",
+    "//ui/events/devices",
     "//ui/events/ozone:events_ozone_evdev",
     "//ui/events/ozone:events_ozone_layout",
+    "//ui/events/platform",
     "//ui/gfx",
   ]
 }
diff --git a/ui/ozone/platform/egltest/egltest.gypi b/ui/ozone/platform/egltest/egltest.gypi
index 4c389e8..8683212 100644
--- a/ui/ozone/platform/egltest/egltest.gypi
+++ b/ui/ozone/platform/egltest/egltest.gypi
@@ -21,9 +21,11 @@
       'dependencies': [
         '../../base/base.gyp:base',
         '../../third_party/khronos/khronos.gyp:khronos_headers',
+        '../events/devices/events_devices.gyp:events_devices',
         '../events/events.gyp:events',
         '../events/ozone/events_ozone.gyp:events_ozone_evdev',
         '../events/ozone/events_ozone.gyp:events_ozone_layout',
+        '../events/platform/events_platform.gyp:events_platform',
         '../gfx/gfx.gyp:gfx',
         'eglplatform_shim',
       ],
diff --git a/ui/ozone/platform/test/BUILD.gn b/ui/ozone/platform/test/BUILD.gn
index b5c1cf38..eaaa60c 100644
--- a/ui/ozone/platform/test/BUILD.gn
+++ b/ui/ozone/platform/test/BUILD.gn
@@ -18,5 +18,6 @@
     "//ui/base",
     "//ui/gfx/geometry",
     "//ui/events/ozone:events_ozone_layout",
+    "//ui/events/platform",
   ]
 }
diff --git a/ui/ozone/platform/test/test.gypi b/ui/ozone/platform/test/test.gypi
index b94f091..6543334 100644
--- a/ui/ozone/platform/test/test.gypi
+++ b/ui/ozone/platform/test/test.gypi
@@ -23,6 +23,7 @@
         '../base/ui_base.gyp:ui_base',
         '../events/events.gyp:events',
         '../events/ozone/events_ozone.gyp:events_ozone_layout',
+        '../events/platform/events_platform.gyp:events_platform',
         '../gfx/gfx.gyp:gfx',
       ],
       'sources': [
diff --git a/ui/strings/app_locale_settings.grd b/ui/strings/app_locale_settings.grd
index 19bb7e5..5b0d951 100644
--- a/ui/strings/app_locale_settings.grd
+++ b/ui/strings/app_locale_settings.grd
@@ -256,7 +256,7 @@
       <if expr="chromeos">
         <!-- The font name like: 'Font Name, 10' -->
         <message name="IDS_UI_FONT_FAMILY_CROS" use_name_for_id="true">
-          Noto Sans UI, 12px
+          Noto Sans UI, 13px
         </message>
 
         <!-- The font used in Web UI (e.g. History). -->
diff --git a/ui/touch_selection/ui_touch_selection_unittests.isolate b/ui/touch_selection/ui_touch_selection_unittests.isolate
index 64e0e54..691e0a6 100644
--- a/ui/touch_selection/ui_touch_selection_unittests.isolate
+++ b/ui/touch_selection/ui_touch_selection_unittests.isolate
@@ -21,6 +21,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
         'files': [
           '../../testing/xvfb.py',
@@ -44,6 +46,8 @@
           '--test-launcher-bot-mode',
           '--asan=<(asan)',
           '--lsan=<(lsan)',
+          '--msan=<(msan)',
+          '--tsan=<(tsan)',
         ],
       },
     }],
diff --git a/ui/views/accessibility/ax_aura_obj_cache.cc b/ui/views/accessibility/ax_aura_obj_cache.cc
index ae2df206..05f1868 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -76,10 +76,11 @@
   delete obj;
 }
 
-AXAuraObjCache::AXAuraObjCache() : current_id_(1) {
+AXAuraObjCache::AXAuraObjCache() : current_id_(1), is_destroying_(false) {
 }
 
 AXAuraObjCache::~AXAuraObjCache() {
+  is_destroying_ = true;
   STLDeleteContainerPairSecondPointers(cache_.begin(), cache_.end());
   cache_.clear();
 }
diff --git a/ui/views/accessibility/ax_aura_obj_cache.h b/ui/views/accessibility/ax_aura_obj_cache.h
index 6e5d9e8..a8316b5 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.h
+++ b/ui/views/accessibility/ax_aura_obj_cache.h
@@ -52,6 +52,9 @@
   // Remove a cached entry based on an id.
   void Remove(int32 id);
 
+  // Indicates if this object's currently being destroyed.
+  bool is_destroying() { return is_destroying_; }
+
  private:
   friend struct DefaultSingletonTraits<AXAuraObjCache>;
 
@@ -75,6 +78,9 @@
   std::map<int32, AXAuraObjWrapper*> cache_;
   int32 current_id_;
 
+  // True immediately when entering this object's destructor.
+  bool is_destroying_;
+
   DISALLOW_COPY_AND_ASSIGN(AXAuraObjCache);
 };
 
diff --git a/ui/views/accessibility/ax_widget_obj_wrapper.cc b/ui/views/accessibility/ax_widget_obj_wrapper.cc
index 36a3143e..44fcfa8 100644
--- a/ui/views/accessibility/ax_widget_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -17,8 +17,10 @@
 }
 
 AXWidgetObjWrapper::~AXWidgetObjWrapper() {
-  widget_->RemoveObserver(this);
-  widget_->RemoveRemovalsObserver(this);
+  if (!AXAuraObjCache::GetInstance()->is_destroying()) {
+    widget_->RemoveObserver(this);
+    widget_->RemoveRemovalsObserver(this);
+  }
   widget_ = NULL;
 }
 
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc
index 381f489d..17457d98 100644
--- a/ui/views/controls/menu/menu_controller_unittest.cc
+++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/run_loop.h"
 #include "ui/aura/scoped_window_targeter.h"
 #include "ui/aura/window.h"
+#include "ui/events/event_handler.h"
 #include "ui/events/event_targeter.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/views/controls/menu/menu_item_view.h"
@@ -186,6 +187,14 @@
     controller_->exit_type_ = MenuController::EXIT_ALL;
     DispatchEvent();
   }
+
+  void DispatchTouch(int evtype, int id) {
+    ui::ScopedXI2Event touch_event;
+    std::vector<ui::Valuator> valuators;
+    touch_event.InitTouchEvent(1, evtype, id, gfx::Point(10, 10), valuators);
+    event_source_.Dispatch(touch_event);
+    DispatchEvent();
+  }
 #endif
 
   void DispatchEvent() {
@@ -266,4 +275,64 @@
 }
 #endif
 
+#if defined(USE_X11)
+
+class TestEventHandler : public ui::EventHandler {
+ public:
+  TestEventHandler() : outstanding_touches_(0) {}
+
+  void OnTouchEvent(ui::TouchEvent* event) override {
+    switch(event->type()) {
+      case ui::ET_TOUCH_PRESSED:
+        outstanding_touches_++;
+        break;
+      case ui::ET_TOUCH_RELEASED:
+      case ui::ET_TOUCH_CANCELLED:
+        outstanding_touches_--;
+        break;
+      default:
+        break;
+    }
+  }
+
+  int outstanding_touches() const { return outstanding_touches_; }
+
+ private:
+  int outstanding_touches_;
+};
+
+// Tests that touch event ids are released correctly. See
+// crbug.com/439051 for details. When the ids aren't managed
+// correctly, we get stuck down touches.
+TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) {
+  scoped_ptr<Widget> owner(CreateOwnerWidget());
+  TestEventHandler test_event_handler;
+  owner->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler(
+      &test_event_handler);
+
+  std::vector<unsigned int> devices;
+  devices.push_back(1);
+  ui::SetUpTouchDevicesForTest(devices);
+
+  DispatchTouch(XI_TouchBegin, 0);
+  DispatchTouch(XI_TouchBegin, 1);
+  DispatchTouch(XI_TouchEnd, 0);
+
+  message_loop()->PostTask(FROM_HERE,
+                           base::Bind(&MenuControllerTest::DispatchTouch,
+                                      base::Unretained(this), XI_TouchEnd, 1));
+
+  message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
+                 base::Unretained(this), MenuController::EXIT_OUTERMOST));
+
+  RunMenu(owner.get());
+  EXPECT_EQ(0, test_event_handler.outstanding_touches());
+
+  owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler(
+      &test_event_handler);
+}
+#endif // defined(USE_X11)
+
 }  // namespace views
diff --git a/ui/views/controls/menu/menu_event_dispatcher_linux.cc b/ui/views/controls/menu/menu_event_dispatcher_linux.cc
index 51990fd0..f61d58b 100644
--- a/ui/views/controls/menu/menu_event_dispatcher_linux.cc
+++ b/ui/views/controls/menu/menu_event_dispatcher_linux.cc
@@ -75,6 +75,14 @@
         should_quit = false;
         should_perform_default = false;
         break;
+      case ui::ET_TOUCH_RELEASED:
+      case ui::ET_TOUCH_CANCELLED:
+        // Don't allow the event copy to clear the native touch id
+        // mapping, or we'll lose the mapping before the initial event
+        // has finished being dispatched.
+        static_cast<ui::TouchEvent*>(ui_event.get())
+            ->set_should_remove_native_touch_id_mapping(false);
+        break;
       default:
         break;
     }
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc
index 0bffda9..8fe27bf0 100644
--- a/ui/views/controls/webview/web_dialog_view.cc
+++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -306,15 +306,15 @@
 void WebDialogView::AddNewContents(content::WebContents* source,
                                    content::WebContents* new_contents,
                                    WindowOpenDisposition disposition,
-                                   const gfx::Rect& initial_pos,
+                                   const gfx::Rect& initial_rect,
                                    bool user_gesture,
                                    bool* was_blocked) {
   if (delegate_ && delegate_->HandleAddNewContents(
-          source, new_contents, disposition, initial_pos, user_gesture)) {
+          source, new_contents, disposition, initial_rect, user_gesture)) {
     return;
   }
   WebDialogWebContentsDelegate::AddNewContents(
-      source, new_contents, disposition, initial_pos, user_gesture,
+      source, new_contents, disposition, initial_rect, user_gesture,
       was_blocked);
 }
 
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h
index ce69cfc..22550dd 100644
--- a/ui/views/controls/webview/web_dialog_view.h
+++ b/ui/views/controls/webview/web_dialog_view.h
@@ -103,7 +103,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   void LoadingStateChanged(content::WebContents* source,
diff --git a/ui/views/controls/webview/webview.cc b/ui/views/controls/webview/webview.cc
index 2e4ba84..e872a58b 100644
--- a/ui/views/controls/webview/webview.cc
+++ b/ui/views/controls/webview/webview.cc
@@ -78,7 +78,7 @@
     DCHECK(!is_embedding_fullscreen_widget_);
   }
   AttachWebContents();
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 void WebView::SetEmbedFullscreenWidgetMode(bool enable) {
@@ -266,7 +266,7 @@
 void WebView::RenderProcessExited(content::RenderProcessHost* host,
                                   base::TerminationStatus status,
                                   int exit_code) {
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 void WebView::RenderProcessHostDestroyed(content::RenderProcessHost* host) {
@@ -293,11 +293,11 @@
 // WebView, content::WebContentsObserver implementation:
 
 void WebView::RenderViewReady() {
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 void WebView::RenderViewDeleted(content::RenderViewHost* render_view_host) {
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
@@ -305,7 +305,7 @@
   FocusManager* const focus_manager = GetFocusManager();
   if (focus_manager && focus_manager->GetFocusedView() == this)
     OnFocus();
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 void WebView::WebContentsDestroyed() {
@@ -313,7 +313,7 @@
     observing_render_process_host_->RemoveObserver(this);
     observing_render_process_host_ = nullptr;
   }
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 void WebView::DidShowFullscreenWidget(int routing_id) {
@@ -332,11 +332,11 @@
 }
 
 void WebView::DidAttachInterstitialPage() {
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 void WebView::DidDetachInterstitialPage() {
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -398,14 +398,19 @@
     // the same.  So, do not change attachment.
     OnBoundsChanged(bounds());
   }
-  NotifyMaybeTextInputClientChanged();
+  NotifyMaybeTextInputClientAndAccessibilityChanged();
 }
 
-void WebView::NotifyMaybeTextInputClientChanged() {
+void WebView::NotifyMaybeTextInputClientAndAccessibilityChanged() {
   // Update the TextInputClient as needed; see GetTextInputClient().
   FocusManager* const focus_manager = GetFocusManager();
   if (focus_manager)
     focus_manager->OnTextInputClientChanged(this);
+
+#if defined(OS_CHROMEOS)
+  if (web_contents())
+    NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, false);
+#endif  // defined OS_CHROMEOS
 }
 
 content::WebContents* WebView::CreateWebContents(
diff --git a/ui/views/controls/webview/webview.h b/ui/views/controls/webview/webview.h
index af64b72..f97449b8 100644
--- a/ui/views/controls/webview/webview.h
+++ b/ui/views/controls/webview/webview.h
@@ -149,7 +149,7 @@
   void AttachWebContents();
   void DetachWebContents();
   void ReattachForFullscreenChange(bool enter_fullscreen);
-  void NotifyMaybeTextInputClientChanged();
+  void NotifyMaybeTextInputClientAndAccessibilityChanged();
 
   // Create a regular or test web contents (based on whether we're running
   // in a unit test or not).
diff --git a/ui/views/widget/desktop_aura/x11_pointer_grab.cc b/ui/views/widget/desktop_aura/x11_pointer_grab.cc
index 1354159..26a1c1d 100644
--- a/ui/views/widget/desktop_aura/x11_pointer_grab.cc
+++ b/ui/views/widget/desktop_aura/x11_pointer_grab.cc
@@ -3,8 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/logging.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/events/devices/x11/device_data_manager_x11.h"
 #include "ui/views/widget/desktop_aura/x11_pointer_grab.h"
 
+#include <X11/extensions/XInput2.h>
 #include <X11/Xlib.h>
 
 namespace views {
@@ -20,10 +23,42 @@
 }  // namespace
 
 int GrabPointer(XID window, bool owner_events, ::Cursor cursor) {
-  int event_mask = PointerMotionMask | ButtonReleaseMask | ButtonPressMask;
-  int result = XGrabPointer(gfx::GetXDisplay(), window, owner_events,
-                            event_mask, GrabModeAsync, GrabModeAsync, None,
-                            cursor, CurrentTime);
+  int result = GrabInvalidTime;
+  if (ui::IsXInput2Available()) {
+    // Do an XInput2 pointer grab. If there is an active XInput2 pointer grab
+    // as a result of normal button press, XGrabPointer() will fail.
+    unsigned char mask[XIMaskLen(XI_LASTEVENT)];
+    memset(mask, 0, sizeof(mask));
+    XISetMask(mask, XI_ButtonPress);
+    XISetMask(mask, XI_ButtonRelease);
+    XISetMask(mask, XI_Motion);
+    XIEventMask evmask;
+    evmask.mask_len = sizeof(mask);
+    evmask.mask = mask;
+
+    const std::vector<int>& master_pointers =
+        ui::DeviceDataManagerX11::GetInstance()->master_pointers();
+    for (int master_pointer : master_pointers) {
+      evmask.deviceid = master_pointer;
+      result = XIGrabDevice(
+          gfx::GetXDisplay(), master_pointer, window, CurrentTime, cursor,
+          GrabModeAsync, GrabModeAsync, owner_events, &evmask);
+      // Assume that the grab will succeed on either all or none of the master
+      // pointers.
+      if (result != GrabSuccess) {
+        // Try core pointer grab.
+        break;
+      }
+    }
+  }
+
+  if (result != GrabSuccess) {
+    int event_mask = PointerMotionMask | ButtonReleaseMask | ButtonPressMask;
+    result =
+        XGrabPointer(gfx::GetXDisplay(), window, owner_events, event_mask,
+                     GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
+  }
+
   if (result == GrabSuccess) {
     g_grab_window = window;
     g_owner_events = owner_events;
@@ -38,6 +73,13 @@
 
 void UngrabPointer() {
   g_grab_window = None;
+  if (ui::IsXInput2Available()) {
+    const std::vector<int>& master_pointers =
+        ui::DeviceDataManagerX11::GetInstance()->master_pointers();
+    for (int master_pointer : master_pointers)
+      XIUngrabDevice(gfx::GetXDisplay(), master_pointer, CurrentTime);
+  }
+  // Try core pointer ungrab in case the XInput2 pointer ungrab failed.
   XUngrabPointer(gfx::GetXDisplay(), CurrentTime);
 }
 
diff --git a/ui/web_dialogs/test/test_web_contents_handler.cc b/ui/web_dialogs/test/test_web_contents_handler.cc
index 4b2077d..7f8e5e5 100644
--- a/ui/web_dialogs/test/test_web_contents_handler.cc
+++ b/ui/web_dialogs/test/test_web_contents_handler.cc
@@ -24,7 +24,7 @@
                                             content::WebContents* source,
                                             content::WebContents* new_contents,
                                             WindowOpenDisposition disposition,
-                                            const gfx::Rect& initial_pos,
+                                            const gfx::Rect& initial_rect,
                                             bool user_gesture) {
 }
 
diff --git a/ui/web_dialogs/test/test_web_contents_handler.h b/ui/web_dialogs/test/test_web_contents_handler.h
index 691376e2..50d7592 100644
--- a/ui/web_dialogs/test/test_web_contents_handler.h
+++ b/ui/web_dialogs/test/test_web_contents_handler.h
@@ -28,7 +28,7 @@
                       content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture) override;
 
   DISALLOW_COPY_AND_ASSIGN(TestWebContentsHandler);
diff --git a/ui/web_dialogs/web_dialog_delegate.cc b/ui/web_dialogs/web_dialog_delegate.cc
index 8020c55..e4895f17 100644
--- a/ui/web_dialogs/web_dialog_delegate.cc
+++ b/ui/web_dialogs/web_dialog_delegate.cc
@@ -43,7 +43,7 @@
     content::WebContents* source,
     content::WebContents* new_contents,
     WindowOpenDisposition disposition,
-    const gfx::Rect& initial_pos,
+    const gfx::Rect& initial_rect,
     bool user_gesture) {
   return false;
 }
diff --git a/ui/web_dialogs/web_dialog_delegate.h b/ui/web_dialogs/web_dialog_delegate.h
index 898b0451..6d2079d 100644
--- a/ui/web_dialogs/web_dialog_delegate.h
+++ b/ui/web_dialogs/web_dialog_delegate.h
@@ -120,13 +120,13 @@
 
   // A callback to create a new tab with |new_contents|. |source| is the
   // WebContent where the operation originated. |disposition| controls how the
-  // new tab should be opened. |initial_pos| is the position of the window if a
-  // new window is created. |user_gesture| is true if the operation was started
-  // by a user gesture. Return false to use the default handler.
+  // new tab should be opened. |initial_rect| is the position and size of the
+  // window if a new window is created. |user_gesture| is true if the operation
+  // was started by a user gesture. Return false to use the default handler.
   virtual bool HandleAddNewContents(content::WebContents* source,
                                     content::WebContents* new_contents,
                                     WindowOpenDisposition disposition,
-                                    const gfx::Rect& initial_pos,
+                                    const gfx::Rect& initial_rect,
                                     bool user_gesture);
 
   // A callback to control whether a WebContents will be created. Returns
diff --git a/ui/web_dialogs/web_dialog_web_contents_delegate.cc b/ui/web_dialogs/web_dialog_web_contents_delegate.cc
index ea0006a..0493e415 100644
--- a/ui/web_dialogs/web_dialog_web_contents_delegate.cc
+++ b/ui/web_dialogs/web_dialog_web_contents_delegate.cc
@@ -42,11 +42,11 @@
 
 void WebDialogWebContentsDelegate::AddNewContents(
     WebContents* source, WebContents* new_contents,
-    WindowOpenDisposition disposition, const gfx::Rect& initial_pos,
+    WindowOpenDisposition disposition, const gfx::Rect& initial_rect,
     bool user_gesture,
     bool* was_blocked) {
   handler_->AddNewContents(browser_context_, source, new_contents, disposition,
-                           initial_pos, user_gesture);
+                           initial_rect, user_gesture);
 }
 
 bool WebDialogWebContentsDelegate::IsPopupOrPanel(
diff --git a/ui/web_dialogs/web_dialog_web_contents_delegate.h b/ui/web_dialogs/web_dialog_web_contents_delegate.h
index 00f9aa4ef..c8d4f10 100644
--- a/ui/web_dialogs/web_dialog_web_contents_delegate.h
+++ b/ui/web_dialogs/web_dialog_web_contents_delegate.h
@@ -31,7 +31,7 @@
                                 content::WebContents* source,
                                 content::WebContents* new_contents,
                                 WindowOpenDisposition disposition,
-                                const gfx::Rect& initial_pos,
+                                const gfx::Rect& initial_rect,
                                 bool user_gesture) = 0;
   };
 
@@ -59,7 +59,7 @@
   void AddNewContents(content::WebContents* source,
                       content::WebContents* new_contents,
                       WindowOpenDisposition disposition,
-                      const gfx::Rect& initial_pos,
+                      const gfx::Rect& initial_rect,
                       bool user_gesture,
                       bool* was_blocked) override;
   bool IsPopupOrPanel(const content::WebContents* source) const override;
diff --git a/ui/webui/resources/css/text_defaults.css b/ui/webui/resources/css/text_defaults.css
index 682a8585..1af823b 100644
--- a/ui/webui/resources/css/text_defaults.css
+++ b/ui/webui/resources/css/text_defaults.css
@@ -23,3 +23,7 @@
   font-family: $2;
   font-size: $3;
 }
+
+button {
+  font-family: $2;
+}
diff --git a/ui/webui/resources/js/cr/ui/focus_grid.js b/ui/webui/resources/js/cr/ui/focus_grid.js
index 2e76ca1..4ff1635 100644
--- a/ui/webui/resources/js/cr/ui/focus_grid.js
+++ b/ui/webui/resources/js/cr/ui/focus_grid.js
@@ -18,28 +18,58 @@
    *   focusable  [focused]  focusable  (row: 1, col: 1)
    *   focusable  focusable  focusable
    *
-   * And pressing right at this point would move the focus to:
+   * And pressing right or tab at this point would move the focus to:
    *
    *   focusable  focusable  focusable
    *   focusable  focusable  [focused]  (row: 1, col: 2)
    *   focusable  focusable  focusable
    *
-   * @param {Node=} opt_boundary Ignore focus events outside this node.
-   * @param {cr.ui.FocusRow.Observer=} opt_observer An observer of rows.
-   * @implements {cr.ui.FocusRow.Delegate}
    * @constructor
    */
-  function FocusGrid(opt_boundary, opt_observer) {
-    /** @type {Node|undefined} */
-    this.boundary_ = opt_boundary;
-
-    /** @private {cr.ui.FocusRow.Observer|undefined} */
-    this.observer_ = opt_observer;
-
+  function FocusGrid() {
     /** @type {!Array.<!cr.ui.FocusRow>} */
     this.rows = [];
+
+    /** @private {!EventTracker} */
+    this.eventTracker_ = new EventTracker;
+    this.eventTracker_.add(cr.doc, 'keydown', this.onKeydown_.bind(this));
+    this.eventTracker_.add(cr.doc, 'focusin', this.onFocusin_.bind(this));
+
+    /** @private {cr.ui.FocusRow.Delegate} */
+    this.delegate_ = new FocusGrid.RowDelegate(this);
   }
 
+  /**
+   * Row delegate to overwrite the behavior of a mouse click to deselect any row
+   * that wasn't clicked.
+   * @param {cr.ui.FocusGrid} focusGrid
+   * @implements {cr.ui.FocusRow.Delegate}
+   */
+  FocusGrid.RowDelegate = function(focusGrid) {
+    /** @private {cr.ui.FocusGrid} */
+    this.focusGrid_ = focusGrid;
+  };
+
+  FocusGrid.RowDelegate.prototype = {
+    /** @override */
+    onKeydown: function(row, e) { return false; },
+
+    /** @override */
+    onMousedown: function(row, e) {
+      // Only care about left mouse click.
+      if (e.button)
+        return false;
+
+      // Only the clicked row should be active.
+      this.focusGrid_.rows.forEach(function(row) {
+        row.makeRowActive(row.contains(e.target));
+      });
+
+      e.preventDefault();
+      return true;
+    },
+  };
+
   FocusGrid.prototype = {
     /**
      * Unregisters event handlers and removes all |this.rows|.
@@ -51,22 +81,25 @@
 
     /**
      * @param {EventTarget} target A target item to find in this grid.
-     * @return {?{row: number, col: number}} A position or null if not found.
+     * @return {number} The row index. -1 if not found.
      */
-    getPositionForTarget: function(target) {
+    getRowIndexForTarget: function(target) {
       for (var i = 0; i < this.rows.length; ++i) {
-        for (var j = 0; j < this.rows[i].items.length; ++j) {
-          if (target == this.rows[i].items[j])
-            return {row: i, col: j};
-        }
+        if (this.rows[i].contains(target))
+          return i;
       }
-      return null;
+      return -1;
     },
 
-    /** @override */
-    onKeydown: function(keyRow, e) {
-      var rowIndex = this.rows.indexOf(keyRow);
-      assert(rowIndex >= 0);
+    /**
+     * Handles keyboard shortcuts to move up/down in the grid.
+     * @param {Event} e The key event.
+     * @private
+     */
+    onKeydown_: function(e) {
+      var rowIndex = this.getRowIndexForTarget(e.target);
+      if (rowIndex == -1)
+        return;
 
       var row = -1;
 
@@ -79,35 +112,53 @@
       else if (e.keyIdentifier == 'PageDown')
         row = this.rows.length - 1;
 
-      if (!this.rows[row])
-        return false;
-
-      var colIndex = keyRow.items.indexOf(e.target);
-      var col = Math.min(colIndex, this.rows[row].items.length - 1);
-
-      this.rows[row].focusIndex(col);
-
-      e.preventDefault();
-      return true;
-    },
-
-    /** @override */
-    onMousedown: function(row, e) {
-      return false;
+      var rowToFocus = this.rows[row];
+      if (rowToFocus) {
+        this.ignoreFocusChange_ = true;
+        rowToFocus.getEquivalentElement(this.lastFocused).focus();
+        e.preventDefault();
+      }
     },
 
     /**
-     * @param {!Array.<!NodeList|!Array.<!Element>>} grid A 2D array of nodes.
+     * Keep track of the last column that the user manually focused.
+     * @param {Event} The focusin event.
+     * @private
      */
-    setGrid: function(grid) {
-      this.destroy();
+    onFocusin_: function(e) {
+      if (this.ignoreFocusChange_) {
+        this.ignoreFocusChange_ = false;
+        return;
+      }
 
-      this.rows = grid.map(function(row) {
-        return new cr.ui.FocusRow(row, this.boundary_, this, this.observer_);
-      }, this);
+      if (this.getRowIndexForTarget(e.target) != -1)
+        this.lastFocused = e.target;
+    },
 
-      if (!this.getPositionForTarget(document.activeElement) && this.rows[0])
-        this.rows[0].activeIndex = 0;
+    /**
+     * Add a FocusRow to this grid. This needs to be called AFTER adding columns
+     * to the row. This is so that TAB focus can be properly enabled in the
+     * columns.
+     * @param {cr.ui.FocusRow} row The row that needs to be added to this grid.
+     */
+    addRow: function(row) {
+      row.delegate = row.delegate || this.delegate_;
+
+      if (this.rows.length == 0) {
+        // The first row should be active if no other row is focused.
+        row.makeRowActive(true);
+      } else if (row.contains(document.activeElement)) {
+        // The current row should be made active if it's the activeElement.
+        row.makeRowActive(true);
+        // Deactivate the first row.
+        this.rows[0].makeRowActive(false);
+      } else {
+        // All other rows should be inactive.
+        row.makeRowActive(false);
+      }
+
+      // Add the row after its initial focus is set.
+      this.rows.push(row);
     },
   };
 
diff --git a/ui/webui/resources/js/cr/ui/focus_outline_manager.js b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
index 2b5ec9fb..7f921ab 100644
--- a/ui/webui/resources/js/cr/ui/focus_outline_manager.js
+++ b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
@@ -58,10 +58,7 @@
      * @type {boolean}
      */
     set visible(visible) {
-      if (visible)
-        this.classList_.add(CLASS_NAME);
-      else
-        this.classList_.remove(CLASS_NAME);
+      this.classList_.toggle(CLASS_NAME, visible);
     },
     get visible() {
       return this.classList_.contains(CLASS_NAME);
diff --git a/ui/webui/resources/js/cr/ui/focus_row.js b/ui/webui/resources/js/cr/ui/focus_row.js
index 26c4c55..697cd699 100644
--- a/ui/webui/resources/js/cr/ui/focus_row.js
+++ b/ui/webui/resources/js/cr/ui/focus_row.js
@@ -11,11 +11,13 @@
    *
    * One could create a FocusRow by doing:
    *
-   *   new cr.ui.FocusRow([checkboxEl, labelEl, buttonEl])
+   *   var focusRow = new cr.ui.FocusRow(rowBoundary, rowEl);
    *
-   * if there are references to each node or querying them from the DOM like so:
+   *   focusRow.addFocusableElement(checkboxEl);
+   *   focusRow.addFocusableElement(labelEl);
+   *   focusRow.addFocusableElement(buttonEl);
    *
-   *   new cr.ui.FocusRow(dialog.querySelectorAll('list input[type=checkbox]'))
+   *   focusRow.setInitialFocusability(true);
    *
    * Pressing left cycles backward and pressing right cycles forward in item
    * order. Pressing Home goes to the beginning of the list and End goes to the
@@ -23,57 +25,20 @@
    *
    * If an item in this row is focused, it'll stay active (accessible via tab).
    * If no items in this row are focused, the row can stay active until focus
-   * changes to a node inside |this.boundary_|. If opt_boundary isn't
-   * specified, any focus change deactivates the row.
+   * changes to a node inside |this.boundary_|. If |boundary| isn't specified,
+   * any focus change deactivates the row.
    *
-   * @param {!Array.<!Element>|!NodeList} items Elements to track focus of.
-   * @param {Node=} opt_boundary Focus events are ignored outside of this node.
-   * @param {FocusRow.Delegate=} opt_delegate A delegate to handle key events.
-   * @param {FocusRow.Observer=} opt_observer An observer that's notified if
-   *     this focus row is added to or removed from the focus order.
    * @constructor
    */
-  function FocusRow(items, opt_boundary, opt_delegate, opt_observer) {
-    /** @type {!Array.<!Element>} */
-    this.items = Array.prototype.slice.call(items);
-    assert(this.items.length > 0);
-
-    /** @type {!Node} */
-    this.boundary_ = opt_boundary || document;
-
-    /** @private {cr.ui.FocusRow.Delegate|undefined} */
-    this.delegate_ = opt_delegate;
-
-    /** @private {cr.ui.FocusRow.Observer|undefined} */
-    this.observer_ = opt_observer;
-
-    /** @private {!EventTracker} */
-    this.eventTracker_ = new EventTracker;
-    this.eventTracker_.add(cr.doc, 'focusin', this.onFocusin_.bind(this));
-    this.eventTracker_.add(cr.doc, 'keydown', this.onKeydown_.bind(this));
-
-    this.items.forEach(function(item) {
-      if (item != document.activeElement)
-        item.tabIndex = -1;
-
-      this.eventTracker_.add(item, 'mousedown', this.onMousedown_.bind(this));
-    }, this);
-
-    /**
-     * The index that should be actively participating in the page tab order.
-     * @type {number}
-     * @private
-     */
-    this.activeIndex_ = this.items.indexOf(document.activeElement);
-  }
+  function FocusRow() {}
 
   /** @interface */
   FocusRow.Delegate = function() {};
 
   FocusRow.Delegate.prototype = {
     /**
-     * Called when a key is pressed while an item in |this.items| is focused. If
-     * |e|'s default is prevented, further processing is skipped.
+     * Called when a key is pressed while an item in |this.focusableElements| is
+     * focused. If |e|'s default is prevented, further processing is skipped.
      * @param {cr.ui.FocusRow} row The row that detected a keydown.
      * @param {Event} e
      * @return {boolean} Whether the event was handled.
@@ -88,58 +53,89 @@
     onMousedown: assertNotReached,
   };
 
-  /** @interface */
-  FocusRow.Observer = function() {};
-
-  FocusRow.Observer.prototype = {
-    /**
-     * Called when the row is activated (added to the focus order).
-     * @param {cr.ui.FocusRow} row The row added to the focus order.
-     */
-    onActivate: assertNotReached,
-
-    /**
-     * Called when the row is deactivated (removed from the focus order).
-     * @param {cr.ui.FocusRow} row The row removed from the focus order.
-     */
-    onDeactivate: assertNotReached,
-  };
-
   FocusRow.prototype = {
-    get activeIndex() {
-      return this.activeIndex_;
-    },
-    set activeIndex(index) {
-      var wasActive = this.items[this.activeIndex_];
-      if (wasActive)
-        wasActive.tabIndex = -1;
+    __proto__: HTMLDivElement.prototype,
 
-      this.items.forEach(function(item) { assert(item.tabIndex == -1); });
-      this.activeIndex_ = index;
+    /**
+     * Should be called in the constructor to decorate |this|.
+     * @param {Node} boundary Focus events are ignored outside of this node.
+     * @param {FocusRow.Delegate=} opt_delegate A delegate to handle key events.
+     */
+    decorate: function(boundary, opt_delegate) {
+      /** @private {!Node} */
+      this.boundary_ = boundary || document;
 
-      if (this.items[index])
-        this.items[index].tabIndex = 0;
+      /** @type {cr.ui.FocusRow.Delegate|undefined} */
+      this.delegate = opt_delegate;
 
-      if (!this.observer_)
-        return;
+      /** @type {Array<Element>} */
+      this.focusableElements = [];
 
-      var isActive = index >= 0 && index < this.items.length;
-      if (isActive == !!wasActive)
-        return;
-
-      if (isActive)
-        this.observer_.onActivate(this);
-      else
-        this.observer_.onDeactivate(this);
+      /** @private {!EventTracker} */
+      this.eventTracker_ = new EventTracker;
+      this.eventTracker_.add(cr.doc, 'focusin', this.onFocusin_.bind(this));
+      this.eventTracker_.add(cr.doc, 'keydown', this.onKeydown_.bind(this));
     },
 
     /**
-     * Focuses the item at |index|.
-     * @param {number} index An index to focus. Must be between 0 and
-     *     this.items.length - 1.
+     * Called when the row's active state changes and it is added/removed from
+     * the focus order.
+     * @param {boolean} state Whether the row has become active or inactive.
      */
-    focusIndex: function(index) {
-      this.items[index].focus();
+    onActiveStateChanged: function(state) {},
+
+    /**
+     * Find the element that best matches |sampleElement|.
+     * @param {Element} sampleElement An element from a row of the same type
+     *     which previously held focus.
+     * @return {!Element} The element that best matches sampleElement.
+     */
+    getEquivalentElement: assertNotReached,
+
+    /**
+     * Add an element to this FocusRow. No-op if |element| is not provided.
+     * @param {Element} element The element that should be added.
+     */
+    addFocusableElement: function(element) {
+      if (!element)
+        return;
+
+      assert(this.focusableElements.indexOf(element) == -1);
+      assert(this.contains(element));
+
+      this.focusableElements.push(element);
+      this.eventTracker_.add(element, 'mousedown',
+                             this.onMousedown_.bind(this));
+    },
+
+    /**
+     * Called when focus changes to activate/deactivate the row. Focus is
+     * removed from the row when |element| is not in the FocusRow.
+     * @param {Element} element The element that has focus. null if focus should
+     *     be removed.
+     * @private
+    */
+    onFocusChange_: function(element) {
+      var isActive = this.contains(element);
+      var wasActive = this.classList.contains('focus-row-active');
+
+      // Only send events if the active state is different for the row.
+      if (isActive != wasActive)
+        this.makeRowActive(isActive);
+    },
+
+    /**
+     * Enables/disables the tabIndex of the focusable elements in the FocusRow.
+     * tabIndex can be set properly.
+     * @param {boolean} active True if tab is allowed for this row.
+     */
+    makeRowActive: function(active) {
+      this.focusableElements.forEach(function(element) {
+        element.tabIndex = active ? 0 : -1;
+      });
+
+      this.classList.toggle('focus-row-active', active);
+      this.onActiveStateChanged(active);
     },
 
     /** Call this to clean up event handling before dereferencing. */
@@ -153,37 +149,38 @@
      */
     onFocusin_: function(e) {
       if (this.boundary_.contains(assertInstanceof(e.target, Node)))
-        this.activeIndex = this.items.indexOf(e.target);
+        this.onFocusChange_(e.target);
     },
 
     /**
-     * @param {Event} e A focus event.
+     * Handles a keypress for an element in this FocusRow.
+     * @param {Event} e The keydown event.
      * @private
      */
     onKeydown_: function(e) {
-      var item = this.items.indexOf(e.target);
-      if (item < 0)
+      if (!this.contains(e.target))
         return;
 
-      if (this.delegate_ && this.delegate_.onKeydown(this, e))
+      if (this.delegate && this.delegate.onKeydown(this, e))
         return;
 
+      var elementIndex = this.focusableElements.indexOf(e.target);
       var index = -1;
 
       if (e.keyIdentifier == 'Left')
-        index = item + (isRTL() ? 1 : -1);
+        index = elementIndex + (isRTL() ? 1 : -1);
       else if (e.keyIdentifier == 'Right')
-        index = item + (isRTL() ? -1 : 1);
+        index = elementIndex + (isRTL() ? -1 : 1);
       else if (e.keyIdentifier == 'Home')
         index = 0;
       else if (e.keyIdentifier == 'End')
-        index = this.items.length - 1;
+        index = this.focusableElements.length - 1;
 
-      if (!this.items[index])
-        return;
-
-      this.focusIndex(index);
-      e.preventDefault();
+      var elementToFocus = this.focusableElements[index];
+      if (elementToFocus) {
+        this.getEquivalentElement(elementToFocus).focus();
+        e.preventDefault();
+      }
     },
 
     /**
@@ -191,11 +188,14 @@
      * @private
      */
     onMousedown_: function(e) {
-      if (this.delegate_ && this.delegate_.onMousedown(this, e))
+      if (this.delegate && this.delegate.onMousedown(this, e))
         return;
 
-      if (!e.button)
-        this.activeIndex = this.items.indexOf(e.currentTarget);
+      // Only accept the left mouse click.
+      if (!e.button) {
+        // Focus this row if the target is one of the elements in this row.
+        this.onFocusChange_(e.target);
+      }
     },
   };
 
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index ad7f86a..aa844d98 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -54,6 +54,9 @@
   <structure name="IDR_POLYMER_CORE_ICONS_CORE_ICONS_HTML"
              file="../../../third_party/polymer/components-chromium/core-icons/core-icons.html"
              type="chrome_html" />
+  <structure name="IDR_POLYMER_CORE_ICONS_IMAGE_ICONS_HTML"
+             file="../../../third_party/polymer/components-chromium/core-icons/image-icons.html"
+             type="chrome_html" />
   <structure name="IDR_POLYMER_CORE_ICONSET_CORE_ICONSET_EXTRACTED_JS"
              file="../../../third_party/polymer/components-chromium/core-iconset/core-iconset-extracted.js"
              type="chrome_html" />
diff --git a/webkit/DEPS b/webkit/DEPS
index 72dbfae..9eae709 100644
--- a/webkit/DEPS
+++ b/webkit/DEPS
@@ -1,6 +1,7 @@
 # Do NOT add chrome to the list below. We shouldn't be including files from
 # src/chrome in src/webkit.
 include_rules = [
+  "+cc/blink",
   "+cc/output",
   "+gpu/GLES2",
   "+gpu/blink",
diff --git a/webkit/common/gpu/context_provider_in_process.cc b/webkit/common/gpu/context_provider_in_process.cc
index a12493c..7eb90a9 100644
--- a/webkit/common/gpu/context_provider_in_process.cc
+++ b/webkit/common/gpu/context_provider_in_process.cc
@@ -4,8 +4,6 @@
 
 #include "webkit/common/gpu/context_provider_in_process.h"
 
-#include <set>
-
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/strings/stringprintf.h"
diff --git a/webkit/common/gpu/context_provider_in_process.h b/webkit/common/gpu/context_provider_in_process.h
index e3c9ea1..0ab7542 100644
--- a/webkit/common/gpu/context_provider_in_process.h
+++ b/webkit/common/gpu/context_provider_in_process.h
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
-#include "webkit/common/gpu/context_provider_web_context.h"
+#include "cc/blink/context_provider_web_context.h"
 #include "webkit/common/gpu/webkit_gpu_export.h"
 
 namespace blink { class WebGraphicsContext3D; }
@@ -25,7 +25,7 @@
 class GrContextForWebGraphicsContext3D;
 
 class WEBKIT_GPU_EXPORT ContextProviderInProcess
-    : NON_EXPORTED_BASE(public ContextProviderWebContext) {
+    : NON_EXPORTED_BASE(public cc_blink::ContextProviderWebContext) {
  public:
   static scoped_refptr<ContextProviderInProcess> Create(
       scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
@@ -43,7 +43,7 @@
       const std::string& debug_name);
   ~ContextProviderInProcess() override;
 
-  // ContextProviderWebContext:
+  // cc_blink::ContextProviderWebContext:
   blink::WebGraphicsContext3D* WebContext3D() override;
 
   // cc::ContextProvider: