diff --git a/DEPS b/DEPS
index fb5af853..05c2257 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # 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': '2aeae78a2ce3b036f0401fd0381d6fd6e2a7a1fc',
+  'skia_revision': '3c727d2386059c1d7cbdcdc9bef5fa18ed33667e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
diff --git a/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py b/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py
index 5faec39..512caf7 100644
--- a/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py
+++ b/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_perf_pages.py
@@ -108,7 +108,7 @@
          timeout=10)
 
       # Load Media
-      self.ExecuteAsyncJavaScript2(
+      self.ExecuteAsyncJavaScript(
           action_runner,
           js_template.Render(
               'loadMedia({{ url }});', url=utils.GetInternalVideoURL()),
@@ -120,7 +120,7 @@
       action_runner.ExecuteJavaScript2('collectPerfData();')
       action_runner.Wait(SESSION_TIME)
       # Stop session
-      self.ExecuteAsyncJavaScript2(
+      self.ExecuteAsyncJavaScript(
           action_runner,
           'stopSession();',
           lambda: not action_runner.EvaluateJavaScript2('currentSession'),
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 424afed2..abb9fff 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-9269.0.0
\ No newline at end of file
+9272.0.0
\ No newline at end of file
diff --git a/chromeos/audio/OWNERS b/chromeos/audio/OWNERS
index 24c3960..ca6d3519 100644
--- a/chromeos/audio/OWNERS
+++ b/chromeos/audio/OWNERS
@@ -1,2 +1 @@
 jennyz@chromium.org
-hshi@chromium.org
diff --git a/media/blink/cdm_result_promise_helper.h b/media/blink/cdm_result_promise_helper.h
index 443f646..badeb5d6 100644
--- a/media/blink/cdm_result_promise_helper.h
+++ b/media/blink/cdm_result_promise_helper.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/time/time.h"
 #include "media/base/cdm_promise.h"
 #include "media/blink/media_blink_export.h"
 #include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc
index d52ccadc..eab2aef 100644
--- a/media/blink/cdm_session_adapter.cc
+++ b/media/blink/cdm_session_adapter.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
@@ -166,7 +167,8 @@
       kMediaEME + GetKeySystemNameForUMA(key_system) + kDot;
 
   // Only report time for successful CDM creation.
-  ReportTimeToCreateCdmUMA(base::TimeTicks::Now() - start_time);
+  base::UmaHistogramTimes(key_system_uma_prefix_ + kTimeToCreateCdmUMAName,
+                          base::TimeTicks::Now() - start_time);
 
   cdm_ = cdm;
 
@@ -240,14 +242,4 @@
   return (session != sessions_.end()) ? session->second.get() : NULL;
 }
 
-void CdmSessionAdapter::ReportTimeToCreateCdmUMA(base::TimeDelta time) const {
-  // Note: This leaks memory, which is expected behavior.
-  base::HistogramBase* histogram = base::Histogram::FactoryTimeGet(
-      GetKeySystemUMAPrefix() + kTimeToCreateCdmUMAName,
-      base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(10),
-      50, base::HistogramBase::kUmaTargetedHistogramFlag);
-
-  histogram->AddTime(time);
-}
-
 }  // namespace media
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h
index d2692971..3a4a7a8 100644
--- a/media/blink/cdm_session_adapter.h
+++ b/media/blink/cdm_session_adapter.h
@@ -130,8 +130,6 @@
   WebContentDecryptionModuleSessionImpl* GetSession(
       const std::string& session_id);
 
-  void ReportTimeToCreateCdmUMA(base::TimeDelta cdm_creation_time) const;
-
   scoped_refptr<ContentDecryptionModule> cdm_;
 
   SessionMap sessions_;
diff --git a/media/blink/new_session_cdm_result_promise.cc b/media/blink/new_session_cdm_result_promise.cc
index 2f37a3e..3536454 100644
--- a/media/blink/new_session_cdm_result_promise.cc
+++ b/media/blink/new_session_cdm_result_promise.cc
@@ -5,11 +5,14 @@
 #include "media/blink/new_session_cdm_result_promise.h"
 
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "media/blink/cdm_result_promise_helper.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 
 namespace media {
 
+const char kTimeUMAPrefix[] = "TimeTo.";
+
 static blink::WebContentDecryptionModuleResult::SessionStatus ConvertStatus(
     SessionInitStatus status) {
   switch (status) {
@@ -28,12 +31,14 @@
 
 NewSessionCdmResultPromise::NewSessionCdmResultPromise(
     const blink::WebContentDecryptionModuleResult& result,
+    const std::string& key_system_uma_prefix,
     const std::string& uma_name,
     const SessionInitializedCB& new_session_created_cb)
     : web_cdm_result_(result),
+      key_system_uma_prefix_(key_system_uma_prefix),
       uma_name_(uma_name),
-      new_session_created_cb_(new_session_created_cb) {
-}
+      new_session_created_cb_(new_session_created_cb),
+      creation_time_(base::TimeTicks::Now()) {}
 
 NewSessionCdmResultPromise::~NewSessionCdmResultPromise() {
   if (!IsPromiseSettled())
@@ -52,7 +57,12 @@
   }
 
   MarkPromiseSettled();
-  ReportCdmResultUMA(uma_name_, SUCCESS);
+  ReportCdmResultUMA(key_system_uma_prefix_ + uma_name_, SUCCESS);
+
+  // Only report time for promise resolution (not rejection).
+  base::UmaHistogramTimes(key_system_uma_prefix_ + kTimeUMAPrefix + uma_name_,
+                          base::TimeTicks::Now() - creation_time_);
+
   web_cdm_result_.completeWithSession(ConvertStatus(status));
 }
 
diff --git a/media/blink/new_session_cdm_result_promise.h b/media/blink/new_session_cdm_result_promise.h
index 7f40422e..7e38abf 100644
--- a/media/blink/new_session_cdm_result_promise.h
+++ b/media/blink/new_session_cdm_result_promise.h
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/time/time.h"
 #include "media/base/cdm_promise.h"
 #include "media/blink/media_blink_export.h"
 #include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h"
@@ -44,6 +45,7 @@
  public:
   NewSessionCdmResultPromise(
       const blink::WebContentDecryptionModuleResult& result,
+      const std::string& key_system_uma_prefix,
       const std::string& uma_name,
       const SessionInitializedCB& new_session_created_cb);
   ~NewSessionCdmResultPromise() override;
@@ -57,13 +59,17 @@
  private:
   blink::WebContentDecryptionModuleResult web_cdm_result_;
 
-  // UMA name to report result to.
+  // UMA prefix and name to report result and time to.
+  std::string key_system_uma_prefix_;
   std::string uma_name_;
 
   // Called on resolve() to convert the session ID into a SessionInitStatus to
   // be reported to blink.
   SessionInitializedCB new_session_created_cb_;
 
+  // Time when |this| is created.
+  base::TimeTicks creation_time_;
+
   DISALLOW_COPY_AND_ASSIGN(NewSessionCdmResultPromise);
 };
 
diff --git a/media/blink/webcontentdecryptionmodulesession_impl.cc b/media/blink/webcontentdecryptionmodulesession_impl.cc
index e7546ffa..4c306ce7 100644
--- a/media/blink/webcontentdecryptionmodulesession_impl.cc
+++ b/media/blink/webcontentdecryptionmodulesession_impl.cc
@@ -360,7 +360,7 @@
   adapter_->InitializeNewSession(
       eme_init_data_type, sanitized_init_data, convertSessionType(session_type),
       std::unique_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise(
-          result, adapter_->GetKeySystemUMAPrefix() + kGenerateRequestUMAName,
+          result, adapter_->GetKeySystemUMAPrefix(), kGenerateRequestUMAName,
           base::Bind(
               &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
               weak_ptr_factory_.GetWeakPtr()))));
@@ -394,7 +394,7 @@
   adapter_->LoadSession(
       CdmSessionType::PERSISTENT_LICENSE_SESSION, sanitized_session_id,
       std::unique_ptr<NewSessionCdmPromise>(new NewSessionCdmResultPromise(
-          result, adapter_->GetKeySystemUMAPrefix() + kLoadSessionUMAName,
+          result, adapter_->GetKeySystemUMAPrefix(), kLoadSessionUMAName,
           base::Bind(
               &WebContentDecryptionModuleSessionImpl::OnSessionInitialized,
               weak_ptr_factory_.GetWeakPtr()))));
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/async-call-stack-async-function-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/async-call-stack-async-function-expected.txt
index 11c0a34d..6d1f7dd 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/async-call-stack-async-function-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/async-call-stack-async-function-expected.txt
@@ -2,11 +2,10 @@
 
 Set timer for test function.
 footest.js:6
-boo awaits foocreated:  test.js:2
+boo awaits foo
 bootest.js:12
-testFunction awaits boocreated:  test.js:9
+testFunction awaits boo
 testFunctiontest.js:18
-async function (async)created:  test.js:15
 setTimeout (async)
 scheduleTestFunctiondebugger-test.js:3
 (anonymous)VM:1
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 8a23215..e48a164 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1107,6 +1107,7 @@
     "html/HTMLDimensionTest.cpp",
     "html/HTMLEmbedElementTest.cpp",
     "html/HTMLFormControlElementTest.cpp",
+    "html/HTMLIFrameElementAllowTest.cpp",
     "html/HTMLIFrameElementPermissionsTest.cpp",
     "html/HTMLIFrameElementTest.cpp",
     "html/HTMLImageElementTest.cpp",
diff --git a/third_party/WebKit/Source/core/dom/SandboxFlags.cpp b/third_party/WebKit/Source/core/dom/SandboxFlags.cpp
index 4b92e66..34e62da 100644
--- a/third_party/WebKit/Source/core/dom/SandboxFlags.cpp
+++ b/third_party/WebKit/Source/core/dom/SandboxFlags.cpp
@@ -26,6 +26,7 @@
 
 #include "core/dom/SandboxFlags.h"
 
+#include "core/html/HTMLIFrameElement.h"
 #include "core/html/parser/HTMLParserIdioms.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "wtf/text/StringBuilder.h"
@@ -72,21 +73,17 @@
                    topNavWithUserActivationInSandboxEnabled()) {
       flags &= ~SandboxTopNavigationWithUserActivation;
     } else {
-      if (numberOfTokenErrors)
-        tokenErrors.append(", '");
-      else
-        tokenErrors.append('\'');
+      tokenErrors.append(tokenErrors.isEmpty() ? "'" : ", '");
       tokenErrors.append(sandboxToken);
-      tokenErrors.append('\'');
+      tokenErrors.append("'");
       numberOfTokenErrors++;
     }
   }
 
   if (numberOfTokenErrors) {
-    if (numberOfTokenErrors > 1)
-      tokenErrors.append(" are invalid sandbox flags.");
-    else
-      tokenErrors.append(" is an invalid sandbox flag.");
+    tokenErrors.append(numberOfTokenErrors > 1
+                           ? " are invalid sandbox flags."
+                           : " is an invalid sandbox flag.");
     invalidTokensErrorMessage = tokenErrors.toString();
   }
 
