Import Cobalt 23.lts.1.309190
diff --git a/cobalt/account/user_authorizer.h b/cobalt/account/user_authorizer.h
index 6bd8ad5..784984a 100644
--- a/cobalt/account/user_authorizer.h
+++ b/cobalt/account/user_authorizer.h
@@ -77,7 +77,8 @@
// request. Calling other methods after |Shutdown| may have no effect.
virtual void Shutdown() {}
- // Instantiates an instance of the platform-specific implementation.
+ // Instantiates an instance of the platform-specific implementation. This may
+ // return nullptr if UserAuthorizer functions are not supported.
static UserAuthorizer* Create();
private:
diff --git a/cobalt/browser/idl_files.gni b/cobalt/browser/idl_files.gni
index 258a1ce..db2d7c5 100644
--- a/cobalt/browser/idl_files.gni
+++ b/cobalt/browser/idl_files.gni
@@ -157,7 +157,7 @@
"//cobalt/h5vcc/h5vcc.idl",
"//cobalt/h5vcc/h5vcc_accessibility.idl",
"//cobalt/h5vcc/h5vcc_account_info.idl",
- "//cobalt/h5vcc/h5vcc_account_manager.idl",
+ "//cobalt/h5vcc/h5vcc_account_manager_internal.idl",
"//cobalt/h5vcc/h5vcc_audio_config.idl",
"//cobalt/h5vcc/h5vcc_audio_config_array.idl",
"//cobalt/h5vcc/h5vcc_crash_log.idl",
diff --git a/cobalt/dom/BUILD.gn b/cobalt/dom/BUILD.gn
index e16397b..f014522 100644
--- a/cobalt/dom/BUILD.gn
+++ b/cobalt/dom/BUILD.gn
@@ -261,7 +261,6 @@
"screenshot.h",
"screenshot_manager.cc",
"screenshot_manager.h",
- "serialized_algorithm_runner.cc",
"serialized_algorithm_runner.h",
"serializer.cc",
"serializer.h",
diff --git a/cobalt/dom/document.cc b/cobalt/dom/document.cc
index 4e665a5..41bfa41a 100644
--- a/cobalt/dom/document.cc
+++ b/cobalt/dom/document.cc
@@ -448,7 +448,7 @@
return;
}
if (cookie_jar_) {
- cookie_jar_->SetCookie(url_as_gurl(), cookie);
+ cookie_jar_->SetCookie(location()->url(), cookie);
}
}
@@ -467,7 +467,7 @@
}
if (cookie_jar_) {
return net::CanonicalCookie::BuildCookieLine(
- cookie_jar_->GetCookies(url_as_gurl()));
+ cookie_jar_->GetCookies(location()->url()));
} else {
DLOG(WARNING) << "Document has no cookie jar";
return "";
@@ -485,7 +485,7 @@
return;
}
if (cookie_jar_) {
- cookie_jar_->SetCookie(url_as_gurl(), cookie);
+ cookie_jar_->SetCookie(location()->url(), cookie);
}
}
@@ -501,7 +501,7 @@
}
if (cookie_jar_) {
return net::CanonicalCookie::BuildCookieLine(
- cookie_jar_->GetCookies(url_as_gurl()));
+ cookie_jar_->GetCookies(location()->url()));
} else {
DLOG(WARNING) << "Document has no cookie jar";
return "";
@@ -517,7 +517,8 @@
// limited quirks mode, or no-quirks mode), and its type (XML document or HTML
// document).
// https://www.w3.org/TR/dom/#concept-node-clone
- return new Document(html_element_context_, Document::Options(url_as_gurl()));
+ return new Document(html_element_context_,
+ Document::Options(location()->url()));
}
scoped_refptr<HTMLHtmlElement> Document::html() const {
diff --git a/cobalt/dom/document.h b/cobalt/dom/document.h
index 2fc0246..89c65c0 100644
--- a/cobalt/dom/document.h
+++ b/cobalt/dom/document.h
@@ -247,8 +247,6 @@
FontCache* font_cache() const { return font_cache_.get(); }
- const GURL& url_as_gurl() const { return location_->url(); }
-
scoped_refptr<HTMLHtmlElement> html() const;
// List of scripts that will execute in order as soon as possible.
diff --git a/cobalt/dom/document_test.cc b/cobalt/dom/document_test.cc
index 8909802..b693173 100644
--- a/cobalt/dom/document_test.cc
+++ b/cobalt/dom/document_test.cc
@@ -103,7 +103,7 @@
new testing::FakeDocument(&html_element_context_, Document::Options(url));
EXPECT_EQ(url.spec(), document->url());
EXPECT_EQ(url.spec(), document->document_uri());
- EXPECT_EQ(url, document->url_as_gurl());
+ EXPECT_EQ(url, document->location()->url());
}
TEST_F(DocumentTest, IsNotXMLDocument) {
diff --git a/cobalt/dom/dom_settings.cc b/cobalt/dom/dom_settings.cc
index d07474b..8390913 100644
--- a/cobalt/dom/dom_settings.cc
+++ b/cobalt/dom/dom_settings.cc
@@ -44,6 +44,11 @@
DOMSettings::~DOMSettings() {}
+Window* DOMSettings::window() const {
+ DCHECK(context()->GetWindowOrWorkerGlobalScope()->IsWindow());
+ return context()->GetWindowOrWorkerGlobalScope()->AsWindow();
+}
+
const GURL& DOMSettings::base_url() const {
// From algorithm for to setup up a window environment settings object:
// https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#set-up-a-window-environment-settings-object
@@ -51,15 +56,10 @@
// algorithms are defined as follows:
// The API base URL
// Return the current base URL of window's associated Document.
- return window()->document()->url_as_gurl();
+ return window()->document()->location()->url();
}
-scoped_refptr<Window> DOMSettings::window() const {
- DCHECK(context()->GetWindowOrWorkerGlobalScope()->IsWindow());
- return context()->GetWindowOrWorkerGlobalScope()->AsWindow();
-}
-
-loader::Origin DOMSettings::document_origin() const {
+loader::Origin DOMSettings::GetOrigin() const {
return window()->document()->location()->GetOriginAsObject();
}
diff --git a/cobalt/dom/dom_settings.h b/cobalt/dom/dom_settings.h
index 33a5c0a..58e221f 100644
--- a/cobalt/dom/dom_settings.h
+++ b/cobalt/dom/dom_settings.h
@@ -69,7 +69,7 @@
return microphone_options_;
}
- scoped_refptr<Window> window() const;
+ Window* window() const;
MediaSourceRegistry* media_source_registry() const {
return media_source_registry_;
@@ -91,13 +91,14 @@
return mutation_observer_task_manager_;
}
- // Return's document's origin.
- loader::Origin document_origin() const;
-
// From: script::EnvironmentSettings
//
const GURL& base_url() const override;
+ // Return the origin of window's associated Document.
+ // https://html.spec.whatwg.org/#set-up-a-window-environment-settings-object
+ loader::Origin GetOrigin() const override;
+
private:
const int max_dom_element_depth_;
const speech::Microphone::Options microphone_options_;
diff --git a/cobalt/dom/html_anchor_element.cc b/cobalt/dom/html_anchor_element.cc
index c262595..0c15a83 100644
--- a/cobalt/dom/html_anchor_element.cc
+++ b/cobalt/dom/html_anchor_element.cc
@@ -54,7 +54,7 @@
}
// Resolve the URL given by the href attribute, relative to the element.
- const GURL& base_url = document->url_as_gurl();
+ const GURL& base_url = document->location()->url();
GURL absolute_url = base_url.Resolve(value);
// If the previous step fails, then abort these steps.
diff --git a/cobalt/dom/html_element.cc b/cobalt/dom/html_element.cc
index aa38f18..970c56e 100644
--- a/cobalt/dom/html_element.cc
+++ b/cobalt/dom/html_element.cc
@@ -2025,7 +2025,7 @@
// came from.
cssom::GURLMap property_key_to_base_url_map;
property_key_to_base_url_map[cssom::kBackgroundImageProperty] =
- document->url_as_gurl();
+ document->location()->url();
// Flags tracking which cached values must be invalidated.
UpdateComputedStyleInvalidationFlags invalidation_flags;
diff --git a/cobalt/dom/html_image_element.cc b/cobalt/dom/html_image_element.cc
index 2cbc162..02300ed 100644
--- a/cobalt/dom/html_image_element.cc
+++ b/cobalt/dom/html_image_element.cc
@@ -119,7 +119,7 @@
if (!src.empty()) {
// 7.1. Resolve selected source, relative to the element. If that is not
// successful, abort these steps.
- const GURL& base_url = node_document()->url_as_gurl();
+ const GURL& base_url = node_document()->location()->url();
const GURL selected_source = base_url.Resolve(src);
if (!selected_source.is_valid()) {
LOG(WARNING) << src << " cannot be resolved based on " << base_url << ".";
@@ -235,7 +235,7 @@
// Resolve selected source, relative to the element.
const auto src_attr = GetAttribute("src");
const std::string src = src_attr.value_or("");
- const GURL& base_url = node_document()->url_as_gurl();
+ const GURL& base_url = node_document()->location()->url();
const GURL selected_source = base_url.Resolve(src);
html_element_context()->performance()->CreatePerformanceResourceTiming(
diff --git a/cobalt/dom/html_link_element.cc b/cobalt/dom/html_link_element.cc
index b51d697..17a6de1 100644
--- a/cobalt/dom/html_link_element.cc
+++ b/cobalt/dom/html_link_element.cc
@@ -147,7 +147,7 @@
void HTMLLinkElement::ResolveAndSetAbsoluteURL() {
// Resolve the URL given by the href attribute, relative to the element.
- const GURL& base_url = node_document()->url_as_gurl();
+ const GURL& base_url = node_document()->location()->url();
absolute_url_ = base_url.Resolve(href());
LOG_IF(WARNING, !absolute_url_.is_valid())
@@ -316,7 +316,7 @@
// If not loading from network-fetched resources or fetched resource is same
// origin as the document, set origin-clean flag to true.
if (request_mode_ != loader::kNoCORSMode || !loader_ ||
- document->url_as_gurl().SchemeIsFile() ||
+ document->location()->url().SchemeIsFile() ||
(fetched_last_url_origin_ == document->location()->GetOriginAsObject())) {
css_style_sheet->SetOriginClean(true);
}
diff --git a/cobalt/dom/html_media_element.cc b/cobalt/dom/html_media_element.cc
index 099559b..d496b01 100644
--- a/cobalt/dom/html_media_element.cc
+++ b/cobalt/dom/html_media_element.cc
@@ -795,7 +795,7 @@
GURL media_url(src);
if (media_url.is_empty()) {
// Try to resolve it as a relative url.
- media_url = node_document()->url_as_gurl().Resolve(src);
+ media_url = node_document()->location()->url().Resolve(src);
}
if (media_url.is_empty()) {
MediaLoadingFailed(WebMediaPlayer::kNetworkStateFormatError,
@@ -1690,7 +1690,7 @@
std::string src = this->src();
GURL current_url = GURL(src);
if (current_url.is_empty()) {
- current_url = node_document()->url_as_gurl().Resolve(src);
+ current_url = node_document()->location()->url().Resolve(src);
}
if (!current_url.SchemeIs("http") &&
OriginIsSafe(request_mode_, current_url,
diff --git a/cobalt/dom/html_script_element.cc b/cobalt/dom/html_script_element.cc
index a036d7c..42f7997 100644
--- a/cobalt/dom/html_script_element.cc
+++ b/cobalt/dom/html_script_element.cc
@@ -78,6 +78,18 @@
DCHECK(document->html_element_context()->script_runner());
}
+std::string HTMLScriptElement::src() const {
+ auto src = GetAttribute("src");
+ if (!src.has_value()) {
+ return "";
+ }
+ if (!node_document()) {
+ return src.value();
+ }
+ const GURL& base_url = node_document()->location()->url();
+ return base_url.Resolve(src.value()).spec();
+}
+
base::Optional<std::string> HTMLScriptElement::cross_origin() const {
base::Optional<std::string> cross_origin_attribute =
GetAttribute("crossOrigin");
@@ -217,7 +229,11 @@
// 1. Let src be the value of the element's src attribute.
// 2. If src is the empty string, queue a task to fire a simple event
// named error at the element, and abort these steps.
- if (HasAttribute("src") && src() == "") {
+ //
+ // Need to use the "src" attribute. The |src| property is fully resolved. See
+ // header file for details.
+ auto src = GetAttribute("src").value_or("");
+ if (HasAttribute("src") && src == "") {
LOG(ERROR) << "src attribute of script element is empty.";
PreventGarbageCollectionAndPostToDispatchEvent(
@@ -229,10 +245,10 @@
// 3. Resolve src relative to the element.
// 4. If the previous step failed, queue a task to fire a simple event named
// error at the element, and abort these steps.
- const GURL& base_url = document_->url_as_gurl();
- url_ = base_url.Resolve(src());
+ const GURL& base_url = document_->location()->url();
+ url_ = base_url.Resolve(src);
if (!url_.is_valid()) {
- LOG(ERROR) << src() << " cannot be resolved based on " << base_url << ".";
+ LOG(ERROR) << src << " cannot be resolved based on " << base_url << ".";
PreventGarbageCollectionAndPostToDispatchEvent(
FROM_HERE, base::Tokens::error(),
@@ -267,7 +283,7 @@
"bugs, it is recommended to use JavaScript to create a "
"script element and load it async. The <script> reference "
"appears at: \""
- << inline_script_location_ << "\" and its src is \"" << src() << "\"";
+ << inline_script_location_ << "\" and its src is \"" << src << "\"";
}
load_option_ = 2;
diff --git a/cobalt/dom/html_script_element.h b/cobalt/dom/html_script_element.h
index 3c9740e..f5537fd 100644
--- a/cobalt/dom/html_script_element.h
+++ b/cobalt/dom/html_script_element.h
@@ -42,7 +42,13 @@
// Web API: HTMLScriptElement
//
- std::string src() const { return GetAttribute("src").value_or(""); }
+ // If the "src" attribute is a relative URL, the |src| property returns a
+ // fully resolved URL used the |document.location.href| as the base URL. This
+ // matches the Chrome implementation of the |src| property.
+ // See:
+ // https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/blink/renderer/bindings/core/v8/v8_html_script_element.cc;l=93;drc=4f7206c7352efba617f4561cd8c95844d9e9814f
+ // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/element.cc;l=7360;drc=5f6702f8b8f9da8510d2b3ec809e177e6db09e53
+ std::string src() const;
void set_src(const std::string& value) { SetAttribute("src", value); }
std::string type() const { return GetAttribute("type").value_or(""); }
diff --git a/cobalt/dom/lottie_player.cc b/cobalt/dom/lottie_player.cc
index 93baab8..4adb4a8 100644
--- a/cobalt/dom/lottie_player.cc
+++ b/cobalt/dom/lottie_player.cc
@@ -298,7 +298,7 @@
const std::string src = GetAttribute("src").value_or("");
if (!src.empty()) {
- const GURL& base_url = node_document()->url_as_gurl();
+ const GURL& base_url = node_document()->location()->url();
const GURL selected_source = base_url.Resolve(src);
if (!selected_source.is_valid()) {
LOG(WARNING) << src << " cannot be resolved based on " << base_url << ".";
diff --git a/cobalt/dom/media_source.cc b/cobalt/dom/media_source.cc
index f9f2c05..1dcc7d3 100644
--- a/cobalt/dom/media_source.cc
+++ b/cobalt/dom/media_source.cc
@@ -83,13 +83,14 @@
// If the system has more processors than the specified value, SourceBuffer
// append and remove algorithm will be offloaded to a non-web thread to reduce
// the load on the web thread.
-// The default value is 2. Set to a reasonably high value (say 1024) will
-// disable algorithm offloading completely.
+// The default value is 1024, which effectively disable offloading by default.
+// Setting to a reasonably low value (say 0 or 2) will enable algorithm
+// offloading.
bool IsAlgorithmOffloadEnabled(script::EnvironmentSettings* settings) {
int min_process_count_to_offload =
GetMediaSettings(settings)
->GetMinimumProcessorCountToOffloadAlgorithm()
- .value_or(2);
+ .value_or(1024);
DCHECK_GE(min_process_count_to_offload, 0);
return SbSystemGetNumberOfProcessors() >= min_process_count_to_offload;
}
@@ -97,10 +98,10 @@
// If this function returns true, SourceBuffer will reduce asynchronous
// behaviors. For example, queued events will be dispatached immediately when
// possible.
-// The default value is true.
+// The default value is false.
bool IsAsynchronousReductionEnabled(script::EnvironmentSettings* settings) {
return GetMediaSettings(settings)->IsAsynchronousReductionEnabled().value_or(
- true);
+ false);
}
// If the size of a job that is part of an algorithm is less than or equal to
@@ -390,9 +391,10 @@
if (algorithm_process_thread_) {
LOG(INFO) << "Algorithm offloading enabled.";
- offload_algorithm_runner_.reset(new OffloadAlgorithmRunner(
- algorithm_process_thread_->message_loop()->task_runner(),
- base::MessageLoop::current()->task_runner()));
+ offload_algorithm_runner_.reset(
+ new OffloadAlgorithmRunner<SourceBufferAlgorithm>(
+ algorithm_process_thread_->message_loop()->task_runner(),
+ base::MessageLoop::current()->task_runner()));
} else {
LOG(INFO) << "Algorithm offloading disabled.";
}
@@ -574,7 +576,8 @@
return has_max_video_capabilities_;
}
-SerializedAlgorithmRunner* MediaSource::GetAlgorithmRunner(int job_size) {
+SerializedAlgorithmRunner<SourceBufferAlgorithm>*
+MediaSource::GetAlgorithmRunner(int job_size) {
if (!offload_algorithm_runner_) {
return &default_algorithm_runner_;
}
diff --git a/cobalt/dom/media_source.h b/cobalt/dom/media_source.h
index bfe0774..65ab2a8 100644
--- a/cobalt/dom/media_source.h
+++ b/cobalt/dom/media_source.h
@@ -59,6 +59,7 @@
#include "cobalt/dom/media_source_ready_state.h"
#include "cobalt/dom/serialized_algorithm_runner.h"
#include "cobalt/dom/source_buffer.h"
+#include "cobalt/dom/source_buffer_algorithm.h"
#include "cobalt/dom/source_buffer_list.h"
#include "cobalt/dom/time_ranges.h"
#include "cobalt/dom/video_track.h"
@@ -126,7 +127,8 @@
void SetSourceBufferActive(SourceBuffer* source_buffer, bool is_active);
HTMLMediaElement* GetMediaElement() const;
bool MediaElementHasMaxVideoCapabilities() const;
- SerializedAlgorithmRunner* GetAlgorithmRunner(int job_size);
+ SerializedAlgorithmRunner<SourceBufferAlgorithm>* GetAlgorithmRunner(
+ int job_size);
DEFINE_WRAPPABLE_TYPE(MediaSource);
void TraceMembers(script::Tracer* tracer) override;
@@ -148,9 +150,10 @@
const int min_size_for_immediate_job_;
// The default algorithm runner runs all steps on the web thread.
- DefaultAlgorithmRunner default_algorithm_runner_;
+ DefaultAlgorithmRunner<SourceBufferAlgorithm> default_algorithm_runner_;
// The offload algorithm runner offloads some steps to a non-web thread.
- std::unique_ptr<OffloadAlgorithmRunner> offload_algorithm_runner_;
+ std::unique_ptr<OffloadAlgorithmRunner<SourceBufferAlgorithm>>
+ offload_algorithm_runner_;
std::unique_ptr<base::Thread> algorithm_process_thread_;
ChunkDemuxer* chunk_demuxer_;
diff --git a/cobalt/dom/serialized_algorithm_runner.cc b/cobalt/dom/serialized_algorithm_runner.cc
deleted file mode 100644
index 07dece0..0000000
--- a/cobalt/dom/serialized_algorithm_runner.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2022 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cobalt/dom/serialized_algorithm_runner.h"
-
-#include "base/message_loop/message_loop.h"
-
-namespace cobalt {
-namespace dom {
-
-void DefaultAlgorithmRunner::Start(const scoped_refptr<HandleBase>& handle) {
- DCHECK(handle);
- TRACE_EVENT0("cobalt::dom", "DefaultAlgorithmRunner::Start()");
-
- if (asynchronous_reduction_enabled_) {
- Process(handle);
- return;
- }
-
- auto task_runner = base::MessageLoop::current()->task_runner();
- task_runner->PostTask(FROM_HERE,
- base::BindOnce(&DefaultAlgorithmRunner::Process,
- base::Unretained(this), handle));
-}
-
-void DefaultAlgorithmRunner::Process(const scoped_refptr<HandleBase>& handle) {
- DCHECK(handle);
- TRACE_EVENT0("cobalt::dom", "DefaultAlgorithmRunner::Process()");
-
- auto task_runner = base::MessageLoop::current()->task_runner();
-
- bool finished = false;
- handle->Process(&finished);
-
- if (finished) {
- handle->Finalize();
- return;
- }
- task_runner->PostTask(FROM_HERE,
- base::BindOnce(&DefaultAlgorithmRunner::Process,
- base::Unretained(this), handle));
-}
-
-OffloadAlgorithmRunner::OffloadAlgorithmRunner(
- const scoped_refptr<TaskRunner>& process_task_runner,
- const scoped_refptr<TaskRunner>& finalize_task_runner)
- : process_task_runner_(process_task_runner),
- finalize_task_runner_(finalize_task_runner) {
- DCHECK(process_task_runner_);
- DCHECK(finalize_task_runner_);
- DCHECK_NE(process_task_runner_, finalize_task_runner_);
-}
-
-void OffloadAlgorithmRunner::Start(const scoped_refptr<HandleBase>& handle) {
- DCHECK(handle);
-
- TRACE_EVENT0("cobalt::dom", "OffloadAlgorithmRunner::Start()");
-
- process_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&OffloadAlgorithmRunner::Process,
- base::Unretained(this), handle));
-}
-
-void OffloadAlgorithmRunner::Process(const scoped_refptr<HandleBase>& handle) {
- DCHECK(handle);
- DCHECK(process_task_runner_->BelongsToCurrentThread());
-
- TRACE_EVENT0("cobalt::dom", "OffloadAlgorithmRunner::Process()");
-
- bool finished = false;
- handle->Process(&finished);
-
- if (finished) {
- finalize_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&HandleBase::Finalize, handle));
- return;
- }
- process_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&OffloadAlgorithmRunner::Process,
- base::Unretained(this), handle));
-}
-
-} // namespace dom
-} // namespace cobalt
diff --git a/cobalt/dom/serialized_algorithm_runner.h b/cobalt/dom/serialized_algorithm_runner.h
index d4c2b39..db625ad 100644
--- a/cobalt/dom/serialized_algorithm_runner.h
+++ b/cobalt/dom/serialized_algorithm_runner.h
@@ -22,6 +22,7 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "starboard/common/mutex.h"
@@ -53,37 +54,56 @@
// This class will keep calling Process() until |finished| becomes false, and
// then call Finalize(). It guarantees that all calls won't be overlapped and
// the member functions of the algorithm don't have to synchronize between them.
+template <typename SerializedAlgorithm>
class SerializedAlgorithmRunner {
public:
- // Abstract the non-template part of the Handle class, and shouldn't be used
- // directly.
- class HandleBase : public base::RefCountedThreadSafe<HandleBase> {
- public:
- virtual ~HandleBase() {}
-
- virtual void Process(bool* finished) = 0;
- virtual void Finalize() = 0;
- };
-
// A handle object for a running algorithm instance, to allow for aborting and
// access the algorithm.
- template <typename SerializedAlgorithm>
- class Handle : public HandleBase {
+ class Handle : public base::RefCountedThreadSafe<Handle> {
public:
- explicit Handle(std::unique_ptr<SerializedAlgorithm> algorithm);
-
// Abort the algorithm and no more processing will happen on return. It is
// possible that Process() has already finished asynchronously, in which
// case this function will call Finalize() instead (if it hasn't been called
// yet).
void Abort();
+ void Process(bool* finished);
+ void FinalizeIfNotAborted();
+
SerializedAlgorithm* algorithm() const { return algorithm_.get(); }
private:
- void Process(bool* finished) override;
- void Finalize() override;
+ friend class SerializedAlgorithmRunner;
- // The |mutex_| is necessary as `Abort()` can be called from any thread.
+ // Provide synchronization only when |synchronization_required| is true.
+ // This allows bypassing of synchronization for algorithm runners that
+ // operate on a single thread, where a mutex could be reentrant if acquired
+ // due to nested calls.
+ class ScopedLockWhenRequired {
+ public:
+ ScopedLockWhenRequired(bool synchronization_required,
+ const starboard::Mutex& mutex)
+ : synchronization_required_(synchronization_required), mutex_(mutex) {
+ if (synchronization_required_) {
+ mutex_.Acquire();
+ }
+ }
+ ~ScopedLockWhenRequired() {
+ if (synchronization_required_) {
+ mutex_.Release();
+ }
+ }
+
+ private:
+ const bool synchronization_required_;
+ const starboard::Mutex& mutex_;
+ };
+
+ Handle(bool synchronization_required,
+ std::unique_ptr<SerializedAlgorithm> algorithm);
+
+ // The |mutex_| is necessary for algorithm runners operate on multiple
+ // threads as `Abort()` can be called from any thread.
+ const bool synchronization_required_;
starboard::Mutex mutex_;
std::unique_ptr<SerializedAlgorithm> algorithm_;
bool aborted_ = false;
@@ -93,21 +113,32 @@
virtual ~SerializedAlgorithmRunner() {}
- virtual void Start(const scoped_refptr<HandleBase>& handle) = 0;
+ virtual scoped_refptr<Handle> CreateHandle(
+ std::unique_ptr<SerializedAlgorithm> algorithm) = 0;
+ virtual void Start(scoped_refptr<Handle> handle) = 0;
+
+ protected:
+ scoped_refptr<Handle> CreateHandle(
+ bool synchronization_required,
+ std::unique_ptr<SerializedAlgorithm> algorithm) {
+ return new Handle(synchronization_required, std::move(algorithm));
+ }
};
template <typename SerializedAlgorithm>
-SerializedAlgorithmRunner::Handle<SerializedAlgorithm>::Handle(
+SerializedAlgorithmRunner<SerializedAlgorithm>::Handle::Handle(
+ bool synchronization_required,
std::unique_ptr<SerializedAlgorithm> algorithm)
- : algorithm_(std::move(algorithm)) {
+ : synchronization_required_(synchronization_required),
+ algorithm_(std::move(algorithm)) {
DCHECK(algorithm_);
}
template <typename SerializedAlgorithm>
-void SerializedAlgorithmRunner::Handle<SerializedAlgorithm>::Abort() {
+void SerializedAlgorithmRunner<SerializedAlgorithm>::Handle::Abort() {
TRACE_EVENT0("cobalt::dom", "SerializedAlgorithmRunner::Handle::Abort()");
- starboard::ScopedLock scoped_lock(mutex_);
+ ScopedLockWhenRequired scoped_lock(synchronization_required_, mutex_);
DCHECK(!aborted_); // Abort() cannot be called twice.
@@ -126,18 +157,19 @@
}
template <typename SerializedAlgorithm>
-void SerializedAlgorithmRunner::Handle<SerializedAlgorithm>::Process(
+void SerializedAlgorithmRunner<SerializedAlgorithm>::Handle::Process(
bool* finished) {
TRACE_EVENT0("cobalt::dom", "SerializedAlgorithmRunner::Handle::Process()");
DCHECK(finished);
- starboard::ScopedLock scoped_lock(mutex_);
+ ScopedLockWhenRequired scoped_lock(synchronization_required_, mutex_);
DCHECK(!finished_);
DCHECK(!finalized_);
if (aborted_) {
+ *finished = true;
return;
}
@@ -147,17 +179,19 @@
}
template <typename SerializedAlgorithm>
-void SerializedAlgorithmRunner::Handle<SerializedAlgorithm>::Finalize() {
+void SerializedAlgorithmRunner<
+ SerializedAlgorithm>::Handle::FinalizeIfNotAborted() {
TRACE_EVENT0("cobalt::dom", "SerializedAlgorithmRunner::Handle::Finalize()");
- starboard::ScopedLock scoped_lock(mutex_);
- DCHECK(finished_);
+ ScopedLockWhenRequired scoped_lock(synchronization_required_, mutex_);
+
DCHECK(!finalized_);
if (aborted_) {
return;
}
+ DCHECK(finished_);
DCHECK(algorithm_);
algorithm_->Finalize();
@@ -167,14 +201,21 @@
// This class runs algorithm on the task runner associated with the thread where
// Start() is called.
-class DefaultAlgorithmRunner : public SerializedAlgorithmRunner {
+template <typename SerializedAlgorithm>
+class DefaultAlgorithmRunner
+ : public SerializedAlgorithmRunner<SerializedAlgorithm> {
public:
explicit DefaultAlgorithmRunner(bool asynchronous_reduction_enabled)
: asynchronous_reduction_enabled_(asynchronous_reduction_enabled) {}
private:
- void Start(const scoped_refptr<HandleBase>& handle) override;
- void Process(const scoped_refptr<HandleBase>& handle);
+ typedef
+ typename SerializedAlgorithmRunner<SerializedAlgorithm>::Handle Handle;
+
+ scoped_refptr<Handle> CreateHandle(
+ std::unique_ptr<SerializedAlgorithm> algorithm) override;
+ void Start(scoped_refptr<Handle> handle) override;
+ void Process(scoped_refptr<Handle> handle);
const bool asynchronous_reduction_enabled_;
};
@@ -185,7 +226,9 @@
// This class will keep calling the Process() member function of the algorithm
// on the process task runner, and then call Finalize() on the finalize task
// runner when |finished| becomes true.
-class OffloadAlgorithmRunner : public SerializedAlgorithmRunner {
+template <typename SerializedAlgorithm>
+class OffloadAlgorithmRunner
+ : public SerializedAlgorithmRunner<SerializedAlgorithm> {
public:
typedef base::SingleThreadTaskRunner TaskRunner;
@@ -193,13 +236,121 @@
const scoped_refptr<TaskRunner>& finalize_task_runner);
private:
- void Start(const scoped_refptr<HandleBase>& handle) override;
- void Process(const scoped_refptr<HandleBase>& handle);
+ typedef
+ typename SerializedAlgorithmRunner<SerializedAlgorithm>::Handle Handle;
+
+ scoped_refptr<Handle> CreateHandle(
+ std::unique_ptr<SerializedAlgorithm> algorithm) override;
+ void Start(scoped_refptr<Handle> handle) override;
+ void Process(scoped_refptr<Handle> handle);
scoped_refptr<TaskRunner> process_task_runner_;
scoped_refptr<TaskRunner> finalize_task_runner_;
};
+template <typename SerializedAlgorithm>
+scoped_refptr<typename SerializedAlgorithmRunner<SerializedAlgorithm>::Handle>
+DefaultAlgorithmRunner<SerializedAlgorithm>::CreateHandle(
+ std::unique_ptr<SerializedAlgorithm> algorithm) {
+ TRACE_EVENT0("cobalt::dom", "DefaultAlgorithmRunner::CreateHandle()");
+
+ const bool kSynchronizationRequired = false;
+ return SerializedAlgorithmRunner<SerializedAlgorithm>::CreateHandle(
+ kSynchronizationRequired, std::move(algorithm));
+}
+
+template <typename SerializedAlgorithm>
+void DefaultAlgorithmRunner<SerializedAlgorithm>::Start(
+ scoped_refptr<Handle> handle) {
+ DCHECK(handle);
+ TRACE_EVENT0("cobalt::dom", "DefaultAlgorithmRunner::Start()");
+
+ if (asynchronous_reduction_enabled_) {
+ Process(handle);
+ return;
+ }
+
+ auto task_runner = base::MessageLoop::current()->task_runner();
+ task_runner->PostTask(FROM_HERE,
+ base::BindOnce(&DefaultAlgorithmRunner::Process,
+ base::Unretained(this), handle));
+}
+
+template <typename SerializedAlgorithm>
+void DefaultAlgorithmRunner<SerializedAlgorithm>::Process(
+ scoped_refptr<Handle> handle) {
+ DCHECK(handle);
+ TRACE_EVENT0("cobalt::dom", "DefaultAlgorithmRunner::Process()");
+
+ auto task_runner = base::MessageLoop::current()->task_runner();
+
+ bool finished = false;
+ handle->Process(&finished);
+
+ if (finished) {
+ handle->FinalizeIfNotAborted();
+ return;
+ }
+ task_runner->PostTask(FROM_HERE,
+ base::BindOnce(&DefaultAlgorithmRunner::Process,
+ base::Unretained(this), handle));
+}
+
+template <typename SerializedAlgorithm>
+OffloadAlgorithmRunner<SerializedAlgorithm>::OffloadAlgorithmRunner(
+ const scoped_refptr<TaskRunner>& process_task_runner,
+ const scoped_refptr<TaskRunner>& finalize_task_runner)
+ : process_task_runner_(process_task_runner),
+ finalize_task_runner_(finalize_task_runner) {
+ DCHECK(process_task_runner_);
+ DCHECK(finalize_task_runner_);
+ DCHECK_NE(process_task_runner_, finalize_task_runner_);
+}
+
+template <typename SerializedAlgorithm>
+scoped_refptr<typename SerializedAlgorithmRunner<SerializedAlgorithm>::Handle>
+OffloadAlgorithmRunner<SerializedAlgorithm>::CreateHandle(
+ std::unique_ptr<SerializedAlgorithm> algorithm) {
+ TRACE_EVENT0("cobalt::dom", "OffloadAlgorithmRunner::CreateHandle()");
+
+ const bool kSynchronizationRequired = true;
+ return SerializedAlgorithmRunner<SerializedAlgorithm>::CreateHandle(
+ kSynchronizationRequired, std::move(algorithm));
+}
+
+template <typename SerializedAlgorithm>
+void OffloadAlgorithmRunner<SerializedAlgorithm>::Start(
+ scoped_refptr<Handle> handle) {
+ DCHECK(handle);
+
+ TRACE_EVENT0("cobalt::dom", "OffloadAlgorithmRunner::Start()");
+
+ process_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&OffloadAlgorithmRunner::Process,
+ base::Unretained(this), handle));
+}
+
+template <typename SerializedAlgorithm>
+void OffloadAlgorithmRunner<SerializedAlgorithm>::Process(
+ scoped_refptr<Handle> handle) {
+ DCHECK(handle);
+ DCHECK(process_task_runner_->BelongsToCurrentThread());
+
+ TRACE_EVENT0("cobalt::dom", "OffloadAlgorithmRunner::Process()");
+
+ bool finished = false;
+ handle->Process(&finished);
+
+ if (finished) {
+ finalize_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&Handle::FinalizeIfNotAborted, handle));
+ return;
+ }
+ process_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&OffloadAlgorithmRunner::Process,
+ base::Unretained(this), handle));
+}
+
} // namespace dom
} // namespace cobalt
diff --git a/cobalt/dom/source_buffer.cc b/cobalt/dom/source_buffer.cc
index ffaee80..1f6278b 100644
--- a/cobalt/dom/source_buffer.cc
+++ b/cobalt/dom/source_buffer.cc
@@ -387,11 +387,11 @@
base::Unretained(this)),
base::Bind(&SourceBuffer::OnAlgorithmFinalized,
base::Unretained(this))));
+ auto algorithm_runner =
+ media_source_->GetAlgorithmRunner(std::numeric_limits<int>::max());
active_algorithm_handle_ =
- new SerializedAlgorithmRunner::Handle<SourceBufferAlgorithm>(
- std::move(algorithm));
- media_source_->GetAlgorithmRunner(std::numeric_limits<int>::max())
- ->Start(active_algorithm_handle_);
+ algorithm_runner->CreateHandle(std::move(algorithm));
+ algorithm_runner->Start(active_algorithm_handle_);
}
void SourceBuffer::set_track_defaults(
@@ -482,9 +482,13 @@
}
void SourceBuffer::ScheduleAndMaybeDispatchImmediately(base::Token event_name) {
+ ScheduleEvent(event_name);
+ // TODO(b/244773734): Re-enable direct event dispatching
+ /*
scoped_refptr<web::Event> event = new web::Event(event_name);
event->set_target(this);
event_queue_->EnqueueAndMaybeDispatchImmediately(event);
+ */
}
bool SourceBuffer::PrepareAppend(size_t new_data_size,
@@ -509,6 +513,7 @@
return false;
}
+ metrics_.StartTracking();
media_source_->OpenIfInEndedState();
double current_time = media_source_->GetMediaElement()->current_time(NULL);
@@ -517,9 +522,11 @@
new_data_size + evict_extra_in_bytes_)) {
web::DOMException::Raise(web::DOMException::kQuotaExceededErr,
exception_state);
+ metrics_.EndTracking(0);
return false;
}
+ metrics_.EndTracking(0);
return true;
}
@@ -528,11 +535,9 @@
script::ExceptionState* exception_state) {
TRACE_EVENT1("cobalt::dom", "SourceBuffer::AppendBufferInternal()", "size",
size);
- metrics_.StartTracking();
if (!PrepareAppend(size, exception_state)) {
return;
}
- metrics_.EndTracking(0);
DCHECK(data || size == 0);
@@ -562,10 +567,10 @@
base::Bind(&SourceBuffer::OnAlgorithmFinalized,
base::Unretained(this)),
&metrics_));
+ auto algorithm_runner = media_source_->GetAlgorithmRunner(size);
active_algorithm_handle_ =
- new SerializedAlgorithmRunner::Handle<SourceBufferAlgorithm>(
- std::move(algorithm));
- media_source_->GetAlgorithmRunner(size)->Start(active_algorithm_handle_);
+ algorithm_runner->CreateHandle(std::move(algorithm));
+ algorithm_runner->Start(active_algorithm_handle_);
}
void SourceBuffer::OnAlgorithmFinalized() {
diff --git a/cobalt/dom/source_buffer.h b/cobalt/dom/source_buffer.h
index 0cf7f28..c7336e6 100644
--- a/cobalt/dom/source_buffer.h
+++ b/cobalt/dom/source_buffer.h
@@ -204,7 +204,7 @@
starboard::Mutex timestamp_offset_mutex_;
double timestamp_offset_ = 0;
- scoped_refptr<SerializedAlgorithmRunner::Handle<SourceBufferAlgorithm>>
+ scoped_refptr<SerializedAlgorithmRunner<SourceBufferAlgorithm>::Handle>
active_algorithm_handle_;
double append_window_start_ = 0;
double append_window_end_ = std::numeric_limits<double>::infinity();
diff --git a/cobalt/dom/storage.cc b/cobalt/dom/storage.cc
index 010890f..5706528 100644
--- a/cobalt/dom/storage.cc
+++ b/cobalt/dom/storage.cc
@@ -57,7 +57,7 @@
key, old_value, new_value, window_->document()->url(), this));
}
-GURL Storage::origin() const { return window_->document()->url_as_gurl(); }
+GURL Storage::origin() const { return window_->document()->location()->url(); }
} // namespace dom
} // namespace cobalt
diff --git a/cobalt/dom/xml_document.h b/cobalt/dom/xml_document.h
index 422b6e4..8e3f684 100644
--- a/cobalt/dom/xml_document.h
+++ b/cobalt/dom/xml_document.h
@@ -29,7 +29,7 @@
// Custom, not in any spec: Node.
scoped_refptr<Node> Duplicate() const override {
return new XMLDocument(html_element_context(),
- Document::Options(url_as_gurl()));
+ Document::Options(location()->url()));
}
// Custom, not in any spec: Document.
diff --git a/cobalt/h5vcc/BUILD.gn b/cobalt/h5vcc/BUILD.gn
index fd7216f..188c6ed 100644
--- a/cobalt/h5vcc/BUILD.gn
+++ b/cobalt/h5vcc/BUILD.gn
@@ -96,8 +96,8 @@
if (enable_account_manager) {
sources += [
- "h5vcc_account_manager.cc",
- "h5vcc_account_manager.h",
+ "h5vcc_account_manager_internal.cc",
+ "h5vcc_account_manager_internal.h",
]
}
diff --git a/cobalt/h5vcc/h5vcc.cc b/cobalt/h5vcc/h5vcc.cc
index 806f7a1..e88b901 100644
--- a/cobalt/h5vcc/h5vcc.cc
+++ b/cobalt/h5vcc/h5vcc.cc
@@ -14,6 +14,11 @@
#include "cobalt/h5vcc/h5vcc.h"
+#if defined(COBALT_ENABLE_ACCOUNT_MANAGER)
+#include "cobalt/h5vcc/h5vcc_account_manager_internal.h"
+#include "cobalt/script/source_code.h"
+#endif
+
#include "cobalt/persistent_storage/persistent_settings.h"
#include "cobalt/sso/sso_interface.h"
@@ -45,6 +50,23 @@
#else
system_ = new H5vccSystem();
#endif
+
+#if defined(COBALT_ENABLE_ACCOUNT_MANAGER)
+ // Bind "H5vccAccountManager" if it is supported. (This is not to be confused
+ // with settings.account_manager.)
+ if (H5vccAccountManagerInternal::IsSupported()) {
+ // Since we don't want to bind an instance of a wrappable, we cannot use
+ // Bind() nor BindTo(). Instead, just evaluate a script to alias the type.
+ scoped_refptr<script::SourceCode> source =
+ script::SourceCode::CreateSourceCode(
+ "H5vccAccountManager = H5vccAccountManagerInternal;"
+ "window.H5vccAccountManager = window.H5vccAccountManagerInternal;",
+ base::SourceLocation("h5vcc.cc", __LINE__, 1));
+ std::string result;
+ bool success = settings.global_environment->EvaluateScript(source, &result);
+ CHECK(success);
+ }
+#endif
}
void H5vcc::TraceMembers(script::Tracer* tracer) {
diff --git a/cobalt/h5vcc/h5vcc_account_manager.cc b/cobalt/h5vcc/h5vcc_account_manager_internal.cc
similarity index 77%
rename from cobalt/h5vcc/h5vcc_account_manager.cc
rename to cobalt/h5vcc/h5vcc_account_manager_internal.cc
index 8705df7..1c0a3c2 100644
--- a/cobalt/h5vcc/h5vcc_account_manager.cc
+++ b/cobalt/h5vcc/h5vcc_account_manager_internal.cc
@@ -14,7 +14,7 @@
#include <memory>
-#include "cobalt/h5vcc/h5vcc_account_manager.h"
+#include "cobalt/h5vcc/h5vcc_account_manager_internal.h"
#include "base/command_line.h"
#include "base/memory/weak_ptr.h"
@@ -24,32 +24,42 @@
namespace cobalt {
namespace h5vcc {
-H5vccAccountManager::H5vccAccountManager()
+H5vccAccountManagerInternal::H5vccAccountManagerInternal()
: user_authorizer_(account::UserAuthorizer::Create()),
owning_message_loop_(base::MessageLoop::current()),
thread_("AccountManager") {
thread_.Start();
}
-void H5vccAccountManager::GetAuthToken(
+// static
+bool H5vccAccountManagerInternal::IsSupported() {
+ auto account_manager = account::UserAuthorizer::Create();
+ if (account_manager) {
+ delete account_manager;
+ return true;
+ }
+ return false;
+}
+
+void H5vccAccountManagerInternal::GetAuthToken(
const AccessTokenCallbackHolder& callback) {
DLOG(INFO) << "Get authorization token.";
PostOperation(kGetToken, callback);
}
-void H5vccAccountManager::RequestPairing(
+void H5vccAccountManagerInternal::RequestPairing(
const AccessTokenCallbackHolder& callback) {
DLOG(INFO) << "Request application linking.";
PostOperation(kPairing, callback);
}
-void H5vccAccountManager::RequestUnpairing(
+void H5vccAccountManagerInternal::RequestUnpairing(
const AccessTokenCallbackHolder& callback) {
DLOG(INFO) << "Request application unlinking.";
PostOperation(kUnpairing, callback);
}
-void H5vccAccountManager::PostOperation(
+void H5vccAccountManagerInternal::PostOperation(
OperationType operation_type, const AccessTokenCallbackHolder& callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
AccessTokenCallbackReference* token_callback =
@@ -57,31 +67,38 @@
pending_callbacks_.push_back(
std::unique_ptr<AccessTokenCallbackReference>(token_callback));
thread_.message_loop()->task_runner()->PostTask(
- FROM_HERE, base::Bind(&H5vccAccountManager::RequestOperationInternal,
- user_authorizer_.get(), operation_type,
- base::Bind(&H5vccAccountManager::PostResult,
- owning_message_loop_,
- base::AsWeakPtr(this), token_callback)));
+ FROM_HERE,
+ base::Bind(&H5vccAccountManagerInternal::RequestOperationInternal,
+ user_authorizer_.get(), operation_type,
+ base::Bind(&H5vccAccountManagerInternal::PostResult,
+ owning_message_loop_, base::AsWeakPtr(this),
+ token_callback)));
}
-H5vccAccountManager::~H5vccAccountManager() {
+H5vccAccountManagerInternal::~H5vccAccountManagerInternal() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Give the UserAuthorizer a chance to abort any long running pending requests
// before the message loop gets shut down.
- user_authorizer_->Shutdown();
+ if (user_authorizer_) {
+ user_authorizer_->Shutdown();
+ }
}
// static
-void H5vccAccountManager::RequestOperationInternal(
+void H5vccAccountManagerInternal::RequestOperationInternal(
account::UserAuthorizer* user_authorizer, OperationType operation,
const base::Callback<void(const std::string&, uint64_t)>& post_result) {
+ bool enabled = user_authorizer != nullptr;
#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(browser::switches::kDisableSignIn)) {
+ enabled = false;
+ }
+#endif // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+ if (!enabled) {
post_result.Run(std::string(), 0);
return;
}
-#endif // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
SbUser current_user = SbUserGetCurrent();
DCHECK(SbUserIsValid(current_user));
@@ -128,18 +145,18 @@
}
// static
-void H5vccAccountManager::PostResult(
+void H5vccAccountManagerInternal::PostResult(
base::MessageLoop* message_loop,
- base::WeakPtr<H5vccAccountManager> h5vcc_account_manager,
+ base::WeakPtr<H5vccAccountManagerInternal> h5vcc_account_manager,
AccessTokenCallbackReference* token_callback, const std::string& token,
uint64_t expiration_in_seconds) {
message_loop->task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&H5vccAccountManager::SendResult, h5vcc_account_manager,
- token_callback, token, expiration_in_seconds));
+ FROM_HERE, base::Bind(&H5vccAccountManagerInternal::SendResult,
+ h5vcc_account_manager, token_callback, token,
+ expiration_in_seconds));
}
-void H5vccAccountManager::SendResult(
+void H5vccAccountManagerInternal::SendResult(
AccessTokenCallbackReference* token_callback, const std::string& token,
uint64_t expiration_in_seconds) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/cobalt/h5vcc/h5vcc_account_manager.h b/cobalt/h5vcc/h5vcc_account_manager_internal.h
similarity index 68%
rename from cobalt/h5vcc/h5vcc_account_manager.h
rename to cobalt/h5vcc/h5vcc_account_manager_internal.h
index 9057f3c..94585a0 100644
--- a/cobalt/h5vcc/h5vcc_account_manager.h
+++ b/cobalt/h5vcc/h5vcc_account_manager_internal.h
@@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef COBALT_H5VCC_H5VCC_ACCOUNT_MANAGER_H_
-#define COBALT_H5VCC_H5VCC_ACCOUNT_MANAGER_H_
+#ifndef COBALT_H5VCC_H5VCC_ACCOUNT_MANAGER_INTERNAL_H_
+#define COBALT_H5VCC_H5VCC_ACCOUNT_MANAGER_INTERNAL_H_
#include <memory>
#include <queue>
#include <string>
+#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
@@ -31,24 +32,32 @@
namespace cobalt {
namespace h5vcc {
-// Implementation of the H5vccAccountManager interface. Requests will be handled
-// one-at-time on another thread in FIFO order. When a request is complete, the
-// AccessTokenCallback will be fired on the thread that the H5vccAccountManager
-// was created on.
-class H5vccAccountManager : public script::Wrappable,
- public base::SupportsWeakPtr<H5vccAccountManager> {
+// Implementation of the H5vccAccountManagerInternal interface. Requests will
+// be handled one-at-time on another thread in FIFO order. When a request is
+// complete, the AccessTokenCallback will be fired on the thread that the
+// H5vccAccountManagerInternal was created on.
+class H5vccAccountManagerInternal
+ : public script::Wrappable,
+ public base::SupportsWeakPtr<H5vccAccountManagerInternal> {
public:
typedef script::CallbackFunction<bool(const std::string&, uint64_t)>
AccessTokenCallback;
typedef script::ScriptValue<AccessTokenCallback> AccessTokenCallbackHolder;
- H5vccAccountManager();
- // H5vccAccountManager interface.
+ // Some platforms may enable the account manager interface at compile-time
+ // but need a runtime check to determine if it should be presented to the
+ // web app. If so, H5vccAccountManagerInternal will be bound to
+ // "H5vccAccountManager".
+ static bool IsSupported();
+
+ H5vccAccountManagerInternal();
+
+ // H5vccAccountManagerInternal interface.
void GetAuthToken(const AccessTokenCallbackHolder& callback);
void RequestPairing(const AccessTokenCallbackHolder& callback);
void RequestUnpairing(const AccessTokenCallbackHolder& callback);
- DEFINE_WRAPPABLE_TYPE(H5vccAccountManager);
+ DEFINE_WRAPPABLE_TYPE(H5vccAccountManagerInternal);
private:
typedef script::ScriptValue<AccessTokenCallback>::Reference
@@ -59,24 +68,24 @@
kGetToken,
};
- ~H5vccAccountManager();
+ ~H5vccAccountManagerInternal();
// Posts an operation to the account manager thread.
void PostOperation(OperationType operation_type,
const AccessTokenCallbackHolder& callback);
// Processes an operation on the account manager thread. Static because
- // H5vccAccountManager may have been destructed before this runs.
+ // H5vccAccountManagerInternal may have been destructed before this runs.
static void RequestOperationInternal(
account::UserAuthorizer* user_authorizer, OperationType operation,
const base::Callback<void(const std::string&, uint64_t)>& post_result);
// Posts the result of an operation from the account manager thread back to
- // the owning thread. Static because H5vccAccountManager may have been
+ // the owning thread. Static because H5vccAccountManagerInternal may have been
// destructed before this runs.
static void PostResult(
base::MessageLoop* message_loop,
- base::WeakPtr<H5vccAccountManager> h5vcc_account_manager,
+ base::WeakPtr<H5vccAccountManagerInternal> h5vcc_account_manager,
AccessTokenCallbackReference* token_callback, const std::string& token,
uint64_t expiration_in_seconds);
@@ -93,9 +102,9 @@
// Thread checker for the thread that creates this instance.
THREAD_CHECKER(thread_checker_);
- // The message loop that the H5vccAccountManager was created on. The public
- // interface must be called from this message loop, and callbacks will be
- // fired on this loop as well.
+ // The message loop that the H5vccAccountManagerInternal was created on. The
+ // public interface must be called from this message loop, and callbacks will
+ // be fired on this loop as well.
base::MessageLoop* owning_message_loop_;
// Each incoming request will have a corresponding task posted to this
@@ -105,11 +114,11 @@
// message loop gets flushed.
base::Thread thread_;
- friend class scoped_refptr<H5vccAccountManager>;
- DISALLOW_COPY_AND_ASSIGN(H5vccAccountManager);
+ friend class scoped_refptr<H5vccAccountManagerInternal>;
+ DISALLOW_COPY_AND_ASSIGN(H5vccAccountManagerInternal);
};
} // namespace h5vcc
} // namespace cobalt
-#endif // COBALT_H5VCC_H5VCC_ACCOUNT_MANAGER_H_
+#endif // COBALT_H5VCC_H5VCC_ACCOUNT_MANAGER_INTERNAL_H_
diff --git a/cobalt/h5vcc/h5vcc_account_manager.idl b/cobalt/h5vcc/h5vcc_account_manager_internal.idl
similarity index 95%
rename from cobalt/h5vcc/h5vcc_account_manager.idl
rename to cobalt/h5vcc/h5vcc_account_manager_internal.idl
index a62f2d5..0c648a2 100644
--- a/cobalt/h5vcc/h5vcc_account_manager.idl
+++ b/cobalt/h5vcc/h5vcc_account_manager_internal.idl
@@ -15,7 +15,7 @@
Conditional=COBALT_ENABLE_ACCOUNT_MANAGER,
Constructor
]
-interface H5vccAccountManager {
+interface H5vccAccountManagerInternal {
void getAuthToken(AccessTokenCallback callback);
void requestPairing(AccessTokenCallback callback);
void requestUnpairing(AccessTokenCallback callback);
diff --git a/cobalt/media_session/media_session_client.cc b/cobalt/media_session/media_session_client.cc
index e668cae..c8290cf 100644
--- a/cobalt/media_session/media_session_client.cc
+++ b/cobalt/media_session/media_session_client.cc
@@ -331,7 +331,7 @@
ext_image.src = media_image.src().c_str();
if (ext_image.src == nullptr) {
// src() is required, but Cobalt IDL parser doesn't enforce it.
- // http://cs/cobalt/cobalt/media_session/media_image.idl?l=19
+ // See cobalt/media_session/media_image.idl for more info.
// https://wicg.github.io/mediasession/#dictdef-mediaimage
LOG(ERROR) << "Required src string for MediaImage is missing.";
}
diff --git a/cobalt/script/BUILD.gn b/cobalt/script/BUILD.gn
index fb5b577..1582517 100644
--- a/cobalt/script/BUILD.gn
+++ b/cobalt/script/BUILD.gn
@@ -58,6 +58,7 @@
deps = [
"//cobalt/base",
+ "//cobalt/loader:origin",
"//nb",
"//starboard:starboard_headers_only",
"//third_party/v8",
diff --git a/cobalt/script/environment_settings.h b/cobalt/script/environment_settings.h
index d1761da..1980d9b 100644
--- a/cobalt/script/environment_settings.h
+++ b/cobalt/script/environment_settings.h
@@ -20,6 +20,7 @@
#include "base/memory/ref_counted.h"
#include "cobalt/base/debugger_hooks.h"
+#include "cobalt/loader/origin.h"
#include "url/gurl.h"
namespace cobalt {
@@ -47,7 +48,10 @@
const GURL& creation_url() const { return creation_url_; }
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-origin
- const GURL GetOrigin() const { return creation_url().GetOrigin(); }
+ // TODO(b/244368134): Replace with url::Origin.
+ virtual loader::Origin GetOrigin() const {
+ return loader::Origin(base_url().GetOrigin());
+ }
const base::DebuggerHooks& debugger_hooks() const { return debugger_hooks_; }
diff --git a/cobalt/web/message_port.cc b/cobalt/web/message_port.cc
index 519e682..e0eb126 100644
--- a/cobalt/web/message_port.cc
+++ b/cobalt/web/message_port.cc
@@ -66,7 +66,7 @@
}
void MessagePort::PostMessage(const script::ValueHandleHolder& message) {
- PostMessageSerialized(std::move(SerializeScriptValue(message)));
+ PostMessageSerialized(std::move(script::SerializeScriptValue(message)));
}
void MessagePort::PostMessageSerialized(
diff --git a/cobalt/worker/service_worker_jobs.cc b/cobalt/worker/service_worker_jobs.cc
index 0c31df7..e30f364 100644
--- a/cobalt/worker/service_worker_jobs.cc
+++ b/cobalt/worker/service_worker_jobs.cc
@@ -841,7 +841,7 @@
ResolveJobPromise(job, registration);
// 8. Let settingsObjects be all environment settings objects whose origin is
// registration’s scope url's origin.
- auto registration_origin = registration->scope_url().GetOrigin();
+ auto registration_origin = loader::Origin(registration->scope_url());
// 9. For each settingsObject of settingsObjects...
for (auto& context : web_context_registrations_) {
if (context->environment_settings()->GetOrigin() == registration_origin) {
@@ -1469,7 +1469,7 @@
DCHECK_NE(kServiceWorkerStateParsed, state);
// 2. Set worker's state to state.
worker->set_state(state);
- auto worker_origin = worker->script_url().GetOrigin();
+ auto worker_origin = loader::Origin(worker->script_url());
// 3. Let settingsObjects be all environment settings objects whose origin is
// worker's script url's origin.
// 4. For each settingsObject of settingsObjects...
@@ -1615,7 +1615,7 @@
// Algorithm for Unregister:
// https://w3c.github.io/ServiceWorker/#unregister-algorithm
// 1. If the origin of job’s scope url is not job’s client's origin, then:
- if (!url::Origin::Create(job->client->GetOrigin())
+ if (!url::Origin::Create(GURL(job->client->GetOrigin().SerializedOrigin()))
.IsSameOriginWith(url::Origin::Create(job->scope_url))) {
// 1.1. Invoke Reject Job Promise with job and "SecurityError" DOMException.
RejectJobPromise(
diff --git a/cobalt/worker/service_worker_object.cc b/cobalt/worker/service_worker_object.cc
index 193638b..436f256 100644
--- a/cobalt/worker/service_worker_object.cc
+++ b/cobalt/worker/service_worker_object.cc
@@ -153,6 +153,9 @@
// Return serviceWorker’s script url.
// The origin
// Return its registering service worker client's origin.
+ WorkerSettings* worker_settings = new WorkerSettings();
+ worker_settings->set_origin(
+ loader::Origin(containing_service_worker_registration()->scope_url()));
// The policy container
// Return workerGlobalScope’s policy container.
// The time origin
@@ -162,7 +165,8 @@
// serviceWorker’s script url, top-level creation URL to null, top-level
// origin to an implementation-defined value, target browsing context to
// null, and active service worker to null.
- web_context_->setup_environment_settings(new WorkerSettings());
+
+ web_context_->setup_environment_settings(worker_settings);
web_context_->environment_settings()->set_creation_url(script_url_);
scoped_refptr<ServiceWorkerGlobalScope> service_worker_global_scope =
new ServiceWorkerGlobalScope(web_context_->environment_settings(), this);
diff --git a/cobalt/worker/worker.cc b/cobalt/worker/worker.cc
index aeed129..a820c8f 100644
--- a/cobalt/worker/worker.cc
+++ b/cobalt/worker/worker.cc
@@ -85,8 +85,14 @@
// . For the global object, if is shared is true, create a new
// SharedWorkerGlobalScope object. Otherwise, create a new
// DedicatedWorkerGlobalScope object.
- web_context_->setup_environment_settings(
- new WorkerSettings(options_.outside_port));
+ WorkerSettings* worker_settings = new WorkerSettings(options_.outside_port);
+ // From algorithm to set up a worker environment settings object
+ // Let inherited origin be outside settings's origin.
+ // The origin return a unique opaque origin if worker global scope's url's
+ // scheme is "data", and inherited origin otherwise.
+ // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#set-up-a-worker-environment-settings-object
+ worker_settings->set_origin(options_.outside_settings->GetOrigin());
+ web_context_->setup_environment_settings(worker_settings);
// From algorithm for to setup up a worker environment settings object:
// https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#set-up-a-worker-environment-settings-object
// 5. Set settings object's creation URL to worker global scope's url.
diff --git a/cobalt/worker/worker_settings.cc b/cobalt/worker/worker_settings.cc
index 8e53e10..df42733 100644
--- a/cobalt/worker/worker_settings.cc
+++ b/cobalt/worker/worker_settings.cc
@@ -43,6 +43,23 @@
return context()->GetWindowOrWorkerGlobalScope()->AsWorker()->Url();
}
+loader::Origin WorkerSettings::GetOrigin() const {
+ // From algorithm for to setup up a worker environment settings object:
+ // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#set-up-a-worker-environment-settings-object
+ // 3. Let settings object be a new environment settings object whose
+ // algorithms are defined as follows:
+ // The origin
+ // Return a unique opaque origin if worker global scope's url's scheme is
+ // "data", and inherited origin otherwise.
+ DCHECK(context()->GetWindowOrWorkerGlobalScope()->IsWorker());
+ const GURL& url =
+ context()->GetWindowOrWorkerGlobalScope()->AsWorker()->Url();
+ // TODO(b/244368134): Replace with url::Origin::CreateUniqueOpaque().
+ // Note: This does not have to be specialized for service workers, since
+ // their URL can not be a data URL.
+ if (url.SchemeIs("data")) return loader::Origin();
+ return origin_;
+}
} // namespace worker
} // namespace cobalt
diff --git a/cobalt/worker/worker_settings.h b/cobalt/worker/worker_settings.h
index b2d7097..3550b19 100644
--- a/cobalt/worker/worker_settings.h
+++ b/cobalt/worker/worker_settings.h
@@ -37,9 +37,16 @@
//
const GURL& base_url() const override;
+ // Return the origin of window's associated Document.
+ // https://html.spec.whatwg.org/#set-up-a-window-environment-settings-object
+ void set_origin(const loader::Origin& origin) { origin_ = origin; }
+ loader::Origin GetOrigin() const override;
+
private:
// Outer message port.
web::MessagePort* message_port_ = nullptr;
+
+ loader::Origin origin_;
};
} // namespace worker
diff --git a/cobalt/xhr/xml_http_request.cc b/cobalt/xhr/xml_http_request.cc
index 56de1ee..d943154 100644
--- a/cobalt/xhr/xml_http_request.cc
+++ b/cobalt/xhr/xml_http_request.cc
@@ -570,7 +570,7 @@
if (upload_) {
upload_listener_ = upload_->HasOneOrMoreAttributeEventListener();
}
- origin_ = loader::Origin(settings_->GetOrigin());
+ origin_ = settings_->GetOrigin();
// Step 9
sent_ = true;
// Now that a send is happening, prevent this object
diff --git a/cobalt/xhr/xml_http_request.h b/cobalt/xhr/xml_http_request.h
index 046e90f..01979a6 100644
--- a/cobalt/xhr/xml_http_request.h
+++ b/cobalt/xhr/xml_http_request.h
@@ -26,6 +26,7 @@
#include "cobalt/dom/document.h"
#include "cobalt/loader/cors_preflight.h"
#include "cobalt/loader/net_fetcher.h"
+#include "cobalt/loader/origin.h"
#include "cobalt/script/array_buffer.h"
#include "cobalt/script/array_buffer_view.h"
#include "cobalt/script/environment_settings.h"
diff --git a/starboard/CHANGELOG.md b/starboard/CHANGELOG.md
index 69ca601..fddc2c3 100644
--- a/starboard/CHANGELOG.md
+++ b/starboard/CHANGELOG.md
@@ -15,6 +15,9 @@
[configuration.h](configuration.h).
## Version 14
+### Require kSbSystemPathStorageDirectory on all platforms.
+Path to directory for permanent persistent storage.
+
### Add MP3, FLAC, and PCM values to SbMediaAudioCodec.
This makes it possible to support these codecs in the future.
diff --git a/starboard/android/apk/apk_sources.gni b/starboard/android/apk/apk_sources.gni
index e0378ea..07912f6 100644
--- a/starboard/android/apk/apk_sources.gni
+++ b/starboard/android/apk/apk_sources.gni
@@ -21,7 +21,6 @@
"//starboard/android/apk/app/src/main/java/dev/cobalt/account/AccessToken.java",
"//starboard/android/apk/app/src/main/java/dev/cobalt/account/NoopUserAuthorizer.java",
"//starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizer.java",
- "//starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java",
"//starboard/android/apk/app/src/main/java/dev/cobalt/coat/AudioPermissionRequester.java",
"//starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltA11yHelper.java",
"//starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java",
diff --git a/starboard/android/apk/app/src/app/AndroidManifest.xml b/starboard/android/apk/app/src/app/AndroidManifest.xml
index 42d8bc0..9c4e11a 100644
--- a/starboard/android/apk/app/src/app/AndroidManifest.xml
+++ b/starboard/android/apk/app/src/app/AndroidManifest.xml
@@ -32,7 +32,7 @@
<!-- This is needed when targeting API 28+ to use foreground services -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
- <!-- Used for go/cobalt-ifa and AdvertisingIdClient.Info.getId() -->
+ <!-- https://iabtechlab.com/OTT-IFA, AdvertisingIdClient.Info.getId() -->
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
<application
diff --git a/starboard/android/apk/app/src/app/java/dev/cobalt/app/MainActivity.java b/starboard/android/apk/app/src/app/java/dev/cobalt/app/MainActivity.java
index dc26a8a..ee4cdee 100644
--- a/starboard/android/apk/app/src/app/java/dev/cobalt/app/MainActivity.java
+++ b/starboard/android/apk/app/src/app/java/dev/cobalt/app/MainActivity.java
@@ -16,7 +16,7 @@
import android.app.Activity;
import android.app.Service;
-import dev.cobalt.account.UserAuthorizerImpl;
+import dev.cobalt.account.NoopUserAuthorizer;
import dev.cobalt.coat.CobaltActivity;
import dev.cobalt.coat.CobaltService;
import dev.cobalt.coat.StarboardBridge;
@@ -42,8 +42,7 @@
getStarboardBridge().requestStop(0);
}
};
- UserAuthorizerImpl userAuthorizer =
- new UserAuthorizerImpl(getApplicationContext(), activityHolder, stopRequester);
+ NoopUserAuthorizer userAuthorizer = new NoopUserAuthorizer();
StarboardBridge bridge =
new StarboardBridge(
getApplicationContext(),
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/account/NoopUserAuthorizer.java b/starboard/android/apk/app/src/main/java/dev/cobalt/account/NoopUserAuthorizer.java
index e995dd2..cf5b7f9 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/account/NoopUserAuthorizer.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/account/NoopUserAuthorizer.java
@@ -18,6 +18,7 @@
import dev.cobalt.util.UsedByNative;
/** UserAuthorizer implementation that doesn't try to sign in. */
+@UsedByNative
public class NoopUserAuthorizer implements UserAuthorizer {
@Override
@@ -55,5 +56,4 @@
@Override
public void onRequestPermissionsResult(
int requestCode, String[] permissions, int[] grantResults) {}
-
}
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java b/starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java
deleted file mode 100644
index 1d96237..0000000
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/account/UserAuthorizerImpl.java
+++ /dev/null
@@ -1,537 +0,0 @@
-// Copyright 2017 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package dev.cobalt.account;
-
-import static android.Manifest.permission.GET_ACCOUNTS;
-import static dev.cobalt.util.Log.TAG;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.OnAccountsUpdateListener;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-import android.widget.Toast;
-import androidx.core.app.ActivityCompat;
-import androidx.core.content.ContextCompat;
-import com.google.android.gms.auth.GoogleAuthException;
-import com.google.android.gms.auth.GoogleAuthUtil;
-import com.google.android.gms.auth.UserRecoverableAuthException;
-import com.google.android.gms.common.AccountPicker;
-import com.google.android.gms.common.AccountPicker.AccountChooserOptions;
-import dev.cobalt.coat.R;
-import dev.cobalt.util.Holder;
-import dev.cobalt.util.Log;
-import dev.cobalt.util.UsedByNative;
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
- * Java side implementation for starboard::android::shared::cobalt::AndroidUserAuthorizer.
- *
- * This implements the following business logic:
- * First run...
- * - if there are no accounts, just be be signed-out
- * - if there is one account, sign-in without any UI
- * - if there are more than one accounts, prompt to choose account
- * Subsequent runs...
- * - sign-in to the same account last used to sign-in
- * - if previously signed-out stay signed-out
- * When user clicks 'sign-in' in the UI...
- * - if there are no accounts, allow user to add an account
- * - if there is one account, sign-in without any UI
- * - if there are more than one accounts, prompt to choose account
- * If the last signed-in account is deleted...
- * - kill the app if stopped in the background to prompt next time it starts
- * - at the next app start, show a toast that the account isn't available
- * - if there are no accounts left, just be be signed-out
- * - if there are one or more accounts left, prompt to choose account
- */
-public class UserAuthorizerImpl implements OnAccountsUpdateListener, UserAuthorizer {
-
- /** Pseudo account indicating the user chose to be signed-out. */
- public static final Account SIGNED_OUT_ACCOUNT = new Account("-", "-");
-
- /** Pseudo account indicating a saved account no longer exists. */
- private static final Account MISSING_ACCOUNT = new Account("!", "!");
-
- /** Foreshortened expiry of Google OAuth token, which typically lasts 1 hour. */
- private static final long DEFAULT_EXPIRY_SECONDS = 5 * 60;
-
- private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
- private static final String[] OAUTH_SCOPES = {
- "https://www.googleapis.com/auth/youtube"
- };
-
- private static final String SHARED_PREFS_NAME = "user_auth";
- private static final String ACCOUNT_NAME_PREF_KEY = "signed_in_account";
-
- /** The thread on which the current request is running, or null if none. */
- private volatile Thread requestThread;
-
- private final Context appContext;
- private final Holder<Activity> activityHolder;
- private final Runnable stopRequester;
- private final Handler mainHandler;
-
- private Account currentAccount = null;
- private AccessToken currentToken = null;
-
- // Result from the account picker UI lands here.
- private String chosenAccountName;
-
- private volatile boolean waitingForPermission;
- private volatile boolean permissionGranted;
-
- public UserAuthorizerImpl(
- Context appContext, Holder<Activity> activityHolder, Runnable stopRequester) {
- this.appContext = appContext;
- this.activityHolder = activityHolder;
- this.stopRequester = stopRequester;
- this.mainHandler = new Handler(Looper.getMainLooper());
- addOnAccountsUpdatedListener(this);
- }
-
- @Override
- public void shutdown() {
- removeOnAccountsUpdatedListener(this);
- }
-
- @Override
- @SuppressWarnings("unused")
- @UsedByNative
- public void interrupt() {
- Thread t = requestThread;
- if (t != null) {
- t.interrupt();
- }
- }
-
- @Override
- @SuppressWarnings("unused")
- @UsedByNative
- public AccessToken authorizeUser() {
- ensureBackgroundThread();
- requestThread = Thread.currentThread();
- // Let the user choose an account, or add one if there are none to choose.
- // However, if there's only one account just choose it without any prompt.
- currentAccount = autoSelectOrAddAccount();
- writeAccountPref(currentAccount);
- AccessToken accessToken = refreshCurrentToken();
- requestThread = null;
- return accessToken;
- }
-
- @Override
- @SuppressWarnings("unused")
- @UsedByNative
- public boolean deauthorizeUser() {
- ensureBackgroundThread();
- requestThread = Thread.currentThread();
- currentAccount = SIGNED_OUT_ACCOUNT;
- writeAccountPref(currentAccount);
- clearCurrentToken();
- requestThread = null;
- return true;
- }
-
- @Override
- @SuppressWarnings("unused")
- @UsedByNative
- public AccessToken refreshAuthorization() {
- ensureBackgroundThread();
- requestThread = Thread.currentThread();
-
- // If we haven't yet determined which account to use, check preferences for a saved account.
- if (currentAccount == null) {
- Account savedAccount = readAccountPref();
- if (savedAccount == null) {
- // No saved account, so this is the first ever run of the app.
- currentAccount = autoSelectAccount();
- } else if (savedAccount.equals(MISSING_ACCOUNT)) {
- // The saved account got deleted.
- currentAccount = forceSelectAccount();
- } else {
- // Use the saved account.
- currentAccount = savedAccount;
- }
- writeAccountPref(currentAccount);
- }
-
- AccessToken accessToken = refreshCurrentToken();
- requestThread = null;
- return accessToken;
- }
-
- private static void ensureBackgroundThread() {
- if (Looper.myLooper() == Looper.getMainLooper()) {
- throw new UnsupportedOperationException("UserAuthorizer can't be called on main thread");
- }
- }
-
- private void showToast(int resId, Object... formatArgs) {
- final String msg = appContext.getResources().getString(resId, formatArgs);
- mainHandler.post(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(appContext, msg, Toast.LENGTH_LONG).show();
- }
- });
- }
-
- private Account readAccountPref() {
- String savedAccountName = loadSignedInAccountName();
- if (TextUtils.isEmpty(savedAccountName)) {
- return null;
- } else if (savedAccountName.equals(SIGNED_OUT_ACCOUNT.name)) {
- // Don't request permissions or look for a device account if we were signed-out.
- return SIGNED_OUT_ACCOUNT;
- } else if (!checkPermission()) {
- // We won't be able to get the account without permission, so warn the user and be signed-out.
- showToast(R.string.starboard_missing_account, savedAccountName);
- return SIGNED_OUT_ACCOUNT;
- } else {
- // Find the saved account name among all accounts on the device.
- for (Account account : getAccounts()) {
- if (account.name.equals(savedAccountName)) {
- return account;
- }
- }
- showToast(R.string.starboard_missing_account, savedAccountName);
- return MISSING_ACCOUNT;
- }
- }
-
- private void writeAccountPref(Account account) {
- if (account == null) {
- return;
- }
- // Always write the account name, even if it's the signed-out pseudo account.
- saveSignedInAccountName(account.name);
- }
-
- private void clearCurrentToken() {
- if (currentToken != null) {
- clearToken(currentToken.getTokenValue());
- currentToken = null;
- }
- }
-
- private AccessToken refreshCurrentToken() {
- clearCurrentToken();
- if (currentAccount == null || SIGNED_OUT_ACCOUNT.equals(currentAccount)) {
- return null;
- }
- String tokenValue = getToken(currentAccount);
- if (tokenValue == null) {
- showToast(R.string.starboard_account_auth_error);
- tokenValue = "";
- }
- // TODO: Get the token details and use the actual expiry.
- long expiry = System.currentTimeMillis() / 1000 + DEFAULT_EXPIRY_SECONDS;
- currentToken = new AccessToken(tokenValue, expiry);
- return currentToken;
- }
-
- /**
- * Prompts the user to select an account, or to add an account if there are none. The prompt is
- * skipped if there is exactly one account to choose from.
- */
- private Account autoSelectOrAddAccount() {
- if (!checkPermission()) {
- return SIGNED_OUT_ACCOUNT;
- }
- Account[] accounts = getAccounts();
- if (accounts.length == 1) {
- return accounts[0];
- }
- return selectOrAddAccount();
- }
-
- /**
- * Prompts the user to select an account. The prompt is skipped if there are zero or one accounts
- * to choose from.
- */
- private Account autoSelectAccount() {
- if (!checkPermission()) {
- return SIGNED_OUT_ACCOUNT;
- }
- Account[] accounts = getAccounts();
- if (accounts.length == 0) {
- return SIGNED_OUT_ACCOUNT;
- } else if (accounts.length == 1) {
- return accounts[0];
- }
- return selectOrAddAccount();
- }
-
- /**
- * Prompts the user to select an account, even if there's only one to choose from. The prompt is
- * skipped if there are zero accounts to choose from.
- */
- private Account forceSelectAccount() {
- // We don't check permissions before calling selectOrAddAccount() because if the account is
- // missing, readAccountPref() must have just checked, and we don't want to show permission
- // prompt or rationale to the user twice.
- Account[] accounts = getAccounts();
- if (accounts.length == 0) {
- return SIGNED_OUT_ACCOUNT;
- }
- return selectOrAddAccount();
- }
-
- /**
- * Prompts the user to select an account, even if there's only one to choose from. If there are
- * zero accounts to choose from, the user is prompted to add one.
- *
- * The caller should ensure permissions are granted before calling this method to avoid showing
- * a picker with accounts that we can't access.
- */
- private Account selectOrAddAccount() {
- String accountName = showAccountPicker();
- // If user cancelled the picker stay signed-out.
- if (TextUtils.isEmpty(accountName)) {
- return SIGNED_OUT_ACCOUNT;
- }
- // Get the accounts after the picker in case one was added in the account picker.
- for (Account account : getAccounts()) {
- if (account.name.equals(accountName)) {
- return account;
- }
- }
- // This shouldn't happen, but if it does let the user know we're still signed-out.
- Log.e(TAG, "Selected account is missing");
- showToast(R.string.starboard_missing_account, accountName);
- return SIGNED_OUT_ACCOUNT;
- }
-
- private synchronized String showAccountPicker() {
- Activity activity = activityHolder.get();
- Intent chooseAccountIntent = newChooseAccountIntent(currentAccount);
- if (activity == null || chooseAccountIntent == null) {
- return "";
- }
- chosenAccountName = null;
- activity.startActivityForResult(chooseAccountIntent, R.id.rc_choose_account);
-
- // Block until the account picker activity returns its result.
- while (chosenAccountName == null) {
- try {
- wait();
- } catch (InterruptedException e) {
- Log.e(TAG, "Account picker interrupted");
- // Return empty string, as if the picker was cancelled.
- return "";
- }
- }
- return chosenAccountName;
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == R.id.rc_choose_account) {
- String accountName = null;
- if (resultCode == Activity.RESULT_OK) {
- accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
- } else if (resultCode != Activity.RESULT_CANCELED) {
- Log.e(TAG, "Account picker error " + resultCode);
- showToast(R.string.starboard_account_picker_error);
- }
-
- // Notify showAccountPicker() which account was chosen.
- synchronized (this) {
- // Return empty string if the picker is cancelled or there's an unexpected result.
- chosenAccountName = (accountName == null) ? "" : accountName;
- notifyAll();
- }
- }
- }
-
- @Override
- public void onAccountsUpdated(Account[] unused) {
- if (currentAccount == null || SIGNED_OUT_ACCOUNT.equals(currentAccount)) {
- // We're not signed-in; the update doesn't affect us.
- return;
- }
- // Call getAccounts() since the param may not match the accounts we can access.
- for (Account account : getAccounts()) {
- if (account.name.equals(currentAccount.name)) {
- // The current account is still there; the update doesn't affect us.
- return;
- }
- }
- // The current account is gone; leave the app so we prompt for sign-in next time.
- // This should only happen while stopped in the background since we don't delete accounts.
- stopRequester.run();
- }
-
- /**
- * Calls framework AccountManager.addOnAccountsUpdatedListener().
- */
- private void addOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
- AccountManager.get(appContext).addOnAccountsUpdatedListener(listener, null, false);
- }
-
- /**
- * Calls framework AccountManager.removeOnAccountsUpdatedListener().
- */
- private void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
- AccountManager.get(appContext).removeOnAccountsUpdatedListener(listener);
- }
-
- /**
- * Calls framework AccountManager.getAccountsByType() for Google accounts.
- */
- private Account[] getAccounts() {
- return AccountManager.get(appContext).getAccountsByType(GOOGLE_ACCOUNT_TYPE);
- }
-
- /**
- * Calls GMS AccountPicker.newChooseAccountIntent().
- *
- * Returns an Intent that when started will always show the account picker even if there's just
- * one account on the device. If there are no accounts on the device it shows the UI to add one.
- */
- private Intent newChooseAccountIntent(Account defaultAccount) {
- AccountChooserOptions chooserOptions = new AccountChooserOptions.Builder()
- .setSelectedAccount(defaultAccount)
- .setAllowableAccountsTypes(Arrays.asList(GOOGLE_ACCOUNT_TYPE))
- .setAlwaysShowAccountPicker(true)
- .build();
- return AccountPicker.newChooseAccountIntent(chooserOptions);
- }
-
- /**
- * Calls GMS GoogleAuthUtil.getToken(), without throwing any exceptions.
- *
- * Returns an empty string if no token is available for the account.
- * Returns null if there was an error getting the token.
- */
- private String getToken(Account account) {
- String joinedScopes = "oauth2:" + TextUtils.join(" ", OAUTH_SCOPES);
- try {
- return GoogleAuthUtil.getToken(appContext, account, joinedScopes);
- } catch (UserRecoverableAuthException e) {
- Log.w(TAG, "Recoverable error getting OAuth token", e);
- Intent intent = e.getIntent();
- Activity activity = activityHolder.get();
- if (intent != null && activity != null) {
- activity.startActivity(intent);
- } else {
- Log.e(TAG, "Failed to recover OAuth token", e);
- }
- return null;
-
- } catch (IOException | GoogleAuthException e) {
- Log.e(TAG, "Error getting auth token", e);
- return null;
- }
- }
-
- /**
- * Calls GMS GoogleAuthUtil.clearToken(), without throwing any exceptions.
- */
- private void clearToken(String tokenValue) {
- try {
- GoogleAuthUtil.clearToken(appContext, tokenValue);
- } catch (GoogleAuthException | IOException e) {
- Log.e(TAG, "Error clearing auth token", e);
- }
- }
-
- /**
- * Checks whether the app has necessary permissions, asking for them if needed.
- *
- * This blocks until permissions are granted/declined, and should not be called on the UI thread.
- *
- * Returns true if permissions are granted.
- */
- private synchronized boolean checkPermission() {
- if (ContextCompat.checkSelfPermission(appContext, GET_ACCOUNTS)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
-
- final Activity activity = activityHolder.get();
- if (activity == null) {
- return false;
- }
-
- // Check if we have previously been denied permission.
- if (ActivityCompat.shouldShowRequestPermissionRationale(activity, GET_ACCOUNTS)) {
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(activity, R.string.starboard_accounts_permission, Toast.LENGTH_LONG)
- .show();
- }
- });
- return false;
- }
-
- // Request permission.
- waitingForPermission = true;
- permissionGranted = false;
- ActivityCompat.requestPermissions(
- activity, new String[]{GET_ACCOUNTS}, R.id.rc_get_accounts_permission);
- try {
- while (waitingForPermission) {
- wait();
- }
- } catch (InterruptedException e) {
- return false;
- }
- return permissionGranted;
- }
-
- /**
- * Callback pass-thru from the Activity with the result from requesting permissions.
- */
- @Override
- public void onRequestPermissionsResult(
- int requestCode, String[] permissions, int[] grantResults) {
- if (requestCode == R.id.rc_get_accounts_permission) {
- synchronized (this) {
- permissionGranted = grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED;
- waitingForPermission = false;
- notifyAll();
- }
- }
- }
-
- /**
- * Remember the name of the signed-in account.
- */
- private void saveSignedInAccountName(String accountName) {
- getPreferences().edit().putString(ACCOUNT_NAME_PREF_KEY, accountName).commit();
- }
-
- /**
- * Returns the remembered name of the signed-in account.
- */
- private String loadSignedInAccountName() {
- return getPreferences().getString(ACCOUNT_NAME_PREF_KEY, "");
- }
-
- private SharedPreferences getPreferences() {
- return appContext.getSharedPreferences(SHARED_PREFS_NAME, 0);
- }
-}
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/libraries/services/clientloginfo/ClientLogInfo.java b/starboard/android/apk/app/src/main/java/dev/cobalt/libraries/services/clientloginfo/ClientLogInfo.java
index 57c39ad..7628f93 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/libraries/services/clientloginfo/ClientLogInfo.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/libraries/services/clientloginfo/ClientLogInfo.java
@@ -6,10 +6,7 @@
import dev.cobalt.coat.CobaltService;
import dev.cobalt.util.Log;
-/**
- * ClientLogInfo to report Android API support on android devices, read go/coat-api-support for more
- * info.
- */
+/** ClientLogInfo to report Android API support on android devices. */
public class ClientLogInfo extends CobaltService {
public static final String TAG = "ClientLogInfo";
diff --git a/starboard/android/shared/cobalt/android_user_authorizer.cc b/starboard/android/shared/cobalt/android_user_authorizer.cc
index d8eb6c9..9b19e75 100644
--- a/starboard/android/shared/cobalt/android_user_authorizer.cc
+++ b/starboard/android/shared/cobalt/android_user_authorizer.cc
@@ -14,6 +14,8 @@
#include "starboard/android/shared/cobalt/android_user_authorizer.h"
+#include <memory>
+
#include "base/time/time.h"
#include "starboard/android/shared/jni_env_ext.h"
#include "starboard/android/shared/jni_utils.h"
@@ -29,6 +31,17 @@
namespace shared {
namespace cobalt {
+bool UserAuthorizerIsSupported() {
+ // If using the NoopUserAuthorizer, then user authorizer functionally is not
+ // supported.
+ JniEnvExt* env = JniEnvExt::Get();
+ jobject local_ref = env->CallStarboardObjectMethodOrAbort(
+ "getUserAuthorizer", "()Ldev/cobalt/account/UserAuthorizer;");
+ return !env->IsInstanceOf(
+ local_ref,
+ env->FindClassExtOrAbort("dev/cobalt/account/NoopUserAuthorizer"));
+}
+
AndroidUserAuthorizer::AndroidUserAuthorizer() : shutdown_(false) {
JniEnvExt* env = JniEnvExt::Get();
jobject local_ref = env->CallStarboardObjectMethodOrAbort(
@@ -71,8 +84,8 @@
"()Z");
}
-std::unique_ptr<AccessToken>
-AndroidUserAuthorizer::RefreshAuthorization(SbUser user) {
+std::unique_ptr<AccessToken> AndroidUserAuthorizer::RefreshAuthorization(
+ SbUser user) {
SB_DCHECK(user == &::starboard::shared::nouser::g_user);
if (shutdown_) {
DLOG(WARNING) << "No-op RefreshAuthorization after shutdown";
@@ -85,8 +98,8 @@
return CreateAccessToken(j_token.Get());
}
-std::unique_ptr<AccessToken>
-AndroidUserAuthorizer::CreateAccessToken(jobject j_token) {
+std::unique_ptr<AccessToken> AndroidUserAuthorizer::CreateAccessToken(
+ jobject j_token) {
if (!j_token) {
return std::unique_ptr<AccessToken>();
}
@@ -101,8 +114,8 @@
env->GetStringStandardUTFOrAbort(j_token_string.Get());
}
- jlong j_expiry = env->CallLongMethodOrAbort(
- j_token, "getExpirySeconds", "()J");
+ jlong j_expiry =
+ env->CallLongMethodOrAbort(j_token, "getExpirySeconds", "()J");
if (j_expiry > 0) {
access_token->expiry =
base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(j_expiry);
@@ -120,7 +133,10 @@
namespace account {
UserAuthorizer* UserAuthorizer::Create() {
- return new ::starboard::android::shared::cobalt::AndroidUserAuthorizer();
+ if (::starboard::android::shared::cobalt::UserAuthorizerIsSupported()) {
+ return new ::starboard::android::shared::cobalt::AndroidUserAuthorizer();
+ }
+ return nullptr;
}
} // namespace account
diff --git a/starboard/nplb/system_get_path_test.cc b/starboard/nplb/system_get_path_test.cc
index e320737..44f4e00 100644
--- a/starboard/nplb/system_get_path_test.cc
+++ b/starboard/nplb/system_get_path_test.cc
@@ -69,6 +69,9 @@
TEST(SbSystemGetPathTest, ReturnsRequiredPaths) {
BasicTest(kSbSystemPathContentDirectory, true, true, __LINE__);
BasicTest(kSbSystemPathCacheDirectory, true, true, __LINE__);
+#if SB_API_VERSION >= 14
+ BasicTest(kSbSystemPathStorageDirectory, true, true, __LINE__);
+#endif // SB_API_VERSION >= 14
}
TEST(SbSystemGetPathTest, FailsGracefullyZeroBufferLength) {