diff --git a/DEPS b/DEPS
index cffbcded..bee087b 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'fdb627dcc6485874d741c0730873d49126bf5d34',
+  'skia_revision': 'bd6366a69ec890211496892e1a76535439ca2b30',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'eaed3912f99e3240995700e3a8f7673de0299573',
+  'v8_revision': 'ce76b7cd4c1f35fc6d4473a38f27c78e4481aa1d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -87,7 +87,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'fc99150025783f0e8409f9eff6c04daaf6ccbbeb',
+  'nacl_revision': 'eff184407eb183c8f6ec65d74abc4356d466f448',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling dEQP
   # and whatever else without interference from each other.
@@ -149,7 +149,7 @@
     Var('chromium_git') + '/external/snappy.git' + '@' + '762bb32f0c9d2f31ba4958c7c0933d22e80c20bf',
 
   'src/tools/gyp':
-    Var('chromium_git') + '/external/gyp.git' + '@' + '5170bfd38fe79bd5b16aa7f6c5439fb90a37ae66',
+    Var('chromium_git') + '/external/gyp.git' + '@' + '2f9ffdc96135eaa102ee90584e7c6e5e5c45915c',
 
   'src/tools/swarming_client':
    Var('chromium_git') + '/external/swarming.client.git' + '@' +  Var('swarming_revision'),
@@ -215,7 +215,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '4056bb64bd32ea1cc1dc55ebcbcb66829b64eb7b', # commit position 11592
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '067ab64dbee579393c17e5b80dfd3beffa3f39bf', # commit position 11616
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
index 0908285..8180d62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
@@ -633,6 +633,7 @@
     }
 
     private void resetSite() {
+        if (getActivity() == null) return;
         // Clear the screen.
         // TODO(mvanouwerkerk): Refactor this class so that it does not depend on the screen state
         // for its logic. This class should maintain its own data model, and only update the screen
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc
index 4650c7a..a2bdf3f 100644
--- a/chrome/browser/download/download_request_limiter.cc
+++ b/chrome/browser/download/download_request_limiter.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/stl_util.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -48,10 +49,11 @@
       status_(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD),
       download_count_(0),
       factory_(this) {
-  content::Source<NavigationController> notification_source(
-      &contents->GetController());
-  registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
-                 notification_source);
+  registrar_.Add(
+      this, content::NOTIFICATION_NAV_ENTRY_PENDING,
+      content::Source<NavigationController>(&contents->GetController()));
+  registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
+                 content::Source<content::WebContents>(contents));
   NavigationEntry* last_entry = originating_web_contents ?
       originating_web_contents->GetController().GetLastCommittedEntry() :
       contents->GetController().GetLastCommittedEntry();
@@ -83,9 +85,10 @@
     case DOWNLOADS_NOT_ALLOWED:
     case ALLOW_ALL_DOWNLOADS:
       // Don't drop this information. The user has explicitly said that they
-      // do/don't want downloads from this host.  If they accidentally Accepted
-      // or Canceled, tough luck, they don't get another chance. They can copy
-      // the URL into a new tab, which will make a new DownloadRequestLimiter.
+      // do/don't want downloads from this host. If they accidentally Accepted
+      // or Canceled, they can adjust the limiter state by adjusting the
+      // automatic downloads content settings. Alternatively, they can copy the
+      // URL into a new tab, which will make a new DownloadRequestLimiter.
       // See also the initial_page_host_ logic in Observe() for
       // NOTIFICATION_NAV_ENTRY_PENDING.
       break;
@@ -197,7 +200,53 @@
     int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
-  DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_PENDING, type);
+  DCHECK(type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED ||
+         type == content::NOTIFICATION_NAV_ENTRY_PENDING);
+
+  // Content settings have been updated for our web contents, e.g. via the OIB
+  // or the settings page. Check to see if the automatic downloads setting is
+  // different to our internal state, and update the internal state to match if
+  // necessary. If there is no content setting persisted, then retain the
+  // current state and do nothing.
+  //
+  // NotifyCallbacks is not called as this notification should be triggered when
+  // a download is not pending.
+  if (type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED) {
+    content::WebContents* contents =
+        content::Source<content::WebContents>(source).ptr();
+    DCHECK_EQ(contents, web_contents());
+
+    // Fetch the content settings map for this web contents, and extract the
+    // automatic downloads permission value.
+    HostContentSettingsMap* content_settings = GetContentSettings(contents);
+    if (content_settings) {
+      ContentSetting setting = content_settings->GetContentSetting(
+          contents->GetURL(), contents->GetURL(),
+          CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, std::string());
+
+      // Update the internal state to match if necessary.
+      switch (setting) {
+        case CONTENT_SETTING_ALLOW:
+          set_download_status(ALLOW_ALL_DOWNLOADS);
+          break;
+        case CONTENT_SETTING_BLOCK:
+          set_download_status(DOWNLOADS_NOT_ALLOWED);
+          break;
+        case CONTENT_SETTING_ASK:
+        case CONTENT_SETTING_DEFAULT:
+        case CONTENT_SETTING_SESSION_ONLY:
+          set_download_status(PROMPT_BEFORE_DOWNLOAD);
+          break;
+        case CONTENT_SETTING_NUM_SETTINGS:
+        case CONTENT_SETTING_DETECT_IMPORTANT_CONTENT:
+          NOTREACHED();
+          return;
+      }
+    }
+    return;
+  }
+
+  // Otherwise, there is a pending navigation entry.
   content::NavigationController* controller = &web_contents()->GetController();
   DCHECK_EQ(controller, content::Source<NavigationController>(source).ptr());
 
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc
index fbb8708e..f153cf4 100644
--- a/chrome/browser/download/download_request_limiter_unittest.cc
+++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -8,12 +8,15 @@
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/frame_navigate_params.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -154,7 +157,7 @@
 
   void TearDown() override {
     content_settings_->ShutdownOnUIThread();
-    content_settings_ = NULL;
+    content_settings_ = nullptr;
     testing_delegate_.TearDown();
     ChromeRenderViewHostTestHarness::TearDown();
   }