diff --git a/third_party/WebKit/Source/core/html/BUILD.gn b/third_party/WebKit/Source/core/html/BUILD.gn
index 62ab1dd..3630cce 100644
--- a/third_party/WebKit/Source/core/html/BUILD.gn
+++ b/third_party/WebKit/Source/core/html/BUILD.gn
@@ -85,6 +85,8 @@
     "HTMLHtmlElement.cpp",
     "HTMLHtmlElement.h",
     "HTMLIFrameElement.cpp",
+    "HTMLIFrameElementAllow.cpp",
+    "HTMLIFrameElementAllow.h",
     "HTMLIFrameElementPermissions.cpp",
     "HTMLIFrameElementPermissions.h",
     "HTMLIFrameElementSandbox.cpp",
diff --git a/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5 b/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5
index 0ad4d65e..e88f53b8 100644
--- a/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5
+++ b/third_party/WebKit/Source/core/html/HTMLAttributeNames.json5
@@ -15,6 +15,7 @@
     "action",
     "align",
     "alink",
+    "allow",
     "allowfullscreen",
     "allowpaymentrequest",
     "alt",
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
index 0ac2d29..b9512059 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -40,6 +40,7 @@
     : HTMLFrameElementBase(iframeTag, document),
       m_didLoadNonEmptyDocument(false),
       m_sandbox(HTMLIFrameElementSandbox::create(this)),
