Merge from Chromium at DEPS revision 225410

This commit was generated by merge_to_master.py.

Change-Id: Ifa1539ca216abb163295ee7a77f81bb67f52e178
diff --git a/chrome/common/automation_constants.cc b/chrome/common/automation_constants.cc
index 1b8d32d..212864c 100644
--- a/chrome/common/automation_constants.cc
+++ b/chrome/common/automation_constants.cc
@@ -19,48 +19,4 @@
 // AutomationProxy to an already-running browser instance.
 const char kNamedInterfacePrefix[] = "NamedTestingInterface:";
 
-const int kChromeDriverAutomationVersion = 1;
-
-namespace {
-
-// Returns the string equivalent of the given |ErrorCode|.
-const char* DefaultMessageForErrorCode(ErrorCode code) {
-  switch (code) {
-    case kUnknownError:
-      return "Unknown error";
-    case kNoJavaScriptModalDialogOpen:
-      return "No JavaScript modal dialog is open";
-    case kBlockedByModalDialog:
-      return "Command blocked by an open modal dialog";
-    case kInvalidId:
-      return "ID is invalid or does not refer to an existing object";
-    default:
-      return "<unknown>";
-  }
-}
-
-}  // namespace
-
-Error::Error() : code_(kUnknownError) { }
-
-Error::Error(ErrorCode code)
-    : code_(code),
-      message_(DefaultMessageForErrorCode(code)) { }
-
-Error::Error(const std::string& error_msg)
-    : code_(kUnknownError), message_(error_msg) { }
-
-Error::Error(ErrorCode code, const std::string& error_msg)
-    : code_(code), message_(error_msg) { }
-
-Error::~Error() { }
-
-ErrorCode Error::code() const {
-  return code_;
-}
-
-const std::string& Error::message() const {
-  return message_;
-}
-
 }  // namespace automation
diff --git a/chrome/common/automation_constants.h b/chrome/common/automation_constants.h
index 4742b39..112e29f 100644
--- a/chrome/common/automation_constants.h
+++ b/chrome/common/automation_constants.h
@@ -64,57 +64,6 @@
   kNoButton,
 };
 
-// The current version of ChromeDriver automation supported by Chrome.
-// This needs to be incremented for each change to ChromeDriver automation that
-// is not backwards compatible. Some examples of this would be:
-// - SendJSONRequest or Hello IPC messages change
-// - The interface for an individual ChromeDriver automation call changes in an
-//   incompatible way
-// TODO(kkania): Investigate a better backwards compatible automation solution.
-extern const int kChromeDriverAutomationVersion;
-
-// Automation error codes. These provide the client a simple way
-// to detect certain types of errors it may be interested in handling.
-// The error code values must stay consistent across compatible versions.
-enum ErrorCode {
-  // An unknown error occurred.
-  kUnknownError = 0,
-  // Trying to operate on a JavaScript modal dialog when none is open.
-  kNoJavaScriptModalDialogOpen = 1,
-  // An open modal dialog blocked the operation. The operation may have
-  // partially completed.
-  kBlockedByModalDialog = 2,
-  // An ID was supplied that is invalid or does not refer to an existing object.
-  kInvalidId = 3,
-};
-
-// Represents an automation error. Each error has a code and an error message.
-class Error {
- public:
-  // Creates an invalid error.
-  Error();
-
-  // Creates an error for the given code. A default message for the given code
-  // will be used as the error message.
-  explicit Error(ErrorCode code);
-
-  // Creates an error for the given message. The |kUnknownError| type will
-  // be used.
-  explicit Error(const std::string& error_msg);
-
-  // Creates an error for the given code and message.
-  Error(ErrorCode code, const std::string& error_msg);
-
-  virtual ~Error();
-
-  ErrorCode code() const;
-  const std::string& message() const;
-
- private:
-  ErrorCode code_;
-  std::string message_;
-};
-
 }  // namespace automation
 
 // Used by AutomationProxy, declared here so that other headers don't need
diff --git a/chrome/common/automation_id.cc b/chrome/common/automation_id.cc
deleted file mode 100644
index b1d5c3a..0000000
--- a/chrome/common/automation_id.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/automation_id.h"
-
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-
-// static
-bool AutomationId::FromValue(
-    base::Value* value, AutomationId* id, std::string* error) {
-  base::DictionaryValue* dict;
-  if (!value->GetAsDictionary(&dict)) {
-    *error = "automation ID must be a dictionary";
-    return false;
-  }
-  int type;
-  if (!dict->GetInteger("type", &type)) {
-    *error = "automation ID 'type' missing or invalid";
-    return false;
-  }
-  std::string type_id;
-  if (!dict->GetString("id", &type_id)) {
-    *error = "automation ID 'type_id' missing or invalid";
-    return false;
-  }
-  *id = AutomationId(static_cast<Type>(type), type_id);
-  return true;
-}
-
-// static
-bool AutomationId::FromValueInDictionary(
-    base::DictionaryValue* dict,
-    const std::string& key,
-    AutomationId* id,
-    std::string* error) {
-  base::Value* id_value;
-  if (!dict->Get(key, &id_value)) {
-    *error = base::StringPrintf("automation ID '%s' missing", key.c_str());
-    return false;
-  }
-  return FromValue(id_value, id, error);
-}
-
-AutomationId::AutomationId() : type_(kTypeInvalid) { }
-
-AutomationId::AutomationId(Type type, const std::string& id)
-    : type_(type), id_(id) { }
-
-bool AutomationId::operator==(const AutomationId& id) const {
-  return type_ == id.type_ && id_ == id.id_;
-}
-
-base::DictionaryValue* AutomationId::ToValue() const {
-  base::DictionaryValue* dict = new base::DictionaryValue();
-  dict->SetInteger("type", type_);
-  dict->SetString("id", id_);
-  return dict;
-}
-
-bool AutomationId::is_valid() const {
-  return type_ != kTypeInvalid;
-}
-
-AutomationId::Type AutomationId::type() const {
-  return type_;
-}
-
-const std::string& AutomationId::id() const {
-  return id_;
-}
diff --git a/chrome/common/automation_id.h b/chrome/common/automation_id.h
deleted file mode 100644
index b05f060..0000000
--- a/chrome/common/automation_id.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_AUTOMATION_ID_H_
-#define CHROME_COMMON_AUTOMATION_ID_H_
-
-#include <string>
-
-namespace base {
-class DictionaryValue;
-class Value;
-}
-
-// A unique ID that JSON automation clients can use to refer to browser
-// entities. The ID has a type so that:
-// 1) supplying an ID of the wrong type can be detected.
-// 2) the client does not have to explicitly supply the type in case multiple
-//    ID types can be accepted (e.g., can use a tab ID or extension popup ID for
-//    executing javascript).
-class AutomationId {
- public:
-  // The value of each entry should be preserved.
-  enum Type {
-    kTypeInvalid = 0,
-    kTypeTab,
-    kTypeExtensionPopup,
-    kTypeExtensionBgPage,
-    kTypeExtensionInfobar,
-    kTypeExtension,
-    kTypeAppShell,
-  };
-
-  static bool FromValue(
-      base::Value* value, AutomationId* id, std::string* error);
-  static bool FromValueInDictionary(
-      base::DictionaryValue* dict, const std::string& key, AutomationId* id,
-      std::string* error);
-
-  // Constructs an invalid ID.
-  AutomationId();
-
-  // Constructs an ID from the given type and type-specific ID.
-  AutomationId(Type type, const std::string& id);
-
-  bool operator==(const AutomationId& id) const;
-
-  // Returns a new dictionary equivalent to this ID.
-  base::DictionaryValue* ToValue() const;
-
-  // Returns whether the automation ID is valid.
-  bool is_valid() const;
-
-  Type type() const;
-  const std::string& id() const;
-
- private:
-  Type type_;
-  std::string id_;
-};
-
-#endif  // CHROME_COMMON_AUTOMATION_ID_H_
diff --git a/chrome/common/badge_util.cc b/chrome/common/badge_util.cc
index ccbaca1..a762a6f 100644
--- a/chrome/common/badge_util.cc
+++ b/chrome/common/badge_util.cc
@@ -124,7 +124,7 @@
 
   // Render the badge bitmap and overlay into a canvas.
   scoped_ptr<gfx::Canvas> canvas(new gfx::Canvas(
-      gfx::Size(badge_width, icon.height()), ui::SCALE_FACTOR_100P, false));
+      gfx::Size(badge_width, icon.height()), 1.0f, false));
   canvas->DrawImageInt(gfx::ImageSkia::CreateFrom1xBitmap(icon), 0, 0);
 
   // Draw the text overlay centered horizontally and vertically. Skia expects
diff --git a/chrome/common/child_process_logging.h b/chrome/common/child_process_logging.h
index 6132061..f437828 100644
--- a/chrome/common/child_process_logging.h
+++ b/chrome/common/child_process_logging.h
@@ -5,23 +5,10 @@
 #ifndef CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
 #define CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
 
-#include <set>
 #include <string>
-#include <vector>
 
 #include "base/basictypes.h"
 #include "base/debug/crash_logging.h"
-#include "base/strings/string16.h"
-
-// The maximum number of variation chunks we will report.
-// Also used in chrome/app, but we define it here to avoid a common->app
-// dependency.
-static const size_t kMaxReportedVariationChunks = 15;
-
-// The maximum size of a variation chunk. This size was picked to be
-// consistent between platforms and the value was chosen from the Windows
-// limit of google_breakpad::CustomInfoEntry::kValueMaxLength.
-static const size_t kMaxVariationChunkSize = 64;
 
 namespace child_process_logging {
 
@@ -29,8 +16,6 @@
 // These are declared here so the crash reporter can access them directly in
 // compromised context without going through the standard library.
 extern char g_client_id[];
-extern char g_num_variations[];
-extern char g_variation_chunks[];
 
 // Assume command line switches are less than 64 chars.
 static const size_t kSwitchLen = 64;
@@ -43,18 +28,11 @@
 // id in |client_id| if it's known, an empty string otherwise.
 std::string GetClientId();
 
-// Initialize the list of experiment info to send along with crash reports.
-void SetExperimentList(const std::vector<string16>& state);
-
-}  // namespace child_process_logging
-
 #if defined(OS_WIN)
-namespace child_process_logging {
-
 // Sets up the base/debug/crash_logging.h mechanism.
 void Init();
+#endif  // defined(OS_WIN)
 
 }  // namespace child_process_logging
-#endif  // defined(OS_WIN)
 
 #endif  // CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
diff --git a/chrome/common/child_process_logging_mac.mm b/chrome/common/child_process_logging_mac.mm
index 572fd52..5747945 100644
--- a/chrome/common/child_process_logging_mac.mm
+++ b/chrome/common/child_process_logging_mac.mm
@@ -7,9 +7,7 @@
 #import <Foundation/Foundation.h>
 
 #include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/common/metrics/variations/variations_util.h"
 #include "chrome/installer/util/google_update_settings.h"
 
 namespace child_process_logging {
@@ -45,31 +43,4 @@
   return std::string(g_client_id);
 }
 
-void SetExperimentList(const std::vector<string16>& experiments) {
-  // These should match the corresponding strings in breakpad_win.cc.
-  const char* kNumExperimentsKey = "num-experiments";
-  const char* kExperimentChunkFormat = "experiment-chunk-%zu";  // 1-based
-
-  std::vector<string16> chunks;
-  chrome_variations::GenerateVariationChunks(experiments, &chunks);
-
-  // Store up to |kMaxReportedVariationChunks| chunks.
-  for (size_t i = 0; i < kMaxReportedVariationChunks; ++i) {
-    std::string key = base::StringPrintf(kExperimentChunkFormat, i + 1);
-    if (i < chunks.size()) {
-      std::string value = UTF16ToUTF8(chunks[i]);
-      SetCrashKeyValue(key, value);
-    } else {
-      ClearCrashKey(key);
-    }
-  }
-
-  // Make note of the total number of experiments, which may be greater than
-  // what was able to fit in |kMaxReportedVariationChunks|. This is useful when
-  // correlating stability with the number of experiments running
-  // simultaneously.
-  SetCrashKeyValue(kNumExperimentsKey,
-                   base::StringPrintf("%zu", experiments.size()));
-}
-
 }  // namespace child_process_logging
diff --git a/chrome/common/child_process_logging_posix.cc b/chrome/common/child_process_logging_posix.cc
index 68f72d2..0ff249a 100644
--- a/chrome/common/child_process_logging_posix.cc
+++ b/chrome/common/child_process_logging_posix.cc
@@ -4,12 +4,8 @@
 
 #include "chrome/common/child_process_logging.h"
 
-#include "base/format_macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/common/metrics/variations/variations_util.h"
 #include "chrome/installer/util/google_update_settings.h"
 
 namespace child_process_logging {
@@ -22,13 +18,6 @@
 // these strings to the browser.
 char g_client_id[kClientIdSize];
 
-static const size_t kNumSize = 32;
-char g_num_variations[kNumSize] = "";
-
-static const size_t kMaxVariationChunksSize =
-    kMaxVariationChunkSize * kMaxReportedVariationChunks + 1;
-char g_variation_chunks[kMaxVariationChunksSize] = "";
-
 void SetClientId(const std::string& client_id) {
   std::string str(client_id);
   ReplaceSubstringsAfterOffset(&str, 0, "-", std::string());
@@ -45,28 +34,4 @@
   return std::string(g_client_id);
 }
 
-void SetExperimentList(const std::vector<string16>& experiments) {
-  std::vector<string16> chunks;
-  chrome_variations::GenerateVariationChunks(experiments, &chunks);
-
-  // Store up to |kMaxReportedVariationChunks| chunks.
-  std::string chunks_str;
-  const size_t number_of_chunks_to_report =
-      std::min(chunks.size(), kMaxReportedVariationChunks);
-  for (size_t i = 0; i < number_of_chunks_to_report; ++i) {
-    chunks_str += UTF16ToUTF8(chunks[i]);
-    // Align short chunks with spaces to be trimmed later.
-    chunks_str.resize(i * kMaxVariationChunkSize, ' ');
-  }
-  base::strlcpy(g_variation_chunks, chunks_str.c_str(),
-                arraysize(g_variation_chunks));
-
-  // Make note of the total number of experiments, which may be greater than
-  // what was able to fit in |kMaxReportedVariationChunks|. This is useful when
-  // correlating stability with the number of experiments running
-  // simultaneously.
-  snprintf(g_num_variations, arraysize(g_num_variations), "%" PRIuS,
-           experiments.size());
-}
-
 }  // namespace child_process_logging
diff --git a/chrome/common/child_process_logging_win.cc b/chrome/common/child_process_logging_win.cc
index 659096c..11a293e 100644
--- a/chrome/common/child_process_logging_win.cc
+++ b/chrome/common/child_process_logging_win.cc
@@ -6,12 +6,10 @@
 
 #include <windows.h>
 
-#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/crash_keys.h"
-#include "chrome/common/metrics/variations/variations_util.h"
 #include "chrome/installer/util/google_update_settings.h"
 
 namespace child_process_logging {
@@ -21,10 +19,6 @@
 // exported in breakpad_win.cc: void __declspec(dllexport) __cdecl SetClientId.
 typedef void (__cdecl *MainSetClientId)(const wchar_t*);
 
-// exported in breakpad_field_trial_win.cc:
-//   void __declspec(dllexport) __cdecl SetExperimentList3
-typedef void (__cdecl *MainSetExperimentList)(const wchar_t**, size_t, size_t);
-
 // exported in breakpad_win.cc:
 //    void __declspec(dllexport) __cdecl SetCrashKeyValueImpl.
 typedef void (__cdecl *SetCrashKeyValue)(const wchar_t*, const wchar_t*);
@@ -33,16 +27,6 @@
 //    void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl.
 typedef void (__cdecl *ClearCrashKeyValue)(const wchar_t*);
 
-
-// Copied from breakpad_win.cc.
-void StringVectorToCStringVector(const std::vector<std::wstring>& wstrings,
-                                 std::vector<const wchar_t*>* cstrings) {
-  cstrings->clear();
-  cstrings->reserve(wstrings.size());
-  for (size_t i = 0; i < wstrings.size(); ++i)
-    cstrings->push_back(wstrings[i].c_str());
-}
-
 }  // namespace
 
 void SetClientId(const std::string& client_id) {
@@ -81,34 +65,6 @@
     return std::string();
 }
 
-void SetExperimentList(const std::vector<string16>& experiments) {
-  static MainSetExperimentList set_experiment_list = NULL;
-  // note: benign race condition on set_experiment_list.
-  if (!set_experiment_list) {
-    HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
-    if (!exe_module)
-      return;
-    set_experiment_list = reinterpret_cast<MainSetExperimentList>(
-        GetProcAddress(exe_module, "SetExperimentList3"));
-    if (!set_experiment_list)
-      return;
-  }
-
-  std::vector<string16> chunks;
-  chrome_variations::GenerateVariationChunks(experiments, &chunks);
-
-  // If the list is empty, notify the child process of the number of experiments
-  // and exit early.
-  if (chunks.empty()) {
-    (set_experiment_list)(NULL, 0, 0);
-    return;
-  }
-
-  std::vector<const wchar_t*> cstrings;
-  StringVectorToCStringVector(chunks, &cstrings);
-  (set_experiment_list)(&cstrings[0], cstrings.size(), experiments.size());
-}
-
 namespace {
 
 void SetCrashKeyValueTrampoline(const base::StringPiece& key,
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 3cd880d..70aedeb 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -73,8 +73,6 @@
 const char kPnaclPluginMimeType[] = "application/x-pnacl";
 const char kPnaclPluginExtension[] = "";
 const char kPnaclPluginDescription[] = "Portable Native Client Executable";
-const uint32 kPnaclPluginPermissions = ppapi::PERMISSION_PRIVATE |
-                                       ppapi::PERMISSION_DEV;
 
 const char kO3DPluginName[] = "Google Talk Plugin Video Accelerator";
 const char kO3DPluginMimeType[] ="application/vnd.o3d.auto";
@@ -90,6 +88,13 @@
 const uint32 kO1DPluginPermissions = ppapi::PERMISSION_PRIVATE |
                                      ppapi::PERMISSION_DEV;
 
+const char kEffectsPluginName[] = "Google Talk Effects Plugin";
+const char kEffectsPluginMimeType[] ="application/x-ppapi-hangouts-effects";
+const char kEffectsPluginExtension[] = "";
+const char kEffectsPluginDescription[] = "Google Talk Effects Plugin";
+const uint32 kEffectsPluginPermissions = ppapi::PERMISSION_PRIVATE |
+                                         ppapi::PERMISSION_DEV;
+
 const char kGTalkPluginName[] = "Google Talk Plugin";
 const char kGTalkPluginMimeType[] ="application/googletalk";
 const char kGTalkPluginExtension[] = ".googletalk";
@@ -108,8 +113,6 @@
     "shared with you. To use this plugin you must first install the "
     "<a href=\"https://chrome.google.com/remotedesktop\">"
     "Chrome Remote Desktop</a> webapp.";
-const base::FilePath::CharType kRemotingViewerPluginPath[] =
-    FILE_PATH_LITERAL("internal-remoting-viewer");
 // Use a consistent MIME-type regardless of branding.
 const char kRemotingViewerPluginMimeType[] =
     "application/vnd.chromium.remoting-viewer";
@@ -227,6 +230,27 @@
     }
   }
 
+  // TODO(vrk): Remove this when NaCl effects plugin replaces the ppapi effects
+  // plugin.
+  static bool skip_effects_file_check = false;
+  if (PathService::Get(chrome::FILE_EFFECTS_PLUGIN, &path)) {
+    if (skip_effects_file_check || base::PathExists(path)) {
+      content::PepperPluginInfo effects;
+      effects.path = path;
+      effects.name = kEffectsPluginName;
+      effects.is_out_of_process = true;
+      effects.is_sandboxed = true;
+      effects.permissions = kEffectsPluginPermissions;
+      content::WebPluginMimeType effects_mime_type(kEffectsPluginMimeType,
+                                                   kEffectsPluginExtension,
+                                                   kEffectsPluginDescription);
+      effects.mime_types.push_back(effects_mime_type);
+      plugins->push_back(effects);
+
+      skip_effects_file_check = true;
+    }
+  }
+
   static bool skip_gtalk_file_check = false;
   if (PathService::Get(chrome::FILE_GTALK_PLUGIN, &path)) {
     if (skip_gtalk_file_check || base::PathExists(path)) {
@@ -278,7 +302,8 @@
   info.is_out_of_process = true;
   info.name = kRemotingViewerPluginName;
   info.description = kRemotingViewerPluginDescription;
-  info.path = base::FilePath(kRemotingViewerPluginPath);
+  info.path = base::FilePath(
+      chrome::ChromeContentClient::kRemotingViewerPluginPath);
   content::WebPluginMimeType remoting_mime_type(
       kRemotingViewerPluginMimeType,
       kRemotingViewerPluginMimeExtension,
diff --git a/chrome/common/chrome_content_client.h b/chrome/common/chrome_content_client.h
index 1ee71d2..53b7441 100644
--- a/chrome/common/chrome_content_client.h
+++ b/chrome/common/chrome_content_client.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/files/file_path.h"
 #include "content/public/common/content_client.h"
 
 namespace chrome {
@@ -18,6 +19,7 @@
   static const char* const kPDFPluginName;
   static const char* const kNaClPluginName;
   static const char* const kNaClOldPluginName;
+  static const base::FilePath::CharType kRemotingViewerPluginPath[];
 
   virtual void SetActiveURL(const GURL& url) OVERRIDE;
   virtual void SetGpuInfo(const gpu::GPUInfo& gpu_info) OVERRIDE;
diff --git a/chrome/common/chrome_content_client_constants.cc b/chrome/common/chrome_content_client_constants.cc
index aeea06f..1366572 100644
--- a/chrome/common/chrome_content_client_constants.cc
+++ b/chrome/common/chrome_content_client_constants.cc
@@ -9,5 +9,8 @@
 const char* const ChromeContentClient::kPDFPluginName = "Chrome PDF Viewer";
 const char* const ChromeContentClient::kNaClPluginName = "Native Client";
 const char* const ChromeContentClient::kNaClOldPluginName = "Chrome NaCl";
+const base::FilePath::CharType
+    ChromeContentClient::kRemotingViewerPluginPath[] =
+        FILE_PATH_LITERAL("internal-remoting-viewer");
 
 }  // namespace chrome
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 904fbef..4238481 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -66,6 +66,9 @@
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 
+const base::FilePath::CharType kEffectsPluginFileName[] =
+    FILE_PATH_LITERAL("pepper/libppeffects.so");
+
 const base::FilePath::CharType kO3DPluginFileName[] =
     FILE_PATH_LITERAL("pepper/libppo3dautoplugin.so");
 
@@ -330,6 +333,11 @@
         return false;
       cur = cur.Append(kO1DPluginFileName);
       break;
+    case chrome::FILE_EFFECTS_PLUGIN:
+      if (!PathService::Get(base::DIR_MODULE, &cur))
+        return false;
+      cur = cur.Append(kEffectsPluginFileName);
+      break;
     case chrome::FILE_GTALK_PLUGIN:
       if (!PathService::Get(base::DIR_MODULE, &cur))
         return false;
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 9d1b050..fe5f6f2 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -85,6 +85,7 @@
                                 // (subdir of DIR_PNACL_BASE).
   FILE_O3D_PLUGIN,              // Full path to the O3D Pepper plugin file.
   FILE_O1D_PLUGIN,              // Full path to the O1D Pepper plugin file.
+  FILE_EFFECTS_PLUGIN,          // Full path to the Effects Pepper plugin file.
   FILE_GTALK_PLUGIN,            // Full path to the GTalk Pepper plugin file.
   DIR_COMPONENT_WIDEVINE_CDM,   // Directory that contains component-updated
                                 // Widevine CDM files.
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 4693e36..2a6f133 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -577,6 +577,10 @@
 // If true devtools experimental settings are enabled.
 const char kEnableDevToolsExperiments[]     = "enable-devtools-experiments";
 
+// Enable device discovery notifications.
+const char kEnableDeviceDiscoveryNotifications[] =
+    "enable-device-discovery-notifications";
+
 // Force-enables DNS probes on main frame DNS errors.  (The user must still
 // opt in to "Use web service to resolve navigation errors".)
 const char kEnableDnsProbes[]               = "enable-dns-probes";
@@ -1130,8 +1134,10 @@
 //   prefetch_only: No prerendering, but enables prefetching.
 const char kPrerenderModeSwitchValuePrefetchOnly[] = "prefetch_only";
 
+#if defined(OS_WIN)
 // Enable conversion from vector to raster for any page.
 const char kPrintRaster[]                   = "print-raster";
+#endif
 
 // Use IPv6 only for privet HTTP.
 const char kPrivetIPv6Only[]                   = "privet-ipv6-only";
@@ -1447,6 +1453,9 @@
 // apps/origins.  This should be used only for testing purpose.
 const char kUnlimitedStorage[]              = "unlimited-storage";
 
+// Use the cacheable New Tab page for Embedded Search.
+const char kUseCacheableNewTabPage[]        = "use-cacheable-new-tab-page";
+
 // Uses Spdy for the transport protocol instead of HTTP. This is a temporary
 // testing flag.
 const char kUseSpdy[]                       = "use-spdy";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 2db9cb4..8015e3d 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -171,6 +171,7 @@
 extern const char kEnableComponentCloudPolicy[];
 extern const char kEnableContacts[];
 extern const char kEnableDevToolsExperiments[];
+extern const char kEnableDeviceDiscoveryNotifications[];
 extern const char kEnableDnsProbes[];
 extern const char kEnableDomDistiller[];
 extern const char kEnableExtensionActivityLogging[];
@@ -387,6 +388,7 @@
 extern const char kUninstallExtension[];
 extern const char kUninstall[];
 extern const char kUnlimitedStorage[];
+extern const char kUseCacheableNewTabPage[];
 extern const char kUseSimpleCacheBackend[];
 extern const char kUseSpdy[];
 extern const char kUseSpellingSuggestions[];
diff --git a/chrome/common/cloud_print/cloud_print_constants.cc b/chrome/common/cloud_print/cloud_print_constants.cc
index 4a82258..c1bad6b 100644
--- a/chrome/common/cloud_print/cloud_print_constants.cc
+++ b/chrome/common/cloud_print/cloud_print_constants.cc
@@ -20,6 +20,7 @@
 const char kPrinterStatusValue[] = "status";
 const char kPrinterTagValue[] = "tag";
 const char kPrinterRemoveTagValue[] = "remove_tag";
+const char kPrinterLocalSettingsValue[] = "local_settings";
 const char kMessageTextValue[] = "message";
 
 const char kPrintSystemFailedMessageId[] = "printsystemfail";
@@ -44,6 +45,10 @@
 const char kPrinterTypeValue[] = "type";
 const char kUserValue[] = "request.user";
 const char kUsersValue[] = "request.users";
+const char kLocalSettingsPendingXmppValue[] =
+    "local_settings.pending.xmpp_timeout_value";
+
+const char kNotificationUpdateSettings[] = "/update_settings";
 
 const char kChromeVersionTagName[] = "chrome_version";
 const char kSystemNameTagName[] = "system_name";
@@ -60,4 +65,9 @@
 const char kJobFetchReasonFailure[] = "failure";
 const char kJobFetchReasonRetry[] = "retry";
 
+const char kCreateLocalSettingsXmppPingFormat[] =
+    "{\"current\":{\"xmpp_timeout_value\": %d}}";
+const char kUpdateLocalSettingsXmppPingFormat[] =
+    "{\"current\":{\"xmpp_timeout_value\": %d},\"pending\":{}}";
+
 }  // namespace cloud_print
diff --git a/chrome/common/cloud_print/cloud_print_constants.h b/chrome/common/cloud_print/cloud_print_constants.h
index 71811d3..f6a4db7 100644
--- a/chrome/common/cloud_print/cloud_print_constants.h
+++ b/chrome/common/cloud_print/cloud_print_constants.h
@@ -28,6 +28,7 @@
 extern const char kPrinterStatusValue[];
 extern const char kPrinterTagValue[];
 extern const char kPrinterRemoveTagValue[];
+extern const char kPrinterLocalSettingsValue[];
 extern const char kMessageTextValue[];
 
 // Value of "code" parameter in cloud print "/message" requests.
@@ -54,6 +55,10 @@
 extern const char kPrinterTypeValue[];
 extern const char kUserValue[];
 extern const char kUsersValue[];
+extern const char kLocalSettingsPendingXmppValue[];
+
+// Value in XMPP notification.
+extern const char kNotificationUpdateSettings[];
 
 // Printer tag names. Don't need prefixes. They will be added on submit.
 extern const char kChromeVersionTagName[];
@@ -79,6 +84,10 @@
 // Job fetch due to scheduled retry.
 extern const char kJobFetchReasonRetry[];
 
+// Format of the local settings containing only XMPP ping.
+extern const char kCreateLocalSettingsXmppPingFormat[];
+extern const char kUpdateLocalSettingsXmppPingFormat[];
+
 // Max retry count for job data fetch requests.
 const int kJobDataMaxRetryCount = 1;
 // Max retry count (infinity) for API fetch requests.
@@ -95,8 +104,8 @@
 
 // When we have XMPP notifications available, we ping server to keep connection
 // alive or check connection status.
-const int kDefaultXmppPingTimeoutSecs = 5*60;  // 5 minutes in seconds
-const int kMinimumXmppPingTimeoutSecs = 2*60;  // 2 minutes in seconds
+const int kDefaultXmppPingTimeoutSecs = 5*60;
+const int kMinXmppPingTimeoutSecs = 1*60;
 const int kXmppPingCheckIntervalSecs = 60;
 
 // Number of failed pings before we try to reinstablish XMPP connection.
diff --git a/chrome/common/cloud_print/cloud_print_helpers.cc b/chrome/common/cloud_print/cloud_print_helpers.cc
index 1f308cf..41838e1 100644
--- a/chrome/common/cloud_print/cloud_print_helpers.cc
+++ b/chrome/common/cloud_print/cloud_print_helpers.cc
@@ -136,12 +136,14 @@
 
 GURL GetUrlForJobStatusUpdate(const GURL& cloud_print_server_url,
                               const std::string& job_id,
-                              const std::string& status_string) {
+                              const std::string& status_string,
+                              int connector_code) {
   std::string path(AppendPathToUrl(cloud_print_server_url, "control"));
   GURL::Replacements replacements;
   replacements.SetPathStr(path);
   std::string query = base::StringPrintf(
-      "jobid=%s&status=%s", job_id.c_str(), status_string.c_str());
+      "jobid=%s&status=%s&connector_code=%d", job_id.c_str(),
+      status_string.c_str(), connector_code);
   replacements.SetQueryStr(query);
   return cloud_print_server_url.ReplaceComponents(replacements);
 }
diff --git a/chrome/common/cloud_print/cloud_print_helpers.h b/chrome/common/cloud_print/cloud_print_helpers.h
index 23a9f8f..7b3b6f8 100644
--- a/chrome/common/cloud_print/cloud_print_helpers.h
+++ b/chrome/common/cloud_print/cloud_print_helpers.h
@@ -48,7 +48,8 @@
                         const std::string& job_id);
 GURL GetUrlForJobStatusUpdate(const GURL& cloud_print_server_url,
                               const std::string& job_id,
-                              const std::string& status_string);
+                              const std::string& status_string,
+                              int connector_code);
 GURL GetUrlForUserMessage(const GURL& cloud_print_server_url,
                           const std::string& message_id);
 GURL GetUrlForGetAuthCode(const GURL& cloud_print_server_url,
diff --git a/chrome/common/cloud_print/cloud_print_helpers_unittest.cc b/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
index 1fdd038..662ee58 100644
--- a/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
+++ b/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
@@ -52,10 +52,11 @@
                 expected_url_base.c_str()),
             GetUrlForJobDelete(server_base_url, "myprinter").spec());
 