@@ -178,7 +181,8 @@
 
   void OnUserGestureFor(WebContents* web_contents) {
     DownloadRequestLimiter::TabDownloadState* state =
-        download_request_limiter_->GetDownloadState(web_contents, NULL, false);
+        download_request_limiter_->GetDownloadState(web_contents, nullptr,
+                                                    false);
     if (state)
       state->DidGetUserGesture();
   }
@@ -195,6 +199,20 @@
     testing_delegate_.ResetCounts();
   }
 
+  void UpdateContentSettings(WebContents* web_contents,
+                             ContentSetting setting) {
+    // Ensure a download state exists.
+    download_request_limiter_->GetDownloadState(web_contents, nullptr, true);
+    SetHostContentSetting(web_contents, setting);
+
+    // Manually send the update notification. In the browser, this is sent from
+    // ContentSettingRPHBubbleModel.
+    content::NotificationService::current()->Notify(
+        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
+        content::Source<WebContents>(web_contents),
+        content::NotificationService::NoDetails());
+  }
+
  protected:
   void ContinueDownload(bool allow) {
     if (allow) {
@@ -485,3 +503,59 @@
   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
             download_request_limiter_->GetDownloadStatus(web_contents()));
 }
+
+TEST_F(DownloadRequestLimiterTest,
+       DownloadRequestLimiter_ContentSettingChanged) {
+  NavigateAndCommit(GURL("http://foo.com/bar"));
+  LoadCompleted();
+  ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+
+  CanDownload();
+  ExpectAndResetCounts(1, 0, 0, __LINE__);
+  ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+
+  // Simulate an accidental deny.
+  UpdateExpectations(CANCEL);
+  CanDownload();
+  ExpectAndResetCounts(0, 1, 1, __LINE__);
+  ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+
+  // Set the content setting to allow and send the notification. Ensure that the
+  // limiter states update to match.
+  UpdateContentSettings(web_contents(), CONTENT_SETTING_ALLOW);
+  ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+
+  // Ask to download, and assert that it succeeded and we are still in allow.
+  CanDownload();
+  ExpectAndResetCounts(1, 0, 0, __LINE__);
+  ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+
+  // Set the content setting to block and send the notification. Ensure that the
+  // limiter states updates to match.
+  UpdateContentSettings(web_contents(), CONTENT_SETTING_BLOCK);
+  ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+
+  // Ensure downloads are blocked.
+  CanDownload();
+  ExpectAndResetCounts(0, 1, 0, __LINE__);
+  ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+
+  // Reset to ask. Verify that the download counts have not changed on the
+  // content settings change (ensuring there is no "free" download after
+  // changing the content setting).
+  UpdateContentSettings(web_contents(), CONTENT_SETTING_ASK);
+  ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+  UpdateExpectations(WAIT);
+  CanDownload();
+  ExpectAndResetCounts(0, 0, 1, __LINE__);
+  ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
+            download_request_limiter_->GetDownloadStatus(web_contents()));
+}
diff --git a/chrome/common/extensions/permissions/media_galleries_permission_unittest.cc b/chrome/common/extensions/permissions/media_galleries_permission_unittest.cc
index 110a0692..e64f4d5 100644
--- a/chrome/common/extensions/permissions/media_galleries_permission_unittest.cc
+++ b/chrome/common/extensions/permissions/media_galleries_permission_unittest.cc
@@ -90,12 +90,8 @@
 
   scoped_ptr<APIPermission> permission(permission_info->CreateAPIPermission());
 
-  // Empty
-  scoped_ptr<base::ListValue> value(new base::ListValue());
-  CheckFromValue(permission.get(), value.get(), false);
-
   // copyTo and delete without read
-  value.reset(new base::ListValue());
+  scoped_ptr<base::ListValue> value(new base::ListValue());
   value->AppendString(MediaGalleriesPermission::kCopyToPermission);
   CheckFromValue(permission.get(), value.get(), false);
 
@@ -281,6 +277,15 @@
   ASSERT_TRUE(vtmp);
   ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
   EXPECT_TRUE(permission1->Equal(permission2.get()));
+
+  value.reset(new base::ListValue());
+  // without sub-permission
+  ASSERT_TRUE(permission1->FromValue(NULL, NULL, NULL));
+
+  vtmp = permission1->ToValue();
+  ASSERT_TRUE(vtmp);
+  ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+  EXPECT_TRUE(permission1->Equal(permission2.get()));
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 26d8cee..885b9fa 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -63,7 +63,6 @@
 class AutofillType;
 class CreditCard;
 class FormStructureBrowserTest;