+      m_allow(HTMLIFrameElementAllow::create(this)),
       m_referrerPolicy(ReferrerPolicyDefault) {}
 
 DEFINE_NODE_FACTORY(HTMLIFrameElement)
@@ -47,6 +48,7 @@
 DEFINE_TRACE(HTMLIFrameElement) {
   visitor->trace(m_sandbox);
   visitor->trace(m_permissions);
+  visitor->trace(m_allow);
   HTMLFrameElementBase::trace(visitor);
   Supplementable<HTMLIFrameElement>::trace(visitor);
 }
@@ -63,6 +65,10 @@
   return m_permissions.get();
 }
 
+DOMTokenList* HTMLIFrameElement::allow() const {
+  return m_allow.get();
+}
+
 bool HTMLIFrameElement::isPresentationAttribute(
     const QualifiedName& name) const {
   if (name == widthAttr || name == heightAttr || name == alignAttr ||
@@ -158,6 +164,9 @@
     m_csp = value;
     if (m_csp != oldCSP)
       frameOwnerPropertiesChanged();
+  } else if (RuntimeEnabledFeatures::featurePolicyEnabled() &&
+             name == allowAttr) {
+    m_allow->setValue(value);
   } else {
     if (name == srcAttr)
       logUpdateAttributeIfIsolatedWorldAndInDocument("iframe", params);
@@ -220,6 +229,19 @@
   setSynchronizedLazyAttribute(sandboxAttr, m_sandbox->value());
 }
 
+void HTMLIFrameElement::allowValueWasSet() {
+  String invalidTokens;
+  m_allowedFeatureNames = m_allow->parseAllowedFeatureNames(invalidTokens);
+  if (!invalidTokens.isNull()) {
+    document().addConsoleMessage(ConsoleMessage::create(
+        OtherMessageSource, ErrorMessageLevel,
+        "Error while parsing the 'allow' attribute: " + invalidTokens));
+  }
+  setSynchronizedLazyAttribute(allowAttr, m_allow->value());
+  // TODO(lunalu): Once allowedFeatureNames is passed to frame owner, call
+  // frameOwnerPropertiesChanged.
+}
+
 ReferrerPolicy HTMLIFrameElement::referrerPolicyAttribute() {
   return m_referrerPolicy;
 }
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
index 6f1d0265..effd213 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
@@ -26,9 +26,11 @@
 
 #include "core/CoreExport.h"
 #include "core/html/HTMLFrameElementBase.h"
+#include "core/html/HTMLIFrameElementAllow.h"
 #include "core/html/HTMLIFrameElementPermissions.h"
 #include "core/html/HTMLIFrameElementSandbox.h"
 #include "platform/Supplementable.h"
+#include "public/platform/WebFeaturePolicy.h"
 #include "public/platform/WebVector.h"
 #include "public/platform/modules/permissions/permission.mojom-blink.h"
 
@@ -46,9 +48,11 @@
   ~HTMLIFrameElement() override;
   DOMTokenList* sandbox() const;
   DOMTokenList* permissions() const;
+  DOMTokenList* allow() const;
 
   void sandboxValueWasSet();
   void permissionsValueWasSet();
+  void allowValueWasSet();
 
  private:
   explicit HTMLIFrameElement(Document&);
@@ -91,8 +95,10 @@
   bool m_allowPaymentRequest;
   Member<HTMLIFrameElementSandbox> m_sandbox;
   Member<HTMLIFrameElementPermissions> m_permissions;
+  Member<HTMLIFrameElementAllow> m_allow;
 
   WebVector<mojom::blink::PermissionName> m_delegatedPermissions;
+  WebVector<WebFeaturePolicyFeature> m_allowedFeatureNames;
 
   ReferrerPolicy m_referrerPolicy;
 };
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl b/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl
index 0a43b10..862f9aa 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.idl
@@ -29,6 +29,7 @@
     [CEReactions, Reflect] attribute boolean allowFullscreen;
     [CEReactions, Reflect] attribute DOMString width;
     [CEReactions, Reflect] attribute DOMString height;
