From 7c927b60bffa117129ba9214fcb6174d753351d9 Mon Sep 17 00:00:00 2001
From: "phajdan.jr@chromium.org"
 <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Wed, 24 Feb 2010 09:54:13 +0000
Subject: Further reduce the bad dependency of chrome/common on chrome/browser.

TEST=none
BUG=none
Review URL: http://codereview.chromium.org/656011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39877 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/common/chrome_constants.cc                  |   2 +
 chrome/common/chrome_constants.h                   |   2 +
 chrome/common/extensions/extension_file_util.cc    | 521 +++++++++++++++++++++
 chrome/common/extensions/extension_file_util.h     | 108 +++++
 .../extensions/extension_file_util_unittest.cc     | 258 ++++++++++
 chrome/common/extensions/extension_l10n_util.cc    |   2 +-
 chrome/common/extensions/extension_unpacker.cc     |   2 +-
 chrome/common/histogram_synchronizer.cc            | 273 -----------
 chrome/common/histogram_synchronizer.h             | 147 ------
 chrome/common/render_messages.h                    |   2 +-
 chrome/common/resource_response.h                  |  50 ++
 11 files changed, 944 insertions(+), 423 deletions(-)
 create mode 100644 chrome/common/extensions/extension_file_util.cc
 create mode 100644 chrome/common/extensions/extension_file_util.h
 create mode 100644 chrome/common/extensions/extension_file_util_unittest.cc
 delete mode 100644 chrome/common/histogram_synchronizer.cc
 delete mode 100644 chrome/common/histogram_synchronizer.h
 create mode 100644 chrome/common/resource_response.h

(limited to 'chrome/common')

diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 8226cd8..ed5947a 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -129,6 +129,8 @@ const bool kRecordModeEnabled = true;
 const bool kRecordModeEnabled = false;
 #endif
 
+const int kHistogramSynchronizerReservedSequenceNumber = 0;
+
 }  // namespace chrome
 
 #undef FPL
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index fc271e0..cd85a14 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -77,6 +77,8 @@ extern const size_t kMaxURLChars;
 
 extern const bool kRecordModeEnabled;
 