-  EXPECT_EQ(base::StringPrintf("%scontrol?jobid=myprinter&status=s1",
+  EXPECT_EQ(base::StringPrintf(
+                "%scontrol?jobid=myprinter&status=s1&connector_code=0",
                 expected_url_base.c_str()),
             GetUrlForJobStatusUpdate(
-                server_base_url, "myprinter", "s1").spec());
+                server_base_url, "myprinter", "s1", 0).spec());
 
   EXPECT_EQ(base::StringPrintf("%smessage?code=testmsg",
                 expected_url_base.c_str()),
diff --git a/chrome/common/content_settings_types.h b/chrome/common/content_settings_types.h
index c1b03a5..cf091fe 100644
--- a/chrome/common/content_settings_types.h
+++ b/chrome/common/content_settings_types.h
@@ -32,6 +32,8 @@
   CONTENT_SETTINGS_TYPE_SAVE_PASSWORD,
 #if defined(OS_WIN)
   CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP,
+#elif defined(OS_ANDROID)
+  CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
 #endif
   CONTENT_SETTINGS_NUM_TYPES,
 };
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 583d533..65b1b90 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -58,6 +58,9 @@
 const char kSwitch[] = "switch-%" PRIuS;
 const char kNumSwitches[] = "num-switches";
 
+const char kNumVariations[] = "num-experiments";
+const char kVariations[] = "variations";
+
 const char kExtensionID[] = "extension-%" PRIuS;
 const char kNumExtensionsCount[] = "num-extensions";
 
@@ -108,6 +111,8 @@
     { kChannel, kSmallSize },
     { kActiveURL, kLargeSize },
     { kNumSwitches, kSmallSize },
+    { kNumVariations, kSmallSize },
+    { kVariations, kLargeSize },
     { kNumExtensionsCount, kSmallSize },
     { kNumberOfViews, kSmallSize },
 #if !defined(OS_ANDROID)
@@ -270,6 +275,25 @@
   }
 }
 
+void SetVariationsList(const std::vector<std::string>& variations) {
+  base::debug::SetCrashKeyValue(kNumVariations,
+      base::StringPrintf("%" PRIuS, variations.size()));
+
+  std::string variations_string;
+  variations_string.reserve(kLargeSize);
+
+  for (size_t i = 0; i < variations.size(); ++i) {
+    const std::string& variation = variations[i];
+    // Do not truncate an individual experiment.
+    if (variations_string.size() + variation.size() >= kLargeSize)
+      break;
+    variations_string += variation;
+    variations_string += ",";
+  }
+
+  base::debug::SetCrashKeyValue(kVariations, variations_string);
+}
+
 void SetActiveExtensions(const std::set<std::string>& extensions) {
   base::debug::SetCrashKeyValue(kNumExtensionsCount,
       base::StringPrintf("%" PRIuS, extensions.size()));
diff --git a/chrome/common/crash_keys.h b/chrome/common/crash_keys.h
index 23fda46..cc57868 100644
--- a/chrome/common/crash_keys.h
+++ b/chrome/common/crash_keys.h
@@ -7,6 +7,7 @@
 
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/debug/crash_logging.h"
 
@@ -21,6 +22,9 @@
 // Sets the kSwitch and kNumSwitches keys based on the given |command_line|.
 void SetSwitchesFromCommandLine(const CommandLine* command_line);
 
+// Sets the list of active experiment/variations info.
+void SetVariationsList(const std::vector<std::string>& variations);
+
 // Sets the list of "active" extensions in this process. We overload "active" to
 // mean different things depending on the process type:
 // - browser: all enabled extensions
@@ -56,6 +60,12 @@
 // |kSwitchesMaxCount| are present.
 extern const char kNumSwitches[];
 
+// The total number of experiments the instance has.
+extern const char kNumVariations[];
+// The experiments chunk. Hashed experiment names separated by |,|. This is
+// typically set by SetExperimentList.
+extern const char kVariations[];
+
 // Installed extensions. |kExtensionID| should be formatted with an integer,
 // in the range [0, kExtensionIDMaxCount).
 const size_t kExtensionIDMaxCount = 10;
diff --git a/chrome/common/encrypted_media_messages_android.cc b/chrome/common/encrypted_media_messages_android.cc
deleted file mode 100644
index 4ad9bb9..0000000
--- a/chrome/common/encrypted_media_messages_android.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/encrypted_media_messages_android.h"
-
-namespace android {
-
-SupportedKeySystemRequest::SupportedKeySystemRequest()
-    : codecs(NO_SUPPORTED_CODECS) {}
-
-SupportedKeySystemRequest::~SupportedKeySystemRequest() {}
-
-SupportedKeySystemResponse::SupportedKeySystemResponse()
-    : compositing_codecs(NO_SUPPORTED_CODECS),
-      non_compositing_codecs(NO_SUPPORTED_CODECS) {}
-
-SupportedKeySystemResponse::~SupportedKeySystemResponse() {}
-
-}  // namespace android
diff --git a/chrome/common/encrypted_media_messages_android.h b/chrome/common/encrypted_media_messages_android.h
index 39c0ddf..00a77d0 100644
--- a/chrome/common/encrypted_media_messages_android.h
+++ b/chrome/common/encrypted_media_messages_android.h
@@ -24,28 +24,6 @@
   MP4_AVC1 = 1 << 2,
 };
 
-struct SupportedKeySystemRequest {
-  SupportedKeySystemRequest();
-  ~SupportedKeySystemRequest();
-
-  // Key system UUID.
-  std::vector<uint8> uuid;
-  // Bitmask of requested codecs.
-  SupportedCodecs codecs;
-};
-
-struct SupportedKeySystemResponse {
-  SupportedKeySystemResponse();
-  ~SupportedKeySystemResponse();
-
-  // Key system UUID.
-  std::vector<uint8> uuid;
-  // Bitmask of supported compositing codecs.
-  SupportedCodecs compositing_codecs;
-  // Bitmask of supported non-compositing codecs.
-  SupportedCodecs non_compositing_codecs;
-};
-
 }  // namespace android
 
 #endif  // CHROME_COMMON_ENCRYPTED_MEDIA_MESSAGES_ANDROID_H
@@ -55,22 +33,24 @@
 
 IPC_ENUM_TRAITS(android::SupportedCodecs)
 
-IPC_STRUCT_TRAITS_BEGIN(android::SupportedKeySystemRequest)
-  IPC_STRUCT_TRAITS_MEMBER(uuid)
-  IPC_STRUCT_TRAITS_MEMBER(codecs)
-IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_BEGIN(SupportedKeySystemRequest)
+  IPC_STRUCT_MEMBER(std::vector<uint8>, uuid)
+  IPC_STRUCT_MEMBER(android::SupportedCodecs, codecs,
+                    android::NO_SUPPORTED_CODECS)
+IPC_STRUCT_END()
 
-IPC_STRUCT_TRAITS_BEGIN(android::SupportedKeySystemResponse)
-  IPC_STRUCT_TRAITS_MEMBER(uuid)
-  IPC_STRUCT_TRAITS_MEMBER(compositing_codecs)
-  IPC_STRUCT_TRAITS_MEMBER(non_compositing_codecs)
-IPC_STRUCT_TRAITS_END()
-
+IPC_STRUCT_BEGIN(SupportedKeySystemResponse)
+  IPC_STRUCT_MEMBER(std::vector<uint8>, uuid)
+  IPC_STRUCT_MEMBER(android::SupportedCodecs, compositing_codecs,
+                    android::NO_SUPPORTED_CODECS)
+  IPC_STRUCT_MEMBER(android::SupportedCodecs, non_compositing_codecs,
+                    android::NO_SUPPORTED_CODECS)
+IPC_STRUCT_END()
 
 // Messages sent from the renderer to the browser.
 
 // Synchronously get a list of supported EME key systems.
 IPC_SYNC_MESSAGE_CONTROL1_1(
     ChromeViewHostMsg_GetSupportedKeySystems,
-    android::SupportedKeySystemRequest /* key system information request */,
-    android::SupportedKeySystemResponse /* key system information response */)
+    SupportedKeySystemRequest /* key system information request */,
+    SupportedKeySystemResponse /* key system information response */)
diff --git a/chrome/common/extensions/OWNERS b/chrome/common/extensions/OWNERS
index a2ed46fd..db382d2 100644
--- a/chrome/common/extensions/OWNERS
+++ b/chrome/common/extensions/OWNERS
@@ -18,5 +18,4 @@
 per-file *_messages*.h=cevans@chromium.org
 per-file *_messages*.h=inferno@chromium.org
 per-file *_messages*.h=jschuh@chromium.org
-per-file *_messages*.h=palmer@chromium.org
 per-file *_messages*.h=tsepez@chromium.org
diff --git a/chrome/common/extensions/PRESUBMIT.py b/chrome/common/extensions/PRESUBMIT.py
index 7841212..2e138c9 100644
--- a/chrome/common/extensions/PRESUBMIT.py
+++ b/chrome/common/extensions/PRESUBMIT.py
@@ -144,7 +144,12 @@
                                     cwd=input_api.PresubmitLocalPath())
   except input_api.subprocess.CalledProcessError:
     results.append(output_api.PresubmitError('IntegrationTest failed!'))
-  _CheckLinks(input_api, output_api, results)
+
+  # TODO(kalman): Re-enable this check, or decide to delete it forever. Now
+  # that we have multiple directories it no longer works.
+  # See http://crbug.com/297178.
+  #_CheckLinks(input_api, output_api, results)
+
   return results
 
 def CheckChangeOnUpload(input_api, output_api):
diff --git a/chrome/common/extensions/api/PRESUBMIT.py b/chrome/common/extensions/api/PRESUBMIT.py
index 20d61fa..771f7fd 100644
--- a/chrome/common/extensions/api/PRESUBMIT.py
+++ b/chrome/common/extensions/api/PRESUBMIT.py
@@ -2,8 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-def _GetJSONParseError(input_api, contents):
+def _GetJSONParseError(input_api, filename):
   try:
+    contents = input_api.ReadFile(filename)
     json_comment_eater = input_api.os_path.join(
         input_api.PresubmitLocalPath(),
         '..', '..', '..', '..', 'tools',
@@ -11,7 +12,8 @@
     process = input_api.subprocess.Popen(
         [input_api.python_executable, json_comment_eater],
         stdin=input_api.subprocess.PIPE,
-        stdout=input_api.subprocess.PIPE)
+        stdout=input_api.subprocess.PIPE,
+        universal_newlines=True)
     (nommed, _) = process.communicate(input=contents)
     input_api.json.loads(nommed)
   except ValueError as e:
@@ -19,6 +21,20 @@
   return None
 
 
+def _GetIDLParseError(input_api, filename):
+  idl_schema = input_api.os_path.join(
+      input_api.PresubmitLocalPath(),
+      '..', '..', '..', '..', 'tools',
+      'json_schema_compiler', 'idl_schema.py')
+  process = input_api.subprocess.Popen(
+      [input_api.python_executable, idl_schema, filename],
+      stdout=input_api.subprocess.PIPE,
+      stderr=input_api.subprocess.PIPE,
+      universal_newlines=True)
+  (_, error) = process.communicate()
+  return error or None
+
+
 def _GetParseErrors(input_api, output_api):
   # Run unit tests.
   results = []
@@ -27,17 +43,24 @@
     results = input_api.canned_checks.RunUnitTestsInDirectory(
         input_api, output_api, '.', whitelist=[r'^PRESUBMIT_test\.py$'])
 
+  actions = {
+    '.idl': _GetIDLParseError,
+    '.json': _GetJSONParseError,
+  }
+
+  def get_action(affected_file):
+    filename = affected_file.LocalPath()
+    return actions.get(input_api.os_path.splitext(filename)[1])
+
   for affected_file in input_api.AffectedFiles(
-      file_filter=lambda f: f.LocalPath().endswith('.json'),
+      file_filter=
+          lambda f: "test_presubmit" not in f.LocalPath() and get_action(f),
       include_deletes=False):
-    filename = affected_file.AbsoluteLocalPath()
-    contents = input_api.ReadFile(filename)
-    parse_error = _GetJSONParseError(input_api, contents)
+    parse_error = get_action(affected_file)(input_api,
+                                            affected_file.AbsoluteLocalPath())
     if parse_error:
-      results.append(output_api.PresubmitError(
-          'Features file %s could not be parsed: %s' %
+      results.append(output_api.PresubmitError('%s could not be parsed: %s' %
           (affected_file.LocalPath(), parse_error)))
-    # TODO(yoz): Also ensure IDL files are parseable.
   return results
 
 
diff --git a/chrome/common/extensions/api/PRESUBMIT_test.py b/chrome/common/extensions/api/PRESUBMIT_test.py
index f14ea7e..88d28e6 100755
--- a/chrome/common/extensions/api/PRESUBMIT_test.py
+++ b/chrome/common/extensions/api/PRESUBMIT_test.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import glob
 import json
 import os
 import subprocess
@@ -22,40 +23,59 @@
   def PresubmitLocalPath(self):
     return os.path.dirname(__file__)
 
+  def ReadFile(self, filename, mode='rU'):
+    with open(filename, mode=mode) as f:
+      return f.read()
+
 
 class JSONParsingTest(unittest.TestCase):
   def testSuccess(self):
     input_api = MockInputApi()
-    input_json = '''
-// This is a comment.
-{
-  "key1": ["value1", "value2"],
-  "key2": 3  // This is an inline comment.
-}
-'''
+    filename = 'test_presubmit/valid_json.json'
     self.assertEqual(None,
-                     PRESUBMIT._GetJSONParseError(input_api, input_json))
+                     PRESUBMIT._GetJSONParseError(input_api, filename))
 
   def testFailure(self):
     input_api = MockInputApi()
-    input_json = '{ x }'
-    self.assertEqual('Expecting property name: line 1 column 2 (char 2)',
-                     str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
+    expected_errors = [
+      'Expecting property name: line 8 column 3 (char 9)',
+      'Invalid control character at: line 8 column 19 (char 25)',
+      'Expecting property name: line 8 column 23 (char 29)',
+      'Expecting , delimiter: line 8 column 12 (char 18)',
+    ]
+    actual_errors = [
+      str(PRESUBMIT._GetJSONParseError(input_api, filename))
+      for filename in sorted(glob.glob('test_presubmit/invalid_*.json'))
+    ]
+    self.assertEqual(expected_errors, actual_errors)
 
-    input_json = '{ "hello": "world }'
-    self.assertEqual(
-        'Unterminated string starting at: line 1 column 11 (char 11)',
-        str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
 
-    input_json = '{ "a": "b", "c": "d", }'
-    self.assertEqual(
-        'Expecting property name: line 1 column 22 (char 22)',
-        str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
+class IDLParsingTest(unittest.TestCase):
+  def testSuccess(self):
+    input_api = MockInputApi()
+    filename = 'test_presubmit/valid_idl_basics.idl'
+    self.assertEqual(None,
+                     PRESUBMIT._GetIDLParseError(input_api, filename))
 
-    input_json = '{ "a": "b" "c": "d" }'
-    self.assertEqual(
-        'Expecting , delimiter: line 1 column 11 (char 11)',
-        str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
+  def testFailure(self):
+    input_api = MockInputApi()
+    expected_errors = [
+      'Unexpected "{" after keyword "dictionary".',
+      'Unexpected symbol DOMString after symbol a.',
+      'Unexpected symbol name2 after symbol name1.',
+      'Trailing comma in block.',
+      'Unexpected ";" after "(".',
+      'Unexpected ")" after symbol long.',
+      'Unexpected symbol Events after symbol interace.',
+      'Did not process Interface Interface(NotEvent)',
+      'Interface missing name.',
+    ]
+    actual_errors = [
+      PRESUBMIT._GetIDLParseError(input_api, filename)
+      for filename in sorted(glob.glob('test_presubmit/invalid_*.idl'))
+    ]
+    for (expected_error, actual_error) in zip(expected_errors, actual_errors):
+      self.assertTrue(expected_error in actual_error)
 
 
 if __name__ == "__main__":
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index afe3be2..c2f64ec 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -233,7 +233,6 @@
     "contexts": ["blessed_extension", "unblessed_extension", "content_script"]
   },
   "feedbackPrivate": {
-    "platform": "chromeos",
     "dependencies": ["permission:feedbackPrivate"],
     "contexts": ["blessed_extension"]
   },
@@ -482,7 +481,7 @@
     "contexts": ["blessed_extension"]
   },
   "sockets.udp": {
-    "dependencies": ["permission:sockets.udp"],
+    "dependencies": ["manifest:sockets"],
     "channel": "dev",
     "contexts": ["blessed_extension"]
   },
@@ -595,6 +594,10 @@
     "channel": "stable",
     "contexts": ["blessed_extension", "unblessed_extension", "content_script"]
   },
+  "webrtcLoggingPrivate": {
+    "dependencies": ["permission:webrtcLoggingPrivate"],
+    "contexts": ["blessed_extension"]
+  },
   "webstore": {
     // Hosted apps can use the webstore API from within a blessed context.
     "channel": "stable",
diff --git a/chrome/common/extensions/api/_manifest_features.json b/chrome/common/extensions/api/_manifest_features.json
index 81a8427..605560e 100644
--- a/chrome/common/extensions/api/_manifest_features.json
+++ b/chrome/common/extensions/api/_manifest_features.json
@@ -204,6 +204,12 @@
       "platform_app"
     ]
   },
+  "kiosk_only": {
+    "channel": "dev",
+    "extension_types": [
+      "platform_app"
+    ]
+  },
   "manifest_version": {
     "channel": "stable",
     "extension_types": "all"
@@ -331,6 +337,10 @@
     "channel": "stable",
     "extension_types": "all"
   },
+  "sockets": {
+    "channel": "dev",
+    "extension_types": ["platform_app"]
+  },
   "spellcheck": {
     "channel": "dev",
     "extension_types": ["extension"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 6dd7b28..c39821c 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -125,6 +125,8 @@
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app", "platform_app"],
     "whitelist": [
+      "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/293683
+      "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/293683
       "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578",  // http://crbug.com/234235
       "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB"   // http://crbug.com/234235
     ]
@@ -184,7 +186,7 @@
     "extension_types": ["extension", "legacy_packaged_app"]
   },
   "developerPrivate": {
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["platform_app"],
     "whitelist": [
         "ohmmkhmmmpcnpikjeljgnaoabkaalbgc", // Published Apps developer tool.
@@ -242,15 +244,15 @@
     }
   ],
   "downloads": {
-    "channel": "beta",
+    "channel": "stable",
     "extension_types": ["extension"]
   },
   "downloads.open": {
-    "channel": "beta",
+    "channel": "stable",
     "extension_types": ["extension"]
   },
   "downloads.shelf": {
-    "channel": "beta",
+    "channel": "stable",
     "extension_types": ["extension"]
   },
   "dial": {
@@ -283,6 +285,8 @@
     "extension_types": ["extension", "platform_app"],
     "whitelist": [
       "7910EAFDAF64B947E1CB31B333A9BD14CA556B6C",  // Feedback UI.
+      "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/293683
+      "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/293683
       "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578",  // http://crbug.com/234235
       "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB"   // http://crbug.com/234235
     ]
@@ -305,11 +309,11 @@
     "whitelist": [ "2FC374607C2DF285634B67C64A2E356C607091C3" ]
   }],
   "fileSystem.directory": [{
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["platform_app"]
   }],
   "fileSystem.retainEntries": [{
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["platform_app"]
   }],
   "fileSystem.write": [{
@@ -415,7 +419,8 @@
           "lphgohfeebnhcpiohjndkgbhhkoapkjc",  // Apps Developer tool.
           "gonnpeheodhmhdjiimoiheniambmdcco",  // Apps Editor old.
           "cbelnpbjogfbjamhpbofhlnklecjpido",  // Apps Editor published.
-          "abjoigjokfeibfhiahiijggogladbmfm"   // Activity Log (Watchdog).
+          "abjoigjokfeibfhiahiijggogladbmfm",  // Watchdog (Activity Log)
+          "hhcnncjlpehbepkbgccanfpkneoejnpb"  // Watchdog Test Version
       ]
     }
   ],
@@ -573,12 +578,11 @@
     "extension_types": ["extension", "platform_app"]
   },
   "imageWriterPrivate": {
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["platform_app"],
     "whitelist": [
-      "nmedaodmkamdcnmfceajookiaicfnkhd", // ImageWriter API Dev App
-      "jdnamgpmgjhphalijaakigbpccepfllk", // Chrome OS Recovery Tool local
-      "jobolcahaebjkjhdedcfcnfkgpjcmkcg" // Chrome OS Recovery Tool CWS
+      "jobolcahaebjkjhdedcfcnfkgpjcmkcg", // Dev version
+      "D7986543275120831B39EF28D1327552FC343960"  // Release version
     ]
   },
   "rtcPrivate": {
@@ -750,12 +754,18 @@
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app"]
   },