+
     [CheckSecurity=ReturnValue] readonly attribute Document? contentDocument;
     readonly attribute Window? contentWindow;
     [CheckSecurity=ReturnValue, RaisesException] Document? getSVGDocument();
@@ -38,6 +39,9 @@
     // https://w3c.github.io/webappsec-csp/embedded/#dom-htmliframeelement-csp
     [RuntimeEnabled=EmbedderCSPEnforcement, CEReactions, Reflect] attribute DOMString csp;
 
+    // Feature Policy allow attribute
+    // https://wicg.github.io/feature-policy/
+    [RuntimeEnabled=FeaturePolicy, CEReactions, PutForwards=value] readonly attribute DOMTokenList allow;
     // obsolete members
     // https://html.spec.whatwg.org/#HTMLIFrameElement-partial
     [CEReactions, Reflect] attribute DOMString align;
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.cpp
new file mode 100644
index 0000000..1d314631
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.cpp
@@ -0,0 +1,72 @@
+// Copyright 2017 The Chromium 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 "core/html/HTMLIFrameElementAllow.h"
+
+#include "core/html/HTMLIFrameElement.h"
+#include "platform/feature_policy/FeaturePolicy.h"
+
+using blink::WebFeaturePolicyFeature;
+
+namespace blink {
+
+HTMLIFrameElementAllow::HTMLIFrameElementAllow(HTMLIFrameElement* element)
+    : DOMTokenList(this), m_element(element) {}
+
+HTMLIFrameElementAllow::~HTMLIFrameElementAllow() {}
+
+DEFINE_TRACE(HTMLIFrameElementAllow) {
+  visitor->trace(m_element);
+  DOMTokenList::trace(visitor);
+  DOMTokenListObserver::trace(visitor);
+}
+
+Vector<WebFeaturePolicyFeature>
+HTMLIFrameElementAllow::parseAllowedFeatureNames(
+    String& invalidTokensErrorMessage) const {
+  Vector<WebFeaturePolicyFeature> featureNames;
+  unsigned numTokenErrors = 0;
+  StringBuilder tokenErrors;
+  const SpaceSplitString& tokens = this->tokens();
+
+  // Collects a list of valid feature names.
+  for (size_t i = 0; i < tokens.size(); ++i) {
+    WebFeaturePolicyFeature feature =
+        FeaturePolicy::getWebFeaturePolicyFeature(tokens[i]);
+    if (feature == WebFeaturePolicyFeature::NotFound) {
+      tokenErrors.append(tokenErrors.isEmpty() ? "'" : ", '");
+      tokenErrors.append(tokens[i]);
+      tokenErrors.append("'");
+      ++numTokenErrors;
+    } else {
+      featureNames.push_back(feature);
+    }
+  }
+
+  if (numTokenErrors) {
+    tokenErrors.append(numTokenErrors > 1 ? " are invalid feature names."
+                                          : " is an invalid feature name.");
+    invalidTokensErrorMessage = tokenErrors.toString();
+  }
+
+  // Create a unique set of feature names.
+  std::sort(featureNames.begin(), featureNames.end());
+  auto it = std::unique(featureNames.begin(), featureNames.end());
+  featureNames.shrink(it - featureNames.begin());
+
+  return featureNames;
+}
+
+bool HTMLIFrameElementAllow::validateTokenValue(const AtomicString& tokenValue,
+                                                ExceptionState&) const {
+  return FeaturePolicy::getWebFeaturePolicyFeature(tokenValue.getString()) !=
+         WebFeaturePolicyFeature::NotFound;
+}
+
+void HTMLIFrameElementAllow::valueWasSet() {
+  DCHECK(m_element);
+  m_element->allowValueWasSet();
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.h b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.h
new file mode 100644
index 0000000..7f62d3a
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllow.h
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium 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 HTMLIFrameElementAllow_h
+#define HTMLIFrameElementAllow_h
+
+#include "core/CoreExport.h"
+#include "core/dom/DOMTokenList.h"
+#include "platform/heap/Handle.h"
+#include "public/platform/WebFeaturePolicy.h"
+
+namespace blink {
+
+class HTMLIFrameElement;
+
+class CORE_EXPORT HTMLIFrameElementAllow final : public DOMTokenList,
+                                                 public DOMTokenListObserver {
+  USING_GARBAGE_COLLECTED_MIXIN(HTMLIFrameElementAllow);
+
+ public:
+  static HTMLIFrameElementAllow* create(HTMLIFrameElement* element) {
+    return new HTMLIFrameElementAllow(element);
+  }
+
+  ~HTMLIFrameElementAllow() override;
+
+  // Returns unique set of valid feature names.
+  Vector<WebFeaturePolicyFeature> parseAllowedFeatureNames(
+      String& invalidTokensErrorMessage) const;
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  explicit HTMLIFrameElementAllow(HTMLIFrameElement*);
+  bool validateTokenValue(const AtomicString&, ExceptionState&) const override;
+
+  // DOMTokenListObserver.
+  void valueWasSet() override;
+
+  Member<HTMLIFrameElement> m_element;
+};
+
+}  // namespace blink
+
+#endif  // HTMLIFrameElementAllow_h
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementAllowTest.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllowTest.cpp
new file mode 100644
index 0000000..42966c9
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementAllowTest.cpp
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium 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 "core/html/HTMLIFrameElementAllow.h"
+
+#include "core/dom/Document.h"
+#include "core/html/HTMLIFrameElement.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::UnorderedElementsAre;
+
+namespace blink {
+
+TEST(HTMLIFrameElementAllowTest, ParseAllowedFeatureNamesValid) {
+  Document* document = Document::create();
+  HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document);
+  HTMLIFrameElementAllow* allow = HTMLIFrameElementAllow::create(iframe);
+  String errorMessage;
+  Vector<WebFeaturePolicyFeature> result;
+
+  allow->setValue("");
+  result = allow->parseAllowedFeatureNames(errorMessage);
+  EXPECT_TRUE(result.isEmpty());
+
+  allow->setValue("fullscreen");
+  result = allow->parseAllowedFeatureNames(errorMessage);
+  EXPECT_THAT(result,
+              UnorderedElementsAre(WebFeaturePolicyFeature::Fullscreen));
+
+  allow->setValue("fullscreen payment vibrate");
+  result = allow->parseAllowedFeatureNames(errorMessage);
+  EXPECT_THAT(result, UnorderedElementsAre(WebFeaturePolicyFeature::Fullscreen,
+                                           WebFeaturePolicyFeature::Payment,
+                                           WebFeaturePolicyFeature::Vibrate));
+}
+
+TEST(HTMLIFrameElementAllowTest, ParseAllowedFeatureNamesInvalid) {
+  Document* document = Document::create();
+  HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document);
+  HTMLIFrameElementAllow* allow = HTMLIFrameElementAllow::create(iframe);
+  String errorMessage;
+  Vector<WebFeaturePolicyFeature> result;
+
+  allow->setValue("invalid");
+  result = allow->parseAllowedFeatureNames(errorMessage);
+  EXPECT_TRUE(result.isEmpty());
+  EXPECT_EQ("'invalid' is an invalid feature name.", errorMessage);
+
+  allow->setValue("fullscreen invalid1 invalid2");
+  result = allow->parseAllowedFeatureNames(errorMessage);
+  EXPECT_THAT(result,
+              UnorderedElementsAre(WebFeaturePolicyFeature::Fullscreen));
+  EXPECT_EQ("'invalid1', 'invalid2' are invalid feature names.", errorMessage);
+
+  allow->setValue("fullscreen invalid vibrate fullscreen");
+  result = allow->parseAllowedFeatureNames(errorMessage);
+  EXPECT_EQ("'invalid' is an invalid feature name.", errorMessage);
+  EXPECT_THAT(result, UnorderedElementsAre(WebFeaturePolicyFeature::Fullscreen,
+                                           WebFeaturePolicyFeature::Vibrate));
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp
index 32c6a5e0..f5bff6e0 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementPermissions.cpp
@@ -63,21 +63,16 @@
     if (getPermissionType(tokens[i], &type)) {
       permissions.push_back(type);
     } else {
-      if (numTokenErrors)
-        tokenErrors.append(", '");
-      else
-        tokenErrors.append('\'');
+      tokenErrors.append(tokenErrors.isEmpty() ? "'" : ", '");
       tokenErrors.append(tokens[i]);
-      tokenErrors.append('\'');
+      tokenErrors.append("'");
       ++numTokenErrors;
     }
   }
 
   if (numTokenErrors) {
-    if (numTokenErrors > 1)
-      tokenErrors.append(" are invalid permissions flags.");
-    else
-      tokenErrors.append(" is an invalid permissions flag.");
+    tokenErrors.append(numTokenErrors > 1 ? " are invalid permissions flags."
+                                          : " is an invalid permissions flag.");
     invalidTokensErrorMessage = tokenErrors.toString();
   }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
index 2651ecb..765ef853 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElementTest.cpp
@@ -9,7 +9,7 @@
 
 namespace blink {
 
-// Test setting via the Element attribute (HTML codepath).
+// Test setting permission via the Element attribute (HTML codepath).
 TEST(HTMLIFrameElementTest, SetPermissionsAttribute) {
   Document* document = Document::create();
   HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document);
@@ -20,7 +20,7 @@
   EXPECT_EQ("geolocation notifications", iframe->permissions()->value());
 }
 
-// Test setting via the DOMTokenList (JS codepath).
+// Test setting permission via the DOMTokenList (JS codepath).
 TEST(HTMLIFrameElementTest, SetPermissionsAttributeJS) {
   Document* document = Document::create();
   HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document);
@@ -29,4 +29,24 @@
   EXPECT_EQ("midi", iframe->getAttribute(HTMLNames::permissionsAttr));
 }
 
