extension_interaction_provider.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "extensions/renderer/extension_interaction_provider.h"
  5. #include "base/feature_list.h"
  6. #include "base/memory/ptr_util.h"
  7. #include "content/public/common/content_features.h"
  8. #include "extensions/renderer/bindings/get_per_context_data.h"
  9. #include "extensions/renderer/get_script_context.h"
  10. #include "extensions/renderer/script_context.h"
  11. #include "extensions/renderer/worker_thread_util.h"
  12. #include "third_party/blink/public/web/web_local_frame.h"
  13. namespace extensions {
  14. namespace {
  15. struct ExtensionInteractionData : public base::SupportsUserData::Data {
  16. static constexpr char kPerContextDataKey[] = "extension_interaction";
  17. int interaction_count = 0;
  18. int token_interaction_count = 0;
  19. };
  20. constexpr char ExtensionInteractionData::kPerContextDataKey[];
  21. } // namespace
  22. // ExtensionInteractionProvider::Token -----------------------------------------
  23. ExtensionInteractionProvider::Token::Token(bool for_worker)
  24. : is_for_service_worker_(for_worker) {}
  25. ExtensionInteractionProvider::Token::~Token() {}
  26. // ExtensionInteractionProvider::Scope -----------------------------------------
  27. ExtensionInteractionProvider::Scope::Scope() {}
  28. ExtensionInteractionProvider::Scope::~Scope() {}
  29. // static.
  30. std::unique_ptr<ExtensionInteractionProvider::Scope>
  31. ExtensionInteractionProvider::Scope::ForWorker(
  32. v8::Local<v8::Context> v8_context) {
  33. DCHECK(worker_thread_util::IsWorkerThread());
  34. auto scope = base::WrapUnique(new Scope());
  35. scope->worker_thread_interaction_ =
  36. std::make_unique<ScopedWorkerInteraction>(v8_context, false);
  37. return scope;
  38. }
  39. // static.
  40. std::unique_ptr<ExtensionInteractionProvider::Scope>
  41. ExtensionInteractionProvider::Scope::ForToken(
  42. v8::Local<v8::Context> v8_context,
  43. std::unique_ptr<InteractionProvider::Token> token) {
  44. Token* token_impl = static_cast<Token*>(token.get());
  45. if (!token_impl->is_for_service_worker()) {
  46. // UserActivationV2 replaces the concept of (scoped) tokens with a
  47. // frame-wide state, hence skips token forwarding.
  48. return nullptr;
  49. }
  50. auto scope = base::WrapUnique(new Scope());
  51. scope->worker_thread_interaction_ =
  52. std::make_unique<ScopedWorkerInteraction>(v8_context, true);
  53. return scope;
  54. }
  55. ExtensionInteractionProvider::Scope::ScopedWorkerInteraction::
  56. ScopedWorkerInteraction(v8::Local<v8::Context> v8_context,
  57. bool created_from_token)
  58. : v8_context_(v8_context), created_from_token_(created_from_token) {
  59. ExtensionInteractionData* per_context_data =
  60. GetPerContextData<ExtensionInteractionData>(v8_context, kCreateIfMissing);
  61. DCHECK(per_context_data);
  62. if (created_from_token_)
  63. per_context_data->token_interaction_count++;
  64. else
  65. per_context_data->interaction_count++;
  66. }
  67. ExtensionInteractionProvider::Scope::ScopedWorkerInteraction::
  68. ~ScopedWorkerInteraction() {
  69. ExtensionInteractionData* per_context_data =
  70. GetPerContextData<ExtensionInteractionData>(v8_context_,
  71. kDontCreateIfMissing);
  72. // If |v8_context_| was invalidated (e.g. because of JS running), bail out.
  73. if (!per_context_data)
  74. return;
  75. if (created_from_token_) {
  76. DCHECK_GT(per_context_data->token_interaction_count, 0);
  77. per_context_data->token_interaction_count--;
  78. } else {
  79. DCHECK_GT(per_context_data->interaction_count, 0);
  80. per_context_data->interaction_count--;
  81. }
  82. }
  83. // ExtensionInteractionProvider ------------------------------------------------
  84. ExtensionInteractionProvider::ExtensionInteractionProvider() = default;
  85. ExtensionInteractionProvider::~ExtensionInteractionProvider() = default;
  86. // static
  87. bool ExtensionInteractionProvider::HasActiveExtensionInteraction(
  88. v8::Local<v8::Context> v8_context) {
  89. // Service Worker based context:
  90. if (worker_thread_util::IsWorkerThread()) {
  91. ExtensionInteractionData* per_context_data =
  92. GetPerContextData<ExtensionInteractionData>(v8_context,
  93. kDontCreateIfMissing);
  94. if (per_context_data && (per_context_data->interaction_count > 0 ||
  95. per_context_data->token_interaction_count > 0)) {
  96. return true;
  97. }
  98. return worker_thread_util::HasWorkerContextProxyInteraction();
  99. }
  100. // RenderFrame based context:
  101. ScriptContext* script_context =
  102. GetScriptContextFromV8ContextChecked(v8_context);
  103. if (!script_context->web_frame())
  104. return false;
  105. return script_context->web_frame()->HasTransientUserActivation();
  106. }
  107. std::unique_ptr<InteractionProvider::Token>
  108. ExtensionInteractionProvider::GetCurrentToken(
  109. v8::Local<v8::Context> v8_context) const {
  110. if (worker_thread_util::IsWorkerThread()) {
  111. ExtensionInteractionData* per_context_data =
  112. GetPerContextData<ExtensionInteractionData>(v8_context,
  113. kDontCreateIfMissing);
  114. const bool has_extension_api_interaction =
  115. per_context_data && per_context_data->interaction_count > 0;
  116. // Only create token for Service Workers when we have an interaction taking
  117. // place that wasn't created through another token (i.e. do not look at
  118. // worker_data->token_interaction_count).
  119. if (!has_extension_api_interaction &&
  120. !worker_thread_util::HasWorkerContextProxyInteraction()) {
  121. return nullptr;
  122. }
  123. return base::WrapUnique(new Token(true));
  124. }
  125. // Render frame based token.
  126. return base::WrapUnique(new Token(false));
  127. }
  128. std::unique_ptr<InteractionProvider::Scope>
  129. ExtensionInteractionProvider::CreateScopedInteraction(
  130. v8::Local<v8::Context> v8_context,
  131. std::unique_ptr<InteractionProvider::Token> token) const {
  132. return Scope::ForToken(v8_context, std::move(token));
  133. }
  134. bool ExtensionInteractionProvider::HasActiveInteraction(
  135. v8::Local<v8::Context> v8_context) const {
  136. return ExtensionInteractionProvider::HasActiveExtensionInteraction(
  137. v8_context);
  138. }
  139. } // namespace extensions