+extern const int kHistogramSynchronizerReservedSequenceNumber;
+
 }  // namespace chrome
 
 #endif  // CHROME_COMMON_CHROME_CONSTANTS_H_
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
new file mode 100644
index 0000000..0192b67
--- /dev/null
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -0,0 +1,521 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/extension_file_util.h"
+
+#include "app/l10n_util.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/json_value_serializer.h"
+#include "net/base/escape.h"
+#include "net/base/file_stream.h"
+
+namespace errors = extension_manifest_errors;
+namespace keys = extension_manifest_keys;
+
+namespace extension_file_util {
+
+// Validates locale info. Doesn't check if messages.json files are valid.
+static bool ValidateLocaleInfo(const Extension& extension, std::string* error);
+
+const char kInstallDirectoryName[] = "Extensions";
+// TODO(mpcomplete): obsolete. remove after migration period.
+// http://code.google.com/p/chromium/issues/detail?id=19733
+const char kCurrentVersionFileName[] = "Current Version";
+
+bool MoveDirSafely(const FilePath& source_dir, const FilePath& dest_dir) {
+  if (file_util::PathExists(dest_dir)) {
+    if (!file_util::Delete(dest_dir, true))
+      return false;
+  } else {
+    FilePath parent = dest_dir.DirName();
+    if (!file_util::DirectoryExists(parent)) {
+      if (!file_util::CreateDirectory(parent))
+        return false;
+    }
+  }
+
+  if (!file_util::Move(source_dir, dest_dir))
+    return false;
+
+  return true;
+}
+
+Extension::InstallType CompareToInstalledVersion(
+    const FilePath& extensions_dir,
+    const std::string& extension_id,
+    const std::string& current_version_str,
+    const std::string& new_version_str,
+    FilePath* version_dir) {
+  FilePath dest_dir = extensions_dir.AppendASCII(extension_id);
+  FilePath current_version_dir = dest_dir.AppendASCII(current_version_str);
+  *version_dir = dest_dir.AppendASCII(new_version_str);
+
+  if (current_version_str.empty())
+    return Extension::NEW_INSTALL;
+
+  scoped_ptr<Version> current_version(
+    Version::GetVersionFromString(current_version_str));
+  scoped_ptr<Version> new_version(
+    Version::GetVersionFromString(new_version_str));
+  int comp = new_version->CompareTo(*current_version);
+  if (comp > 0)
+    return Extension::UPGRADE;
+  if (comp < 0)
+    return Extension::DOWNGRADE;
+
+  // Same version. Treat corrupted existing installation as new install case.
+  if (!SanityCheckExtension(current_version_dir))
+    return Extension::NEW_INSTALL;
+
+  return Extension::REINSTALL;
+}
+
+bool SanityCheckExtension(const FilePath& dir) {
+  // Verify that the directory actually exists.
+  // TODO(erikkay): A further step would be to verify that the extension
+  // has actually loaded successfully.
+  FilePath manifest_file(dir.Append(Extension::kManifestFilename));
+  return file_util::PathExists(dir) && file_util::PathExists(manifest_file);
+}
+
+bool InstallExtension(const FilePath& src_dir,
+                      const FilePath& version_dir,
+                      std::string* error) {
+  // If anything fails after this, we want to delete the extension dir.
+  ScopedTempDir scoped_version_dir;
+  scoped_version_dir.Set(version_dir);
+
+  if (!MoveDirSafely(src_dir, version_dir)) {
+    *error = "Could not move extension directory into profile.";
+    return false;
+  }
+
+  scoped_version_dir.Take();
+  return true;
+}
+
+Extension* LoadExtension(const FilePath& extension_path,
+                         bool require_key,
+                         std::string* error) {
+  FilePath manifest_path =
+      extension_path.Append(Extension::kManifestFilename);
+  if (!file_util::PathExists(manifest_path)) {
+    *error = extension_manifest_errors::kManifestUnreadable;
+    return NULL;
+  }
+
+  JSONFileValueSerializer serializer(manifest_path);
+  scoped_ptr<Value> root(serializer.Deserialize(error));
+  if (!root.get()) {
+    if (error->empty()) {
+      // If |error| is empty, than the file could not be read.
+      // It would be cleaner to have the JSON reader give a specific error
+      // in this case, but other code tests for a file error with
+      // error->empty().  For now, be consistent.
+      *error = extension_manifest_errors::kManifestUnreadable;
+    } else {
+      *error = StringPrintf("%s  %s",
+                            extension_manifest_errors::kManifestParseError,
+                            error->c_str());
+    }
+    return NULL;
+  }
+
+  if (!root->IsType(Value::TYPE_DICTIONARY)) {
+    *error = extension_manifest_errors::kInvalidManifest;
+    return NULL;
+  }
+
+  DictionaryValue* manifest = static_cast<DictionaryValue*>(root.get());
+
+  scoped_ptr<Extension> extension(new Extension(extension_path));
+
+  if (!extension_l10n_util::LocalizeExtension(extension.get(), manifest, error))
+    return NULL;
+
+  if (!extension->InitFromValue(*manifest, require_key, error))
+    return NULL;
+
+  if (!ValidateExtension(extension.get(), error))
+    return NULL;
+
+  return extension.release();
+}
+
+bool ValidateExtension(Extension* extension, std::string* error) {
+  // Validate icons exist.
+  for (std::map<int, std::string>::const_iterator iter =
+       extension->icons().begin(); iter != extension->icons().end(); ++iter) {
+    const FilePath path = extension->GetResource(iter->second).GetFilePath();
+    if (!file_util::PathExists(path)) {
+      *error = StringPrintf("Could not load extension icon '%s'.",
+                            iter->second.c_str());
+      return false;
+    }
+  }
+
+  // Theme resource validation.
+  if (extension->IsTheme()) {
+    DictionaryValue* images_value = extension->GetThemeImages();
+    if (images_value) {
+      for (DictionaryValue::key_iterator iter = images_value->begin_keys();
+           iter != images_value->end_keys(); ++iter) {
+        std::string val;
+        if (images_value->GetStringWithoutPathExpansion(*iter, &val)) {
+          FilePath image_path = extension->path().AppendASCII(val);
+          if (!file_util::PathExists(image_path)) {
+            *error = StringPrintf(
+                "Could not load '%s' for theme.",
+                WideToUTF8(image_path.ToWStringHack()).c_str());
+            return false;
+          }
+        }
+      }
+    }
+
+    // Themes cannot contain other extension types.
+    return true;
+  }
+
+  // Validate that claimed script resources actually exist.
+  for (size_t i = 0; i < extension->content_scripts().size(); ++i) {
+    const UserScript& script = extension->content_scripts()[i];
+
+    for (size_t j = 0; j < script.js_scripts().size(); j++) {
+      const UserScript::File& js_script = script.js_scripts()[j];
+      const FilePath& path = ExtensionResource::GetFilePath(
+          js_script.extension_root(), js_script.relative_path());
+      if (!file_util::PathExists(path)) {
+        *error = StringPrintf(
+            "Could not load javascript '%s' for content script.",
+            WideToUTF8(js_script.relative_path().ToWStringHack()).c_str());
+        return false;
+      }
+    }
+
+    for (size_t j = 0; j < script.css_scripts().size(); j++) {
+      const UserScript::File& css_script = script.css_scripts()[j];
+      const FilePath& path = ExtensionResource::GetFilePath(
+          css_script.extension_root(), css_script.relative_path());
+      if (!file_util::PathExists(path)) {
+        *error = StringPrintf(
+            "Could not load css '%s' for content script.",
+            WideToUTF8(css_script.relative_path().ToWStringHack()).c_str());
+        return false;
+      }
+    }
+  }
+
+  // Validate claimed plugin paths.
+  for (size_t i = 0; i < extension->plugins().size(); ++i) {
+    const Extension::PluginInfo& plugin = extension->plugins()[i];
+    if (!file_util::PathExists(plugin.path)) {
+      *error = StringPrintf("Could not load '%s' for plugin.",
+                            WideToUTF8(plugin.path.ToWStringHack()).c_str());
+      return false;
+    }
+  }
+
+  // Validate icon location for page actions.
+  ExtensionAction* page_action = extension->page_action();
+  if (page_action) {
+    std::vector<std::string> icon_paths(*page_action->icon_paths());
+    if (!page_action->default_icon_path().empty())
+      icon_paths.push_back(page_action->default_icon_path());
+    for (std::vector<std::string>::iterator iter = icon_paths.begin();
+         iter != icon_paths.end(); ++iter) {
+      if (!file_util::PathExists(extension->GetResource(*iter).GetFilePath())) {
+        *error = StringPrintf("Could not load icon '%s' for page action.",
+                              iter->c_str());
+        return false;
+      }
+    }
+  }
+
+  // Validate icon location for browser actions.
+  // Note: browser actions don't use the icon_paths().
+  ExtensionAction* browser_action = extension->browser_action();
+  if (browser_action) {
+    std::string path = browser_action->default_icon_path();
+    if (!path.empty() &&
+        !file_util::PathExists(extension->GetResource(path).GetFilePath())) {
+        *error = StringPrintf("Could not load icon '%s' for browser action.",
+                              path.c_str());
+        return false;
+    }
+  }
+
+  // Validate background page location.
+  if (!extension->background_url().is_empty()) {
+    FilePath page_path = ExtensionURLToRelativeFilePath(
+        extension->background_url());
+    const FilePath path = extension->GetResource(page_path).GetFilePath();
+    if (!file_util::PathExists(path)) {
+      *error = StringPrintf("Could not load background page '%s'.",
+                            WideToUTF8(path.ToWStringHack()).c_str());
+      return false;
+    }
+  }
+
+  // Validate locale info.
+  if (!ValidateLocaleInfo(*extension, error))
+    return false;
+
+  // Check children of extension root to see if any of them start with _ and is
+  // not on the reserved list.
+  if (!CheckForIllegalFilenames(extension->path(), error)) {
+    return false;
+  }
+
+  return true;
+}
+
+void UninstallExtension(const std::string& id, const FilePath& extensions_dir) {
+  // First, delete the Current Version file. If the directory delete fails, then
+  // at least the extension won't be loaded again.
+  FilePath extension_root = extensions_dir.AppendASCII(id);
+
+  if (!file_util::PathExists(extension_root)) {
+    LOG(WARNING) << "Asked to remove a non-existent extension " << id;
+    return;
+  }
+
+  FilePath current_version_file = extension_root.AppendASCII(
+      kCurrentVersionFileName);
+  if (!file_util::PathExists(current_version_file)) {
+    // This is OK, since we're phasing out the current version file.
+  } else {
+    if (!file_util::Delete(current_version_file, false)) {
+      LOG(WARNING) << "Could not delete Current Version file for extension "
+                   << id;
+      return;
+    }
+  }
+
+  // OK, now try and delete the entire rest of the directory. One major place
+  // this can fail is if the extension contains a plugin (stupid plugins). It's
+  // not a big deal though, because we'll notice next time we startup that the
+  // Current Version file is gone and finish the delete then.
+  if (!file_util::Delete(extension_root, true))
+    LOG(WARNING) << "Could not delete directory for extension " << id;
+}
+
+void GarbageCollectExtensions(
+    const FilePath& install_directory,
+    const std::set<std::string>& installed_ids,
+    const std::map<std::string, std::string>& installed_versions) {
+  // Nothing to clean up if it doesn't exist.
+  if (!file_util::DirectoryExists(install_directory))
+    return;
+
+  LOG(INFO) << "Loading installed extensions...";
+  file_util::FileEnumerator enumerator(install_directory,
+                                       false,  // Not recursive.
+                                       file_util::FileEnumerator::DIRECTORIES);
+  FilePath extension_path;
+  for (extension_path = enumerator.Next(); !extension_path.value().empty();
+       extension_path = enumerator.Next()) {
+    std::string extension_id = WideToASCII(
+        extension_path.BaseName().ToWStringHack());
+
+    // If there is no entry in the prefs file, just delete the directory and
+    // move on. This can legitimately happen when an uninstall does not
+    // complete, for example, when a plugin is in use at uninstall time.
+    if (installed_ids.count(extension_id) == 0) {
+      LOG(INFO) << "Deleting unreferenced install for directory "
+                << WideToASCII(extension_path.ToWStringHack()) << ".";
+      file_util::Delete(extension_path, true);  // Recursive.
+      continue;
+    }
+
+    // Delete directories that aren't valid IDs.
+    if (!Extension::IdIsValid(extension_id)) {
+      LOG(WARNING) << "Invalid extension ID encountered in extensions "
+                      "directory: " << extension_id;
+      LOG(INFO) << "Deleting invalid extension directory "
+                << WideToASCII(extension_path.ToWStringHack()) << ".";
+      file_util::Delete(extension_path, true);  // Recursive.
+      continue;
+    }
+
+    // Clean up old version directories.
+    file_util::FileEnumerator versions_enumerator(
+        extension_path,
+        false,  // Not recursive.
+        file_util::FileEnumerator::DIRECTORIES);
+    for (FilePath version_dir = versions_enumerator.Next();
+         !version_dir.value().empty();
+         version_dir = versions_enumerator.Next()) {
+      std::map<std::string, std::string>::const_iterator installed_version =
+          installed_versions.find(extension_id);
+      if (installed_version == installed_versions.end()) {
+        NOTREACHED() << "No installed version found for " << extension_id;
+        continue;
+      }
+
+      std::string version = WideToASCII(version_dir.BaseName().ToWStringHack());
+      if (version != installed_version->second) {
+        LOG(INFO) << "Deleting old version for directory "
+                  << WideToASCII(version_dir.ToWStringHack()) << ".";
+        file_util::Delete(version_dir, true);  // Recursive.
+      }
+    }
+  }
+}
+
+ExtensionMessageBundle* LoadExtensionMessageBundle(
+    const FilePath& extension_path,
+    const std::string& default_locale,
+    std::string* error) {
+  error->clear();
+  // Load locale information if available.
+  FilePath locale_path = extension_path.Append(Extension::kLocaleFolder);
+  if (!file_util::PathExists(locale_path))
+    return NULL;
+
+  std::set<std::string> locales;
+  if (!extension_l10n_util::GetValidLocales(locale_path, &locales, error))
+    return NULL;
+
+  if (default_locale.empty() ||
+      locales.find(default_locale) == locales.end()) {
+    *error = extension_manifest_errors::kLocalesNoDefaultLocaleSpecified;
+    return NULL;
+  }
+
+  ExtensionMessageBundle* message_bundle =
+      extension_l10n_util::LoadMessageCatalogs(
+          locale_path,
+          default_locale,
+          extension_l10n_util::CurrentLocaleOrDefault(),
+          locales,
+          error);
+
+  return message_bundle;
+}
+
+static bool ValidateLocaleInfo(const Extension& extension, std::string* error) {
+  // default_locale and _locales have to be both present or both missing.
+  const FilePath path = extension.path().Append(Extension::kLocaleFolder);
+  bool path_exists = file_util::PathExists(path);
+  std::string default_locale = extension.default_locale();
+
+  // If both default locale and _locales folder are empty, skip verification.
+  if (!default_locale.empty() || path_exists) {
+    if (default_locale.empty() && path_exists) {
+      *error = errors::kLocalesNoDefaultLocaleSpecified;
+      return false;
+    } else if (!default_locale.empty() && !path_exists) {
+      *error = errors::kLocalesTreeMissing;
+      return false;
+    }
+
+    // Treat all folders under _locales as valid locales.
+    file_util::FileEnumerator locales(path,
+                                      false,
+                                      file_util::FileEnumerator::DIRECTORIES);
+
+    FilePath locale_path = locales.Next();
+    if (locale_path.empty()) {
+      *error = errors::kLocalesTreeMissing;
+      return false;
+    }
+
+    const FilePath default_locale_path = path.AppendASCII(default_locale);
+    bool has_default_locale_message_file = false;
+    do {
+      // Skip any strings with '.'. This happens sometimes, for example with
+      // '.svn' directories.
+      FilePath relative_path;
+      if (!extension.path().AppendRelativePath(locale_path, &relative_path))
+        NOTREACHED();
+      std::wstring subdir(relative_path.ToWStringHack());
+      if (std::find(subdir.begin(), subdir.end(), L'.') != subdir.end())
+        continue;
+
+      FilePath messages_path =
+        locale_path.Append(Extension::kMessagesFilename);
+
+      if (!file_util::PathExists(messages_path)) {
+        *error = StringPrintf(
+            "%s %s", errors::kLocalesMessagesFileMissing,
+            WideToUTF8(messages_path.ToWStringHack()).c_str());
+        return false;
+      }
+
+      if (locale_path == default_locale_path)
+        has_default_locale_message_file = true;
+    } while (!(locale_path = locales.Next()).empty());
+
+    // Only message file for default locale has to exist.
+    if (!has_default_locale_message_file) {
+      *error = errors::kLocalesNoDefaultMessages;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool CheckForIllegalFilenames(const FilePath& extension_path,
+                              std::string* error) {
+  // Reserved underscore names.
+  static const FilePath::CharType* reserved_names[] = {
+    Extension::kLocaleFolder,
+    FILE_PATH_LITERAL("__MACOSX"),
+  };
+  static std::set<FilePath::StringType> reserved_underscore_names(
+      reserved_names, reserved_names + arraysize(reserved_names));
+
+  // Enumerate all files and directories in the extension root.
+  // There is a problem when using pattern "_*" with FileEnumerator, so we have
+  // to cheat with find_first_of and match all.
+  file_util::FileEnumerator all_files(
+    extension_path,
+    false,
+    static_cast<file_util::FileEnumerator::FILE_TYPE>(
+        file_util::FileEnumerator::DIRECTORIES |
+          file_util::FileEnumerator::FILES));
+
+  FilePath file;
+  while (!(file = all_files.Next()).empty()) {
+    FilePath::StringType filename = file.BaseName().value();
+    // Skip all that don't start with "_".
+    if (filename.find_first_of(FILE_PATH_LITERAL("_")) != 0) continue;
+    if (reserved_underscore_names.find(filename) ==
+        reserved_underscore_names.end()) {
+      *error = StringPrintf(
+        "Cannot load extension with file or directory name %s. "
+        "Filenames starting with \"_\" are reserved for use by the system.",
+        filename.c_str());
+      return false;
+    }
+  }
+
+  return true;
+}
+
+FilePath ExtensionURLToRelativeFilePath(const GURL& url) {
+  std::string url_path = url.path();
+  if (url_path.empty() || url_path[0] != '/')
+    return FilePath();
+
+  // Drop the leading slash and convert %-encoded UTF8 to regular UTF8.
+  std::string file_path = UnescapeURLComponent(url_path.substr(1),
+      UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
+
+#if defined(OS_POSIX)
+  return FilePath(file_path);
+#elif defined(OS_WIN)
+  return FilePath(UTF8ToWide(file_path));
+#endif
+}
+
+}  // namespace extension_file_util
diff --git a/chrome/common/extensions/extension_file_util.h b/chrome/common/extensions/extension_file_util.h
new file mode 100644
index 0000000..b711df0
--- /dev/null
+++ b/chrome/common/extensions/extension_file_util.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_FILE_UTIL_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_FILE_UTIL_H_
+
+#include <set>
+#include <string>
+
+#include "base/file_path.h"
+#include "chrome/common/extensions/extension.h"
+
+class ExtensionMessageBundle;
+
+// Utilties for manipulating the on-disk storage of extensions.
+namespace extension_file_util {
+
+// The name of the directory inside the profile that we store installed
+// extension in.
+extern const char kInstallDirectoryName[];
+
+// The name of the file that contains the current version of an installed
+// extension.
+extern const char kCurrentVersionFileName[];
+
+// Move source_dir to dest_dir (it will actually be named dest_dir, not inside
+// dest_dir). If the parent path doesn't exixt, create it. If something else is
+// already there, remove it.
+bool MoveDirSafely(const FilePath& source_dir, const FilePath& dest_dir);
+
+// Updates the Current Version file inside the installed extension.
+bool SetCurrentVersion(const FilePath& dest_dir,
+                       const std::string& version,
+                       std::string* error);
+
+// Reads the Current Version file.
+bool ReadCurrentVersion(const FilePath& dir, std::string* version_string);
+
+// Determine what type of install it is (new, upgrade, overinstall, downgrade)
+// given the current version and a newly installing version. |extensions_dir| is
+// the root directory containing all extensions in the user profile.
+// |extension_id| and |current_version_str| are the id and version of the
+// extension contained in |src_dir|, if any.
+//
+// Returns the full path to the destination version directory and the type of
+// install that was attempted.
+Extension::InstallType CompareToInstalledVersion(
+    const FilePath& extensions_dir,
+    const std::string& extension_id,
+    const std::string& current_version_str,
+    const std::string& new_version_str,
+    FilePath* version_dir);
+
+// Sanity check that the directory has the minimum files to be a working
+// extension.
+bool SanityCheckExtension(const FilePath& extension_root);
+
+// Installs an extension unpacked in |src_dir|.
+//
+// On failure, also returns an error message.
+//
+// NOTE: |src_dir| is not actually copied in the case of downgrades or
+// overinstall of previous verisons of the extension. In that case, the function
+// returns true and install_type is populated.
+bool InstallExtension(const FilePath& src_dir,
+                      const FilePath& version_dir,
+                      std::string* error);
+
+// Loads and validates an extension from the specified directory. Returns NULL
+// on failure, with a description of the error in |error|.
+Extension* LoadExtension(const FilePath& extension_root,
+                         bool require_key,
+                         std::string* error);
+
+// Returns true if the given extension object is valid and consistent.
+// Otherwise, a description of the error is returned in |error|.
+bool ValidateExtension(Extension* extension, std::string* error);
+
+// Uninstalls the extension |id| from the install directory |extensions_dir|.
+void UninstallExtension(const std::string& id, const FilePath& extensions_dir);
+
+// Clean up directories that aren't valid extensions from the install directory.
+void GarbageCollectExtensions(
+    const FilePath& extensions_dir,
+    const std::set<std::string>& installed_ids,
+    const std::map<std::string, std::string>& installed_versions);
+
+// Loads extension message catalogs and returns message bundle.
+// Returns NULL on error, or if extension is not localized.
+ExtensionMessageBundle* LoadExtensionMessageBundle(
+    const FilePath& extension_path,
+    const std::string& default_locale,
+    std::string* error);
+
+// We need to reserve the namespace of entries that start with "_" for future
+// use by Chrome.
+// If any files or directories are found using "_" prefix and are not on
+// reserved list we return false, and set error message.
+bool CheckForIllegalFilenames(const FilePath& extension_path,
+                              std::string* error);
+
+// Get a relative file path from a chrome-extension:// URL.
+FilePath ExtensionURLToRelativeFilePath(const GURL& url);
+
+}  // extension_file_util
+
+#endif  // CHROME_COMMON_EXTENSIONS_EXTENSION_FILE_UTIL_H_
diff --git a/chrome/common/extensions/extension_file_util_unittest.cc b/chrome/common/extensions/extension_file_util_unittest.cc
new file mode 100644
index 0000000..9856e42
--- /dev/null
+++ b/chrome/common/extensions/extension_file_util_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/extension_file_util.h"
+
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace keys = extension_manifest_keys;
+
+TEST(ExtensionFileUtil, MoveDirSafely) {
+  // Create a test directory structure with some data in it.
+  ScopedTempDir temp;
+  ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+  FilePath src_path = temp.path().AppendASCII("src");
+  ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+  std::string data = "foobar";
+  ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("data"),
+                                   data.c_str(), data.length()));
+
+  // Move it to a path that doesn't exist yet.
+  FilePath dest_path = temp.path().AppendASCII("dest").AppendASCII("dest");
+  ASSERT_TRUE(extension_file_util::MoveDirSafely(src_path, dest_path));
+
+  // The path should get created.
+  ASSERT_TRUE(file_util::DirectoryExists(dest_path));
+
+  // The data should match.
+  std::string data_out;
+  ASSERT_TRUE(file_util::ReadFileToString(dest_path.AppendASCII("data"),
+                                          &data_out));
+  ASSERT_EQ(data, data_out);
+
+  // The src path should be gone.
+  ASSERT_FALSE(file_util::PathExists(src_path));
+
+  // Create some new test data.
+  ASSERT_TRUE(file_util::CopyDirectory(dest_path, src_path,
+                                       true));  // recursive
+  data = "hotdog";
+  ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("data"),
+                                   data.c_str(), data.length()));
+
+  // Test again, overwriting the old path.
+  ASSERT_TRUE(extension_file_util::MoveDirSafely(src_path, dest_path));
+  ASSERT_TRUE(file_util::DirectoryExists(dest_path));
+
+  data_out.clear();
+  ASSERT_TRUE(file_util::ReadFileToString(dest_path.AppendASCII("data"),
+                                          &data_out));
+  ASSERT_EQ(data, data_out);
+  ASSERT_FALSE(file_util::PathExists(src_path));
+}
+
+TEST(ExtensionFileUtil, CompareToInstalledVersion) {
+  // Compare to an existing extension.
+  FilePath install_dir;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+  install_dir = install_dir.AppendASCII("extensions")
+      .AppendASCII("good")
+      .AppendASCII("Extensions");
+
+  const std::string kId = "behllobkkfkfnphdnhnkndlbkcpglgmj";
+  const std::string kCurrentVersion = "1.0.0.0";
+
+  FilePath version_dir;
+
+  ASSERT_EQ(Extension::UPGRADE,
+            extension_file_util::CompareToInstalledVersion(
+                install_dir, kId, kCurrentVersion, "1.0.0.1", &version_dir));
+
+  ASSERT_EQ(Extension::REINSTALL,
+            extension_file_util::CompareToInstalledVersion(
+                install_dir, kId, kCurrentVersion, "1.0.0.0", &version_dir));
+
+  ASSERT_EQ(Extension::REINSTALL,
+            extension_file_util::CompareToInstalledVersion(
+                install_dir, kId, kCurrentVersion, "1.0.0", &version_dir));
+
+  ASSERT_EQ(Extension::DOWNGRADE,
+            extension_file_util::CompareToInstalledVersion(
+                install_dir, kId, kCurrentVersion, "0.0.1.0", &version_dir));
+
+  // Compare to an extension that is missing its manifest file.
+  ScopedTempDir temp;
+  ASSERT_TRUE(temp.CreateUniqueTempDir());
+  FilePath src = install_dir.AppendASCII(kId).AppendASCII(kCurrentVersion);
+  FilePath dest = temp.path().AppendASCII(kId).AppendASCII(kCurrentVersion);
+  ASSERT_TRUE(file_util::CreateDirectory(dest.DirName()));
+  ASSERT_TRUE(file_util::CopyDirectory(src, dest, true));
+  ASSERT_TRUE(file_util::Delete(dest.AppendASCII("manifest.json"), false));
+
+  ASSERT_EQ(Extension::NEW_INSTALL,
+            extension_file_util::CompareToInstalledVersion(
+                temp.path(), kId, kCurrentVersion, "1.0.0", &version_dir));
+
+  // Compare to a non-existent extension.
+  const std::string kMissingVersion = "";
+  const std::string kBadId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+  ASSERT_EQ(Extension::NEW_INSTALL,
+            extension_file_util::CompareToInstalledVersion(
+                temp.path(), kBadId, kMissingVersion, "1.0.0", &version_dir));
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithValidLocales) {
+  FilePath install_dir;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+  install_dir = install_dir.AppendASCII("extensions")
+      .AppendASCII("good")
+      .AppendASCII("Extensions")
+      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+      .AppendASCII("1.0.0.0");
+
+  std::string error;
+  scoped_ptr<Extension> extension(
+      extension_file_util::LoadExtension(install_dir, false, &error));
+  ASSERT_TRUE(extension != NULL);
+  EXPECT_EQ("The first extension that I made.", extension->description());
+}
+
+TEST(ExtensionFileUtil, LoadExtensionWithoutLocalesFolder) {
+  FilePath install_dir;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+  install_dir = install_dir.AppendASCII("extensions")
+      .AppendASCII("good")
+      .AppendASCII("Extensions")
+      .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa")
+      .AppendASCII("1.0");
+
+  std::string error;
+  scoped_ptr<Extension> extension(
+      extension_file_util::LoadExtension(install_dir, false, &error));
+  ASSERT_FALSE(extension == NULL);
+  EXPECT_TRUE(error.empty());
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesNoUnderscores) {
+  ScopedTempDir temp;
+  ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+  FilePath src_path = temp.path().AppendASCII("some_dir");
+  ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+  std::string data = "{ \"name\": { \"message\": \"foobar\" } }";
+  ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("some_file.txt"),
+                                   data.c_str(), data.length()));
+  std::string error;
+  EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+                                                            &error));
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesOnlyReserved) {
+  ScopedTempDir temp;
+  ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+  FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
+  ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+  std::string error;
+  EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+                                                            &error));
+}
+
+TEST(ExtensionFileUtil, CheckIllegalFilenamesReservedAndIllegal) {
+  ScopedTempDir temp;
+  ASSERT_TRUE(temp.CreateUniqueTempDir());
+
+  FilePath src_path = temp.path().Append(Extension::kLocaleFolder);
+  ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+  src_path = temp.path().AppendASCII("_some_dir");
+  ASSERT_TRUE(file_util::CreateDirectory(src_path));
+
+  std::string error;
+  EXPECT_FALSE(extension_file_util::CheckForIllegalFilenames(temp.path(),
+                                                             &error));
+}
+
+TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnMissingManifest) {
+  FilePath install_dir;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+  install_dir = install_dir.AppendASCII("extensions")
+      .AppendASCII("bad")
+      .AppendASCII("Extensions")
+      .AppendASCII("dddddddddddddddddddddddddddddddd")
+      .AppendASCII("1.0");
+
+  std::string error;
+  scoped_ptr<Extension> extension(
+      extension_file_util::LoadExtension(install_dir, false, &error));
+  ASSERT_TRUE(extension == NULL);
+  ASSERT_FALSE(error.empty());
+  ASSERT_STREQ("Manifest file is missing or unreadable.", error.c_str());
+}
+
+TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnBadManifest) {
+  FilePath install_dir;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+  install_dir = install_dir.AppendASCII("extensions")
+      .AppendASCII("bad")
+      .AppendASCII("Extensions")
+      .AppendASCII("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
+      .AppendASCII("1.0");
+
+  std::string error;
+  scoped_ptr<Extension> extension(
+      extension_file_util::LoadExtension(install_dir, false, &error));
+  ASSERT_TRUE(extension == NULL);
+  ASSERT_FALSE(error.empty());
+  ASSERT_STREQ("Manifest is not valid JSON.  "
+               "Line: 2, column: 16, Syntax error.", error.c_str());
+}
+
+#define URL_PREFIX "chrome-extension://extension-id/"
+
+TEST(ExtensionFileUtil, ExtensionURLToRelativeFilePath) {
+  struct TestCase {
+    const char* url;
+    const char* expected_relative_path;
+  } test_cases[] = {
+    { URL_PREFIX "simple.html",
+      "simple.html" },
+    { URL_PREFIX "directory/to/file.html",
+      "directory/to/file.html" },
+    { URL_PREFIX "escape%20spaces.html",
+      "escape spaces.html" },
+    { URL_PREFIX "%C3%9Cber.html",
+      "\xC3\x9C" "ber.html" },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
+    GURL url(test_cases[i].url);
+#if defined(OS_POSIX)
+    FilePath expected_path(test_cases[i].expected_relative_path);
+#elif defined(OS_WIN)
+    FilePath expected_path(UTF8ToWide(test_cases[i].expected_relative_path));
+#endif
+
+    FilePath actual_path =
+        extension_file_util::ExtensionURLToRelativeFilePath(url);
+    EXPECT_FALSE(actual_path.IsAbsolute()) <<
+      " For the path " << actual_path.value();
+    EXPECT_EQ(expected_path.value(), actual_path.value());
+  }
+}
+
+// TODO(aa): More tests as motivation allows. Maybe steal some from
+// ExtensionsService? Many of them could probably be tested here without the
+// MessageLoop shenanigans.
diff --git a/chrome/common/extensions/extension_l10n_util.cc b/chrome/common/extensions/extension_l10n_util.cc
index 2fd3f92..3f329fb 100644
--- a/chrome/common/extensions/extension_l10n_util.cc
+++ b/chrome/common/extensions/extension_l10n_util.cc
@@ -14,10 +14,10 @@
 #include "base/string_util.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extension_file_util.h"
 #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_message_bundle.h"
 #include "chrome/common/json_value_serializer.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/common/extensions/extension_unpacker.cc b/chrome/common/extensions/extension_unpacker.cc
index 425105f..ac643df 100644
--- a/chrome/common/extensions/extension_unpacker.cc
+++ b/chrome/common/extensions/extension_unpacker.cc
@@ -11,10 +11,10 @@
 #include "base/thread.h"
 #include "base/values.h"
 #include "net/base/file_stream.h"
-#include "chrome/browser/extensions/extension_file_util.h"
 #include "chrome/common/common_param_traits.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/json_value_serializer.h"
 #include "chrome/common/notification_service.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/common/histogram_synchronizer.cc b/chrome/common/histogram_synchronizer.cc
deleted file mode 100644
index 9aeff5e..0000000
--- a/chrome/common/histogram_synchronizer.cc
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/histogram_synchronizer.h"
-
-#include "base/histogram.h"
-#include "base/logging.h"
-#include "base/thread.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/common/render_messages.h"
-
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-
-HistogramSynchronizer::HistogramSynchronizer()
-  : lock_(),
-    received_all_renderer_historgrams_(&lock_),
-    callback_task_(NULL),
-    callback_thread_(NULL),
-    io_message_loop_(NULL),
-    next_available_sequence_number_(0),
-    async_sequence_number_(0),
-    async_renderers_pending_(0),
-    async_callback_start_time_(TimeTicks::Now()),
-    synchronous_sequence_number_(0),
-    synchronous_renderers_pending_(0) {
-  DCHECK(histogram_synchronizer_ == NULL);
-  histogram_synchronizer_ = this;
-}
-
-HistogramSynchronizer::~HistogramSynchronizer() {
-  // Clean up.
-  delete callback_task_;
-  callback_task_ = NULL;
-  callback_thread_ = NULL;
-  histogram_synchronizer_ = NULL;
-}
-
-// static
-HistogramSynchronizer* HistogramSynchronizer::CurrentSynchronizer() {
-  DCHECK(histogram_synchronizer_ != NULL);
-  return histogram_synchronizer_;
-}
-
-void HistogramSynchronizer::FetchRendererHistogramsSynchronously(
-    TimeDelta wait_time) {
-  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
-
-  int sequence_number = GetNextAvaibleSequenceNumber(SYNCHRONOUS_HISTOGRAMS);
-  for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
-       !it.IsAtEnd(); it.Advance()) {
-    it.GetCurrentValue()->Send(
-        new ViewMsg_GetRendererHistograms(sequence_number));
-    IncrementPendingRenderers(SYNCHRONOUS_HISTOGRAMS);
-  }
-
-  TimeTicks start = TimeTicks::Now();
-  TimeTicks end_time = start + wait_time;
-  int unresponsive_renderer_count;
-  {
-    AutoLock auto_lock(lock_);
-    while (synchronous_renderers_pending_ > 0 &&
-           TimeTicks::Now() < end_time) {
-      wait_time = end_time - TimeTicks::Now();
-      received_all_renderer_historgrams_.TimedWait(wait_time);
-    }
-    unresponsive_renderer_count = synchronous_renderers_pending_;
-    synchronous_renderers_pending_ = 0;
-    synchronous_sequence_number_ = 0;
-  }
-  UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingSynchronous",
-                       unresponsive_renderer_count);
-  if (!unresponsive_renderer_count)
-    UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsSynchronously",
-                        TimeTicks::Now() - start);
-}
-
-// static
-void HistogramSynchronizer::FetchRendererHistogramsAsynchronously(
-    MessageLoop* callback_thread,
-    Task* callback_task,
-    int wait_time) {
-  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
-  DCHECK(callback_thread != NULL);
-  DCHECK(callback_task != NULL);
-
-  HistogramSynchronizer* current_synchronizer =
-      HistogramSynchronizer::CurrentSynchronizer();
-
-  if (current_synchronizer == NULL) {
-    // System teardown is happening.
-    callback_thread->PostTask(FROM_HERE, callback_task);
-    return;
-  }
-
-  // callback_task_ member can only be accessed on IO thread.
-  ChromeThread::PostTask(
-      ChromeThread::IO, FROM_HERE,
-      NewRunnableMethod(
-          current_synchronizer,
-          &HistogramSynchronizer::SetCallbackTaskToCallAfterGettingHistograms,
-          callback_thread,
-          callback_task));
-
-  // Tell all renderer processes to send their histograms.
-  int sequence_number =
-      current_synchronizer->GetNextAvaibleSequenceNumber(ASYNC_HISTOGRAMS);
-  for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
-       !it.IsAtEnd(); it.Advance()) {
-    it.GetCurrentValue()->Send(
-        new ViewMsg_GetRendererHistograms(sequence_number));
-    current_synchronizer->IncrementPendingRenderers(ASYNC_HISTOGRAMS);
-  }
-
-  // Post a task that would be called after waiting for wait_time.
-  ChromeThread::PostDelayedTask(
-      ChromeThread::IO, FROM_HERE,
-      NewRunnableMethod(
-          current_synchronizer,
-          &HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback,
-          sequence_number),
-      wait_time);
-}
-
-// static
-void HistogramSynchronizer::DeserializeHistogramList(
-    int sequence_number,
-    const std::vector<std::string>& histograms) {
-  HistogramSynchronizer* current_synchronizer =
-      HistogramSynchronizer::CurrentSynchronizer();
-  if (current_synchronizer == NULL)
-    return;
-
-  DCHECK(current_synchronizer->IsOnIoThread());
-
-  for (std::vector<std::string>::const_iterator it = histograms.begin();
-       it < histograms.end();
-       ++it) {
-    Histogram::DeserializeHistogramInfo(*it);
-  }
-
-  // Record that we have received a histogram from renderer process.
-  current_synchronizer->RecordRendererHistogram(sequence_number);
-}
-
-bool HistogramSynchronizer::RecordRendererHistogram(int sequence_number) {
-  DCHECK(IsOnIoThread());
-
-  if (sequence_number == async_sequence_number_) {
-    if ((async_renderers_pending_ == 0) ||
-        (--async_renderers_pending_ > 0))
-      return false;
-    DCHECK(callback_task_ != NULL);
-    CallCallbackTaskAndResetData();
-    return true;
-  }
-
-  {
-    AutoLock auto_lock(lock_);
-    if (sequence_number != synchronous_sequence_number_) {
-      // No need to do anything if the sequence_number does not match current
-      // synchronous_sequence_number_ or async_sequence_number_.
-      return true;
-    }
-    if ((synchronous_renderers_pending_ == 0) ||
-        (--synchronous_renderers_pending_ > 0))
-      return false;
-    DCHECK_EQ(synchronous_renderers_pending_, 0);
-  }
-
-  // We could call Signal() without holding the lock.
-  received_all_renderer_historgrams_.Signal();
-  return true;
-}
-
-// This method is called on the IO thread.
-void HistogramSynchronizer::SetCallbackTaskToCallAfterGettingHistograms(
-    MessageLoop* callback_thread,
-    Task* callback_task) {
-  DCHECK(IsOnIoThread());
-
-  // Test for the existence of a previous task, and post call to post it if it
-  // exists. We promised to post it after some timeout... and at this point, we
-  // should just force the posting.
-  if (callback_task_ != NULL) {
-    CallCallbackTaskAndResetData();
-  }
-
-  // Assert there was no callback_task_ already.
-  DCHECK(callback_task_ == NULL);
-
-  // Save the thread and the callback_task.
-  DCHECK(callback_thread != NULL);
-  DCHECK(callback_task != NULL);
-  callback_task_ = callback_task;
-  callback_thread_ = callback_thread;
-  async_callback_start_time_ = TimeTicks::Now();
-}
-
-void HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback(
-    int sequence_number) {
-  DCHECK(IsOnIoThread());
-
-  if (sequence_number == async_sequence_number_) {
-     CallCallbackTaskAndResetData();
-  }
-}
-
-// If wait time has elapsed or if we have received all the histograms from all
-// the renderers, call the callback_task if a callback_task exists. This is
-// called on IO Thread.
-void HistogramSynchronizer::CallCallbackTaskAndResetData() {
-  DCHECK(IsOnIoThread());
-
-  // callback_task_ would be set to NULL, if we have heard from all renderers
-  // and we would have called the callback_task already.
-  if (callback_task_ == NULL) {
-    return;
-  }
-
-  UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingAsynchronous",
-                       async_renderers_pending_);
-  if (!async_renderers_pending_)
-    UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsAsynchronously",
-                        TimeTicks::Now() - async_callback_start_time_);
-
-  DCHECK(callback_thread_ != NULL);
-  DCHECK(callback_task_ != NULL);
-  callback_thread_->PostTask(FROM_HERE, callback_task_);
-  async_renderers_pending_ = 0;
-  async_callback_start_time_ = TimeTicks::Now();
-  callback_task_ = NULL;
-  callback_thread_ = NULL;
-}
-
-int HistogramSynchronizer::GetNextAvaibleSequenceNumber(
-    RendererHistogramRequester requester) {
-  AutoLock auto_lock(lock_);
-  ++next_available_sequence_number_;
-  if (0 > next_available_sequence_number_)  // We wrapped around.
-    next_available_sequence_number_ = kReservedSequenceNumber + 1;
-  DCHECK(next_available_sequence_number_ != kReservedSequenceNumber);
-  if (requester == ASYNC_HISTOGRAMS) {
-    async_sequence_number_ = next_available_sequence_number_;
-    async_renderers_pending_ = 0;
-  } else if (requester == SYNCHRONOUS_HISTOGRAMS) {
-    synchronous_sequence_number_ = next_available_sequence_number_;
-    synchronous_renderers_pending_ = 0;
-  }
-  return next_available_sequence_number_;
-}
-
-void HistogramSynchronizer::IncrementPendingRenderers(
-    RendererHistogramRequester requester) {
-  if (requester == ASYNC_HISTOGRAMS) {
-    async_renderers_pending_++;
-  } else {
-    synchronous_renderers_pending_++;
-  }
-}
-
-bool HistogramSynchronizer::IsOnIoThread() {
-  if (io_message_loop_ == NULL) {
-    io_message_loop_ = MessageLoop::current();
-  }
-  return (MessageLoop::current() == io_message_loop_);
-}
-
-// static
-HistogramSynchronizer* HistogramSynchronizer::histogram_synchronizer_ = NULL;
diff --git a/chrome/common/histogram_synchronizer.h b/chrome/common/histogram_synchronizer.h
deleted file mode 100644
index 1190555..0000000
--- a/chrome/common/histogram_synchronizer.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_
-#define CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/condition_variable.h"
-#include "base/lock.h"
-#include "base/ref_counted.h"
-#include "base/time.h"
-
-class MessageLoop;
-class Task;
-
-class HistogramSynchronizer : public
-    base::RefCountedThreadSafe<HistogramSynchronizer> {
- public:
-
-  enum RendererHistogramRequester {
-    ASYNC_HISTOGRAMS,
-    SYNCHRONOUS_HISTOGRAMS
-  };
-
-  static const int kReservedSequenceNumber = 0;
-
-  HistogramSynchronizer();
-
-  ~HistogramSynchronizer();
-
-  // Return pointer to the singleton instance, which is allocated and
-  // deallocated on the main UI thread (during system startup and teardown).
-  static HistogramSynchronizer* CurrentSynchronizer();
-
-  // Contact all renderers, and get them to upload to the browser any/all
-  // changes to histograms.  Return when all changes have been acquired, or when
-  // the wait time expires (whichever is sooner). This method is called on the
-  // main UI thread from about:histograms.
-  void FetchRendererHistogramsSynchronously(base::TimeDelta wait_time);
-
-  // Contact all renderers, and get them to upload to the browser any/all
-  // changes to histograms.  When all changes have been acquired, or when the
-  // wait time expires (whichever is sooner), post the callback_task to the UI
-  // thread. Note the callback_task is posted exactly once. This method is
-  // called on the IO thread from UMA via PostMessage.
-  static void FetchRendererHistogramsAsynchronously(
-      MessageLoop* callback_thread, Task* callback_task, int wait_time);
-
-  // This method is called on the IO thread. Desrializes the histograms and
-  // records that we have received histograms from a renderer process.
-  static void DeserializeHistogramList(
-      int sequence_number, const std::vector<std::string>& histograms);
-
- private:
-  // Records that we have received the histograms from a renderer for the given
-  // sequence number. If we have received a response from all histograms, either
-  // signal the waiting process or call the callback function. Returns true when
-  // we receive histograms from the last of N renderers that were contacted for
-  // an update. This is called on IO Thread.
-  bool RecordRendererHistogram(int sequence_number);
-
-  void SetCallbackTaskToCallAfterGettingHistograms(
-      MessageLoop* callback_thread, Task* callback_task);
-
-  void ForceHistogramSynchronizationDoneCallback(int sequence_number);
-
-  // Calls the callback task, if there is a callback_task.
-  void CallCallbackTaskAndResetData();
-
-  // Gets a new sequence number to be sent to renderers from broswer process.
-  // This will also reset the current pending renderers for the given type.
-  int GetNextAvaibleSequenceNumber(RendererHistogramRequester requster);
-
-  // Increments the count of the renderers we're waiting for for the request
-  // of the given type.
-  void IncrementPendingRenderers(RendererHistogramRequester requester);
-
-  // For use ONLY in a DCHECK. This method initializes io_message_loop_ in its
-  // first call and then compares io_message_loop_ with MessageLoop::current()
-  // in subsequent calls. This method guarantees we're consistently on the
-  // singular IO thread and we don't need to worry about locks.
-  bool IsOnIoThread();
-
-  // This lock_ protects access to sequence number and
-  // synchronous_renderers_pending_.
-  Lock lock_;
-
-  // This condition variable is used to block caller of the synchronous request
-  // to update histograms, and to signal that thread when updates are completed.
-  ConditionVariable received_all_renderer_historgrams_;
-
-  // When a request is made to asynchronously update the histograms, we store
-  // the task and thread we use to post a completion notification in
-  // callback_task_ and callback_thread_.
-  Task* callback_task_;
-  MessageLoop* callback_thread_;
-
-  // For use ONLY in a DCHECK and is used in IsOnIoThread(). io_message_loop_ is
-  // initialized during the first call to IsOnIoThread(), and then compares
-  // MessageLoop::current() against io_message_loop_ in subsequent calls for
-  // consistency.
-  MessageLoop* io_message_loop_;
-
-  // We don't track the actual renderers that are contacted for an update, only
-  // the count of the number of renderers, and we can sometimes time-out and
-  // give up on a "slow to respond" renderer.  We use a sequence_number to be
-  // sure a response from a renderer is associated with the current round of
-  // requests (and not merely a VERY belated prior response).
-  // next_available_sequence_number_ is the next available number (used to
-  // avoid reuse for a long time).
-  int next_available_sequence_number_;
-
-  // The sequence number used by the most recent asynchronous update request to
-  // contact all renderers.
-  int async_sequence_number_;
-
-  // The number of renderers that have not yet responded to requests (as part of
-  // an asynchronous update).
-  int async_renderers_pending_;
-
-  // The time when we were told to start the fetch histograms asynchronously
-  // from renderers.
-  base::TimeTicks async_callback_start_time_;
-
-  // The sequence number used by the most recent synchronous update request to
-  // contact all renderers.
-  int synchronous_sequence_number_;
-
-  // The number of renderers that have not yet responded to requests (as part of
-  // a synchronous update).
-  int synchronous_renderers_pending_;
-
-  // This singleton instance should be started during the single threaded
-  // portion of main(). It initializes globals to provide support for all future
-  // calls. This object is created on the UI thread, and it is destroyed after
-  // all the other threads have gone away. As a result, it is ok to call it
-  // from the UI thread (for UMA uploads), or for about:histograms.
-  static HistogramSynchronizer* histogram_synchronizer_;
-
-  DISALLOW_COPY_AND_ASSIGN(HistogramSynchronizer);
-};
-
-#endif  // CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 7e05039..42b0313 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -16,7 +16,6 @@
 #include "base/ref_counted.h"
 #include "base/shared_memory.h"
 #include "base/string16.h"