+// Test setting feature policy via the Element attribute (HTML codepath).
+TEST(HTMLIFrameElementTest, SetAllowAttribute) {
+  Document* document = Document::create();
+  HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document);
+
+  iframe->setAttribute(HTMLNames::allowAttr, "fullscreen");
+  EXPECT_EQ("fullscreen", iframe->allow()->value());
+  iframe->setAttribute(HTMLNames::allowAttr, "fullscreen vibrate");
+  EXPECT_EQ("fullscreen vibrate", iframe->allow()->value());
+}
+
+// Test setting feature policy via the DOMTokenList (JS codepath).
+TEST(HTMLIFrameElementTest, SetAllowAttributeJS) {
+  Document* document = Document::create();
+  HTMLIFrameElement* iframe = HTMLIFrameElement::create(*document);
+
+  iframe->allow()->setValue("fullscreen");
+  EXPECT_EQ("fullscreen", iframe->getAttribute(HTMLNames::allowAttr));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
index 3869aa84..933f79f 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
@@ -93,8 +93,8 @@
     var peviousStackTrace = details.callFrames;
     while (asyncStackTrace) {
       var title = '';
-      if (asyncStackTrace.description === 'async function' && peviousStackTrace.length &&
-          asyncStackTrace.callFrames.length) {
+      var isAwait = asyncStackTrace.description === 'async function';
+      if (isAwait && peviousStackTrace.length && asyncStackTrace.callFrames.length) {
         var lastPreviousFrame = peviousStackTrace[peviousStackTrace.length - 1];
         var topFrame = asyncStackTrace.callFrames[0];
         var lastPreviousFrameName = UI.beautifyFunctionName(lastPreviousFrame.functionName);
@@ -111,11 +111,16 @@
                 /** @type {!SDK.DebuggerModel.Location} */ (this._itemLocation(item))));
         hiddenCallFramesCount += asyncStackTrace.callFrames.length - asyncItems.length;
       }
-      if (asyncItems.length || asyncStackTrace.promiseCreationFrame) {
-        var titleItem = {asyncStackHeader: title};
-        if (asyncStackTrace.promiseCreationFrame)
-          titleItem.promiseCreationFrame = asyncStackTrace.promiseCreationFrame;
-        items.push(titleItem);
+
+      if (asyncStackTrace.promiseCreationFrame && !isAwait) {
+        var chainedItem = {promiseCreationFrame: asyncStackTrace.promiseCreationFrame};
+        if (!Bindings.blackboxManager.isBlackboxedRawLocation(
+                /** @type {!SDK.DebuggerModel.Location} */ (this._itemLocation(chainedItem))))
+          items.push(chainedItem);
+      }
+
+      if (asyncItems.length) {
+        items.push({asyncStackHeader: title});
         items = items.concat(asyncItems);
       }
 
@@ -147,13 +152,15 @@
    */
   createElementForItem(item) {
     var element = createElementWithClass('div', 'call-frame-item');
-    element.createChild('div', 'call-frame-item-title').textContent = this._itemTitle(item);
+    var title = element.createChild('div', 'call-frame-item-title');
+    if (item.promiseCreationFrame)
+      title.createChild('div', 'call-frame-chained-arrow').textContent = '\u2935';
+    title.createChild('div', 'call-frame-title-text').textContent = this._itemTitle(item);
     if (item.asyncStackHeader)
       element.classList.add('async-header');
 
     var location = this._itemLocation(item);
     if (location) {
-      element.classList.add('contains-location');
       if (Bindings.blackboxManager.isBlackboxedRawLocation(location))
         element.classList.add('blackboxed-call-frame');
 
@@ -164,13 +171,12 @@
         var uiLocation = liveLocation.uiLocation();
         if (!uiLocation)
           return;
-        var text = (hasPromiseCreationFrame ? Common.UIString('created:  ') : '') + uiLocation.linkText();
+        var text = uiLocation.linkText();
         linkElement.textContent = text.trimMiddle(30);
         linkElement.title = text;
       }
 
       var linkElement = element.createChild('div', 'call-frame-location');
-      var hasPromiseCreationFrame = !!item.promiseCreationFrame;
       Bindings.debuggerWorkspaceBinding.createCallFrameLiveLocation(location, updateLocation, this._locationPool);
     }
 
@@ -233,6 +239,8 @@
       return UI.beautifyFunctionName(item.debuggerCallFrame.functionName);
     if (item.runtimeCallFrame)
       return UI.beautifyFunctionName(item.runtimeCallFrame.functionName);
+    if (item.promiseCreationFrame)
+      return Common.UIString('chained at');
     return item.asyncStackHeader || '';
   }
 
@@ -353,6 +361,8 @@
     var text = [];
     for (var i = 0; i < this._list.length(); i++) {
       var item = this._list.itemAtIndex(i);
+      if (item.promiseCreationFrame)
+        continue;
       var itemText = this._itemTitle(item);
       var location = this._itemLocation(item);
       if (location) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/callStackSidebarPane.css b/third_party/WebKit/Source/devtools/front_end/sources/callStackSidebarPane.css
index 652f133c..d92c3c58 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/callStackSidebarPane.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/callStackSidebarPane.css
@@ -25,11 +25,22 @@
     flex-wrap: wrap;
 }
 
+.call-frame-chained-arrow {
+    transform: rotate(180deg);
+    margin-right: 3px;
+    flex-shrink: 0;
+}
+
+.call-frame-title-text {
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
 .call-frame-item:not(.async-header) {
     border-top: 1px solid #efefef;
 }
 
-.call-frame-item.contains-location:hover {
+.call-frame-item:not(.async-header):hover {
     background-color: #eee;
 }
 
@@ -39,8 +50,7 @@
 
 .call-frame-item-title,
 .call-frame-location {
-    text-overflow: ellipsis;
-    overflow: hidden;
+    display: flex;
     white-space: nowrap;
 }
 
@@ -48,12 +58,6 @@
     color: #888;
     margin-left: auto;
     padding: 0 10px 0 10px;
-    background-color: white;
-    white-space: pre;
-}
-
-.call-frame-item:hover .call-frame-location {
-    background-color: inherit;
 }
 
 .async-header::before {
@@ -74,10 +78,6 @@
     padding: 0 5px;
 }
 
-.call-frame-item.contains-location:hover .call-frame-item-title {
-    background-color: inherit;
-}
-
 .blackboxed-call-frame {
     opacity: 0.6;
     font-style: italic;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index 1e0993b..46ae30a 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -386,6 +386,10 @@
       status: "experimental",
     },
     {
+      name: "FeaturePolicyExperimentalFeatures",
+      status: "experimental",
+    },
+    {
       name: "FileAPIBlobClose",
       status: "experimental",
     },
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
index f2d6cf5d..cc07f33c 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp
@@ -4,6 +4,7 @@
 
 #include "platform/feature_policy/FeaturePolicy.h"
 
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/json/JSONValues.h"
 #include "platform/network/HTTPParsers.h"
 #include "platform/weborigin/KURL.h"
@@ -59,6 +60,41 @@
 const FeaturePolicy::Feature kWebRTC{
     "webrtc", FeaturePolicy::FeatureDefault::EnableForAll};
 
+WebFeaturePolicyFeature FeaturePolicy::getWebFeaturePolicyFeature(
+    const String& feature) {
+  if (feature == "fullscreen")
+    return WebFeaturePolicyFeature::Fullscreen;
+  if (feature == "payment")
+    return WebFeaturePolicyFeature::Payment;
+  if (feature == "vibrate")
+    return WebFeaturePolicyFeature::Vibrate;
+  if (feature == "usermedia")
+    return WebFeaturePolicyFeature::Usermedia;
+  if (RuntimeEnabledFeatures::featurePolicyExperimentalFeaturesEnabled()) {
+    if (feature == "cookie")
+      return WebFeaturePolicyFeature::DocumentCookie;
+    if (feature == "domain")
+      return WebFeaturePolicyFeature::DocumentDomain;
+    if (feature == "docwrite")
+      return WebFeaturePolicyFeature::DocumentWrite;
+    if (feature == "geolocation")
+      return WebFeaturePolicyFeature::Geolocation;
+    if (feature == "midi")
+      return WebFeaturePolicyFeature::MidiFeature;
+    if (feature == "notifications")
+      return WebFeaturePolicyFeature::Notifications;
+    if (feature == "push")
+      return WebFeaturePolicyFeature::Push;
+    if (feature == "sync-script")
+      return WebFeaturePolicyFeature::SyncScript;
+    if (feature == "sync-xhr")
+      return WebFeaturePolicyFeature::SyncXHR;
+    if (feature == "webrtc")
+      return WebFeaturePolicyFeature::WebRTC;
+  }
+  return WebFeaturePolicyFeature::NotFound;
+}
+
 // static
 std::unique_ptr<FeaturePolicy::Whitelist> FeaturePolicy::Whitelist::from(
     const WebParsedFeaturePolicyDeclaration& parsedDeclaration) {
diff --git a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
index 94e84cb..f45ccd1 100644
--- a/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
+++ b/third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.h
@@ -157,6 +157,11 @@
 
   String toString();
 
+  // Returns the corresponding WebFeaturePolicyFeature enum given a feature
+  // string.
+  static WebFeaturePolicyFeature getWebFeaturePolicyFeature(
+      const String& feature);
+
  private:
   friend class FeaturePolicyTest;
   friend class FeaturePolicyInFrameTest;
diff --git a/third_party/zlib/google/OWNERS b/third_party/zlib/google/OWNERS
index ec86872..1ca2531 100644
--- a/third_party/zlib/google/OWNERS
+++ b/third_party/zlib/google/OWNERS
@@ -1,4 +1,3 @@
-hshi@chromium.org
 satorux@chromium.org
 
 # compression_utils*
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0834e1be..a78db125 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -25316,6 +25316,13 @@
   <summary>KeyError event count using the Clear Key key system.</summary>
 </histogram>
 
+<histogram name="Media.EME.ClearKey.TimeTo" units="ms">
+  <owner>xhwang@chromium.org</owner>
+  <summary>
+    The time it takes to resolve a CDM promise for Clear Key key system.
+  </summary>
+</histogram>
+
 <histogram name="Media.EME.KeySystemSupport.Widevine"
     enum="MediaKeySystemSupportStatus">
   <obsolete>
@@ -25411,6 +25418,13 @@
   <summary>System code count using an unknown key system.</summary>
 </histogram>
 
+<histogram name="Media.EME.Unknown.TimeTo" units="ms">
+  <owner>xhwang@chromium.org</owner>
+  <summary>
+    The time it takes to resolve a CDM promise for an unknown key system.
+  </summary>
+</histogram>
+
 <histogram name="Media.EME.Widevine" enum="CdmPromiseResult">
   <owner>sandersd@chromium.org</owner>
   <summary>
@@ -25472,6 +25486,13 @@
   <summary>System code count using the Widevine key system.</summary>
 </histogram>
 
+<histogram name="Media.EME.Widevine.TimeTo" units="ms">
+  <owner>xhwang@chromium.org</owner>
+  <summary>
+    The time it takes to resolve a CDM promise for the Widevine key system.
+  </summary>
+</histogram>
+
 <histogram name="Media.EME.Widevine.VideoCapability.HasEmptyRobustness"
     enum="BooleanEmpty">
   <owner>xhwang@chromium.org</owner>
@@ -113707,6 +113728,14 @@
   <affected-histogram name="Media.EME.Widevine"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="EmeTimeToResolvePromise" separator=".">
+  <suffix name="GenerateRequest" label="GenerateRequest promises only."/>
+  <suffix name="LoadSession" label="LoadSession promises only."/>
+  <affected-histogram name="Media.EME.ClearKey.TimeTo"/>
+  <affected-histogram name="Media.EME.Unknown.TimeTo"/>
+  <affected-histogram name="Media.EME.Widevine.TimeTo"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="EngagementScoreBuckets">
   <owner>calamity@chromium.org</owner>
   <suffix name="0"/>
diff --git a/ui/ozone/OWNERS b/ui/ozone/OWNERS
index 68277d59..ec43a6d 100644
--- a/ui/ozone/OWNERS
+++ b/ui/ozone/OWNERS
@@ -1,4 +1,3 @@
 rjkroege@chromium.org
 spang@chromium.org
 alexst@chromium.org
-hshi@chromium.org