+  "webrtcLoggingPrivate": {
+    "channel": "dev",
+    "extension_types": ["extension"],
+    "whitelist": ["80B9DC58E5210749F052F5B4DB239C50CF72AEB6"]
+  },
   "webstorePrivate": {
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app"],
     "whitelist": [
       "ahfgeienlihckogmohjhadlkjgocpleb",  // Web Store
-      "afchcafgojfnemjkcbhfekplkmjaldaa"   // Enterprise Web Store
+      "afchcafgojfnemjkcbhfekplkmjaldaa",  // Enterprise Web Store
+      "dofmkfphhdaddeofjngcjphcegkbbooh"   // Chrome Login Proxy (prototype)
     ]
   },
   "webRequest": {
@@ -766,8 +776,18 @@
     "channel": "stable",
     "extension_types": ["extension", "legacy_packaged_app"]
   },
-  "webview": {
+  "webview": [{
     "channel": "stable",
     "extension_types": ["platform_app"]
-  }
+  }, {
+    // General support for webview in component extensions still in progress.
+    // Only allowed for whitelisted extensions until all the caveats are
+    // addressed. Tracked in crbug/285151.
+    "channel": "stable",
+    "extension_types": ["extension"],
+    "location": "component",
+    "whitelist": [
+      "mfffpogegjflfpflabcdkioaeobkgjik"  // GAIA Component Extension
+    ]
+  }]
 }
diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp
index b868bbd..48b4ae8 100644
--- a/chrome/common/extensions/api/api.gyp
+++ b/chrome/common/extensions/api/api.gyp
@@ -87,7 +87,6 @@
           'power.idl',
           'push_messaging.idl',
           'image_writer_private.idl',
-          'rtc_private.idl',
           'runtime.json',
           'serial.idl',
           'sessions.json',
@@ -107,10 +106,12 @@
           'test.json',
           'top_sites.json',
           'usb.idl',
+          'virtual_keyboard_private.json',
           'wallpaper.json',
           'wallpaper_private.json',
           'web_navigation.json',
           'web_request.json',
+          'webrtc_logging_private.idl',
           'webstore_private.json',
           'webview.json',
           'windows.json',
@@ -154,7 +155,6 @@
             'music_manager_private.idl',
             'networking_private.json',
             'power.idl',
-            'rtc_private.idl',
             'system_indicator.idl',
             'system_private.json',
             'terminal_private.json',
@@ -167,7 +167,14 @@
           'schema_files!': [
             'file_browser_handler_internal.json',
             'log_private.idl',
-            'rtc_private.idl',
+            'virtual_keyboard_private.json',
+            'wallpaper.json',
+            'wallpaper_private.json',
+          ],
+        }],
+        ['enable_webrtc==0', {
+          'schema_files!': [
+            'webrtc_logging_private.idl',
           ],
         }],
       ],
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index 027268e..e33fa17 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -42,6 +42,9 @@
     // Get login status.
     static void loginStatus(LoginStatusCallback callback);
 
+    // Locks the screen.
+    static void lockScreen();
+
     // Simulates a memory access bug for asan testing.
     static void simulateAsanMemoryBug();
   };
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index ca3ffeb..a609ac8 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -260,8 +260,6 @@
   RegisterSchemaResource("tts", IDR_EXTENSION_API_JSON_TTS);
   RegisterSchemaResource("types", IDR_EXTENSION_API_JSON_TYPES);
   RegisterSchemaResource("types.private", IDR_EXTENSION_API_JSON_TYPES_PRIVATE);
-  RegisterSchemaResource("virtualKeyboardPrivate",
-      IDR_EXTENSION_API_JSON_VIRTUALKEYBOARDPRIVATE);
   RegisterSchemaResource("webRequestInternal",
       IDR_EXTENSION_API_JSON_WEBREQUESTINTERNAL);
   RegisterSchemaResource("webstore", IDR_EXTENSION_API_JSON_WEBSTORE);
diff --git a/chrome/common/extensions/api/feedback_private.idl b/chrome/common/extensions/api/feedback_private.idl
index 5641caa..93f799c 100644
--- a/chrome/common/extensions/api/feedback_private.idl
+++ b/chrome/common/extensions/api/feedback_private.idl
@@ -48,9 +48,9 @@
     SystemInformation[]? systemInformation;
 
     // TODO(rkc): Remove these once we have bindings to send blobs to Chrome.
-    // Used internally to store the blob Url after parameter customization.
-    DOMString? attachedFileBlobUrl;
-    DOMString? screenshotBlobUrl;
+    // Used internally to store the blob uuid after parameter customization.
+    DOMString? attachedFileBlobUuid;
+    DOMString? screenshotBlobUuid;
   };
 
   // Status of the sending of a feedback report.
diff --git a/chrome/common/extensions/api/file_browser_private.json b/chrome/common/extensions/api/file_browser_private.json
index 7300335..8d65788 100644
--- a/chrome/common/extensions/api/file_browser_private.json
+++ b/chrome/common/extensions/api/file_browser_private.json
@@ -264,14 +264,19 @@
         "properties": {
           "type": {
             "type": "string",
-            "enum": ["begin_entry_copy", "end_entry_copy", "progress", "success", "error"],
-            "description": "The type of the progress event. \"begin_entry_copy\" is fired for each entry (file or directory) before starting the copy operation, \"end_entry_copy\" is fired for each entry (file or directory) after ending the copy operation. \"progress\" is fired periodically to report progress of a file copy (not directory). \"success\" is fired after all entries are copied. \"error\" is fired when an error occurs."
+            "enum": ["begin_copy_entry", "end_copy_entry", "progress", "success", "error"],
+            "description": "The type of the progress event. \"begin_copy_entry\" is fired for each entry (file or directory) before starting the copy operation, \"end_copy_entry\" is fired for each entry (file or directory) after ending the copy operation. \"progress\" is fired periodically to report progress of a file copy (not directory). \"success\" is fired after all entries are copied. \"error\" is fired when an error occurs."
           },
-          "url": {
+          "sourceUrl": {
             "type": "string",
             "optional": true,
             "description": "URL for the entry currently being copied. This field is particularly useful when a directory copy is initiated with startCopy(). The field tells what file/directory in that directory is now being copied."
           },
+          "destinationUrl": {
+            "type": "string",
+            "optional": true,
+            "description": "URL for the entry currently being created. This field is particularly useful when a directory copy is initiated with startCopy(). The field tells what file/directory in that directory is being created. Available only for end_copy_entry and success."
+          },
           "size": {
             "type": "number",
             "optional": true,
@@ -899,12 +904,10 @@
             "properties": {
               "query": {
                 "type": "string",
-                "optional": true,
                 "description": "Search query."
               },
               "nextFeed": {
                 "type": "string",
-                "optional": true,
                 "description": "ID of the search feed that should be fetched next. Value passed here should be gotten from previous searchDrive call. It can be empty for the initial search request."
               }
             }
@@ -943,18 +946,15 @@
             "properties": {
               "query": {
                 "type": "string",
-                "optional": true,
                 "description": "Search query. It can be empty. Any filename matches to an empty query."
               },
               "types": {
                 "type": "string",
                 "enum": ["EXCLUDE_DIRECTORIES", "SHARED_WITH_ME", "OFFLINE", "ALL"],
-                "optional": true,
                 "description": "The type of entry that is needed. Default to ALL."
               },
               "maxResults": {
                 "type": "integer",
-                "optional": true,
                 "description": "Maximum number of results."
               }
             }
@@ -1199,29 +1199,29 @@
       // Suppose a/b/c.txt (100bytes) and a/b/d.txt (200bytes), and trying to
       // copy a to x recursively. The events will be:
       //
-      // begin_entry_copy a
+      // begin_copy_entry "a"
       // <create empty directory x/a>
-      // end_entry_copy a
+      // end_copy_entry "a" "x/a"
       //
-      // begin_entry_copy a/b
+      // begin_copy_entry "a/b"
       // <create empty directory x/a/b>
-      // end_entry_copy a/b
+      // end_copy_entry "a/b" "x/a/b"
       //
-      // begin_entry_copy a/b/c.txt
-      // progress a/b/c.txt 0
-      // progress a/b/c.txt 10
+      // begin_copy_entry "a/b/c.txt"
+      // progress "a/b/c.txt" 0
+      // progress "a/b/c.txt" 10
       //     :
-      // progress a/b/c.txt 100
-      // end_entry_copy a/b/c.txt
+      // progress "a/b/c.txt" 100
+      // end_copy_entry "a/b/c.txt" "x/a/b/c.txt"
       //
-      // begin_entry_copy a/b/d.txt
-      // progress a/b/d.txt 0
-      // progress a/b/d.txt 10
+      // begin_copy_entry "a/b/d.txt"
+      // progress "a/b/d.txt" 0
+      // progress "a/b/d.txt" 10
       //     :
-      // progress a/b/d.txt 200
-      // end_entry_copy a/b/d.txt
+      // progress "a/b/d.txt" 200
+      // end_copy_entry "a/b/d.txt" "x/a/b/d.txt"
       //
-      // success x/a
+      // success "a" "x/a"
       {
         "name": "onCopyProgress",
         "type": "function",
diff --git a/chrome/common/extensions/api/file_system.idl b/chrome/common/extensions/api/file_system.idl
index 7e3d6d6..0d82c92 100644
--- a/chrome/common/extensions/api/file_system.idl
+++ b/chrome/common/extensions/api/file_system.idl
@@ -116,10 +116,10 @@
     // Returns an id that can be passed to restoreEntry to regain access to a
     // given file entry. Only the 500 most recently used entries are retained,
     // where calls to retainEntry and restoreEntry count as use. If the app has
-    // the 'retainEntries' permission under 'fileSystem' (currently restricted
-    // to dev channel), entries are retained indefinitely. Otherwise, entries
-    // are retained only while the app is running and across restarts. This
-    // method is new in Chrome 30.
+    // the 'retainEntries' permission under 'fileSystem' (new in Chrome 31),
+    // entries are retained indefinitely. Otherwise, entries are retained only
+    // while the app is running and across restarts. This method is new in
+    // Chrome 30.
     static DOMString retainEntry([instanceOf=Entry] object entry);
   };
 };
diff --git a/chrome/common/extensions/api/identity.idl b/chrome/common/extensions/api/identity.idl
index 6771794..cba84e4 100644
--- a/chrome/common/extensions/api/identity.idl
+++ b/chrome/common/extensions/api/identity.idl
@@ -10,7 +10,7 @@
     // approve the application's requested scopes. If the interactive
     // flag is <code>true</code>, <code>getAuthToken</code> will
     // prompt the user as necessary. When the flag is
-    // <code>false</code> or ommitted, <code>getAuthToken</code> will
+    // <code>false</code> or omitted, <code>getAuthToken</code> will
     // return failure any time a prompt would be required.
     boolean? interactive;
   };
@@ -33,7 +33,7 @@
     //
     // If the interactive flag is <code>true</code>, the window will
     // be displayed when a page load completes. If the flag is
-    // <code>false</code> or ommitted, <code>launchWebAuthFlow</code>
+    // <code>false</code> or omitted, <code>launchWebAuthFlow</code>
     // will return with an error if the initial navigation does not
     // complete the flow.
     boolean? interactive;
diff --git a/chrome/common/extensions/api/input_ime/input_components_handler.cc b/chrome/common/extensions/api/input_ime/input_components_handler.cc
index c6b1a33..b6376d6 100644
--- a/chrome/common/extensions/api/input_ime/input_components_handler.cc
+++ b/chrome/common/extensions/api/input_ime/input_components_handler.cc
@@ -199,6 +199,11 @@
   return true;
 }
 
+const std::vector<std::string>
+InputComponentsHandler::PrerequisiteKeys() const {
+  return SingleKey(keys::kOptionsPage);
+}
+
 const std::vector<std::string> InputComponentsHandler::Keys() const {
   return SingleKey(keys::kInputComponents);
 }
diff --git a/chrome/common/extensions/api/input_ime/input_components_handler.h b/chrome/common/extensions/api/input_ime/input_components_handler.h
index 1261ae2..977e56b 100644
--- a/chrome/common/extensions/api/input_ime/input_components_handler.h
+++ b/chrome/common/extensions/api/input_ime/input_components_handler.h
@@ -61,6 +61,9 @@
 
   virtual bool Parse(Extension* extension, string16* error) OVERRIDE;
 
+  // Requires kOptionsPage is already parsed.
+  virtual const std::vector<std::string> PrerequisiteKeys() const OVERRIDE;
+
  private:
   virtual const std::vector<std::string> Keys() const OVERRIDE;
 
diff --git a/chrome/common/extensions/api/manifest_types.json b/chrome/common/extensions/api/manifest_types.json
index e14ed37..1658cf6 100644
--- a/chrome/common/extensions/api/manifest_types.json
+++ b/chrome/common/extensions/api/manifest_types.json
@@ -32,6 +32,35 @@
             "items": {"type": "string"}
           }
         }
+      },
+      {
+        "id": "sockets",
+        "type": "object",
+        "description": "The <code>sockets</code> manifest property declares which sockets operations an app can issue.",
+        "properties": {
+          "udp": {
+            "description": "The <code>udp</code> manifest property declares which sockets.udp operations an app can issue.",
+            "optional": true,
+            "type": "object",
+            "properties": {
+              "bind": {
+                "description": "<p>The host:port pattern for <code>bind</code> operations.</p>",
+                "optional": true,
+                "type": "string"
+              },
+              "send": {
+                "description": "<p>The host:port pattern for <code>send</code> operations.</p>",
+                "optional": true,
+                "type": "string"
+              },
+              "multicastMembership": {
+                "description": "<p>The host:port pattern for <code>joinGroup</code> operations.</p>",
+                "optional": true,
+                "type": "string"
+              }
+            }
+          }
+        }
       }
     ]
   }
diff --git a/chrome/common/extensions/api/rtc_private.idl b/chrome/common/extensions/api/rtc_private.idl
deleted file mode 100644
index 73e26af..0000000
--- a/chrome/common/extensions/api/rtc_private.idl
+++ /dev/null
@@ -1,30 +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.
-
-// rtcPrivate.
-namespace rtcPrivate {
-  // Launch action type.
-  enum ActionType {chat, voice, video};
-
-  dictionary LaunchIntent {
-    // Launch action.
-    ActionType action;
-
-    // Launch data payload.
-    object data;
-
-    // MIME type.
-    DOMString type;
-  };
-
-  dictionary LaunchData {
-    // Launch intent.
-    LaunchIntent intent;
-  };
-
-  interface Events {
-    // Fired when an RTC launch event is raised.
-    static void onLaunch(optional LaunchData data);
-  };
-};
diff --git a/chrome/common/extensions/api/signed_in_devices.idl b/chrome/common/extensions/api/signed_in_devices.idl
index 15a421a..6a56ee3 100644
--- a/chrome/common/extensions/api/signed_in_devices.idl
+++ b/chrome/common/extensions/api/signed_in_devices.idl
@@ -60,6 +60,6 @@
     // change or a new device is added or a device removed.
     // |callback|: The callback to be invoked with the array of DeviceInfo
     // objects.
-    static void onDeviceInfoChange(DeviceInfoCallback callback);
+    static void onDeviceInfoChange(DeviceInfo[] devices);
   };
 };
