Import Cobalt 24.lts.5.1032616
diff --git a/.github/config/linux-modular.json b/.github/config/linux-modular.json index ee3f9b1..c4e25d4 100644 --- a/.github/config/linux-modular.json +++ b/.github/config/linux-modular.json
@@ -10,7 +10,7 @@ "name":"modular", "platform":"linux-x64x11-modular", "target_platform":"linux-x64x11", - "extra_gn_arguments":"build_with_separate_cobalt_toolchain=true" + "extra_gn_arguments":"build_with_separate_cobalt_toolchain=true use_contrib_cast=true" } ] }
diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h index e8a2add..ef498e9 100644 --- a/base/i18n/base_i18n_export.h +++ b/base/i18n/base_i18n_export.h
@@ -5,7 +5,11 @@ #ifndef BASE_I18N_BASE_I18N_EXPORT_H_ #define BASE_I18N_BASE_I18N_EXPORT_H_ -#if defined(COMPONENT_BUILD) +#ifdef USE_COBALT_CUSTOMIZATIONS +#include "starboard/configuration.h" +#endif // USE_COBALT_CUSTOMIZATIONS + +#if defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN) #if defined(WIN32) #if defined(BASE_I18N_IMPLEMENTATION) @@ -22,7 +26,7 @@ #endif #endif -#else // defined(COMPONENT_BUILD) +#else // defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN) #define BASE_I18N_EXPORT #endif
diff --git a/build/config/win/visual_studio_version.gni b/build/config/win/visual_studio_version.gni index 63b9a97..22ec3af 100644 --- a/build/config/win/visual_studio_version.gni +++ b/build/config/win/visual_studio_version.gni
@@ -39,6 +39,8 @@ declare_args() { msvc_path = "$visual_studio_path/VC/Tools/MSVC/$visual_studio_version" + + llvm_clang_path = "$visual_studio_path/VC/Tools/Llvm/x64/bin" } } else { declare_args() {
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index 89b26d3..2a2cc3c 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -117,7 +117,7 @@ template("gcc_toolchain") { toolchain(target_name) { is_starboard_toolchain = target_name == "starboard" - if (!build_with_separate_cobalt_toolchain) { + if (!sb_is_modular || sb_is_evergreen) { not_needed(["is_starboard_toolchain"]) } assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value") @@ -391,7 +391,7 @@ # TODO(b/206642994): see if we can remove this condition. It's needed for # now to add cflags for evergreen platforms but we haven't yet decided # whether cflags should be added here for all platforms. - if (is_starboard && sb_is_evergreen && !is_starboard_toolchain) { + if (!is_starboard_toolchain && is_starboard && sb_is_modular) { command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}" } else { command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}"
diff --git a/cobalt/BUILD.gn b/cobalt/BUILD.gn index 53c4bc3..92fe9dc 100644 --- a/cobalt/BUILD.gn +++ b/cobalt/BUILD.gn
@@ -81,8 +81,5 @@ "//components/update_client", ] } - if (!build_with_separate_cobalt_toolchain) { - deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ] - } } }
diff --git a/cobalt/browser/BUILD.gn b/cobalt/browser/BUILD.gn index 3228260..25e387a 100644 --- a/cobalt/browser/BUILD.gn +++ b/cobalt/browser/BUILD.gn
@@ -55,6 +55,7 @@ ":browser", ":browser_switches", "//cobalt/base", + "//cobalt/css_parser", "//net", ] data_deps = [ @@ -414,3 +415,10 @@ cache_templates("cached_jinja_templates") { output_dir = _bindings_scripts_output_dir } + +group("test_dependencies_on_browser") { + testonly = true + + # TODO: 297087147 - Depend on smaller targets than browser. + deps = [ "//cobalt/browser" ] +}
diff --git a/cobalt/browser/browser_module.cc b/cobalt/browser/browser_module.cc index d83200f..c6f7f18 100644 --- a/cobalt/browser/browser_module.cc +++ b/cobalt/browser/browser_module.cc
@@ -492,33 +492,51 @@ // First try any registered handlers. If one of these handles the URL, we // don't use the web module. - if (TryURLHandlers(url)) { + if (NavigateTryURLHandlers(url)) { return; } // Clear error handling once we're told to navigate, either because it's the // retry from the error or something decided we should navigate elsewhere. - on_error_retry_timer_.Stop(); - waiting_for_error_retry_ = false; + NavigateResetErrorHandling(); // Navigations aren't allowed if the app is frozen. If this is the case, // simply set the pending navigate url, which will cause the navigation to // occur when Cobalt resumes, and return. - if (application_state_ == base::kApplicationStateFrozen) { - pending_navigate_url_ = url; + if (NavigateHandleStateFrozen(url)) { return; } - // Now that we know the navigation is occurring, clear out - // |pending_navigate_url_|. - pending_navigate_url_ = GURL::EmptyGURL(); + // Destroys the old WebModule, increments the navigation generation + // number, and resets the main WebModule layer + NavigateResetWebModule(); + // checks whether a service worker should be started for the given URL + auto service_worker_started_event = std::make_unique<base::WaitableEvent>(); + bool can_start_service_worker = + NavigateServiceWorkerSetups(url, service_worker_started_event.get()); + + // Wait until after the old WebModule is destroyed before setting the navigate + // time so that it won't be included in the time taken to load the URL. + navigate_time_ = base::TimeTicks::Now().ToInternalValue(); + + const ViewportSize viewport_size = GetViewportSize(); + + // Show a splash screen while we're waiting for the web page to load. + NavigateSetupSplashScreen(url, viewport_size); + + NavigateSetupScrollEngine(); + + NavigateCreateWebModule(url, can_start_service_worker, + service_worker_started_event.get(), viewport_size); +} + +void BrowserModule::NavigateResetWebModule() { #if defined(ENABLE_DEBUGGER) if (web_module_) { web_module_->FreezeDebugger(&debugger_state_); } #endif // defined(ENABLE_DEBUGGER) - // Destroy old WebModule first, so we don't get a memory high-watermark after // the second WebModule's constructor runs, but before // std::unique_ptr::reset() is run. @@ -534,23 +552,56 @@ current_main_web_module_timeline_id_ = next_timeline_id_++; main_web_module_layer_->Reset(); +} +void BrowserModule::NavigateResetErrorHandling() { + on_error_retry_timer_.Stop(); + waiting_for_error_retry_ = false; +} + +bool BrowserModule::NavigateHandleStateFrozen(const GURL& url) { + if (application_state_ == base::kApplicationStateFrozen) { + pending_navigate_url_ = url; + return true; + } + + // Now that we know the navigation is occurring, clear out + // |pending_navigate_url_|. + pending_navigate_url_ = GURL::EmptyGURL(); + return false; +} + +bool BrowserModule::NavigateServiceWorkerSetups( + const GURL& url, base::WaitableEvent* service_worker_started_event) { // Service worker should only start for HTTP or HTTPS fetches. // https://fetch.spec.whatwg.org/commit-snapshots/8f8ab504da6ca9681db5c7f8aa3d1f4b6bf8840c/#http-fetch bool can_start_service_worker = url.SchemeIsHTTPOrHTTPS(); - auto service_worker_started_event = std::make_unique<base::WaitableEvent>(); + watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance(); + if (watchdog) { + std::vector<std::string> service_worker_clients = { + worker::WorkerConsts::kServiceWorkerRegistryName, + worker::WorkerConsts::kServiceWorkerName}; + std::string violation_json = + watchdog->GetWatchdogViolations(service_worker_clients); + { + if (violation_json != "") { + LOG(WARNING) << "Service Worker watchdog violation detected: " + << violation_json; + LOG(WARNING) << "Erase Service Worker registration map."; + can_start_service_worker = false; + service_worker_registry_->EraseRegistrationMap(); + } + } + } if (can_start_service_worker) { service_worker_registry_->EnsureServiceWorkerStarted( - url::Origin::Create(url), url, service_worker_started_event.get()); + url::Origin::Create(url), url, service_worker_started_event); } + return can_start_service_worker; +} - // Wait until after the old WebModule is destroyed before setting the navigate - // time so that it won't be included in the time taken to load the URL. - navigate_time_ = base::TimeTicks::Now().ToInternalValue(); - - // Show a splash screen while we're waiting for the web page to load. - const ViewportSize viewport_size = GetViewportSize(); - +void BrowserModule::NavigateSetupSplashScreen( + const GURL& url, const ViewportSize viewport_size) { DestroySplashScreen(); if (options_.enable_splash_screen_on_reloads || main_web_module_generation_ == 1) { @@ -571,10 +622,17 @@ lifecycle_observers_.AddObserver(splash_screen_.get()); } } +} +void BrowserModule::NavigateSetupScrollEngine() { scroll_engine_.reset(new ui_navigation::scroll_engine::ScrollEngine()); scroll_engine_->thread()->Start(); +} +void BrowserModule::NavigateCreateWebModule( + const GURL& url, bool can_start_service_worker, + base::WaitableEvent* service_worker_started_event, + const ViewportSize viewport_size) { // Create new WebModule. #if !defined(COBALT_FORCE_CSP) options_.web_module_options.csp_insecure_allowed_token = @@ -1345,7 +1403,7 @@ } } -bool BrowserModule::TryURLHandlers(const GURL& url) { +bool BrowserModule::NavigateTryURLHandlers(const GURL& url) { for (URLHandlerCollection::const_iterator iter = url_handlers_.begin(); iter != url_handlers_.end(); ++iter) { if (iter->Run(url)) {
diff --git a/cobalt/browser/browser_module.h b/cobalt/browser/browser_module.h index 00fd5ce..2011577 100644 --- a/cobalt/browser/browser_module.h +++ b/cobalt/browser/browser_module.h
@@ -139,6 +139,7 @@ // |pending_navigate_url_| to the specified url, which will trigger a // navigation when Cobalt resumes. void Navigate(const GURL& url_reference); + // Reloads web module. void Reload(); @@ -334,9 +335,28 @@ bool FilterKeyEventForHotkeys(base::Token type, const dom::KeyboardEventInit& event); + void NavigateResetErrorHandling(); + + bool NavigateHandleStateFrozen(const GURL& url); + + void NavigateResetWebModule(); + + bool NavigateServiceWorkerSetups( + const GURL& url, base::WaitableEvent* service_worker_started_event); + + void NavigateSetupSplashScreen(const GURL& url, + const cssom::ViewportSize viewport_size); + + void NavigateSetupScrollEngine(); + + void NavigateCreateWebModule( + const GURL& url, bool can_start_service_worker, + base::WaitableEvent* service_worker_started_event, + const cssom::ViewportSize viewport_size); + // Tries all registered URL handlers for a URL. Returns true if one of the // handlers handled the URL, false if otherwise. - bool TryURLHandlers(const GURL& url); + bool NavigateTryURLHandlers(const GURL& url); // Destroys the splash screen, if currently displayed. void DestroySplashScreen(base::TimeDelta close_time = base::TimeDelta());
diff --git a/cobalt/browser/main.cc b/cobalt/browser/main.cc index 7d0d0a0..ff13b37 100644 --- a/cobalt/browser/main.cc +++ b/cobalt/browser/main.cc
@@ -18,6 +18,7 @@ #include "cobalt/base/wrap_main.h" #include "cobalt/browser/application.h" #include "cobalt/browser/switches.h" +#include "cobalt/css_parser/switches.h" #include "cobalt/version.h" namespace { @@ -41,6 +42,7 @@ cobalt::browser::switches::kHelp)) { SbLogRaw("Options: \n"); SbLogRaw(cobalt::browser::switches::HelpMessage().c_str()); + SbLogRaw(cobalt::css_parser::switches::HelpMessage().c_str()); return true; } return false;
diff --git a/cobalt/browser/metrics/BUILD.gn b/cobalt/browser/metrics/BUILD.gn index 3f25f1a..62c85fa 100644 --- a/cobalt/browser/metrics/BUILD.gn +++ b/cobalt/browser/metrics/BUILD.gn
@@ -51,6 +51,7 @@ deps = [ ":metrics", "//base", + "//cobalt//browser:test_dependencies_on_browser", "//cobalt/browser:generated_types", "//cobalt/h5vcc", "//cobalt/h5vcc:metric_event_handler_wrapper",
diff --git a/cobalt/browser/service_worker_registry.cc b/cobalt/browser/service_worker_registry.cc index bbfdf0f..89b9395 100644 --- a/cobalt/browser/service_worker_registry.cc +++ b/cobalt/browser/service_worker_registry.cc
@@ -31,8 +31,6 @@ // Signals the given WaitableEvent. void SignalWaitableEvent(base::WaitableEvent* event) { event->Signal(); } -// The watchdog client name used to represent service worker registry thread. -const char kWatchdogName[] = "service worker registry"; // The watchdog time interval in microseconds allowed between pings before // triggering violations. const int64_t kWatchdogTimeInterval = 15000000; @@ -61,7 +59,8 @@ // Registers service worker thread as a watchdog client. if (watchdog) { watchdog_registered_ = true; - watchdog->Register(kWatchdogName, kWatchdogName, + watchdog->Register(worker::WorkerConsts::kServiceWorkerRegistryName, + worker::WorkerConsts::kServiceWorkerRegistryName, base::kApplicationStateStarted, kWatchdogTimeInterval, kWatchdogTimeWait, watchdog::PING); message_loop()->task_runner()->PostDelayedTask( @@ -101,7 +100,7 @@ watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance(); if (watchdog) { watchdog_registered_ = false; - watchdog->Unregister(kWatchdogName); + watchdog->Unregister(worker::WorkerConsts::kServiceWorkerRegistryName); } // Ensure that the destruction observer got added before stopping the thread. @@ -120,7 +119,7 @@ // If watchdog is already unregistered or shut down, stop ping watchdog. if (!watchdog_registered_ || !watchdog) return; - watchdog->Ping(kWatchdogName); + watchdog->Ping(worker::WorkerConsts::kServiceWorkerRegistryName); message_loop()->task_runner()->PostDelayedTask( FROM_HERE, base::Bind(&ServiceWorkerRegistry::PingWatchdog, base::Unretained(this)), @@ -134,6 +133,10 @@ done_event); } +void ServiceWorkerRegistry::EraseRegistrationMap() { + service_worker_context()->EraseRegistrationMap(); +} + worker::ServiceWorkerContext* ServiceWorkerRegistry::service_worker_context() { // Ensure that the thread had a chance to allocate the object. destruction_observer_added_.Wait();
diff --git a/cobalt/browser/service_worker_registry.h b/cobalt/browser/service_worker_registry.h index 4880d6a..f0e934e 100644 --- a/cobalt/browser/service_worker_registry.h +++ b/cobalt/browser/service_worker_registry.h
@@ -49,6 +49,8 @@ const GURL& client_url, base::WaitableEvent* done_event); + void EraseRegistrationMap(); + worker::ServiceWorkerContext* service_worker_context(); private:
diff --git a/cobalt/build/build_info.py b/cobalt/build/build_info.py index aed2646..52f4494 100755 --- a/cobalt/build/build_info.py +++ b/cobalt/build/build_info.py
@@ -57,7 +57,7 @@ output = subprocess.check_output(['git', 'rev-list', '--count', 'HEAD'], cwd=cwd) build_id = int(output.strip().decode()) + COMMIT_COUNT_BUILD_ID_OFFSET - return build_id + return str(build_id) def _get_last_commit_with_format(placeholder, cwd):
diff --git a/cobalt/build/get_build_id_test.py b/cobalt/build/get_build_id_test.py index 562179f..26e7b2b 100644 --- a/cobalt/build/get_build_id_test.py +++ b/cobalt/build/get_build_id_test.py
@@ -87,8 +87,9 @@ self.make_commit() build_number = build_info.get_build_id_from_commit_count( cwd=self.test_dir.name) - self.assertEqual(build_number, - num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET) + self.assertEqual( + int(build_number), + num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET) def testCommitsOutrankCommitCount(self): self.make_commit() @@ -102,8 +103,9 @@ for _ in range(num_commits): self.make_commit() build_number = get_build_id.main(cwd=self.test_dir.name) - self.assertEqual(build_number, - num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET) + self.assertEqual( + int(build_number), + num_commits + build_info.COMMIT_COUNT_BUILD_ID_OFFSET) if __name__ == '__main__':
diff --git a/cobalt/build/gn.py b/cobalt/build/gn.py index 7ff3bc4..e8c4472 100755 --- a/cobalt/build/gn.py +++ b/cobalt/build/gn.py
@@ -68,7 +68,7 @@ parser.add_argument( '-p', '--platform', - required=True, + default='linux-x64x11', choices=list(PLATFORMS), help='The platform to build.') parser.add_argument(
diff --git a/cobalt/css_parser/BUILD.gn b/cobalt/css_parser/BUILD.gn index d6a668c..8cbc194 100644 --- a/cobalt/css_parser/BUILD.gn +++ b/cobalt/css_parser/BUILD.gn
@@ -76,6 +76,8 @@ "shadow_property_parse_structures.cc", "shadow_property_parse_structures.h", "string_pool.h", + "switches.cc", + "switches.h", "text_decoration_shorthand_property_parse_structures.cc", "text_decoration_shorthand_property_parse_structures.h", "transition_shorthand_property_parse_structures.cc", @@ -92,6 +94,7 @@ deps = [ ":css_grammar", + "//base", "//cobalt/base", "//cobalt/cssom", "//nb", @@ -119,7 +122,9 @@ ":css_grammar", ":css_parser", "//base", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/cssom", + "//cobalt/dom", "//cobalt/test:run_all_unittests", "//testing/gmock", "//testing/gtest",
diff --git a/cobalt/css_parser/parser.cc b/cobalt/css_parser/parser.cc index ccc9b42..aaaf474 100644 --- a/cobalt/css_parser/parser.cc +++ b/cobalt/css_parser/parser.cc
@@ -23,6 +23,7 @@ #include <string> #include "base/bind.h" +#include "base/command_line.h" #include "base/containers/hash_tables.h" #include "base/lazy_instance.h" #include "base/optional.h" @@ -39,6 +40,7 @@ #include "cobalt/css_parser/ref_counted_util.h" #include "cobalt/css_parser/scanner.h" #include "cobalt/css_parser/string_pool.h" +#include "cobalt/css_parser/switches.h" #include "cobalt/css_parser/trivial_string_piece.h" #include "cobalt/css_parser/trivial_type_pairs.h" #include "cobalt/cssom/active_pseudo_class.h" @@ -539,11 +541,19 @@ void LogWarningCallback(const ::base::DebuggerHooks* debugger_hooks, const std::string& message) { CLOG(WARNING, *debugger_hooks) << message; + ::base::CommandLine* command_line = ::base::CommandLine::ForCurrentProcess(); + if (command_line->GetSwitchValueASCII(switches::kOnCssWarning) == "crash") { + IMMEDIATE_CRASH() << message; + } } void LogErrorCallback(const ::base::DebuggerHooks* debugger_hooks, const std::string& message) { CLOG(ERROR, *debugger_hooks) << message; + ::base::CommandLine* command_line = ::base::CommandLine::ForCurrentProcess(); + if (command_line->GetSwitchValueASCII(switches::kOnCssError) == "crash") { + IMMEDIATE_CRASH() << message; + } } } // namespace
diff --git a/cobalt/css_parser/switches.cc b/cobalt/css_parser/switches.cc new file mode 100644 index 0000000..bb4e085 --- /dev/null +++ b/cobalt/css_parser/switches.cc
@@ -0,0 +1,50 @@ +// Copyright 2023 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/css_parser/switches.h" + +#include <map> + +namespace cobalt { +namespace css_parser { +namespace switches { + +const char kOnCssError[] = "on_css_error"; +const char kOnCssErrorHelp[] = + "If set to \"crash\", crashes on CSS error even when recoverable."; + +const char kOnCssWarning[] = "on_css_warning"; +const char kOnCssWarningHelp[] = "If set to \"crash\", crashes on CSS warning."; + +std::string HelpMessage() { + std::string help_message; + std::map<std::string, const char*> help_map{ + {kOnCssError, kOnCssErrorHelp}, + {kOnCssWarning, kOnCssWarningHelp}, + }; + + for (const auto& switch_message : help_map) { + help_message.append(" --") + .append(switch_message.first) + .append("\n") + .append(" ") + .append(switch_message.second) + .append("\n\n"); + } + return help_message; +} + +} // namespace switches +} // namespace css_parser +} // namespace cobalt
diff --git a/cobalt/css_parser/switches.h b/cobalt/css_parser/switches.h new file mode 100644 index 0000000..cd3943f --- /dev/null +++ b/cobalt/css_parser/switches.h
@@ -0,0 +1,35 @@ +// Copyright 2023 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. + +#ifndef COBALT_CSS_PARSER_SWITCHES_H_ +#define COBALT_CSS_PARSER_SWITCHES_H_ + +#include <string> + +namespace cobalt { +namespace css_parser { +namespace switches { + +extern const char kOnCssError[]; +extern const char kOnCssErrorHelp[]; +extern const char kOnCssWarning[]; +extern const char kOnCssWarningHelp[]; + +std::string HelpMessage(); + +} // namespace switches +} // namespace css_parser +} // namespace cobalt + +#endif // COBALT_CSS_PARSER_SWITCHES_H_
diff --git a/cobalt/cssom/BUILD.gn b/cobalt/cssom/BUILD.gn index b313c59..04dae86 100644 --- a/cobalt/cssom/BUILD.gn +++ b/cobalt/cssom/BUILD.gn
@@ -319,8 +319,10 @@ deps = [ "//cobalt/base", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/css_parser", "//cobalt/cssom", + "//cobalt/dom", "//cobalt/math", "//cobalt/test:run_all_unittests", "//testing/gmock",
diff --git a/cobalt/h5vcc/BUILD.gn b/cobalt/h5vcc/BUILD.gn index f081ce4..901f668 100644 --- a/cobalt/h5vcc/BUILD.gn +++ b/cobalt/h5vcc/BUILD.gn
@@ -28,12 +28,6 @@ has_pedantic_warnings = true sources = [ - "dial/dial_http_request.cc", - "dial/dial_http_request.h", - "dial/dial_http_response.cc", - "dial/dial_http_response.h", - "dial/dial_server.cc", - "dial/dial_server.h", "h5vcc.cc", "h5vcc.h", "h5vcc_accessibility.cc", @@ -91,10 +85,23 @@ "//cobalt/web:dom_exception", "//cobalt/worker", "//net", - "//net:http_server", "//starboard", "//third_party/protobuf:protobuf_lite", ] + if (enable_in_app_dial) { + sources += [ + "dial/dial_http_request.cc", + "dial/dial_http_request.h", + "dial/dial_http_response.cc", + "dial/dial_http_response.h", + "dial/dial_server.cc", + "dial/dial_server.h", + ] + deps += [ + "//net:cobalt_dial_server", + "//net:http_server", + ] + } if (enable_account_manager) { sources += [
diff --git a/cobalt/h5vcc/h5vcc_crash_log.cc b/cobalt/h5vcc/h5vcc_crash_log.cc index b3e76e7..39c545c 100644 --- a/cobalt/h5vcc/h5vcc_crash_log.cc +++ b/cobalt/h5vcc/h5vcc_crash_log.cc
@@ -191,6 +191,19 @@ return ""; } +script::Sequence<std::string> H5vccCrashLog::GetWatchdogViolationClients() { + watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance(); + script::Sequence<std::string> client_names; + if (watchdog) { + std::vector<std::string> client_string_names = + watchdog->GetWatchdogViolationClientNames(); + for (std::size_t i = 0; i < client_string_names.size(); ++i) { + client_names.push_back(client_string_names[i]); + } + } + return client_names; +} + bool H5vccCrashLog::GetPersistentSettingWatchdogEnable() { watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance(); if (watchdog) return watchdog->GetPersistentSettingWatchdogEnable();
diff --git a/cobalt/h5vcc/h5vcc_crash_log.h b/cobalt/h5vcc/h5vcc_crash_log.h index ea06c88..e01d23e 100644 --- a/cobalt/h5vcc/h5vcc_crash_log.h +++ b/cobalt/h5vcc/h5vcc_crash_log.h
@@ -81,6 +81,8 @@ std::string GetWatchdogViolations( const script::Sequence<std::string>& clients = {}); + script::Sequence<std::string> GetWatchdogViolationClients(); + bool GetPersistentSettingWatchdogEnable(); void SetPersistentSettingWatchdogEnable(bool enable_watchdog);
diff --git a/cobalt/h5vcc/h5vcc_crash_log.idl b/cobalt/h5vcc/h5vcc_crash_log.idl index 8d4a3ba..e60e0ab 100644 --- a/cobalt/h5vcc/h5vcc_crash_log.idl +++ b/cobalt/h5vcc/h5vcc_crash_log.idl
@@ -86,6 +86,9 @@ // } DOMString getWatchdogViolations(optional sequence<DOMString> clients); + // Returns a sequence of the client names that have watchdog violations. + sequence<DOMString> getWatchdogViolationClients(); + // Gets a persistent Watchdog setting that determines whether or not Watchdog // is enabled. When disabled, Watchdog behaves like a stub except that // persistent settings can still be get/set. Requires a restart to take
diff --git a/cobalt/h5vcc/h5vcc_storage.cc b/cobalt/h5vcc/h5vcc_storage.cc index f059e8e..dac5b5c 100644 --- a/cobalt/h5vcc/h5vcc_storage.cc +++ b/cobalt/h5vcc/h5vcc_storage.cc
@@ -25,7 +25,7 @@ #include "cobalt/cache/cache.h" #include "cobalt/persistent_storage/persistent_settings.h" #include "cobalt/storage/storage_manager.h" -#include "cobalt/worker/service_worker_consts.h" +#include "cobalt/worker/worker_consts.h" #include "net/base/completion_once_callback.h" #include "net/disk_cache/cobalt/cobalt_backend_impl.h" #include "net/disk_cache/cobalt/resource_type.h" @@ -419,7 +419,7 @@ kSbFileMaxPath); base::FilePath service_worker_file_path = base::FilePath(storage_dir.data()) - .Append(worker::ServiceWorkerConsts::kSettingsJson); + .Append(worker::WorkerConsts::kSettingsJson); base::DeleteFile(service_worker_file_path, /*recursive=*/false); }
diff --git a/cobalt/layout/BUILD.gn b/cobalt/layout/BUILD.gn index 7966365..36c0181 100644 --- a/cobalt/layout/BUILD.gn +++ b/cobalt/layout/BUILD.gn
@@ -140,6 +140,7 @@ deps = [ ":layout", "//base", + "//cobalt//browser:test_dependencies_on_browser", "//cobalt/base", "//cobalt/css_parser", "//cobalt/cssom",
diff --git a/cobalt/loader/BUILD.gn b/cobalt/loader/BUILD.gn index 2db902d..9b808f9 100644 --- a/cobalt/loader/BUILD.gn +++ b/cobalt/loader/BUILD.gn
@@ -195,6 +195,7 @@ deps = [ ":loader", "//cobalt/base:base", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/dom", "//cobalt/dom_parser", "//cobalt/math:math",
diff --git a/cobalt/loader/image/sandbox/BUILD.gn b/cobalt/loader/image/sandbox/BUILD.gn index adf6ab1..dbfc6a2 100644 --- a/cobalt/loader/image/sandbox/BUILD.gn +++ b/cobalt/loader/image/sandbox/BUILD.gn
@@ -18,10 +18,12 @@ # This target will build a sandbox application that allows for easy # experimentation with the ImageDecoder on any platform. target(final_executable_type, "image_decoder_sandbox") { + testonly = true sources = [ "image_decoder_sandbox.cc" ] deps = [ "//cobalt/base", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/loader", "//cobalt/loader:copy_loader_test_data", "//cobalt/math",
diff --git a/cobalt/media/BUILD.gn b/cobalt/media/BUILD.gn index 813baa2..0e7c06d 100644 --- a/cobalt/media/BUILD.gn +++ b/cobalt/media/BUILD.gn
@@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//starboard/build/config/os_definitions.gni") + config("media_config") { if (!is_win) { cflags_cc = [ @@ -129,6 +131,7 @@ deps = [ ":media", "//base/test:test_support", + "//cobalt//browser:test_dependencies_on_browser", "//cobalt/base", "//cobalt/test:run_all_unittests", "//testing/gmock", @@ -137,4 +140,9 @@ ] data_deps = [ "//cobalt/media/testing:cobalt_media_download_test_data" ] + + # TODO: b/296715826 - Fix symbol resolution in cval_stats_test.cc. + if (sb_is_modular && is_host_win) { + sources -= [ "base/cval_stats_test.cc" ] + } }
diff --git a/cobalt/media/sandbox/BUILD.gn b/cobalt/media/sandbox/BUILD.gn index 19be835..84d2620 100644 --- a/cobalt/media/sandbox/BUILD.gn +++ b/cobalt/media/sandbox/BUILD.gn
@@ -16,9 +16,11 @@ # media/renderer interface. target(final_executable_type, "media_sandbox") { + testonly = true sources = [ "media2_sandbox.cc" ] deps = [ + "//cobalt//browser:test_dependencies_on_browser", "//cobalt/base", "//cobalt/math", "//cobalt/media", @@ -28,6 +30,7 @@ } target(final_executable_type, "web_media_player_sandbox") { + testonly = true sources = [ "format_guesstimator.cc", "format_guesstimator.h", @@ -42,6 +45,7 @@ "//cobalt/base", # Use test data from demos to avoid keeping two copies of video files. + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/demos/content:demos_testdata", "//cobalt/loader", "//cobalt/math",
diff --git a/cobalt/network/BUILD.gn b/cobalt/network/BUILD.gn index 1a4fd75..73e33ca 100644 --- a/cobalt/network/BUILD.gn +++ b/cobalt/network/BUILD.gn
@@ -63,10 +63,7 @@ } if (enable_in_app_dial) { - deps += [ - # DialService depends on http server. - "//net:http_server", - ] + deps += [ "//net:cobalt_dial_server" ] } # Enable network logging on all but gold builds.
diff --git a/cobalt/renderer/BUILD.gn b/cobalt/renderer/BUILD.gn index 2b4ac9d..54d2187 100644 --- a/cobalt/renderer/BUILD.gn +++ b/cobalt/renderer/BUILD.gn
@@ -128,6 +128,7 @@ ":renderer", ":renderer_headers_only", "//base:i18n", + "//cobalt//browser:test_dependencies_on_browser", "//cobalt/base", "//cobalt/loader", "//cobalt/math",
diff --git a/cobalt/renderer/sandbox/BUILD.gn b/cobalt/renderer/sandbox/BUILD.gn index 30d7def..bf1b00b 100644 --- a/cobalt/renderer/sandbox/BUILD.gn +++ b/cobalt/renderer/sandbox/BUILD.gn
@@ -20,10 +20,12 @@ # also be useful for visually inspecting the output that the Cobalt # renderer is producing. target(final_executable_type, "renderer_sandbox") { + testonly = true sources = [ "renderer_sandbox_main.cc" ] deps = [ "//cobalt/base", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/math", "//cobalt/renderer", "//cobalt/renderer/test/scenes", @@ -39,10 +41,12 @@ # is constantly animating, which for many implementations can be a # performance problem. target(final_executable_type, "scaling_text_sandbox") { + testonly = true sources = [ "scaling_text_sandbox_main.cc" ] deps = [ "//cobalt/base", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/math", "//cobalt/renderer", "//cobalt/renderer/test/scenes",
diff --git a/cobalt/script/v8c/v8c_exception_state.cc b/cobalt/script/v8c/v8c_exception_state.cc index ee9fbe0..ee47099 100644 --- a/cobalt/script/v8c/v8c_exception_state.cc +++ b/cobalt/script/v8c/v8c_exception_state.cc
@@ -70,6 +70,7 @@ V8cGlobalEnvironment* global_environment = V8cGlobalEnvironment::GetFromIsolate(isolate_); + if (!global_environment) return; v8::Local<v8::Object> wrapper = global_environment->wrapper_factory()->GetWrapper(exception);
diff --git a/cobalt/script/v8c/v8c_global_environment.cc b/cobalt/script/v8c/v8c_global_environment.cc index 9ec5c07..04e94d1 100644 --- a/cobalt/script/v8c/v8c_global_environment.cc +++ b/cobalt/script/v8c/v8c_global_environment.cc
@@ -378,7 +378,7 @@ V8cGlobalEnvironment* global_environment = V8cGlobalEnvironment::GetFromIsolate(context->GetIsolate()); DCHECK(global_environment); - if (!global_environment->report_eval_.is_null()) { + if (global_environment && !global_environment->report_eval_.is_null()) { global_environment->report_eval_.Run(); } // This callback should only be called while code generation from strings is @@ -396,7 +396,8 @@ v8::Isolate* isolate = v8::Isolate::GetCurrent(); V8cGlobalEnvironment* global_environment = V8cGlobalEnvironment::GetFromIsolate(isolate); - if (isolate->GetEnteredOrMicrotaskContext().IsEmpty()) { + if (!global_environment || + isolate->GetEnteredOrMicrotaskContext().IsEmpty()) { return; } if (message->ErrorLevel() != v8::Isolate::kMessageError) {
diff --git a/cobalt/site/docs/development/setup-android.md b/cobalt/site/docs/development/setup-android.md index 2a5f0b1..82e26aa 100644 --- a/cobalt/site/docs/development/setup-android.md +++ b/cobalt/site/docs/development/setup-android.md
@@ -26,12 +26,16 @@ Where 4 is the number of parallel threads. You can adjust the number of parallel threads according to how your workstation performs. -1. Run `cobalt/build/gn.py -p android-x86` to configure the Cobalt build, - which also installs the SDK and NDK. (This step will have to be repeated - with 'android-arm' or 'android-arm64' to target those architectures.) The - SDK and NDK will be downloaded and installed into a `starboard-toolchains` - directory as needed. If prompted, read and accept the license agreement to - proceed forward. +1. Run `starboard/android/shared/download_sdk.sh` to download the SDK and NDK. + The SDK and NDK will be downloaded and installed into + `~/starboard-toolchains`. If you wish to customize the download location + you must set the relevant environment variables accordingly. + + If prompted, read and accept the license agreement. + +1. Run `cobalt/build/gn.py -p android-x86` to configure the Cobalt build. + (This step will have to be repeated with 'android-arm' or 'android-arm64' + to target those architectures.) **Note:** If you have trouble building with an error referencing the `debug.keystore` you may need to set one up on your system:
diff --git a/cobalt/site/docs/development/setup-windows.md b/cobalt/site/docs/development/setup-windows.md index 65b9496..47a98cc 100644 --- a/cobalt/site/docs/development/setup-windows.md +++ b/cobalt/site/docs/development/setup-windows.md
@@ -27,10 +27,10 @@ <aside class="note"> <b>Note:</b> By default, Cobalt's build system will check - C:\Program Files (x86)\ for the Visual Studio install directory. If you - installed it elsewhere, you can set the `VSINSTALLDIR` environment + <code>C:\Program Files (x86)\</code> for the Visual Studio install directory. If you + installed it elsewhere, you can set the <code>VSINSTALLDIR</code> environment variable to point to the correct location. For example - `C:/Program Files/Microsoft Visual Studio/2022/Professional` + <code>C:/Program Files/Microsoft Visual Studio/2022/Professional</code> </aside> 1. Install GN, which we use for our build system code. There are a few ways to @@ -63,12 +63,12 @@ ``` <aside class="note"> - If you plan to contribute to the Cobalt codebase it is recommended that - you create your own - [fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks) - of the [Cobalt repository](https://github.com/youtube/cobalt), apply - changes to the fork, and then - [create a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) + <b>Note:</b> If you plan to contribute to the Cobalt codebase it is + recommended that you create your own + <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks">fork</a> + of the <a href="https://github.com/youtube/cobalt">Cobalt repository</a>, + apply changes to the fork, and then + <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork">create a pull request</a> to merge those changes into the Cobalt repository. </aside> @@ -141,7 +141,8 @@ configuration](/starboard/porting.html#1-enumerate-and-name-your-platform-configurations) that identifies the platform. As described in the Starboard porting guide, it contains a `family name` (like `linux`) and a - `binary variant` (like `x64x11`), separated by a hyphen. + `binary variant` (like `x64x11`), separated by a hyphen. For Windows + builds use win-win32. 1. `<build_type>` is the build you are compiling. Possible values are `debug`, `devel`, `qa`, and `gold`. 1. `<target_name>` is the name assigned to the compiled code and it is @@ -222,10 +223,10 @@ but they should work for local testing. <aside class="note"> - <b>Note:</b> if you change the value of `PUBLISHER` in - `appx_product_settings.py` you <b>must</b> regenerate a pfx file in order for - the packaging step below to work correctly. Follow the instructions in - `starboard/xb1/cert/README.md` to generate your own pfx. + <b>Note:</b> if you change the value of <code>PUBLISHER</code> in + <code>appx_product_settings.py</code> you <b>must</b> regenerate a pfx file in + order for the packaging step below to work correctly. Follow the instructions + in <code>starboard/xb1/cert/README.md</code> to generate your own pfx. </aside> ### Build Cobalt
diff --git a/cobalt/storage/BUILD.gn b/cobalt/storage/BUILD.gn index 9c575bd..0bab5d9 100644 --- a/cobalt/storage/BUILD.gn +++ b/cobalt/storage/BUILD.gn
@@ -55,7 +55,6 @@ ":storage", "//cobalt/base", "//cobalt/test:run_all_unittests", - "//net", "//testing/gmock", "//testing/gtest", "//url",
diff --git a/cobalt/ui_navigation/scroll_engine/BUILD.gn b/cobalt/ui_navigation/scroll_engine/BUILD.gn index 980b3fd..25dc91b 100644 --- a/cobalt/ui_navigation/scroll_engine/BUILD.gn +++ b/cobalt/ui_navigation/scroll_engine/BUILD.gn
@@ -34,6 +34,7 @@ sources = [ "free_scrolling_nav_item_test.cc" ] deps = [ ":scroll_engine", + "//cobalt//browser:test_dependencies_on_browser", "//cobalt/base", "//cobalt/test:run_all_unittests", "//testing/gmock",
diff --git a/cobalt/version.h b/cobalt/version.h index 9d152df..517e7d5 100644 --- a/cobalt/version.h +++ b/cobalt/version.h
@@ -35,6 +35,6 @@ // release is cut. //. -#define COBALT_VERSION "24.lts.4" +#define COBALT_VERSION "24.lts.5" #endif // COBALT_VERSION_H_
diff --git a/cobalt/watchdog/watchdog.cc b/cobalt/watchdog/watchdog.cc index 5e2a599..1e43688 100644 --- a/cobalt/watchdog/watchdog.cc +++ b/cobalt/watchdog/watchdog.cc
@@ -109,6 +109,7 @@ // Starts monitor thread. is_monitoring_.store(true); + InitializeViolationsMap(this); SB_DCHECK(!SbThreadIsValid(watchdog_thread_)); watchdog_thread_ = SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity, true, "Watchdog", &Watchdog::Monitor, this); @@ -146,10 +147,17 @@ return watchdog_file_path_; } -std::vector<std::string> Watchdog::GetWatchdogClientNames() { +std::vector<std::string> Watchdog::GetWatchdogViolationClientNames() { + if (pending_write_) WriteWatchdogViolations(); + + std::string watchdog_json = ReadViolationFile(GetWatchdogFilePath().c_str()); std::vector<std::string> names; - for (auto& it : client_map_) { - names.push_back(it.first); + if (watchdog_json != "") { + std::unique_ptr<base::Value> violations_map = + base::JSONReader::Read(watchdog_json); + for (const auto& it : violations_map->DictItems()) { + names.push_back(it.first); + } } return names; } @@ -228,8 +236,6 @@ void Watchdog::UpdateViolationsMap(void* context, Client* client, SbTimeMonotonic time_delta) { // Gets violation dictionary with key client name from violations_map_. - if (static_cast<Watchdog*>(context)->violations_map_ == nullptr) - InitializeViolationsMap(context); base::Value* violation_dict = (static_cast<Watchdog*>(context)->violations_map_)->FindKey(client->name); @@ -317,19 +323,26 @@ static_cast<Watchdog*>(context)->pending_write_ = true; } +std::string Watchdog::ReadViolationFile(const char* file_path) { + starboard::ScopedFile read_file(file_path, kSbFileOpenOnly | kSbFileRead); + if (read_file.IsValid()) { + int64_t kFileSize = read_file.GetSize(); + std::vector<char> buffer(kFileSize + 1, 0); + read_file.ReadAll(buffer.data(), kFileSize); + return std::string(buffer.data()); + } + return ""; +} + void Watchdog::InitializeViolationsMap(void* context) { // Loads the previous Watchdog violations file containing violations before // app start, if it exists, to populate violations_map_. static_cast<Watchdog*>(context)->violations_count_ = 0; - starboard::ScopedFile read_file( - (static_cast<Watchdog*>(context)->GetWatchdogFilePath()).c_str(), - kSbFileOpenOnly | kSbFileRead); - if (read_file.IsValid()) { - int64_t kFileSize = read_file.GetSize(); - std::vector<char> buffer(kFileSize + 1, 0); - read_file.ReadAll(buffer.data(), kFileSize); - std::string watchdog_json = std::string(buffer.data()); + std::string watchdog_json = + static_cast<Watchdog*>(context)->ReadViolationFile( + (static_cast<Watchdog*>(context)->GetWatchdogFilePath()).c_str()); + if (watchdog_json != "") { static_cast<Watchdog*>(context)->violations_map_ = base::JSONReader::Read(watchdog_json); } @@ -538,48 +551,37 @@ if (pending_write_) WriteWatchdogViolations(); - starboard::ScopedFile file(GetWatchdogFilePath().c_str(), - kSbFileOpenOnly | kSbFileRead | kSbFileWrite); - if (file.IsValid()) { - int64_t kFileSize = file.GetSize(); - std::vector<char> buffer(kFileSize + 1, 0); - file.ReadAll(buffer.data(), kFileSize); - watchdog_json = std::string(buffer.data()); - - // If clients is empty we will fetch all clients. + if (!static_cast<base::DictionaryValue*>(violations_map_.get())->empty()) { + // Get all Watchdog violations if clients is given. if (clients.empty()) { + // Removes all Watchdog violations. + base::JSONWriter::Write(*violations_map_, &watchdog_json_fetched); if (clear) { - if (violations_map_) { - static_cast<base::DictionaryValue*>(violations_map_.get())->Clear(); - violations_count_ = 0; - } + static_cast<base::DictionaryValue*>(violations_map_.get())->Clear(); + violations_count_ = 0; starboard::SbFileDeleteRecursive(GetWatchdogFilePath().c_str(), true); } - watchdog_json_fetched = watchdog_json; } else { - std::string watchdog_json_not_read = ""; - std::unique_ptr<base::Value> violations_map = - base::JSONReader::Read(watchdog_json); base::Value filtered_client_data(base::Value::Type::DICTIONARY); for (int i = 0; i < clients.size(); i++) { - base::Value* violation_dict = violations_map->FindKey(clients[i]); + base::Value* violation_dict = + static_cast<base::DictionaryValue*>(violations_map_.get()) + ->FindKey(clients[i]); if (violation_dict != nullptr) { filtered_client_data.SetKey(clients[i], (*violation_dict).Clone()); if (clear) { base::Value* violations = violation_dict->FindKey("violations"); int violations_count = violations->GetList().size(); - violations_map->RemoveKey(clients[i]); - if (violations_map_) { - bool result = - static_cast<base::DictionaryValue*>(violations_map_.get()) - ->RemoveKey(clients[i]); - if (result) { - violations_count_ -= violations_count; - } - if (violations_count_ == 0) { - static_cast<base::DictionaryValue*>(violations_map_.get()) - ->Clear(); - } + + static_cast<base::DictionaryValue*>(violations_map_.get()) + ->RemoveKey(clients[i]); + violations_count_ -= violations_count; + if (!static_cast<base::DictionaryValue*>(violations_map_.get()) + ->empty()) { + WriteWatchdogViolations(); + } else { + starboard::SbFileDeleteRecursive(GetWatchdogFilePath().c_str(), + true); } } } @@ -587,19 +589,6 @@ if (!filtered_client_data.DictEmpty()) { base::JSONWriter::Write(filtered_client_data, &watchdog_json_fetched); } - if (clear) { - // If all data is fetched, delete the violation file. - if (violations_map->DictEmpty()) { - starboard::SbFileDeleteRecursive(GetWatchdogFilePath().c_str(), true); - } else { - base::JSONWriter::Write(*violations_map, &watchdog_json_not_read); - file.Seek(kSbFileFromBegin, 0); - file.WriteAll(watchdog_json_not_read.c_str(), - static_cast<int>(watchdog_json_not_read.size())); - file.Truncate(static_cast<int>(watchdog_json_not_read.size())); - time_last_written_microseconds_ = SbTimeGetMonotonicNow(); - } - } } SB_LOG(INFO) << "[Watchdog] Reading violations:\n" << watchdog_json_fetched; } else {
diff --git a/cobalt/watchdog/watchdog.h b/cobalt/watchdog/watchdog.h index fde3b4b..8aa9a7c 100644 --- a/cobalt/watchdog/watchdog.h +++ b/cobalt/watchdog/watchdog.h
@@ -82,7 +82,7 @@ bool InitializeStub(); void Uninitialize(); std::string GetWatchdogFilePath(); - std::vector<std::string> GetWatchdogClientNames(); + std::vector<std::string> GetWatchdogViolationClientNames(); void UpdateState(base::ApplicationState state); bool Register(std::string name, std::string description, base::ApplicationState monitor_state, @@ -105,6 +105,7 @@ private: void WriteWatchdogViolations(); + std::string ReadViolationFile(const char* file_path); static void* Monitor(void* context); static void UpdateViolationsMap(void* context, Client* client, SbTimeMonotonic time_delta);
diff --git a/cobalt/watchdog/watchdog_test.cc b/cobalt/watchdog/watchdog_test.cc index 0681ce0..1cafc43 100644 --- a/cobalt/watchdog/watchdog_test.cc +++ b/cobalt/watchdog/watchdog_test.cc
@@ -325,7 +325,10 @@ starboard::ScopedFile file(watchdog_->GetWatchdogFilePath().c_str(), kSbFileCreateAlways | kSbFileWrite); file.WriteAll(json.c_str(), static_cast<int>(json.size())); - + TearDown(); + watchdog_ = new watchdog::Watchdog(); + watchdog_->InitializeCustom(nullptr, std::string(kWatchdogViolationsJson), + kWatchdogMonitorFrequency); ASSERT_TRUE(watchdog_->Register("test-name-3", "test-desc-3", base::kApplicationStateStarted, kWatchdogMonitorFrequency)); @@ -489,23 +492,26 @@ ASSERT_NE(write_json, json); } -TEST_F(WatchdogTest, GetRegisteredClientNames) { +TEST_F(WatchdogTest, GetViolationClientNames) { ASSERT_TRUE(watchdog_->Register("test-name-1", "test-desc-1", base::kApplicationStateStarted, kWatchdogMonitorFrequency)); ASSERT_TRUE(watchdog_->Register("test-name-2", "test-desc-2", base::kApplicationStateStarted, kWatchdogMonitorFrequency)); - std::vector<std::string> names = watchdog_->GetWatchdogClientNames(); + SbThreadSleep(kWatchdogSleepDuration); + ASSERT_TRUE(watchdog_->Unregister("test-name-1")); + ASSERT_TRUE(watchdog_->Unregister("test-name-2")); + std::vector<std::string> names = watchdog_->GetWatchdogViolationClientNames(); + ASSERT_EQ(names.size(), 2); std::set<std::string> expected_names = {"test-name-1", "test-name-2"}; for (std::vector<std::string>::const_iterator it = names.begin(); it != names.end(); ++it) { const std::string name = *it; ASSERT_TRUE((expected_names.find(name) != expected_names.end())); } - ASSERT_TRUE(watchdog_->Unregister("test-name-1")); - ASSERT_TRUE(watchdog_->Unregister("test-name-2")); - names = watchdog_->GetWatchdogClientNames(); + watchdog_->GetWatchdogViolations(); + names = watchdog_->GetWatchdogViolationClientNames(); ASSERT_EQ(names.size(), 0); }
diff --git a/cobalt/web/agent.cc b/cobalt/web/agent.cc index a2f8901..e9f51e4 100644 --- a/cobalt/web/agent.cc +++ b/cobalt/web/agent.cc
@@ -43,6 +43,7 @@ #include "cobalt/worker/service_worker_object.h" #include "cobalt/worker/service_worker_registration.h" #include "cobalt/worker/service_worker_registration_object.h" +#include "cobalt/worker/worker_consts.h" namespace cobalt { namespace web { @@ -547,7 +548,7 @@ } watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance(); - if (watchdog) { + if (watchdog && watchdog_registered_) { watchdog_registered_ = false; watchdog->Unregister(watchdog_name_); } @@ -577,12 +578,15 @@ if (!thread_.StartWithOptions(thread_options)) return; DCHECK(message_loop()); + // Registers service worker thread as a watchdog client. watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance(); - // Registers service worker thread as a watchdog client. if (watchdog) { - watchdog_name_ = - thread_.thread_name() + std::to_string(thread_.GetThreadId()); + watchdog_name_ = thread_.thread_name(); + if (watchdog_name_ == worker::WorkerConsts::kServiceWorkerName || + watchdog_name_ == worker::WorkerConsts::kDedicatedWorkerName) { + watchdog_name_ += std::to_string(thread_.GetThreadId()); + } watchdog_registered_ = true; watchdog->Register(watchdog_name_, watchdog_name_, base::kApplicationStateStarted, kWatchdogTimeInterval,
diff --git a/cobalt/web/cache.cc b/cobalt/web/cache.cc index a47a3c6..29e3372 100644 --- a/cobalt/web/cache.cc +++ b/cobalt/web/cache.cc
@@ -198,13 +198,13 @@ script::EnvironmentSettings* environment_settings, std::unique_ptr<script::ValueHandleHolder::Reference> request_reference, std::unique_ptr<script::ValuePromiseVoid::Reference> promise_reference) { + base::AutoLock auto_lock(fetcher_lock_); auto* global_environment = get_global_environment(environment_settings); auto* isolate = global_environment->isolate(); script::v8c::EntryScope entry_scope(isolate); uint32_t key = cache_utils::GetKey(environment_settings->base_url(), request_reference->referenced_value()); if (fetchers_.find(key) != fetchers_.end()) { - base::AutoLock auto_lock(*(fetchers_[key]->lock())); auto* promises = &(fetch_contexts_[key].first); promises->push_back(std::move(promise_reference)); return; @@ -402,6 +402,7 @@ } void Cache::OnFetchCompleted(uint32_t key, bool success) { + base::AutoLock auto_lock(fetcher_lock_); auto* environment_settings = fetch_contexts_[key].second; auto* context = get_context(environment_settings); context->message_loop()->task_runner()->PostTask( @@ -410,17 +411,15 @@ } void Cache::OnFetchCompletedMainThread(uint32_t key, bool success) { + base::AutoLock auto_lock(fetcher_lock_); auto* fetcher = fetchers_[key].get(); auto* promises = &(fetch_contexts_[key].first); int status = fetcher->response_code(); // |status| of 200-299 excluding 206 "Partial Content" should be cached. if (!success || status == 206 || status < 200 || status > 299) { - { - base::AutoLock auto_lock(*fetcher->lock()); - while (promises->size() > 0) { - promises->back()->value().Reject(); - promises->pop_back(); - } + while (promises->size() > 0) { + promises->back()->value().Reject(); + promises->pop_back(); } fetchers_.erase(key); fetch_contexts_.erase(key); @@ -447,12 +446,9 @@ global_environment->Compile(script::SourceCode::CreateSourceCode( fetcher->BufferToString(), base::SourceLocation(__FILE__, 1, 1))); } - { - base::AutoLock auto_lock(*fetcher->lock()); - while (promises->size() > 0) { - promises->back()->value().Resolve(); - promises->pop_back(); - } + while (promises->size() > 0) { + promises->back()->value().Resolve(); + promises->pop_back(); } fetchers_.erase(key); fetch_contexts_.erase(key);
diff --git a/cobalt/web/cache.h b/cobalt/web/cache.h index 02e5c88..88e0855 100644 --- a/cobalt/web/cache.h +++ b/cobalt/web/cache.h
@@ -75,7 +75,6 @@ int response_code() const { return response_code_; } const std::string& status_text() const { return status_text_; } base::ListValue headers() { return std::move(headers_); } - base::Lock* lock() const { return &lock_; } std::vector<uint8_t> BufferToVector() const; std::string BufferToString() const; @@ -95,7 +94,6 @@ int response_code_; base::ListValue headers_; std::string status_text_; - mutable base::Lock lock_; }; void PerformAdd( @@ -106,6 +104,7 @@ void OnFetchCompletedMainThread(uint32_t key, bool success); std::map<uint32_t, std::unique_ptr<Fetcher>> fetchers_; + mutable base::Lock fetcher_lock_; std::map<uint32_t, std::pair<std::vector<std::unique_ptr< script::ValuePromiseVoid::Reference>>, script::EnvironmentSettings*>>
diff --git a/cobalt/web_animations/BUILD.gn b/cobalt/web_animations/BUILD.gn index 81ee087..6d4f09f 100644 --- a/cobalt/web_animations/BUILD.gn +++ b/cobalt/web_animations/BUILD.gn
@@ -53,8 +53,10 @@ deps = [ ":web_animations", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/css_parser", "//cobalt/cssom", + "//cobalt/dom", "//cobalt/test:run_all_unittests", "//testing/gmock", "//testing/gtest",
diff --git a/cobalt/worker/BUILD.gn b/cobalt/worker/BUILD.gn index 23aeaa1..4b07e54 100644 --- a/cobalt/worker/BUILD.gn +++ b/cobalt/worker/BUILD.gn
@@ -36,8 +36,6 @@ "navigation_preload_manager.h", "service_worker.cc", "service_worker.h", - "service_worker_consts.cc", - "service_worker_consts.h", "service_worker_container.cc", "service_worker_container.h", "service_worker_context.cc", @@ -60,6 +58,7 @@ "window_client.h", "worker.cc", "worker.h", + "worker_consts.h", "worker_global_scope.cc", "worker_global_scope.h", "worker_location.h", @@ -105,6 +104,7 @@ "//cobalt/browser:browser", "//cobalt/browser:generated_bindings", "//cobalt/browser:generated_types", + "//cobalt/browser:test_dependencies_on_browser", "//cobalt/css_parser", "//cobalt/cssom", "//cobalt/dom/testing:dom_testing",
diff --git a/cobalt/worker/dedicated_worker.cc b/cobalt/worker/dedicated_worker.cc index 489a987..783cead 100644 --- a/cobalt/worker/dedicated_worker.cc +++ b/cobalt/worker/dedicated_worker.cc
@@ -28,10 +28,6 @@ namespace cobalt { namespace worker { -namespace { -const char kDedicatedWorkerName[] = "DedicatedWorker"; -} // namespace - DedicatedWorker::DedicatedWorker(script::EnvironmentSettings* settings, const std::string& scriptURL, script::ExceptionState* exception_state) @@ -111,7 +107,7 @@ options.construction_location.file_path = environment_settings()->creation_url().spec(); } - worker_.reset(new Worker(kDedicatedWorkerName, options)); + worker_.reset(new Worker(WorkerConsts::kDedicatedWorkerName, options)); // 10. Return worker. }
diff --git a/cobalt/worker/service_worker_consts.cc b/cobalt/worker/service_worker_consts.cc deleted file mode 100644 index 4254b85..0000000 --- a/cobalt/worker/service_worker_consts.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2023 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/worker/service_worker_consts.h" - -namespace cobalt { -namespace worker { -const char ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError[] = - "Service Worker Register failed: The script has an unsupported MIME type " - "('%s')."; - -const char ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError[] = - "Service Worker Register failed: The script does not have a MIME type."; - -const char - ServiceWorkerConsts::kServiceWorkerRegisterScriptOriginNotSameError[] = - "Service Worker Register failed: Script URL ('%s') and referrer ('%s') " - "origin are not the same."; - -const char - ServiceWorkerConsts::kServiceWorkerRegisterScopeOriginNotSameError[] = - "Service Worker Register failed: Scope URL ('%s') and referrer ('%s') " - "origin are not the same."; - -const char ServiceWorkerConsts::kServiceWorkerRegisterBadScopeError[] = - "Service Worker Register failed: Scope ('%s') is not allowed."; - -const char - ServiceWorkerConsts::kServiceWorkerUnregisterScopeOriginNotSameError[] = - "Service Worker Unregister failed: Scope origin does not match."; - -const char ServiceWorkerConsts::kServiceWorkerAllowed[] = - "Service-Worker-Allowed"; - -const char ServiceWorkerConsts::kSettingsJson[] = - "service_worker_settings.json"; - -const char* const ServiceWorkerConsts::kJavaScriptMimeTypes[16] = { - "application/ecmascript", - "application/javascript", - "application/x-ecmascript", - "application/x-javascript", - "text/ecmascript", - "text/javascript", - "text/javascript1.0", - "text/javascript1.1", - "text/javascript1.2", - "text/javascript1.3", - "text/javascript1.4", - "text/javascript1.5", - "text/jscript", - "text/livescript", - "text/x-ecmascript", - "text/x-javascript"}; -} // namespace worker -} // namespace cobalt
diff --git a/cobalt/worker/service_worker_consts.h b/cobalt/worker/service_worker_consts.h deleted file mode 100644 index 5bb8dd1..0000000 --- a/cobalt/worker/service_worker_consts.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2023 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. - -#ifndef COBALT_WORKER_SERVICE_WORKER_CONSTS_H_ -#define COBALT_WORKER_SERVICE_WORKER_CONSTS_H_ - -namespace cobalt { -namespace worker { - -struct ServiceWorkerConsts { - // Constants for error messages. - static const char kServiceWorkerRegisterBadMIMEError[]; - static const char kServiceWorkerRegisterNoMIMEError[]; - static const char kServiceWorkerRegisterScriptOriginNotSameError[]; - static const char kServiceWorkerRegisterScopeOriginNotSameError[]; - static const char kServiceWorkerRegisterBadScopeError[]; - static const char kServiceWorkerUnregisterScopeOriginNotSameError[]; - static const char kServiceWorkerAllowed[]; - - // Constants for ServiceWorkerPersistentSettings - static const char kSettingsJson[]; - - // Array of JavaScript mime types, according to the MIME Sniffinc spec: - // https://mimesniff.spec.whatwg.org/#javascript-mime-type - static const char* const kJavaScriptMimeTypes[16]; -}; - -} // namespace worker -} // namespace cobalt - -#endif // COBALT_WORKER_SERVICE_WORKER_CONSTS_H_
diff --git a/cobalt/worker/service_worker_context.cc b/cobalt/worker/service_worker_context.cc index 5c39206..b4b4bac 100644 --- a/cobalt/worker/service_worker_context.cc +++ b/cobalt/worker/service_worker_context.cc
@@ -376,6 +376,16 @@ service_worker_object->ObtainWebAgentAndWaitUntilDone(); } +void ServiceWorkerContext::EraseRegistrationMap() { + if (message_loop() != base::MessageLoop::current()) { + message_loop()->task_runner()->PostTask( + FROM_HERE, base::BindOnce(&ServiceWorkerContext::EraseRegistrationMap, + base::Unretained(this))); + return; + } + scope_to_registration_map_->DeletePersistentSettings(); +} + std::string* ServiceWorkerContext::RunServiceWorker(ServiceWorkerObject* worker, bool force_bypass_cache) { TRACE_EVENT0("cobalt::worker", "ServiceWorkerContext::RunServiceWorker()");
diff --git a/cobalt/worker/service_worker_context.h b/cobalt/worker/service_worker_context.h index 1446fe8..e51882d 100644 --- a/cobalt/worker/service_worker_context.h +++ b/cobalt/worker/service_worker_context.h
@@ -150,6 +150,8 @@ const GURL& client_url, base::WaitableEvent* done_event); + void EraseRegistrationMap(); + ServiceWorkerJobs* jobs() { return jobs_.get(); } ServiceWorkerRegistrationMap* registration_map() { return scope_to_registration_map_.get();
diff --git a/cobalt/worker/service_worker_jobs.cc b/cobalt/worker/service_worker_jobs.cc index 5c93575..fa0451b 100644 --- a/cobalt/worker/service_worker_jobs.cc +++ b/cobalt/worker/service_worker_jobs.cc
@@ -325,8 +325,7 @@ PromiseErrorData( web::DOMException::kSecurityErr, base::StringPrintf( - ServiceWorkerConsts:: - kServiceWorkerRegisterScriptOriginNotSameError, + WorkerConsts::kServiceWorkerRegisterScriptOriginNotSameError, job->script_url.spec().c_str(), job->referrer.spec().c_str()))); // 2.2. Invoke Finish Job with job and abort these steps. FinishJob(job); @@ -343,8 +342,7 @@ PromiseErrorData( web::DOMException::kSecurityErr, base::StringPrintf( - ServiceWorkerConsts:: - kServiceWorkerRegisterScopeOriginNotSameError, + WorkerConsts::kServiceWorkerRegisterScopeOriginNotSameError, job->scope_url.spec().c_str(), job->referrer.spec().c_str()))); // 3.2. Invoke Finish Job with job and abort these steps. @@ -491,12 +489,11 @@ if (content_type.empty()) { RejectJobPromise( state->job, - PromiseErrorData( - web::DOMException::kSecurityErr, - ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError)); + PromiseErrorData(web::DOMException::kSecurityErr, + WorkerConsts::kServiceWorkerRegisterNoMIMEError)); return true; } - for (auto mime_type : ServiceWorkerConsts::kJavaScriptMimeTypes) { + for (auto mime_type : WorkerConsts::kJavaScriptMimeTypes) { if (net::MatchesMimeType(mime_type, content_type)) { mime_type_is_javascript = true; break; @@ -511,16 +508,15 @@ state->job, PromiseErrorData( web::DOMException::kSecurityErr, - base::StringPrintf( - ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError, - content_type.c_str()))); + base::StringPrintf(WorkerConsts::kServiceWorkerRegisterBadMIMEError, + content_type.c_str()))); return true; } // 8.8. Let serviceWorkerAllowed be the result of extracting header list // values given `Service-Worker-Allowed` and response’s header list. std::string service_worker_allowed; bool service_worker_allowed_exists = headers->GetNormalizedHeader( - ServiceWorkerConsts::kServiceWorkerAllowed, &service_worker_allowed); + WorkerConsts::kServiceWorkerAllowed, &service_worker_allowed); // 8.9. Set policyContainer to the result of creating a policy container // from a fetch response given response. state->script_headers = headers; @@ -564,11 +560,10 @@ // 8.16.2. Asynchronously complete these steps with a network error. RejectJobPromise( state->job, - PromiseErrorData( - web::DOMException::kSecurityErr, - base::StringPrintf( - ServiceWorkerConsts::kServiceWorkerRegisterBadScopeError, - scope_string.c_str()))); + PromiseErrorData(web::DOMException::kSecurityErr, + base::StringPrintf( + WorkerConsts::kServiceWorkerRegisterBadScopeError, + scope_string.c_str()))); return true; } return true; @@ -722,7 +717,7 @@ // 11. Let worker be a new service worker. ServiceWorkerObject::Options options( - "ServiceWorker", state->job->client->web_settings(), + WorkerConsts::kServiceWorkerName, state->job->client->web_settings(), state->job->client->network_module(), state->registration); options.web_options.platform_info = state->job->client->platform_info(); options.web_options.service_worker_context = @@ -1014,9 +1009,9 @@ // 1.1. Invoke Reject Job Promise with job and "SecurityError" DOMException. RejectJobPromise( job, - PromiseErrorData(web::DOMException::kSecurityErr, - ServiceWorkerConsts:: - kServiceWorkerUnregisterScopeOriginNotSameError)); + PromiseErrorData( + web::DOMException::kSecurityErr, + WorkerConsts::kServiceWorkerUnregisterScopeOriginNotSameError)); // 1.2. Invoke Finish Job with job and abort these steps. FinishJob(job);
diff --git a/cobalt/worker/service_worker_persistent_settings.cc b/cobalt/worker/service_worker_persistent_settings.cc index f74d63f..fc81821 100644 --- a/cobalt/worker/service_worker_persistent_settings.cc +++ b/cobalt/worker/service_worker_persistent_settings.cc
@@ -30,11 +30,11 @@ #include "cobalt/script/promise.h" #include "cobalt/script/script_value.h" #include "cobalt/web/cache_utils.h" -#include "cobalt/worker/service_worker_consts.h" #include "cobalt/worker/service_worker_context.h" #include "cobalt/worker/service_worker_jobs.h" #include "cobalt/worker/service_worker_registration_object.h" #include "cobalt/worker/service_worker_update_via_cache.h" +#include "cobalt/worker/worker_consts.h" #include "cobalt/worker/worker_global_scope.h" #include "net/base/completion_once_callback.h" #include "net/disk_cache/cobalt/resource_type.h" @@ -88,7 +88,7 @@ const Options& options) : options_(options) { persistent_settings_.reset(new cobalt::persistent_storage::PersistentSettings( - ServiceWorkerConsts::kSettingsJson)); + WorkerConsts::kSettingsJson)); persistent_settings_->ValidatePersistentSettings(); DCHECK(persistent_settings_); } @@ -110,7 +110,7 @@ persistent_settings_->GetPersistentSettingAsDictionary(key_string); if (dict.empty()) { DLOG(INFO) << "Key: " << key_string << " does not exist in " - << ServiceWorkerConsts::kSettingsJson; + << WorkerConsts::kSettingsJson; continue; } if (!CheckPersistentValue(key_string, kSettingsStorageKeyKey, dict, @@ -461,5 +461,9 @@ } } +void ServiceWorkerPersistentSettings::DeleteAll(base::OnceClosure closure) { + persistent_settings_->DeletePersistentSettings(std::move(closure)); +} + } // namespace worker } // namespace cobalt
diff --git a/cobalt/worker/service_worker_persistent_settings.h b/cobalt/worker/service_worker_persistent_settings.h index e595acb..f855895 100644 --- a/cobalt/worker/service_worker_persistent_settings.h +++ b/cobalt/worker/service_worker_persistent_settings.h
@@ -87,6 +87,8 @@ void RemoveAll(); + void DeleteAll(base::OnceClosure closure); + private: Options options_;
diff --git a/cobalt/worker/service_worker_registration_map.cc b/cobalt/worker/service_worker_registration_map.cc index 3532094..24bfd5d 100644 --- a/cobalt/worker/service_worker_registration_map.cc +++ b/cobalt/worker/service_worker_registration_map.cc
@@ -61,8 +61,6 @@ new ServiceWorkerPersistentSettings(options)); DCHECK(service_worker_persistent_settings_); - // TODO(b/259731731) For now do not read from persisted settings until - // activation of persisted registrations works. ReadPersistentSettings(); } @@ -71,6 +69,15 @@ registration_map_); } +void ServiceWorkerRegistrationMap::DeletePersistentSettings() { + base::OnceClosure closure = base::BindOnce( + [](std::map<RegistrationMapKey, + scoped_refptr<ServiceWorkerRegistrationObject>>* + registration_map) { (*registration_map).clear(); }, + ®istration_map_); + service_worker_persistent_settings_->DeleteAll(std::move(closure)); +} + scoped_refptr<ServiceWorkerRegistrationObject> ServiceWorkerRegistrationMap::MatchServiceWorkerRegistration( const url::Origin& storage_key, const GURL& client_url) {
diff --git a/cobalt/worker/service_worker_registration_map.h b/cobalt/worker/service_worker_registration_map.h index 591f58f..421e6f8 100644 --- a/cobalt/worker/service_worker_registration_map.h +++ b/cobalt/worker/service_worker_registration_map.h
@@ -81,6 +81,8 @@ void ReadPersistentSettings(); + void DeletePersistentSettings(); + private: // ThreadChecker for use by the methods operating on the registration map. THREAD_CHECKER(thread_checker_);
diff --git a/cobalt/worker/worker.cc b/cobalt/worker/worker.cc index d01d252..28ee68e 100644 --- a/cobalt/worker/worker.cc +++ b/cobalt/worker/worker.cc
@@ -174,9 +174,19 @@ // 1. Set request's reserved client to inside settings. // 2. Fetch request, and asynchronously wait to run the remaining steps as // part of fetch's process response for the response response. + DCHECK(web_context_); + DCHECK(web_context_->environment_settings()); const GURL& url = web_context_->environment_settings()->creation_url(); + DCHECK(!url.is_empty()); loader::Origin origin = loader::Origin(url.GetOrigin()); + DCHECK(options_.outside_context); + + // Window thread may remove its global object before destroying worker. + if (!options_.outside_context->GetWindowOrWorkerGlobalScope()) { + return; + } + csp::SecurityCallback csp_callback = base::Bind( &web::CspDelegate::CanLoad, base::Unretained(options_.outside_context->GetWindowOrWorkerGlobalScope()
diff --git a/cobalt/worker/worker.h b/cobalt/worker/worker.h index d37d462..364837a 100644 --- a/cobalt/worker/worker.h +++ b/cobalt/worker/worker.h
@@ -63,13 +63,13 @@ base::SourceLocation construction_location; // True if worker is a SharedWorker object, and false otherwise. - bool is_shared; + bool is_shared = false; // Parameters from 'Run a worker' step 9.1 in the spec. // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#dom-worker GURL url; web::Context* outside_context = nullptr; - web::EventTarget* outside_event_target; + web::EventTarget* outside_event_target = nullptr; web::MessagePort* outside_port = nullptr; WorkerOptions options; };
diff --git a/cobalt/worker/worker_consts.h b/cobalt/worker/worker_consts.h new file mode 100644 index 0000000..9ee5c52 --- /dev/null +++ b/cobalt/worker/worker_consts.h
@@ -0,0 +1,80 @@ +// Copyright 2023 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. + +#ifndef COBALT_WORKER_WORKER_CONSTS_H_ +#define COBALT_WORKER_WORKER_CONSTS_H_ + +namespace cobalt { +namespace worker { + +namespace WorkerConsts { + +// Constants for error messages. +constexpr const char kServiceWorkerRegisterBadMIMEError[] = + "Service Worker Register failed: The script has an unsupported MIME type " + "('%s')."; +constexpr const char kServiceWorkerRegisterNoMIMEError[] = + "Service Worker Register failed: The script does not have a MIME type."; +constexpr const char kServiceWorkerRegisterScriptOriginNotSameError[] = + "Service Worker Register failed: Script URL ('%s') and referrer ('%s') " + "origin are not the same."; +constexpr const char kServiceWorkerRegisterScopeOriginNotSameError[] = + "Service Worker Register failed: Scope URL ('%s') and referrer ('%s') " + "origin are not the same."; +constexpr const char kServiceWorkerRegisterBadScopeError[] = + "Service Worker Register failed: Scope ('%s') is not allowed."; +constexpr const char kServiceWorkerUnregisterScopeOriginNotSameError[] = + "Service Worker Unregister failed: Scope origin does not match."; + +constexpr const char kServiceWorkerAllowed[] = "Service-Worker-Allowed"; + +// Constants for ServiceWorkerPersistentSettings +constexpr const char kSettingsJson[] = "service_worker_settings.json"; + +// Array of JavaScript mime types, according to the MIME Sniffinc spec: +// https://mimesniff.spec.whatwg.org/#javascript-mime-type +constexpr const char* const kJavaScriptMimeTypes[16] = { + "application/ecmascript", + "application/javascript", + "application/x-ecmascript", + "application/x-javascript", + "text/ecmascript", + "text/javascript", + "text/javascript1.0", + "text/javascript1.1", + "text/javascript1.2", + "text/javascript1.3", + "text/javascript1.4", + "text/javascript1.5", + "text/jscript", + "text/livescript", + "text/x-ecmascript", + "text/x-javascript"}; + +// The name of a Service Worker thread. +constexpr const char kServiceWorkerName[] = "ServiceWorker"; + +// The name of a Service Worker Registry thread. +constexpr const char kServiceWorkerRegistryName[] = "ServiceWorkerRegistry"; + +// The name of a Dedicated Worker thread. +constexpr const char kDedicatedWorkerName[] = "DedicatedWorker"; + +}; // namespace WorkerConsts + + +} // namespace worker +} // namespace cobalt + +#endif // COBALT_WORKER_WORKER_CONSTS_H_
diff --git a/cobalt/worker/worker_global_scope.cc b/cobalt/worker/worker_global_scope.cc index 0f2372b..7bf72c0 100644 --- a/cobalt/worker/worker_global_scope.cc +++ b/cobalt/worker/worker_global_scope.cc
@@ -31,8 +31,8 @@ #include "cobalt/web/user_agent_platform_info.h" #include "cobalt/web/window_or_worker_global_scope.h" #include "cobalt/web/window_timers.h" -#include "cobalt/worker/service_worker_consts.h" #include "cobalt/worker/service_worker_object.h" +#include "cobalt/worker/worker_consts.h" #include "cobalt/worker/worker_location.h" #include "cobalt/worker/worker_navigator.h" #include "net/base/mime_util.h" @@ -169,7 +169,7 @@ std::string content_type; bool mime_type_is_javascript = false; if (headers->GetNormalizedHeader("Content-type", &content_type)) { - for (auto mime_type : ServiceWorkerConsts::kJavaScriptMimeTypes) { + for (auto mime_type : WorkerConsts::kJavaScriptMimeTypes) { if (net::MatchesMimeType(mime_type, content_type)) { mime_type_is_javascript = true; break; @@ -177,13 +177,12 @@ } } if (content_type.empty()) { - error->reset(new std::string(base::StringPrintf( - ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError, - content_type.c_str()))); + error->reset(new std::string( + base::StringPrintf(WorkerConsts::kServiceWorkerRegisterNoMIMEError))); } else if (!mime_type_is_javascript) { - error->reset(new std::string(base::StringPrintf( - ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError, - content_type.c_str()))); + error->reset(new std::string( + base::StringPrintf(WorkerConsts::kServiceWorkerRegisterBadMIMEError, + content_type.c_str()))); } return true; }
diff --git a/cobalt/worker/worker_global_scope.h b/cobalt/worker/worker_global_scope.h index 9c3468f..49ce6d7 100644 --- a/cobalt/worker/worker_global_scope.h +++ b/cobalt/worker/worker_global_scope.h
@@ -35,7 +35,7 @@ #include "cobalt/web/user_agent_platform_info.h" #include "cobalt/web/window_or_worker_global_scope.h" #include "cobalt/web/window_timers.h" -#include "cobalt/worker/service_worker_consts.h" +#include "cobalt/worker/worker_consts.h" #include "cobalt/worker/worker_location.h" #include "cobalt/worker/worker_navigator.h" #include "net/http/http_response_headers.h"
diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn index d83b2e6..08c7c4d 100644 --- a/components/update_client/BUILD.gn +++ b/components/update_client/BUILD.gn
@@ -246,10 +246,7 @@ "//starboard/loader_app:installation_manager", "//testing/gmock", "//testing/gtest", + # TODO: b/296919440 - Make this a data dep + "//starboard/loader_app($starboard_toolchain)", ] - if (build_with_separate_cobalt_toolchain) { - data_deps = [ "//starboard/loader_app($starboard_toolchain)" ] - } else { - deps += [ "//starboard/loader_app" ] - } }
diff --git a/content/browser/speech/BUILD.gn b/content/browser/speech/BUILD.gn index 6e5ae30..21ba4c7 100644 --- a/content/browser/speech/BUILD.gn +++ b/content/browser/speech/BUILD.gn
@@ -39,6 +39,7 @@ ] deps = [ ":speech", + "//cobalt//browser:test_dependencies_on_browser", "//cobalt/media", "//cobalt/test:run_all_unittests", "//starboard",
diff --git a/docker/docsite/Dockerfile b/docker/docsite/Dockerfile index 6b1bd9d..2e164c8 100644 --- a/docker/docsite/Dockerfile +++ b/docker/docsite/Dockerfile
@@ -46,7 +46,10 @@ RUN mkdir /project_out_dir \ && chown ${USER:-defaultuser}:defaultgroup /project_out_dir +<<<<<<< HEAD RUN git config --global --add safe.directory /code +======= +>>>>>>> 77f6a7c80d7 (Fix git config for /code in Linux containers (#611)) COPY Gemfile /app/Gemfile # Note: This file was generated by running a working version of this Docker
diff --git a/docker/linux/base/build/Dockerfile b/docker/linux/base/build/Dockerfile index 38fa8ce..4d0306d 100644 --- a/docker/linux/base/build/Dockerfile +++ b/docker/linux/base/build/Dockerfile
@@ -110,5 +110,7 @@ && echo ${CLANG_16_VER} >> ${CLANG_16_TC_HOME}/cr_build_revision \ && rm clang-llvmorg-${CLANG_16_VER}.tgz +RUN git config --global --add safe.directory /code + WORKDIR /code CMD ["/usr/bin/python","--version"]
diff --git a/docker/windows/base/visualstudio2022/Dockerfile b/docker/windows/base/visualstudio2022/Dockerfile index 780d9bf..a2722ff 100644 --- a/docker/windows/base/visualstudio2022/Dockerfile +++ b/docker/windows/base/visualstudio2022/Dockerfile
@@ -31,13 +31,16 @@ -ArgumentList '--quiet --wait --norestart --nocache` --installPath C:\BuildTools ` --add Microsoft.VisualStudio.Component.VC.CoreIde ` - --add Microsoft.VisualStudio.Component.VC.14.34.17.4.x86.x64 ` - --add Microsoft.VisualStudio.Component.VC.Llvm.Clang ` - --add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset ` - --add Microsoft.VisualStudio.Component.Windows10SDK.18362';` + --add Microsoft.VisualStudio.Component.VC.14.34.17.4.x86.x64 ` + --add Microsoft.VisualStudio.Component.VC.Llvm.Clang ` + --add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset ` + --add Microsoft.VisualStudio.Component.Windows10SDK.18362'; ` Write-Host ('Cleaning up vs_buildtools.exe');` Remove-Item -Force -Recurse ${env:ProgramFiles(x86)}\'Microsoft Visual Studio'\Installer;` Remove-Item -Force -Recurse $env:TEMP\*;` + Remove-Item -Force -Recurse $env:ProgramData\'Package Cache'\;` + Remove-Item -Force -Recurse C:\BuildTools\VC\Tools\Llvm\ARM64;` + Remove-Item -Force -Recurse C:\BuildTools\Common7\IDE;` Remove-Item C:\TEMP\vs_buildtools.exe ENV VSINSTALLDIR "C:\BuildTools"
diff --git a/nb/BUILD.gn b/nb/BUILD.gn index eb947a2..ff056c9 100644 --- a/nb/BUILD.gn +++ b/nb/BUILD.gn
@@ -63,7 +63,9 @@ "//starboard/common", ] - if (defined(has_nb_platform) && has_nb_platform) { + # TODO: b/295615064 Remove nb platform specific dependency. + if (defined(has_nb_platform) && has_nb_platform && + current_toolchain == starboard_toolchain) { deps += [ "//$starboard_path/nb:nb_platform" ] } }
diff --git a/net/BUILD.gn b/net/BUILD.gn index 0412e4d..e694523 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -198,7 +198,6 @@ "der/tag.cc", "der/tag.h", - # dial is a legacy Chromium component with heavy Cobalt modifications. "base/arena.cc", "base/arena.h", "base/backoff_entry.cc", @@ -344,18 +343,6 @@ "cookies/cookie_util.h", "cookies/parsed_cookie.cc", "cookies/parsed_cookie.h", - "dial/dial_http_server.cc", - "dial/dial_http_server.h", - "dial/dial_service.cc", - "dial/dial_service.h", - "dial/dial_service_handler.h", - "dial/dial_system_config.cc", - "dial/dial_system_config.h", - "dial/dial_system_config_starboard.cc", - "dial/dial_udp_server.cc", - "dial/dial_udp_server.h", - "dial/dial_udp_socket_factory.cc", - "dial/dial_udp_socket_factory.h", "dns/address_sorter.h", "dns/address_sorter.h", "dns/address_sorter_starboard.cc", @@ -3630,12 +3617,6 @@ "dns/record_rdata_unittest.cc", "dns/serial_worker_unittest.cc", - # dial is a legacy component we kept from old Chromium net. - "dial/dial_http_server_unittest.cc", - "dial/dial_service_unittest.cc", - "dial/dial_test_helpers.h", - "dial/dial_udp_server_unittests.cc", - # disk_cache component is disabled because only http cache depends on # it and Cobalt does not support http cache yet. # "disk_cache/backend_cleanup_tracker_unittest.cc", @@ -4194,6 +4175,17 @@ ] } + if (enable_in_app_dial) { + sources += [ + # DIAL server is Cobalt custom implementation. This is the wrong place for + # it and it should be moved to cobalt/network in the future. + "dial/dial_http_server_unittest.cc", + "dial/dial_service_unittest.cc", + "dial/dial_test_helpers.h", + "dial/dial_udp_server_unittests.cc", + ] + } + # Avoid compiler errors due to conversion from "0x00" to char. if (is_win) { if (!is_starboard) { @@ -4234,6 +4226,9 @@ "//url", "//url:url_features", ] + if (enable_in_app_dial) { + deps += [ ":cobalt_dial_server" ] + } if (is_starboard) { data_deps = [ @@ -4243,6 +4238,33 @@ "//third_party/icu:icudata", ] } + + if(use_cobalt_customizations) { + # TODO: b/296715826 - Fix unused symbols which cause linker errors for windows platform modular builds. + sources -= [ + "http/http_stream_factory_job_controller_unittest.cc", + "http/http_stream_factory_unittest.cc", + "http/http_stream_parser_unittest.cc", + "quic/bidirectional_stream_quic_impl_unittest.cc", + "quic/crypto/proof_verifier_chromium_test.cc", + "quic/network_connection_unittest.cc", + "quic/properties_based_quic_server_info_test.cc", + "quic/quic_address_mismatch_test.cc", + "quic/quic_chromium_alarm_factory_test.cc", + "quic/quic_chromium_client_session_test.cc", + "quic/quic_chromium_client_stream_test.cc", + "quic/quic_chromium_connection_helper_test.cc", + "quic/quic_clock_skew_detector_test.cc", + "quic/quic_connectivity_probing_manager_test.cc", + "quic/quic_end_to_end_unittest.cc", + "quic/quic_http_stream_test.cc", + "quic/quic_network_transaction_unittest.cc", + "quic/quic_proxy_client_socket_unittest.cc", + "quic/quic_stream_factory_test.cc", + "quic/quic_utils_chromium_test.cc", + ] + + } } static_library("test_support") { @@ -4255,6 +4277,7 @@ # "disk_cache/disk_cache_test_util.cc", # "disk_cache/disk_cache_test_util.h", + "base/directory_lister.h", "base/test_data_stream.cc", "base/test_data_stream.h", "quic/quic_test_packet_maker.cc", @@ -4421,6 +4444,16 @@ "//third_party/zlib", "//url", ] + + if(use_cobalt_customizations) { + # TODO: b/296715826 - Fix unused symbols which cause linker errors for windows platform modular builds. + sources -= [ + "test/quic_simple_test_server.cc", + "test/quic_simple_test_server.h", + "quic/quic_test_packet_maker.cc", + "quic/quic_test_packet_maker.h", + ] + } } static_library("quic_test_tools") { @@ -4659,3 +4692,28 @@ "//starboard/common", ] } + +if (enable_in_app_dial) { +static_library("cobalt_dial_server") { + sources = [ + "dial/dial_http_server.cc", + "dial/dial_http_server.h", + "dial/dial_service.cc", + "dial/dial_service.h", + "dial/dial_service_handler.h", + "dial/dial_system_config.cc", + "dial/dial_system_config.h", + "dial/dial_system_config_starboard.cc", + "dial/dial_udp_server.cc", + "dial/dial_udp_server.h", + "dial/dial_udp_socket_factory.cc", + "dial/dial_udp_socket_factory.h", + ] + deps = [ + ":http_server", + ":net", + "//base:base", + "//starboard/common", + ] + } +}
diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h index 3f8b541..e5677e4 100644 --- a/net/base/directory_lister.h +++ b/net/base/directory_lister.h
@@ -21,6 +21,7 @@ namespace net { +#if !defined(USE_COBALT_CUSTOMIZATIONS) // This class provides an API for asynchronously listing the contents of a // directory on the filesystem. It runs a task on a background thread, and // enumerates all files in the specified directory on that thread. Destroying @@ -135,6 +136,37 @@ DISALLOW_COPY_AND_ASSIGN(DirectoryLister); }; +#else + +// TODO b/296715826 Fix stubbed out class. +class NET_EXPORT DirectoryLister { + public: + struct DirectoryListerData { + base::FileEnumerator::FileInfo info; + base::FilePath path; + base::FilePath absolute_path; + }; + class DirectoryListerDelegate { + public: + virtual void OnListFile(const DirectoryListerData& data) = 0; + + virtual void OnListDone(int error) = 0; + + protected: + virtual ~DirectoryListerDelegate() {} + }; + enum ListingType {}; + DirectoryLister(const base::FilePath& dir, + DirectoryListerDelegate* delegate){}; + DirectoryLister(const base::FilePath& dir, + ListingType type, + DirectoryListerDelegate* delegate){}; + ~DirectoryLister(){}; + void Start() {}; + void Cancel() {}; +}; + +#endif // !defined(USE_COBALT_CUSTOMIZATIONS) } // namespace net #endif // NET_BASE_DIRECTORY_LISTER_H_
diff --git a/net/base/net_export.h b/net/base/net_export.h index 55cf986..29891cf 100644 --- a/net/base/net_export.h +++ b/net/base/net_export.h
@@ -4,12 +4,16 @@ #ifndef NET_BASE_NET_EXPORT_H_ #define NET_BASE_NET_EXPORT_H_ - // Defines NET_EXPORT so that functionality implemented by the net module can // be exported to consumers, and NET_EXPORT_PRIVATE that allows unit tests to // access features not intended to be used directly by real consumers. -#if defined(COMPONENT_BUILD) +#ifdef USE_COBALT_CUSTOMIZATIONS +#include "starboard/configuration.h" +#endif // USE_COBALT_CUSTOMIZATIONS + +#if defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN) + #if defined(WIN32) #if defined(NET_IMPLEMENTATION) @@ -30,7 +34,7 @@ #endif #endif -#else /// defined(COMPONENT_BUILD) +#else // defined(COMPONENT_BUILD) || SB_IS(MODULAR) && !SB_IS(EVERGREEN) #define NET_EXPORT #define NET_EXPORT_PRIVATE #endif
diff --git a/starboard/BUILD.gn b/starboard/BUILD.gn index 630ec47..3ab468c 100644 --- a/starboard/BUILD.gn +++ b/starboard/BUILD.gn
@@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//starboard/build/config/os_definitions.gni") import("//starboard/build/config/starboard_target_type.gni") +import("//starboard/contrib/cast/cast.gni") group("gn_all") { testonly = true @@ -57,9 +59,8 @@ deps += [ "//starboard/benchmark" ] } - if (build_with_separate_cobalt_toolchain && is_cobalt_toolchain) { - assert(sb_is_modular, - "sb_is_modular should be set when building with cobalt_toolchain") + if (build_with_separate_cobalt_toolchain && use_contrib_cast) { + deps += [ "//starboard/contrib/cast/cast_starboard_api/samples:cast" ] } if (!sb_is_evergreen) { @@ -68,7 +69,7 @@ if (sb_is_evergreen_compatible) { deps += [ "//third_party/crashpad/client" ] data_deps = [ - "//starboard/loader_app", + "//starboard/loader_app($starboard_toolchain)", "//third_party/crashpad/handler:crashpad_handler(//$starboard_path/toolchain:native_target)", ] } @@ -89,7 +90,7 @@ "//starboard/client_porting/eztime", ] - if (sb_is_modular) { + if (sb_is_modular && current_toolchain == cobalt_toolchain) { public_deps += [ "//third_party/llvm-project/compiler-rt:compiler_rt", "//third_party/llvm-project/libcxx:cxx", @@ -98,11 +99,13 @@ ] if (sb_is_evergreen) { public_deps += [ "//starboard/elf_loader:sabi_string" ] - } - if (build_with_separate_cobalt_toolchain) { - data_deps = [ ":starboard_platform_group($starboard_toolchain)" ] } else { - public_deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ] + data_deps = [ ":starboard_platform_group($starboard_toolchain)" ] + } + + # TODO: b/295702296 Fix libunwind for modular builds. + if (sb_is_evergreen || is_host_win) { + public_deps += [ "//third_party/llvm-project/libunwind:unwind" ] } } else { public_deps += [ @@ -110,7 +113,7 @@ "//starboard/common", ] - if (!build_with_separate_cobalt_toolchain) { + if (!sb_is_modular || sb_is_evergreen) { if (sb_is_evergreen_compatible) { public_deps += [ "//third_party/crashpad/wrapper" ] } else { @@ -177,24 +180,8 @@ } if (current_toolchain == starboard_toolchain) { - target(starboard_target_type, "starboard_platform_group") { - if (starboard_target_type == "shared_library") { - build_loader = false - } - public_deps = [ - "//starboard/client_porting/cwrappers", - "//starboard/client_porting/eztime", - "//starboard/common", - "//starboard/egl_and_gles", - ] - if (sb_is_evergreen_compatible) { - public_deps += [ "//third_party/crashpad/wrapper" ] - } else { - public_deps += [ "//third_party/crashpad/wrapper:wrapper_stub" ] - } - if (!sb_is_modular) { - public_deps += [ "//$starboard_path:starboard_platform" ] - } + # This is the default 'starboard_platform_target'; use default properties + starboard_platform_target("starboard_platform_group") { } if (platform_tests_path == "") { @@ -206,10 +193,17 @@ sources = [ "//starboard/common/test_main.cc" ] public_deps = [ - ":starboard", + ":starboard_with_main", "//testing/gmock", "//testing/gtest", ] } } + + group("starboard_with_main") { + public_deps = [ ":starboard" ] + if (sb_is_modular && !sb_is_evergreen) { + public_deps += [ "//$starboard_path:starboard_platform_with_main" ] + } + } }
diff --git a/starboard/android/apk/app/CMakeLists.txt b/starboard/android/apk/app/CMakeLists.txt index 8c7d129..d10920b 100644 --- a/starboard/android/apk/app/CMakeLists.txt +++ b/starboard/android/apk/app/CMakeLists.txt
@@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Since libcoat.so is an "IMPORTED" library in CMake, in order to debug in +# Since libcobalt.so is an "IMPORTED" library in CMake, in order to debug in # Android Studio you have to manually set the debugger type so that LLDB will # be started: # Run -> Edit Configurations -> "app" -> Debugger -> Debug Type = Dual @@ -65,18 +65,18 @@ set(skip_ninja_arg -n) endif() -# Run Cobalt ninja, and copy the result as our "IMPORTED" libcoat.so. +# Run Cobalt ninja, and copy the result as our "IMPORTED" libcobalt.so. # ("coat_lib" never gets created, so this runs every time.) add_custom_command(OUTPUT coat_lib COMMAND ${CMAKE_CURRENT_LIST_DIR}/cobalt-ninja.sh ${skip_ninja_arg} -C ${COBALT_PRODUCT_DIR} ${COBALT_TARGET} COMMAND ${CMAKE_COMMAND} -E copy ${COBALT_LIBRARY_DIR}/lib${COBALT_TARGET}.so - ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcoat.so + ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcobalt.so ) if(EVERGREEN_COMPATIBLE) - # Follow the pattern used to import libcoat.so, above. + # Follow the pattern used to import libcobalt.so, above. add_custom_command(OUTPUT crashpad_handler_lib COMMAND ${CMAKE_CURRENT_LIST_DIR}/cobalt-ninja.sh ${skip_ninja_arg} -C ${COBALT_PRODUCT_DIR} crashpad_handler @@ -109,15 +109,15 @@ # We need a target (not a file) for the phony native dependency below. add_custom_target(external_cobalt_build DEPENDS coat_lib cobalt_content) -# Declare libcoat.so as a shared library that needs to be included in the APK. +# Declare libcobalt.so as a shared library that needs to be included in the APK. # However, Android Studio will build it as an "IMPORTED" library. add_library(coat SHARED IMPORTED) set_target_properties(coat PROPERTIES - IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcoat.so + IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcobalt.so ) if(EVERGREEN_COMPATIBLE) - # Follow the pattern used to include libcoat.so, above. + # Follow the pattern used to include libcobalt.so, above. add_library(crashpadhandler SHARED IMPORTED) set_target_properties(crashpadhandler PROPERTIES IMPORTED_LOCATION ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libcrashpad_handler.so
diff --git a/starboard/android/apk/app/src/app/AndroidManifest.xml b/starboard/android/apk/app/src/app/AndroidManifest.xml index 0bece9b..6b2602d 100644 --- a/starboard/android/apk/app/src/app/AndroidManifest.xml +++ b/starboard/android/apk/app/src/app/AndroidManifest.xml
@@ -50,7 +50,7 @@ <meta-data android:name="cobalt.APP_URL" android:value="https://www.youtube.com/tv"/> <meta-data android:name="cobalt.SPLASH_URL" android:value="h5vcc-embedded://cobalt_splash_screen.html"/> <meta-data android:name="cobalt.EVERGREEN_LITE" android:value="false"/> - <meta-data android:name="android.app.lib_name" android:value="coat"/> + <meta-data android:name="android.app.lib_name" android:value="cobalt"/> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java index 56a2ffd..e5f5df8 100644 --- a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java +++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltHttpHelper.java
@@ -25,6 +25,7 @@ /** Helper class that implements an HTTP POST function used by DRM one-time provisioning. */ public class CobaltHttpHelper { + private static final int HTTP_TIMEOUT_MILLIS = 10000; private static final int RETRY_SLEEP_MILLIS = 250; private static final int MAX_ATTEMPTS = 3; @@ -72,6 +73,8 @@ private byte[] internalPerformHttpPost(String url) throws IOException, TransientFailure { HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); try { + conn.setConnectTimeout(HTTP_TIMEOUT_MILLIS); + conn.setReadTimeout(HTTP_TIMEOUT_MILLIS); conn.setRequestMethod("POST"); conn.setDoOutput(false); conn.setDoInput(true);
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java index 2d719ad..61f4bca 100644 --- a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java +++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
@@ -85,7 +85,11 @@ static { // Even though NativeActivity already loads our library from C++, // we still have to load it from Java to make JNI calls into it. - System.loadLibrary("coat"); + + // GameActivity has code to load the libcobalt.so as well. + // It reads the library name from the meta data field "android.app.lib_name" in the + // AndroidManifest.xml + System.loadLibrary("cobalt"); } private final Context appContext;
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java b/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java index 23ab5f3..ffcea69 100644 --- a/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java +++ b/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
@@ -535,41 +535,10 @@ if (mMediaDrm == null) { throw new IllegalStateException("Cannot create media crypto with null mMediaDrm."); } - if (mMediaCryptoSession != null) { - throw new IllegalStateException( - "Cannot create media crypto with non-null mMediaCryptoSession."); - } - // TODO: Cannot do this during provisioning pending. - - // Open media crypto session. - try { - mMediaCryptoSession = openSession(); - } catch (NotProvisionedException e) { - Log.d(TAG, "Device not provisioned", e); - if (!attemptProvisioning()) { - Log.e(TAG, "Failed to provision device during MediaCrypto creation."); - return false; - } - try { - mMediaCryptoSession = openSession(); - } catch (NotProvisionedException e2) { - Log.e(TAG, "Device still not provisioned after supposedly successful provisioning", e2); - return false; - } - } - - if (mMediaCryptoSession == null) { - Log.e(TAG, "Cannot create MediaCrypto Session."); - return false; - } - Log.d( - TAG, - String.format("MediaCrypto Session created: %s", bytesToHexString(mMediaCryptoSession))); - // Create MediaCrypto object. try { if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) { - MediaCrypto mediaCrypto = new MediaCrypto(mSchemeUUID, mMediaCryptoSession); + MediaCrypto mediaCrypto = new MediaCrypto(mSchemeUUID, new byte[0]); Log.d(TAG, "MediaCrypto successfully created!"); mMediaCrypto = mediaCrypto; return true; @@ -580,14 +549,6 @@ Log.e(TAG, "Cannot create MediaCrypto", e); } - try { - // Some implementations let this method throw exceptions. - mMediaDrm.closeSession(mMediaCryptoSession); - } catch (Exception e) { - Log.e(TAG, "closeSession failed: ", e); - } - mMediaCryptoSession = null; - return false; } @@ -621,6 +582,59 @@ } } + @UsedByNative + boolean createMediaCryptoSession() { + if (mMediaCryptoSession != null) { + return true; + } + Log.w(TAG, "MediaDrmBridge createMediaCryptoSession"); + if (mMediaCrypto == null) { + throw new IllegalStateException("Cannot create media crypto session with null mMediaCrypto."); + } + + // Open media crypto session. + try { + mMediaCryptoSession = openSession(); + } catch (NotProvisionedException e) { + Log.w(TAG, "Device not provisioned", e); + if (!attemptProvisioning()) { + Log.e(TAG, "Failed to provision device during MediaCrypto creation."); + return false; + } + try { + mMediaCryptoSession = openSession(); + } catch (NotProvisionedException e2) { + Log.e(TAG, "Device still not provisioned after supposedly successful provisioning", e2); + return false; + } + } + + if (mMediaCryptoSession == null) { + Log.e(TAG, "Cannot create MediaCrypto Session."); + return false; + } + + try { + mMediaCrypto.setMediaDrmSession(mMediaCryptoSession); + } catch (MediaCryptoException e3) { + Log.e(TAG, "Unable to set media drm session", e3); + try { + // Some implementations let this method throw exceptions. + mMediaDrm.closeSession(mMediaCryptoSession); + } catch (Exception e) { + Log.e(TAG, "closeSession failed: ", e); + } + mMediaCryptoSession = null; + return false; + } + + Log.d( + TAG, + String.format("MediaCrypto Session created: %s", bytesToHexString(mMediaCryptoSession))); + + return true; + } + /** * Attempt to get the device that we are currently running on provisioned. *
diff --git a/starboard/android/arm/toolchain/BUILD.gn b/starboard/android/arm/toolchain/BUILD.gn index b49df51..6b167d1 100644 --- a/starboard/android/arm/toolchain/BUILD.gn +++ b/starboard/android/arm/toolchain/BUILD.gn
@@ -21,7 +21,6 @@ cc = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang" cxx = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang++" ld = cxx - ar = "$prefix/arm-linux-androideabi-readelf" ar = "ar" nm = "nm" @@ -35,7 +34,6 @@ cc = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang" cxx = "$prefix/armv7a-linux-androideabi${android_ndk_api_level}-clang++" ld = cxx - ar = "$prefix/arm-linux-androideabi-readelf" ar = "ar" nm = "nm"
diff --git a/starboard/android/shared/application_android.cc b/starboard/android/shared/application_android.cc index 0334d1f..33b26ad 100644 --- a/starboard/android/shared/application_android.cc +++ b/starboard/android/shared/application_android.cc
@@ -143,6 +143,7 @@ } ApplicationAndroid::~ApplicationAndroid() { + // The application is exiting. // Release the global reference. if (resource_overlay_) { JniEnvExt* env = JniEnvExt::Get(); @@ -156,6 +157,12 @@ ALooper_removeFd(looper_, keyboard_inject_readfd_); close(keyboard_inject_readfd_); close(keyboard_inject_writefd_); + + { + // Signal for any potentially waiting window creation or destroy commands. + ScopedLock lock(android_command_mutex_); + android_command_condition_.Signal(); + } } void ApplicationAndroid::Initialize() { @@ -251,7 +258,10 @@ JniEnvExt* env = JniEnvExt::Get(); AndroidCommand cmd; int err = read(android_command_readfd_, &cmd, sizeof(cmd)); - SB_DCHECK(err >= 0) << "Command read failed. errno=" << errno; + if (err < 0) { + SB_DCHECK(err >= 0) << "Command read failed. errno=" << errno; + return; + } SB_LOG(INFO) << "Android command: " << AndroidCommandName(cmd.type); @@ -394,7 +404,10 @@ SB_LOG(INFO) << "Send Android command: " << AndroidCommandName(type); AndroidCommand cmd{type, data}; ScopedLock lock(android_command_mutex_); - write(android_command_writefd_, &cmd, sizeof(cmd)); + if (write(android_command_writefd_, &cmd, sizeof(cmd)) == -1) { + SB_LOG(ERROR) << "Writing Android command failed"; + return; + } // Synchronization only necessary when managing resources. switch (type) { case AndroidCommand::kNativeWindowCreated:
diff --git a/starboard/android/shared/application_android.h b/starboard/android/shared/application_android.h index d023e74..e8917c1 100644 --- a/starboard/android/shared/application_android.h +++ b/starboard/android/shared/application_android.h
@@ -56,8 +56,8 @@ kDeepLink, } CommandType; - CommandType type; - void* data; + CommandType type = kUndefined; + void* data = nullptr; }; #if SB_API_VERSION >= 15
diff --git a/starboard/android/shared/drm_system.cc b/starboard/android/shared/drm_system.cc index 3b195e5..7897d3b 100644 --- a/starboard/android/shared/drm_system.cc +++ b/starboard/android/shared/drm_system.cc
@@ -14,10 +14,15 @@ #include "starboard/android/shared/drm_system.h" +#include <memory> +#include <utility> + #include "starboard/android/shared/jni_env_ext.h" #include "starboard/android/shared/jni_utils.h" #include "starboard/android/shared/media_common.h" +#include "starboard/common/atomic.h" #include "starboard/common/instance_counter.h" +#include "starboard/common/thread.h" namespace { @@ -177,7 +182,8 @@ SbDrmSessionUpdateRequestFunc update_request_callback, SbDrmSessionUpdatedFunc session_updated_callback, SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback) - : key_system_(key_system), + : Thread("DrmSystemThread"), + key_system_(key_system), context_(context), update_request_callback_(update_request_callback), session_updated_callback_(session_updated_callback), @@ -206,10 +212,35 @@ return; } j_media_crypto_ = env->ConvertLocalRefToGlobalRef(j_media_crypto_); + + Start(); +} + +void DrmSystem::Run() { + JniEnvExt* env = JniEnvExt::Get(); + bool result = env->CallBooleanMethodOrAbort( + j_media_drm_bridge_, "createMediaCryptoSession", "()Z"); + if (result) { + created_media_crypto_session_.store(true); + } + if (!result && j_media_crypto_) { + env->DeleteGlobalRef(j_media_crypto_); + j_media_crypto_ = NULL; + return; + } + + ScopedLock scoped_lock(mutex_); + if (!deferred_session_update_requests_.empty()) { + for (const auto& update_request : deferred_session_update_requests_) { + update_request->Generate(j_media_drm_bridge_); + } + deferred_session_update_requests_.clear(); + } } DrmSystem::~DrmSystem() { ON_INSTANCE_RELEASED(AndroidDrmSystem); + Join(); JniEnvExt* env = JniEnvExt::Get(); if (j_media_crypto_) { @@ -223,17 +254,64 @@ } } +DrmSystem::SessionUpdateRequest::SessionUpdateRequest( + int ticket, + const char* type, + const void* initialization_data, + int initialization_data_size) { + JniEnvExt* env = JniEnvExt::Get(); + j_ticket_ = static_cast<jint>(ticket); + j_init_data_ = + ByteArrayFromRaw(initialization_data, initialization_data_size); + j_mime_ = env->NewStringStandardUTFOrAbort(type); +} + +void DrmSystem::SessionUpdateRequest::ConvertLocalRefToGlobalRef() { + if (!references_are_global_) { + JniEnvExt* env = JniEnvExt::Get(); + j_init_data_ = env->ConvertLocalRefToGlobalRef(j_init_data_); + j_mime_ = env->ConvertLocalRefToGlobalRef(j_mime_); + references_are_global_ = true; + } +} + +DrmSystem::SessionUpdateRequest::~SessionUpdateRequest() { + JniEnvExt* env = JniEnvExt::Get(); + if (references_are_global_) { + env->DeleteGlobalRef(j_init_data_); + env->DeleteGlobalRef(j_mime_); + } else { + env->DeleteLocalRef(j_init_data_); + env->DeleteLocalRef(j_mime_); + } + j_init_data_ = nullptr; + j_mime_ = nullptr; +} + +void DrmSystem::SessionUpdateRequest::Generate( + jobject j_media_drm_bridge) const { + JniEnvExt* env = JniEnvExt::Get(); + env->CallVoidMethodOrAbort(j_media_drm_bridge, "createSession", + "(I[BLjava/lang/String;)V", j_ticket_, + j_init_data_, j_mime_); +} + void DrmSystem::GenerateSessionUpdateRequest(int ticket, const char* type, const void* initialization_data, int initialization_data_size) { - ScopedLocalJavaRef<jbyteArray> j_init_data( - ByteArrayFromRaw(initialization_data, initialization_data_size)); - JniEnvExt* env = JniEnvExt::Get(); - ScopedLocalJavaRef<jstring> j_mime(env->NewStringStandardUTFOrAbort(type)); - env->CallVoidMethodOrAbort( - j_media_drm_bridge_, "createSession", "(I[BLjava/lang/String;)V", - static_cast<jint>(ticket), j_init_data.Get(), j_mime.Get()); + std::unique_ptr<SessionUpdateRequest> session_update_request( + new SessionUpdateRequest(ticket, type, initialization_data, + initialization_data_size)); + if (created_media_crypto_session_.load()) { + session_update_request->Generate(j_media_drm_bridge_); + } else { + // Defer generating the update request. + session_update_request->ConvertLocalRefToGlobalRef(); + ScopedLock scoped_lock(mutex_); + deferred_session_update_requests_.push_back( + std::move(session_update_request)); + } // |update_request_callback_| will be called by Java calling into // |onSessionMessage|. }
diff --git a/starboard/android/shared/drm_system.h b/starboard/android/shared/drm_system.h index 48051c5..f60d25b 100644 --- a/starboard/android/shared/drm_system.h +++ b/starboard/android/shared/drm_system.h
@@ -18,21 +18,25 @@ #include "starboard/shared/starboard/drm/drm_system_internal.h" #include <jni.h> +#include <memory> #include <string> #include <unordered_map> #include <vector> +#include "starboard/android/shared/jni_utils.h" #include "starboard/android/shared/media_common.h" +#include "starboard/common/atomic.h" #include "starboard/common/log.h" #include "starboard/common/mutex.h" +#include "starboard/common/thread.h" #include "starboard/types.h" namespace starboard { namespace android { namespace shared { -class DrmSystem : public ::SbDrmSystemPrivate { +class DrmSystem : public ::SbDrmSystemPrivate, private Thread { public: DrmSystem(const char* key_system, void* context, @@ -81,9 +85,33 @@ return IsWidevineL1(key_system_.c_str()); } + // Return true when the drm system is ready for secure input buffers. + bool IsReady() { return created_media_crypto_session_.load(); } + private: + class SessionUpdateRequest { + public: + SessionUpdateRequest(int ticket, + const char* type, + const void* initialization_data, + int initialization_data_size); + ~SessionUpdateRequest(); + + void ConvertLocalRefToGlobalRef(); + void Generate(jobject j_media_drm_bridge) const; + + private: + bool references_are_global_ = false; + jint j_ticket_; + jobject j_init_data_; + jobject j_mime_; + }; + void CallKeyStatusesChangedCallbackWithKeyStatusRestricted_Locked(); + // From Thread. + void Run() override; + const std::string key_system_; void* context_; SbDrmSessionUpdateRequestFunc update_request_callback_; @@ -94,9 +122,13 @@ jobject j_media_drm_bridge_; jobject j_media_crypto_; + std::vector<std::unique_ptr<SessionUpdateRequest>> + deferred_session_update_requests_; + Mutex mutex_; - std::unordered_map<std::string, std::vector<SbDrmKeyId> > cached_drm_key_ids_; + std::unordered_map<std::string, std::vector<SbDrmKeyId>> cached_drm_key_ids_; bool hdcp_lost_; + atomic_bool created_media_crypto_session_; std::vector<uint8_t> metrics_; };
diff --git a/starboard/android/shared/media_decoder.cc b/starboard/android/shared/media_decoder.cc index 721680e..78425b7 100644 --- a/starboard/android/shared/media_decoder.cc +++ b/starboard/android/shared/media_decoder.cc
@@ -35,6 +35,9 @@ const jint kNoSize = 0; const jint kNoBufferFlags = 0; +// Delay to use after a retryable error has been encountered. +const SbTime kErrorRetryDelay = 50 * kSbTimeMillisecond; + const char* GetNameForMediaCodecStatus(jint status) { switch (status) { case MEDIA_CODEC_OK: @@ -461,15 +464,23 @@ jint status; if (event.type == Event::kWriteCodecConfig) { - status = media_codec_bridge_->QueueInputBuffer(dequeue_input_result.index, - kNoOffset, size, kNoPts, - BUFFER_FLAG_CODEC_CONFIG); + if (!drm_system_ || (drm_system_ && drm_system_->IsReady())) { + status = media_codec_bridge_->QueueInputBuffer(dequeue_input_result.index, + kNoOffset, size, kNoPts, + BUFFER_FLAG_CODEC_CONFIG); + } else { + status = MEDIA_CODEC_NO_KEY; + } } else if (event.type == Event::kWriteInputBuffer) { jlong pts_us = input_buffer->timestamp(); if (drm_system_ && input_buffer->drm_info()) { - status = media_codec_bridge_->QueueSecureInputBuffer( - dequeue_input_result.index, kNoOffset, *input_buffer->drm_info(), - pts_us); + if (drm_system_->IsReady()) { + status = media_codec_bridge_->QueueSecureInputBuffer( + dequeue_input_result.index, kNoOffset, *input_buffer->drm_info(), + pts_us); + } else { + status = MEDIA_CODEC_NO_KEY; + } } else { status = media_codec_bridge_->QueueInputBuffer( dequeue_input_result.index, kNoOffset, size, pts_us, kNoBufferFlags); @@ -534,6 +545,7 @@ SB_LOG(INFO) << "|" << action_name << "| failed with status: " << GetNameForMediaCodecStatus(status) << ", will try again after a delay."; + SbThreadYield(); } else { SB_LOG(ERROR) << "|" << action_name << "| failed with status: " << GetNameForMediaCodecStatus(status) << ".";
diff --git a/starboard/android/shared/media_get_audio_configuration.cc b/starboard/android/shared/media_get_audio_configuration.cc index dbd658f..6b645b6 100644 --- a/starboard/android/shared/media_get_audio_configuration.cc +++ b/starboard/android/shared/media_get_audio_configuration.cc
@@ -17,6 +17,7 @@ #include "starboard/android/shared/jni_env_ext.h" #include "starboard/android/shared/jni_utils.h" #include "starboard/android/shared/media_capabilities_cache.h" +#include "starboard/common/media.h" // Constants for output types from // https://developer.android.com/reference/android/media/AudioDeviceInfo. @@ -129,11 +130,19 @@ bool SbMediaGetAudioConfiguration( int output_index, SbMediaAudioConfiguration* out_configuration) { + using starboard::GetMediaAudioConnectorName; using starboard::android::shared::JniEnvExt; using starboard::android::shared::MediaCapabilitiesCache; using starboard::android::shared::ScopedLocalJavaRef; - if (output_index < 0 || out_configuration == NULL) { + if (output_index < 0) { + SB_LOG(WARNING) << "output_index is " << output_index + << ", which cannot be negative."; + return false; + } + + if (out_configuration == nullptr) { + SB_LOG(WARNING) << "out_configuration cannot be nullptr."; return false; } @@ -152,6 +161,8 @@ output_index, j_output_device_info.Get()); if (!succeeded) { + SB_LOG(WARNING) + << "Call to AudioOutputManager.getOutputDeviceInfo() failed."; return false; } @@ -171,9 +182,8 @@ int channels = MediaCapabilitiesCache::GetInstance()->GetMaxAudioOutputChannels(); if (channels < 2) { - SB_LOG(WARNING) - << "The supported channels from output device is smaller than 2. " - "Fallback to 2 channels"; + SB_LOG(WARNING) << "The supported channels from output device is " + << channels << ", set to 2 channels instead."; out_configuration->number_of_channels = 2; } else { out_configuration->number_of_channels = channels; @@ -182,5 +192,10 @@ out_configuration->number_of_channels = 2; } + SB_LOG(INFO) << "Audio connector type for index " << output_index << " is " + << GetMediaAudioConnectorName(out_configuration->connector) + << " and it has " << out_configuration->number_of_channels + << " channels."; + return true; }
diff --git a/starboard/android/shared/media_get_audio_output_count.cc b/starboard/android/shared/media_get_audio_output_count.cc index befefd3..0c4d473 100644 --- a/starboard/android/shared/media_get_audio_output_count.cc +++ b/starboard/android/shared/media_get_audio_output_count.cc
@@ -15,6 +15,9 @@ #include "starboard/media.h" int SbMediaGetAudioOutputCount() { - // Only supports one HDMI output. - return 1; + // TODO(b/284140486, b/297426689): Tentatively returns 16 to ensure that all + // audio output devices are checked in `IsAudioOutputSupported()`. We should + // revisit this, and probably remove `SbMediaGetAudioOutputCount()` completely + // from Starboard. + return 16; }
diff --git a/starboard/build/config/BUILD.gn b/starboard/build/config/BUILD.gn index 0c816e8..6a0290a 100644 --- a/starboard/build/config/BUILD.gn +++ b/starboard/build/config/BUILD.gn
@@ -92,7 +92,7 @@ config("target") { if (current_toolchain != host_toolchain) { if (final_executable_type == "shared_library") { - if (!build_with_separate_cobalt_toolchain) { + if (!sb_is_modular || sb_is_evergreen) { # Rewrite main() functions into StarboardMain. TODO: This is a # hack, it would be better to be more surgical, here. defines = [ "main=StarboardMain" ] @@ -229,7 +229,8 @@ # override flags specified in a platform's "platform_configuration" config, # which is where these particular flags would otherwise naturally fit. config("default_compiler_flags") { - if (is_starboardized_toolchain && sb_is_modular && target_cpu == "arm") { + if (is_starboardized_toolchain && sb_is_modular && + current_toolchain == cobalt_toolchain && target_cpu == "arm") { cflags = [ "-mfpu=vfpv3" ] asmflags = cflags }
diff --git a/starboard/build/config/BUILDCONFIG.gn b/starboard/build/config/BUILDCONFIG.gn index 6c7d409..4075ed3 100644 --- a/starboard/build/config/BUILDCONFIG.gn +++ b/starboard/build/config/BUILDCONFIG.gn
@@ -99,13 +99,7 @@ host_toolchain = "//starboard/build/toolchain/$host_os:$_host_toolchain_cpu" if (build_with_separate_cobalt_toolchain) { - # TODO(b/294450490): decide a way to set cobalt_toolchain for modular builds for all platforms. - # we'll need more conditionals for other platforms. - if (host_os == "win") { - cobalt_toolchain = "//$starboard_path/toolchain:cobalt" - } else { - cobalt_toolchain = "//starboard/build/toolchain:clang" - } + cobalt_toolchain = "//starboard/build/toolchain:clang" starboard_toolchain = "//$starboard_path/toolchain:starboard" } else { cobalt_toolchain = "//$starboard_path/toolchain:target" @@ -117,6 +111,9 @@ import("//$starboard_path/platform_configuration/configuration.gni") import("//starboard/build/config/build_assertions.gni") +# TODO(b/295399926) Clean up flag by moving to modular/helper_var.gni +sb_is_modular = sb_is_evergreen || build_with_separate_cobalt_toolchain + declare_args() { use_tsan = getenv("USE_TSAN") == 1 }
diff --git a/starboard/build/config/os_definitions.gni b/starboard/build/config/os_definitions.gni index 6a5747b..16c48ef 100644 --- a/starboard/build/config/os_definitions.gni +++ b/starboard/build/config/os_definitions.gni
@@ -31,3 +31,5 @@ is_apple = is_ios || is_mac is_posix = !is_win && !is_fuchsia + +is_host_win = host_os == "win" || host_os == "winuwp"
diff --git a/starboard/build/config/starboard_target_type.gni b/starboard/build/config/starboard_target_type.gni index 0c3983a..c1ebc17 100644 --- a/starboard/build/config/starboard_target_type.gni +++ b/starboard/build/config/starboard_target_type.gni
@@ -17,9 +17,36 @@ } if (starboard_target_type == "") { - if (build_with_separate_cobalt_toolchain) { + if (sb_is_modular && !sb_is_evergreen) { starboard_target_type = "shared_library" } else { starboard_target_type = "group" } } + +template("starboard_platform_target") { + target(starboard_target_type, target_name) { + forward_variables_from(invoker, [ "extra_configs" ]) + + if (defined(invoker.extra_configs)) { + configs += extra_configs + } + if (starboard_target_type == "shared_library") { + build_loader = false + } + public_deps = [ + "//starboard/client_porting/cwrappers", + "//starboard/client_porting/eztime", + "//starboard/common", + "//starboard/egl_and_gles", + ] + if (sb_is_evergreen_compatible) { + public_deps += [ "//third_party/crashpad/wrapper" ] + } else { + public_deps += [ "//third_party/crashpad/wrapper:wrapper_stub" ] + } + if (!sb_is_evergreen) { + public_deps += [ "//$starboard_path:starboard_platform" ] + } + } +}
diff --git a/starboard/build/toolchain/BUILD.gn b/starboard/build/toolchain/BUILD.gn index 2bfec6e..21a6a3c 100644 --- a/starboard/build/toolchain/BUILD.gn +++ b/starboard/build/toolchain/BUILD.gn
@@ -13,8 +13,59 @@ # limitations under the License. import("//build/config/clang/clang.gni") +import("//build/config/win/visual_studio_version.gni") import("//build/toolchain/gcc_toolchain.gni") +import("//starboard/build/config/os_definitions.gni") -clang_toolchain("clang") { - clang_base_path = clang_base_path +# Use this toolchain for linux-x64 platforms. +if (is_linux && !using_old_compiler && target_cpu == "x64") { + clang_toolchain("clang") { + clang_base_path = clang_base_path + } +} else { + import("//$starboard_path/toolchain/variables.gni") + assert( + defined(native_linker_path), + "native_linker_path should be defined in $starboard_path/toolchain/variables.gni") +} + +# Use this toolchain for raspi platforms, old linux compiler platforms. +if ((is_linux && target_cpu == "arm") || (using_old_compiler && !is_host_win)) { + gcc_toolchain("clang") { + prefix = rebase_path("$clang_base_path/bin", root_build_dir) + cc = "$prefix/clang" + cxx = "$prefix/clang++" + ld = native_linker_path + readelf = "readelf" + ar = "${prefix}/llvm-ar" + nm = "nm" + toolchain_args = { + is_clang = true + } + } +} + +# Use this toolchain for Windows based platforms. +if (is_host_win) { + gcc_toolchain("clang") { + prefix = llvm_clang_path + cc = "$prefix/clang.exe" + cxx = "$prefix/clang++.exe" + ld = native_linker_path + readelf = "$prefix/llvm-readobj.exe" + ar = "${prefix}/llvm-ar.exe" + nm = "${prefix}/llvm-nm.exe" + toolchain_args = { + is_clang = true + } + + executable_extension = native_executable_extension + shlib_extension = native_shlib_extension + if (defined(native_snarl_linker)) { + using_snarl_linker = true + } + toolchain_args = { + is_clang = true + } + } }
diff --git a/starboard/common/optional.h b/starboard/common/optional.h index 6c65763..f67609c 100644 --- a/starboard/common/optional.h +++ b/starboard/common/optional.h
@@ -21,7 +21,6 @@ #include "starboard/common/log.h" #include "starboard/configuration.h" -#include "starboard/export.h" #include "starboard/memory.h" namespace starboard { @@ -89,7 +88,7 @@ extern const in_place_t in_place; template <typename T> -class SB_EXPORT optional { +class optional { public: // Construction via the default constructor results in an optional that is // not engaged.
diff --git a/starboard/contrib/cast/README.md b/starboard/contrib/cast/README.md new file mode 100644 index 0000000..479ab3c --- /dev/null +++ b/starboard/contrib/cast/README.md
@@ -0,0 +1,53 @@ +## Cast Starboard API + +The Cast Starboard API is a shared library which contains the portion of +Starboard required to run Cast. + +### Customizations + +As of Starboard 15, there are public methods required for Cast that are not +already exposed by `libstarboard_platform_group.so`. As a result, the dedicated +header `cast_starboard_api.h` is omitted from this release, though it may +return in the future. + +Cast still requires additional behavior be implemented behind the existing +Starboard APIs. Reference the `Cast TV Integration Guide` for details. + +### Reference Implementation + +The `cast_starboard_api/samples/` directory contains the reference target +`cast_starboard_api` which can be built when both +`build_with_separate_cobalt_toolchain=true` and `use_contrib_cast=true` are +specified. To generate the target: + +``` +gn gen out/linux-x64x11_devel --args="target_platform=\"linux-x64x11\" build_with_separate_cobalt_toolchain=true use_contrib_cast=true build_type=\"devel\"" +``` + +To build the target: + +``` +ninja -C out/linux-x64x11_devel/ cast_starboard_api +``` + +### Test Suite + +Tests for Cast-specific behaviors are not currently included in NPLB or YTS. + +A limited test suite, `cast_starboard_api_test`, is provided to ensure the +standalone library can be initialized and a window surface can be created in the +format required by Cast. To build the test suite: + +``` +ninja -C out/linux-x64x11_devel/ cast_starboard_api_test +``` + +To run the test suite: + +``` +./out/linux-x64x11_devel/cast_starboard_api_test_loader +``` + +### Known Issues + +- When `build_type=\"devel\"`, some systems may SB_DCHECK in `NetworkNotifier`.
diff --git a/starboard/contrib/cast/cast.gni b/starboard/contrib/cast/cast.gni new file mode 100644 index 0000000..4a0cd3f --- /dev/null +++ b/starboard/contrib/cast/cast.gni
@@ -0,0 +1,5 @@ +declare_args() { + # Includes `//starboard/contrib/cast/cast_starboard_api/samples:cast` into + # `//starboard:gn_all`. + use_contrib_cast = false +}
diff --git a/starboard/contrib/cast/cast_starboard_api/samples/BUILD.gn b/starboard/contrib/cast/cast_starboard_api/samples/BUILD.gn new file mode 100644 index 0000000..a26bfa4 --- /dev/null +++ b/starboard/contrib/cast/cast_starboard_api/samples/BUILD.gn
@@ -0,0 +1,57 @@ +# Copyright 2023 The Cobalt Authors. All rights reserved. +import("//starboard/build/config/starboard_target_type.gni") +import("//starboard/contrib/cast/cast.gni") + +assert(build_with_separate_cobalt_toolchain && use_contrib_cast) + +group("cast") { + public_deps = [ ":cast_starboard_api($starboard_toolchain)" ] +} + +config("default") { + ldflags = [ + # Hide unwanted symbols, which also shrinks the resulting binary. + "-Wl,--version-script=" + + rebase_path("./cast_starboard_api.lds", root_build_dir), + ] + + if (!use_asan) { + ldflags += [ + # Prevent unresolved symbols, which would require the consumer of + # `cast_starboard_api` to be aware of transitive dependences at runtime. + "-Wl,-z,defs", + ] + } +} + +if (current_toolchain == starboard_toolchain) { + starboard_platform_target("cast_starboard_api") { + extra_configs = [ ":default" ] + } + + copy("cast_starboard_api_test_data") { + install_content = true + sources = [ "$root_out_dir/libcast_starboard_api.so" ] + + # This artifact is consumed by a test built outside of the + # starboard_toolchain; move from `starboard/content/` to `content/`. + outputs = [ + "$sb_static_contents_output_data_dir/../../content/{{source_file_part}}", + ] + deps = [ ":cast_starboard_api" ] + } +} + +target(gtest_target_type, "cast_starboard_api_test") { + testonly = true + sources = [ + "//starboard/common/test_main.cc", + "cast_starboard_api_test.cc", + ] + data_deps = [ ":cast_starboard_api_test_data($starboard_toolchain)" ] + deps = [ + "//starboard", + "//starboard/nplb/testdata/file_tests:nplb_file_tests_data", + "//testing/gtest", + ] +}
diff --git a/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api.lds b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api.lds new file mode 100644 index 0000000..b686799 --- /dev/null +++ b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api.lds
@@ -0,0 +1,9 @@ +# Copyright 2023 The Cobalt Authors. All rights reserved. +LIBCAST_STARBOARD_API { + global: + CastStarboardApi*; + kSb*; + Sb*; + local: + *; +};
diff --git a/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api_test.cc b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api_test.cc new file mode 100644 index 0000000..cc6ff4d --- /dev/null +++ b/starboard/contrib/cast/cast_starboard_api/samples/cast_starboard_api_test.cc
@@ -0,0 +1,271 @@ +// Copyright 2023 The Cobalt Authors. All rights reserved. + +#include <dlfcn.h> + +#include "starboard/common/condition_variable.h" +#include "starboard/common/log.h" +#include "starboard/common/mutex.h" +#include "starboard/common/thread.h" +#include "starboard/egl.h" +#include "starboard/event.h" +#include "starboard/file.h" +#include "starboard/gles.h" +#include "starboard/system.h" +#include "starboard/window.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class CastStarboardApiTest : public ::testing::Test { + public: + // This acts as a proxy to the Starboard implementation provided by + // `libcast_starboard_api.so`. + struct CastStarboardApi { + decltype(SbRunStarboardMain)* SbRunStarboardMain; + decltype(SbEventSchedule)* SbEventSchedule; + decltype(SbGetEglInterface)* SbGetEglInterface; + decltype(SbGetGlesInterface)* SbGetGlesInterface; + decltype(SbWindowCreate)* SbWindowCreate; + decltype(SbWindowDestroy)* SbWindowDestroy; + decltype(SbWindowGetPlatformHandle)* SbWindowGetPlatformHandle; + decltype(SbSystemRequestStop)* SbSystemRequestStop; + }; + + CastStarboardApiTest(); + ~CastStarboardApiTest(); + + // Receives events from the static |EventHandle|. If |event| is non-null, + // add its type to |received_| so tests can see it. If |event| is null, + // then it was a manually scheduled event and we signal |received_cond_|. + void EventHandleInternal(const SbEvent* event); + + // Waits until |received_cond_| has been signalled; used to ensure the event + // loop is running. + void WaitForEventCallback(); + + // Signals |received_cond_|. + void EventCallbackInternal(); + + CastStarboardApi& api() { return api_; } + const std::vector<SbEventType>& events() { return received_; } + + private: + class CastStarboardApiThread : public starboard::Thread { + public: + explicit CastStarboardApiThread(CastStarboardApi* api) + : starboard::Thread("cast_thread"), api_(api) {} + + void Run() override; + + private: + CastStarboardApi* api_; + }; + + template <class FuncType> + void DlSym(void* lib, const char* func_name, FuncType* func) { + *func = (FuncType)(dlsym(lib, func_name)); + EXPECT_NE(func, nullptr) << func_name << " could not be loaded"; + } + + CastStarboardApi api_; + + // These properties are used to initialize the main Starboard thread. + std::unique_ptr<CastStarboardApiThread> sb_thread_; + std::unique_ptr<starboard::ConditionVariable> started_cond_; + starboard::Mutex started_mutex_; + + // These properties are used to track event dispatch during tests. + std::vector<SbEventType> received_; + starboard::Mutex received_mutex_; + std::unique_ptr<starboard::ConditionVariable> received_cond_; +}; + +// A behavior in the default implementation prevents dlclose from being used on +// this library, so we must only open it once. +void* g_lib = nullptr; + +// |EventHandleStatic| must be able to operate on the |g_test_instance|, so it's +// tracked here. +CastStarboardApiTest* g_test_instance = nullptr; + +// Static callback for SbEvent(s); forwards to |EventHandleInternal|. +void EventHandleStatic(const SbEvent* event) { + g_test_instance->EventHandleInternal(event); +} + +// Static callback for manually scheduled events; forwards to +// |EventHandleInternal|. +void EventCallbackStatic(void* context) { + static_cast<CastStarboardApiTest*>(context)->EventCallbackInternal(); +} + +CastStarboardApiTest::CastStarboardApiTest() { + g_test_instance = this; + started_cond_ = + std::make_unique<starboard::ConditionVariable>(started_mutex_); + received_cond_ = + std::make_unique<starboard::ConditionVariable>(received_mutex_); + + // Ensure libcast_starboard_api.so has been opened. + if (!g_lib) { + std::vector<char> content_path(kSbFileMaxPath + 1); + EXPECT_TRUE(SbSystemGetPath(kSbSystemPathContentDirectory, + content_path.data(), kSbFileMaxPath + 1)); + const std::string lib_path = std::string(content_path.data()) + + kSbFileSepChar + "libcast_starboard_api.so"; + g_lib = dlopen(lib_path.c_str(), RTLD_LAZY); + EXPECT_NE(g_lib, nullptr) + << lib_path << " could not be loaded: " << dlerror(); + } + + // Assign the |api_| methods. + DlSym(g_lib, "SbRunStarboardMain", &api_.SbRunStarboardMain); + DlSym(g_lib, "SbEventSchedule", &api_.SbEventSchedule); + DlSym(g_lib, "SbGetEglInterface", &api_.SbGetEglInterface); + DlSym(g_lib, "SbGetGlesInterface", &api_.SbGetGlesInterface); + DlSym(g_lib, "SbWindowCreate", &api_.SbWindowCreate); + DlSym(g_lib, "SbWindowDestroy", &api_.SbWindowDestroy); + DlSym(g_lib, "SbWindowGetPlatformHandle", &api_.SbWindowGetPlatformHandle); + DlSym(g_lib, "SbSystemRequestStop", &api_.SbSystemRequestStop); + + // Start the Starboard thread and wait for kSbEventTypeStart to propagate. + sb_thread_ = std::make_unique<CastStarboardApiThread>(&api_); + sb_thread_->Start(); + + // Watch event for initialation completion. + started_mutex_.Acquire(); + started_cond_->Wait(); + started_mutex_.Release(); +} + +CastStarboardApiTest::~CastStarboardApiTest() { + api().SbSystemRequestStop(0); + sb_thread_->Join(); + sb_thread_.reset(); + started_cond_.reset(); + g_test_instance = nullptr; +} + +void CastStarboardApiTest::EventHandleInternal(const SbEvent* event) { + switch (event->type) { + case kSbEventTypeStart: + started_cond_->Signal(); + break; + default: + break; + } + + received_.push_back(event->type); +} + +void CastStarboardApiTest::EventCallbackInternal() { + received_cond_->Signal(); +} + +void CastStarboardApiTest::WaitForEventCallback() { + received_mutex_.Acquire(); + received_cond_->Wait(); + received_mutex_.Release(); +} + +void CastStarboardApiTest::CastStarboardApiThread::Run() { + api_->SbRunStarboardMain(0, nullptr, &EventHandleStatic); +} + +// The default Application only be started once in the lifetime of the +// executable. To simplify and avoid race conditions in the test framework, both +// test scenarios are implemented in a single test case. +TEST_F(CastStarboardApiTest, EventLoop_CastWindowSurface) { + // Test 1: + // Ensure the event loop is running after initialization, and that SbEvent(s) + // are being received. Effectively tests |SbRunStarboardMain|. + api().SbEventSchedule(&EventCallbackStatic, this, 0); + WaitForEventCallback(); + EXPECT_FALSE(events().empty()); + EXPECT_EQ(events().front(), kSbEventTypeStart); + + // Test 2: + // Ensure that a window surface can be created which supports the config + // required by Cast. + const SbEglInterface* egl = api().SbGetEglInterface(); + + // Cast expects `SB_EGL_DEFAULT_DISPLAY` to refer to the correct display. + SbEglDisplay display = egl->eglGetDisplay(SB_EGL_DEFAULT_DISPLAY); + EXPECT_TRUE(egl->eglInitialize(display, nullptr, nullptr)) + << "Failed eglInitialize for display: " << egl->eglGetError(); + + SbWindow window = api().SbWindowCreate(nullptr); + SbEglNativeWindowType window_type = reinterpret_cast<SbEglNativeWindowType>( + api().SbWindowGetPlatformHandle(window)); + + SbEglInt32 config_attribs[] = {SB_EGL_BUFFER_SIZE, + 32, + SB_EGL_ALPHA_SIZE, + 8, + SB_EGL_BLUE_SIZE, + 8, + SB_EGL_GREEN_SIZE, + 8, + SB_EGL_RED_SIZE, + 8, + SB_EGL_RENDERABLE_TYPE, + SB_EGL_OPENGL_ES2_BIT, + SB_EGL_SURFACE_TYPE, + SB_EGL_WINDOW_BIT, + SB_EGL_NONE}; + + int32_t num_configs; + EXPECT_TRUE( + egl->eglChooseConfig(display, config_attribs, nullptr, 0, &num_configs)) + << "Failed eglChooseConfig for the specified config_attribs: " + << egl->eglGetError(); + EXPECT_NE(num_configs, 0) << "No suitable EGL configs found."; + + std::unique_ptr<SbEglConfig[]> configs(new SbEglConfig[num_configs]); + EXPECT_TRUE(egl->eglChooseConfig(display, config_attribs, configs.get(), + num_configs, &num_configs)) + << "Failed eglChooseConfig: " << egl->eglGetError(); + + SbEglSurface surface = nullptr; + SbEglConfig config; + for (int i = 0; i < num_configs; i++) { + surface = + egl->eglCreateWindowSurface(display, configs[i], window_type, NULL); + if (surface) { + config = configs[i]; + egl->eglDestroySurface(display, surface); + break; + } + } + + EXPECT_NE(surface, nullptr) + << "Failed eglCreateWindowSurface for all configs: " + << egl->eglGetError(); + const SbGlesInterface* gles = api().SbGetGlesInterface(); + + const SbEglInt32 context_attribs[] = {SB_EGL_CONTEXT_CLIENT_VERSION, 2, + SB_EGL_NONE}; + + SbEglContext context = + egl->eglCreateContext(display, config, NULL, context_attribs); + egl->eglMakeCurrent(display, SB_EGL_NO_SURFACE, SB_EGL_NO_SURFACE, context); + std::string version( + reinterpret_cast<const char*>(gles->glGetString(SB_GL_VERSION))); + const std::string prefix = "OpenGL ES "; + EXPECT_TRUE(version.find(prefix, 0) == 0); + EXPECT_GT(version.length(), prefix.length() + 1); + + char actual_version = version.at(prefix.length()); + if (!(actual_version == '2' || actual_version == '3')) { + // Normally we could check whether gles->glGetStringi (or other OpenGL 3+ + // functions) are non-null, but various Starboard implementations actually + // report the underlying version even if OpenGL 3+ functions are not + // exposed. Cast will automatically treat any valid OpenGL 2+ version as + // OpenGL ES 2.0. + FAIL() << "Expected OpenGL ES 2 or 3."; + } + + api().SbWindowDestroy(window); +} + +} // namespace
diff --git a/starboard/evergreen/shared/platform_configuration/BUILD.gn b/starboard/evergreen/shared/platform_configuration/BUILD.gn index 01ac96f..2340c86 100644 --- a/starboard/evergreen/shared/platform_configuration/BUILD.gn +++ b/starboard/evergreen/shared/platform_configuration/BUILD.gn
@@ -28,7 +28,7 @@ "-Wl,-u GetEvergreenSabiString", ] - if (!build_with_separate_cobalt_toolchain) { + if (sb_is_evergreen) { ldflags += [ "-nostdlib" ] } cflags = [
diff --git a/starboard/evergreen/shared/platform_configuration/configuration.gni b/starboard/evergreen/shared/platform_configuration/configuration.gni index c76baea..4327e1d 100644 --- a/starboard/evergreen/shared/platform_configuration/configuration.gni +++ b/starboard/evergreen/shared/platform_configuration/configuration.gni
@@ -14,9 +14,7 @@ import("//starboard/build/config/base_configuration.gni") -sb_is_modular = true - -sb_is_evergreen = true +sb_is_evergreen = !build_with_separate_cobalt_toolchain cobalt_font_package = "empty"
diff --git a/starboard/extension/BUILD.gn b/starboard/extension/BUILD.gn index 5212664..57b95b1 100644 --- a/starboard/extension/BUILD.gn +++ b/starboard/extension/BUILD.gn
@@ -26,7 +26,7 @@ "//testing/gmock", "//testing/gtest", ] - if (sb_is_modular) { + if (sb_is_modular && current_toolchain == cobalt_toolchain) { deps += cobalt_platform_dependencies } }
diff --git a/starboard/linux/shared/BUILD.gn b/starboard/linux/shared/BUILD.gn index 065f2c4..57b7908 100644 --- a/starboard/linux/shared/BUILD.gn +++ b/starboard/linux/shared/BUILD.gn
@@ -428,13 +428,15 @@ build_loader = false testonly = true - sources = media_tests_sources + player_tests_sources + - [ "//starboard/common/test_main.cc" ] + sources = media_tests_sources + player_tests_sources + [ + "//starboard/common/test_main.cc", + "//starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc", + ] configs += [ "//starboard/build/config:starboard_implementation" ] deps = [ - "//starboard", + "//starboard:starboard_with_main", "//starboard/shared/starboard/player/filter/testing:test_util", "//testing/gmock", "//testing/gtest",
diff --git a/starboard/linux/shared/launcher.py b/starboard/linux/shared/launcher.py index 022073a..10cdbde 100644 --- a/starboard/linux/shared/launcher.py +++ b/starboard/linux/shared/launcher.py
@@ -31,8 +31,6 @@ # This file is still executed with Python2 in CI. # pylint:disable=consider-using-f-string,super-with-arguments -IS_MODULAR_BUILD = os.getenv("MODULAR_BUILD", "0") == "1" - def GetProcessStatus(pid): """Returns process running status given its pid, or empty string if not found. @@ -63,7 +61,7 @@ self.device_ip = socket.gethostbyname(socket.gethostname()) self.executable = self.GetTargetPath() - if IS_MODULAR_BUILD: + if abstract_launcher.IS_MODULAR_BUILD: self.executable += "_loader" if not os.path.exists(self.executable): self.executable = os.path.abspath(
diff --git a/starboard/linux/shared/media_is_audio_supported.cc b/starboard/linux/shared/media_is_audio_supported.cc index 8d2e637..d857bd5 100644 --- a/starboard/linux/shared/media_is_audio_supported.cc +++ b/starboard/linux/shared/media_is_audio_supported.cc
@@ -49,6 +49,12 @@ if (audio_codec == kSbMediaAudioCodecMp3) { return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond; } + if (audio_codec == kSbMediaAudioCodecPcm) { + return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond; + } + if (audio_codec == kSbMediaAudioCodecFlac) { + return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond; + } #endif // SB_API_VERSION >= 14 return false;
diff --git a/starboard/linux/shared/platform_configuration/BUILD.gn b/starboard/linux/shared/platform_configuration/BUILD.gn index 87ea329..4e7334a 100644 --- a/starboard/linux/shared/platform_configuration/BUILD.gn +++ b/starboard/linux/shared/platform_configuration/BUILD.gn
@@ -63,8 +63,8 @@ # Do not warn about unused function params. "-Wno-unused-parameter", ] - if (build_with_separate_cobalt_toolchain) { - # If we're building modularly, we need visibility. + if (sb_is_modular && !sb_is_evergreen) { + # If we're building with cobalt toolchain and native linker, we need visibility. cflags += [ "-fvisibility=default" ] } else { # Default visibility to hidden, to enable dead stripping. @@ -143,7 +143,7 @@ "rt", ] - if (!sb_is_modular) { + if (!sb_is_modular || current_toolchain != cobalt_toolchain) { ldflags += [ "-static-libstdc++" ] }
diff --git a/starboard/linux/x64x11/BUILD.gn b/starboard/linux/x64x11/BUILD.gn index ad6b13a..3666f36 100644 --- a/starboard/linux/x64x11/BUILD.gn +++ b/starboard/linux/x64x11/BUILD.gn
@@ -15,7 +15,10 @@ static_library("starboard_platform") { check_includes = false - sources = [ "//starboard/linux/x64x11/main.cc" ] + sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ] + if (!sb_is_modular || sb_is_evergreen) { + sources += [ "//starboard/linux/x64x11/main.cc" ] + } public_deps = [ "//starboard/linux/x64x11/shared:starboard_platform", @@ -24,3 +27,12 @@ configs += [ "//starboard/build/config:starboard_implementation" ] } + +if (sb_is_modular && !sb_is_evergreen) { + static_library("starboard_platform_with_main") { + check_includes = false + sources = [ "//starboard/linux/x64x11/main.cc" ] + configs += [ "//starboard/build/config:starboard_implementation" ] + public_deps = [ ":starboard_platform" ] + } +}
diff --git a/starboard/linux/x64x11/clang/3.9/BUILD.gn b/starboard/linux/x64x11/clang/3.9/BUILD.gn index ba56f59..f947b50 100644 --- a/starboard/linux/x64x11/clang/3.9/BUILD.gn +++ b/starboard/linux/x64x11/clang/3.9/BUILD.gn
@@ -15,7 +15,10 @@ static_library("starboard_platform") { check_includes = false - sources = [ "//starboard/linux/x64x11/main.cc" ] + sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ] + if (!sb_is_modular || sb_is_evergreen) { + sources += [ "//starboard/linux/x64x11/main.cc" ] + } public_deps = [ "//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/linux/x64x11/egl/BUILD.gn b/starboard/linux/x64x11/egl/BUILD.gn index ad6b13a..91ed007 100644 --- a/starboard/linux/x64x11/egl/BUILD.gn +++ b/starboard/linux/x64x11/egl/BUILD.gn
@@ -15,7 +15,10 @@ static_library("starboard_platform") { check_includes = false - sources = [ "//starboard/linux/x64x11/main.cc" ] + sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ] + if (!sb_is_modular || sb_is_evergreen) { + sources += [ "//starboard/linux/x64x11/main.cc" ] + } public_deps = [ "//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/linux/x64x11/gcc/6.3/BUILD.gn b/starboard/linux/x64x11/gcc/6.3/BUILD.gn index ba56f59..f947b50 100644 --- a/starboard/linux/x64x11/gcc/6.3/BUILD.gn +++ b/starboard/linux/x64x11/gcc/6.3/BUILD.gn
@@ -15,7 +15,10 @@ static_library("starboard_platform") { check_includes = false - sources = [ "//starboard/linux/x64x11/main.cc" ] + sources = [ "//starboard/linux/x64x11/run_starboard_main.cc" ] + if (!sb_is_modular || sb_is_evergreen) { + sources += [ "//starboard/linux/x64x11/main.cc" ] + } public_deps = [ "//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/linux/x64x11/main.cc b/starboard/linux/x64x11/main.cc index 82046a0..5cfd197 100644 --- a/starboard/linux/x64x11/main.cc +++ b/starboard/linux/x64x11/main.cc
@@ -53,6 +53,7 @@ return 1; } +#if !SB_IS(MODULAR) bool start_handler_at_crash = command_line.HasSwitch( starboard::shared::starboard::kStartHandlerAtCrash) || @@ -60,6 +61,7 @@ starboard::shared::starboard::kStartHandlerAtLaunch); third_party::crashpad::wrapper::InstallCrashpadHandler(start_handler_at_crash, ca_certificates_path); +#endif // !SB_IS(MODULAR) #endif #if SB_HAS_QUIRK(BACKTRACE_DLOPEN_BUG) @@ -83,15 +85,3 @@ starboard::shared::signal::UninstallCrashSignalHandlers(); return result; } - -#if SB_API_VERSION >= 15 -int SbRunStarboardMain(int argc, char** argv, SbEventHandleCallback callback) { - starboard::shared::x11::ApplicationX11 application(callback); - int result = 0; - { - starboard::shared::starboard::LinkReceiver receiver(&application); - result = application.Run(argc, argv); - } - return result; -} -#endif // SB_API_VERSION >= 15
diff --git a/starboard/linux/x64x11/run_starboard_main.cc b/starboard/linux/x64x11/run_starboard_main.cc new file mode 100644 index 0000000..813e1df --- /dev/null +++ b/starboard/linux/x64x11/run_starboard_main.cc
@@ -0,0 +1,30 @@ +// Copyright 2023 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 "starboard/event.h" + +#include "starboard/shared/starboard/link_receiver.h" +#include "starboard/shared/x11/application_x11.h" + +#if SB_API_VERSION >= 15 +int SbRunStarboardMain(int argc, char** argv, SbEventHandleCallback callback) { + starboard::shared::x11::ApplicationX11 application(callback); + int result = 0; + { + starboard::shared::starboard::LinkReceiver receiver(&application); + result = application.Run(argc, argv); + } + return result; +} +#endif // SB_API_VERSION >= 15
diff --git a/starboard/linux/x64x11/shared/BUILD.gn b/starboard/linux/x64x11/shared/BUILD.gn index d58d764..2da6b40 100644 --- a/starboard/linux/x64x11/shared/BUILD.gn +++ b/starboard/linux/x64x11/shared/BUILD.gn
@@ -45,7 +45,7 @@ "//starboard/shared/x11/window_internal.cc", ] - if (!build_with_separate_cobalt_toolchain) { + if (!sb_is_modular || sb_is_evergreen) { sources += [ "//starboard/linux/x64x11/sanitizer_options.cc" ] }
diff --git a/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn b/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn index 32c24f6..ab9cf36 100644 --- a/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn +++ b/starboard/linux/x64x11/shared/platform_configuration/BUILD.gn
@@ -13,8 +13,8 @@ # limitations under the License. config("platform_configuration") { - if (current_toolchain == default_toolchain && - build_with_separate_cobalt_toolchain) { + if (current_toolchain == default_toolchain && sb_is_modular && + !sb_is_evergreen) { configs = [ "//starboard/evergreen/x64/platform_configuration" ] } else { configs = [ @@ -28,7 +28,7 @@ config("libraries") { configs = [ "//starboard/linux/shared/platform_configuration:libraries" ] - if (build_with_separate_cobalt_toolchain) { + if (sb_is_modular && !sb_is_evergreen) { libs = [ "//third_party/libvpx/platforms/linux-x64/libvpx.so.6" ] ldflags = [ "-Wl,-rpath=" + rebase_path("//") + "/third_party/libvpx/platforms/linux-x64/" ]
diff --git a/starboard/linux/x64x11/skia/BUILD.gn b/starboard/linux/x64x11/skia/BUILD.gn index 024e560..66917ea 100644 --- a/starboard/linux/x64x11/skia/BUILD.gn +++ b/starboard/linux/x64x11/skia/BUILD.gn
@@ -16,11 +16,14 @@ check_includes = false sources = [ - "//starboard/linux/x64x11/main.cc", + "//starboard/linux/x64x11/run_starboard_main.cc", "//starboard/linux/x64x11/skia/configuration.cc", "//starboard/linux/x64x11/skia/configuration.h", "//starboard/linux/x64x11/skia/system_get_extensions.cc", ] + if (!sb_is_modular || sb_is_evergreen) { + sources += [ "//starboard/linux/x64x11/main.cc" ] + } public_deps = [ "//starboard/linux/x64x11/shared:starboard_platform",
diff --git a/starboard/loader_app/BUILD.gn b/starboard/loader_app/BUILD.gn index 4d38cce..e0384a1 100644 --- a/starboard/loader_app/BUILD.gn +++ b/starboard/loader_app/BUILD.gn
@@ -106,6 +106,7 @@ deps = [ ":common_loader_app_dependencies", "//cobalt/content/fonts:copy_font_data", + "//starboard:starboard_with_main", "//starboard/elf_loader", ] if (sb_is_evergreen_compatible && sb_evergreen_compatible_package) {
diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn index 08e415a..664751b 100644 --- a/starboard/nplb/BUILD.gn +++ b/starboard/nplb/BUILD.gn
@@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//starboard/build/config/os_definitions.gni") + target(gtest_target_type, "nplb") { testonly = true @@ -268,4 +270,31 @@ # signedness_and_size_of_enum_test.cc casts -1 to enum value cflags = [ "-Wno-enum-constexpr-conversion" ] } + + # TODO b/296238576 Add these tests for windows based platform modular builds + if (sb_is_modular && !sb_is_evergreen && is_host_win) { + sources -= [ + "maximum_player_configuration_explorer.cc", + "maximum_player_configuration_explorer.h", + "maximum_player_configuration_explorer_test.cc", + "media_buffer_test.cc", + "media_set_audio_write_duration_test.cc", + "player_create_test.cc", + "player_creation_param_helpers.cc", + "player_creation_param_helpers.h", + "player_get_audio_configuration_test.cc", + "player_get_preferred_output_mode_test.cc", + "player_test_fixture.cc", + "player_test_fixture.h", + "player_test_util.cc", + "player_test_util.h", + "player_write_sample_test.cc", + "vertical_video_test.cc", + ] + + deps -= [ + "//starboard/shared/starboard/media:media_util", + "//starboard/shared/starboard/player:video_dmp", + ] + } }
diff --git a/starboard/nplb/media_can_play_mime_and_key_system_test.cc b/starboard/nplb/media_can_play_mime_and_key_system_test.cc index 2a5594e..a77a4e9 100644 --- a/starboard/nplb/media_can_play_mime_and_key_system_test.cc +++ b/starboard/nplb/media_can_play_mime_and_key_system_test.cc
@@ -72,6 +72,21 @@ return kDeviceTypeFHD; } +testing::AssertionResult IsMimeAndKeySystemSupported(std::string param, + std::string key_system) { + SbMediaSupportType support_type = + SbMediaCanPlayMimeAndKeySystem(param.c_str(), key_system.c_str()); + if (support_type == kSbMediaSupportTypeProbably) { + return testing::AssertionSuccess(); + } + + return testing::AssertionFailure() + << "SbMediaCanPlayMimeAndKeySystem(\"" << param << "\", \"" + << key_system << "\") returns " << support_type + << ". It should return kSbMediaSupportTypeProbably (" + << kSbMediaSupportTypeProbably << ")."; +} + TEST(SbMediaCanPlayMimeAndKeySystem, SunnyDay) { // Vp9 SbMediaCanPlayMimeAndKeySystem( @@ -292,20 +307,20 @@ mime_params = params_fhd; } + const char* key_system = ""; for (auto& param : mime_params) { - SbMediaSupportType support = SbMediaCanPlayMimeAndKeySystem(param, ""); - EXPECT_TRUE(support == kSbMediaSupportTypeProbably); + EXPECT_TRUE(IsMimeAndKeySystemSupported(param, key_system)); } // AAC-LC - SbMediaSupportType result = SbMediaCanPlayMimeAndKeySystem( - "audio/mp4; codecs=\"mp4a.40.2\"; channels=2; bitrate=256000;", ""); - ASSERT_EQ(result, kSbMediaSupportTypeProbably); + ASSERT_TRUE(IsMimeAndKeySystemSupported( + "audio/mp4; codecs=\"mp4a.40.2\"; channels=2; bitrate=256000", + key_system)); // HE-AAC - result = SbMediaCanPlayMimeAndKeySystem( - "audio/mp4; codecs=\"mp4a.40.5\"; channels=2; bitrate=48000;", ""); - ASSERT_EQ(result, kSbMediaSupportTypeProbably); + ASSERT_TRUE(IsMimeAndKeySystemSupported( + "audio/mp4; codecs=\"mp4a.40.5\"; channels=2; bitrate=48000", + key_system)); } TEST(SbMediaCanPlayMimeAndKeySystem, AnySupportedKeySystems) {
diff --git a/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc index 17937fa..4cf444b 100644 --- a/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc +++ b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc
@@ -20,6 +20,7 @@ #include "starboard/audio_sink.h" #include "starboard/common/log.h" #include "starboard/common/string.h" +#include "starboard/media.h" #include "starboard/memory.h" #include "starboard/shared/starboard/media/media_util.h" @@ -36,7 +37,10 @@ return kSbMediaAudioSampleTypeInt16Deprecated; } -AVCodecID GetFfmpegCodecIdByMediaCodec(SbMediaAudioCodec audio_codec) { +AVCodecID GetFfmpegCodecIdByMediaCodec( + starboard::media::AudioStreamInfo stream_info) { + SbMediaAudioCodec audio_codec = stream_info.codec; + switch (audio_codec) { case kSbMediaAudioCodecAac: return AV_CODEC_ID_AAC; @@ -57,6 +61,24 @@ #if SB_API_VERSION >= 14 case kSbMediaAudioCodecMp3: return AV_CODEC_ID_MP3; + case kSbMediaAudioCodecPcm: + if (stream_info.bits_per_sample == 16) { + return AV_CODEC_ID_PCM_S16LE; + } else { + SB_LOG(ERROR) << "PCM is only supported for 16-bit audio (" + << stream_info.bits_per_sample + << " bits per sample was requested)"; + return AV_CODEC_ID_NONE; + } + case kSbMediaAudioCodecFlac: + if (stream_info.bits_per_sample == 16) { + return AV_CODEC_ID_FLAC; + } else { + SB_LOG(ERROR) << "FLAC is only supported for 16-bit audio (" + << stream_info.bits_per_sample + << " bits per sample was requested)"; + return AV_CODEC_ID_NONE; + } #endif // SB_API_VERSION >= 14 default: return AV_CODEC_ID_NONE; @@ -78,7 +100,7 @@ stream_ended_(false), audio_stream_info_(audio_stream_info) { SB_DCHECK(g_registered) << "Decoder Specialization registration failed."; - SB_DCHECK(GetFfmpegCodecIdByMediaCodec(audio_stream_info_.codec) != + SB_DCHECK(GetFfmpegCodecIdByMediaCodec(audio_stream_info_) != AV_CODEC_ID_NONE) << "Unsupported audio codec " << audio_stream_info_.codec; ffmpeg_ = FFMPEGDispatch::GetInstance(); @@ -277,10 +299,16 @@ } codec_context_->codec_type = AVMEDIA_TYPE_AUDIO; - codec_context_->codec_id = - GetFfmpegCodecIdByMediaCodec(audio_stream_info_.codec); + codec_context_->codec_id = GetFfmpegCodecIdByMediaCodec(audio_stream_info_); // Request_sample_fmt is set by us, but sample_fmt is set by the decoder. - if (GetSupportedSampleType() == kSbMediaAudioSampleTypeInt16Deprecated) { + if (GetSupportedSampleType() == kSbMediaAudioSampleTypeInt16Deprecated +#if SB_API_VERSION >= 14 + // If we request FLT for 16-bit FLAC, FFmpeg will pick S32 as the closest + // option. Since the rest of this pipeline doesn't support S32, we should + // use S16 as the desired format. + || audio_stream_info_.codec == kSbMediaAudioCodecFlac +#endif // SB_API_VERSION >= 14 + ) { codec_context_->request_sample_fmt = AV_SAMPLE_FMT_S16; } else { codec_context_->request_sample_fmt = AV_SAMPLE_FMT_FLT;
diff --git a/starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc new file mode 100644 index 0000000..c009bb4 --- /dev/null +++ b/starboard/shared/ffmpeg/ffmpeg_audio_decoder_test.cc
@@ -0,0 +1,84 @@ +// Copyright 2023 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 "starboard/shared/ffmpeg/ffmpeg_audio_decoder.h" + +#include <memory> + +#include "starboard/media.h" +#include "starboard/shared/starboard/media/media_util.h" +#include "starboard/shared/starboard/player/job_queue.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace shared { +namespace ffmpeg { +namespace { + +// The codecs tested by these tests were introduced in SB_API_VERSION 14. +#if SB_API_VERSION >= 14 +using ::starboard::shared::starboard::media::AudioStreamInfo; +using ::testing::NotNull; + +AudioStreamInfo CreateStreamInfoForCodec(SbMediaAudioCodec codec) { + AudioStreamInfo stream_info; + stream_info.codec = codec; + stream_info.number_of_channels = 2; + stream_info.samples_per_second = 44100; + stream_info.bits_per_sample = 8; + return stream_info; +} + +class FFmpegAudioDecoderTest + : public ::testing::Test, + public ::starboard::shared::starboard::player::JobQueue::JobOwner { + protected: + FFmpegAudioDecoderTest() : JobOwner(kDetached) { AttachToCurrentThread(); } + + ~FFmpegAudioDecoderTest() override = default; + + // Create a JobQueue for use on the current thread. + ::starboard::shared::starboard::player::JobQueue job_queue_; +}; + +TEST_F(FFmpegAudioDecoderTest, SupportsMp3Codec) { + AudioStreamInfo stream_info = CreateStreamInfoForCodec(kSbMediaAudioCodecMp3); + std::unique_ptr<AudioDecoder> decoder(AudioDecoder::Create(stream_info)); + ASSERT_THAT(decoder, NotNull()); + EXPECT_TRUE(decoder->is_valid()); +} + +TEST_F(FFmpegAudioDecoderTest, SupportsFlacCodecFor16BitAudio) { + AudioStreamInfo stream_info = + CreateStreamInfoForCodec(kSbMediaAudioCodecFlac); + stream_info.bits_per_sample = 16; + std::unique_ptr<AudioDecoder> decoder(AudioDecoder::Create(stream_info)); + ASSERT_THAT(decoder, NotNull()); + EXPECT_TRUE(decoder->is_valid()); +} + +TEST_F(FFmpegAudioDecoderTest, SupportsPcmCodecFor16BitAudio) { + AudioStreamInfo stream_info = CreateStreamInfoForCodec(kSbMediaAudioCodecPcm); + stream_info.bits_per_sample = 16; + std::unique_ptr<AudioDecoder> decoder(AudioDecoder::Create(stream_info)); + ASSERT_THAT(decoder, NotNull()); + EXPECT_TRUE(decoder->is_valid()); +} +#endif // SB_API_VERSION >= 14 + +} // namespace +} // namespace ffmpeg +} // namespace shared +} // namespace starboard
diff --git a/starboard/shared/starboard/crash_handler.cc b/starboard/shared/starboard/crash_handler.cc index a9c998f..e1fec16 100644 --- a/starboard/shared/starboard/crash_handler.cc +++ b/starboard/shared/starboard/crash_handler.cc
@@ -29,7 +29,11 @@ } bool SetString(const char* key, const char* value) { +#if SB_IS(MODULAR) + return false; +#else return third_party::crashpad::wrapper::InsertCrashpadAnnotation(key, value); +#endif // SB_IS(MODULAR) } const CobaltExtensionCrashHandlerApi kCrashHandlerApi = {
diff --git a/starboard/shared/starboard/media/codec_util.cc b/starboard/shared/starboard/media/codec_util.cc index 291bee1..1c2c1b3 100644 --- a/starboard/shared/starboard/media/codec_util.cc +++ b/starboard/shared/starboard/media/codec_util.cc
@@ -103,6 +103,11 @@ if (strcmp(codec, "flac") == 0) { return kSbMediaAudioCodecFlac; } + // For WAV, the "codecs" parameter of a MIME type refers to the WAVE format + // ID, where 1 represents PCM: https://datatracker.ietf.org/doc/html/rfc2361 + if (strcmp(codec, "1") == 0) { + return kSbMediaAudioCodecPcm; + } #endif // SB_API_VERSION >= 14 #if SB_API_VERSION >= 15 if (strncmp(codec, "iamf.", 5) == 0) {
diff --git a/starboard/shared/starboard/media/media_tests.gni b/starboard/shared/starboard/media/media_tests.gni index a720a48..4777863 100644 --- a/starboard/shared/starboard/media/media_tests.gni +++ b/starboard/shared/starboard/media/media_tests.gni
@@ -17,6 +17,7 @@ "//starboard/shared/starboard/media/codec_util_test.cc", "//starboard/shared/starboard/media/media_util_test.cc", "//starboard/shared/starboard/media/mime_type_test.cc", + "//starboard/shared/starboard/media/mime_util_test.cc", "//starboard/shared/starboard/media/video_capabilities_test.cc", "//starboard/shared/starboard/media/vp9_util_test.cc", ]
diff --git a/starboard/shared/starboard/media/mime_util.cc b/starboard/shared/starboard/media/mime_util.cc index fe49830..0ef4b2d 100644 --- a/starboard/shared/starboard/media/mime_util.cc +++ b/starboard/shared/starboard/media/mime_util.cc
@@ -37,12 +37,15 @@ // Use SbMediaGetAudioConfiguration() to check if the platform can support // |channels|. bool IsAudioOutputSupported(SbMediaAudioCodingType coding_type, int channels) { + // TODO(b/284140486, b/297426689): Consider removing the call to + // `SbMediaGetAudioOutputCount()` completely as the loop will be terminated + // once `SbMediaGetAudioConfiguration()` returns false. int count = SbMediaGetAudioOutputCount(); for (int output_index = 0; output_index < count; ++output_index) { SbMediaAudioConfiguration configuration; if (!SbMediaGetAudioConfiguration(output_index, &configuration)) { - continue; + break; } if (configuration.coding_type == coding_type && @@ -99,9 +102,20 @@ break; #if SB_API_VERSION >= 14 case kSbMediaAudioCodecMp3: + if (mime_type.subtype() != "mpeg" && mime_type.subtype() != "mp3") { + return false; + } + break; case kSbMediaAudioCodecFlac: + if (mime_type.subtype() != "ogg" && mime_type.subtype() != "flac") { + return false; + } + break; case kSbMediaAudioCodecPcm: - return false; + if (mime_type.subtype() != "wav") { + return false; + } + break; #endif // SB_API_VERSION >= 14 #if SB_API_VERSION >= 15 case kSbMediaAudioCodecIamf:
diff --git a/starboard/shared/starboard/media/mime_util_test.cc b/starboard/shared/starboard/media/mime_util_test.cc new file mode 100644 index 0000000..14784e6 --- /dev/null +++ b/starboard/shared/starboard/media/mime_util_test.cc
@@ -0,0 +1,122 @@ +// Copyright 2023 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 "starboard/shared/starboard/media/mime_util.h" + +#include "starboard/media.h" +#include "starboard/shared/starboard/media/media_support_internal.h" +#include "starboard/shared/starboard/media/mime_type.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace shared { +namespace starboard { +namespace media { +namespace { + +// The codecs tested by these tests were introduced in SB_API_VERSION 14. +#if SB_API_VERSION >= 14 +constexpr char kEmptyKeySystem[] = ""; +constexpr int64_t kBitrate = 44100; + +TEST(MimeUtilTest, ChecksSupportedMp3Containers) { + const std::string valid_mp3_mime_str_1 = + "audio/mpeg; codecs=\"mp3\"; bitrate=44100"; + const MimeType valid_mp3_mime_1(valid_mp3_mime_str_1); + EXPECT_EQ( + CanPlayMimeAndKeySystem(valid_mp3_mime_str_1.c_str(), kEmptyKeySystem), + SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_mp3_mime_1, + kBitrate) + ? kSbMediaSupportTypeProbably + : kSbMediaSupportTypeNotSupported); + + const std::string valid_mp3_mime_str_2 = + "audio/mp3; codecs=\"mp3\"; bitrate=44100"; + const MimeType valid_mp3_mime_2(valid_mp3_mime_str_2); + EXPECT_EQ( + CanPlayMimeAndKeySystem(valid_mp3_mime_str_2.c_str(), kEmptyKeySystem), + SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_mp3_mime_2, + kBitrate) + ? kSbMediaSupportTypeProbably + : kSbMediaSupportTypeNotSupported); +} + +TEST(MimeUtilTest, ChecksUnsupportedMp3Containers) { + // Invalid container for MP3 codec. + const std::string invalid_mp3_mime_str = + "audio/mp4; codecs=\"mp3\"; bitrate=44100"; + const MimeType invalid_mp3_mime(invalid_mp3_mime_str); + EXPECT_EQ( + CanPlayMimeAndKeySystem(invalid_mp3_mime_str.c_str(), kEmptyKeySystem), + kSbMediaSupportTypeNotSupported); +} + +TEST(MimeUtilTest, ChecksSupportedFlacContainers) { + const std::string valid_flac_mime_str_1 = + "audio/ogg; codecs=\"flac\"; bitrate=44100"; + const MimeType valid_flac_mime_1(valid_flac_mime_str_1); + EXPECT_EQ( + CanPlayMimeAndKeySystem(valid_flac_mime_str_1.c_str(), kEmptyKeySystem), + SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_flac_mime_1, + kBitrate) + ? kSbMediaSupportTypeProbably + : kSbMediaSupportTypeNotSupported); + + const std::string valid_flac_mime_str_2 = + "audio/flac; codecs=\"flac\"; bitrate=44100"; + const MimeType valid_flac_mime_2(valid_flac_mime_str_2); + EXPECT_EQ( + CanPlayMimeAndKeySystem(valid_flac_mime_str_2.c_str(), kEmptyKeySystem), + SbMediaIsAudioSupported(kSbMediaAudioCodecMp3, &valid_flac_mime_2, + kBitrate) + ? kSbMediaSupportTypeProbably + : kSbMediaSupportTypeNotSupported); +} + +TEST(MimeUtilTest, ChecksUnsupportedFlacContainers) { + // Invalid container for FLAC codec. + const std::string invalid_flac_mime_str = + "audio/mp4; codecs=\"flac\"; bitrate=44100"; + const MimeType invalid_flac_mime(invalid_flac_mime_str); + EXPECT_EQ( + CanPlayMimeAndKeySystem(invalid_flac_mime_str.c_str(), kEmptyKeySystem), + kSbMediaSupportTypeNotSupported); +} + +TEST(MimeUtilTest, ChecksSupportedPcmContainers) { + const std::string valid_pcm_mime_str = + "audio/wav; codecs=\"1\"; bitrate=44100"; + const MimeType valid_pcm_mime(valid_pcm_mime_str); + EXPECT_EQ( + CanPlayMimeAndKeySystem(valid_pcm_mime_str.c_str(), kEmptyKeySystem), + SbMediaIsAudioSupported(kSbMediaAudioCodecPcm, &valid_pcm_mime, kBitrate) + ? kSbMediaSupportTypeProbably + : kSbMediaSupportTypeNotSupported); +} + +TEST(MimeUtilTest, ChecksUnsupportedWavCodecs) { + const std::string invalid_wav_mime_str = + "audio/wav; codecs=\"aac\"; bitrate=44100"; + const MimeType invalid_wav_mime(invalid_wav_mime_str); + EXPECT_EQ( + CanPlayMimeAndKeySystem(invalid_wav_mime_str.c_str(), kEmptyKeySystem), + kSbMediaSupportTypeNotSupported); +} +#endif // SB_API_VERSION >= 14 + +} // namespace +} // namespace media +} // namespace starboard +} // namespace shared +} // namespace starboard
diff --git a/starboard/shared/starboard/player/filter/audio_resampler_impl.cc b/starboard/shared/starboard/player/filter/audio_resampler_impl.cc index c07f29e..b0fa874 100644 --- a/starboard/shared/starboard/player/filter/audio_resampler_impl.cc +++ b/starboard/shared/starboard/player/filter/audio_resampler_impl.cc
@@ -12,9 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "starboard/shared/starboard/player/filter/audio_resampler.h" + +#include <deque> + #include "starboard/common/log.h" #include "starboard/configuration.h" -#include "starboard/shared/starboard/player/filter/audio_resampler.h" #include "starboard/shared/starboard/player/filter/interleaved_sinc_resampler.h" namespace starboard { @@ -58,8 +61,11 @@ SbMediaAudioSampleType destination_sample_type_; SbMediaAudioFrameStorageType destination_storage_type_; + std::deque<scoped_refptr<DecodedAudio>> audio_inputs_; + size_t frames_to_resample_ = 0; size_t frames_resampled_ = 0; + size_t frames_outputted_ = 0; }; } // namespace @@ -82,69 +88,84 @@ scoped_refptr<DecodedAudio> AudioResamplerImpl::WriteEndOfStream() { double sample_rate_ratio = interleaved_resampler_.GetSampleRateRatio(); int out_num_of_frames = - round(frames_to_resample_ / sample_rate_ratio) - frames_resampled_; + round(frames_to_resample_ / sample_rate_ratio) - frames_outputted_; if (out_num_of_frames > 0) { - interleaved_resampler_.QueueBuffer(nullptr, 0); - int channels = interleaved_resampler_.channels(); - int resampled_audio_size = out_num_of_frames * channels * sizeof(float); - scoped_refptr<DecodedAudio> resampled_audio = new DecodedAudio( - channels, kSbMediaAudioSampleTypeFloat32, - kSbMediaAudioFrameStorageTypeInterleaved, 0, resampled_audio_size); + SB_DCHECK(!audio_inputs_.empty()); + // If there're frames left in |interleaved_resampler_|, |audio_inputs_| + // should not be empty. To be cautious in production, we add a check here. + if (!audio_inputs_.empty()) { + interleaved_resampler_.QueueBuffer(nullptr, 0); + int channels = interleaved_resampler_.channels(); + int resampled_audio_size = out_num_of_frames * channels * sizeof(float); + scoped_refptr<DecodedAudio> resampled_audio = new DecodedAudio( + channels, kSbMediaAudioSampleTypeFloat32, + kSbMediaAudioFrameStorageTypeInterleaved, + audio_inputs_.front()->timestamp(), resampled_audio_size); - float* dst = reinterpret_cast<float*>(resampled_audio->data()); - interleaved_resampler_.Resample(dst, out_num_of_frames); + float* dst = reinterpret_cast<float*>(resampled_audio->data()); + interleaved_resampler_.Resample(dst, out_num_of_frames); - if (!resampled_audio->IsFormat(destination_sample_type_, - destination_storage_type_)) { - resampled_audio = resampled_audio->SwitchFormatTo( - destination_sample_type_, destination_storage_type_); + if (!resampled_audio->IsFormat(destination_sample_type_, + destination_storage_type_)) { + resampled_audio = resampled_audio->SwitchFormatTo( + destination_sample_type_, destination_storage_type_); + } + return resampled_audio; } - return resampled_audio; } return new DecodedAudio; } scoped_refptr<DecodedAudio> AudioResamplerImpl::Resample( - scoped_refptr<DecodedAudio> audio_data) { - SB_DCHECK(audio_data->channels() == interleaved_resampler_.channels()); + scoped_refptr<DecodedAudio> audio_input) { + SB_DCHECK(audio_input->channels() == interleaved_resampler_.channels()); + + audio_inputs_.push_back(audio_input); // It does nothing if source sample type is float and source storage type is // interleaved. - if (!audio_data->IsFormat(kSbMediaAudioSampleTypeFloat32, - kSbMediaAudioFrameStorageTypeInterleaved)) { - audio_data = - audio_data->SwitchFormatTo(kSbMediaAudioSampleTypeFloat32, - kSbMediaAudioFrameStorageTypeInterleaved); + if (!audio_input->IsFormat(kSbMediaAudioSampleTypeFloat32, + kSbMediaAudioFrameStorageTypeInterleaved)) { + audio_input = + audio_input->SwitchFormatTo(kSbMediaAudioSampleTypeFloat32, + kSbMediaAudioFrameStorageTypeInterleaved); } - int num_of_frames = audio_data->frames(); - frames_to_resample_ += num_of_frames; - int channels = audio_data->channels(); - int out_num_of_frames = static_cast<int>( - ceil(num_of_frames / interleaved_resampler_.GetSampleRateRatio())); + // Enqueue the input. + int num_of_input_frames = audio_input->frames(); + frames_to_resample_ += num_of_input_frames; + float* input_samples = reinterpret_cast<float*>(audio_input->data()); + interleaved_resampler_.QueueBuffer(input_samples, num_of_input_frames); - int resampled_audio_size = out_num_of_frames * channels * sizeof(float); + // Check if we have enough frames to output. + scoped_refptr<DecodedAudio>& next_audio_to_output = audio_inputs_.front(); + int num_of_output_frames = + static_cast<int>( + ceil((frames_resampled_ + next_audio_to_output->frames()) / + interleaved_resampler_.GetSampleRateRatio())) - + frames_outputted_; + int channels = next_audio_to_output->channels(); scoped_refptr<DecodedAudio> resampled_audio = nullptr; - - float* samples = reinterpret_cast<float*>(audio_data->data()); - interleaved_resampler_.QueueBuffer(samples, num_of_frames); - - if (interleaved_resampler_.HasEnoughData(out_num_of_frames)) { + if (interleaved_resampler_.HasEnoughData(num_of_output_frames)) { + int output_audio_size = num_of_output_frames * channels * sizeof(float); resampled_audio = new DecodedAudio(channels, kSbMediaAudioSampleTypeFloat32, kSbMediaAudioFrameStorageTypeInterleaved, - audio_data->timestamp(), resampled_audio_size); + next_audio_to_output->timestamp(), output_audio_size); float* dst = reinterpret_cast<float*>(resampled_audio->data()); - interleaved_resampler_.Resample(dst, out_num_of_frames); - frames_resampled_ += out_num_of_frames; + interleaved_resampler_.Resample(dst, num_of_output_frames); + frames_resampled_ += next_audio_to_output->frames(); + frames_outputted_ += num_of_output_frames; if (!resampled_audio->IsFormat(destination_sample_type_, destination_storage_type_)) { resampled_audio = resampled_audio->SwitchFormatTo( destination_sample_type_, destination_storage_type_); } + + audio_inputs_.pop_front(); } return resampled_audio;
diff --git a/starboard/shared/starboard/player/filter/testing/BUILD.gn b/starboard/shared/starboard/player/filter/testing/BUILD.gn index 80f2765..9d6f6b9 100644 --- a/starboard/shared/starboard/player/filter/testing/BUILD.gn +++ b/starboard/shared/starboard/player/filter/testing/BUILD.gn
@@ -26,6 +26,7 @@ "audio_decoder_test.cc", "audio_frame_discarder_test.cc", "audio_renderer_internal_test.cc", + "audio_resampler_test.cc", "file_cache_reader_test.cc", "media_time_provider_impl_test.cc", "player_components_test.cc", @@ -38,6 +39,7 @@ public_deps = [ ":test_util", + "//starboard:starboard_with_main", "//starboard/shared/starboard/media:media_util", "//testing/gmock", ]
diff --git a/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc b/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc index 7a2b8fe..5d6f6e0 100644 --- a/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc +++ b/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
@@ -43,6 +43,7 @@ namespace testing { namespace { +using std::deque; using std::string; using std::vector; using ::testing::Bool; @@ -112,9 +113,11 @@ ASSERT_LT(buffer_index, dmp_reader->number_of_audio_buffers()); can_accept_more_input_ = false; + scoped_refptr<InputBuffer> input = + GetAudioInputBuffer(dmp_reader, buffer_index); + written_inputs_.push_back(input); audio_decoder_->Decode( - {GetAudioInputBuffer(dmp_reader, buffer_index)}, - std::bind(&AdaptiveAudioDecoderTest::OnConsumed, this)); + {input}, std::bind(&AdaptiveAudioDecoderTest::OnConsumed, this)); } void WriteMultipleInputs(VideoDmpReader* dmp_reader, @@ -191,6 +194,7 @@ vector<std::unique_ptr<VideoDmpReader>> dmp_readers_; scoped_refptr<DecodedAudio> last_decoded_audio_; + deque<scoped_refptr<InputBuffer>> written_inputs_; int num_of_output_frames_ = 0; int output_sample_rate_; bool first_output_received_ = false; @@ -244,11 +248,23 @@ last_decoded_audio_ = decoded_audio; return; } - // TODO: fix resampler timestamp issue. - // if (last_decoded_audio_) { - // ASSERT_LT(last_decoded_audio_->timestamp(), - // decoded_audio->timestamp()); - // } + + // Stub decoder doesn't produce outputs with right timestamp. + if (!using_stub_decoder_) { + ASSERT_NEAR(decoded_audio->timestamp(), + written_inputs_.front()->timestamp(), 5); + written_inputs_.pop_front(); + + // TODO: The timestamps of inputs are not monotonic increasing, so + // that we can't get monotonic increasing output timestamps here. We + // can enable the check below once we make the input timestamps monotonic + // increasing. + if (last_decoded_audio_) { + // ASSERT_LE(last_decoded_audio_->timestamp(), + // decoded_audio->timestamp()); + } + } + last_decoded_audio_ = decoded_audio; num_of_output_frames_ += last_decoded_audio_->frames(); }
diff --git a/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc b/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc index 43fbff5..b9500df 100644 --- a/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc +++ b/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
@@ -224,10 +224,7 @@ ASSERT_EQ(decoded_audio_sample_type_, local_decoded_audio->sample_type()); ASSERT_EQ(decoded_audio_sample_rate_, decoded_sample_rate); - // TODO: Adaptive audio decoder may set output timestamp to 0, so we don't - // verify audio timestamp if it's 0. Consider enabling it after we - // fix timestamp issues. - if (local_decoded_audio->timestamp() != 0 && !decoded_audios_.empty()) { + if (!decoded_audios_.empty()) { ASSERT_LT(decoded_audios_.back()->timestamp(), local_decoded_audio->timestamp()); }
diff --git a/starboard/shared/starboard/player/filter/testing/audio_resampler_test.cc b/starboard/shared/starboard/player/filter/testing/audio_resampler_test.cc new file mode 100644 index 0000000..ad88fa6 --- /dev/null +++ b/starboard/shared/starboard/player/filter/testing/audio_resampler_test.cc
@@ -0,0 +1,195 @@ +// Copyright 2023 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 <tuple> +#include <vector> + +#include "starboard/common/string.h" +#include "starboard/shared/starboard/player/filter/audio_resampler.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace shared { +namespace starboard { +namespace player { +namespace filter { +namespace testing { +namespace { + +using ::testing::Combine; +using ::testing::ValuesIn; + +typedef ::testing::tuple<SbMediaAudioSampleType, + SbMediaAudioFrameStorageType, + int, + SbMediaAudioSampleType, + SbMediaAudioFrameStorageType, + int, + int> + AudioResamplerTestParam; + +SbMediaAudioSampleType kSampleTypesToTest[] = { + kSbMediaAudioSampleTypeInt16Deprecated, + kSbMediaAudioSampleTypeFloat32, +}; +SbMediaAudioFrameStorageType kStorageTypesToTest[] = { + kSbMediaAudioFrameStorageTypeInterleaved, + kSbMediaAudioFrameStorageTypePlanar, +}; +int kSampleRatesToTest[] = {22050, 44100, 48000}; +int kChannelsToTest[] = {1, 2, 6}; + +const char* ConvertSampleTypeToString(SbMediaAudioSampleType sample_type) { + if (sample_type == kSbMediaAudioSampleTypeInt16Deprecated) { + return "int16"; + } else if (sample_type == kSbMediaAudioSampleTypeFloat32) { + return "float32"; + } + SB_NOTREACHED(); + return ""; +} + +const char* ConvertStorageTypeToString( + SbMediaAudioFrameStorageType storage_type) { + if (storage_type == kSbMediaAudioFrameStorageTypeInterleaved) { + return "interleaved"; + } else if (storage_type == kSbMediaAudioFrameStorageTypePlanar) { + return "planar"; + } + SB_NOTREACHED(); + return ""; +} + +class AudioResamplerTest + : public ::testing::TestWithParam<AudioResamplerTestParam> { + protected: + AudioResamplerTest() { + const AudioResamplerTestParam& param = GetParam(); + source_sample_type_ = std::get<0>(param); + source_storage_type_ = std::get<1>(param); + source_sample_rate_ = std::get<2>(param); + destination_sample_type_ = std::get<3>(param); + destination_storage_type_ = std::get<4>(param); + destination_sample_rate_ = std::get<5>(param); + channels_ = std::get<6>(param); + + GenerateAudioInputs(); + } + + void GenerateAudioInputs() { + const int kNumberOfInputs = 40; + const int kSamplesPerInput = 1024; + + int total_frames = 0; + for (int i = 0; i < kNumberOfInputs; i++) { + int sample_size = + source_sample_type_ == kSbMediaAudioSampleTypeInt16Deprecated + ? sizeof(int16_t) + : sizeof(float); + int audio_size = kSamplesPerInput * channels_ * sample_size; + scoped_refptr<DecodedAudio> input = new DecodedAudio( + channels_, source_sample_type_, source_storage_type_, + kSbTimeSecond * total_frames / source_sample_rate_, audio_size); + total_frames += kSamplesPerInput; + inputs_.push_back(input); + } + } + + SbMediaAudioSampleType source_sample_type_; + SbMediaAudioFrameStorageType source_storage_type_; + int source_sample_rate_; + SbMediaAudioSampleType destination_sample_type_; + SbMediaAudioFrameStorageType destination_storage_type_; + int destination_sample_rate_; + int channels_; + + std::vector<scoped_refptr<DecodedAudio>> inputs_; +}; + +TEST_P(AudioResamplerTest, SunnyDay) { + scoped_ptr<AudioResampler> resampler = AudioResampler::Create( + source_sample_type_, source_storage_type_, source_sample_rate_, + destination_sample_type_, destination_storage_type_, + destination_sample_rate_, channels_); + + int total_input_frames = 0; + std::vector<scoped_refptr<DecodedAudio>> outputs; + for (auto input : inputs_) { + scoped_refptr<DecodedAudio> output = resampler->Resample(input); + total_input_frames += input->frames(); + if (output) { + outputs.push_back(output); + } + } + scoped_refptr<DecodedAudio> output = resampler->WriteEndOfStream(); + if (output) { + outputs.push_back(output); + } + + // Theoretically, if the input is too small, the last output could consist + // of multiple inputs. But as our audio unit is always larger than resampler + // block size. The amount of outputs should be always same as the inputs, and + // they should have same timestamp. + EXPECT_EQ(inputs_.size(), outputs.size()); + int total_output_frames = 0; + for (int i = 0; i < outputs.size(); i++) { + EXPECT_EQ(inputs_[i]->timestamp(), outputs[i]->timestamp()); + total_output_frames += outputs[i]->frames(); + EXPECT_NEAR( + inputs_[i]->frames() * destination_sample_rate_ / source_sample_rate_, + outputs[i]->frames(), 5); + } + EXPECT_NEAR( + total_input_frames * destination_sample_rate_ / source_sample_rate_, + total_output_frames, 5); +} + +std::string GetTestConfigName( + ::testing::TestParamInfo<AudioResamplerTestParam> info) { + const AudioResamplerTestParam& param = info.param; + SbMediaAudioSampleType source_sample_type = std::get<0>(param); + SbMediaAudioFrameStorageType source_storage_type = std::get<1>(param); + int source_sample_rate = std::get<2>(param); + SbMediaAudioSampleType destination_sample_type = std::get<3>(param); + SbMediaAudioFrameStorageType destination_storage_type = std::get<4>(param); + int destination_sample_rate = std::get<5>(param); + int channels = std::get<6>(param); + std::string name = FormatString( + "%s_%s_%d_to_%s_%s_%d_channels_%d", + ConvertSampleTypeToString(source_sample_type), + ConvertStorageTypeToString(source_storage_type), source_sample_rate, + ConvertSampleTypeToString(destination_sample_type), + ConvertStorageTypeToString(destination_storage_type), + destination_sample_rate, channels); + return name; +} + +INSTANTIATE_TEST_CASE_P(AudioResamplerTests, + AudioResamplerTest, + Combine(ValuesIn(kSampleTypesToTest), + ValuesIn(kStorageTypesToTest), + ValuesIn(kSampleRatesToTest), + ValuesIn(kSampleTypesToTest), + ValuesIn(kStorageTypesToTest), + ValuesIn(kSampleRatesToTest), + ValuesIn(kChannelsToTest)), + GetTestConfigName); + +} // namespace +} // namespace testing +} // namespace filter +} // namespace player +} // namespace starboard +} // namespace shared +} // namespace starboard
diff --git a/starboard/shared/starboard/player/filter/tools/BUILD.gn b/starboard/shared/starboard/player/filter/tools/BUILD.gn index b2d0a78..f1842ff 100644 --- a/starboard/shared/starboard/player/filter/tools/BUILD.gn +++ b/starboard/shared/starboard/player/filter/tools/BUILD.gn
@@ -18,7 +18,7 @@ sources = [ "audio_dmp_player.cc" ] configs += [ "//starboard/build/config:starboard_implementation" ] public_deps = [ - "//starboard", + "//starboard:starboard_with_main", "//starboard/shared/starboard/media:media_util", "//starboard/shared/starboard/player:player_download_test_data", "//starboard/shared/starboard/player:video_dmp",
diff --git a/starboard/shared/uwp/media_is_video_supported.cc b/starboard/shared/uwp/media_is_video_supported.cc index 5316a98..eab4c87 100644 --- a/starboard/shared/uwp/media_is_video_supported.cc +++ b/starboard/shared/uwp/media_is_video_supported.cc
@@ -112,11 +112,7 @@ case starboard::shared::uwp::kXboxOneX: // Horizontal video resolutions hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 3840, 2160, - 30); - hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2560, 1440, 60); - // Until we can resolve b/170881040, we should cap Xbox One X to 2K for - // HDR 60 FPS. hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 3840, 2160, 30); hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 2560, 1440, @@ -124,7 +120,7 @@ // Vertical video resolutions hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2160, 3840, 30); - hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 1440, 2560, + hw_decoder_capabilities_.AddSdrRule(kSbMediaVideoCodecVp9, 2160, 3840, 60); hw_decoder_capabilities_.AddHdrRule(kSbMediaVideoCodecVp9, 2160, 3840, 30);
diff --git a/starboard/shared/x11/application_x11.cc b/starboard/shared/x11/application_x11.cc index d2b4f12..7efa103 100644 --- a/starboard/shared/x11/application_x11.cc +++ b/starboard/shared/x11/application_x11.cc
@@ -919,7 +919,12 @@ return pending_event; } - SB_DCHECK(dev_input_); + // In modular builds, |CreateWindow| is not always called before the event + // loop is running. + if (!dev_input_) { + return nullptr; + } + shared::starboard::Application::Event* evdev_event = dev_input_->WaitForSystemEventWithTimeout(time);
diff --git a/starboard/tools/abstract_launcher.py b/starboard/tools/abstract_launcher.py index ff0ad61..9928039 100644 --- a/starboard/tools/abstract_launcher.py +++ b/starboard/tools/abstract_launcher.py
@@ -26,6 +26,8 @@ ARG_SYSTOOLS = "systools" ARG_DRYRUN = "dryrun" +IS_MODULAR_BUILD = os.getenv("MODULAR_BUILD", "0") == "1" + def _GetLauncherForPlatform(platform_name): """Gets the module containing a platform's concrete launcher implementation.
diff --git a/starboard/xb1/args.gn b/starboard/xb1/args.gn index 5101b33..2bf8065 100644 --- a/starboard/xb1/args.gn +++ b/starboard/xb1/args.gn
@@ -16,4 +16,3 @@ target_os = "winuwp" target_cpu = "x64" is_clang = false -is_internal_build = false
diff --git a/starboard/xb1/platform_configuration/BUILD.gn b/starboard/xb1/platform_configuration/BUILD.gn index 5c493ae..68b7862 100644 --- a/starboard/xb1/platform_configuration/BUILD.gn +++ b/starboard/xb1/platform_configuration/BUILD.gn
@@ -57,9 +57,10 @@ "vcruntime.lib", "ucrt.lib", ] - ldflags += [ "/DEBUG:FASTLINK" ] } + ldflags += [ "/DEBUG:FASTLINK" ] + ldflags += [ "/NODEFAULTLIB" ] arflags += [ "/NODEFAULTLIB" ] libs += [
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn index f90940c..51f71e4 100644 --- a/third_party/boringssl/BUILD.gn +++ b/third_party/boringssl/BUILD.gn
@@ -176,26 +176,3 @@ configs += [ "//starboard/build/config:speed" ] } } - -target(final_executable_type, "crypto_tool") { - sources = [ - "src/tool/args.cc", - "src/tool/ciphers.cc", - "src/tool/const.cc", - "src/tool/digest.cc", - "src/tool/file.cc", - "src/tool/generate_ed25519.cc", - "src/tool/genrsa.cc", - "src/tool/pkcs12.cc", - "src/tool/rand.cc", - "src/tool/sign.cc", - "src/tool/speed.cc", - "src/tool/tool.cc", - ] - include_dirs = [ "src/include" ] - defines = [ "OPENSSL_NO_SOCK" ] - deps = [ ":crypto" ] - if (is_starboard) { - deps += [ "//starboard" ] - } -}
diff --git a/third_party/inspector_protocol/crdtp/json_platform.cc b/third_party/inspector_protocol/crdtp/json_platform.cc index facc7c8..968df8e 100644 --- a/third_party/inspector_protocol/crdtp/json_platform.cc +++ b/third_party/inspector_protocol/crdtp/json_platform.cc
@@ -26,7 +26,6 @@ } std::string DToStr(double value) { - //Ask Kaido/Yavor if this is needed. #if SB_IS(MODULAR) #error "The std::locale::classic() is not supported for Evergreen. Please use base::NumberToString()." #endif
diff --git a/third_party/llvm-project/libcxx/BUILD.gn b/third_party/llvm-project/libcxx/BUILD.gn index 1d47c23..0c80cac 100644 --- a/third_party/llvm-project/libcxx/BUILD.gn +++ b/third_party/llvm-project/libcxx/BUILD.gn
@@ -119,7 +119,4 @@ "//third_party/llvm-project/libcxxabi:cxxabi", "//third_party/musl:c", ] - if (!build_with_separate_cobalt_toolchain) { - deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ] - } }
diff --git a/third_party/llvm-project/libcxxabi/BUILD.gn b/third_party/llvm-project/libcxxabi/BUILD.gn index 0ed1b42..9142fa4 100644 --- a/third_party/llvm-project/libcxxabi/BUILD.gn +++ b/third_party/llvm-project/libcxxabi/BUILD.gn
@@ -90,7 +90,4 @@ all_dependent_configs = [ ":cxxabi_dependents_config" ] deps = [ "//third_party/musl:c" ] - if (!build_with_separate_cobalt_toolchain) { - deps += [ "//third_party/llvm-project/libunwind:unwind_evergreen" ] - } }
diff --git a/third_party/llvm-project/libunwind/BUILD.gn b/third_party/llvm-project/libunwind/BUILD.gn index 44d7882..cedc13b 100644 --- a/third_party/llvm-project/libunwind/BUILD.gn +++ b/third_party/llvm-project/libunwind/BUILD.gn
@@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//starboard/build/config/os_definitions.gni") + common_sources = [ "src/AddressSpace.hpp", "src/CompactUnwinder.hpp", @@ -55,8 +57,9 @@ # dependencies from spilling over to gn check when run for non-evergreen # platforms (e.g., raspi-2_gn_devel). It can and should be removed once the gn # check errors have been resolved for evergreen. -if (sb_is_evergreen) { - config("unwind_evergreen_config") { +# TODO: b/295702296 Fix libunwind for modular builds. +if (sb_is_evergreen || (sb_is_modular && is_host_win)) { + config("unwind_config") { configs = [ ":common_unwind_dependents_config" ] cflags = [ @@ -90,10 +93,10 @@ ] } - static_library("unwind_evergreen") { + static_library("unwind") { sources = common_sources - configs += [ ":unwind_evergreen_config" ] + configs += [ ":unwind_config" ] all_dependent_configs = [ ":common_unwind_dependents_config" ] deps = [
diff --git a/third_party/musl/BUILD.gn b/third_party/musl/BUILD.gn index 740216a..8d00e30 100644 --- a/third_party/musl/BUILD.gn +++ b/third_party/musl/BUILD.gn
@@ -520,9 +520,7 @@ ] } -target(gtest_target_type, "musl_unittests") { - build_loader = false - testonly = true +static_library("musl_unittests") { sources = [ "test/type_size_test.cc" ] deps = [ ":c",
diff --git a/third_party/musl/test/type_size_test.cc b/third_party/musl/test/type_size_test.cc index f85a0ce..ae2e93f 100644 --- a/third_party/musl/test/type_size_test.cc +++ b/third_party/musl/test/type_size_test.cc
@@ -190,8 +190,13 @@ // TODO: Decide if we should, and how, verify that __WCHAR_TYPE__ is the // expected size. #else // !SB_IS(ARCH_X86) +#if SB_IS(WCHAR_T_UTF16) +SB_COMPILE_ASSERT(sizeof(wchar_t) == 2, + SB_IS_WCHAR_T_UTF16_is_inconsistent_with_sizeof_wchar_t); +#else SB_COMPILE_ASSERT(sizeof(wchar_t) == SB_SIZE_OF_INT, SB_SIZE_OF_INT_is_inconsistent_with_sizeof_wchar_t); +#endif // SB_IS(WCHAR_T_UTF16) #endif // SB_IS(ARCH_X86) #endif // SB_IS(MODULAR)
diff --git a/third_party/opus/starboard/config.h b/third_party/opus/starboard/config.h index 7c67f29..4a9f5e1 100644 --- a/third_party/opus/starboard/config.h +++ b/third_party/opus/starboard/config.h
@@ -35,6 +35,9 @@ #define OPUS_BUILD 1 +/* Don't let EXPORT to be redefined by later config code. */ +#define OPUS_EXPORT + #if defined(_M_IX86) || defined(_M_X64) /* Can always compile SSE intrinsics (no special compiler flags necessary) */ #define OPUS_X86_MAY_HAVE_SSE