-template <class WebTestT> class FormStructureBrowserTestIos;
 
 struct FormData;
 struct FormFieldData;
@@ -517,8 +516,6 @@
 
   friend class AutofillManagerTest;
   friend class FormStructureBrowserTest;
-  friend class FormStructureBrowserTestIos<ChromeUIWebViewWebTest>;
-  friend class FormStructureBrowserTestIos<ChromeWKWebViewWebTest>;
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
                            DeterminePossibleFieldTypesForUpload);
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
diff --git a/device/usb/usb_descriptors.cc b/device/usb/usb_descriptors.cc
index 22414d7a..6defda8 100644
--- a/device/usb/usb_descriptors.cc
+++ b/device/usb/usb_descriptors.cc
@@ -7,7 +7,6 @@
 #include <stddef.h>
 
 #include <algorithm>
-#include <vector>
 
 #include "base/barrier_closure.h"
 #include "base/bind.h"
@@ -27,42 +26,6 @@
 
 const int kControlTransferTimeout = 60000;  // 1 minute
 
-struct UsbInterfaceAssociationDescriptor {
-  UsbInterfaceAssociationDescriptor(uint8_t first_interface,
-                                    uint8_t interface_count)
-      : first_interface(first_interface), interface_count(interface_count) {}
-
-  bool operator<(const UsbInterfaceAssociationDescriptor& other) const {
-    return first_interface < other.first_interface;
-  }
-
-  uint8_t first_interface;
-  uint8_t interface_count;
-};
-
-void ParseInterfaceAssociationDescriptors(
-    const std::vector<uint8_t>& buffer,
-    std::vector<UsbInterfaceAssociationDescriptor>* functions) {
-  const uint8_t kInterfaceAssociationDescriptorType = 11;
-  const uint8_t kInterfaceAssociationDescriptorLength = 8;
-  std::vector<uint8_t>::const_iterator it = buffer.begin();
-
-  while (it != buffer.end()) {
-    // All descriptors must be at least 2 byte which means the length and type
-    // are safe to read.
-    if (std::distance(it, buffer.end()) < 2)
-      return;
-    uint8_t length = it[0];
-    if (length > std::distance(it, buffer.end()))
-      return;
-    if (it[1] == kInterfaceAssociationDescriptorType &&
-        length == kInterfaceAssociationDescriptorLength) {
-      functions->push_back(UsbInterfaceAssociationDescriptor(it[2], it[3]));
-    }
-    std::advance(it, length);
-  }
-}
-
 void StoreStringDescriptor(IndexMap::iterator it,
                            const base::Closure& callback,
                            const base::string16& string) {
@@ -150,8 +113,7 @@
       alternate_setting(alternate_setting),
       interface_class(interface_class),
       interface_subclass(interface_subclass),
-      interface_protocol(interface_protocol),
-      first_interface(interface_number) {}
+      interface_protocol(interface_protocol) {}
 
 UsbInterfaceDescriptor::~UsbInterfaceDescriptor() = default;
 
@@ -166,47 +128,6 @@
 
 UsbConfigDescriptor::~UsbConfigDescriptor() = default;
 
-void UsbConfigDescriptor::AssignFirstInterfaceNumbers() {
-  std::vector<UsbInterfaceAssociationDescriptor> functions;
-  ParseInterfaceAssociationDescriptors(extra_data, &functions);
-  for (const auto& interface : interfaces) {
-    ParseInterfaceAssociationDescriptors(interface.extra_data, &functions);
-    for (const auto& endpoint : interface.endpoints)
-      ParseInterfaceAssociationDescriptors(endpoint.extra_data, &functions);
-  }
-
-  // libusb has collected interface association descriptors in the |extra_data|
-  // fields of other descriptor types. This may have disturbed their order
-  // but sorting by the bFirstInterface should fix it.
-  std::sort(functions.begin(), functions.end());
-
-  uint8_t remaining_interfaces = 0;
-  auto function_it = functions.cbegin();
-  for (auto interface_it = interfaces.begin(); interface_it != interfaces.end();
-       ++interface_it) {
-    if (remaining_interfaces > 0) {
-      // Continuation of a previous function. Tag all alternate interfaces
-      // (which are guaranteed to be contiguous).
-      for (uint8_t interface_number = interface_it->interface_number;
-           interface_it != interfaces.end() &&
-           interface_it->interface_number == interface_number;
-           ++interface_it) {
-        interface_it->first_interface = function_it->first_interface;
-      }
-      if (--remaining_interfaces == 0)
-        ++function_it;
-    } else if (function_it != functions.end() &&
-               interface_it->interface_number == function_it->first_interface) {
-      // Start of a new function.
-      interface_it->first_interface = function_it->first_interface;
-      remaining_interfaces = function_it->interface_count - 1;
-    } else {
-      // Unassociated interfaces already have |first_interface| set to
-      // |interface_number|.
-    }
-  }
-}
-
 bool ParseUsbStringDescriptor(const std::vector<uint8_t>& descriptor,
                               base::string16* output) {
   if (descriptor.size() < 2 || descriptor[1] != kStringDescriptorType)
diff --git a/device/usb/usb_descriptors.h b/device/usb/usb_descriptors.h
index a1414154f..c99a6def 100644
--- a/device/usb/usb_descriptors.h
+++ b/device/usb/usb_descriptors.h
@@ -85,8 +85,6 @@
   uint8_t interface_protocol;
   std::vector<UsbEndpointDescriptor> endpoints;
   std::vector<uint8_t> extra_data;
-  // First interface of the function to which this interface belongs.
-  uint8_t first_interface;
 };
 
 struct UsbConfigDescriptor {
@@ -97,10 +95,6 @@
   UsbConfigDescriptor() = delete;
   ~UsbConfigDescriptor();
 
-  // Scans through |extra_data| for interface association descriptors and
-  // populates |first_interface| for each interface in this configuration.
-  void AssignFirstInterfaceNumbers();
-
   uint8_t configuration_value;
   bool self_powered;
   bool remote_wakeup;
diff --git a/device/usb/usb_descriptors_unittest.cc b/device/usb/usb_descriptors_unittest.cc
index 5bc2943..402304f 100644
--- a/device/usb/usb_descriptors_unittest.cc
+++ b/device/usb/usb_descriptors_unittest.cc
@@ -32,81 +32,6 @@
 
 class UsbDescriptorsTest : public ::testing::Test {};
 
-TEST_F(UsbDescriptorsTest, NoInterfaceAssociations) {
-  UsbConfigDescriptor config(1, false, false, 0);
-  config.interfaces.emplace_back(0, 0, 255, 255, 255);
-  config.interfaces.emplace_back(0, 1, 255, 255, 255);
-  config.interfaces.emplace_back(1, 0, 255, 255, 255);
-  config.AssignFirstInterfaceNumbers();
-
-  EXPECT_EQ(0, config.interfaces[0].first_interface);
-  EXPECT_EQ(0, config.interfaces[1].first_interface);
-  EXPECT_EQ(1, config.interfaces[2].first_interface);
-}
-
-TEST_F(UsbDescriptorsTest, InterfaceAssociations) {
-  // Links interfaces 0 and 1 into a single function.
-  static const uint8_t kIAD1[] = {0x08, 0x0b, 0x00, 0x02,
-                                  0xff, 0xff, 0xff, 0x00};
-  // Only references a single interface, 2.
-  static const uint8_t kIAD2[] = {0x08, 0x0b, 0x02, 0x01,
-                                  0xff, 0xff, 0xff, 0x00};
-  // Malformed. References interface 3 but bInterfaceCount is 0.
-  static const uint8_t kIAD3[] = {0x08, 0x0b, 0x03, 0x00,
-                                  0xff, 0xff, 0xff, 0x00};
-  // Malformed. References an indefined interface.
-  static const uint8_t kIAD4[] = {0x08, 0x0b, 0x07, 0x00,
-                                  0xff, 0xff, 0xff, 0x00};
-  // Links interfaces 4 and 5 into a single function.
-  static const uint8_t kIAD5[] = {0x08, 0x0b, 0x04, 0x01,
-                                  0xff, 0xff, 0xff, 0x00};
-
-  UsbConfigDescriptor config(1, false, false, 0);
-  config.extra_data.assign(kIAD1, kIAD1 + sizeof(kIAD1));
-  config.extra_data.insert(config.extra_data.end(), kIAD2,
-                           kIAD2 + sizeof(kIAD2));
-  config.interfaces.emplace_back(0, 0, 255, 255, 255);
-  config.interfaces.emplace_back(1, 0, 255, 255, 255);
-  UsbInterfaceDescriptor iface1a(1, 1, 255, 255, 255);
-  iface1a.extra_data.assign(kIAD3, kIAD3 + sizeof(kIAD3));
-  config.interfaces.push_back(std::move(iface1a));
-  config.interfaces.emplace_back(2, 0, 255, 255, 255);
-  config.interfaces.emplace_back(3, 0, 255, 255, 255);
-  UsbInterfaceDescriptor iface4(4, 0, 255, 255, 255);
-  iface4.extra_data.assign(kIAD4, kIAD4 + sizeof(kIAD4));
-  iface4.extra_data.insert(iface4.extra_data.end(), kIAD5,
-                           kIAD5 + sizeof(kIAD5));
-  config.interfaces.push_back(std::move(iface4));
-  config.interfaces.emplace_back(5, 0, 255, 255, 255);
-  config.AssignFirstInterfaceNumbers();
-
-  EXPECT_EQ(0, config.interfaces[0].first_interface);
-  EXPECT_EQ(0, config.interfaces[1].first_interface);
-  EXPECT_EQ(0, config.interfaces[2].first_interface);
-  EXPECT_EQ(2, config.interfaces[3].first_interface);
-  EXPECT_EQ(3, config.interfaces[4].first_interface);
-  EXPECT_EQ(4, config.interfaces[5].first_interface);
-  EXPECT_EQ(4, config.interfaces[5].first_interface);
-}
-
-TEST_F(UsbDescriptorsTest, CorruptInterfaceAssociations) {
-  {
-    // Descriptor is too short.
-    static const uint8_t kIAD[] = {0x01};
-    UsbConfigDescriptor config(1, false, false, 0);
-    config.extra_data.assign(kIAD, kIAD + sizeof(kIAD));
-    config.AssignFirstInterfaceNumbers();
-  }
-  {
-    // Descriptor is too long.
-    static const uint8_t kIAD[] = {0x09, 0x0b, 0x00, 0x00,
-                                   0x00, 0x00, 0x00, 0x00};
-    UsbConfigDescriptor config(1, false, false, 0);
-    config.extra_data.assign(kIAD, kIAD + sizeof(kIAD));
-    config.AssignFirstInterfaceNumbers();
-  }
-}
-
 TEST_F(UsbDescriptorsTest, StringDescriptor) {
   static const uint8_t kBuffer[] = {0x1a, 0x03, 'H', 0, 'e', 0, 'l', 0, 'l', 0,
                                     'o',  0,    ' ', 0, 'w', 0, 'o', 0, 'r', 0,
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc
index 118416d..1a8bedf1 100644
--- a/device/usb/usb_device_impl.cc
+++ b/device/usb/usb_device_impl.cc
@@ -135,8 +135,6 @@
   configuration->extra_data.assign(
       platform_config->extra,
       platform_config->extra + platform_config->extra_length);
-
-  configuration->AssignFirstInterfaceNumbers();
 }
 
 }  // namespace
diff --git a/extensions/common/permissions/media_galleries_permission.h b/extensions/common/permissions/media_galleries_permission.h
index 870a0a9d..40a2277b 100644
--- a/extensions/common/permissions/media_galleries_permission.h
+++ b/extensions/common/permissions/media_galleries_permission.h
@@ -21,6 +21,10 @@
 //                'delete' <tertiary-access>
 //   <tertiary-access>
 //             := 'copyTo' | 'copyTo' <tertiary-access>
+// An example of a line for mediaGalleries permissions in a manifest file:
+//   {"mediaGalleries": "read delete"},
+// We also allow a permission without any sub-permissions:
+//   "mediaGalleries",
 class MediaGalleriesPermission
   : public SetDisjunctionPermission<MediaGalleriesPermissionData,
                                     MediaGalleriesPermission> {
diff --git a/extensions/common/permissions/set_disjunction_permission.h b/extensions/common/permissions/set_disjunction_permission.h
index 0e97e9d..ce1c6ee1d 100644
--- a/extensions/common/permissions/set_disjunction_permission.h
+++ b/extensions/common/permissions/set_disjunction_permission.h
@@ -105,9 +105,14 @@
     data_set_.clear();
     const base::ListValue* list = NULL;
 
-    if (!value || !value->GetAsList(&list) || list->GetSize() == 0) {
+    if (!value) {
+      // treat null as an empty list.
+      return true;
+    }
+
+    if (!value->GetAsList(&list)) {
       if (error)
-        *error = "NULL or empty permission list";
+        *error = "Cannot parse the permission list. It's not a list.";
       return false;
     }
 
diff --git a/extensions/common/permissions/socket_permission.cc b/extensions/common/permissions/socket_permission.cc
index c2ca223..a8e5c18 100644
--- a/extensions/common/permissions/socket_permission.cc
+++ b/extensions/common/permissions/socket_permission.cc
@@ -38,6 +38,21 @@
 
 SocketPermission::~SocketPermission() {}
 
+bool SocketPermission::FromValue(
+    const base::Value* value,
+    std::string* error,
+    std::vector<std::string>* unhandled_permissions) {
+  bool parsed_ok = SetDisjunctionPermission<
+      SocketPermissionData, SocketPermission>::FromValue(value, error,
+                                                         unhandled_permissions);
+  if (parsed_ok && data_set_.empty()) {
+    if (error)
+      *error = "NULL or empty permission list";
+    return false;
+  }
+  return parsed_ok;
+}
+
 PermissionIDSet SocketPermission::GetPermissions() const {
   PermissionIDSet ids;
   SocketPermissionEntrySet entries = ExtractSocketEntries(data_set_);
diff --git a/extensions/common/permissions/socket_permission.h b/extensions/common/permissions/socket_permission.h
index 01be06c..590ed5d 100644
--- a/extensions/common/permissions/socket_permission.h
+++ b/extensions/common/permissions/socket_permission.h
@@ -30,6 +30,12 @@
 
   ~SocketPermission() override;
 
+  // SetDisjunctionPermission overrides.
+  bool FromValue(const base::Value* value,
+                 std::string* error,
+                 std::vector<std::string>* unhandled_permissions) override;
+
+  // APIPermission overrides
   PermissionIDSet GetPermissions() const override;
 };
 
diff --git a/extensions/common/permissions/usb_device_permission.cc b/extensions/common/permissions/usb_device_permission.cc
index ab279b6..fd94783 100644
--- a/extensions/common/permissions/usb_device_permission.cc
+++ b/extensions/common/permissions/usb_device_permission.cc
@@ -25,6 +25,21 @@
 
 UsbDevicePermission::~UsbDevicePermission() {}
 
+bool UsbDevicePermission::FromValue(
+    const base::Value* value,
+    std::string* error,
+    std::vector<std::string>* unhandled_permissions) {
+  bool parsed_ok =
+      SetDisjunctionPermission<UsbDevicePermissionData, UsbDevicePermission>::
+          FromValue(value, error, unhandled_permissions);
+  if (parsed_ok && data_set_.empty()) {
+    if (error)
+      *error = "NULL or empty permission list";
+    return false;
+  }
+  return parsed_ok;
+}
+
 PermissionIDSet UsbDevicePermission::GetPermissions() const {
   PermissionIDSet ids;
 
diff --git a/extensions/common/permissions/usb_device_permission.h b/extensions/common/permissions/usb_device_permission.h
index 7cba580..2658011 100644
--- a/extensions/common/permissions/usb_device_permission.h
+++ b/extensions/common/permissions/usb_device_permission.h
@@ -30,6 +30,11 @@
   explicit UsbDevicePermission(const APIPermissionInfo* info);
   ~UsbDevicePermission() override;
 
+  // SetDisjunctionPermission overrides.
+  bool FromValue(const base::Value* value,
+                 std::string* error,
+                 std::vector<std::string>* unhandled_permissions) override;
+
   // APIPermission overrides
   PermissionIDSet GetPermissions() const override;
 };
diff --git a/mojo/edk/embedder/platform_handle.cc b/mojo/edk/embedder/platform_handle.cc
index 57da181..62dc850 100644
--- a/mojo/edk/embedder/platform_handle.cc
+++ b/mojo/edk/embedder/platform_handle.cc
@@ -23,9 +23,18 @@
     return;
 
 #if defined(OS_POSIX)
-  bool success = (close(handle) == 0);
-  DPCHECK(success);
-  handle = -1;
+  if (type == Type::POSIX) {
+    bool success = (close(handle) == 0);
+    DPCHECK(success);
+    handle = -1;
+  }
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  else {
+     kern_return_t rv = mach_port_deallocate(mach_task_self(), port);
+     DPCHECK(rv == KERN_SUCCESS);
+     port = MACH_PORT_NULL;
+  }
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 #elif defined(OS_WIN)
   bool success = !!CloseHandle(handle);
   DPCHECK(success);
diff --git a/mojo/edk/embedder/platform_handle.h b/mojo/edk/embedder/platform_handle.h
index 77ae3e08..1c0c752 100644
--- a/mojo/edk/embedder/platform_handle.h
+++ b/mojo/edk/embedder/platform_handle.h
@@ -10,6 +10,8 @@
 
 #if defined(OS_WIN)
 #include <windows.h>
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach.h>
 #endif
 
 namespace mojo {
@@ -17,14 +19,36 @@
 
 #if defined(OS_POSIX)
 struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandle {
-  PlatformHandle() : handle(-1) {}
+  PlatformHandle() {}
   explicit PlatformHandle(int handle) : handle(handle) {}
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  explicit PlatformHandle(mach_port_t port)
+      : type(Type::MACH), port(port) {}
+#endif
 
   void CloseIfNecessary();
 
-  bool is_valid() const { return handle != -1; }
+  bool is_valid() const {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+    if (type == Type::MACH)
+      return port != MACH_PORT_NULL;
+#endif
+    return handle != -1;
+  }
 
-  int handle;
+  enum class Type {
+    POSIX,
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+    MACH,
+#endif
+  };
+  Type type = Type::POSIX;
+
+  int handle = -1;
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  mach_port_t port = MACH_PORT_NULL;
+#endif
 };
 #elif defined(OS_WIN)
 struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandle {
diff --git a/mojo/edk/system/wait_set_dispatcher.cc b/mojo/edk/system/wait_set_dispatcher.cc
index fd44715..7d59f32 100644
--- a/mojo/edk/system/wait_set_dispatcher.cc
+++ b/mojo/edk/system/wait_set_dispatcher.cc
@@ -107,20 +107,19 @@
 MojoResult WaitSetDispatcher::RemoveWaitingDispatcher(
     const scoped_refptr<Dispatcher>& dispatcher) {
   uintptr_t dispatcher_handle = reinterpret_cast<uintptr_t>(dispatcher.get());
-  {
-    base::AutoLock lock(lock_);
-    if (is_closed_)
-      return MOJO_RESULT_INVALID_ARGUMENT;
 
-    auto it = waiting_dispatchers_.find(dispatcher_handle);
-    if (it == waiting_dispatchers_.end())
-      return MOJO_RESULT_NOT_FOUND;
+  base::AutoLock lock(lock_);
+  if (is_closed_)
+    return MOJO_RESULT_INVALID_ARGUMENT;
 
-    dispatcher->RemoveAwakable(waiter_.get(), nullptr);
-    // At this point, it should not be possible for |waiter_| to be woken with
-    // |dispatcher|.
-    waiting_dispatchers_.erase(it);
-  }
+  auto it = waiting_dispatchers_.find(dispatcher_handle);
+  if (it == waiting_dispatchers_.end())
+    return MOJO_RESULT_NOT_FOUND;
+
+  dispatcher->RemoveAwakable(waiter_.get(), nullptr);
+  // At this point, it should not be possible for |waiter_| to be woken with
+  // |dispatcher|.
+  waiting_dispatchers_.erase(it);
 
   base::AutoLock locker(awoken_lock_);
   int num_erased = 0;
diff --git a/mojo/public/mojo_application_manifest.gni b/mojo/public/mojo_application_manifest.gni
index 1ba5c1e..d1a3cc0 100644
--- a/mojo/public/mojo_application_manifest.gni
+++ b/mojo/public/mojo_application_manifest.gni
@@ -23,6 +23,9 @@
 #   packaged_applications (optional)
 #       An array of application_names of the dependent applications.
 #
+#   type (default is mojo)
+#       Possible values are 'mojo' and 'exe'. Default is 'mojo'.
+#
 # Outputs:
 #
 #   An instantiation of this template produces in
@@ -45,12 +48,25 @@
            "\"deps\" building the dependent packaged applications must be " +
                "provided.")
   }
+  if (defined(invoker.type)) {
+    assert(invoker.type == "mojo" || invoker.type == "exe",
+           "\"type\" must be one of \"mojo\" or \"exe\".")
+  }
 
   action(target_name) {
     script = "//mojo/public/tools/manifest/manifest_collator.py"
 
+    type = "mojo"
+    if (defined(invoker.type)) {
+      type = invoker.type
+    }
+
     application_name = invoker.application_name
-    output = "$root_out_dir/$application_name/manifest.json"
+    if (type == "mojo") {
+      output = "$root_out_dir/$application_name/manifest.json"
+    } else {
+      output = "$root_out_dir/${application_name}_manifest.json"
+    }
     outputs = [
       output,
     ]
diff --git a/mojo/shell/application_manager.cc b/mojo/shell/application_manager.cc
index b8dda51..4912803 100644
--- a/mojo/shell/application_manager.cc
+++ b/mojo/shell/application_manager.cc
@@ -96,7 +96,8 @@
 
   ApplicationLoader* loader = GetLoaderForURL(params->target().url());
   if (loader) {
-    GURL url = params->target().url();
+    const GURL url = params->target().url();
+    package_manager_->BuiltinAppLoaded(url);
     loader->Load(url, CreateAndConnectToInstance(std::move(params), nullptr));
     return;
   }
diff --git a/mojo/shell/package_manager.h b/mojo/shell/package_manager.h
index 80b5b8b..998cc73 100644
--- a/mojo/shell/package_manager.h
+++ b/mojo/shell/package_manager.h
@@ -31,6 +31,9 @@
   // associated ApplicationManager.
   virtual void SetApplicationManager(ApplicationManager* manager) = 0;
 
+  // Called when an app is loaded via an ApplicationLoader.
+  virtual void BuiltinAppLoaded(const GURL& url) = 0;
+
   // Asks the delegate to fetch the specified url.
   // TODO(beng): figure out how not to expose Fetcher at all at this layer.
   virtual void FetchRequest(
diff --git a/mojo/shell/package_manager/package_manager_impl.cc b/mojo/shell/package_manager/package_manager_impl.cc
index 21f00a4..c06e9b3 100644
--- a/mojo/shell/package_manager/package_manager_impl.cc
+++ b/mojo/shell/package_manager/package_manager_impl.cc
@@ -131,6 +131,12 @@
   application_manager_ = manager;
 }
 
+void PackageManagerImpl::BuiltinAppLoaded(const GURL& url) {
+  // TODO(beng): Determine if this is in the right place, and block
+  //             establishing the connection on receiving a complete manifest.
+  EnsureURLInCatalog(url);
+}
+
 void PackageManagerImpl::FetchRequest(
     URLRequestPtr request,
     const Fetcher::FetchCallback& loader_callback) {
@@ -299,7 +305,7 @@
 }
 
 void PackageManagerImpl::EnsureURLInCatalog(const GURL& url) {
-  if (IsURLInCatalog(url.spec()))
+  if (IsURLInCatalog(url.spec()) || !url_resolver_)
     return;
 
   GURL manifest_url = url_resolver_->ResolveMojoManifest(url);
@@ -348,7 +354,11 @@
 const ApplicationInfo& PackageManagerImpl::DeserializeApplication(
     const base::DictionaryValue* dictionary) {
   ApplicationInfo info = BuildApplicationInfoFromDictionary(*dictionary);
-  CHECK(catalog_.find(info.url) == catalog_.end());
+  // If another app refers to this app, then we already added an entry for
+  // |info| as a result of reading the first apps manifest.
+  if (catalog_.count(info.url))
+    return catalog_[info.url];
+
   catalog_[info.url] = info;
 
   if (dictionary->HasKey("applications")) {
diff --git a/mojo/shell/package_manager/package_manager_impl.h b/mojo/shell/package_manager/package_manager_impl.h
index ee215a61..0bbc01c 100644
--- a/mojo/shell/package_manager/package_manager_impl.h
+++ b/mojo/shell/package_manager/package_manager_impl.h
@@ -90,6 +90,7 @@
 
   // Overridden from PackageManager:
   void SetApplicationManager(ApplicationManager* manager) override;
+  void BuiltinAppLoaded(const GURL& url) override;
   void FetchRequest(
       URLRequestPtr request,
       const Fetcher::FetchCallback& loader_callback) override;
diff --git a/mojo/shell/test_package_manager.cc b/mojo/shell/test_package_manager.cc
index 3947b52..84a9d18 100644
--- a/mojo/shell/test_package_manager.cc
+++ b/mojo/shell/test_package_manager.cc
@@ -14,6 +14,7 @@
 TestPackageManager::~TestPackageManager() {}
 
 void TestPackageManager::SetApplicationManager(ApplicationManager* manager) {}
+void TestPackageManager::BuiltinAppLoaded(const GURL& url) {}
 void TestPackageManager::FetchRequest(
     URLRequestPtr request,
     const Fetcher::FetchCallback& loader_callback) {}
diff --git a/mojo/shell/test_package_manager.h b/mojo/shell/test_package_manager.h
index fc05576..267a37a3 100644
--- a/mojo/shell/test_package_manager.h
+++ b/mojo/shell/test_package_manager.h
@@ -22,6 +22,7 @@
  private:
   // Overridden from PackageManager:
   void SetApplicationManager(ApplicationManager* manager) override;
+  void BuiltinAppLoaded(const GURL& url) override;
   void FetchRequest(
       URLRequestPtr request,
       const Fetcher::FetchCallback& loader_callback) override;
diff --git a/testing/scripts/run_under_valgrind.py b/testing/scripts/run_under_valgrind.py
index d13ecd2..789aa55 100755
--- a/testing/scripts/run_under_valgrind.py
+++ b/testing/scripts/run_under_valgrind.py
@@ -12,11 +12,10 @@
 
 
 def main_run(args):
-  rc = common.run_command([
+  rc = common.run_runtest(args, [
       os.path.join(common.SRC_DIR, 'tools', 'valgrind', 'chrome_tests.sh'),
       '--tool', 'memcheck',
-      '--target', args.build_config_fs,
-      '--build-dir', 'src/out',
+      '--build-dir', os.path.join(common.SRC_DIR, 'out', args.build_config_fs),
     ] + args.args)
 
   json.dump({
diff --git a/third_party/WebKit/Source/wtf/dtoa/utils.h b/third_party/WebKit/Source/wtf/dtoa/utils.h
index dcc433f..0a61c015 100644
--- a/third_party/WebKit/Source/wtf/dtoa/utils.h
+++ b/third_party/WebKit/Source/wtf/dtoa/utils.h
@@ -163,9 +163,9 @@
         // Returns the pointer to the start of the data in the vector.
         T* start() const { return start_; }
 
-        // Access individual vector elements.
+        // Access individual vector elements - checks bounds in debug mode.
         T& operator[](int index) const {
-            RELEASE_ASSERT(0 <= index && index < length_);
+            ASSERT(0 <= index && index < length_);
             return start_[index];
         }
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index a0d7f70..c4ae4323 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -726,6 +726,7 @@
       'linux_chromium_asan_rel_ng': 'swarming_asan_lsan_gyp_release_trybot',
       'linux_full_bisect_builder': 'swarming_gyp_release_bot',
       'linux_site_isolation': 'gn_release_trybot',
+      'linux_valgrind': 'gyp_valgrind_release_bot',
       'linux_chromium_compile_rel_ng': 'swarming_gn_release_trybot',
       'linux_chromium_rel_ng': 'swarming_gpu_tests_gn_release_trybot',
       'linux_chromium_cfi_rel_ng': 'gn_cfi_release_trybot',
diff --git a/ui/file_manager/audio_player/manifest.json b/ui/file_manager/audio_player/manifest.json
index 30bca62..c5e89fe 100644
--- a/ui/file_manager/audio_player/manifest.json
+++ b/ui/file_manager/audio_player/manifest.json
@@ -24,12 +24,7 @@
       "fileSystem": ["requestFileSystem", "write"]
     },
     "fullscreen",
-    {
-      // TODO(ryoh): we do not need any permissions to use getMetadata,
-      // but mediaGalleriesAPI requires nonempty list,
-      // or treated as invalid permission requests.
-      "mediaGalleries": ["we don't need any permissions"]
-    },
+    "mediaGalleries",
     "mediaPlayerPrivate",
     "power",
     "storage",
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 6c2606e..58222b4 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -36,12 +36,7 @@
     "https://drive.google.com/",
     "https://www.google-analytics.com/",
     "launcherSearchProvider",
-    {
-      // TODO(ryoh): we do not need any permissions to use getMetadata,
-      // but mediaGalleriesAPI requires nonempty list,
-      // or treated as invalid permission requests.
-      "mediaGalleries": ["we don't need any permissions"]
-    },
+    "mediaGalleries",
     "mediaPlayerPrivate",
     "metricsPrivate",
     "notifications",
diff --git a/ui/file_manager/gallery/manifest.json b/ui/file_manager/gallery/manifest.json
index 7ae2b2272..d67cda1 100644
--- a/ui/file_manager/gallery/manifest.json
+++ b/ui/file_manager/gallery/manifest.json
@@ -28,12 +28,7 @@
       "fileSystem": ["requestFileSystem", "write"]
     },
     "fullscreen",
-    {
-      // TODO(ryoh): we do not need any permissions to use getMetadata,
-      // but mediaGalleriesAPI requires nonempty list,
-      // or treated as invalid permission requests.
-      "mediaGalleries": ["we don't need any permissions"]
-    },
+    "mediaGalleries",
     "metricsPrivate",
     "storage",
     "webview"