\ No newline at end of file
diff --git a/chrome/common/extensions/api/sockets/sockets_handler.cc b/chrome/common/extensions/api/sockets/sockets_handler.cc
new file mode 100644
index 0000000..a367239
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_handler.cc
@@ -0,0 +1,139 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/api/sockets/sockets_handler.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/extensions/api/manifest_types.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/permissions/api_permission_set.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
+#include "chrome/common/extensions/permissions/socket_permission_data.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace sockets_errors {
+const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'";
+}
+
+namespace keys = extensions::manifest_keys;
+namespace errors = sockets_errors;
+using api::manifest_types::Sockets;
+
+SocketsHandler::SocketsHandler() {}
+
+SocketsHandler::~SocketsHandler() {}
+
+bool SocketsHandler::Parse(Extension* extension, string16* error) {
+  const base::Value* sockets = NULL;
+  CHECK(extension->manifest()->Get(keys::kSockets, &sockets));
+  std::vector<InstallWarning> install_warnings;
+  scoped_ptr<SocketsManifestData> data =
+      SocketsManifestData::FromValue(*sockets,
+                                     &install_warnings,
+                                     error);
+  if (!data)
+    return false;
+
+  extension->AddInstallWarnings(install_warnings);
+  extension->SetManifestData(keys::kSockets, data.release());
+  return true;
+}
+
+const std::vector<std::string> SocketsHandler::Keys() const {
+  return SingleKey(manifest_keys::kSockets);
+}
+
+SocketsManifestData::SocketsManifestData() {}
+SocketsManifestData::~SocketsManifestData() {}
+
+// static
+SocketsManifestData* SocketsManifestData::Get(const Extension* extension) {
+  return static_cast<SocketsManifestData*>(
+      extension->GetManifestData(keys::kSockets));
+}
+
+// static
+bool SocketsManifestData::CheckRequest(
+    const Extension* extension,
+    const content::SocketPermissionRequest& request) {
+  SocketsManifestData* data = SocketsManifestData::Get(extension);
+  if (data == NULL)
+    return false;
+
+  return data->CheckRequestImpl(extension, request);
+}
+
+// static
+scoped_ptr<SocketsManifestData> SocketsManifestData::FromValue(
+    const base::Value& value,
+    std::vector<InstallWarning>* install_warnings,
+    string16* error) {
+  scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error);
+  if (!sockets)
+    return scoped_ptr<SocketsManifestData>();
+
+  scoped_ptr<SocketsManifestData> result(new SocketsManifestData());
+  if (sockets->udp) {
+    if (!ParseHostPattern(result.get(),
+        content::SocketPermissionRequest::UDP_BIND,
+        sockets->udp->bind,
+        error)) {
+      return scoped_ptr<SocketsManifestData>();
+    }
+    if (!ParseHostPattern(result.get(),
+        content::SocketPermissionRequest::UDP_SEND_TO,
+        sockets->udp->send,
+        error)) {
+      return scoped_ptr<SocketsManifestData>();
+    }
+    if (!ParseHostPattern(result.get(),
+        content::SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
+        sockets->udp->multicast_membership,
+        error)) {
+      return scoped_ptr<SocketsManifestData>();
+    }
+  }
+  return result.Pass();
+}
+
+// static
+bool SocketsManifestData::ParseHostPattern(
+    SocketsManifestData* manifest_data,
+    content::SocketPermissionRequest::OperationType operation_type,
+    const scoped_ptr<std::string>& value,
+    string16* error) {
+  if (value) {
+    SocketPermissionEntry entry;
+    if (!SocketPermissionEntry::ParseHostPattern(
+          operation_type, *value, &entry)) {
+      *error = ErrorUtils::FormatErrorMessageUTF16(
+          errors::kErrorInvalidHostPattern, *value);
+      return false;
+    }
+    manifest_data->AddPermission(entry);
+  }
+  return true;
+}
+
+void SocketsManifestData::AddPermission(const SocketPermissionEntry& entry) {
+  permissions_.insert(entry);
+}
+
+bool SocketsManifestData::CheckRequestImpl(
+    const Extension* extension,
+    const content::SocketPermissionRequest& request) {
+  for (PermissionSet::const_iterator it = permissions_.begin();
+       it != permissions_.end(); ++it) {
+    if (it->Check(request))
+      return true;
+  }
+  return false;
+}
+
+}  // namespace extensions
diff --git a/chrome/common/extensions/api/sockets/sockets_handler.h b/chrome/common/extensions/api/sockets/sockets_handler.h
new file mode 100644
index 0000000..ff280d1
--- /dev/null
+++ b/chrome/common/extensions/api/sockets/sockets_handler.h
@@ -0,0 +1,68 @@
+// Copyright 2013 The Chromium Authors. 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_API_SOCKETS_SOCKETS_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_HANDLER_H_
+
+#include "base/strings/string16.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest_handler.h"
+#include "chrome/common/extensions/permissions/socket_permission_data.h"
+
+namespace extensions {
+
+// Parses the "sockets" manifest key.
+class SocketsHandler : public ManifestHandler {
+ public:
+  SocketsHandler();
+  virtual ~SocketsHandler();
+
+  virtual bool Parse(Extension* extension, string16* error) OVERRIDE;
+
+ private:
+  virtual const std::vector<std::string> Keys() const OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(SocketsHandler);
+};
+
+// The parsed form of the "sockets" manifest entry.
+class SocketsManifestData : public Extension::ManifestData {
+ public:
+  SocketsManifestData();
+  virtual ~SocketsManifestData();
+
+  // Gets the ExternallyConnectableInfo for |extension|, or NULL if none was
+  // specified.
+  static SocketsManifestData* Get(const Extension* extension);
+
+  static bool CheckRequest(const Extension* extension,
+                           const content::SocketPermissionRequest& request);
+
+  // Tries to construct the info based on |value|, as it would have appeared in
+  // the manifest. Sets |error| and returns an empty scoped_ptr on failure.
+  static scoped_ptr<SocketsManifestData> FromValue(
+      const base::Value& value,
+      std::vector<InstallWarning>* install_warnings,
+      string16* error);
+
+ private:
+  typedef std::set<SocketPermissionEntry> PermissionSet;
+
+  static bool ParseHostPattern(
+      SocketsManifestData* manifest_data,
+      content::SocketPermissionRequest::OperationType operation_type,
+      const scoped_ptr<std::string>& value,
+      string16* error);
+
+  void AddPermission(const SocketPermissionEntry& entry);
+
+  bool CheckRequestImpl(const Extension* extension,
+                        const content::SocketPermissionRequest& request);
+
+  PermissionSet permissions_;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_COMMON_EXTENSIONS_API_SOCKETS_SOCKETS_HANDLER_H_
diff --git a/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc b/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc
index 28c8557..d95a967 100644
--- a/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc
+++ b/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc
@@ -15,7 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
-#include "components/policy/core/common/policy_schema.h"
+#include "components/policy/core/common/schema.h"
 #include "extensions/common/install_warning.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
@@ -29,13 +29,13 @@
 StorageSchemaManifestHandler::~StorageSchemaManifestHandler() {}
 
 // static
-scoped_ptr<policy::PolicySchema> StorageSchemaManifestHandler::GetSchema(
+scoped_ptr<policy::SchemaOwner> StorageSchemaManifestHandler::GetSchema(
     const Extension* extension,
     std::string* error) {
   if (!extension->HasAPIPermission(APIPermission::kStorage)) {
     *error = base::StringPrintf("The storage permission is required to use %s",
                                 kStorageManagedSchema);
-    return scoped_ptr<policy::PolicySchema>();
+    return scoped_ptr<policy::SchemaOwner>();
   }
   std::string path;
   extension->manifest()->GetString(kStorageManagedSchema, &path);
@@ -43,20 +43,20 @@
   if (file.IsAbsolute() || file.ReferencesParent()) {
     *error = base::StringPrintf("%s must be a relative path without ..",
                                 kStorageManagedSchema);
-    return scoped_ptr<policy::PolicySchema>();
+    return scoped_ptr<policy::SchemaOwner>();
   }
   file = extension->path().AppendASCII(path);
   if (!base::PathExists(file)) {
     *error =
         base::StringPrintf("File does not exist: %s", file.value().c_str());
-    return scoped_ptr<policy::PolicySchema>();
+    return scoped_ptr<policy::SchemaOwner>();
   }
   std::string content;
   if (!base::ReadFileToString(file, &content)) {
     *error = base::StringPrintf("Can't read %s", file.value().c_str());
-    return scoped_ptr<policy::PolicySchema>();
+    return scoped_ptr<policy::SchemaOwner>();
   }
-  return policy::PolicySchema::Parse(content, error);
+  return policy::SchemaOwner::Parse(content, error);
 }
 
 bool StorageSchemaManifestHandler::Parse(Extension* extension,
diff --git a/chrome/common/extensions/api/storage/storage_schema_manifest_handler.h b/chrome/common/extensions/api/storage/storage_schema_manifest_handler.h
index c988362..d2406d6 100644
--- a/chrome/common/extensions/api/storage/storage_schema_manifest_handler.h
+++ b/chrome/common/extensions/api/storage/storage_schema_manifest_handler.h
@@ -9,7 +9,7 @@
 #include "chrome/common/extensions/manifest_handler.h"
 
 namespace policy {
-class PolicySchema;
+class SchemaOwner;
 }
 
 namespace extensions {
@@ -24,8 +24,8 @@
   // If the schema is invalid then NULL is returned, and the failure reason
   // is stored in |error|.
   // This function does file I/O and must be called on a thread that allows I/O.
-  static scoped_ptr<policy::PolicySchema> GetSchema(const Extension* extension,
-                                                    std::string* error);
+  static scoped_ptr<policy::SchemaOwner> GetSchema(const Extension* extension,
+                                                   std::string* error);
 
  private:
   // ManifestHandler implementation:
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_1.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_1.idl
new file mode 100644
index 0000000..32a048e
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_1.idl
@@ -0,0 +1,12 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Unexpected "{" after keyword "dictionary".
+  dictionary {
+    DOMString s;
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_2.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_2.idl
new file mode 100644
index 0000000..72996ed
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_2.idl
@@ -0,0 +1,13 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Unexpected symbol DOMString after symbol a.
+  dictionary MissingSemicolon {
+    DOMString a
+    DOMString b;
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_3.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_3.idl
new file mode 100644
index 0000000..e70e095
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_3.idl
@@ -0,0 +1,13 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Unexpected symbol name2 after symbol name1.
+  enum MissingComma {
+    name1
+    name2
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_4.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_4.idl
new file mode 100644
index 0000000..28b42ff
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_4.idl
@@ -0,0 +1,13 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Trailing comma in block.
+  enum TrailingComma {
+    name1,
+    name2,
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_5.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_5.idl
new file mode 100644
index 0000000..c3ed4f7
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_5.idl
@@ -0,0 +1,10 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Unexpected ";" after "(".
+  callback Callback1 = void(;
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_6.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_6.idl
new file mode 100644
index 0000000..2b2ff68
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_6.idl
@@ -0,0 +1,10 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Unexpected ")" after symbol long.
+  callback Callback1 = void(long );
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_7.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_7.idl
new file mode 100644
index 0000000..da69c33
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_7.idl
@@ -0,0 +1,12 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Unexpected symbol Events after symbol interace.
+  interace Events {
+    static void onFoo1();
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_8.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_8.idl
new file mode 100644
index 0000000..5cfc9ec
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_8.idl
@@ -0,0 +1,12 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Did not process Interface Interface(NotEvent).
+  interface NotEvent {
+    static void onFoo1();
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_idl_9.idl b/chrome/common/extensions/api/test_presubmit/invalid_idl_9.idl
new file mode 100644
index 0000000..3f2905c
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_idl_9.idl
@@ -0,0 +1,12 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid IDL file.
+
+namespace test {
+  // Interface missing name.
+  interface {
+    static void function1();
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_json_1.json b/chrome/common/extensions/api/test_presubmit/invalid_json_1.json
new file mode 100644
index 0000000..fcaa875
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_json_1.json
@@ -0,0 +1,8 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid JSON file.
+
+// Expecting property name: line 8 column 3 (char 9).
+{ x }
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_json_2.json b/chrome/common/extensions/api/test_presubmit/invalid_json_2.json
new file mode 100644
index 0000000..d157424
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_json_2.json
@@ -0,0 +1,8 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid JSON file.
+
+// Invalid control character at: line 8 column 19 (char 25).
+{ "hello": "world }
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_json_3.json b/chrome/common/extensions/api/test_presubmit/invalid_json_3.json
new file mode 100644
index 0000000..9dd3500
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_json_3.json
@@ -0,0 +1,8 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid JSON file.
+
+// Expecting property name: line 8 column 23 (char 29).
+{ "a": "b", "c": "d", }
diff --git a/chrome/common/extensions/api/test_presubmit/invalid_json_4.json b/chrome/common/extensions/api/test_presubmit/invalid_json_4.json
new file mode 100644
index 0000000..af6a1a6
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/invalid_json_4.json
@@ -0,0 +1,8 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests an invalid JSON file.
+
+// Expecting , delimiter: line 8 column 12 (char 18).
+{ "a": "b" "c": "d" }
diff --git a/chrome/common/extensions/api/test_presubmit/valid_idl_basics.idl b/chrome/common/extensions/api/test_presubmit/valid_idl_basics.idl
new file mode 100644
index 0000000..d0071e1
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/valid_idl_basics.idl
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests a valid IDL file.
+
+namespace idl_basics {
+  enum EnumType {
+    name1,
+    name2
+  };
+
+  dictionary MyType1 {
+    DOMString a;
+  };
+
+  callback Callback1 = void();
+  callback Callback2 = void(long x);
+  callback Callback3 = void(MyType1 arg);
+  callback Callback4 = void(EnumType type);
+
+  interface Functions {
+    static void function1();
+    static void function2(long x);
+    static void function3(MyType1 arg);
+    static void function4(Callback1 cb);
+    static void function5(Callback2 cb);
+    static void function6(Callback3 cb);
+    static void function7(Callback4 cb);
+  };
+
+  interface Events {
+    static void onFoo1();
+    static void onFoo2(long x);
+    static void onFoo2(MyType1 arg);
+    static void onFoo3(EnumType type);
+  };
+};
diff --git a/chrome/common/extensions/api/test_presubmit/valid_json.json b/chrome/common/extensions/api/test_presubmit/valid_json.json
new file mode 100644
index 0000000..615ea28
--- /dev/null
+++ b/chrome/common/extensions/api/test_presubmit/valid_json.json
@@ -0,0 +1,11 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests a valid IDL file.
+
+// This is a comment.
+{
+  "key1": ["value1", "value2"],
+  "key2": 3  // This is an inline comment.
+}
diff --git a/chrome/common/extensions/api/virtual_keyboard_private.json b/chrome/common/extensions/api/virtual_keyboard_private.json
index 35129cd..9094008 100644
--- a/chrome/common/extensions/api/virtual_keyboard_private.json
+++ b/chrome/common/extensions/api/virtual_keyboard_private.json
@@ -5,6 +5,9 @@
 [
   {
     "namespace": "virtualKeyboardPrivate",
+    "compiler_options": {
+      "implemented_in": "chrome/browser/extensions/api/input/input.h"
+    },
     "platforms": ["chromeos"],
     "description": "none",
     "types": [
@@ -88,6 +91,27 @@
           }
         ]
       }
+    ],
+    "events": [
+      {
+        "name": "onTextInputBoxFocused",
+        "type": "function",
+        "description": "This event is sent when focus enters a text input box.",
+        "parameters": [
+          {
+            "type": "object",
+            "name": "context",
+            "description": "Describes the text input box that has acquired focus. Note only the type of text input box is passed. This API is intended to be used by non-ime virtual keyboard only. Normal ime virtual keyboard should use chrome.input.ime.onFocus to get the more detailed InputContext.",
+            "properties": {
+              "type": {
+                "type": "string",
+                "description": "The value of type attribute of the focused text input box.",
+                "enum": ["text", "number", "password", "date", "url", "tel", "email"]
+              }
+            }
+          }
+        ]
+      }
     ]
   }
 ]
diff --git a/chrome/common/extensions/api/wallpaper.json b/chrome/common/extensions/api/wallpaper.json
index d24f260..7cb631f 100644
--- a/chrome/common/extensions/api/wallpaper.json
+++ b/chrome/common/extensions/api/wallpaper.json
@@ -6,7 +6,7 @@
   {
     "namespace":"wallpaper",
     "compiler_options": {
-     "implemented_in": "chrome/browser/chromeos/extensions/wallpaper_api.h"
+      "implemented_in": "chrome/browser/chromeos/extensions/wallpaper_api.h"
     },
     "platforms": ["chromeos"],
     "description": "none",
diff --git a/chrome/common/extensions/api/webrtc_logging_private.idl b/chrome/common/extensions/api/webrtc_logging_private.idl
new file mode 100644
index 0000000..b43c895
--- /dev/null
+++ b/chrome/common/extensions/api/webrtc_logging_private.idl
@@ -0,0 +1,43 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Use the <code>chrome.webrtcLoggingPrivate</code> API to control diagnostic
+// WebRTC logging.
+[nodoc] namespace webrtcLoggingPrivate {
+  dictionary UploadResult {
+    // The report ID for the uploaded log. Will be empty if not successful.
+    DOMString reportId;
+  };
+
+  callback GenericDoneCallback = void ();
+  callback UploadDoneCallback = void (UploadResult result);
+
+  interface Functions {
+    // Sets additional custom meta data that will be uploaded along with the
+    // log. |metaData| is a dictionary of the metadata (key, value).
+    static void setMetaData(object metaData, GenericDoneCallback callback);
+
+    // Starts logging. If logging has already been started for this render
+    // process, the call will be ignored. |appSessionId| is the unique session
+    // ID which will be added to the log.
+    static void start(GenericDoneCallback callback);
+
+    // Sets whether the log should be uploaded automatically for the case when
+    // the render process goes away (tab is closed or crashes) and stop has not
+    // been called before that. If |shouldUpload| is true it will be uploaded,
+    // otherwise it will be discarded. The default setting is to discard it.
+    static void setUploadOnRenderClose(boolean shouldUpload);
+
+    // Stops logging. After stop has finished, either upload() or discard()
+    // should be called, otherwise the log will be kept in memory until the
+    // render process is closed or logging restarted.
+    static void stop(GenericDoneCallback callback);
+
+    // Uploads the log. Logging must be stopped before this function is called.
+    static void upload(UploadDoneCallback callback);
+
+    // Discards the log. Logging must be stopped before this function is called.
+    static void discard(GenericDoneCallback callback);
+  };
+};
diff --git a/chrome/common/extensions/api/webview.json b/chrome/common/extensions/api/webview.json
index 7fe3548..dbce3d5 100644
--- a/chrome/common/extensions/api/webview.json
+++ b/chrome/common/extensions/api/webview.json
@@ -165,6 +165,20 @@
         ]
       },
       {
+        "name": "overrideUserAgent",
+        "type": "function",
+        "parameters": [
+          {
+            "type": "integer",
+            "name": "instanceId"
+          },
+          {
+            "type": "string",
+            "name": "userAgentOverride"
+          }
+        ]
+      },
+      {
         "name": "reload",
         "type": "function",
         "parameters": [
diff --git a/chrome/common/extensions/chrome_manifest_handlers.cc b/chrome/common/extensions/chrome_manifest_handlers.cc
index 07137d9..c4cf4db 100644
--- a/chrome/common/extensions/chrome_manifest_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -20,6 +20,7 @@
 #include "chrome/common/extensions/api/media_galleries_private/media_galleries_handler.h"
 #include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
+#include "chrome/common/extensions/api/sockets/sockets_handler.h"
 #include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
 #include "chrome/common/extensions/api/spellcheck/spellcheck_handler.h"
 #include "chrome/common/extensions/api/system_indicator/system_indicator_handler.h"
@@ -32,7 +33,7 @@
 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h"
+#include "chrome/common/extensions/manifest_handlers/kiosk_mode_info.h"
 #include "chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h"
 #include "chrome/common/extensions/manifest_handlers/nacl_modules_handler.h"
 #include "chrome/common/extensions/manifest_handlers/offline_enabled_info.h"
@@ -70,7 +71,7 @@
 #if defined(OS_CHROMEOS)
   (new InputComponentsHandler)->Register();
 #endif
-  (new KioskEnabledHandler)->Register();
+  (new KioskModeHandler)->Register();
   (new ManagedModeHandler)->Register();
   (new MediaGalleriesHandlerParser)->Register();
   (new MimeTypesHandlerParser)->Register();
@@ -86,6 +87,7 @@
   (new SandboxedPageHandler)->Register();
   (new ScriptBadgeHandler)->Register();
   (new SharedModuleHandler)->Register();
+  (new SocketsHandler)->Register();
   (new SpellcheckHandler)->Register();
   (new StorageSchemaManifestHandler)->Register();
   (new SystemIndicatorHandler)->Register();
diff --git a/chrome/common/extensions/csp_validator.cc b/chrome/common/extensions/csp_validator.cc
index f33e1ac..523d51e 100644
--- a/chrome/common/extensions/csp_validator.cc
+++ b/chrome/common/extensions/csp_validator.cc
@@ -21,7 +21,6 @@
 const char kSandboxDirectiveName[] = "sandbox";
 const char kAllowSameOriginToken[] = "allow-same-origin";
 const char kAllowTopNavigation[] = "allow-top-navigation";
-const char kAllowPopups[] = "allow-popups";
 
 struct DirectiveStatus {
   explicit DirectiveStatus(const char* name)
diff --git a/chrome/common/extensions/docs/server2/api_schema_graph.py b/chrome/common/extensions/docs/server2/api_schema_graph.py
index 03d3744..b81102a 100644
--- a/chrome/common/extensions/docs/server2/api_schema_graph.py
+++ b/chrome/common/extensions/docs/server2/api_schema_graph.py
@@ -2,8 +2,48 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import collections
 import json
+from collections import Iterable, Mapping
+from copy import deepcopy
+
+class LookupResult(object):
+  '''Returned from APISchemaGraph.Lookup(), and relays whether or not
+  some element was found and what annotation object was associated with it,
+  if any.
+  '''
+
+  def __init__(self, found=None, annotation=None):
+    assert found is not None, 'LookupResult was given None value for |found|.'
+    self.found = found
+    self.annotation = annotation
+
+  def __eq__(self, other):
+    return self.found == other.found and self.annotation == other.annotation
+
+  def __ne__(self, other):
+    return not (self == other)
+
+
+class _GraphNode(dict):
+  '''Represents some element of an API schema, and allows extra information
+  about that element to be stored on the |_annotation| object.
+  '''
+
+  def __init__(self, *args, **kwargs):
+    # Use **kwargs here since Python is picky with ordering of default args
+    # and variadic args in the method signature. The only keyword arg we care
+    # about here is 'annotation'. Intentionally don't pass |**kwargs| into the
+    # superclass' __init__().
+    dict.__init__(self, *args)
+    self._annotation = kwargs.get('annotation')
+
+  def __eq__(self, other):
+    # _GraphNode inherits __eq__() from dict, which will not take annotation
+    # objects into account when comparing.
+    return dict.__eq__(self, other)
+
+  def __ne__(self, other):
+    return not (self == other)
 
 
 def _NameForNode(node):
@@ -14,6 +54,7 @@
   if 'name' in node: return node['name']
   if 'id' in node: return node['id']
   if 'type' in node: return node['type']
+  if '$ref' in node: return node['$ref']
   assert False, 'Problems with naming node: %s' % json.dumps(node, indent=3)
 
 
@@ -21,25 +62,29 @@
   '''Determines whether or not |value| is a list made up entirely of
   dict-like objects.
   '''
-  return (isinstance(value, collections.Iterable) and
-          all(isinstance(node, collections.Mapping) for node in value))
+  return (isinstance(value, Iterable) and
+          all(isinstance(node, Mapping) for node in value))
 
 
 def _CreateGraph(root):
   '''Recursively moves through an API schema, replacing lists of objects
   and non-object values with objects.
   '''
-  schema_graph = {}
+  schema_graph = _GraphNode()
   if _IsObjectList(root):
     for node in root:
       name = _NameForNode(node)
-      assert name not in schema_graph, 'Duplicate name in availability graph.'
-      schema_graph[name] = dict((key, _CreateGraph(value)) for key, value
-                                in node.iteritems())
-  elif isinstance(root, collections.Mapping):
+      assert name not in schema_graph, 'Duplicate name in API schema graph.'
+      schema_graph[name] = _GraphNode((key, _CreateGraph(value)) for
+                                      key, value in node.iteritems())
+
+  elif isinstance(root, Mapping):
     for name, node in root.iteritems():
-      schema_graph[name] = dict((key, _CreateGraph(value)) for key, value
-                                in node.iteritems())
+      if not isinstance(node, Mapping):
+        schema_graph[name] = _GraphNode()
+      else:
+        schema_graph[name] = _GraphNode((key, _CreateGraph(value)) for
+                                        key, value in node.iteritems())
   return schema_graph
 
 
@@ -48,7 +93,7 @@
   which contains key-value pairs found in |minuend| but not in
   |subtrahend|.
   '''
-  difference = {}
+  difference = _GraphNode()
   for key in minuend:
     if key not in subtrahend:
       # Record all of this key's children as being part of the difference.
@@ -63,19 +108,49 @@
   return difference
 
 
+def _Update(base, addend, annotation=None):
+  '''A Set Union adaptation for graphs. Returns a graph which contains
+  the key-value pairs from |base| combined with any key-value pairs
+  from |addend| that are not present in |base|.
+  '''
+  for key in addend:
+    if key not in base:
+      # Add this key and the rest of its children.
+      base[key] = _Update(_GraphNode(annotation=annotation),
+                          addend[key],
+                          annotation=annotation)
+    else:
+      # The key is already in |base|, but check its children.
+       _Update(base[key], addend[key], annotation=annotation)
+  return base
+
+
+
 class APISchemaGraph(object):
   '''Provides an interface for interacting with an API schema graph, a
   nested dict structure that allows for simpler lookups of schema data.
   '''
 
-  def __init__(self, api_schema):
-    self._graph = _CreateGraph(api_schema)
+  def __init__(self, api_schema=None, _graph=None):
+    self._graph = _graph if _graph is not None else _CreateGraph(api_schema)
+
+  def __eq__(self, other):
+    return self._graph == other._graph
+
+  def __ne__(self, other):
+    return not (self == other)
 
   def Subtract(self, other):
     '''Returns an APISchemaGraph instance representing keys that are in
     this graph but not in |other|.
     '''
-    return APISchemaGraph(_Subtract(self._graph, other._graph))
+    return APISchemaGraph(_graph=_Subtract(self._graph, other._graph))
+
+  def Update(self, other, annotation=None):
+    '''Modifies this graph by adding keys from |other| that are not
+    already present in this graph.
+    '''
+    _Update(self._graph, other._graph, annotation=annotation)
 
   def Lookup(self, *path):
     '''Given a list of path components, |path|, checks if the
@@ -85,8 +160,8 @@
     for path_piece in path:
       node = node.get(path_piece)
       if node is None:
-        return False
-    return True
+        return LookupResult(found=False, annotation=None)
+    return LookupResult(found=True, annotation=node._annotation)
 
   def IsEmpty(self):
     '''Checks for an empty schema graph.
diff --git a/chrome/common/extensions/docs/server2/api_schema_graph_test.py b/chrome/common/extensions/docs/server2/api_schema_graph_test.py
index 14ccc52..d27e535 100755
--- a/chrome/common/extensions/docs/server2/api_schema_graph_test.py
+++ b/chrome/common/extensions/docs/server2/api_schema_graph_test.py
@@ -5,7 +5,7 @@
 
 import unittest
 
-from api_schema_graph import APISchemaGraph
+from api_schema_graph import APISchemaGraph, LookupResult
 
 
 API_SCHEMA = [{
@@ -62,56 +62,80 @@
     # A few assertions to make sure that Lookup works on empty sets.
     empty_graph = APISchemaGraph({})
     self.assertTrue(empty_graph.IsEmpty())
-    self.assertFalse(empty_graph.Lookup('tabs', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     empty_graph.Lookup('tabs', 'properties',
                                         'TAB_PROPERTY_ONE'))
-    self.assertFalse(empty_graph.Lookup('tabs', 'functions', 'get',
+    self.assertEqual(LookupResult(False, None),
+                     empty_graph.Lookup('tabs', 'functions', 'get',
                                         'parameters', 'tab'))
-    self.assertFalse(empty_graph.Lookup('tabs', 'functions', 'get',
+    self.assertEqual(LookupResult(False, None),
+                     empty_graph.Lookup('tabs', 'functions', 'get',
                                         'parameters', 'tabId'))
-    self.assertFalse(empty_graph.Lookup('tabs', 'events', 'onActivated',
+    self.assertEqual(LookupResult(False, None),
+                     empty_graph.Lookup('tabs', 'events', 'onActivated',
                                         'parameters', 'activeInfo'))
-    self.assertFalse(empty_graph.Lookup('tabs', 'events', 'onUpdated',
+    self.assertEqual(LookupResult(False, None),
+                     empty_graph.Lookup('tabs', 'events', 'onUpdated',
                                         'parameters', 'updateInfo'))
 
   def testSubtractEmpty(self):
     self._testApiSchema(
         APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph({})))
 
+  def _testApiSchema(self, api_schema_graph):
+    self.assertEqual(LookupResult(True, None),
+                     api_schema_graph.Lookup('tabs', 'properties',
+                                             'TAB_PROPERTY_ONE'))
+    self.assertEqual(LookupResult(True, None),
+                     api_schema_graph.Lookup('tabs', 'types', 'Tab'))
+    self.assertEqual(LookupResult(True, None),
+                    api_schema_graph.Lookup('tabs', 'functions', 'get',
+                                            'parameters', 'tab'))
+    self.assertEqual(LookupResult(True, None),
+                    api_schema_graph.Lookup('tabs', 'functions', 'get',
+                                            'parameters', 'tabId'))
+    self.assertEqual(LookupResult(True, None),
+                    api_schema_graph.Lookup('tabs', 'functions', 'get',
+                                            'parameters', 'tab', 'type'))
+    self.assertEqual(LookupResult(True, None),
+                    api_schema_graph.Lookup('tabs', 'events',
+                                            'onActivated', 'parameters',
+                                            'activeInfo'))
+    self.assertEqual(LookupResult(True, None),
+                    api_schema_graph.Lookup('tabs', 'events', 'onUpdated',
+                                            'parameters', 'updateInfo'))
+    self.assertEqual(LookupResult(True, None),
+                    api_schema_graph.Lookup('tabs', 'properties',
+                                            'lowercase', 'properties',
+                                            'one', 'value'))
+    self.assertEqual(LookupResult(True, None),
+                    api_schema_graph.Lookup('tabs', 'properties',
+                                            'lowercase', 'properties',
+                                            'two', 'description'))
+    self.assertEqual(LookupResult(False, None),
+                     api_schema_graph.Lookup('windows'))
+    self.assertEqual(LookupResult(False, None),
+                     api_schema_graph.Lookup('tabs', 'properties',
+                                             'TAB_PROPERTY_DEUX'))
+    self.assertEqual(LookupResult(False, None),
+                     api_schema_graph.Lookup('tabs', 'events', 'onActivated',
+                                             'parameters', 'callback'))
+    self.assertEqual(LookupResult(False, None),
+                     api_schema_graph.Lookup('tabs', 'functions', 'getById',
+                                             'parameters', 'tab'))
+    self.assertEqual(LookupResult(False, None),
+                     api_schema_graph.Lookup('tabs', 'functions', 'get',
+                                             'parameters', 'type'))
+    self.assertEqual(LookupResult(False, None),
+                     api_schema_graph.Lookup('tabs', 'properties',
+                                             'lowercase', 'properties',
+                                             'two', 'value'))
+
   def testSubtractSelf(self):
     self.assertTrue(
         APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph(API_SCHEMA))
             .IsEmpty())
 
-  def _testApiSchema(self, api_schema_graph):
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'properties',
-                                            'TAB_PROPERTY_ONE'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'types', 'Tab'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'functions', 'get',
-                                            'parameters', 'tab'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'functions', 'get',
-                                            'parameters', 'tabId'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'functions', 'get',
-                                            'parameters', 'tab', 'type'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'events', 'onActivated',
-                                            'parameters', 'activeInfo'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'events', 'onUpdated',
-                                            'parameters', 'updateInfo'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'properties', 'lowercase',
-                                            'properties', 'one', 'value'))
-    self.assertTrue(api_schema_graph.Lookup('tabs', 'properties', 'lowercase',
-                                            'properties', 'two', 'description'))
-
-    self.assertFalse(api_schema_graph.Lookup('windows'))
-    self.assertFalse(api_schema_graph.Lookup('tabs', 'properties',
-                                             'TAB_PROPERTY_DEUX'))
-    self.assertFalse(api_schema_graph.Lookup('tabs', 'events', 'onActivated',
-                                             'parameters', 'callback'))
-    self.assertFalse(api_schema_graph.Lookup('tabs', 'functions', 'getById',
-                                             'parameters', 'tab'))
-    self.assertFalse(api_schema_graph.Lookup('tabs', 'functions', 'get',
-                                             'parameters', 'type'))
-    self.assertFalse(api_schema_graph.Lookup('tabs', 'properties', 'lowercase',
-                                             'properties', 'two', 'value'))
 
   def testSubtractDisjointSet(self):
     difference = APISchemaGraph(API_SCHEMA).Subtract(APISchemaGraph({
@@ -148,23 +172,33 @@
         }
       }
     }))
-    self.assertTrue(difference.Lookup('tabs', 'properties',
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs', 'properties',
                                       'TAB_PROPERTY_ONE'))
-    self.assertTrue(difference.Lookup('tabs', 'functions', 'get',
+    self.assertEqual(LookupResult(True, None),
+                    difference.Lookup('tabs', 'functions', 'get',
                                       'parameters', 'tab'))
-    self.assertTrue(difference.Lookup('tabs', 'events', 'onUpdated',
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs', 'events', 'onUpdated',
                                       'parameters', 'updateInfo'))
-    self.assertTrue(difference.Lookup('tabs', 'functions', 'get',
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs', 'functions', 'get',
                                       'parameters', 'tabId'))
-    self.assertFalse(difference.Lookup('contextMenus', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('contextMenus', 'properties',
                                        'CONTEXT_MENU_PROPERTY_ONE'))
-    self.assertFalse(difference.Lookup('contextMenus', 'types', 'Menu'))
-    self.assertFalse(difference.Lookup('contextMenus', 'types', 'Menu',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('contextMenus', 'types', 'Menu'))
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('contextMenus', 'types', 'Menu',
                                        'properties', 'id'))
-    self.assertFalse(difference.Lookup('contextMenus', 'functions'))
-    self.assertFalse(difference.Lookup('contextMenus', 'events', 'onClicked',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('contextMenus', 'functions'))
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('contextMenus', 'events', 'onClicked',
                                        'parameters', 'clickInfo'))
-    self.assertFalse(difference.Lookup('contextMenus', 'events', 'onUpdated',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('contextMenus', 'events', 'onUpdated',
                                        'parameters', 'updateInfo'))
 
   def testSubtractSubset(self):
@@ -197,22 +231,31 @@
         }
       }
     }))
-    self.assertTrue(difference.Lookup('tabs'))
-    self.assertTrue(difference.Lookup('tabs', 'properties',
-                                      'TAB_PROPERTY_TWO'))
-    self.assertTrue(difference.Lookup('tabs', 'properties', 'lowercase',
-                                      'properties', 'two', 'description'))
-    self.assertTrue(difference.Lookup('tabs', 'types', 'Tab', 'properties',
-                                      'url'))
-    self.assertTrue(difference.Lookup('tabs', 'events', 'onActivated',
-                                      'parameters', 'activeInfo'))
-    self.assertFalse(difference.Lookup('tabs', 'events', 'onUpdated',
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs'))
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs', 'properties',
+                                       'TAB_PROPERTY_TWO'))
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs', 'properties', 'lowercase',
+                                       'properties', 'two', 'description'))
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs', 'types', 'Tab', 'properties',
+                                       'url'))
+    self.assertEqual(LookupResult(True, None),
+                     difference.Lookup('tabs', 'events', 'onActivated',
+                                       'parameters', 'activeInfo'))
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'events', 'onUpdated',
                                        'parameters', 'updateInfo'))
-    self.assertFalse(difference.Lookup('tabs', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'properties',
                                        'TAB_PROPERTY_ONE'))
-    self.assertFalse(difference.Lookup('tabs', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'properties',
                                        'TAB_PROPERTY_ONE', 'value'))
-    self.assertFalse(difference.Lookup('tabs', 'functions', 'get',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'functions', 'get',
                                        'parameters', 'tab'))
 
   def testSubtractSuperset(self):
@@ -279,23 +322,127 @@
         }
       }
     }))
-    self.assertFalse(difference.Lookup('tabs'))
-    self.assertFalse(difference.Lookup('tabs', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs'))
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'properties',
                                        'TAB_PROPERTY_TWO'))
-    self.assertFalse(difference.Lookup('tabs', 'properties'))
-    self.assertFalse(difference.Lookup('tabs', 'types', 'Tab', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'properties'))
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'types', 'Tab', 'properties',
                                        'url'))
-    self.assertFalse(difference.Lookup('tabs', 'types', 'Tab', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'types', 'Tab', 'properties',
                                        'id'))
-    self.assertFalse(difference.Lookup('tabs', 'events', 'onUpdated',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'events', 'onUpdated',
                                        'parameters', 'updateInfo'))
-    self.assertFalse(difference.Lookup('tabs', 'properties',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'properties',
                                        'TAB_PROPERTY_ONE'))
-    self.assertFalse(difference.Lookup('tabs', 'functions', 'get',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('tabs', 'functions', 'get',
                                        'parameters', 'tabId'))
-    self.assertFalse(difference.Lookup('events', 'onUpdated', 'parameters',
+    self.assertEqual(LookupResult(False, None),
+                     difference.Lookup('events', 'onUpdated', 'parameters',
                                        'updateInfo'))
 
+  def testUpdate(self):
+    result = APISchemaGraph(API_SCHEMA)
+    to_add = APISchemaGraph({
+      'tabs': {
+        'properties': {
+          'TAB_PROPERTY_THREE': { 'description': 'better than two' },
+          'TAB_PROPERTY_FOUR': { 'value': 4 }
+        },
+        'functions': {
+        'get': {
+          'name': {},
+          'parameters': {
+            'tab': {
+              'type': {},
+              'name': {},
+              'description': {},
+              'surprise': {}
+            }
+          }
+        },
+          'getAllInWindow': {
+            'parameters': {
+              'windowId': { 'type': 'object' }
+            }
+          }
+        }
+      }
+    })
+    result.Update(to_add, annotation='first')
+    # Looking up elements that were originally available in |result|. Because
+    # of this, no |annotation| object should be attached to the LookupResult
+    # object.
+    self.assertEqual(LookupResult(True, None),
+                     result.Lookup('tabs'))
+    self.assertEqual(LookupResult(True, None),
+                     result.Lookup('tabs', 'functions', 'get',
+                                   'parameters'))
+    self.assertEqual(LookupResult(True, None),
+                     result.Lookup('tabs', 'properties',
+                                   'TAB_PROPERTY_ONE'))
+    self.assertEqual(LookupResult(True, None),
+                     result.Lookup('tabs', 'properties',
+                                   'TAB_PROPERTY_ONE'))
+    self.assertEqual(LookupResult(True, None),
+                     result.Lookup('tabs', 'functions', 'get',
+                                   'parameters', 'tabId'))
+
+    # Looking up elements that were just added to |result|.
+    self.assertEqual(LookupResult(True, 'first'),
+                     result.Lookup('tabs', 'properties',
+                                   'TAB_PROPERTY_THREE'))
+    self.assertEqual(LookupResult(True, 'first'),
+                     result.Lookup('tabs', 'properties',
+                                   'TAB_PROPERTY_FOUR'))
+    self.assertEqual(LookupResult(True, 'first'),
+                     result.Lookup('tabs', 'functions', 'getAllInWindow',
+                                   'parameters', 'windowId'))
+    self.assertEqual(LookupResult(True, 'first'),
+                     result.Lookup('tabs', 'functions', 'get', 'parameters',
+                                   'tab', 'surprise'))
+
+    to_add = APISchemaGraph({
+      'tabs': {
+        'properties': {
+          'TAB_PROPERTY_FIVE': { 'description': 'stayin\' alive' }
+        },
+        'functions': {
+          'getAllInWindow': {
+            'parameters': {
+              'callback': { 'type': 'function' }
+            }
+          }
+        }
+      }
+    })
+    result.Update(to_add, annotation='second')
+    # Looking up the second group of elements added to |result|.
+    self.assertEqual(LookupResult(True, 'first'),
+                     result.Lookup('tabs', 'properties',
+                                   'TAB_PROPERTY_FOUR'))
+    self.assertEqual(LookupResult(True, 'second'),
+                     result.Lookup('tabs', 'properties',
+                                   'TAB_PROPERTY_FIVE'))
+    self.assertEqual(LookupResult(True, 'first'),
+                     result.Lookup('tabs', 'functions',
+                                   'getAllInWindow', 'parameters',
+                                   'windowId'))
+    self.assertEqual(LookupResult(True, 'second'),
+                     result.Lookup('tabs', 'functions',
+                                   'getAllInWindow', 'parameters',
+                                   'callback'))
+    self.assertEqual(LookupResult(True, 'first'),
+                     result.Lookup('tabs', 'functions',
+                                   'getAllInWindow'))
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index aec5138..bc42d42 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
 application: chrome-apps-doc
-version: 2-28-2
+version: 2-28-3
 runtime: python27
 api_version: 1
 threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/availability_finder.py b/chrome/common/extensions/docs/server2/availability_finder.py
index b4ab31a..e88523b 100644
--- a/chrome/common/extensions/docs/server2/availability_finder.py
+++ b/chrome/common/extensions/docs/server2/availability_finder.py
@@ -5,15 +5,18 @@
 import collections
 import os
 
-import svn_constants
+from api_schema_graph import APISchemaGraph
 from branch_utility import BranchUtility
 from compiled_file_system import CompiledFileSystem
-from file_system import FileNotFoundError
-from third_party.json_schema_compiler import json_parse
-from third_party.json_schema_compiler.memoize import memoize
+from svn_constants import API_PATH
+from third_party.json_schema_compiler import idl_schema, idl_parser, json_parse
+from third_party.json_schema_compiler.json_parse import OrderedDict
 from third_party.json_schema_compiler.model import UnixName
 
 
+_EXTENSION_API = 'extension_api.json'
+
+
 def _GetChannelFromFeatures(api_name, file_system, path):
   '''Finds API channel information within _features.json files at the given
   |path| for the given |file_system|. Returns None if channel information for
@@ -35,38 +38,55 @@
   return _GetChannelFromFeatures(
       api_name,
       file_system,
-      '%s/_api_features.json' % svn_constants.API_PATH)
+      '%s/_api_features.json' % API_PATH)
 
 
 def _GetChannelFromManifestFeatures(api_name, file_system):
   return _GetChannelFromFeatures(
       UnixName(api_name), #_manifest_features uses unix_style API names
       file_system,
-      '%s/_manifest_features.json' % svn_constants.API_PATH)
+      '%s/_manifest_features.json' % API_PATH)
 
 
 def _GetChannelFromPermissionFeatures(api_name, file_system):
   return _GetChannelFromFeatures(
       api_name,
       file_system,
-      '%s/_permission_features.json' % svn_constants.API_PATH)
+      '%s/_permission_features.json' % API_PATH)
 
 
-def _ExistsInExtensionApi(api_name, file_system):
-  '''Parses the api/extension_api.json file (available in Chrome versions
-  before 18) for an API namespace. If this is successfully found, then the API
-  is considered to have been 'stable' for the given version.
+def _GetApiSchema(api_name, file_system):
+  '''Searches |file_system| for |api_name|'s API schema data, and parses and
+  returns it if found.
   '''
-  try:
-    extension_api_json = file_system.GetFromFile(
-        '%s/extension_api.json' % svn_constants.API_PATH)
-    api_rows = [row.get('namespace') for row in extension_api_json
-                if 'namespace' in row]
-    return api_name in api_rows
-  except FileNotFoundError:
-    # This should only happen on preview.py since extension_api.json is no
-    # longer present in trunk.
-    return False
+  file_names = file_system.ReadSingle('%s/' % API_PATH)
+  # API names can be represented in unix_style and camelCase formats.
+  possibilities = (api_name, UnixName(api_name))
+
+  def get_file_data(file_name):
+    return file_system.ReadSingle('%s/%s' % (API_PATH, file_name))
+
+  if _EXTENSION_API in file_names:
+    # Prior to Chrome version 18, extension_api.json contained all API schema
+    # data, which replaced the current implementation of individual API files.
+    #
+    # TODO(epeterson) This file will be parsed a lot, but the data remains the
+    # same for each API. Avoid doing unnecessary work by re-parsing.
+    # (see http://crbug.com/295812)
+    extension_api_json = json_parse.Parse(get_file_data(_EXTENSION_API))
+    api = [api for api in extension_api_json if api['namespace'] == api_name]
+    return api if api else None
+
+  def check_file(file_name):
+    return os.path.splitext(file_name)[0] in (api_name, UnixName(api_name))
+
+  for file_name in file_names:
+    if check_file(file_name):
+      if file_name.endswith('idl'):
+        idl_data = idl_parser.IDLParser().ParseData(get_file_data(file_name))
+        return idl_schema.IDLSchema(idl_data).process()
+      return json_parse.Parse(get_file_data(file_name))
+  return None
 
 
 class AvailabilityFinder(object):
@@ -77,23 +97,16 @@
   def __init__(self,
                file_system_iterator,
                object_store_creator,
-               branch_utility):
+               branch_utility,
+               host_file_system):
     self._file_system_iterator = file_system_iterator
     self._object_store_creator = object_store_creator
-    self._object_store = self._object_store_creator.Create(AvailabilityFinder)
+    def create_object_store(category):
+      return object_store_creator.Create(AvailabilityFinder, category=category)
+    self._top_level_object_store = create_object_store('top_level')
+    self._node_level_object_store = create_object_store('node_level')
     self._branch_utility = branch_utility
-
-  def _ExistsInFileSystem(self, api_name, file_system):
-    '''Checks for existence of |api_name| within the list of api files in the
-    api/ directory found using the given |file_system|.
-    '''
-    file_names = file_system.ReadSingle('%s/' % svn_constants.API_PATH)
-    api_names = tuple(os.path.splitext(name)[0] for name in file_names
-                      if os.path.splitext(name)[1][1:] in ['json', 'idl'])
-
-    # API file names in api/ are unix_name at every version except for versions
-    # 18, 19, and 20. Since unix_name is the more common format, check it first.
-    return (UnixName(api_name) in api_names) or (api_name in api_names)
+    self._host_file_system = host_file_system
 
   def _CheckStableAvailability(self, api_name, file_system, version):
     '''Checks for availability of an API, |api_name|, on the stable channel.
@@ -122,15 +135,11 @@
           or _GetChannelFromManifestFeatures(api_name, features_fs))
       if available_channel is not None:
         return available_channel == 'stable'
-    if version >= 18:
-      # Fall back to a check for file system existence if the API is not
-      # stable in any of the _features.json files, OR if we're dealing with
-      # version 18 or 19, which don't contain relevant _features information.
-      return self._ExistsInFileSystem(api_name, file_system)
     if version >= 5:
-      # Versions 17 down to 5 have an extension_api.json file which
-      # contains namespaces for each API that was available at the time.
-      return _ExistsInExtensionApi(api_name, features_fs)
+      # Fall back to a check for file system existence if the API is not
+      # stable in any of the _features.json files, or if the _features files
+      # do not exist (version 19 and earlier).
+      return _GetApiSchema(api_name, file_system) is not None
 
   def _CheckChannelAvailability(self, api_name, file_system, channel_name):
     '''Searches through the _features files in a given |file_system| and
@@ -146,7 +155,7 @@
         or _GetChannelFromPermissionFeatures(api_name, features_fs)
         or _GetChannelFromManifestFeatures(api_name, features_fs))
     if (available_channel is None and
-        self._ExistsInFileSystem(api_name, file_system)):
+        _GetApiSchema(api_name, file_system) is not None):
       # If an API is not represented in any of the _features files, but exists
       # in the filesystem, then assume it is available in this version.
       # The windows API is an example of this.
@@ -175,7 +184,7 @@
     HostFileSystemIterator instance to traverse multiple version of the
     SVN filesystem.
     '''
-    availability = self._object_store.Get(api_name).Get()
+    availability = self._top_level_object_store.Get(api_name).Get()
     if availability is not None:
       return availability
 
@@ -188,5 +197,37 @@
     if availability is None:
       # The API wasn't available on 'dev', so it must be a 'trunk'-only API.
       availability = self._branch_utility.GetChannelInfo('trunk')
-    self._object_store.Set(api_name, availability)
+    self._top_level_object_store.Set(api_name, availability)
     return availability
+
+  def GetApiNodeAvailability(self, api_name):
+    '''Returns an APISchemaGraph annotated with each node's availability (the
+    ChannelInfo at the oldest channel it's available in).
+    '''
+    availability_graph = self._node_level_object_store.Get(api_name).Get()
+    if availability_graph is not None:
+      return availability_graph
+
+    availability_graph = APISchemaGraph()
+    trunk_graph = APISchemaGraph(_GetApiSchema(api_name,
+                                               self._host_file_system))
+    def update_availability_graph(file_system, channel_info):
+      version_graph = APISchemaGraph(_GetApiSchema(api_name, file_system))
+      # Keep track of any new schema elements from this version by adding
+      # them to |availability_graph|.
+      #
+      # Calling |availability_graph|.Lookup() on the nodes being updated
+      # will return the |annotation| object.
+      availability_graph.Update(version_graph.Subtract(availability_graph),
+                                annotation=channel_info)
+
+      # Continue looping until there are no longer differences between this
+      # version and trunk.
+      return trunk_graph != version_graph
+
+    self._file_system_iterator.Ascending(
+        self.GetApiAvailability(api_name),
+        update_availability_graph)
+
+    self._node_level_object_store.Set(api_name, availability_graph)
+    return availability_graph
diff --git a/chrome/common/extensions/docs/server2/availability_finder_test.py b/chrome/common/extensions/docs/server2/availability_finder_test.py
index 83ab7c7..0cfc373 100755
--- a/chrome/common/extensions/docs/server2/availability_finder_test.py
+++ b/chrome/common/extensions/docs/server2/availability_finder_test.py
@@ -2,12 +2,14 @@
 # Copyright 2013 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
+import json
 
 import os
 import sys
 import unittest
 
 from availability_finder import AvailabilityFinder
+from api_schema_graph import LookupResult
 from branch_utility import BranchUtility
 from compiled_file_system import CompiledFileSystem
 from fake_url_fetcher import FakeUrlFetcher
@@ -15,30 +17,40 @@
 from object_store_creator import ObjectStoreCreator
 from test_file_system import TestFileSystem
 from test_data.canned_data import (CANNED_API_FILE_SYSTEM_DATA, CANNED_BRANCHES)
+from test_data.object_level_availability.tabs import TABS_SCHEMA_BRANCHES
 
 
 class FakeHostFileSystemCreator(object):
 
+  def __init__(self, file_system_data):
+    self._file_system_data = file_system_data
+
   def Create(self, branch):
-    return TestFileSystem(CANNED_API_FILE_SYSTEM_DATA[str(branch)])
+    return TestFileSystem(self._file_system_data[str(branch)])
 
 
 class AvailabilityFinderTest(unittest.TestCase):
 
   def setUp(self):
-    branch_utility = BranchUtility(
+    self._branch_utility = BranchUtility(
         os.path.join('branch_utility', 'first.json'),
         os.path.join('branch_utility', 'second.json'),
         FakeUrlFetcher(os.path.join(sys.path[0], 'test_data')),
         ObjectStoreCreator.ForTest())
-    fake_host_file_system_creator = FakeHostFileSystemCreator()
-    file_system_iterator = HostFileSystemIterator(
-      fake_host_file_system_creator,
-      fake_host_file_system_creator.Create('trunk'),
-      branch_utility)
-    self._avail_finder = AvailabilityFinder(file_system_iterator,
-                                            ObjectStoreCreator.ForTest(),
-                                            branch_utility)
+
+    def create_availability_finder(file_system_data):
+      fake_host_fs_creator = FakeHostFileSystemCreator(file_system_data)
+      fake_host_fs = fake_host_fs_creator.Create('trunk')
+      return AvailabilityFinder(HostFileSystemIterator(
+                                    fake_host_fs_creator,
+                                    fake_host_fs,
+                                    self._branch_utility),
+                                ObjectStoreCreator.ForTest(),
+                                self._branch_utility,
+                                fake_host_fs)
+
+    self._avail_finder = create_availability_finder(CANNED_API_FILE_SYSTEM_DATA)
+    self._node_avail_finder = create_availability_finder(TABS_SCHEMA_BRANCHES)
 
   def testGetApiAvailability(self):
     # Key: Using 'channel' (i.e. 'beta') to represent an availability listing
@@ -46,7 +58,7 @@
     # represent the development channel, or phase of development, where an API's
     # availability is being checked.
 
-    # Testing whitelisted API
+    # Testing a whitelisted API.
     self.assertEquals('beta',
         self._avail_finder.GetApiAvailability('declarativeWebRequest').channel)
     self.assertEquals(27,
@@ -174,5 +186,108 @@
     self.assertEquals('trunk',
         self._avail_finder.GetApiAvailability('events').version)
 
+  def testGetApiNodeAvailability(self):
+    availability_graph = self._node_avail_finder.GetApiNodeAvailability('tabs')
+
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetChannelInfo('trunk')),
+        availability_graph.Lookup('tabs', 'properties',
+                                  'fakeTabsProperty3'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetChannelInfo('dev')),
+        availability_graph.Lookup('tabs', 'events', 'onActivated',
+                                  'parameters', 'activeInfo', 'properties',
+                                  'windowId'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetChannelInfo('dev')),
+        availability_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters',
+                                  'tab'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetChannelInfo('beta')),
+        availability_graph.Lookup('tabs', 'events','onActivated'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetChannelInfo('beta')),
+        availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
+                                  'tabId'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetChannelInfo('stable')),
+        availability_graph.Lookup('tabs', 'types', 'InjectDetails',
+                                  'properties', 'code'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetChannelInfo('stable')),
+        availability_graph.Lookup('tabs', 'types', 'InjectDetails',
+                                  'properties', 'file'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(25)),
+        availability_graph.Lookup('tabs', 'types', 'InjectDetails'))
+
+    # Nothing new in version 24 or 23.
+
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(22)),
+        availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
+                                  'windowId'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(21)),
+        availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
+                                  'selected'))
+
+    # Nothing new in version 20.
+
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(19)),
+        availability_graph.Lookup('tabs', 'functions', 'getCurrent'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(18)),
+        availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
+                                  'index'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(17)),
+        availability_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters',
+                                  'changeInfo'))
+
+    # Nothing new in version 16.
+
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(15)),
+        availability_graph.Lookup('tabs', 'properties',
+                                  'fakeTabsProperty2'))
+
+    # Everything else is available at the API's release, version 14 here.
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
+        availability_graph.Lookup('tabs', 'types', 'Tab'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
+        availability_graph.Lookup('tabs', 'types', 'Tab',
+                                  'properties', 'url'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
+        availability_graph.Lookup('tabs', 'properties',
+                                  'fakeTabsProperty1'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
+        availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
+                                  'callback'))
+    self.assertEquals(
+        LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
+        availability_graph.Lookup('tabs', 'events', 'onUpdated'))
+
+    # Test things that aren't available.
+    self.assertEqual(LookupResult(False, None),
+                     availability_graph.Lookup('tabs', 'types',
+                                               'UpdateInfo'))
+    self.assertEqual(LookupResult(False, None),
+                     availability_graph.Lookup('tabs', 'functions', 'get',
+                                               'parameters', 'callback',
+                                               'parameters', 'tab', 'id'))
+    self.assertEqual(LookupResult(False, None),
+                     availability_graph.Lookup('functions'))
+    self.assertEqual(LookupResult(False, None),
+                     availability_graph.Lookup('events', 'onActivated',
+                                               'parameters', 'activeInfo',
+                                               'tabId'))
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/chrome/common/extensions/docs/server2/branch_utility.py b/chrome/common/extensions/docs/server2/branch_utility.py
index eb1dffc..7eb164c 100644
--- a/chrome/common/extensions/docs/server2/branch_utility.py
+++ b/chrome/common/extensions/docs/server2/branch_utility.py
@@ -189,7 +189,7 @@
       # Here, entry['title'] looks like: '<title> - <version>.##.<branch>.##'
       version_title = entry['title'].split(' - ')[1].split('.')
       if version_title[0] == str(version):
-        self._branch_object_store.Set(str(version), version_title[2])
+        self._branch_object_store.Set(str(version), int(version_title[2]))
         return int(version_title[2])
 
     raise ValueError('The branch for %s could not be found.' % version)
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
index 5a1047b..dc55ff3 100644
--- a/chrome/common/extensions/docs/server2/cron.yaml
+++ b/chrome/common/extensions/docs/server2/cron.yaml
@@ -2,4 +2,4 @@
 - description: Repopulates all cached data.
   url: /_cron
   schedule: every 5 minutes
-  target: 2-28-2
+  target: 2-28-3
diff --git a/chrome/common/extensions/docs/server2/new_github_file_system_test.py b/chrome/common/extensions/docs/server2/new_github_file_system_test.py
index 8eae40a..157dc08 100755
--- a/chrome/common/extensions/docs/server2/new_github_file_system_test.py
+++ b/chrome/common/extensions/docs/server2/new_github_file_system_test.py
@@ -86,11 +86,13 @@
   def testReads(self):
     self._gfs.Refresh().Get()
     expected = {
-      '/src/': ['hello.notpy', '__init__.notpy'],
-      '/': ['requirements.txt', '.gitignore', 'README.md', 'src/']
+      '/src/': sorted(['hello.notpy', '__init__.notpy']),
+      '/': sorted(['requirements.txt', '.gitignore', 'README.md', 'src/'])
     }
 
-    self.assertEqual(expected, self._gfs.Read(['/', '/src/']).Get())
+    read = self._gfs.Read(['/', '/src/']).Get()
+    self.assertEqual(expected['/src/'], sorted(read['/src/']))
+    self.assertEqual(expected['/'], sorted(read['/']))
 
   def testStat(self):
     self._gfs.Refresh().Get()
diff --git a/chrome/common/extensions/docs/server2/server_instance.py b/chrome/common/extensions/docs/server2/server_instance.py
index ef92a06..1194e9e 100644
--- a/chrome/common/extensions/docs/server2/server_instance.py
+++ b/chrome/common/extensions/docs/server2/server_instance.py
@@ -52,7 +52,8 @@
     self.availability_finder = AvailabilityFinder(
         self.host_file_system_iterator,
         object_store_creator,
-        branch_utility)
+        branch_utility,
+        host_file_system)
 
     self.api_list_data_source_factory = APIListDataSource.Factory(
         self.compiled_host_fs_factory,
diff --git a/chrome/common/extensions/docs/server2/test_data/canned_data.py b/chrome/common/extensions/docs/server2/test_data/canned_data.py
index b3a0136..a227f1a 100644
--- a/chrome/common/extensions/docs/server2/test_data/canned_data.py
+++ b/chrome/common/extensions/docs/server2/test_data/canned_data.py
@@ -181,11 +181,11 @@
           'channel': 'trunk'
         }
       }),
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents',
-      'windows.json': 'windows contents'
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}',
+      'windows.json': '{}'
     },
     'docs': {
       'templates': {
@@ -280,11 +280,11 @@
           'channel': 'beta'
         }
       }),
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents',
-      'windows.json': 'windows contents'
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}',
+      'windows.json': '{}'
     }
   },
   '1453': {
@@ -348,11 +348,11 @@
           'channel': 'dev'
         }
       }),
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents',
-      'windows.json': 'windows contents'
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}',
+      'windows.json': '{}'
     }
   },
   '1410': {
@@ -399,11 +399,11 @@
           'channel': 'stable'
         }
       }),
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents',
-      'windows.json': 'windows contents'
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}',
+      'windows.json': '{}'
     }
   },
   '1364': {
@@ -430,11 +430,11 @@
           'channel': 'stable'
         }
       }),
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents',
-      'windows.json': 'windows contents'
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}',
+      'windows.json': '{}'
     }
   },
   '1312': {
@@ -461,11 +461,11 @@
           'channel': 'stable'
         }
       }),
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents',
-      'windows.json': 'windows contents'
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}',
+      'windows.json': '{}'
     }
   },
   '1271': {
@@ -492,12 +492,12 @@
           'channel': 'stable'
         }
       }),
