| // Copyright 2015 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. |
| |
| #if defined(STARBOARD) |
| #include "starboard/client_porting/poem/stdio_leaks_poem.h" |
| #endif |
| |
| #include "cobalt/browser/application.h" |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/metrics/statistics_recorder.h" |
| #include "base/optional.h" |
| #include "base/path_service.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/task/task_scheduler/task_scheduler.h" |
| #include "base/time/time.h" |
| #include "base/trace_event/trace_event.h" |
| #include "build/build_config.h" |
| #include "cobalt/base/accessibility_caption_settings_changed_event.h" |
| #include "cobalt/base/accessibility_settings_changed_event.h" |
| #include "cobalt/base/accessibility_text_to_speech_settings_changed_event.h" |
| #include "cobalt/base/cobalt_paths.h" |
| #include "cobalt/base/deep_link_event.h" |
| #include "cobalt/base/get_application_key.h" |
| #include "cobalt/base/init_cobalt.h" |
| #include "cobalt/base/language.h" |
| #include "cobalt/base/localized_strings.h" |
| #include "cobalt/base/on_screen_keyboard_blurred_event.h" |
| #include "cobalt/base/on_screen_keyboard_focused_event.h" |
| #include "cobalt/base/on_screen_keyboard_hidden_event.h" |
| #include "cobalt/base/on_screen_keyboard_shown_event.h" |
| #include "cobalt/base/on_screen_keyboard_suggestions_updated_event.h" |
| #include "cobalt/base/startup_timer.h" |
| #if defined(COBALT_ENABLE_VERSION_COMPATIBILITY_VALIDATIONS) |
| #include "cobalt/base/version_compatibility.h" |
| #endif // defined(COBALT_ENABLE_VERSION_COMPATIBILITY_VALIDATIONS) |
| #include "cobalt/base/window_size_changed_event.h" |
| #include "cobalt/browser/device_authentication.h" |
| #include "cobalt/browser/memory_settings/auto_mem_settings.h" |
| #include "cobalt/browser/memory_tracker/tool.h" |
| #include "cobalt/browser/storage_upgrade_handler.h" |
| #include "cobalt/browser/switches.h" |
| #include "cobalt/browser/user_agent_string.h" |
| #include "cobalt/configuration/configuration.h" |
| #include "cobalt/extension/crash_handler.h" |
| #include "cobalt/extension/installation_manager.h" |
| #include "cobalt/loader/image/image_decoder.h" |
| #include "cobalt/math/size.h" |
| #include "cobalt/script/javascript_engine.h" |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| #include "cobalt/storage/savegame_fake.h" |
| #endif // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| #include "cobalt/system_window/input_event.h" |
| #include "cobalt/trace_event/scoped_trace_to_file.h" |
| #include "starboard/configuration.h" |
| #include "starboard/system.h" |
| #include "url/gurl.h" |
| |
| #if SB_IS(EVERGREEN) |
| #include "cobalt/updater/utils.h" |
| #endif |
| |
| using cobalt::cssom::ViewportSize; |
| |
| namespace cobalt { |
| namespace browser { |
| |
| namespace { |
| const int kStatUpdatePeriodMs = 1000; |
| |
| const char kDefaultURL[] = "https://www.youtube.com/tv"; |
| |
| #if defined(ENABLE_ABOUT_SCHEME) |
| const char kAboutBlankURL[] = "about:blank"; |
| #endif // defined(ENABLE_ABOUT_SCHEME) |
| |
| bool IsStringNone(const std::string& str) { |
| return !base::strcasecmp(str.c_str(), "none"); |
| } |
| |
| #if defined(ENABLE_WEBDRIVER) || defined(ENABLE_DEBUGGER) |
| std::string GetDevServersListenIp() { |
| bool ip_v6; |
| #if SB_API_VERSION >= 12 |
| ip_v6 = SbSocketIsIpv6Supported(); |
| #elif SB_HAS(IPV6) |
| ip_v6 = true; |
| #else |
| ip_v6 = false; |
| #endif |
| // Default to INADDR_ANY |
| std::string listen_ip(ip_v6 ? "::" : "0.0.0.0"); |
| |
| // Desktop PCs default to loopback. |
| if (SbSystemGetDeviceType() == kSbSystemDeviceTypeDesktopPC) { |
| listen_ip = ip_v6 ? "::1" : "127.0.0.1"; |
| } |
| |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kDevServersListenIp)) { |
| listen_ip = |
| command_line->GetSwitchValueASCII(switches::kDevServersListenIp); |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| |
| return listen_ip; |
| } |
| #endif // defined(ENABLE_WEBDRIVER) || defined(ENABLE_DEBUGGER) |
| |
| #if defined(ENABLE_DEBUGGER) |
| int GetRemoteDebuggingPort() { |
| #if defined(SB_OVERRIDE_DEFAULT_REMOTE_DEBUGGING_PORT) |
| const unsigned int kDefaultRemoteDebuggingPort = |
| SB_OVERRIDE_DEFAULT_REMOTE_DEBUGGING_PORT; |
| #else |
| const unsigned int kDefaultRemoteDebuggingPort = 9222; |
| #endif // defined(SB_OVERRIDE_DEFAULT_REMOTE_DEBUGGING_PORT) |
| unsigned int remote_debugging_port = kDefaultRemoteDebuggingPort; |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kRemoteDebuggingPort)) { |
| std::string switch_value = |
| command_line->GetSwitchValueASCII(switches::kRemoteDebuggingPort); |
| if (!base::StringToUint(switch_value, &remote_debugging_port)) { |
| DLOG(ERROR) << "Invalid port specified for remote debug server: " |
| << switch_value |
| << ". Using default port: " << kDefaultRemoteDebuggingPort; |
| remote_debugging_port = kDefaultRemoteDebuggingPort; |
| } |
| } |
| DCHECK(remote_debugging_port != 0 || |
| !command_line->HasSwitch(switches::kWaitForWebDebugger)) |
| << switches::kWaitForWebDebugger << " switch can't be used when " |
| << switches::kRemoteDebuggingPort << " is 0 (disabled)."; |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| return uint16_t(remote_debugging_port); |
| } |
| #endif // ENABLE_DEBUGGER |
| |
| #if defined(ENABLE_WEBDRIVER) |
| int GetWebDriverPort() { |
| // The default port on which the webdriver server should listen for incoming |
| // connections. |
| #if defined(SB_OVERRIDE_DEFAULT_WEBDRIVER_PORT) |
| const int kDefaultWebDriverPort = SB_OVERRIDE_DEFAULT_WEBDRIVER_PORT; |
| #else |
| const int kDefaultWebDriverPort = 4444; |
| #endif // defined(SB_OVERRIDE_DEFAULT_WEBDRIVER_PORT) |
| int webdriver_port = kDefaultWebDriverPort; |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kWebDriverPort)) { |
| if (!base::StringToInt( |
| command_line->GetSwitchValueASCII(switches::kWebDriverPort), |
| &webdriver_port)) { |
| DLOG(ERROR) << "Invalid port specified for WebDriver server: " |
| << command_line->GetSwitchValueASCII(switches::kWebDriverPort) |
| << ". Using default port: " << kDefaultWebDriverPort; |
| webdriver_port = kDefaultWebDriverPort; |
| } |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| return webdriver_port; |
| } |
| |
| std::string GetWebDriverListenIp() { |
| // The default IP on which the webdriver server should listen for incoming |
| // connections. |
| std::string webdriver_listen_ip = GetDevServersListenIp(); |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kWebDriverListenIp)) { |
| DLOG(WARNING) << "The \"--" << switches::kWebDriverListenIp |
| << "\" switch is deprecated; please use \"--" |
| << switches::kDevServersListenIp << "\" instead."; |
| webdriver_listen_ip = |
| command_line->GetSwitchValueASCII(switches::kWebDriverListenIp); |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| return webdriver_listen_ip; |
| } |
| #endif // ENABLE_WEBDRIVER |
| |
| GURL GetInitialURL(bool should_preload) { |
| GURL initial_url = GURL(kDefaultURL); |
| // Allow the user to override the default URL via a command line parameter. |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kInitialURL)) { |
| std::string url_switch = |
| command_line->GetSwitchValueASCII(switches::kInitialURL); |
| #if defined(ENABLE_ABOUT_SCHEME) |
| // Check the switch itself since some non-empty strings parse to empty URLs. |
| if (url_switch.empty()) { |
| LOG(ERROR) << "URL from parameter is empty, using " << kAboutBlankURL; |
| return GURL(kAboutBlankURL); |
| } |
| #endif // defined(ENABLE_ABOUT_SCHEME) |
| GURL url = GURL(url_switch); |
| if (url.is_valid()) { |
| initial_url = url; |
| } else { |
| LOG(ERROR) << "URL \"" << url_switch |
| << "\" from parameter is not valid, using default URL " |
| << initial_url; |
| } |
| } |
| |
| if (should_preload) { |
| std::string query = initial_url.query(); |
| if (!query.empty()) { |
| query += "&"; |
| } |
| query += "launch=preload"; |
| GURL::Replacements replacements; |
| replacements.SetQueryStr(query); |
| initial_url = initial_url.ReplaceComponents(replacements); |
| } |
| |
| #if SB_API_VERSION >= 11 |
| if (!command_line->HasSwitch( |
| switches::kOmitDeviceAuthenticationQueryParameters)) { |
| // Append the device authentication query parameters based on the platform's |
| // certification secret to the initial URL. |
| std::string query = initial_url.query(); |
| std::string device_authentication_query_string = |
| GetDeviceAuthenticationSignedURLQueryString(); |
| if (!query.empty() && !device_authentication_query_string.empty()) { |
| query += "&"; |
| } |
| query += device_authentication_query_string; |
| |
| if (!query.empty()) { |
| GURL::Replacements replacements; |
| replacements.SetQueryStr(query); |
| initial_url = initial_url.ReplaceComponents(replacements); |
| } |
| } |
| #endif // SB_API_VERSION >= 11 |
| |
| return initial_url; |
| } |
| |
| bool ValidateSplashScreen(const base::Optional<GURL>& url) { |
| if (url->is_valid() && |
| (url->SchemeIsFile() || url->SchemeIs("h5vcc-embedded"))) { |
| return true; |
| } |
| LOG(FATAL) << "Ignoring invalid fallback splash screen: " << url->spec(); |
| return false; |
| } |
| |
| base::Optional<GURL> GetFallbackSplashScreenURL() { |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| std::string fallback_splash_screen_string; |
| if (command_line->HasSwitch(switches::kFallbackSplashScreenURL)) { |
| fallback_splash_screen_string = |
| command_line->GetSwitchValueASCII(switches::kFallbackSplashScreenURL); |
| } else { |
| fallback_splash_screen_string = configuration::Configuration::GetInstance() |
| ->CobaltFallbackSplashScreenUrl(); |
| } |
| if (IsStringNone(fallback_splash_screen_string)) { |
| return base::Optional<GURL>(); |
| } |
| base::Optional<GURL> fallback_splash_screen_url = |
| GURL(fallback_splash_screen_string); |
| ValidateSplashScreen(fallback_splash_screen_url); |
| return fallback_splash_screen_url; |
| } |
| |
| // Parses the fallback_splash_screen_topics command line parameter |
| // and maps topics to full file url locations, if valid. |
| void ParseFallbackSplashScreenTopics( |
| const base::Optional<GURL>& default_fallback_splash_screen_url, |
| std::map<std::string, GURL>* fallback_splash_screen_topic_map) { |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| std::string topics; |
| if (command_line->HasSwitch(switches::kFallbackSplashScreenTopics)) { |
| topics = command_line->GetSwitchValueASCII( |
| switches::kFallbackSplashScreenTopics); |
| } else { |
| topics = configuration::Configuration::GetInstance() |
| ->CobaltFallbackSplashScreenTopics(); |
| } |
| |
| // Note: values in topics_map may be either file paths or filenames. |
| std::map<std::string, std::string> topics_map; |
| BrowserModule::GetParamMap(topics, topics_map); |
| for (auto iterator = topics_map.begin(); iterator != topics_map.end(); |
| iterator++) { |
| std::string topic = iterator->first; |
| std::string location = iterator->second; |
| base::Optional<GURL> topic_fallback_url = GURL(location); |
| |
| // If not a valid url, check whether it is a valid filename in the |
| // same directory as the default fallback url. |
| if (!topic_fallback_url->is_valid()) { |
| if (default_fallback_splash_screen_url) { |
| topic_fallback_url = GURL( |
| default_fallback_splash_screen_url->GetWithoutFilename().spec() + |
| location); |
| } else { |
| break; |
| } |
| } |
| if (ValidateSplashScreen(topic_fallback_url)) { |
| (*fallback_splash_screen_topic_map)[topic] = topic_fallback_url.value(); |
| } |
| } |
| } |
| |
| base::TimeDelta GetTimedTraceDuration() { |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| int duration_in_seconds = 0; |
| if (command_line->HasSwitch(switches::kTimedTrace) && |
| base::StringToInt( |
| command_line->GetSwitchValueASCII(switches::kTimedTrace), |
| &duration_in_seconds)) { |
| return base::TimeDelta::FromSeconds(duration_in_seconds); |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| |
| return base::TimeDelta(); |
| } |
| |
| base::FilePath GetExtraWebFileDir() { |
| // Default is empty, command line can override. |
| base::FilePath result; |
| |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kExtraWebFileDir)) { |
| result = base::FilePath( |
| command_line->GetSwitchValueASCII(switches::kExtraWebFileDir)); |
| if (!result.IsAbsolute()) { |
| // Non-absolute paths are relative to the executable directory. |
| base::FilePath content_path; |
| base::PathService::Get(base::DIR_EXE, &content_path); |
| result = content_path.DirName().DirName().Append(result); |
| } |
| DLOG(INFO) << "Extra web file dir: " << result.value(); |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| |
| return result; |
| } |
| |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| void EnableUsingStubImageDecoderIfRequired() { |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kStubImageDecoder)) { |
| loader::image::ImageDecoder::UseStubImageDecoder(); |
| } |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| |
| base::Optional<cssom::ViewportSize> GetRequestedViewportSize( |
| base::CommandLine* command_line) { |
| DCHECK(command_line); |
| if (!command_line->HasSwitch(browser::switches::kViewport)) { |
| return base::nullopt; |
| } |
| |
| std::string switch_value = |
| command_line->GetSwitchValueASCII(browser::switches::kViewport); |
| |
| std::vector<std::string> lengths = base::SplitString( |
| switch_value, "x", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| |
| if (lengths.empty()) { |
| DLOG(ERROR) << "Viewport " << switch_value << " is invalid."; |
| return base::nullopt; |
| } |
| |
| int width = 0; |
| if (!base::StringToInt(lengths[0], &width)) { |
| DLOG(ERROR) << "Viewport " << switch_value << " has invalid width."; |
| return base::nullopt; |
| } |
| |
| if (lengths.size() < 2) { |
| // Allow shorthand specification of the viewport by only giving the |
| // width. This calculates the height at 4:3 aspect ratio for smaller |
| // viewport widths, and 16:9 for viewports 1280 pixels wide or larger. |
| if (width >= 1280) { |
| return ViewportSize(width, 9 * width / 16); |
| } |
| return ViewportSize(width, 3 * width / 4); |
| } |
| |
| int height = 0; |
| if (!base::StringToInt(lengths[1], &height)) { |
| DLOG(ERROR) << "Viewport " << switch_value << " has invalid height."; |
| return base::nullopt; |
| } |
| |
| if (lengths.size() < 3) { |
| return ViewportSize(width, height); |
| } |
| |
| double screen_diagonal_inches = 0.0f; |
| if (lengths.size() >= 3) { |
| if (!base::StringToDouble(lengths[2], &screen_diagonal_inches)) { |
| DLOG(ERROR) << "Viewport " << switch_value |
| << " has invalid screen_diagonal_inches."; |
| return base::nullopt; |
| } |
| } |
| |
| double video_pixel_ratio = 1.0f; |
| if (lengths.size() >= 4) { |
| if (!base::StringToDouble(lengths[3], &video_pixel_ratio)) { |
| DLOG(ERROR) << "Viewport " << switch_value |
| << " has invalid video_pixel_ratio."; |
| return base::nullopt; |
| } |
| } |
| |
| return ViewportSize(width, height, static_cast<float>(video_pixel_ratio), |
| static_cast<float>(screen_diagonal_inches)); |
| } |
| |
| std::string GetMinLogLevelString() { |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kMinLogLevel)) { |
| return command_line->GetSwitchValueASCII(switches::kMinLogLevel); |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| return "info"; |
| } |
| |
| int StringToLogLevel(const std::string& log_level) { |
| if (log_level == "info") { |
| return logging::LOG_INFO; |
| } else if (log_level == "warning") { |
| return logging::LOG_WARNING; |
| } else if (log_level == "error") { |
| return logging::LOG_ERROR; |
| } else if (log_level == "fatal") { |
| return logging::LOG_FATAL; |
| } else { |
| NOTREACHED() << "Unrecognized logging level: " << log_level; |
| return logging::LOG_INFO; |
| } |
| } |
| |
| void SetIntegerIfSwitchIsSet(const char* switch_name, int* output) { |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) { |
| int32 out; |
| if (base::StringToInt32( |
| base::CommandLine::ForCurrentProcess()->GetSwitchValueNative( |
| switch_name), |
| &out)) { |
| LOG(INFO) << "Command line switch '" << switch_name << "': Modifying " |
| << *output << " -> " << out; |
| *output = out; |
| } else { |
| LOG(ERROR) << "Invalid value for command line setting: " << switch_name; |
| } |
| } |
| } |
| |
| void ApplyCommandLineSettingsToRendererOptions( |
| renderer::RendererModule::Options* options) { |
| SetIntegerIfSwitchIsSet(browser::switches::kScratchSurfaceCacheSizeInBytes, |
| &options->scratch_surface_cache_size_in_bytes); |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| auto command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(browser::switches::kDisableRasterizerCaching) || |
| command_line->HasSwitch( |
| browser::switches::kForceDeterministicRendering)) { |
| options->force_deterministic_rendering = true; |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| } |
| |
| struct NonTrivialStaticFields { |
| NonTrivialStaticFields() : system_language(base::GetSystemLanguage()) {} |
| |
| const std::string system_language; |
| std::string user_agent; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(NonTrivialStaticFields); |
| }; |
| |
| struct SecurityFlags { |
| csp::CSPHeaderPolicy csp_header_policy; |
| network::HTTPSRequirement https_requirement; |
| }; |
| |
| // |non_trivial_static_fields| will be lazily created on the first time it's |
| // accessed. |
| base::LazyInstance<NonTrivialStaticFields>::DestructorAtExit |
| non_trivial_static_fields = LAZY_INSTANCE_INITIALIZER; |
| |
| #if defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| const char kMemoryTrackerCommand[] = "memory_tracker"; |
| const char kMemoryTrackerCommandShortHelp[] = "Create a memory tracker."; |
| const char kMemoryTrackerCommandLongHelp[] = |
| "Create a memory tracker of the given type. Use an empty string to see the " |
| "available trackers."; |
| #endif // defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| |
| #if SB_API_VERSION >= 11 |
| bool AddCrashHandlerAnnotations() { |
| auto crash_handler_extension = |
| SbSystemGetExtension(kCobaltExtensionCrashHandlerName); |
| if (!crash_handler_extension) { |
| LOG(INFO) << "No crash handler extension, not sending annotations."; |
| return false; |
| } |
| |
| auto platform_info = cobalt::browser::GetUserAgentPlatformInfoFromSystem(); |
| std::string user_agent = |
| cobalt::browser::CreateUserAgentString(platform_info); |
| std::string version = ""; |
| #if SB_IS(EVERGREEN) |
| version = cobalt::updater::GetCurrentEvergreenVersion(); |
| std::string product = "Cobalt_Evergreen"; |
| #else |
| std::string product = "Cobalt"; |
| #endif |
| if (version.empty()) { |
| base::StringAppendF(&version, "%s.%s-%s", |
| platform_info.cobalt_version.c_str(), |
| platform_info.cobalt_build_version_number.c_str(), |
| platform_info.build_configuration.c_str()); |
| } |
| |
| user_agent.push_back('\0'); |
| product.push_back('\0'); |
| version.push_back('\0'); |
| |
| CrashpadAnnotations crashpad_annotations; |
| SbMemorySet(&crashpad_annotations, sizeof(CrashpadAnnotations), 0); |
| SbStringCopy(crashpad_annotations.user_agent_string, user_agent.c_str(), |
| USER_AGENT_STRING_MAX_SIZE); |
| SbStringCopy(crashpad_annotations.product, product.c_str(), |
| CRASHPAD_ANNOTATION_DEFAULT_LENGTH); |
| SbStringCopy(crashpad_annotations.version, version.c_str(), |
| CRASHPAD_ANNOTATION_DEFAULT_LENGTH); |
| bool result = static_cast<const CobaltExtensionCrashHandlerApi*>( |
| crash_handler_extension) |
| ->OverrideCrashpadAnnotations(&crashpad_annotations); |
| if (result) { |
| LOG(INFO) << "Sent annotations to crash handler"; |
| } else { |
| LOG(ERROR) << "Could not send annotations to crash handler."; |
| } |
| return result; |
| } |
| #endif // SB_API_VERSION >= 11 |
| |
| } // namespace |
| |
| // Helper stub to disable histogram tracking in StatisticsRecorder |
| struct RecordCheckerStub : public base::RecordHistogramChecker { |
| bool ShouldRecord(uint64_t) const override { return false; } |
| }; |
| |
| // Static user logs |
| ssize_t Application::available_memory_ = 0; |
| int64 Application::lifetime_in_ms_ = 0; |
| |
| Application::AppStatus Application::app_status_ = |
| Application::kUninitializedAppStatus; |
| |
| Application::Application(const base::Closure& quit_closure, bool should_preload) |
| : message_loop_(base::MessageLoop::current()), |
| quit_closure_(quit_closure) |
| #if defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| , |
| ALLOW_THIS_IN_INITIALIZER_LIST(memory_tracker_command_handler_( |
| kMemoryTrackerCommand, |
| base::Bind(&Application::OnMemoryTrackerCommand, |
| base::Unretained(this)), |
| kMemoryTrackerCommandShortHelp, kMemoryTrackerCommandLongHelp)) |
| #endif // defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| { |
| DCHECK(!quit_closure_.is_null()); |
| // Check to see if a timed_trace has been set, indicating that we should |
| // begin a timed trace upon startup. |
| base::TimeDelta trace_duration = GetTimedTraceDuration(); |
| if (trace_duration != base::TimeDelta()) { |
| trace_event::TraceToFileForDuration( |
| base::FilePath(FILE_PATH_LITERAL("timed_trace.json")), trace_duration); |
| } |
| |
| TRACE_EVENT0("cobalt::browser", "Application::Application()"); |
| |
| DCHECK(base::MessageLoop::current()); |
| DCHECK_EQ( |
| base::MessageLoop::TYPE_UI, |
| static_cast<base::MessageLoop*>(base::MessageLoop::current())->type()); |
| |
| DETACH_FROM_THREAD(network_event_thread_checker_); |
| DETACH_FROM_THREAD(application_event_thread_checker_); |
| |
| // Set the minimum logging level, if specified on the command line. |
| logging::SetMinLogLevel(StringToLogLevel(GetMinLogLevelString())); |
| |
| stats_update_timer_.Start( |
| FROM_HERE, base::TimeDelta::FromMilliseconds(kStatUpdatePeriodMs), |
| base::Bind(&Application::UpdatePeriodicStats, base::Unretained(this))); |
| |
| // Get the initial URL. |
| GURL initial_url = GetInitialURL(should_preload); |
| DLOG(INFO) << "Initial URL: " << initial_url; |
| |
| // Get the fallback splash screen URL. |
| base::Optional<GURL> fallback_splash_screen_url = |
| GetFallbackSplashScreenURL(); |
| DLOG(INFO) << "Fallback splash screen URL: " |
| << (fallback_splash_screen_url ? fallback_splash_screen_url->spec() |
| : "none"); |
| |
| // Get the system language and initialize our localized strings. |
| std::string language = base::GetSystemLanguage(); |
| base::LocalizedStrings::GetInstance()->Initialize(language); |
| |
| // Disable histogram tracking before TaskScheduler creates StatisticsRecorder |
| // instances. |
| auto record_checker = std::make_unique<RecordCheckerStub>(); |
| base::StatisticsRecorder::SetRecordChecker(std::move(record_checker)); |
| |
| // A one-per-process task scheduler is needed for usage of APIs in |
| // base/post_task.h which will be used by some net APIs like |
| // URLRequestContext; |
| base::TaskScheduler::CreateAndStartWithDefaultParams("Cobalt TaskScheduler"); |
| |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| base::Optional<cssom::ViewportSize> requested_viewport_size = |
| GetRequestedViewportSize(command_line); |
| |
| unconsumed_deep_link_ = GetInitialDeepLink(); |
| DLOG(INFO) << "Initial deep link: " << unconsumed_deep_link_; |
| |
| WebModule::Options web_options; |
| storage::StorageManager::Options storage_manager_options; |
| network::NetworkModule::Options network_module_options; |
| // Create the main components of our browser. |
| BrowserModule::Options options(web_options); |
| options.web_module_options.name = "MainWebModule"; |
| network_module_options.preferred_language = language; |
| options.command_line_auto_mem_settings = |
| memory_settings::GetSettings(*command_line); |
| options.build_auto_mem_settings = memory_settings::GetDefaultBuildSettings(); |
| options.fallback_splash_screen_url = fallback_splash_screen_url; |
| |
| ParseFallbackSplashScreenTopics(fallback_splash_screen_url, |
| &options.fallback_splash_screen_topic_map); |
| |
| if (command_line->HasSwitch(browser::switches::kFPSPrint)) { |
| options.renderer_module_options.enable_fps_stdout = true; |
| } |
| if (command_line->HasSwitch(browser::switches::kFPSOverlay)) { |
| options.renderer_module_options.enable_fps_overlay = true; |
| } |
| |
| ApplyCommandLineSettingsToRendererOptions(&options.renderer_module_options); |
| |
| if (command_line->HasSwitch(browser::switches::kDisableJavaScriptJit)) { |
| options.web_module_options.javascript_engine_options.disable_jit = true; |
| } |
| |
| if (command_line->HasSwitch( |
| browser::switches::kRetainRemoteTypefaceCacheDuringSuspend)) { |
| options.web_module_options.should_retain_remote_typeface_cache_on_freeze = |
| true; |
| } |
| |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| if (command_line->HasSwitch(browser::switches::kNullSavegame)) { |
| storage_manager_options.savegame_options.factory = |
| &storage::SavegameFake::Create; |
| } |
| #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| if (command_line->HasSwitch(browser::switches::kDisableOnScreenKeyboard)) { |
| options.enable_on_screen_keyboard = false; |
| } |
| #endif // SB_API_VERSION >= 12 || |
| // SB_HAS(ON_SCREEN_KEYBOARD) |
| |
| #endif // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| |
| #if defined(COBALT_ENABLE_VERSION_COMPATIBILITY_VALIDATIONS) |
| constexpr int kDefaultMinCompatibilityVersion = 1; |
| int minimum_version = kDefaultMinCompatibilityVersion; |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| if (command_line->HasSwitch(browser::switches::kMinCompatibilityVersion)) { |
| std::string switch_value = |
| command_line->GetSwitchValueASCII(switches::kMinCompatibilityVersion); |
| if (!base::StringToInt(switch_value, &minimum_version)) { |
| DLOG(ERROR) << "Invalid min_compatibility_version provided."; |
| } |
| } |
| #endif // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| base::VersionCompatibility::GetInstance()->SetMinimumVersion(minimum_version); |
| #endif // defined(COBALT_ENABLE_VERSION_COMPATIBILITY_VALIDATIONS) |
| |
| base::Optional<std::string> partition_key; |
| if (command_line->HasSwitch(browser::switches::kLocalStoragePartitionUrl)) { |
| std::string local_storage_partition_url = command_line->GetSwitchValueASCII( |
| browser::switches::kLocalStoragePartitionUrl); |
| partition_key = base::GetApplicationKey(GURL(local_storage_partition_url)); |
| CHECK(partition_key) << "local_storage_partition_url is not a valid URL."; |
| } else { |
| partition_key = base::GetApplicationKey(initial_url); |
| } |
| storage_manager_options.savegame_options.id = partition_key; |
| |
| base::Optional<std::string> default_key = |
| base::GetApplicationKey(GURL(kDefaultURL)); |
| if (command_line->HasSwitch( |
| browser::switches::kForceMigrationForStoragePartitioning) || |
| partition_key == default_key) { |
| storage_manager_options.savegame_options.fallback_to_default_id = true; |
| } |
| |
| // User can specify an extra search path entry for files loaded via file://. |
| options.web_module_options.extra_web_file_dir = GetExtraWebFileDir(); |
| SecurityFlags security_flags{csp::kCSPRequired, network::kHTTPSRequired}; |
| // Set callback to be notified when a navigation occurs that destroys the |
| // underlying WebModule. |
| options.web_module_created_callback = |
| base::Bind(&Application::WebModuleCreated, base::Unretained(this)); |
| |
| // The main web module's stat tracker tracks event stats. |
| options.web_module_options.track_event_stats = true; |
| |
| if (command_line->HasSwitch(browser::switches::kProxy)) { |
| network_module_options.custom_proxy = |
| command_line->GetSwitchValueASCII(browser::switches::kProxy); |
| } |
| |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| #if defined(ENABLE_IGNORE_CERTIFICATE_ERRORS) |
| if (command_line->HasSwitch(browser::switches::kIgnoreCertificateErrors)) { |
| network_module_options.ignore_certificate_errors = true; |
| } |
| #endif // defined(ENABLE_IGNORE_CERTIFICATE_ERRORS) |
| |
| if (!command_line->HasSwitch(switches::kRequireHTTPSLocation)) { |
| security_flags.https_requirement = network::kHTTPSOptional; |
| } |
| |
| if (!command_line->HasSwitch(browser::switches::kRequireCSP)) { |
| security_flags.csp_header_policy = csp::kCSPOptional; |
| } |
| |
| if (command_line->HasSwitch(browser::switches::kProd)) { |
| security_flags.https_requirement = network::kHTTPSRequired; |
| security_flags.csp_header_policy = csp::kCSPRequired; |
| } |
| |
| if (command_line->HasSwitch(switches::kVideoPlaybackRateMultiplier)) { |
| double playback_rate = 1.0; |
| base::StringToDouble(command_line->GetSwitchValueASCII( |
| switches::kVideoPlaybackRateMultiplier), |
| &playback_rate); |
| options.web_module_options.video_playback_rate_multiplier = |
| static_cast<float>(playback_rate); |
| DLOG(INFO) << "Set video playback rate multiplier to " |
| << options.web_module_options.video_playback_rate_multiplier; |
| } |
| |
| EnableUsingStubImageDecoderIfRequired(); |
| |
| #if defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| if (command_line->HasSwitch(switches::kMemoryTracker)) { |
| std::string command_arg = |
| command_line->GetSwitchValueASCII(switches::kMemoryTracker); |
| memory_tracker_tool_ = memory_tracker::CreateMemoryTrackerTool(command_arg); |
| } |
| #endif // defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| |
| if (command_line->HasSwitch(switches::kDisableImageAnimations)) { |
| options.web_module_options.enable_image_animations = false; |
| } |
| if (command_line->HasSwitch(switches::kDisableSplashScreenOnReloads)) { |
| options.enable_splash_screen_on_reloads = false; |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| |
| // Production-builds override all switches to the most secure configuration. |
| #if defined(COBALT_FORCE_HTTPS) |
| security_flags.https_requirement = network::kHTTPSRequired; |
| #endif // defined(COBALT_FORCE_HTTPS) |
| |
| #if defined(COBALT_FORCE_CSP) |
| security_flags.csp_header_policy = csp::kCSPRequired; |
| #endif // defined(COBALT_FORCE_CSP) |
| |
| network_module_options.https_requirement = security_flags.https_requirement; |
| options.web_module_options.require_csp = security_flags.csp_header_policy; |
| options.web_module_options.csp_enforcement_mode = dom::kCspEnforcementEnable; |
| |
| options.requested_viewport_size = requested_viewport_size; |
| account_manager_.reset(new account::AccountManager()); |
| |
| storage_manager_.reset(new storage::StorageManager( |
| std::unique_ptr<storage::StorageManager::UpgradeHandler>( |
| new StorageUpgradeHandler(initial_url)), |
| storage_manager_options)); |
| |
| network_module_.reset(new network::NetworkModule( |
| CreateUserAgentString(GetUserAgentPlatformInfoFromSystem()), |
| storage_manager_.get(), &event_dispatcher_, network_module_options)); |
| |
| #if SB_API_VERSION >= 11 |
| AddCrashHandlerAnnotations(); |
| #endif |
| |
| #if SB_IS(EVERGREEN) |
| if (SbSystemGetExtension(kCobaltExtensionInstallationManagerName)) { |
| updater_module_.reset(new updater::UpdaterModule(network_module_.get())); |
| } |
| #endif |
| browser_module_.reset(new BrowserModule( |
| initial_url, |
| (should_preload ? base::kApplicationStateConcealed |
| : base::kApplicationStateStarted), |
| &event_dispatcher_, account_manager_.get(), network_module_.get(), |
| #if SB_IS(EVERGREEN) |
| updater_module_.get(), |
| #endif |
| options)); |
| |
| UpdateUserAgent(); |
| |
| app_status_ = (should_preload ? kConcealedAppStatus : kRunningAppStatus); |
| |
| // Register event callbacks. |
| #if SB_API_VERSION >= 8 |
| window_size_change_event_callback_ = base::Bind( |
| &Application::OnWindowSizeChangedEvent, base::Unretained(this)); |
| event_dispatcher_.AddEventCallback(base::WindowSizeChangedEvent::TypeId(), |
| window_size_change_event_callback_); |
| #endif // SB_API_VERSION >= 8 |
| #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| on_screen_keyboard_shown_event_callback_ = base::Bind( |
| &Application::OnOnScreenKeyboardShownEvent, base::Unretained(this)); |
| event_dispatcher_.AddEventCallback(base::OnScreenKeyboardShownEvent::TypeId(), |
| on_screen_keyboard_shown_event_callback_); |
| on_screen_keyboard_hidden_event_callback_ = base::Bind( |
| &Application::OnOnScreenKeyboardHiddenEvent, base::Unretained(this)); |
| event_dispatcher_.AddEventCallback( |
| base::OnScreenKeyboardHiddenEvent::TypeId(), |
| on_screen_keyboard_hidden_event_callback_); |
| on_screen_keyboard_focused_event_callback_ = base::Bind( |
| &Application::OnOnScreenKeyboardFocusedEvent, base::Unretained(this)); |
| event_dispatcher_.AddEventCallback( |
| base::OnScreenKeyboardFocusedEvent::TypeId(), |
| on_screen_keyboard_focused_event_callback_); |
| on_screen_keyboard_blurred_event_callback_ = base::Bind( |
| &Application::OnOnScreenKeyboardBlurredEvent, base::Unretained(this)); |
| event_dispatcher_.AddEventCallback( |
| base::OnScreenKeyboardBlurredEvent::TypeId(), |
| on_screen_keyboard_blurred_event_callback_); |
| #if SB_API_VERSION >= 11 |
| on_screen_keyboard_suggestions_updated_event_callback_ = |
| base::Bind(&Application::OnOnScreenKeyboardSuggestionsUpdatedEvent, |
| base::Unretained(this)); |
| event_dispatcher_.AddEventCallback( |
| base::OnScreenKeyboardSuggestionsUpdatedEvent::TypeId(), |
| on_screen_keyboard_suggestions_updated_event_callback_); |
| #endif // SB_API_VERSION >= 11 |
| #endif // SB_API_VERSION >= 12 || |
| // SB_HAS(ON_SCREEN_KEYBOARD) |
| |
| #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| on_caption_settings_changed_event_callback_ = base::Bind( |
| &Application::OnCaptionSettingsChangedEvent, base::Unretained(this)); |
| event_dispatcher_.AddEventCallback( |
| base::AccessibilityCaptionSettingsChangedEvent::TypeId(), |
| on_caption_settings_changed_event_callback_); |
| #endif // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| #if defined(ENABLE_WEBDRIVER) |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| bool create_webdriver_module = |
| !command_line->HasSwitch(switches::kDisableWebDriver); |
| #else |
| bool create_webdriver_module = true; |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| if (create_webdriver_module) { |
| web_driver_module_.reset(new webdriver::WebDriverModule( |
| GetWebDriverPort(), GetWebDriverListenIp(), |
| base::Bind(&BrowserModule::CreateSessionDriver, |
| base::Unretained(browser_module_.get())), |
| base::Bind(&BrowserModule::RequestScreenshotToMemory, |
| base::Unretained(browser_module_.get())), |
| base::Bind(&BrowserModule::SetProxy, |
| base::Unretained(browser_module_.get())), |
| base::Bind(&Application::Quit, base::Unretained(this)))); |
| } |
| #endif // ENABLE_WEBDRIVER |
| |
| #if defined(ENABLE_DEBUGGER) |
| int remote_debugging_port = GetRemoteDebuggingPort(); |
| if (remote_debugging_port == 0) { |
| DLOG(INFO) << "Remote web debugger disabled because " |
| << switches::kRemoteDebuggingPort << " is 0."; |
| } else { |
| debug_web_server_.reset(new debug::remote::DebugWebServer( |
| remote_debugging_port, GetDevServersListenIp(), |
| base::Bind(&BrowserModule::CreateDebugClient, |
| base::Unretained(browser_module_.get())))); |
| } |
| #endif // ENABLE_DEBUGGER |
| |
| #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) |
| int duration_in_seconds = 0; |
| if (command_line->HasSwitch(switches::kShutdownAfter) && |
| base::StringToInt( |
| command_line->GetSwitchValueASCII(switches::kShutdownAfter), |
| &duration_in_seconds)) { |
| // If the "shutdown_after" command line option is specified, setup a delayed |
| // message to quit the application after the specified number of seconds |
| // have passed. |
| message_loop_->task_runner()->PostDelayedTask( |
| FROM_HERE, quit_closure_, |
| base::TimeDelta::FromSeconds(duration_in_seconds)); |
| } |
| #endif // ENABLE_DEBUG_COMMAND_LINE_SWITCHES |
| } |
| |
| Application::~Application() { |
| // explicitly reset here because the destruction of the object is complex |
| // and involves a thread join. If this were to hang the app then having |
| // the destruction at this point gives a real file-line number and a place |
| // for the debugger to land. |
| #if defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| memory_tracker_tool_.reset(NULL); |
| #endif // defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| |
| // Unregister event callbacks. |
| #if SB_API_VERSION >= 8 |
| event_dispatcher_.RemoveEventCallback(base::WindowSizeChangedEvent::TypeId(), |
| window_size_change_event_callback_); |
| #endif // SB_API_VERSION >= 8 |
| #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| event_dispatcher_.RemoveEventCallback( |
| base::OnScreenKeyboardShownEvent::TypeId(), |
| on_screen_keyboard_shown_event_callback_); |
| event_dispatcher_.RemoveEventCallback( |
| base::OnScreenKeyboardHiddenEvent::TypeId(), |
| on_screen_keyboard_hidden_event_callback_); |
| event_dispatcher_.RemoveEventCallback( |
| base::OnScreenKeyboardFocusedEvent::TypeId(), |
| on_screen_keyboard_focused_event_callback_); |
| event_dispatcher_.RemoveEventCallback( |
| base::OnScreenKeyboardBlurredEvent::TypeId(), |
| on_screen_keyboard_blurred_event_callback_); |
| #if SB_API_VERSION >= 11 |
| event_dispatcher_.RemoveEventCallback( |
| base::OnScreenKeyboardSuggestionsUpdatedEvent::TypeId(), |
| on_screen_keyboard_suggestions_updated_event_callback_); |
| #endif // SB_API_VERSION >= 11 |
| #endif // SB_API_VERSION >= 12 || |
| // SB_HAS(ON_SCREEN_KEYBOARD) |
| #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| event_dispatcher_.RemoveEventCallback( |
| base::AccessibilityCaptionSettingsChangedEvent::TypeId(), |
| on_caption_settings_changed_event_callback_); |
| #endif // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| |
| app_status_ = kShutDownAppStatus; |
| } |
| |
| void Application::Start() { |
| if (base::MessageLoop::current() != message_loop_) { |
| message_loop_->task_runner()->PostTask( |
| FROM_HERE, base::Bind(&Application::Start, base::Unretained(this))); |
| return; |
| } |
| |
| if (app_status_ != kConcealedAppStatus) { |
| NOTREACHED() << __FUNCTION__ << ": Redundant call."; |
| return; |
| } |
| |
| OnApplicationEvent(kSbEventTypeStart); |
| } |
| |
| void Application::Quit() { |
| if (base::MessageLoop::current() != message_loop_) { |
| message_loop_->task_runner()->PostTask( |
| FROM_HERE, base::Bind(&Application::Quit, base::Unretained(this))); |
| return; |
| } |
| |
| quit_closure_.Run(); |
| app_status_ = kQuitAppStatus; |
| } |
| |
| void Application::HandleStarboardEvent(const SbEvent* starboard_event) { |
| DCHECK(starboard_event); |
| DCHECK_EQ(base::MessageLoop::current(), message_loop_); |
| |
| // Forward input events to |SystemWindow|. |
| if (starboard_event->type == kSbEventTypeInput) { |
| system_window::HandleInputEvent(starboard_event); |
| return; |
| } |
| |
| // Create a Cobalt event from the Starboard event, if recognized. |
| switch (starboard_event->type) { |
| #if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \ |
| SB_HAS(CONCEALED_STATE) |
| case kSbEventTypeBlur: |
| case kSbEventTypeFocus: |
| case kSbEventTypeConceal: |
| case kSbEventTypeReveal: |
| case kSbEventTypeFreeze: |
| case kSbEventTypeUnfreeze: |
| case kSbEventTypeLowMemory: |
| OnApplicationEvent(starboard_event->type); |
| break; |
| #else |
| case kSbEventTypePause: |
| case kSbEventTypeUnpause: |
| case kSbEventTypeSuspend: |
| case kSbEventTypeResume: |
| case kSbEventTypeLowMemory: |
| OnApplicationEvent(starboard_event->type); |
| break; |
| #endif // SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || |
| // SB_HAS(CONCEALED_STATE) |
| #if SB_API_VERSION >= 8 |
| case kSbEventTypeWindowSizeChanged: |
| DispatchEventInternal(new base::WindowSizeChangedEvent( |
| static_cast<SbEventWindowSizeChangedData*>(starboard_event->data) |
| ->window, |
| static_cast<SbEventWindowSizeChangedData*>(starboard_event->data) |
| ->size)); |
| break; |
| #endif // SB_API_VERSION >= 8 |
| #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| case kSbEventTypeOnScreenKeyboardShown: |
| DCHECK(starboard_event->data); |
| DispatchEventInternal(new base::OnScreenKeyboardShownEvent( |
| *static_cast<int*>(starboard_event->data))); |
| break; |
| case kSbEventTypeOnScreenKeyboardHidden: |
| DispatchEventInternal(new base::OnScreenKeyboardHiddenEvent( |
| *static_cast<int*>(starboard_event->data))); |
| break; |
| case kSbEventTypeOnScreenKeyboardFocused: |
| DCHECK(starboard_event->data); |
| DispatchEventInternal(new base::OnScreenKeyboardFocusedEvent( |
| *static_cast<int*>(starboard_event->data))); |
| break; |
| case kSbEventTypeOnScreenKeyboardBlurred: |
| DispatchEventInternal(new base::OnScreenKeyboardBlurredEvent( |
| *static_cast<int*>(starboard_event->data))); |
| break; |
| #if SB_API_VERSION >= 11 |
| case kSbEventTypeOnScreenKeyboardSuggestionsUpdated: |
| DispatchEventInternal(new base::OnScreenKeyboardSuggestionsUpdatedEvent( |
| *static_cast<int*>(starboard_event->data))); |
| break; |
| #endif // SB_API_VERSION >= 11 |
| #endif // SB_API_VERSION >= 12 || |
| // SB_HAS(ON_SCREEN_KEYBOARD) |
| case kSbEventTypeLink: { |
| DispatchDeepLink(static_cast<const char*>(starboard_event->data)); |
| break; |
| } |
| case kSbEventTypeAccessiblitySettingsChanged: |
| DispatchEventInternal(new base::AccessibilitySettingsChangedEvent()); |
| #if SB_API_VERSION < 12 |
| // Also dispatch the newer text-to-speech settings changed event since |
| // the specific kSbEventTypeAccessiblityTextToSpeechSettingsChanged |
| // event is not available in this starboard version. |
| DispatchEventInternal( |
| new base::AccessibilityTextToSpeechSettingsChangedEvent()); |
| #endif |
| break; |
| #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| case kSbEventTypeAccessibilityCaptionSettingsChanged: |
| DispatchEventInternal( |
| new base::AccessibilityCaptionSettingsChangedEvent()); |
| break; |
| #endif // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| #if SB_API_VERSION >= 12 |
| case kSbEventTypeAccessiblityTextToSpeechSettingsChanged: |
| DispatchEventInternal( |
| new base::AccessibilityTextToSpeechSettingsChangedEvent()); |
| break; |
| #endif |
| // Explicitly list unhandled cases here so that the compiler can give a |
| // warning when a value is added, but not handled. |
| case kSbEventTypeInput: |
| case kSbEventTypePreload: |
| #if SB_API_VERSION < 11 |
| case kSbEventTypeNetworkConnect: |
| case kSbEventTypeNetworkDisconnect: |
| #endif // SB_API_VERSION < 11 |
| case kSbEventTypeScheduled: |
| case kSbEventTypeStart: |
| case kSbEventTypeStop: |
| case kSbEventTypeUser: |
| case kSbEventTypeVerticalSync: |
| DLOG(WARNING) << "Unhandled Starboard event of type: " |
| << starboard_event->type; |
| } |
| } |
| |
| void Application::OnApplicationEvent(SbEventType event_type) { |
| TRACE_EVENT0("cobalt::browser", "Application::OnApplicationEvent()"); |
| DCHECK_CALLED_ON_VALID_THREAD(application_event_thread_checker_); |
| switch (event_type) { |
| case kSbEventTypeStop: |
| DLOG(INFO) << "Got quit event."; |
| app_status_ = kWillQuitAppStatus; |
| Quit(); |
| DLOG(INFO) << "Finished quitting."; |
| break; |
| case kSbEventTypeStart: |
| DLOG(INFO) << "Got start event."; |
| app_status_ = kRunningAppStatus; |
| browser_module_->Reveal(); |
| browser_module_->Focus(); |
| DLOG(INFO) << "Finished starting."; |
| break; |
| #if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \ |
| SB_HAS(CONCEALED_STATE) |
| case kSbEventTypeBlur: |
| DLOG(INFO) << "Got blur event."; |
| app_status_ = kBlurredAppStatus; |
| browser_module_->Blur(); |
| DLOG(INFO) << "Finished blurring."; |
| break; |
| case kSbEventTypeFocus: |
| DLOG(INFO) << "Got focus event."; |
| app_status_ = kRunningAppStatus; |
| browser_module_->Focus(); |
| DLOG(INFO) << "Finished focusing."; |
| break; |
| case kSbEventTypeConceal: |
| DLOG(INFO) << "Got conceal event."; |
| app_status_ = kConcealedAppStatus; |
| browser_module_->Conceal(); |
| DLOG(INFO) << "Finished concealing."; |
| break; |
| case kSbEventTypeReveal: |
| DCHECK(SbSystemSupportsResume()); |
| DLOG(INFO) << "Got reveal event."; |
| app_status_ = kBlurredAppStatus; |
| browser_module_->Reveal(); |
| DLOG(INFO) << "Finished revealing."; |
| break; |
| case kSbEventTypeFreeze: |
| DLOG(INFO) << "Got freeze event."; |
| app_status_ = kFrozenAppStatus; |
| browser_module_->Freeze(); |
| #if SB_IS(EVERGREEN) |
| if (updater_module_) updater_module_->Suspend(); |
| #endif |
| DLOG(INFO) << "Finished freezing."; |
| break; |
| case kSbEventTypeUnfreeze: |
| DLOG(INFO) << "Got unfreeze event."; |
| app_status_ = kConcealedAppStatus; |
| browser_module_->Unfreeze(); |
| #if SB_IS(EVERGREEN) |
| if (updater_module_) updater_module_->Resume(); |
| #endif |
| DLOG(INFO) << "Finished unfreezing."; |
| break; |
| #else |
| case kSbEventTypePause: |
| DLOG(INFO) << "Got pause event."; |
| app_status_ = kBlurredAppStatus; |
| browser_module_->Blur(); |
| DLOG(INFO) << "Finished pausing."; |
| break; |
| case kSbEventTypeUnpause: |
| DLOG(INFO) << "Got unpause event."; |
| app_status_ = kRunningAppStatus; |
| browser_module_->Focus(); |
| DLOG(INFO) << "Finished unpausing."; |
| break; |
| case kSbEventTypeSuspend: |
| DLOG(INFO) << "Got suspend event."; |
| app_status_ = kConcealedAppStatus; |
| browser_module_->Conceal(); |
| app_status_ = kFrozenAppStatus; |
| browser_module_->Freeze(); |
| #if SB_IS(EVERGREEN) |
| if (updater_module_) updater_module_->Suspend(); |
| #endif |
| DLOG(INFO) << "Finished suspending."; |
| break; |
| case kSbEventTypeResume: |
| DCHECK(SbSystemSupportsResume()); |
| DLOG(INFO) << "Got resume event."; |
| app_status_ = kConcealedAppStatus; |
| browser_module_->Unfreeze(); |
| app_status_ = kBlurredAppStatus; |
| browser_module_->Reveal(); |
| #if SB_IS(EVERGREEN) |
| if (updater_module_) updater_module_->Resume(); |
| #endif |
| DLOG(INFO) << "Finished resuming."; |
| break; |
| #endif // SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || |
| // SB_HAS(CONCEALED_STATE) |
| case kSbEventTypeLowMemory: |
| DLOG(INFO) << "Got low memory event."; |
| browser_module_->ReduceMemory(); |
| DLOG(INFO) << "Finished reducing memory usage."; |
| break; |
| // All of the remaining event types are unexpected: |
| case kSbEventTypePreload: |
| #if SB_API_VERSION >= 8 |
| case kSbEventTypeWindowSizeChanged: |
| #endif |
| #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| case kSbEventTypeAccessibilityCaptionSettingsChanged: |
| #endif // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| #if SB_API_VERSION >= 12 |
| case kSbEventTypeAccessiblityTextToSpeechSettingsChanged: |
| #endif // SB_API_VERSION >= 12 |
| #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| case kSbEventTypeOnScreenKeyboardBlurred: |
| case kSbEventTypeOnScreenKeyboardFocused: |
| case kSbEventTypeOnScreenKeyboardHidden: |
| case kSbEventTypeOnScreenKeyboardShown: |
| #if SB_API_VERSION >= 11 |
| case kSbEventTypeOnScreenKeyboardSuggestionsUpdated: |
| #endif // SB_API_VERSION >= 11 |
| #endif // SB_API_VERSION >= 12 || |
| // SB_HAS(ON_SCREEN_KEYBOARD) |
| case kSbEventTypeAccessiblitySettingsChanged: |
| case kSbEventTypeInput: |
| case kSbEventTypeLink: |
| #if SB_API_VERSION < 11 |
| case kSbEventTypeNetworkConnect: |
| case kSbEventTypeNetworkDisconnect: |
| #endif // SB_API_VERSION < 11 |
| case kSbEventTypeScheduled: |
| case kSbEventTypeUser: |
| case kSbEventTypeVerticalSync: |
| NOTREACHED() << "Unexpected event type: " << event_type; |
| return; |
| } |
| } |
| |
| #if SB_API_VERSION >= 8 |
| void Application::OnWindowSizeChangedEvent(const base::Event* event) { |
| TRACE_EVENT0("cobalt::browser", "Application::OnWindowSizeChangedEvent()"); |
| const base::WindowSizeChangedEvent* window_size_change_event = |
| base::polymorphic_downcast<const base::WindowSizeChangedEvent*>(event); |
| const auto& size = window_size_change_event->size(); |
| #if SB_API_VERSION >= 11 |
| float diagonal = |
| SbWindowGetDiagonalSizeInInches(window_size_change_event->window()); |
| #else |
| float diagonal = 0.0f; // Special value meaning diagonal size is not known. |
| #endif |
| |
| // A value of 0.0 for the video pixel ratio means that the ratio could not be |
| // determined. In that case it should be assumed to be the same as the |
| // graphics resolution, which corresponds to a device pixel ratio of 1.0. |
| float device_pixel_ratio = |
| (size.video_pixel_ratio == 0) ? 1.0f : size.video_pixel_ratio; |
| cssom::ViewportSize viewport_size(size.width, size.height, diagonal, |
| device_pixel_ratio); |
| browser_module_->OnWindowSizeChanged(viewport_size); |
| } |
| #endif // SB_API_VERSION >= 8 |
| |
| #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| void Application::OnOnScreenKeyboardShownEvent(const base::Event* event) { |
| TRACE_EVENT0("cobalt::browser", |
| "Application::OnOnScreenKeyboardShownEvent()"); |
| browser_module_->OnOnScreenKeyboardShown( |
| base::polymorphic_downcast<const base::OnScreenKeyboardShownEvent*>( |
| event)); |
| } |
| |
| void Application::OnOnScreenKeyboardHiddenEvent(const base::Event* event) { |
| TRACE_EVENT0("cobalt::browser", |
| "Application::OnOnScreenKeyboardHiddenEvent()"); |
| browser_module_->OnOnScreenKeyboardHidden( |
| base::polymorphic_downcast<const base::OnScreenKeyboardHiddenEvent*>( |
| event)); |
| } |
| |
| void Application::OnOnScreenKeyboardFocusedEvent(const base::Event* event) { |
| TRACE_EVENT0("cobalt::browser", |
| "Application::OnOnScreenKeyboardFocusedEvent()"); |
| browser_module_->OnOnScreenKeyboardFocused( |
| base::polymorphic_downcast<const base::OnScreenKeyboardFocusedEvent*>( |
| event)); |
| } |
| |
| void Application::OnOnScreenKeyboardBlurredEvent(const base::Event* event) { |
| TRACE_EVENT0("cobalt::browser", |
| "Application::OnOnScreenKeyboardBlurredEvent()"); |
| browser_module_->OnOnScreenKeyboardBlurred( |
| base::polymorphic_downcast<const base::OnScreenKeyboardBlurredEvent*>( |
| event)); |
| } |
| |
| #if SB_API_VERSION >= 11 |
| void Application::OnOnScreenKeyboardSuggestionsUpdatedEvent( |
| const base::Event* event) { |
| TRACE_EVENT0("cobalt::browser", |
| "Application::OnOnScreenKeyboardSuggestionsUpdatedEvent()"); |
| browser_module_->OnOnScreenKeyboardSuggestionsUpdated( |
| base::polymorphic_downcast< |
| const base::OnScreenKeyboardSuggestionsUpdatedEvent*>(event)); |
| } |
| #endif // SB_API_VERSION >= 11 |
| #endif // SB_API_VERSION >= 12 || |
| // SB_HAS(ON_SCREEN_KEYBOARD) |
| |
| #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| void Application::OnCaptionSettingsChangedEvent(const base::Event* event) { |
| TRACE_EVENT0("cobalt::browser", |
| "Application::OnCaptionSettingsChangedEvent()"); |
| browser_module_->OnCaptionSettingsChanged( |
| base::polymorphic_downcast< |
| const base::AccessibilityCaptionSettingsChangedEvent*>(event)); |
| } |
| #endif // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS) |
| |
| void Application::WebModuleCreated() { |
| TRACE_EVENT0("cobalt::browser", "Application::WebModuleCreated()"); |
| DispatchDeepLinkIfNotConsumed(); |
| #if defined(ENABLE_WEBDRIVER) |
| if (web_driver_module_) { |
| web_driver_module_->OnWindowRecreated(); |
| } |
| #endif |
| } |
| |
| Application::CValStats::CValStats() |
| : free_cpu_memory("Memory.CPU.Free", 0, |
| "Total free application CPU memory remaining."), |
| used_cpu_memory("Memory.CPU.Used", 0, |
| "Total CPU memory allocated via the app's allocators."), |
| app_start_time("Time.Cobalt.Start", |
| base::StartupTimer::StartTime().ToInternalValue(), |
| "Start time of the application in microseconds."), |
| app_lifetime("Cobalt.Lifetime", base::TimeDelta(), |
| "Application lifetime in microseconds.") { |
| if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) { |
| free_gpu_memory.emplace("Memory.GPU.Free", 0, |
| "Total free application GPU memory remaining."); |
| used_gpu_memory.emplace("Memory.GPU.Used", 0, |
| "Total GPU memory allocated by the application."); |
| } |
| } |
| |
| // NOTE: UserAgent registration is handled separately, as the value is not |
| // available when the app is first being constructed. Registration must happen |
| // each time the user agent is modified, because the string may be pointing |
| // to a new location on the heap. |
| void Application::UpdateUserAgent() { |
| non_trivial_static_fields.Get().user_agent = browser_module_->GetUserAgent(); |
| LOG(INFO) << "User Agent: " << non_trivial_static_fields.Get().user_agent; |
| } |
| |
| void Application::UpdatePeriodicStats() { |
| TRACE_EVENT0("cobalt::browser", "Application::UpdatePeriodicStats()"); |
| c_val_stats_.app_lifetime = base::StartupTimer::TimeElapsed(); |
| |
| int64_t used_cpu_memory = SbSystemGetUsedCPUMemory(); |
| base::Optional<int64_t> used_gpu_memory; |
| if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) { |
| used_gpu_memory = SbSystemGetUsedGPUMemory(); |
| } |
| |
| available_memory_ = |
| static_cast<ssize_t>(SbSystemGetTotalCPUMemory() - used_cpu_memory); |
| c_val_stats_.free_cpu_memory = available_memory_; |
| c_val_stats_.used_cpu_memory = used_cpu_memory; |
| |
| if (used_gpu_memory) { |
| *c_val_stats_.free_gpu_memory = |
| SbSystemGetTotalGPUMemory() - *used_gpu_memory; |
| *c_val_stats_.used_gpu_memory = *used_gpu_memory; |
| } |
| |
| browser_module_->UpdateJavaScriptHeapStatistics(); |
| |
| browser_module_->CheckMemory(used_cpu_memory, used_gpu_memory); |
| } |
| |
| void Application::DispatchEventInternal(base::Event* event) { |
| event_dispatcher_.DispatchEvent(std::unique_ptr<base::Event>(event)); |
| } |
| |
| #if defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| void Application::OnMemoryTrackerCommand(const std::string& message) { |
| if (base::MessageLoop::current() != message_loop_) { |
| message_loop_->task_runner()->PostTask( |
| FROM_HERE, base::Bind(&Application::OnMemoryTrackerCommand, |
| base::Unretained(this), message)); |
| return; |
| } |
| |
| if (memory_tracker_tool_) { |
| LOG(ERROR) << "Can not create a memory tracker when one is already active."; |
| return; |
| } |
| LOG(WARNING) << "Creating \"" << message << "\" memory tracker."; |
| memory_tracker_tool_ = memory_tracker::CreateMemoryTrackerTool(message); |
| } |
| #endif // defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) |
| |
| // Called to handle deep link consumed events. |
| void Application::OnDeepLinkConsumedCallback(const std::string& link) { |
| LOG(INFO) << "Got deep link consumed callback: " << link; |
| base::AutoLock auto_lock(unconsumed_deep_link_lock_); |
| if (link == unconsumed_deep_link_) { |
| unconsumed_deep_link_.clear(); |
| } |
| } |
| |
| void Application::DispatchDeepLink(const char* link) { |
| if (!link || *link == 0) { |
| return; |
| } |
| |
| std::string deep_link; |
| // This block exists to ensure that the lock is held while accessing |
| // unconsumed_deep_link_. |
| { |
| base::AutoLock auto_lock(unconsumed_deep_link_lock_); |
| // Stash the deep link so that if it is not consumed, it can be dispatched |
| // again after the next WebModule is created. |
| unconsumed_deep_link_ = link; |
| deep_link = unconsumed_deep_link_; |
| } |
| |
| LOG(INFO) << "Dispatching deep link: " << deep_link; |
| DispatchEventInternal(new base::DeepLinkEvent( |
| deep_link, base::Bind(&Application::OnDeepLinkConsumedCallback, |
| base::Unretained(this), deep_link))); |
| } |
| |
| void Application::DispatchDeepLinkIfNotConsumed() { |
| std::string deep_link; |
| // This block exists to ensure that the lock is held while accessing |
| // unconsumed_deep_link_. |
| { |
| base::AutoLock auto_lock(unconsumed_deep_link_lock_); |
| deep_link = unconsumed_deep_link_; |
| } |
| |
| if (!deep_link.empty()) { |
| LOG(INFO) << "Dispatching deep link: " << deep_link; |
| DispatchEventInternal(new base::DeepLinkEvent( |
| deep_link, base::Bind(&Application::OnDeepLinkConsumedCallback, |
| base::Unretained(this), deep_link))); |
| } |
| } |
| |
| } // namespace browser |
| } // namespace cobalt |
| |
| const char* GetCobaltUserAgentString() { |
| static std::string ua = cobalt::browser::CreateUserAgentString( |
| cobalt::browser::GetUserAgentPlatformInfoFromSystem()); |
| return ua.c_str(); |
| } |