-#include "chrome/browser/renderer_host/resource_handler.h"
 #include "chrome/common/common_param_traits.h"
 #include "chrome/common/css_colors.h"
 #include "chrome/common/dom_storage_common.h"
@@ -26,6 +25,7 @@
 #include "chrome/common/navigation_gesture.h"
 #include "chrome/common/page_transition_types.h"
 #include "chrome/common/renderer_preferences.h"
+#include "chrome/common/resource_response.h"
 #include "chrome/common/transport_dib.h"
 #include "chrome/common/view_types.h"
 #include "chrome/common/webkit_param_traits.h"
diff --git a/chrome/common/resource_response.h b/chrome/common/resource_response.h
new file mode 100644
index 0000000..840b864
--- /dev/null
+++ b/chrome/common/resource_response.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// See http://dev.chromium.org/developers/design-documents/multi-process-resource-loading
+
+#ifndef CHROME_COMMON_RESOURCE_RESPONSE_H_
+#define CHROME_COMMON_RESOURCE_RESPONSE_H_
+
+#include <string>
+
+#include "base/ref_counted.h"
+#include "chrome/common/filter_policy.h"
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request_status.h"
+#include "webkit/glue/resource_loader_bridge.h"
+
+// Parameters for a resource response header.
+struct ResourceResponseHead
+    : webkit_glue::ResourceLoaderBridge::ResponseInfo {
+  ResourceResponseHead() : filter_policy(FilterPolicy::DONT_FILTER) {}
+
+  // The response status.
+  URLRequestStatus status;
+
+  // Specifies if the resource should be filtered before being displayed
+  // (insecure resources can be filtered to keep the page secure).
+  FilterPolicy::Type filter_policy;
+};
+
+// Parameters for a synchronous resource response.
+struct SyncLoadResult : ResourceResponseHead {
+  // The final URL after any redirects.
+  GURL final_url;
+
+  // The response data.
+  std::string data;
+};
+
+// Simple wrapper that refcounts ResourceResponseHead.
+struct ResourceResponse : public base::RefCounted<ResourceResponse> {
+  ResourceResponseHead response_head;
+
+ private:
+  friend class base::RefCounted<ResourceResponse>;
+
+  ~ResourceResponse() {}
+};
+
+#endif  // CHROME_COMMON_RESOURCE_RESPONSE_H_
-- 
cgit v1.1