-      'alarms.idl': 'alarms contents',
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents',
-      'windows.json': 'windows contents'
+      'alarms.idl': '{}',
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}',
+      'windows.json': '{}'
     }
   },
   '1229': {
@@ -521,12 +521,12 @@
           'channel': 'beta'
         }
       }),
-      'alarms.idl': 'alarms contents',
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'system_info_display.idl': 'systemInfo.display contents',
-      'tabs.json': 'tabs contents'
+      'alarms.idl': '{}',
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'system_info_display.idl': '{}',
+      'tabs.json': '{}'
     }
   },
   '1180': {
@@ -547,11 +547,11 @@
           'channel': 'stable'
         }
       }),
-      'bookmarks.json': 'bookmarks contents',
-      'idle.json': 'idle contents',
-      'input_ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents'
+      'bookmarks.json': '{}',
+      'idle.json': '{}',
+      'input_ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}'
     }
   },
   '1132': {
@@ -569,11 +569,11 @@
           'channel': 'stable'
         }
       }),
-      'bookmarks.json': 'bookmarks contents',
-      'idle.json': 'idle contents',
-      'input.ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'tabs.json': 'tabs contents'
+      'bookmarks.json': '{}',
+      'idle.json': '{}',
+      'input.ime.json': '{}',
+      'menus.json': '{}',
+      'tabs.json': '{}'
     }
   },
   '1084': {
@@ -581,22 +581,22 @@
       '_manifest_features.json': json.dumps({
         'contents': 'nothing of interest here,really'
       }),
-      'idle.json': 'idle contents',
-      'input.ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'pageAction.json': 'pageAction contents',
-      'tabs.json': 'tabs contents',
-      'webRequest.json': 'webRequest contents'
+      'idle.json': '{}',
+      'input.ime.json': '{}',
+      'menus.json': '{}',
+      'pageAction.json': '{}',
+      'tabs.json': '{}',
+      'webRequest.json': '{}'
     }
   },
   '1025': {
     'api': {
-      'idle.json': 'idle contents',
-      'input.ime.json': 'input.ime contents',
-      'menus.json': 'menus contents',
-      'pageAction.json': 'pageAction contents',
-      'tabs.json': 'tabs contents',
-      'webRequest.json': 'webRequest contents'
+      'idle.json': '{}',
+      'input.ime.json': '{}',
+      'menus.json': '{}',
+      'pageAction.json': '{}',
+      'tabs.json': '{}',
+      'webRequest.json': '{}'
     }
   },
   '963': {
diff --git a/chrome/common/extensions/docs/server2/test_data/github_file_system/test_owner/repo/zipball b/chrome/common/extensions/docs/server2/test_data/github_file_system/test_owner/repo/zipball
index be0dde6..1992481 100644
--- a/chrome/common/extensions/docs/server2/test_data/github_file_system/test_owner/repo/zipball
+++ b/chrome/common/extensions/docs/server2/test_data/github_file_system/test_owner/repo/zipball
Binary files differ
diff --git a/chrome/common/extensions/docs/server2/test_data/object_level_availability/__init__.py b/chrome/common/extensions/docs/server2/test_data/object_level_availability/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_data/object_level_availability/__init__.py
diff --git a/chrome/common/extensions/docs/server2/test_data/object_level_availability/tabs.py b/chrome/common/extensions/docs/server2/test_data/object_level_availability/tabs.py
new file mode 100644
index 0000000..e2a2b24
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_data/object_level_availability/tabs.py
@@ -0,0 +1,1108 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+
+
+TABS_SCHEMA_BRANCHES = {
+  'trunk': {
+    'api': {
+      '_api_features.json': json.dumps({}),
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          },
+          {
+            'id': 'InjectDetails',
+            'properties': {
+              'allFrames': {},
+              'code': {},
+              'file': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {},
+          'fakeTabsProperty3': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              },
+              {
+                'name': 'tabId'
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onActivated',
+            'parameters': [
+              {
+                'name': 'activeInfo',
+                'properties': {
+                  'tabId': {},
+                  'windowId': {}
+                }
+              }
+            ]
+          },
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'tab'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1500': {
+    'api': {
+      '_api_features.json': json.dumps({}),
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          },
+          {
+            'id': 'InjectDetails',
+            'properties': {
+              'allFrames': {},
+              'code': {},
+              'file': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              },
+              {
+                'name': 'tabId'
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onActivated',
+            'parameters': [
+              {
+                'name': 'activeInfo',
+                'properties': {
+                  'tabId': {},
+                  'windowId': {}
+                }
+              }
+            ]
+          },
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'tab'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1453': {
+    'api': {
+      '_api_features.json': json.dumps({}),
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          },
+          {
+            'id': 'InjectDetails',
+            'properties': {
+              'allFrames': {},
+              'code': {},
+              'file': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              },
+              {
+                'name': 'tabId'
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onActivated',
+            'parameters': [
+              {
+                'name': 'activeInfo',
+                'properties': {
+                  'tabId': {}
+                }
+              }
+            ]
+          },
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1410': {
+    'api': {
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          },
+          {
+            'id': 'InjectDetails',
+            'properties': {
+              'allFrames': {},
+              'code': {},
+              'file': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1364': {
+    'api': {
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          },
+          {
+            'id': 'InjectDetails',
+            'properties': {
+              'allFrames': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1312': {
+    'api': {
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1271': {
+    'api': {
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1229': {
+    'api': {
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {},
+              'windowId': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1180': {
+    'api': {
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'selected': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1132': {
+    'api': {
+      '_manifest_features.json': json.dumps({}),
+      '_permission_features.json': json.dumps({}),
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1084': {
+    'api': {
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'getCurrent',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          },
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '1025': {
+    'api': {
+      'tabs.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'index': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '963': {
+    'api': {
+      'extension_api.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              },
+              {
+                'name': 'changeInfo',
+                'properties': {
+                  'pinned': {},
+                  'status': {}
+                }
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '912': {
+    'api': {
+      'extension_api.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '874': {
+    'api': {
+      'extension_api.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {},
+          'fakeTabsProperty2': {}
+        },
+        'functions': [
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '835': {
+    'api': {
+      'extension_api.json': json.dumps([{
+        'namespace': 'tabs',
+        'types': [
+          {
+            'id': 'Tab',
+            'properties': {
+              'url': {},
+              'id': {}
+            }
+          }
+        ],
+        'properties': {
+          'fakeTabsProperty1': {}
+        },
+        'functions': [
+          {
+            'name': 'get',
+            'parameters': [
+              {
+                'name': 'callback',
+                'parameters': [
+                  {
+                    'name': 'tab'
+                  }
+                ]
+              }
+            ]
+          }
+        ],
+        'events': [
+          {
+            'name': 'onUpdated',
+            'parameters': [
+              {
+                'name': 'tabId'
+              }
+            ]
+          }
+        ]
+      }])
+    }
+  },
+  '782': {
+    'api': {
+      'extension_api.json': json.dumps({})
+    }
+  }
+}
diff --git a/chrome/common/extensions/docs/templates/articles/about_apps.html b/chrome/common/extensions/docs/templates/articles/about_apps.html
index dd130ee..ab41e52 100644
--- a/chrome/common/extensions/docs/templates/articles/about_apps.html
+++ b/chrome/common/extensions/docs/templates/articles/about_apps.html
@@ -12,7 +12,7 @@
 </p>
 
 <p>
-<iframe title="YouTube video player" width="610" height="380" src="http://www.youtube.com/embed/lBUGTVIJVfM" frameborder="0" allowfullscreen></iframe>
+<iframe title="YouTube video player" width="610" height="380" src="//www.youtube.com/embed/lBUGTVIJVfM" frameborder="0" allowfullscreen></iframe>
 </p>
 
 <p>
diff --git a/chrome/common/extensions/docs/templates/articles/api_index.html b/chrome/common/extensions/docs/templates/articles/api_index.html
index f9a1232..891a7c9 100644
--- a/chrome/common/extensions/docs/templates/articles/api_index.html
+++ b/chrome/common/extensions/docs/templates/articles/api_index.html
@@ -54,6 +54,6 @@
 
 {{^is_apps}}
 <p class="doc-family extensions">
-<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/bmxr75CV36A?rel=0" frameborder="0" allowfullscreen></iframe>
+<iframe title="YouTube video player" width="640" height="390" src="//www.youtube.com/embed/bmxr75CV36A?rel=0" frameborder="0" allowfullscreen></iframe>
 </p>
 {{/is_apps}}
diff --git a/chrome/common/extensions/docs/templates/articles/app_architecture.html b/chrome/common/extensions/docs/templates/articles/app_architecture.html
index 3f61720..f74d9dc 100644
--- a/chrome/common/extensions/docs/templates/articles/app_architecture.html
+++ b/chrome/common/extensions/docs/templates/articles/app_architecture.html
@@ -67,7 +67,7 @@
 <p>
 
 <p>
-<iframe title="YouTube video player" width="610" height="380" src="http://www.youtube.com/embed/yr1jgREbH8U" frameborder="0" allowfullscreen></iframe>
+<iframe title="YouTube video player" width="610" height="380" src="//www.youtube.com/embed/yr1jgREbH8U" frameborder="0" allowfullscreen></iframe>
 </p>
 
 <h3 id="lifecycle">App lifecycle at a glance</h3>
@@ -167,7 +167,7 @@
 </p>
 
 <p>
-<iframe title="YouTube video player" width="610" height="380" src="http://www.youtube.com/embed/EDtiWN42lHs" frameborder="0" allowfullscreen></iframe>
+<iframe title="YouTube video player" width="610" height="380" src="//www.youtube.com/embed/EDtiWN42lHs" frameborder="0" allowfullscreen></iframe>
 </p>
 
 <p class="backtotop"><a href="#top">Back to top</a></p>
diff --git a/chrome/common/extensions/docs/templates/articles/content_scripts.html b/chrome/common/extensions/docs/templates/articles/content_scripts.html
index 5cecf95..3811402 100644
--- a/chrome/common/extensions/docs/templates/articles/content_scripts.html
+++ b/chrome/common/extensions/docs/templates/articles/content_scripts.html
@@ -448,7 +448,7 @@
 </p>
 
 <p>
-<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/laLudeUmXHM?rel=0" frameborder="0" allowfullscreen></iframe>
+<iframe title="YouTube video player" width="640" height="390" src="//www.youtube.com/embed/laLudeUmXHM?rel=0" frameborder="0" allowfullscreen></iframe>
 </p>
 
 <p>
@@ -458,5 +458,5 @@
 </p>
 
 <p>
-<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/B4M_a7xejYI?rel=0" frameborder="0" allowfullscreen></iframe>
+<iframe title="YouTube video player" width="640" height="390" src="//www.youtube.com/embed/B4M_a7xejYI?rel=0" frameborder="0" allowfullscreen></iframe>
 </p>
diff --git a/chrome/common/extensions/docs/templates/articles/extensions_index.html b/chrome/common/extensions/docs/templates/articles/extensions_index.html
index 182694c..0f317a8 100644
--- a/chrome/common/extensions/docs/templates/articles/extensions_index.html
+++ b/chrome/common/extensions/docs/templates/articles/extensions_index.html
@@ -65,5 +65,5 @@
 </p>
 
 <p>
-  <iframe title="YouTube video player" width="300" height="199" src="http://www.youtube.com/embed/wRDPTnY3yO8?rel=0" frameborder="0" allowfullscreen=""></iframe>
+  <iframe title="YouTube video player" width="300" height="199" src="//www.youtube.com/embed/wRDPTnY3yO8?rel=0" frameborder="0" allowfullscreen=""></iframe>
 </p>
diff --git a/chrome/common/extensions/docs/templates/articles/manifest/externally_connectable.html b/chrome/common/extensions/docs/templates/articles/manifest/externally_connectable.html
index 6eab3fe..e0a5e6d 100644
--- a/chrome/common/extensions/docs/templates/articles/manifest/externally_connectable.html
+++ b/chrome/common/extensions/docs/templates/articles/manifest/externally_connectable.html
@@ -1,7 +1,7 @@
 <h1>externally_connectable</h1>
 
 <p>
-The <code>externally_connectable</code> manifest property declares which extensions, apps, and web pages can connect to your extension via <a href="../runtime.html#method-connect">runtime.connect</a> and <a href="../runtime.html#method-sendMessage">runtime.sendMessage</a>.
+The <code>externally_connectable</code> manifest property declares which extensions, apps, and web pages can connect to your {{platform}} via <a href="../runtime.html#method-connect">runtime.connect</a> and <a href="../runtime.html#method-sendMessage">runtime.sendMessage</a>.
 </p>
 
 <p>
diff --git a/chrome/common/extensions/docs/templates/articles/manifest/kiosk_enabled.html b/chrome/common/extensions/docs/templates/articles/manifest/kiosk_enabled.html
index 0256389..8eb7b58 100644
--- a/chrome/common/extensions/docs/templates/articles/manifest/kiosk_enabled.html
+++ b/chrome/common/extensions/docs/templates/articles/manifest/kiosk_enabled.html
@@ -6,3 +6,10 @@
 display (forced full screen). The kiosk-enabled apps are expected to be designed
 with this constraint in mind.
 </p>
+
+<h1 id="kiosk_only">Manifest - Kiosk Only</h1>
+
+<p>
+Whether the packaged app is only intended to be installed and run in ChromeOS
+kiosk mode. This field is only valid if the <code>kiosk_enabled</code> field is <code>true</code>.
+</p>
diff --git a/chrome/common/extensions/docs/templates/json/manifest.json b/chrome/common/extensions/docs/templates/json/manifest.json
index b3ac91f..2cb5331 100644
--- a/chrome/common/extensions/docs/templates/json/manifest.json
+++ b/chrome/common/extensions/docs/templates/json/manifest.json
@@ -75,7 +75,11 @@
     "example": "publicKey"
   },
   "kiosk_enabled": {
-    "documentation": "manifest/kiosk_enabled.html",
+    "documentation": "manifest/kiosk_enabled.html#kiosk_enabled",
+    "example": true
+  },
+  "kiosk_only": {
+    "documentation": "manifest/kiosk_enabled.html#kiosk_only",
     "example": true
   },
   "manifest_version": {
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 7e75d73..2894283 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -87,6 +87,11 @@
 
 const char kGalleryBrowsePrefix[] = "https://chrome.google.com/webstore";
 
+const char kWebstoreSourceField[] = "utm_source";
+
+const char kLaunchSourceAppList[] = "chrome-app-launcher";
+const char kLaunchSourceAppListSearch[] = "chrome-app-launcher-search";
+
 }  // namespace extension_urls
 
 namespace extension_misc {
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 52eb362..7938d4f 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -54,6 +54,13 @@
   // The greatest common prefixes of the main extensions gallery's browse and
   // download URLs.
   extern const char kGalleryBrowsePrefix[];
+
+  // Field to use with webstore URL for tracking launch source.
+  extern const char kWebstoreSourceField[];
+
+  // Values to use with webstore URL launch source field.
+  extern const char kLaunchSourceAppList[];
+  extern const char kLaunchSourceAppListSearch[];
 }  // namespace extension_urls
 
 namespace extension_misc {
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 8d3b3e1..00a3275 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -168,9 +168,13 @@
   IPC_STRUCT_TRAITS_MEMBER(port)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(extensions::SocketPermissionEntry)
+  IPC_STRUCT_TRAITS_MEMBER(pattern_)
+  IPC_STRUCT_TRAITS_MEMBER(match_subdomains_)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(extensions::SocketPermissionData)
-  IPC_STRUCT_TRAITS_MEMBER(pattern())
-  IPC_STRUCT_TRAITS_MEMBER(match_subdomains())
+  IPC_STRUCT_TRAITS_MEMBER(entry())
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(extensions::UsbDevicePermissionData)
diff --git a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.cc b/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.cc
deleted file mode 100644
index 4c50de5..0000000
--- a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "extensions/common/manifest_constants.h"
-
-namespace extensions {
-
-namespace keys = manifest_keys;
-
-KioskEnabledInfo::KioskEnabledInfo(bool is_kiosk_enabled)
-    : kiosk_enabled(is_kiosk_enabled) {
-}
-
-KioskEnabledInfo::~KioskEnabledInfo() {
-}
-
-// static
-bool KioskEnabledInfo::IsKioskEnabled(const Extension* extension) {
-  KioskEnabledInfo* info = static_cast<KioskEnabledInfo*>(
-      extension->GetManifestData(keys::kKioskEnabled));
-  return info ? info->kiosk_enabled : false;
-}
-
-KioskEnabledHandler::KioskEnabledHandler() {
-}
-
-KioskEnabledHandler::~KioskEnabledHandler() {
-}
-
-bool KioskEnabledHandler::Parse(Extension* extension, string16* error) {
-  DCHECK(extension->manifest()->HasKey(keys::kKioskEnabled));
-
-  bool kiosk_enabled = false;
-  if (!extension->manifest()->GetBoolean(keys::kKioskEnabled, &kiosk_enabled)) {
-    *error = ASCIIToUTF16(manifest_errors::kInvalidKioskEnabled);
-    return false;
-  }
-
-  // All other use cases should be already filtered out by manifest feature
-  // checks.
-  DCHECK(extension->is_platform_app());
-
-  extension->SetManifestData(keys::kKioskEnabled,
-                             new KioskEnabledInfo(kiosk_enabled));
-  return true;
-}
-
-const std::vector<std::string> KioskEnabledHandler::Keys() const {
-  return SingleKey(keys::kKioskEnabled);
-}
-
-}  // namespace extensions
diff --git a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h b/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h
deleted file mode 100644
index 3c61b08..0000000
--- a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_KIOSK_ENABLED_INFO_H_
-#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_KIOSK_ENABLED_INFO_H_
-
-#include <string>
-#include <vector>
-
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest_handler.h"
-#include "extensions/common/manifest.h"
-
-namespace extensions {
-
-struct KioskEnabledInfo : public Extension::ManifestData {
-  explicit KioskEnabledInfo(bool is_kiosk_enabled);
-  virtual ~KioskEnabledInfo();
-
-  bool kiosk_enabled;
-
-  // Whether the extension or app should be enabled in app kiosk mode.
-  static bool IsKioskEnabled(const Extension* extension);
-};
-
-// Parses the "kiosk_enabled" manifest key.
-class KioskEnabledHandler : public ManifestHandler {
- public:
-  KioskEnabledHandler();
-  virtual ~KioskEnabledHandler();
-
-  virtual bool Parse(Extension* extension, string16* error) OVERRIDE;
- private:
-  virtual const std::vector<std::string> Keys() const OVERRIDE;
-
-  DISALLOW_COPY_AND_ASSIGN(KioskEnabledHandler);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_KIOSK_ENABLED_INFO_H_
diff --git a/chrome/common/extensions/manifest_handlers/kiosk_mode_info.cc b/chrome/common/extensions/manifest_handlers/kiosk_mode_info.cc
new file mode 100644
index 0000000..e610490
--- /dev/null
+++ b/chrome/common/extensions/manifest_handlers/kiosk_mode_info.cc
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors. 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/manifest_handlers/kiosk_mode_info.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+
+KioskModeInfo::KioskModeInfo(KioskStatus kiosk_status)
+    : kiosk_status(kiosk_status) {
+}
+
+KioskModeInfo::~KioskModeInfo() {
+}
+
+// static
+bool KioskModeInfo::IsKioskEnabled(const Extension* extension) {
+  KioskModeInfo* info = static_cast<KioskModeInfo*>(
+      extension->GetManifestData(keys::kKioskMode));
+  return info ? info->kiosk_status != NONE : false;
+}
+
+// static
+bool KioskModeInfo::IsKioskOnly(const Extension* extension) {
+  KioskModeInfo* info = static_cast<KioskModeInfo*>(
+      extension->GetManifestData(keys::kKioskMode));
+  return info ? info->kiosk_status == ONLY : false;
+}
+
+KioskModeHandler::KioskModeHandler() {
+  supported_keys_.push_back(keys::kKioskEnabled);
+  supported_keys_.push_back(keys::kKioskOnly);
+}
+
+KioskModeHandler::~KioskModeHandler() {
+}
+
+bool KioskModeHandler::Parse(Extension* extension, string16* error) {
+  const Manifest* manifest = extension->manifest();
+  DCHECK(manifest->HasKey(keys::kKioskEnabled) ||
+         manifest->HasKey(keys::kKioskOnly));
+
+  bool kiosk_enabled = false;
+  if (manifest->HasKey(keys::kKioskEnabled) &&
+      !manifest->GetBoolean(keys::kKioskEnabled, &kiosk_enabled)) {
+    *error = ASCIIToUTF16(manifest_errors::kInvalidKioskEnabled);
+    return false;
+  }
+
+  bool kiosk_only = false;
+  if (manifest->HasKey(keys::kKioskOnly) &&
+      !manifest->GetBoolean(keys::kKioskOnly, &kiosk_only)) {
+    *error = ASCIIToUTF16(manifest_errors::kInvalidKioskOnly);
+    return false;
+  }
+
+  if (kiosk_only && !kiosk_enabled) {
+    *error = ASCIIToUTF16(manifest_errors::kInvalidKioskOnlyButNotEnabled);
+    return false;
+  }
+
+  // All other use cases should be already filtered out by manifest feature
+  // checks.
+  DCHECK(extension->is_platform_app());
+
+  KioskModeInfo::KioskStatus kiosk_status = KioskModeInfo::NONE;
+  if (kiosk_enabled)
+    kiosk_status = kiosk_only ? KioskModeInfo::ONLY : KioskModeInfo::ENABLED;
+
+  extension->SetManifestData(keys::kKioskMode,
+      new KioskModeInfo(kiosk_status));
+
+  return true;
+}
+
+const std::vector<std::string> KioskModeHandler::Keys() const {
+  return supported_keys_;
+}
+
+}  // namespace extensions
diff --git a/chrome/common/extensions/manifest_handlers/kiosk_mode_info.h b/chrome/common/extensions/manifest_handlers/kiosk_mode_info.h
new file mode 100644
index 0000000..05a553a
--- /dev/null
+++ b/chrome/common/extensions/manifest_handlers/kiosk_mode_info.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_KIOSK_MODE_INFO_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_KIOSK_MODE_INFO_H_
+
+#include <string>
+#include <vector>
+
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest_handler.h"
+#include "extensions/common/manifest.h"
+
+namespace extensions {
+
+struct KioskModeInfo : public Extension::ManifestData {
+ public:
+  enum KioskStatus {
+    NONE,
+    ENABLED,
+    ONLY
+  };
+
+  explicit KioskModeInfo(KioskStatus kiosk_status);
+  virtual ~KioskModeInfo();
+
+  KioskStatus kiosk_status;
+
+  // Whether the extension or app is enabled for app kiosk mode.
+  static bool IsKioskEnabled(const Extension* extension);
+
+  // Whether the extension or app should only be available in kiosk mode.
+  static bool IsKioskOnly(const Extension* extension);
+};
+
+// Parses the "kiosk_enabled" and "kiosk_only" manifest keys.
+class KioskModeHandler : public ManifestHandler {
+ public:
+  KioskModeHandler();
+  virtual ~KioskModeHandler();
+
+  virtual bool Parse(Extension* extension, string16* error) OVERRIDE;
+
+ private:
+  virtual const std::vector<std::string> Keys() const OVERRIDE;
+
+  std::vector<std::string> supported_keys_;
+
+  DISALLOW_COPY_AND_ASSIGN(KioskModeHandler);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_KIOSK_MODE_INFO_H_
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
index b63abee..fa00693 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
@@ -3,55 +3,97 @@
 // found in the LICENSE file.
 
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h"
+#include "chrome/common/extensions/manifest_handlers/kiosk_mode_info.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
 
-class ExtensionManifestKioskEnabledTest : public ExtensionManifestTest {
+class ExtensionManifestKioskModeTest : public ExtensionManifestTest {
 };
 
-TEST_F(ExtensionManifestKioskEnabledTest, InvalidKioskEnabled) {
+TEST_F(ExtensionManifestKioskModeTest, InvalidKioskEnabled) {
   LoadAndExpectError("kiosk_enabled_invalid.json",
                      manifest_errors::kInvalidKioskEnabled);
 }
 
-TEST_F(ExtensionManifestKioskEnabledTest, KioskEnabledHostedApp) {
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledHostedApp) {
   scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("kiosk_enabled_hosted_app.json"));
-  EXPECT_FALSE(KioskEnabledInfo::IsKioskEnabled(extension.get()));
+  EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
 }
 
-TEST_F(ExtensionManifestKioskEnabledTest, KioskEnabledPackagedApp) {
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledPackagedApp) {
   scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("kiosk_enabled_packaged_app.json"));
-  EXPECT_FALSE(KioskEnabledInfo::IsKioskEnabled(extension.get()));
+  EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
 }
 
-TEST_F(ExtensionManifestKioskEnabledTest, KioskEnabledExtension) {
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledExtension) {
   scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("kiosk_enabled_extension.json"));
-  EXPECT_FALSE(KioskEnabledInfo::IsKioskEnabled(extension.get()));
+  EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
 }
 
-TEST_F(ExtensionManifestKioskEnabledTest, KioskEnabledPlatformApp) {
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledPlatformApp) {
   scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("kiosk_enabled_platform_app.json"));
-  EXPECT_TRUE(KioskEnabledInfo::IsKioskEnabled(extension.get()));
+  EXPECT_TRUE(KioskModeInfo::IsKioskEnabled(extension.get()));
 }
 
-TEST_F(ExtensionManifestKioskEnabledTest, KioskDisabledPlatformApp) {
+TEST_F(ExtensionManifestKioskModeTest, KioskDisabledPlatformApp) {
   scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("kiosk_disabled_platform_app.json"));
-  EXPECT_FALSE(KioskEnabledInfo::IsKioskEnabled(extension.get()));
+  EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
 }
 
-TEST_F(ExtensionManifestKioskEnabledTest, KioskDefaultPlatformApp) {
+TEST_F(ExtensionManifestKioskModeTest, KioskDefaultPlatformApp) {
   scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("kiosk_default_platform_app.json"));
-  EXPECT_FALSE(KioskEnabledInfo::IsKioskEnabled(extension.get()));
+  EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
+  EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledDefaultRequired) {
+  scoped_refptr<Extension> extension(
+      LoadAndExpectSuccess("kiosk_enabled_platform_app.json"));
+  EXPECT_TRUE(KioskModeInfo::IsKioskEnabled(extension.get()));
+  EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyPlatformApp) {
+  scoped_refptr<Extension> extension(
+      LoadAndExpectSuccess("kiosk_only_platform_app.json"));
+  EXPECT_TRUE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyInvalid) {
+  LoadAndExpectError("kiosk_only_invalid.json",
+                     manifest_errors::kInvalidKioskOnly);
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyButNotEnabled) {
+  LoadAndExpectError("kiosk_only_not_enabled.json",
+                     manifest_errors::kInvalidKioskOnlyButNotEnabled);
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyHostedApp) {
+  scoped_refptr<Extension> extension(
+      LoadAndExpectSuccess("kiosk_only_hosted_app.json"));
+  EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyPackagedApp) {
+  scoped_refptr<Extension> extension(
+      LoadAndExpectSuccess("kiosk_only_packaged_app.json"));
+  EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyExtension) {
+  scoped_refptr<Extension> extension(
+      LoadAndExpectSuccess("kiosk_only_extension.json"));
+  EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
 }
 
 }  // namespace extensions
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index 311aa3f..2775d78 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -151,6 +151,7 @@
     kWebRequest,
     kWebRequestBlocking,
     kWebRequestInternal,
+    kWebrtcLoggingPrivate,
     kWebstorePrivate,
     kWebView,
     kSystemCpu,
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index f57c58e..308aaef 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -234,6 +234,8 @@
     { APIPermission::kEnterprisePlatformKeysPrivate,
       "enterprise.platformKeysPrivate",
       APIPermissionInfo::kFlagCannotBeOptional },
+    { APIPermission::kWebrtcLoggingPrivate, "webrtcLoggingPrivate",
+      APIPermissionInfo::kFlagCannotBeOptional },
 
     // Full url access permissions.
     { APIPermission::kDebugger, "debugger",
diff --git a/chrome/common/extensions/permissions/permission_message.cc b/chrome/common/extensions/permissions/permission_message.cc
index b792ae9..006e91a 100644
--- a/chrome/common/extensions/permissions/permission_message.cc
+++ b/chrome/common/extensions/permissions/permission_message.cc
@@ -45,17 +45,27 @@
     default:
       message_id = kHosts4OrMore;
 
-    message = l10n_util::GetStringFUTF16(
-        IDS_EXTENSION_PROMPT_WARNING_HOSTS,
-        base::IntToString16(host_list.size()));
+      const int kRetainedFilesMessageIDs[6] = {
+          IDS_EXTENSION_PROMPT_WARNING_HOSTS_DEFAULT,
+          IDS_EXTENSION_PROMPT_WARNING_HOST_SINGULAR,
+          IDS_EXTENSION_PROMPT_WARNING_HOSTS_ZERO,
+          IDS_EXTENSION_PROMPT_WARNING_HOSTS_TWO,
+          IDS_EXTENSION_PROMPT_WARNING_HOSTS_FEW,
+          IDS_EXTENSION_PROMPT_WARNING_HOSTS_MANY,
+      };
+      std::vector<int> message_ids;
+      for (size_t i = 0; i < arraysize(kRetainedFilesMessageIDs); i++) {
+        message_ids.push_back(kRetainedFilesMessageIDs[i]);
+      }
+      message = l10n_util::GetPluralStringFUTF16(message_ids, host_list.size());
 
-    for (size_t i = 0; i < host_list.size(); ++i) {
-      if (i > 0)
-        details += ASCIIToUTF16("\n");
-      details += l10n_util::GetStringFUTF16(
-          IDS_EXTENSION_PROMPT_WARNING_HOST_LIST_ENTRY,
-          UTF8ToUTF16(host_list[i]));
-    }
+      for (size_t i = 0; i < host_list.size(); ++i) {
+        if (i > 0)
+          details += ASCIIToUTF16("\n");
+        details += l10n_util::GetStringFUTF16(
+            IDS_EXTENSION_PROMPT_WARNING_HOST_LIST_ENTRY,
+            UTF8ToUTF16(host_list[i]));
+      }
   }
 
   return PermissionMessage(message_id, message, details);
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 9991ecc..cd4a2e1 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -729,6 +729,7 @@
   skip.insert(APIPermission::kVirtualKeyboardPrivate);
   skip.insert(APIPermission::kWallpaperPrivate);
   skip.insert(APIPermission::kWebRequestInternal);
+  skip.insert(APIPermission::kWebrtcLoggingPrivate);
   skip.insert(APIPermission::kWebstorePrivate);
 
   // Warned as part of host permissions.
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index d1b70e9..1fc56c5 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -175,7 +175,7 @@
       PermissionsData::GetPermissionMessageDetailsStrings(extension.get());
   ASSERT_EQ(1u, warnings.size());
   ASSERT_EQ(1u, warnings_details.size());
-  EXPECT_EQ("Access your data on 5 website(s)", UTF16ToUTF8(warnings[0]));
+  EXPECT_EQ("Access your data on 5 websites", UTF16ToUTF8(warnings[0]));
   EXPECT_EQ("- www.a.com\n- www.b.com\n- www.c.com\n- www.d.com\n- www.e.com",
             UTF16ToUTF8(warnings_details[0]));
 }
diff --git a/chrome/common/extensions/permissions/socket_permission.cc b/chrome/common/extensions/permissions/socket_permission.cc
index ebf7205..9f2c35c 100644
--- a/chrome/common/extensions/permissions/socket_permission.cc
+++ b/chrome/common/extensions/permissions/socket_permission.cc
@@ -37,8 +37,8 @@
 bool SocketPermission::AddAnyHostMessage(PermissionMessages& messages) const {
   std::set<SocketPermissionData>::const_iterator i;
   for (i = data_set_.begin(); i != data_set_.end(); ++i) {
-    if (i->IsAddressBoundType() &&
-        i->GetHostType() == SocketPermissionData::ANY_HOST) {
+    if (i->entry().IsAddressBoundType() &&
+        i->entry().GetHostType() == SocketPermissionEntry::ANY_HOST) {
       messages.push_back(PermissionMessage(
           PermissionMessage::kSocketAnyHost,
           l10n_util::GetStringUTF16(
@@ -54,8 +54,8 @@
   std::set<string16> domains;
   std::set<SocketPermissionData>::const_iterator i;
   for (i = data_set_.begin(); i != data_set_.end(); ++i) {
-    if (i->GetHostType() == SocketPermissionData::HOSTS_IN_DOMAINS)
-      domains.insert(UTF8ToUTF16(i->GetHost()));
+    if (i->entry().GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS)
+      domains.insert(UTF8ToUTF16(i->entry().pattern().host));
   }
   if (!domains.empty()) {
     int id = (domains.size() == 1) ?
@@ -76,8 +76,8 @@
   std::set<string16> hostnames;
   std::set<SocketPermissionData>::const_iterator i;
   for (i = data_set_.begin(); i != data_set_.end(); ++i) {
-    if (i->GetHostType() == SocketPermissionData::SPECIFIC_HOSTS)
-      hostnames.insert(UTF8ToUTF16(i->GetHost()));
+    if (i->entry().GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS)
+      hostnames.insert(UTF8ToUTF16(i->entry().pattern().host));
   }
   if (!hostnames.empty()) {
     int id = (hostnames.size() == 1) ?
@@ -97,7 +97,8 @@
     PermissionMessages& messages) const {
   std::set<SocketPermissionData>::const_iterator i;
   for (i = data_set_.begin(); i != data_set_.end(); ++i) {
-    if (i->pattern().type == content::SocketPermissionRequest::NETWORK_STATE) {
+    if (i->entry().pattern().type ==
+        content::SocketPermissionRequest::NETWORK_STATE) {
       messages.push_back(PermissionMessage(
           PermissionMessage::kNetworkState,
           l10n_util::GetStringUTF16(
diff --git a/chrome/common/extensions/permissions/socket_permission_data.cc b/chrome/common/extensions/permissions/socket_permission_data.cc
index fc7908e..e87fd84 100644
--- a/chrome/common/extensions/permissions/socket_permission_data.cc
+++ b/chrome/common/extensions/permissions/socket_permission_data.cc
@@ -23,8 +23,6 @@
 using extensions::SocketPermissionData;
 
 const char kColon = ':';
-const char kDot = '.';
-const char kWildcard[] = "*";
 const char kInvalid[] = "invalid";
 const char kTCPConnect[] = "tcp-connect";
 const char kTCPListen[] = "tcp-listen";
@@ -34,8 +32,6 @@
 const char kResolveHost[] = "resolve-host";
 const char kResolveProxy[] = "resolve-proxy";
 const char kNetworkState[] = "network-state";
-const int kWildcardPortNumber = 0;
-const int kInvalidPort = -1;
 
 SocketPermissionRequest::OperationType StringToType(const std::string& s) {
   if (s == kTCPConnect)
@@ -80,52 +76,20 @@
   }
 }
 
-bool StartsOrEndsWithWhitespace(const std::string& str) {
-  if (str.find_first_not_of(kWhitespaceASCII) != 0)
-    return true;
-  if (str.find_last_not_of(kWhitespaceASCII) != str.length() - 1)
-    return true;
-  return false;
-}
-
 }  // namespace
 
 namespace extensions {
 
-SocketPermissionData::SocketPermissionData()
-  : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort) {
-  Reset();
-}
+SocketPermissionData::SocketPermissionData() { }
 
-SocketPermissionData::~SocketPermissionData() {
-}
+SocketPermissionData::~SocketPermissionData() { }
 
 bool SocketPermissionData::operator<(const SocketPermissionData& rhs) const {
-  if (pattern_.type < rhs.pattern_.type)
-    return true;
-  if (pattern_.type > rhs.pattern_.type)
-    return false;
-
-  if (pattern_.host < rhs.pattern_.host)
-    return true;
-  if (pattern_.host > rhs.pattern_.host)
-    return false;
-
-  if (match_subdomains_ < rhs.match_subdomains_)
-    return true;
-  if (match_subdomains_ > rhs.match_subdomains_)
-    return false;
-
-  if (pattern_.port < rhs.pattern_.port)
-    return true;
-  return false;
+  return entry_ < rhs.entry_;
 }
 
 bool SocketPermissionData::operator==(const SocketPermissionData& rhs) const {
-  return (pattern_.type == rhs.pattern_.type) &&
-         (pattern_.host == rhs.pattern_.host) &&
-         (match_subdomains_ == rhs.match_subdomains_) &&
-         (pattern_.port == rhs.pattern_.port);
+  return entry_ == rhs.entry_;
 }
 
 bool SocketPermissionData::Check(
@@ -136,41 +100,7 @@
       *static_cast<const SocketPermission::CheckParam*>(param);
   const SocketPermissionRequest &request = specific_param.request;
 
-  if (pattern_.type != request.type)
-    return false;
-
-  std::string lhost = StringToLowerASCII(request.host);
-  if (pattern_.host != lhost) {
-    if (!match_subdomains_)
-      return false;
-
-    if (!pattern_.host.empty()) {
-      // Do not wildcard part of IP address.
-      url_parse::Component component(0, lhost.length());
-      url_canon::RawCanonOutputT<char, 128> ignored_output;
-      url_canon::CanonHostInfo host_info;
-      url_canon::CanonicalizeIPAddress(lhost.c_str(), component,
-                                       &ignored_output, &host_info);
-      if (host_info.IsIPAddress())
-        return false;
-
-      // host should equal one or more chars + "." +  host_.
-      int i = lhost.length() - pattern_.host.length();
-      if (i < 2)
-        return false;
-
-      if (lhost.compare(i, pattern_.host.length(), pattern_.host) != 0)
-        return false;
-
-      if (lhost[i - 1] != kDot)
-        return false;
-    }
-  }
-
-  if (pattern_.port != request.port && pattern_.port != kWildcardPortNumber)
-    return false;
-
-  return true;
+  return entry_.Check(request);
 }
 
 scoped_ptr<base::Value> SocketPermissionData::ToValue() const {
@@ -185,95 +115,27 @@
   return Parse(spec);
 }
 
-bool SocketPermissionData::IsAddressBoundType() const {
-  return pattern_.type == SocketPermissionRequest::TCP_CONNECT ||
-      pattern_.type == SocketPermissionRequest::TCP_LISTEN ||
-      pattern_.type == SocketPermissionRequest::UDP_BIND ||
-      pattern_.type == SocketPermissionRequest::UDP_SEND_TO;
-}
-
-SocketPermissionData::HostType SocketPermissionData::GetHostType() const {
-  return pattern_.host.empty() ? SocketPermissionData::ANY_HOST :
-         match_subdomains_     ? SocketPermissionData::HOSTS_IN_DOMAINS :
-                                 SocketPermissionData::SPECIFIC_HOSTS;
-}
-
-const std::string SocketPermissionData::GetHost() const {
-  return pattern_.host;
-}
-
-content::SocketPermissionRequest& SocketPermissionData::pattern() {
-  // Clear the spec because the caller could mutate |this|.
-  spec_.clear();
-  return pattern_;
-}
-
-bool& SocketPermissionData::match_subdomains() {
-  // Clear the spec because the caller could mutate |this|.
-  spec_.clear();
-  return match_subdomains_;
+SocketPermissionEntry& SocketPermissionData::entry() {
+   // Clear the spec because the caller could mutate |this|.
+   spec_.clear();
+  return entry_;
 }
 
 // TODO(ikarienator): Rewrite this method to support IPv6.
 bool SocketPermissionData::Parse(const std::string& permission) {
-  do {
-    pattern_.host.clear();
-    match_subdomains_ = true;
-    pattern_.port = kWildcardPortNumber;
-    spec_.clear();
-
-    std::vector<std::string> tokens;
-    base::SplitStringDontTrim(permission, kColon, &tokens);
-
-    if (tokens.empty() || tokens.size() > 3)
-      break;
-
-    pattern_.type = StringToType(tokens[0]);
-    if (pattern_.type == SocketPermissionRequest::NONE)
-      break;
-
-    if (tokens.size() == 1)
-      return true;
-
-    // Return an error if address is specified for permissions that don't
-    // need it (such as 'resolve-host').
-    if (!IsAddressBoundType())
-      break;
-
-    pattern_.host = tokens[1];
-    if (!pattern_.host.empty()) {
-      if (StartsOrEndsWithWhitespace(pattern_.host))
-        break;
-      pattern_.host = StringToLowerASCII(pattern_.host);
-
-      // The first component can optionally be '*' to match all subdomains.
-      std::vector<std::string> host_components;
-      base::SplitString(pattern_.host, kDot, &host_components);
-      DCHECK(!host_components.empty());
-
-      if (host_components[0] == kWildcard || host_components[0].empty()) {
-        host_components.erase(host_components.begin(),
-                              host_components.begin() + 1);
-      } else {
-        match_subdomains_ = false;
-      }
-      pattern_.host = JoinString(host_components, kDot);
-    }
-
-    if (tokens.size() == 2 || tokens[2].empty() || tokens[2] == kWildcard)
-      return true;
-
-    if (StartsOrEndsWithWhitespace(tokens[2]))
-      break;
-
-    if (!base::StringToInt(tokens[2], &pattern_.port) ||
-        pattern_.port < 1 || pattern_.port > 65535)
-      break;
-    return true;
-  } while (false);
-
   Reset();
-  return false;
+
+  std::vector<std::string> tokens;
+  base::SplitStringDontTrim(permission, kColon, &tokens);
+  if (tokens.empty())
+    return false;
+
+  SocketPermissionRequest::OperationType type = StringToType(tokens[0]);
+  if (type == SocketPermissionRequest::NONE)
+    return false;
+
+  tokens.erase(tokens.begin());
+  return SocketPermissionEntry::ParseHostPattern(type, tokens, &entry_);
 }
 
 const std::string& SocketPermissionData::GetAsString() const {
@@ -281,32 +143,16 @@
     return spec_;
 
   spec_.reserve(64);
-  spec_.append(TypeToString(pattern_.type));
-
-  if (!IsAddressBoundType())
-    return spec_;
-
-  if (match_subdomains_) {
-    spec_.append(1, kColon).append(kWildcard);
-    if (!pattern_.host.empty())
-      spec_.append(1, kDot).append(pattern_.host);
-  } else {
-     spec_.append(1, kColon).append(pattern_.host);
+  spec_.append(TypeToString(entry_.pattern().type));
+  std::string pattern = entry_.GetHostPatternAsString();
+  if (!pattern.empty()) {
+    spec_.append(1, kColon).append(pattern);
   }
-
-  if (pattern_.port == kWildcardPortNumber)
-    spec_.append(1, kColon).append(kWildcard);
-  else
-    spec_.append(1, kColon).append(base::IntToString(pattern_.port));
-
   return spec_;
 }
 
 void SocketPermissionData::Reset() {
-  pattern_.type = SocketPermissionRequest::NONE;
-  pattern_.host.clear();
-  match_subdomains_ = false;
-  pattern_.port = kInvalidPort;
+  entry_ = SocketPermissionEntry();
   spec_.clear();
 }
 
diff --git a/chrome/common/extensions/permissions/socket_permission_data.h b/chrome/common/extensions/permissions/socket_permission_data.h
index 1a23cc2..d647568 100644
--- a/chrome/common/extensions/permissions/socket_permission_data.h
+++ b/chrome/common/extensions/permissions/socket_permission_data.h
@@ -6,9 +6,11 @@
 
 #include <string>
 
-#include "base/memory/scoped_ptr.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
-#include "content/public/common/socket_permission_request.h"
+#include "chrome/common/extensions/permissions/socket_permission_entry.h"
+#include "ipc/ipc_param_traits.h"
+
+template <class T> struct FuzzTraits;
 
 namespace extensions {
 
@@ -35,12 +37,6 @@
 // The multicast membership permission implies a permission to any address.
 class SocketPermissionData {
  public:
-  enum HostType {
-    ANY_HOST,
-    HOSTS_IN_DOMAINS,
-    SPECIFIC_HOSTS,
-  };
-
   SocketPermissionData();
   ~SocketPermissionData();
 
@@ -59,33 +55,26 @@
   // Populate |this| from a base::Value.
   bool FromValue(const base::Value* value);
 
-  // Returns true if the permission type can be bound to a host or port.
-  bool IsAddressBoundType() const;
-
-  HostType GetHostType() const;
-  const std::string GetHost() const;
-
-  const content::SocketPermissionRequest& pattern() const { return pattern_; }
-  const bool& match_subdomains() const { return match_subdomains_; }
-
-  // These accessors are provided for IPC_STRUCT_TRAITS_MEMBER.  Please
-  // think twice before using them for anything else.
-  content::SocketPermissionRequest& pattern();
-  bool& match_subdomains();
-
   // TODO(bryeung): SocketPermissionData should be encoded as a base::Value
   // instead of a string.  Until that is done, expose these methods for
   // testing.
   bool ParseForTest(const std::string& permission) { return Parse(permission); }
   const std::string& GetAsStringForTest() const { return GetAsString(); }
 
+  const SocketPermissionEntry& entry() const { return entry_; }
+
  private:
+  // Friend so ParamTraits can serialize us.
+  friend struct IPC::ParamTraits<SocketPermissionData>;
+  friend struct FuzzTraits<SocketPermissionData>;
+
+  SocketPermissionEntry& entry();
+
   bool Parse(const std::string& permission);
   const std::string& GetAsString() const;
   void Reset();
 
-  content::SocketPermissionRequest pattern_;
-  bool match_subdomains_;
+  SocketPermissionEntry entry_;
   mutable std::string spec_;
 };
 
diff --git a/chrome/common/extensions/permissions/socket_permission_entry.cc b/chrome/common/extensions/permissions/socket_permission_entry.cc
new file mode 100644
index 0000000..17f2ef7
--- /dev/null
+++ b/chrome/common/extensions/permissions/socket_permission_entry.cc
@@ -0,0 +1,227 @@
+// Copyright 2013 The Chromium Authors. 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/permissions/socket_permission_entry.h"
+
+#include <cstdlib>
+#include <sstream>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/extensions/permissions/api_permission.h"
+#include "chrome/common/extensions/permissions/socket_permission.h"
+#include "url/url_canon.h"
+
+namespace {
+
+using content::SocketPermissionRequest;
+
+const char kColon = ':';
+const char kDot = '.';
+const char kWildcard[] = "*";
+const int kWildcardPortNumber = 0;
+const int kInvalidPort = -1;
+
+bool StartsOrEndsWithWhitespace(const std::string& str) {
+  if (str.find_first_not_of(kWhitespaceASCII) != 0)
+    return true;
+  if (str.find_last_not_of(kWhitespaceASCII) != str.length() - 1)
+    return true;
+  return false;
+}
+
+}  // namespace
+
+namespace extensions {
+
+SocketPermissionEntry::SocketPermissionEntry()
+  : pattern_(SocketPermissionRequest::NONE, std::string(), kInvalidPort),
+    match_subdomains_(false) {
+}
+
+SocketPermissionEntry::~SocketPermissionEntry() {}
+
+bool SocketPermissionEntry::operator<(const SocketPermissionEntry& rhs) const {
+  if (pattern_.type < rhs.pattern_.type)
+    return true;
+  if (pattern_.type > rhs.pattern_.type)
+    return false;
+
+  if (pattern_.host < rhs.pattern_.host)
+    return true;
+  if (pattern_.host > rhs.pattern_.host)
+    return false;
+
+  if (match_subdomains_ < rhs.match_subdomains_)
+    return true;
+  if (match_subdomains_ > rhs.match_subdomains_)
+    return false;
+
+  if (pattern_.port < rhs.pattern_.port)
+    return true;
+  return false;
+}
+
+bool SocketPermissionEntry::operator==(const SocketPermissionEntry& rhs) const {
+  return (pattern_.type == rhs.pattern_.type) &&
+         (pattern_.host == rhs.pattern_.host) &&
+         (match_subdomains_ == rhs.match_subdomains_) &&
+         (pattern_.port == rhs.pattern_.port);
+}
+
+bool SocketPermissionEntry::Check(
+    const content::SocketPermissionRequest& request) const {
+  if (pattern_.type != request.type)
+    return false;
+
+  std::string lhost = StringToLowerASCII(request.host);
+  if (pattern_.host != lhost) {
+    if (!match_subdomains_)
+      return false;
+
+    if (!pattern_.host.empty()) {
+      // Do not wildcard part of IP address.
+      url_parse::Component component(0, lhost.length());
+      url_canon::RawCanonOutputT<char, 128> ignored_output;
+      url_canon::CanonHostInfo host_info;
+      url_canon::CanonicalizeIPAddress(lhost.c_str(), component,
+                                       &ignored_output, &host_info);
+      if (host_info.IsIPAddress())
+        return false;
+
+      // host should equal one or more chars + "." +  host_.
+      int i = lhost.length() - pattern_.host.length();
+      if (i < 2)
+        return false;
+
+      if (lhost.compare(i, pattern_.host.length(), pattern_.host) != 0)
+        return false;
+
+      if (lhost[i - 1] != kDot)
+        return false;
+    }
+  }
+
+  if (pattern_.port != request.port && pattern_.port != kWildcardPortNumber)
+    return false;
+
+  return true;
+}
+
+SocketPermissionEntry::HostType SocketPermissionEntry::GetHostType() const {
+  return pattern_.host.empty() ? SocketPermissionEntry::ANY_HOST :
+         match_subdomains_     ? SocketPermissionEntry::HOSTS_IN_DOMAINS :
+                                 SocketPermissionEntry::SPECIFIC_HOSTS;
+}
+
+bool SocketPermissionEntry::IsAddressBoundType() const {
+  return pattern_.type == SocketPermissionRequest::TCP_CONNECT ||
+      pattern_.type == SocketPermissionRequest::TCP_LISTEN ||
+      pattern_.type == SocketPermissionRequest::UDP_BIND ||
+      pattern_.type == SocketPermissionRequest::UDP_SEND_TO;
+}
+
+// static
+bool SocketPermissionEntry::ParseHostPattern(
+    SocketPermissionRequest::OperationType type,
+    const std::string& pattern,
+    SocketPermissionEntry* entry) {
+  std::vector<std::string> tokens;
+  base::SplitStringDontTrim(pattern, kColon, &tokens);
+  return ParseHostPattern(type, tokens, entry);
+}
+
+// static
+bool SocketPermissionEntry::ParseHostPattern(
+    SocketPermissionRequest::OperationType type,
+    const std::vector<std::string>& pattern_tokens,
+    SocketPermissionEntry* entry) {
+
+  SocketPermissionEntry result;
+
+  if (type == SocketPermissionRequest::NONE)
+    return false;
+
+  if (pattern_tokens.size() > 2)
+    return false;
+
+  result.pattern_.type = type;
+  result.pattern_.port = kWildcardPortNumber;
+  result.match_subdomains_ = true;
+
+  if (pattern_tokens.size() == 0) {
+    *entry = result;
+    return true;
+  }
+
+    // Return an error if address is specified for permissions that don't
+    // need it (such as 'resolve-host').
+    if (!result.IsAddressBoundType())
+      return false;
+
+  result.pattern_.host = pattern_tokens[0];
+  if (!result.pattern_.host.empty()) {
+    if (StartsOrEndsWithWhitespace(result.pattern_.host))
+      return false;
+    result.pattern_.host = StringToLowerASCII(result.pattern_.host);
+
+    // The first component can optionally be '*' to match all subdomains.
+    std::vector<std::string> host_components;
+    base::SplitString(result.pattern_.host, kDot, &host_components);
+    DCHECK(!host_components.empty());
+
+    if (host_components[0] == kWildcard || host_components[0].empty()) {
+      host_components.erase(host_components.begin(),
+                            host_components.begin() + 1);
+    } else {
+      result.match_subdomains_ = false;
+    }
+    result.pattern_.host = JoinString(host_components, kDot);
+  }
+
+  if (pattern_tokens.size() == 1 ||
+      pattern_tokens[1].empty() ||
+      pattern_tokens[1] == kWildcard) {
+    *entry = result;
+    return true;
+  }
+
+  if (StartsOrEndsWithWhitespace(pattern_tokens[1]))
+    return false;
+
+  if (!base::StringToInt(pattern_tokens[1], &result.pattern_.port) ||
+      result.pattern_.port < 1 || result.pattern_.port > 65535)
+    return false;
+
+  *entry = result;
+  return true;
+}
+
+std::string SocketPermissionEntry::GetHostPatternAsString() const {
+  std::string result;
+
+  if (!IsAddressBoundType())
+    return result;
+
+  if (match_subdomains()) {
+    result.append(kWildcard);
+    if (!pattern_.host.empty())
+      result.append(1, kDot).append(pattern_.host);
+  } else {
+     result.append(pattern_.host);
+  }
+
+  if (pattern_.port == kWildcardPortNumber)
+    result.append(1, kColon).append(kWildcard);
+  else
+    result.append(1, kColon).append(base::IntToString(pattern_.port));
+
+  return result;
+}
+
+}  // namespace extensions
diff --git a/chrome/common/extensions/permissions/socket_permission_entry.h b/chrome/common/extensions/permissions/socket_permission_entry.h
new file mode 100644
index 0000000..b656471
--- /dev/null
+++ b/chrome/common/extensions/permissions/socket_permission_entry.h
@@ -0,0 +1,82 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CHROME_COMMON_EXTENSIONS_PERMISSIONS_SOCKET_PERMISSION_ENTRY_H_
+#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_SOCKET_PERMISSION_ENTRY_H_
+
+#include <string>
+#include <vector>
+
+#include "content/public/common/socket_permission_request.h"
+#include "ipc/ipc_param_traits.h"
+
+template <class T> struct FuzzTraits;
+
+namespace extensions {
+
+// Internal representation of a socket permission for a specific operation, such
+// as UDP "bind", host 127.0.0.1, port *.
+class SocketPermissionEntry {
+ public:
+  enum HostType {
+    ANY_HOST,
+    HOSTS_IN_DOMAINS,
+    SPECIFIC_HOSTS,
+  };
+
+  SocketPermissionEntry();
+  ~SocketPermissionEntry();
+
+  // operators <, == are needed by container std::set and algorithms
+  // std::set_includes and std::set_differences.
+  bool operator<(const SocketPermissionEntry& rhs) const;
+  bool operator==(const SocketPermissionEntry& rhs) const;
+
+  bool Check(const content::SocketPermissionRequest& request) const;
+
+  // Parse a host:port pattern for a given operation type.
+  //   <pattern> := '' |
+  //                <host> |
+  //                ':' <port> |
+  //                <host> ':' <port> |
+  //
+  //   <host> := '*' |
+  //             '*.' <anychar except '/' and '*'>+ |
+  //             <anychar except '/' and '*'>+
+  //
+  //   <port> := '*' |
+  //             <port number between 0 and 65535>)
+  static bool ParseHostPattern(
+      content::SocketPermissionRequest::OperationType type,
+      const std::string& pattern,
+      SocketPermissionEntry* entry);
+
+  static bool ParseHostPattern(
+      content::SocketPermissionRequest::OperationType type,
+      const std::vector<std::string>& pattern_tokens,
+      SocketPermissionEntry* entry);
+
+  // Returns true if the permission type can be bound to a host or port.
+  bool IsAddressBoundType() const;
+
+  std::string GetHostPatternAsString() const;
+  HostType GetHostType() const;
+
+  const content::SocketPermissionRequest& pattern() const { return pattern_; }
+  bool match_subdomains() const { return match_subdomains_; }
+
+ private:
+  // Friend so ParamTraits can serialize us.
+  friend struct IPC::ParamTraits<SocketPermissionEntry>;
+  friend struct FuzzTraits<SocketPermissionEntry>;
+
+  // The permission type, host and port.
+  content::SocketPermissionRequest pattern_;
+
+  // True if there was a wildcard in the host name.
+  bool match_subdomains_;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_COMMON_EXTENSIONS_PERMISSIONS_SOCKET_PERMISSION_ENTRY_H_
diff --git a/chrome/common/external_ipc_fuzzer.cc b/chrome/common/external_ipc_fuzzer.cc
index 9e125cc..10416c4 100644
--- a/chrome/common/external_ipc_fuzzer.cc
+++ b/chrome/common/external_ipc_fuzzer.cc
@@ -6,17 +6,16 @@
 
 #if defined(OS_LINUX)
 #include <dlfcn.h>
-#endif
 
 typedef IPC::ChannelProxy::OutgoingMessageFilter *(*GetFuzzerFunction)();
 const char kFuzzLibraryName[] = "libipcfuzz.so";
 const char kFuzzEntryName[] = "GetFilter";
+#endif
 
 IPC::ChannelProxy::OutgoingMessageFilter* LoadExternalIPCFuzzer() {
   IPC::ChannelProxy::OutgoingMessageFilter* result = NULL;
 
 #if defined(OS_LINUX)
-
   // Fuzz is currently linux-only feature
   void *fuzz_library =  dlopen(kFuzzLibraryName, RTLD_NOW);
   if (fuzz_library) {
diff --git a/chrome/common/icon_with_badge_image_source.cc b/chrome/common/icon_with_badge_image_source.cc
index 1665030..007292c 100644
--- a/chrome/common/icon_with_badge_image_source.cc
+++ b/chrome/common/icon_with_badge_image_source.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/icon_with_badge_image_source.h"
 
 #include "chrome/common/badge_util.h"
+//#include "ui/base/layout.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/rect.h"
 
diff --git a/chrome/common/importer/OWNERS b/chrome/common/importer/OWNERS
index 66d2678..6238904 100644
--- a/chrome/common/importer/OWNERS
+++ b/chrome/common/importer/OWNERS
@@ -8,5 +8,4 @@
 per-file *_messages*.h=cevans@chromium.org
 per-file *_messages*.h=inferno@chromium.org
 per-file *_messages*.h=jschuh@chromium.org
-per-file *_messages*.h=palmer@chromium.org
 per-file *_messages*.h=tsepez@chromium.org
diff --git a/chrome/common/local_discovery/local_discovery_messages.h b/chrome/common/local_discovery/local_discovery_messages.h
index a5ebccc..1add9a2 100644
--- a/chrome/common/local_discovery/local_discovery_messages.h
+++ b/chrome/common/local_discovery/local_discovery_messages.h
@@ -73,6 +73,9 @@
 // Utility process host messages:
 // These are messages from the utility process to the browser.
 
+// Notifies browser process if process failed.
+IPC_MESSAGE_CONTROL0(LocalDiscoveryHostMsg_Error)
+
 // Notifies browser process about new services.
 IPC_MESSAGE_CONTROL3(LocalDiscoveryHostMsg_WatcherCallback,
                      uint64 /* id */,
diff --git a/chrome/common/localized_error.cc b/chrome/common/localized_error.cc
index 893e379..c9d774c 100644
--- a/chrome/common/localized_error.cc
+++ b/chrome/common/localized_error.cc
@@ -491,7 +491,9 @@
 
 const char LocalizedError::kHttpErrorDomain[] = "http";
 
-void LocalizedError::GetStrings(const WebKit::WebURLError& error,
+void LocalizedError::GetStrings(int error_code,
+                                const std::string& error_domain,
+                                const GURL& failed_url,
                                 bool is_post,
                                 const std::string& locale,
                                 base::DictionaryValue* error_strings) {
@@ -509,15 +511,11 @@
     SUGGEST_NONE,
   };
 
-  const std::string error_domain = error.domain.utf8();
-  int error_code = error.reason;
   const LocalizedErrorMap* error_map = LookupErrorMap(error_domain, error_code,
                                                       is_post);
   if (error_map)
     options = *error_map;
 
-  const GURL failed_url = error.unreachableURL;
-
   // If we got "access denied" but the url was a file URL, then we say it was a
   // file instead of just using the "not available" default message. Just adding
   // ERR_ACCESS_DENIED to the map isn't sufficient, since that message may be
@@ -788,7 +786,6 @@
 }
 
 void LocalizedError::GetAppErrorStrings(
-    const WebURLError& error,
     const GURL& display_url,
     const extensions::Extension* app,
     base::DictionaryValue* error_strings) {
diff --git a/chrome/common/localized_error.h b/chrome/common/localized_error.h
index 3fb8b28..7323c59 100644
--- a/chrome/common/localized_error.h
+++ b/chrome/common/localized_error.h
@@ -28,7 +28,9 @@
  public:
   // Fills |error_strings| with values to be used to build an error page used
   // on HTTP errors, like 404 or connection reset.
-  static void GetStrings(const WebKit::WebURLError& error,
+  static void GetStrings(int error_code,
+                         const std::string& error_domain,
+                         const GURL& failed_url,
                          bool is_post,
                          const std::string& locale,
                          base::DictionaryValue* strings);
@@ -44,8 +46,7 @@
   // on HTTP errors, like 404 or connection reset, but using information from
   // the associated |app| in order to make the error page look like it's more
   // part of the app.
-  static void GetAppErrorStrings(const WebKit::WebURLError& error,
-                                 const GURL& display_url,
+  static void GetAppErrorStrings(const GURL& display_url,
                                  const extensions::Extension* app,
                                  base::DictionaryValue* error_strings);
 
diff --git a/chrome/common/metrics/variations/variations_util.cc b/chrome/common/metrics/variations/variations_util.cc
index 5ef0bf8..0ae01e1 100644
--- a/chrome/common/metrics/variations/variations_util.cc
+++ b/chrome/common/metrics/variations/variations_util.cc
@@ -13,6 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/child_process_logging.h"
+#include "chrome/common/crash_keys.h"
 #include "chrome/installer/util/google_update_experiment_util.h"
 
 namespace chrome_variations {
@@ -68,39 +69,20 @@
 }
 
 void GetFieldTrialActiveGroupIdsAsStrings(
-    std::vector<string16>* output) {
+    std::vector<std::string>* output) {
   DCHECK(output->empty());
   std::vector<ActiveGroupId> name_group_ids;
   GetFieldTrialActiveGroupIds(&name_group_ids);
   for (size_t i = 0; i < name_group_ids.size(); ++i) {
-    output->push_back(UTF8ToUTF16(base::StringPrintf(
-        "%x-%x", name_group_ids[i].name, name_group_ids[i].group)));
+    output->push_back(base::StringPrintf(
+        "%x-%x", name_group_ids[i].name, name_group_ids[i].group));
   }
 }
 
-void GenerateVariationChunks(const std::vector<string16>& experiments,
-                             std::vector<string16>* chunks) {
-  string16 current_chunk;
-  for (size_t i = 0; i < experiments.size(); ++i) {
-    const size_t needed_length =
-        (current_chunk.empty() ? 1 : 0) + experiments[i].length();
-    if (current_chunk.length() + needed_length > kMaxVariationChunkSize) {
-      chunks->push_back(current_chunk);
-      current_chunk = experiments[i];
-    } else {
-      if (!current_chunk.empty())
-        current_chunk.push_back(',');
-      current_chunk += experiments[i];
-    }
-  }
-  if (!current_chunk.empty())
-    chunks->push_back(current_chunk);
-}
-
 void SetChildProcessLoggingVariationList() {
-  std::vector<string16> experiment_strings;
+  std::vector<std::string> experiment_strings;
   GetFieldTrialActiveGroupIdsAsStrings(&experiment_strings);
-  child_process_logging::SetExperimentList(experiment_strings);
+  crash_keys::SetVariationsList(experiment_strings);
 }
 
 string16 BuildGoogleUpdateExperimentLabel(
diff --git a/chrome/common/metrics/variations/variations_util.h b/chrome/common/metrics/variations/variations_util.h
index cd0c787..d32cae7 100644
--- a/chrome/common/metrics/variations/variations_util.h
+++ b/chrome/common/metrics/variations/variations_util.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_COMMON_METRICS_VARIATIONS_VARIATIONS_UTIL_H_
 #define CHROME_COMMON_METRICS_VARIATIONS_VARIATIONS_UTIL_H_
 
+#include <string>
 #include <vector>
 
 #include "base/metrics/field_trial.h"
@@ -24,12 +25,7 @@
 // has a chosen group. The strings are formatted as "<TrialName>-<GroupName>",
 // with the names as hex strings. Field Trials for which a group has not been
 // chosen yet are NOT returned in this list.
-void GetFieldTrialActiveGroupIdsAsStrings(std::vector<string16>* output);
-
-// Generates variation chunks from |variation_strings| that are suitable for
-// crash reporting.
-void GenerateVariationChunks(const std::vector<string16>& variation_strings,
-                             std::vector<string16>* chunks);
+void GetFieldTrialActiveGroupIdsAsStrings(std::vector<std::string>* output);
 
 // Get the current set of chosen FieldTrial groups (aka variations) and send
 // them to the child process logging module so it can save it for crash dumps.
diff --git a/chrome/common/metrics/variations/variations_util_unittest.cc b/chrome/common/metrics/variations/variations_util_unittest.cc
index 1f9e140..e14d53a 100644
--- a/chrome/common/metrics/variations/variations_util_unittest.cc
+++ b/chrome/common/metrics/variations/variations_util_unittest.cc
@@ -104,60 +104,6 @@
   EXPECT_EQ(0U, expected_groups.size());
 }
 
-TEST_F(VariationsUtilTest, GenerateExperimentChunks) {
-  const char* kExperimentStrings[] = {
-      "1d3048f1-9de009d0",
-      "cd73da34-cf196cb",
-      "6214fa18-9e6dc24d",
-      "4dcb0cd6-d31c4ca1",
-      "9d5bce6-30d7d8ac",
-  };
-  const char* kExpectedChunks1[] = {
-      "1d3048f1-9de009d0",
-  };
-  const char* kExpectedChunks2[] = {
-      "1d3048f1-9de009d0,cd73da34-cf196cb",
-  };
-  const char* kExpectedChunks3[] = {
-      "1d3048f1-9de009d0,cd73da34-cf196cb,6214fa18-9e6dc24d",
-  };
-  const char* kExpectedChunks4[] = {
-      "1d3048f1-9de009d0,cd73da34-cf196cb,6214fa18-9e6dc24d",
-      "4dcb0cd6-d31c4ca1",
-  };
-  const char* kExpectedChunks5[] = {
-      "1d3048f1-9de009d0,cd73da34-cf196cb,6214fa18-9e6dc24d",
-      "4dcb0cd6-d31c4ca1,9d5bce6-30d7d8ac",
-  };
-
-  struct {
-    size_t strings_length;
-    size_t expected_chunks_length;
-    const char** expected_chunks;
-  } cases[] = {
-    { 0, 0, NULL },
-    { 1, arraysize(kExpectedChunks1), kExpectedChunks1 },
-    { 2, arraysize(kExpectedChunks2), kExpectedChunks2 },
-    { 3, arraysize(kExpectedChunks3), kExpectedChunks3 },
-    { 4, arraysize(kExpectedChunks4), kExpectedChunks4 },
-    { 5, arraysize(kExpectedChunks5), kExpectedChunks5 },
-  };
-
-  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
-    ASSERT_LE(cases[i].strings_length, arraysize(kExperimentStrings));
-
-    std::vector<string16> experiments;
-    for (size_t j = 0; j < cases[i].strings_length; ++j)
-      experiments.push_back(UTF8ToUTF16(kExperimentStrings[j]));
-
-    std::vector<string16> chunks;
-    GenerateVariationChunks(experiments, &chunks);
-    ASSERT_EQ(cases[i].expected_chunks_length, chunks.size());
-    for (size_t j = 0; j < chunks.size(); ++j)
-      EXPECT_EQ(UTF8ToUTF16(cases[i].expected_chunks[j]), chunks[j]);
-  }
-}
-
 TEST_F(VariationsUtilTest, BuildGoogleUpdateExperimentLabel) {
   struct {
     const char* active_group_pairs;
diff --git a/chrome/common/omaha_query_params/omaha_query_params.cc b/chrome/common/omaha_query_params/omaha_query_params.cc
index f320310..f68c9be 100644
--- a/chrome/common/omaha_query_params/omaha_query_params.cc
+++ b/chrome/common/omaha_query_params/omaha_query_params.cc
@@ -46,14 +46,18 @@
 #endif
 
 const char kChrome[] = "chrome";
-const char kChromeCrx[] = "chromecrx";
-const char kChromiumCrx[] = "chromiumcrx";
 
 const char kStable[] = "stable";
 const char kBeta[] = "beta";
 const char kDev[] = "dev";
 const char kCanary[] = "canary";
 
+#if defined(GOOGLE_CHROME_BUILD)
+const char kChromeCrx[] = "chromecrx";
+#else
+const char kChromiumCrx[] = "chromiumcrx";
+#endif  // defined(GOOGLE_CHROME_BUILD)
+
 }  // namespace
 
 namespace chrome {
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index d7e195b..1ff7bde 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -844,6 +844,16 @@
 // A boolean pref that tracks whether the user indicated they wish to be asked
 // for consent for every site that uses remote attestation.
 const char kRAConsentAlways[] = "settings.privacy.ra_consent_always";
+
+// A boolean pref recording whether user has dismissed the multiprofile
+// notification.
+const char kMultiProfileNotificationDismissed[] =
+    "settings.multi_profile_notification_dismissed";
+
+// A string pref that holds string enum values of how the user should behave
+// in a multiprofile session. See ChromeOsMultiProfileUserBehavior policy
+// for more details of the valid values.
+const char kMultiProfileUserBehavior[] = "settings.multiprofile_user_behavior";
 #endif  // defined(OS_CHROMEOS)
 
 // The disabled messages in IPC logging.
@@ -1233,6 +1243,11 @@
 // platforms.
 extern const char kFullscreenAllowed[] = "fullscreen.allowed";
 
+// Enable notifications for new devices on the local network that can be
+// registered to the user's account, e.g. Google Cloud Print printers.
+const char kLocalDiscoveryNotificationsEnabled[] =
+    "local_discovery.notifications_enabled";
+
 // *************** LOCAL STATE ***************
 // These are attached to the machine/installation
 
@@ -1688,33 +1703,6 @@
 // Boolean indicating whether the web store is active for the current locale.
 const char kNtpWebStoreEnabled[] = "ntp.webstore_enabled";
 
-// The id of the last web store promo actually displayed on the NTP.
-const char kNtpWebStorePromoLastId[] = "ntp.webstore_last_promo_id";
-
-// The id of the current web store promo.
-const char kNtpWebStorePromoId[] = "ntp.webstorepromo.id";
-
-// The header line for the NTP web store promo.
-const char kNtpWebStorePromoHeader[] = "ntp.webstorepromo.header";
-
-// The button text for the NTP web store promo.
-const char kNtpWebStorePromoButton[] = "ntp.webstorepromo.button";
-
-// The button link for the NTP web store promo.
-const char kNtpWebStorePromoLink[] = "ntp.webstorepromo.link";
-
-// The image URL for the NTP web store promo logo.
-const char kNtpWebStorePromoLogo[] = "ntp.webstorepromo.logo";
-
-// The original URL for the NTP web store promo logo.
-const char kNtpWebStorePromoLogoSource[] = "ntp.webstorepromo.logo_source";
-
-// The "hide this" link text for the NTP web store promo.
-const char kNtpWebStorePromoExpire[] = "ntp.webstorepromo.expire";
-
-// Specifies what users should maximize the NTP web store promo.
-const char kNtpWebStorePromoUserGroup[] = "ntp.webstorepromo.usergroup";
-
 // Customized app page names that appear on the New Tab Page.
 const char kNtpAppPageNames[] = "ntp.app_page_names";
 
@@ -1999,30 +1987,36 @@
 const char kHttpOriginalContentLength[] = "http_original_content_length";
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
-// A List pref that contains daily totals of the original size of all HTTP
-// that was received over the network.
+// A List pref that contains daily totals of the original size of all HTTP/HTTPS
+// that was received from the network.
 const char kDailyHttpOriginalContentLength[] =
     "data_reduction.daily_original_length";
 
-// A List pref that contains daily totals of the size of all HTTP content that
-// has been received from the network.
+// A List pref that contains daily totals of the size of all HTTP/HTTPS content
+// that was received from the network.
 const char kDailyHttpReceivedContentLength[] =
     "data_reduction.daily_received_length";
 
-// A List pref that contains daily totals of the size of all HTTP content that
-// has been received via the data reduction proxy.
-const char kDailyHttpReceivedContentLengthViaDataReductionProxy[] =
-    "data_reduction.daily_received_length_via_data_reduction_proxy";
+// A List pref that contains daily totals of the original size of all HTTP/HTTPS
+// that was received while the data reduction proxy is enabled.
+const char kDailyOriginalContentLengthWithDataReductionProxyEnabled[] =
+    "data_reduction.daily_original_length_with_data_reduction_proxy_enabled";
 
-// A List pref that contains daily totals of the size of all HTTP content that
-// has been received when the data reduction proxy is enabled.
-// Note: this is different from
-// kDailyHttpReceivedContentLengthViaDataReductionProxy because content
-// doesn't necessarily go through the data reduction proxy when it is enabled.
-// E.g., the proxy doesn't handle HTTPS traffic.
-const char kDailyHttpReceivedContentLengthWithDataReductionProxyEnabled[] =
+// A List pref that contains daily totals of the size of all HTTP/HTTPS
+// that was received while the data reduction proxy is enabled.
+const char kDailyContentLengthWithDataReductionProxyEnabled[] =
     "data_reduction.daily_received_length_with_data_reduction_proxy_enabled";
 
+// A List pref that contains daily totals of the original size of all HTTP/HTTPS
+// that was received via the data reduction proxy.
+const char kDailyOriginalContentLengthViaDataReductionProxy[] =
+    "data_reduction.daily_original_length_via_data_reduction_proxy";
+
+// A List pref that contains daily totals of the size of all HTTP/HTTPS
+// that was received via the data reduction proxy.
+const char kDailyContentLengthViaDataReductionProxy[] =
+    "data_reduction.daily_received_length_via_data_reduction_proxy";
+
 // An int64 pref that contains an internal representation of midnight on the
 // date of the last update to |kDailyHttp{Original,Received}ContentLength|.
 const char kDailyHttpContentLengthLastUpdateDate[] =
@@ -2052,6 +2046,12 @@
 // TODO(tommi): Update comment when this is supported for all modes.
 const char kVideoCaptureAllowedUrls[] = "hardware.video_capture_allowed_urls";
 
+#if defined(OS_ANDROID)
+// Boolean that controls the global enabled-state of protected media identifier.
+const char kProtectedMediaIdentifierEnabled[] =
+    "protected_media_identifier.enabled";
+#endif
+
 #if defined(OS_CHROMEOS)
 // Dictionary for transient storage of settings that should go into device
 // settings storage before owner has been assigned.
@@ -2138,6 +2138,10 @@
 // A dictionary pref of the echo offer check flag. It sets offer info when
 // an offer is checked.
 extern const char kEchoCheckedOffers[] = "EchoCheckedOffers";
+
+// Key name of a dictionary in local state to store cached multiprofle user
+// behavior policy value.
+const char kCachedMultiProfileUserBehavior[] = "CachedMultiProfileUserBehavior";
 #endif
 
 // Whether there is a Flash version installed that supports clearing LSO data.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 721c4de..3aa63fb 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -288,6 +288,8 @@
 extern const char kRAConsentFirstTime[];
 extern const char kRAConsentDomains[];
 extern const char kRAConsentAlways[];
+extern const char kMultiProfileNotificationDismissed[];
+extern const char kMultiProfileUserBehavior[];
 #endif  // defined(OS_CHROMEOS)
 extern const char kIpcDisabledMessages[];
 extern const char kShowHomeButton[];
@@ -411,6 +413,8 @@
 
 extern const char kFullscreenAllowed[];
 
+extern const char kLocalDiscoveryNotificationsEnabled[];
+
 // Local state prefs. Please add Profile prefs above instead.
 extern const char kCertRevocationCheckingEnabled[];
 extern const char kCertRevocationCheckingRequiredLocalAnchors[];
@@ -734,6 +738,10 @@
 extern const char kVideoCaptureAllowed[];
 extern const char kVideoCaptureAllowedUrls[];
 
+#if defined(OS_ANDROID)
+extern const char kProtectedMediaIdentifierEnabled[];
+#endif
+
 #if defined(OS_CHROMEOS)
 extern const char kDeviceSettingsCache[];
 extern const char kHardwareKeyboardLayout[];
@@ -756,6 +764,7 @@
 extern const char kDeviceEnrollmentCanExit[];
 extern const char kUsersLRUInputMethod[];
 extern const char kEchoCheckedOffers[];
+extern const char kCachedMultiProfileUserBehavior[];
 #endif
 
 extern const char kClearPluginLSODataEnabled[];
@@ -790,9 +799,10 @@
 #if defined(OS_ANDROID) || defined(OS_IOS)
 extern const char kDailyHttpOriginalContentLength[];
 extern const char kDailyHttpReceivedContentLength[];
-extern const char kDailyHttpReceivedContentLengthViaDataReductionProxy[];
-extern const char
-    kDailyHttpReceivedContentLengthWithDataReductionProxyEnabled[];
+extern const char kDailyOriginalContentLengthWithDataReductionProxyEnabled[];
+extern const char kDailyContentLengthWithDataReductionProxyEnabled[];
+extern const char kDailyOriginalContentLengthViaDataReductionProxy[];
+extern const char kDailyContentLengthViaDataReductionProxy[];
 extern const char kDailyHttpContentLengthLastUpdateDate[];
 #endif
 
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index f5d997d..174f189 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -442,6 +442,11 @@
 // Misc messages
 // These are messages sent from the renderer to the browser process.
 
+// Provides the contents for the given page that was loaded recently.
+IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_PageContents,
+                    GURL         /* URL of the page */,
+                    string16     /* page contents */)
+
 // Notification that the language for the tab has been determined.
 IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_TranslateLanguageDetermined,
                     LanguageDetectionDetails /* details about lang detection */,
@@ -623,11 +628,6 @@
                     std::string           /* the translated language */,
                     TranslateErrors::Type /* the error type if available */)
 
-// Message sent from the renderer to the browser to notify it of events which
-// may lead to the cancellation of a prerender. The message is sent only when
-// the renderer is prerendering.
-IPC_MESSAGE_ROUTED0(ChromeViewHostMsg_MaybeCancelPrerenderForHTML5Media)
-
 // Message sent from the renderer to the browser to notify it of a
 // window.print() call which should cancel the prerender. The message is sent
 // only when the renderer is prerendering.
diff --git a/chrome/common/safe_browsing/OWNERS b/chrome/common/safe_browsing/OWNERS
index dc45c86..cd4e37c 100644
--- a/chrome/common/safe_browsing/OWNERS
+++ b/chrome/common/safe_browsing/OWNERS
@@ -10,5 +10,4 @@
 per-file *_messages*.h=cevans@chromium.org
 per-file *_messages*.h=inferno@chromium.org
 per-file *_messages*.h=jschuh@chromium.org
-per-file *_messages*.h=palmer@chromium.org
 per-file *_messages*.h=tsepez@chromium.org
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 5fa5190..c84731e 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -235,7 +235,7 @@
 const char kChromeUIWelcomeHost[] = "welcome";
 #endif
 
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
 const char kChromeUILinuxProxyConfigHost[] = "linux-proxy-config";
 const char kChromeUISandboxHost[] = "sandbox";
 #endif
@@ -519,8 +519,10 @@
   kChromeUIChromeURLsHost,
   kChromeUICrashesHost,
   kChromeUICreditsHost,
+  kChromeUIDevicesHost,
   kChromeUIDNSHost,
   kChromeUIFlagsHost,
+  kChromeUIHelpHost,
   kChromeUIHistoryHost,
   kChromeUIIPCHost,
   kChromeUIMemoryHost,
@@ -539,6 +541,7 @@
   kChromeUISyncInternalsHost,
   kChromeUITermsHost,
   kChromeUITranslateInternalsHost,
+  kChromeUIUberHost,
   kChromeUIUserActionsHost,
   kChromeUIVersionHost,
 #if defined(OS_ANDROID)
@@ -555,7 +558,7 @@
 #if defined(OS_WIN)
   kChromeUIConflictsHost,
 #endif
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
   kChromeUILinuxProxyConfigHost,
   kChromeUISandboxHost,
 #endif
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 7030610..3acb602 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -227,7 +227,7 @@
 extern const char kChromeUIWelcomeHost[];
 #endif
 
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
 extern const char kChromeUILinuxProxyConfigHost[];
 extern const char kChromeUISandboxHost[];
 #endif
@@ -469,10 +469,10 @@
 #if defined(OS_CHROMEOS)
 extern const char kCrosScheme[];
 extern const char kDriveScheme[];
+#endif
 
 // "Learn more" URL for the Cloud Print section under Options.
 extern const char kCloudPrintLearnMoreURL[];
-#endif
 
 // Parameters that get appended to force SafeSearch.
 extern const char kSafeSearchSafeParameter[];