Import Cobalt 23.master.0.309337
diff --git a/cobalt/bindings/templates/dictionary.h.template b/cobalt/bindings/templates/dictionary.h.template index b31fb2c..d178bd6 100644 --- a/cobalt/bindings/templates/dictionary.h.template +++ b/cobalt/bindings/templates/dictionary.h.template
@@ -60,7 +60,7 @@ {% if used_class.conditional %} #if defined({{used_class.conditional}}) {% endif %} -using {{used_class.fully_qualified_name}}; +using ::{{used_class.fully_qualified_name}}; {% if used_class.conditional %} #endif // defined({{used_class.conditional}}) {% endif %}
diff --git a/cobalt/black_box_tests/black_box_tests.py b/cobalt/black_box_tests/black_box_tests.py index 7ac37d0..34b2ffe 100644 --- a/cobalt/black_box_tests/black_box_tests.py +++ b/cobalt/black_box_tests/black_box_tests.py
@@ -63,8 +63,6 @@ 'allow_eval', 'compression_test', 'disable_eval_with_csp', - # http_cache is disabled due to flakiness. Planned update to make use of - # transferSize rather than load timings to make it more consistent. 'http_cache', 'persistent_cookie', 'soft_mic_platform_service_test', @@ -72,6 +70,8 @@ 'web_debugger', 'web_platform_tests', 'web_worker_test', + 'worker_csp_test', + 'service_worker_message_test', 'service_worker_test', ] # These tests can only be run on platforms whose app launcher can send deep
diff --git a/cobalt/black_box_tests/testdata/http_cache.html b/cobalt/black_box_tests/testdata/http_cache.html index cad147f..e1f2e48 100644 --- a/cobalt/black_box_tests/testdata/http_cache.html +++ b/cobalt/black_box_tests/testdata/http_cache.html
@@ -1,10 +1,34 @@ <!DOCTYPE html> +<!-- + To add a new check to this test: + 1. Create the test file to be loaded and place it in + /testdata/http_cache_test_resources/. The server delays responses when + serving files from that directory, to make a clear distinction of what's + being loaded from the cache. + 2. Add the file name to either CACHED_ELEMENT_LOCATIONS if you expect that + file's mime type to be cached or UNCACHED_ELEMENT_LOCATIONS if you + expect the file to be excluded from the cache. + 3. Add a call to the window.onload function to fetch your file, making a + call to measureLoadTime after the file has been loaded. +--> <head> <title>Cobalt HTTP Cache Test</title> <script src="black_box_js_test_utils.js"></script> <script> - var NUMBER_OF_CACHE_ELEMENTS = Number.MAX_SAFE_INTEGER; + var TESTDATA_LOCATION = window.location.protocol + '//' + + window.location.host + + '/testdata/http_cache_test_resources/'; + var CACHED_ELEMENT_LOCATIONS = { + 'js': TESTDATA_LOCATION + 'http_cache.js', + 'img': TESTDATA_LOCATION + 'cobalt_logo.png', + 'css': TESTDATA_LOCATION + 'http_cache.css', + }; + var UNCACHED_ELEMENT_LOCATIONS = { + 'txt': TESTDATA_LOCATION + 'http_cache.txt', + }; + var EXPECTED_NUMBER_OF_ELEMENTS = Object.keys(CACHED_ELEMENT_LOCATIONS).length + + Object.keys(UNCACHED_ELEMENT_LOCATIONS).length; var loadTimes = new Map(); var cacheSize = 0; @@ -20,50 +44,90 @@ var initialLoadTime = loadTimes.has('initialLoadTime') ? loadTimes.get('initialLoadTime') : new Date().getTime(); var reloadUrl = 'http_cache.html?initialLoadTime=' + initialLoadTime; + // Append the timestamp string to each resource url to force reload the + // files the first time the page is accessed each test run. The load time + // is recorded on the first run and passed to the second run to ensure + // the same url is used both times. + var timestampString = '?t=' + initialLoadTime; + // Validate the tranferSize attribute of each performance entry specified + // in CACHED_ELEMENT_LOCATIONS and UNCACHED_ELEMENT_LOCATIONS. + function checkTransferSizes() { + let elementsChecked = 0; + // https://www.w3.org/TR/resource-timing-2/#dom-performanceresourcetiming-transfersize + // Verify that the transferSize attribute for each resource is less than + // 300. If greater than 300, it wasn't fetched from the cache. + for (let location in CACHED_ELEMENT_LOCATIONS) { + elementsChecked++; + let tranferSize = performance.getEntriesByName(CACHED_ELEMENT_LOCATIONS[location] + timestampString)[0].transferSize; + if (tranferSize > 300) { + console.log('Element at ' + CACHED_ELEMENT_LOCATIONS[location] + + ' was expected to be cached, but was loaded from the server instead.'); + notReached(); + } + } + + for (let location in UNCACHED_ELEMENT_LOCATIONS) { + elementsChecked++; + let tranferSize = performance.getEntriesByName(UNCACHED_ELEMENT_LOCATIONS[location] + timestampString)[0].transferSize; + if (tranferSize <= 300) { + console.log('Element at ' + UNCACHED_ELEMENT_LOCATIONS[location] + + ' was not expected to be cached, but was loaded from the cache.'); + notReached(); + } + } + + if (elementsChecked == (EXPECTED_NUMBER_OF_ELEMENTS)) { + onEndTest(); + } else { + console.log(elementsChecked + ' elements were checked, but ' + + EXPECTED_NUMBER_OF_ELEMENTS + + ' elements were expected. Verify that EXPECTED_NUMBER_OF_ELEMENTS is correctly set.'); + notReached(); + } + } + + // On first page load, measure the load time of the specified element and + // update the reloadUrl to record the load time. Once the expected number of + // elements is reached, reload the page. + // On second load, measure the load time of the specified element and + // compare it to the first load time to validate if the cache was used, + // failing the test if the second load took longer. function measureLoadTime(element, initialTime) { cacheSize++; onLoadTime = new Date().getTime() - initialTime; if (loadTimes.has(element)) { - // TODO: change to using transferSize once its implemented (b/231475964) - // Load times might give false positives, but should rarely give false - // negatives (i.e. this may pass when caching didn't actually occur, - // but will likely never fail when caching does occur). console.log(element + ' first load time: ' + loadTimes.get(element)); console.log(element + ' second load time: ' + onLoadTime); - assertTrue(onLoadTime <= loadTimes.get(element)); - if (cacheSize == NUMBER_OF_CACHE_ELEMENTS) { - onEndTest(); + if (cacheSize == EXPECTED_NUMBER_OF_ELEMENTS) { + setTimeout(() => { checkTransferSizes(); }, 500); } } else { reloadUrl += '&' + element + '=' + onLoadTime; - if (cacheSize == NUMBER_OF_CACHE_ELEMENTS) { + if (cacheSize == EXPECTED_NUMBER_OF_ELEMENTS) { setTimeout(() => { window.location.href = reloadUrl; }, 100); } } } + + // Add elements after window loads. In Cobalt, adding the onload property // directly to an html tag doesn't execute. window.onload = function () { - NUMBER_OF_CACHE_ELEMENTS = document.getElementsByTagName('div').length; - // Append the timestamp string to each resource url to force reload the - // files the first time the page is accessed each test run. The load time - // is recorded on the first run and passed to the second run to ensure - // the same url is used both times. - let timestampString = '?t=' + initialLoadTime; - + // text/javascript let initialJsTime = new Date().getTime(); let script = document.createElement('script'); - script.onload = () => { + script.onload = (event) => { measureLoadTime('javascript', initialJsTime); }; script.onerror = () => { notReached(); }; - script.src = 'http_cache_test_resources/http_cache.js' + timestampString; + script.src = CACHED_ELEMENT_LOCATIONS['js'] + timestampString; document.getElementById('js_div').appendChild(script); + // image/png let initialImgTime = new Date().getTime(); let image = document.createElement('img'); image.onload = () => { @@ -72,10 +136,11 @@ image.onerror = (e) => { notReached(); }; - image.src = 'http_cache_test_resources/cobalt_logo.png' + timestampString; + image.src = CACHED_ELEMENT_LOCATIONS['img'] + timestampString; image.alt = 'falied to load image'; document.getElementById('image_div').appendChild(image); + // text/css let initialCssTime = new Date().getTime(); let css = document.createElement('link'); css.onload = () => { @@ -85,8 +150,19 @@ notReached(); }; css.rel = 'stylesheet'; - css.href = 'http_cache_test_resources/http_cache.css' + timestampString; + css.href = CACHED_ELEMENT_LOCATIONS['css'] + timestampString; document.getElementById('css_div').appendChild(css); + + // text/plain + let initialTxtTime = new Date().getTime(); + let txt = document.createElement('p'); + fetch(UNCACHED_ELEMENT_LOCATIONS['txt'] + timestampString) + .then(response => response.text()) + .then(text => { + txt.innerHTML = text; + document.getElementById('txt_div').appendChild(txt); + measureLoadTime('txt', initialTxtTime); + }); } </script> @@ -103,4 +179,7 @@ <div id="css_div"> <h2>Loading CSS file</h2> </div> + <div id="txt_div"> + <h2>Loading txt file</h2> + </div> </body>
diff --git a/cobalt/black_box_tests/testdata/http_cache_test_resources/http_cache.txt b/cobalt/black_box_tests/testdata/http_cache_test_resources/http_cache.txt new file mode 100644 index 0000000..ad4f0dc --- /dev/null +++ b/cobalt/black_box_tests/testdata/http_cache_test_resources/http_cache.txt
@@ -0,0 +1 @@ +Cobalt does not cache text/plain files. This is NOT expected to be cached.
diff --git a/cobalt/black_box_tests/testdata/service_worker_message_test.html b/cobalt/black_box_tests/testdata/service_worker_message_test.html new file mode 100644 index 0000000..ac8f3f4 --- /dev/null +++ b/cobalt/black_box_tests/testdata/service_worker_message_test.html
@@ -0,0 +1,129 @@ +<!DOCTYPE html> +<!-- + Copyright 2022 The Cobalt Authors. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- + This is a basic test of the message event for service workers. +--> + +<html> + +<head> + <title>Cobalt Service Worker Message Test</title> + <script src='black_box_js_test_utils.js'></script> +</head> + +<body> + <script> + var expected_event_count = 0; + + function count_event(expected_value) { + expected_event_count += 1; + console.log('Expected events counted:', expected_event_count) + if (expected_value) { + assertEqual(expected_value, expected_event_count) + } + return expected_event_count; + } + + navigator.serviceWorker.onmessage = function (event) { + console.log('Got onmessage event ', JSON.stringify(event.data));; + assertTrue(event instanceof MessageEvent); + assertEqual('[object MessageEvent]', `${event}`); + assertEqual('[object ServiceWorkerContainer]', `${event.target}`); + assertEqual('[object Object]', `${event.data}`); + switch (count_event()) { + case 3: + assertEqual('Foo', event.data.text); + assertEqual('BarString', event.data.bar); + break; + case 4: + assertEqual('Service Worker received a message', + event.data.text); + assertEqual('{"message":"Registration ready resolved."}', + JSON.stringify(event.data.data)); + assertEqual('[object ExtendableMessageEvent]', + event.data.event_type); + break; + case 5: + assertEqual('Foo', event.data.text); + assertEqual('BarString', event.data.bar); + break; + case 6: + assertEqual('Service Worker received a message', + event.data.text); + assertEqual('"Controllerchange event received."', + JSON.stringify(event.data.data)); + assertEqual('[object ExtendableMessageEvent]', + event.data.event_type); + break; + default: + notReached(); + break; + } + + } + + navigator.serviceWorker.oncontrollerchange = function (event) { + console.log('Got oncontrollerchange event', event.target); + count_event(2); + navigator.serviceWorker.controller.postMessage( + 'Controllerchange event received.'); + } + + navigator.serviceWorker.ready.then(function ( + registration) { + assertNotEqual(null, registration); + assertNotEqual(null, registration.active); + registration.active.postMessage({ message: + 'Registration ready resolved.'}); + count_event(1); + window.setTimeout( + () => { + registration.unregister() + .then(function (success) { + console.log('(Expected) unregister success :', + success); + count_event(7); + }, function (error) { + console.log('(Unexpected) unregister ' + + `${error}`, error); + assertIncludes('SecurityError: ', `${error}`); + notReached(); + }); + }, 1000); + }); + + navigator.serviceWorker.register('service_worker_message_test.js', { + scope: './', + }).catch(function (error) { + console.log('(Unexpected) :', error); + notReached(); + }); + + setupFinished(); + // This delay has to be long enough to guarantee that the test has + // finished. + window.setTimeout( + () => { + console.log('Events:', expected_event_count) + assertEqual(7, expected_event_count); + onEndTest(); + }, 2000); + + </script> +</body> + +</html>
diff --git a/cobalt/black_box_tests/testdata/service_worker_message_test.js b/cobalt/black_box_tests/testdata/service_worker_message_test.js new file mode 100644 index 0000000..20a3334 --- /dev/null +++ b/cobalt/black_box_tests/testdata/service_worker_message_test.js
@@ -0,0 +1,49 @@ +// Copyright 2022 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +console.log('Service Worker Script Started'); +self.onmessage = function (event) { + console.log('Got onmessage event', event, JSON.stringify(event.data), event.source, event.target); + if (event instanceof ExtendableMessageEvent) { + var options = { + includeUncontrolled: false, type: 'window' + }; + event.waitUntil(self.clients.matchAll(options).then(function (clients) { + for (var i = 0; i < clients.length; i++) { + message = { text: 'Foo', bar: 'BarString' }; + console.log('Posting to client:', JSON.stringify(message)); + clients[i].postMessage(message); + } + })); + event.waitUntil(self.clients.matchAll(options).then(function (clients) { + for (var i = 0; i < clients.length; i++) { + message = { + text: 'Service Worker received a message', + data: event.data, + event_type: `${event}` + } + console.log('Posting to client:', JSON.stringify(message)); + clients[i].postMessage(message); + } + })); + } +} + +self.onactivate = function (e) { + e.waitUntil(self.clients.claim().then(function (result) { + console.log('(Expected) self.clients.claim():', result); + }, function (error) { + console.log(`(Unexpected) self.clients.claim(): ${error}`, error); + })); +}
diff --git a/cobalt/black_box_tests/testdata/web_worker_test.html b/cobalt/black_box_tests/testdata/web_worker_test.html index 2976cdf..9be8f5b 100644 --- a/cobalt/black_box_tests/testdata/web_worker_test.html +++ b/cobalt/black_box_tests/testdata/web_worker_test.html
@@ -37,9 +37,10 @@ console.log('running'); // This is expected trigger a an error event on window. - var worker_with_error = new Worker('web_worker_test_with_syntax_error.js'); + var worker_with_error = new Worker('web_worker_test_with_syntax_error.js', + { name : 'worker_with_error'}); - var worker = new Worker('web_worker_test.js'); + var worker = new Worker('web_worker_test.js', { name : 'test_worker'}); console.log(worker); worker.onmessage = function (event) { message_event_count += 1;
diff --git a/cobalt/black_box_tests/testdata/worker_csp_test.html b/cobalt/black_box_tests/testdata/worker_csp_test.html new file mode 100644 index 0000000..fdb1cea --- /dev/null +++ b/cobalt/black_box_tests/testdata/worker_csp_test.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- + Copyright 2022 The Cobalt Authors. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<head> + <title>Verify that XHR on workers correctly follows CSP</title> + <script src='black_box_js_test_utils.js'></script> +</head> + +<body style="background-color: white;"> + <h1> + <span>ID element</span> + </h1> + <script> + var worker = new Worker('worker_csp_test.js'); + worker.onmessage = function (event) { + notReached(); + }; + + window.setTimeout( + () => { + worker.terminate(); + onEndTest(); + }, 250); + </script> +</body>
diff --git a/cobalt/black_box_tests/testdata/worker_csp_test.js b/cobalt/black_box_tests/testdata/worker_csp_test.js new file mode 100644 index 0000000..58874aa --- /dev/null +++ b/cobalt/black_box_tests/testdata/worker_csp_test.js
@@ -0,0 +1,6 @@ +const xhr = new XMLHttpRequest(); +// Script should fail and stop execution at this step due to SecurityViolation. +xhr.open("GET", "http://www.google.com"); +xhr.send(); + +self.postMessage("Should not be reached!");
diff --git a/cobalt/black_box_tests/tests/http_cache.py b/cobalt/black_box_tests/tests/http_cache.py index 3b24fc5..63719ff 100644 --- a/cobalt/black_box_tests/tests/http_cache.py +++ b/cobalt/black_box_tests/tests/http_cache.py
@@ -35,7 +35,7 @@ parsed_path = urlparse(self.path) if parsed_path.path.startswith('/testdata/http_cache_test_resources/'): - time.sleep(10) + time.sleep(3) return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
diff --git a/cobalt/black_box_tests/tests/service_worker_message_test.py b/cobalt/black_box_tests/tests/service_worker_message_test.py new file mode 100644 index 0000000..9e92654 --- /dev/null +++ b/cobalt/black_box_tests/tests/service_worker_message_test.py
@@ -0,0 +1,30 @@ +# Copyright 2022 The Cobalt Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests Service Worker Messaging functionality.""" + +from cobalt.black_box_tests import black_box_tests +from cobalt.black_box_tests.threaded_web_server import ThreadedWebServer + + +class ServiceWorkerMessageTest(black_box_tests.BlackBoxTestCase): + """Test basic Service Worker functionality.""" + + def test_simple(self): + + with ThreadedWebServer(binding_address=self.GetBindingAddress()) as server: + url = server.GetURL(file_name='testdata/service_worker_message_test.html') + + with self.CreateCobaltRunner(url=url) as runner: + runner.WaitForJSTestsSetup() + self.assertTrue(runner.JSTestsSucceeded())
diff --git a/cobalt/black_box_tests/tests/worker_csp_test.py b/cobalt/black_box_tests/tests/worker_csp_test.py new file mode 100644 index 0000000..1af8735 --- /dev/null +++ b/cobalt/black_box_tests/tests/worker_csp_test.py
@@ -0,0 +1,44 @@ +# Copyright 2022 The Cobalt Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Tests workers handling CSP Violations.""" + +import os + +from cobalt.black_box_tests import black_box_tests +from cobalt.black_box_tests.threaded_web_server import ThreadedWebServer, MakeCustomHeaderRequestHandlerClass + +paths_to_headers = { + 'worker_csp_test.html': { + 'Content-Security-Policy': + "script-src 'unsafe-inline' 'self'; connect-src 'self';" + }, + 'worker_csp_test.js': { + 'Content-Security-Policy': "connect-src 'self';" + } +} + + +class WorkerCspTest(black_box_tests.BlackBoxTestCase): + """Verify correct correct CSP behavior.""" + + def test_simple(self): + path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + with ThreadedWebServer( + binding_address=self.GetBindingAddress(), + handler=MakeCustomHeaderRequestHandlerClass( + path, paths_to_headers)) as server: + url = server.GetURL(file_name='testdata/worker_csp_test.html') + + with self.CreateCobaltRunner(url=url) as runner: + self.assertTrue(runner.JSTestsSucceeded())
diff --git a/cobalt/black_box_tests/threaded_web_server.py b/cobalt/black_box_tests/threaded_web_server.py index 1064355..1e173e3 100644 --- a/cobalt/black_box_tests/threaded_web_server.py +++ b/cobalt/black_box_tests/threaded_web_server.py
@@ -60,6 +60,87 @@ return TestDataHTTPRequestHandler +def MakeCustomHeaderRequestHandlerClass(base_path, paths_to_headers): + """RequestHandler that serves files that reside relative to base_path. + + Args: + base_path: A path considered to be the root directory. + paths_to_headers: A dictionary with keys partial paths and values of header + dicts. Key is expected to be a substring of a file being served. + + E.g. if you have a test with files foo.html and foo.js, you can serve them + separate headers with the following: + paths_to_headers = { + 'foo.html': { + 'Content-Security-Policy', "script-src 'unsafe-inline';" + }, + 'foo.js': {'Content-Security-Policy', "default-src 'self';"} + } + + Returns: + A RequestHandler class. + """ + + class TestDataHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + """Handles HTTP requests and serves responses with specified headers. + + For testing purposes only. + """ + + _current_working_directory = os.getcwd() + _base_path = base_path + _paths_to_headers = paths_to_headers + + def do_GET(self): # pylint: disable=invalid-name + content = self.get_content() + self.wfile.write(content) + + def do_HEAD(self): # pylint: disable=invalid-name + # Run get_content to send the headers, but ignore the returned results + self.get_content() + + def translate_path(self, path): + """Translate the request path to the file in the testdata directory.""" + + potential_path = SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path( + self, path) + potential_path = potential_path.replace(self._current_working_directory, + self._base_path) + return potential_path + + def get_content(self): + """Returns the contents of the file at path with added headers.""" + path = self.translate_path(self.path) + modified_date_time = None + raw_content = None + try: + with open(path, 'rb') as f: + filestream = os.fstat(f.fileno()) + modified_date_time = self.date_time_string(filestream.st_mtime) + raw_content = f.read() + except IOError: + self.send_error(404, 'File not found') + return None + + content_type = self.guess_type(path) + self.send_response(200) + self.send_header('Content-type', content_type) + for partial_path, headers in self._paths_to_headers.items(): + if partial_path in path: + for header_key, header_value in headers.items(): + self.send_header(header_key, header_value) + + content_length = len(raw_content) + + self.send_header('Content-Length', content_length) + self.send_header('Last-Modified', modified_date_time) + self.end_headers() + + return raw_content + + return TestDataHTTPRequestHandler + + class ThreadedWebServer(object): """A HTTP WebServer that serves requests in a separate thread."""
diff --git a/cobalt/browser/application.cc b/cobalt/browser/application.cc index b6a691f..855b484 100644 --- a/cobalt/browser/application.cc +++ b/cobalt/browser/application.cc
@@ -100,6 +100,15 @@ const char kPersistentSettingsJson[] = "settings.json"; +// The watchdog client name used to represent Stats. +const char kWatchdogName[] = "stats"; +// The watchdog time interval in microseconds allowed between pings before +// triggering violations. +const int64_t kWatchdogTimeInterval = 10000000; +// The watchdog time wait in microseconds to initially wait before triggering +// violations. +const int64_t kWatchdogTimeWait = 2000000; + bool IsStringNone(const std::string& str) { return !base::strcasecmp(str.c_str(), "none"); } @@ -512,12 +521,13 @@ "available trackers."; #endif // defined(ENABLE_DEBUGGER) && defined(STARBOARD_ALLOWS_MEMORY_TRACKING) -bool AddCrashHandlerAnnotations() { +void AddCrashHandlerAnnotations() { auto crash_handler_extension = - SbSystemGetExtension(kCobaltExtensionCrashHandlerName); + static_cast<const CobaltExtensionCrashHandlerApi*>( + SbSystemGetExtension(kCobaltExtensionCrashHandlerName)); if (!crash_handler_extension) { LOG(INFO) << "No crash handler extension, not sending annotations."; - return false; + return; } auto platform_info = cobalt::browser::GetUserAgentPlatformInfoFromSystem(); @@ -541,23 +551,41 @@ product.push_back('\0'); version.push_back('\0'); - CrashpadAnnotations crashpad_annotations; - memset(&crashpad_annotations, 0, sizeof(CrashpadAnnotations)); - strncpy(crashpad_annotations.user_agent_string, user_agent.c_str(), - USER_AGENT_STRING_MAX_SIZE); - strncpy(crashpad_annotations.product, product.c_str(), - CRASHPAD_ANNOTATION_DEFAULT_LENGTH); - strncpy(crashpad_annotations.version, version.c_str(), - CRASHPAD_ANNOTATION_DEFAULT_LENGTH); - bool result = static_cast<const CobaltExtensionCrashHandlerApi*>( - crash_handler_extension) - ->OverrideCrashpadAnnotations(&crashpad_annotations); + bool result = true; + if (crash_handler_extension->version == 1) { + CrashpadAnnotations crashpad_annotations; + memset(&crashpad_annotations, 0, sizeof(CrashpadAnnotations)); + strncpy(crashpad_annotations.user_agent_string, user_agent.c_str(), + USER_AGENT_STRING_MAX_SIZE); + strncpy(crashpad_annotations.product, product.c_str(), + CRASHPAD_ANNOTATION_DEFAULT_LENGTH); + strncpy(crashpad_annotations.version, version.c_str(), + CRASHPAD_ANNOTATION_DEFAULT_LENGTH); + result = crash_handler_extension->OverrideCrashpadAnnotations( + &crashpad_annotations); + } else if (crash_handler_extension->version > 1) { + // These particular annotation key names (e.g., ver) are expected by + // Crashpad. + // TODO(b/201538792): figure out a clean way to define these constants once + // and use them everywhere. + if (!crash_handler_extension->SetString("user_agent_string", + user_agent.c_str())) { + result = false; + } + if (!crash_handler_extension->SetString("prod", product.c_str())) { + result = false; + } + if (!crash_handler_extension->SetString("ver", version.c_str())) { + result = false; + } + } else { + result = false; + } // Invalid extension version if (result) { LOG(INFO) << "Sent annotations to crash handler"; } else { - LOG(ERROR) << "Could not send annotations to crash handler."; + LOG(ERROR) << "Could not send some annotation(s) to crash handler."; } - return result; } } // namespace @@ -650,6 +678,12 @@ watchdog::Watchdog::CreateInstance(persistent_settings_.get()); DCHECK(watchdog); + // Registers Stats as a watchdog client. + if (watchdog) + watchdog->Register(kWatchdogName, kWatchdogName, + base::kApplicationStateStarted, kWatchdogTimeInterval, + kWatchdogTimeWait, watchdog::NONE); + cobalt::cache::Cache::GetInstance()->set_persistent_settings( persistent_settings_.get()); @@ -660,11 +694,10 @@ unconsumed_deep_link_ = GetInitialDeepLink(); DLOG(INFO) << "Initial deep link: " << unconsumed_deep_link_; - WebModule::Options web_options("MainWebModule"); storage::StorageManager::Options storage_manager_options; network::NetworkModule::Options network_module_options; // Create the main components of our browser. - BrowserModule::Options options(web_options); + BrowserModule::Options options; network_module_options.preferred_language = language; network_module_options.persistent_settings = persistent_settings_.get(); options.persistent_settings = persistent_settings_.get(); @@ -749,7 +782,7 @@ // 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)); + base::Bind(&Application::MainWebModuleCreated, base::Unretained(this)); // The main web module's stat tracker tracks event stats. options.web_module_options.track_event_stats = true; @@ -1370,8 +1403,9 @@ } #endif -void Application::WebModuleCreated(WebModule* web_module) { - TRACE_EVENT0("cobalt::browser", "Application::WebModuleCreated()"); +void Application::MainWebModuleCreated(WebModule* web_module) { + TRACE_EVENT0("cobalt::browser", "Application::MainWebModuleCreated()"); + // Note: This is a callback function that runs in the MainWebModule thread. DCHECK(web_module); if (preload_timestamp_.has_value()) { web_module->SetApplicationStartOrPreloadTimestamp( @@ -1431,6 +1465,16 @@ TRACE_EVENT0("cobalt::browser", "Application::UpdatePeriodicStats()"); c_val_stats_.app_lifetime = base::StartupTimer::TimeElapsed(); + // Pings watchdog. + watchdog::Watchdog* watchdog = watchdog::Watchdog::GetInstance(); + if (watchdog) { +#if defined(_DEBUG) + // Injects delay for watchdog debugging. + watchdog->MaybeInjectDebugDelay(kWatchdogName); +#endif // defined(_DEBUG) + watchdog->Ping(kWatchdogName); + } + int64_t used_cpu_memory = SbSystemGetUsedCPUMemory(); base::Optional<int64_t> used_gpu_memory; if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) { @@ -1499,10 +1543,9 @@ // again after the next WebModule is created. unconsumed_deep_link_ = link; deep_link = unconsumed_deep_link_; + deep_link_timestamp_ = timestamp; } - deep_link_timestamp_ = timestamp; - LOG(INFO) << "Dispatching deep link: " << deep_link; DispatchEventInternal(new base::DeepLinkEvent( deep_link, base::Bind(&Application::OnDeepLinkConsumedCallback, @@ -1516,11 +1559,17 @@ void Application::DispatchDeepLinkIfNotConsumed() { std::string deep_link; +#if SB_API_VERSION >= 13 + SbTimeMonotonic timestamp; +#endif // SB_API_VERSION >= 13 // 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 SB_API_VERSION >= 13 + timestamp = deep_link_timestamp_; +#endif // SB_API_VERSION >= 13 } if (!deep_link.empty()) { @@ -1531,7 +1580,7 @@ } #if SB_API_VERSION >= 13 if (browser_module_) { - browser_module_->SetDeepLinkTimestamp(deep_link_timestamp_); + browser_module_->SetDeepLinkTimestamp(timestamp); } #endif // SB_API_VERSION >= 13 }
diff --git a/cobalt/browser/application.h b/cobalt/browser/application.h index d2ad7ca..96480b7 100644 --- a/cobalt/browser/application.h +++ b/cobalt/browser/application.h
@@ -90,7 +90,7 @@ #endif // Called when a navigation occurs in the BrowserModule. - void WebModuleCreated(WebModule* web_module); + void MainWebModuleCreated(WebModule* web_module); void CollectUnloadEventTimingInfo(base::TimeTicks start_time, base::TimeTicks end_time);
diff --git a/cobalt/browser/browser_module.cc b/cobalt/browser/browser_module.cc index b80da96..780f86d 100644 --- a/cobalt/browser/browser_module.cc +++ b/cobalt/browser/browser_module.cc
@@ -341,11 +341,12 @@ // Setup our main web module to have the H5VCC API injected into it. DCHECK(!ContainsKey( + options_.web_module_options.injected_global_object_attributes, "h5vcc")); + DCHECK(!ContainsKey( options_.web_module_options.web_options.injected_global_object_attributes, "h5vcc")); - options_.web_module_options.web_options - .injected_global_object_attributes["h5vcc"] = - base::Bind(&BrowserModule::CreateH5vcc, base::Unretained(this)); + options_.web_module_options.injected_global_object_attributes["h5vcc"] = + base::Bind(&BrowserModule::CreateH5vccCallback, base::Unretained(this)); if (command_line->HasSwitch(switches::kDisableTimerResolutionLimit)) { options_.web_module_options.limit_performance_timer_resolution = false; @@ -515,7 +516,7 @@ if (web_module_) { lifecycle_observers_.RemoveObserver(web_module_.get()); } - web_module_.reset(NULL); + web_module_.reset(); // Increment the navigation generation so that we can attach it to event // callbacks as a way of identifying the new web module from the old ones. @@ -608,7 +609,8 @@ options.web_options.service_worker_jobs = service_worker_registry_.service_worker_jobs(); options.web_options.platform_info = platform_info_.get(); - web_module_.reset(new WebModule( + web_module_.reset(new WebModule("MainWebModule")); + web_module_->Run( url, application_state_, base::Bind(&BrowserModule::QueueOnRenderTreeProduced, base::Unretained(this), main_web_module_generation_), @@ -616,7 +618,7 @@ base::Bind(&BrowserModule::OnWindowClose, base::Unretained(this)), base::Bind(&BrowserModule::OnWindowMinimize, base::Unretained(this)), can_play_type_handler_.get(), media_module_.get(), viewport_size, - GetResourceProvider(), kLayoutMaxRefreshFrequencyInHz, options)); + GetResourceProvider(), kLayoutMaxRefreshFrequencyInHz, options); lifecycle_observers_.AddObserver(web_module_.get()); if (system_window_) { @@ -686,6 +688,7 @@ const base::Optional<math::Rect>& clip_rect, const base::Closure& done_callback) { TRACE_EVENT0("cobalt::browser", "BrowserModule::RequestScreenshotToFile()"); + DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); DCHECK(screen_shot_writer_); scoped_refptr<render_tree::Node> render_tree; @@ -704,6 +707,7 @@ const base::Optional<math::Rect>& clip_rect, const ScreenShotWriter::ImageEncodeCompleteCallback& screenshot_ready) { TRACE_EVENT0("cobalt::browser", "BrowserModule::RequestScreenshotToMemory()"); + DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); DCHECK(screen_shot_writer_); scoped_refptr<render_tree::Node> render_tree; @@ -898,6 +902,7 @@ } void BrowserModule::OnWindowSizeChanged(const ViewportSize& viewport_size) { + DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); if (web_module_) { web_module_->SetSize(viewport_size); } @@ -964,6 +969,7 @@ void BrowserModule::OnCaptionSettingsChanged( const base::AccessibilityCaptionSettingsChangedEvent* event) { + DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); if (web_module_) { web_module_->InjectCaptionSettingsChangedEvent(); } @@ -972,6 +978,7 @@ #if SB_API_VERSION >= 13 void BrowserModule::OnDateTimeConfigurationChanged( const base::DateTimeConfigurationChangedEvent* event) { + DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); icu::TimeZone::adoptDefault(icu::TimeZone::detectHostTimeZone()); if (web_module_) { web_module_->UpdateDateTimeConfiguration(); @@ -1122,12 +1129,14 @@ } void BrowserModule::OnWindowOnOnlineEvent(const base::Event* event) { + DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); if (web_module_) { web_module_->InjectWindowOnOnlineEvent(event); } } void BrowserModule::OnWindowOnOfflineEvent(const base::Event* event) { + DCHECK_EQ(base::MessageLoop::current(), self_message_loop_); if (web_module_) { web_module_->InjectWindowOnOfflineEvent(event); } @@ -2021,13 +2030,15 @@ } } -scoped_refptr<script::Wrappable> BrowserModule::CreateH5vcc( - script::EnvironmentSettings* settings) { - DCHECK(web_module_); +scoped_refptr<script::Wrappable> BrowserModule::CreateH5vccCallback( + WebModule* web_module, web::EnvironmentSettings* settings) { + DCHECK_NE(base::MessageLoop::current(), self_message_loop_); + // Note: This is a callback function that runs in the MainWebModule thread. + // The web_module_ member can not be safely used in this function. h5vcc::H5vcc::Settings h5vcc_settings; h5vcc_settings.set_media_source_setting_func = base::Bind( - &WebModule::SetMediaSourceSetting, base::Unretained(web_module_.get())); + &WebModule::SetMediaSourceSetting, base::Unretained(web_module)); h5vcc_settings.network_module = network_module_; #if SB_IS(EVERGREEN) h5vcc_settings.updater_module = updater_module_; @@ -2035,22 +2046,27 @@ h5vcc_settings.account_manager = account_manager_; h5vcc_settings.event_dispatcher = event_dispatcher_; - auto* dom_settings = base::polymorphic_downcast<dom::DOMSettings*>(settings); - - h5vcc_settings.user_agent_data = - dom_settings->window()->navigator()->user_agent_data(); - h5vcc_settings.global_environment = - dom_settings->context()->global_environment(); + h5vcc_settings.user_agent_data = settings->context() + ->GetWindowOrWorkerGlobalScope() + ->navigator_base() + ->user_agent_data(); + h5vcc_settings.global_environment = settings->context()->global_environment(); h5vcc_settings.persistent_settings = options_.persistent_settings; auto* h5vcc_object = new h5vcc::H5vcc(h5vcc_settings); if (!web_module_created_callback_.is_null()) { - web_module_created_callback_.Run(web_module_.get()); + web_module_created_callback_.Run(web_module); } return scoped_refptr<script::Wrappable>(h5vcc_object); } void BrowserModule::SetDeepLinkTimestamp(SbTimeMonotonic timestamp) { + if (base::MessageLoop::current() != self_message_loop_) { + self_message_loop_->task_runner()->PostTask( + FROM_HERE, base::Bind(&BrowserModule::SetDeepLinkTimestamp, + base::Unretained(this), timestamp)); + return; + } DCHECK(web_module_); web_module_->SetDeepLinkTimestamp(timestamp); }
diff --git a/cobalt/browser/browser_module.h b/cobalt/browser/browser_module.h index 6730fa2..646b750 100644 --- a/cobalt/browser/browser_module.h +++ b/cobalt/browser/browser_module.h
@@ -99,9 +99,8 @@ // All browser subcomponent options should have default constructors that // setup reasonable default options. struct Options { - explicit Options(const WebModule::Options& web_options) - : web_module_options(web_options), - command_line_auto_mem_settings( + Options() + : command_line_auto_mem_settings( memory_settings::AutoMemSettings::kTypeCommandLine), build_auto_mem_settings(memory_settings::AutoMemSettings::kTypeBuild), enable_splash_screen_on_reloads(true) {} @@ -465,9 +464,10 @@ // Returns the topic used, or an empty Optional if a topic isn't found. base::Optional<std::string> SetSplashScreenTopicFallback(const GURL& url); - // Function that creates the H5vcc object that will be injected into WebModule - scoped_refptr<script::Wrappable> CreateH5vcc( - script::EnvironmentSettings* settings); + // Callback function that creates the H5vcc object that will be injected into + // the MainWebModule. + scoped_refptr<script::Wrappable> CreateH5vccCallback( + WebModule* web_module, web::EnvironmentSettings* settings); // Validates the PersistentSettings for cache backend, if in use. void ValidateCacheBackendSettings();
diff --git a/cobalt/browser/debug_console.cc b/cobalt/browser/debug_console.cc index 72069e3..1f0bba5 100644 --- a/cobalt/browser/debug_console.cc +++ b/cobalt/browser/debug_console.cc
@@ -97,7 +97,7 @@ scoped_refptr<script::Wrappable> CreateDebugHub( const debug::console::DebugHub::GetHudModeCallback& get_hud_mode_function, const debug::CreateDebugClientCallback& create_debug_client_callback, - script::EnvironmentSettings* settings) { + web::EnvironmentSettings* settings) { return new debug::console::DebugHub(get_hud_mode_function, create_debug_client_callback); } @@ -116,7 +116,7 @@ const base::Closure& maybe_freeze_callback) { mode_ = GetInitialMode(); - WebModule::Options web_module_options("DebugConsoleWebModule"); + WebModule::Options web_module_options; // The debug console does not load any image assets. web_module_options.image_cache_capacity = 0; // Disable CSP for the Debugger's WebModule. This will also allow eval() in @@ -143,15 +143,15 @@ web_module_options.web_options.network_module = network_module; web_module_options.web_options.platform_info = platform_info; - web_module_.reset( - new WebModule(GURL(kInitialDebugConsoleUrl), initial_application_state, - render_tree_produced_callback, - base::Bind(&DebugConsole::OnError, base::Unretained(this)), - WebModule::CloseCallback(), /* window_close_callback */ - base::Closure(), /* window_minimize_callback */ - NULL /* can_play_type_handler */, NULL /* media_module */, - window_dimensions, resource_provider, layout_refresh_rate, - web_module_options)); + web_module_.reset(new WebModule("DebugConsoleWebModule")); + web_module_->Run(GURL(kInitialDebugConsoleUrl), initial_application_state, + render_tree_produced_callback, + base::Bind(&DebugConsole::OnError, base::Unretained(this)), + WebModule::CloseCallback(), /* window_close_callback */ + base::Closure(), /* window_minimize_callback */ + NULL /* can_play_type_handler */, NULL /* media_module */, + window_dimensions, resource_provider, layout_refresh_rate, + web_module_options); } DebugConsole::~DebugConsole() {}
diff --git a/cobalt/browser/on_screen_keyboard_starboard_bridge.cc b/cobalt/browser/on_screen_keyboard_starboard_bridge.cc index 969f822..ccd818e 100644 --- a/cobalt/browser/on_screen_keyboard_starboard_bridge.cc +++ b/cobalt/browser/on_screen_keyboard_starboard_bridge.cc
@@ -97,8 +97,8 @@ keep_focus); } -void OnScreenKeyboardStarboardBridge::SetBackgroundColor( - const char* background_color) { +void OnScreenKeyboardStarboardBridge::SetBackgroundColor(uint8 r, uint8 g, + uint8 b) { const CobaltExtensionOnScreenKeyboardApi* on_screen_keyboard_extension = static_cast<const CobaltExtensionOnScreenKeyboardApi*>( SbSystemGetExtension(kCobaltExtensionOnScreenKeyboardName)); @@ -108,11 +108,11 @@ kCobaltExtensionOnScreenKeyboardName) == 0 && on_screen_keyboard_extension->version >= 1) { on_screen_keyboard_extension->SetBackgroundColor(sb_window_provider_.Run(), - background_color); + r, g, b); } } -void OnScreenKeyboardStarboardBridge::SetDarkTheme(bool dark_theme) { +void OnScreenKeyboardStarboardBridge::SetLightTheme(bool light_theme) { const CobaltExtensionOnScreenKeyboardApi* on_screen_keyboard_extension = static_cast<const CobaltExtensionOnScreenKeyboardApi*>( SbSystemGetExtension(kCobaltExtensionOnScreenKeyboardName)); @@ -121,8 +121,8 @@ strcmp(on_screen_keyboard_extension->name, kCobaltExtensionOnScreenKeyboardName) == 0 && on_screen_keyboard_extension->version >= 1) { - on_screen_keyboard_extension->SetDarkTheme(sb_window_provider_.Run(), - dark_theme); + on_screen_keyboard_extension->SetLightTheme(sb_window_provider_.Run(), + light_theme); } } } // namespace browser
diff --git a/cobalt/browser/on_screen_keyboard_starboard_bridge.h b/cobalt/browser/on_screen_keyboard_starboard_bridge.h index 6ee9a70..682f2f4 100644 --- a/cobalt/browser/on_screen_keyboard_starboard_bridge.h +++ b/cobalt/browser/on_screen_keyboard_starboard_bridge.h
@@ -59,9 +59,9 @@ void SetKeepFocus(bool keep_focus) override; - void SetBackgroundColor(const char* background_color) override; + void SetBackgroundColor(uint8 r, uint8 g, uint8 b) override; - void SetDarkTheme(bool dark_theme) override; + void SetLightTheme(bool light_theme) override; private: base::Callback<SbWindow()> sb_window_provider_;
diff --git a/cobalt/browser/splash_screen.cc b/cobalt/browser/splash_screen.cc index 2739ec0..952f790 100644 --- a/cobalt/browser/splash_screen.cc +++ b/cobalt/browser/splash_screen.cc
@@ -67,7 +67,7 @@ self_message_loop_(base::MessageLoop::current()), on_splash_screen_shutdown_complete_(on_splash_screen_shutdown_complete), shutdown_signaled_(false) { - WebModule::Options web_module_options("SplashScreenWebModule"); + WebModule::Options web_module_options; // We want the splash screen to load and appear as quickly as possible, so // we set it and its image decoding thread to be high priority. @@ -106,13 +106,14 @@ web_module_options.web_options.platform_info = platform_info; DCHECK(url_to_pass); - web_module_.reset(new WebModule( - *url_to_pass, initial_application_state, render_tree_produced_callback_, - base::Bind(&OnError), on_window_close, - base::Closure(), // window_minimize_callback - NULL /* can_play_type_handler */, NULL /* media_module */, - window_dimensions, resource_provider, layout_refresh_rate, - web_module_options)); + web_module_.reset(new WebModule("SplashScreenWebModule")); + web_module_->Run(*url_to_pass, initial_application_state, + render_tree_produced_callback_, base::Bind(&OnError), + on_window_close, + base::Closure(), // window_minimize_callback + NULL /* can_play_type_handler */, NULL /* media_module */, + window_dimensions, resource_provider, layout_refresh_rate, + web_module_options); } SplashScreen::~SplashScreen() {
diff --git a/cobalt/browser/web_module.cc b/cobalt/browser/web_module.cc index ecc0f56..a7cfd00 100644 --- a/cobalt/browser/web_module.cc +++ b/cobalt/browser/web_module.cc
@@ -1320,15 +1320,32 @@ } while (event && !layout_manager_->IsRenderTreePending()); } -WebModule::Options::Options(const std::string& name) - : web_options(name), - layout_trigger(layout::LayoutManager::kOnDocumentMutation), +WebModule::Options::Options() + : layout_trigger(layout::LayoutManager::kOnDocumentMutation), mesh_cache_capacity(configuration::Configuration::GetInstance() ->CobaltMeshCacheSizeInBytes()) { web_options.stack_size = cobalt::browser::kWebModuleStackSize; } -WebModule::WebModule( +WebModule::WebModule(const std::string& name) + : ui_nav_root_(new ui_navigation::NavItem( + ui_navigation::kNativeItemTypeContainer, + // Currently, events do not need to be processed for the root item. + base::Closure(), base::Closure(), base::Closure())) { + web_agent_.reset(new web::Agent(name)); +} + +WebModule::~WebModule() { + DCHECK(message_loop()); + DCHECK(web_agent_); + // This will cancel the timers for tasks, which help the thread exit + ClearAllIntervalsAndTimeouts(); + web_agent_->WaitUntilDone(); + web_agent_->Stop(); + web_agent_.reset(); +} + +void WebModule::Run( const GURL& initial_url, base::ApplicationState initial_application_state, const OnRenderTreeProducedCallback& render_tree_produced_callback, OnErrorCallback error_callback, const CloseCallback& window_close_callback, @@ -1336,11 +1353,7 @@ media::CanPlayTypeHandler* can_play_type_handler, media::MediaModule* media_module, const ViewportSize& window_dimensions, render_tree::ResourceProvider* resource_provider, float layout_refresh_rate, - const Options& options) - : ui_nav_root_(new ui_navigation::NavItem( - ui_navigation::kNativeItemTypeContainer, - // Currently, events do not need to be processed for the root item. - base::Closure(), base::Closure(), base::Closure())) { + const Options& options) { ConstructionData construction_data( initial_url, initial_application_state, render_tree_produced_callback, error_callback, window_close_callback, window_minimize_callback, @@ -1351,24 +1364,27 @@ #endif // defined(ENABLE_DEBUGGER) &synchronous_loader_interrupt_, options); - web_agent_.reset( - new web::Agent(options.web_options, - base::Bind(&WebModule::Initialize, base::Unretained(this), - construction_data), - this)); + web::Agent::Options web_options(options.web_options); + if (!options.injected_global_object_attributes.empty()) { + for (Options::InjectedGlobalObjectAttributes::const_iterator iter = + options.injected_global_object_attributes.begin(); + iter != options.injected_global_object_attributes.end(); ++iter) { + DCHECK(!ContainsKey(web_options.injected_global_object_attributes, + iter->first)); + // Trampoline to the given callback, adding a pointer to this WebModule. + web_options.injected_global_object_attributes[iter->first] = + base::Bind(iter->second, base::Unretained(this)); + } + } + + web_agent_->Run(web_options, + base::Bind(&WebModule::InitializeTaskInThread, + base::Unretained(this), construction_data), + this); } -WebModule::~WebModule() { - DCHECK(message_loop()); - DCHECK(web_agent_); - // This will cancel the timers for tasks, which help the thread exit - ClearAllIntervalsAndTimeouts(); - web_agent_->WaitUntilDone(); - web_agent_.reset(); -} - -void WebModule::Initialize(const ConstructionData& data, - web::Context* context) { +void WebModule::InitializeTaskInThread(const ConstructionData& data, + web::Context* context) { DCHECK_EQ(base::MessageLoop::current(), message_loop()); impl_.reset(new Impl(context, data)); }
diff --git a/cobalt/browser/web_module.h b/cobalt/browser/web_module.h index 3e442c8..a29c1bd 100644 --- a/cobalt/browser/web_module.h +++ b/cobalt/browser/web_module.h
@@ -55,6 +55,7 @@ #include "cobalt/web/blob.h" #include "cobalt/web/context.h" #include "cobalt/web/csp_delegate.h" +#include "cobalt/web/environment_settings.h" #include "cobalt/web/user_agent_platform_info.h" #include "cobalt/webdriver/session_driver.h" #include "starboard/atomic.h" @@ -90,9 +91,15 @@ public LifecycleObserver { public: struct Options { + typedef base::Callback<scoped_refptr<script::Wrappable>( + WebModule*, web::EnvironmentSettings*)> + CreateObjectFunction; + typedef base::hash_map<std::string, CreateObjectFunction> + InjectedGlobalObjectAttributes; + // All optional parameters defined in this structure should have their // values initialized in the default constructor to useful defaults. - explicit Options(const std::string& name); + Options(); web::Agent::Options web_options; @@ -240,6 +247,11 @@ // time. base::Callback<void(base::TimeTicks, base::TimeTicks)> collect_unload_event_time_callback; + + // injected_global_attributes contains a map of attributes to be injected + // into the Web Agent's window object upon construction. This provides + // a mechanism to inject custom APIs into the Web Agent object. + InjectedGlobalObjectAttributes injected_global_object_attributes; }; typedef layout::LayoutManager::LayoutResults LayoutResults; @@ -248,18 +260,19 @@ typedef base::Callback<void(const GURL&, const std::string&)> OnErrorCallback; typedef dom::Window::CloseCallback CloseCallback; - WebModule(const GURL& initial_url, - base::ApplicationState initial_application_state, - const OnRenderTreeProducedCallback& render_tree_produced_callback, - OnErrorCallback error_callback, - const CloseCallback& window_close_callback, - const base::Closure& window_minimize_callback, - media::CanPlayTypeHandler* can_play_type_handler, - media::MediaModule* media_module, - const cssom::ViewportSize& window_dimensions, - render_tree::ResourceProvider* resource_provider, - float layout_refresh_rate, const Options& options); + explicit WebModule(const std::string& name); ~WebModule(); + void Run(const GURL& initial_url, + base::ApplicationState initial_application_state, + const OnRenderTreeProducedCallback& render_tree_produced_callback, + OnErrorCallback error_callback, + const CloseCallback& window_close_callback, + const base::Closure& window_minimize_callback, + media::CanPlayTypeHandler* can_play_type_handler, + media::MediaModule* media_module, + const cssom::ViewportSize& window_dimensions, + render_tree::ResourceProvider* resource_provider, + float layout_refresh_rate, const Options& options); // Injects an on screen keyboard input event into the web module. The value // for type represents beforeinput or input. @@ -391,7 +404,7 @@ private: // Data required to construct a WebModule, initialized in the constructor and - // passed to |Initialize|. + // passed to |InitializeTaskInThread|. struct ConstructionData { ConstructionData(const GURL& initial_url, base::ApplicationState initial_application_state, @@ -453,9 +466,10 @@ // Forward declaration of the private implementation class. class Impl; - // Called by the constructor to create the private implementation object and + // Called by |Run| to create the private implementation object and // perform any other initialization required on the dedicated thread. - void Initialize(const ConstructionData& data, web::Context* context); + void InitializeTaskInThread(const ConstructionData& data, + web::Context* context); void ClearAllIntervalsAndTimeouts(); @@ -467,7 +481,7 @@ // The message loop this object is running on. base::MessageLoop* message_loop() const { DCHECK(web_agent_); - return web_agent_->message_loop(); + return web_agent_ ? web_agent_->message_loop() : nullptr; } // Private implementation object.
diff --git a/cobalt/demos/content/watchdog-demo/index.html b/cobalt/demos/content/watchdog-demo/index.html index c5f17f8..d23e7d4 100644 --- a/cobalt/demos/content/watchdog-demo/index.html +++ b/cobalt/demos/content/watchdog-demo/index.html
@@ -63,7 +63,7 @@ } else if (watchdogFunction == 'unregister') { ret = h5vcc.crashLog.unregister('test-name'); } else if (watchdogFunction == 'ping') { - ret = h5vcc.crashLog.ping('test-name', `test-ping`); + ret = h5vcc.crashLog.ping('test-name', 'test-ping'); } else if (watchdogFunction == 'getWatchdogViolations') { ret = h5vcc.crashLog.getWatchdogViolations(); } else if (watchdogFunction == 'getPersistentSettingWatchdogEnable') {
diff --git a/cobalt/dom/event_queue.cc b/cobalt/dom/event_queue.cc index ca851e8..1bd5282 100644 --- a/cobalt/dom/event_queue.cc +++ b/cobalt/dom/event_queue.cc
@@ -44,23 +44,6 @@ events_.push_back(event); } -void EventQueue::EnqueueAndMaybeDispatchImmediately( - const scoped_refptr<web::Event>& event) { - DCHECK(message_loop_->BelongsToCurrentThread()); - - bool was_empty = events_.empty(); - - Enqueue(event); - - if (was_empty) { - // We can only dispatch the event immediately if there aren't any existing - // events in the queue, because dom activities (including events) have to - // happen in order, and any existing events in the queue may mean that these - // events have to be dispatched after other activities not tracked here. - DispatchEvents(); - } -} - void EventQueue::CancelAllEvents() { DCHECK(message_loop_->BelongsToCurrentThread());
diff --git a/cobalt/dom/event_queue.h b/cobalt/dom/event_queue.h index 6aad863..a81e482 100644 --- a/cobalt/dom/event_queue.h +++ b/cobalt/dom/event_queue.h
@@ -44,11 +44,6 @@ explicit EventQueue(web::EventTarget* event_target); void Enqueue(const scoped_refptr<web::Event>& event); - // Try to dispatch the event immediately if there are no existing events in - // the queue, otherwise it has the same behavior as Enqueue(), which enqueues - // the event and the event will be dispatched after the existing events. - void EnqueueAndMaybeDispatchImmediately( - const scoped_refptr<web::Event>& event); void CancelAllEvents(); void TraceMembers(script::Tracer* tracer) override;
diff --git a/cobalt/dom/event_queue_test.cc b/cobalt/dom/event_queue_test.cc index be4a970..e8fc35f 100644 --- a/cobalt/dom/event_queue_test.cc +++ b/cobalt/dom/event_queue_test.cc
@@ -90,42 +90,6 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(EventQueueTest, EnqueueAndMaybeDispatchImmediatelyTest) { - scoped_refptr<web::EventTarget> event_target = - new web::EventTarget(&environment_settings_); - scoped_refptr<web::Event> event = new web::Event(base::Token("event")); - std::unique_ptr<MockEventListener> event_listener = - MockEventListener::Create(); - EventQueue event_queue(event_target.get()); - - event->set_target(event_target); - event_target->AddEventListener( - "event", FakeScriptValue<web::EventListener>(event_listener.get()), - false); - - { - ::testing::InSequence s; - ExpectHandleEventCallWithEventAndTarget(event_listener.get(), event, - event_target); - // The event should be dispatched immediately as the queue is empty, so the - // expectation should be set before being enqueued. - event_queue.EnqueueAndMaybeDispatchImmediately(event); - } - - { - ::testing::InSequence s; - event_queue.Enqueue(event); - // The event won't be dispatched immediately as the queue isn't empty, so - // the expectations can be set after being enqueued. - event_queue.EnqueueAndMaybeDispatchImmediately(event); - ExpectHandleEventCallWithEventAndTarget(event_listener.get(), event, - event_target); - ExpectHandleEventCallWithEventAndTarget(event_listener.get(), event, - event_target); - base::RunLoop().RunUntilIdle(); - } -} - TEST_F(EventQueueTest, CancelAllEventsTest) { scoped_refptr<web::EventTarget> event_target = new web::EventTarget(&environment_settings_);
diff --git a/cobalt/dom/html_script_element.cc b/cobalt/dom/html_script_element.cc index 42f7997..236cd3e 100644 --- a/cobalt/dom/html_script_element.cc +++ b/cobalt/dom/html_script_element.cc
@@ -351,6 +351,7 @@ base::Bind(&loader::TextDecoder::Create, base::Bind(&HTMLScriptElement::OnSyncContentProduced, base::Unretained(this)), + loader::TextDecoder::ResponseStartedCallback(), loader::Decoder::OnCompleteFunction()), base::Bind(&HTMLScriptElement::OnSyncLoadingComplete, base::Unretained(this)));
diff --git a/cobalt/dom/media_source.cc b/cobalt/dom/media_source.cc index 1dcc7d3..22f6bc5 100644 --- a/cobalt/dom/media_source.cc +++ b/cobalt/dom/media_source.cc
@@ -243,9 +243,8 @@ ChunkDemuxer::Status status = chunk_demuxer_->AddId(guid, type); switch (status) { case ChunkDemuxer::kOk: - source_buffer = new SourceBuffer(settings, guid, this, - asynchronous_reduction_enabled_, - chunk_demuxer_, &event_queue_); + source_buffer = + new SourceBuffer(settings, guid, this, chunk_demuxer_, &event_queue_); break; case ChunkDemuxer::kNotSupported: web::DOMException::Raise(web::DOMException::kNotSupportedErr,
diff --git a/cobalt/dom/media_source_settings.cc b/cobalt/dom/media_source_settings.cc index a330f83..84ac0f9 100644 --- a/cobalt/dom/media_source_settings.cc +++ b/cobalt/dom/media_source_settings.cc
@@ -52,6 +52,12 @@ LOG(INFO) << name << ": set to " << value; return true; } + } else if (name == "MediaSource.MaxSourceBufferAppendSizeInBytes") { + if (value > 0) { + max_source_buffer_append_size_in_bytes_ = value; + LOG(INFO) << name << ": set to " << value; + return true; + } } else { LOG(WARNING) << "Ignore unknown setting with name \"" << name << "\""; return false;
diff --git a/cobalt/dom/media_source_settings.h b/cobalt/dom/media_source_settings.h index 8d1b0be..61641b1 100644 --- a/cobalt/dom/media_source_settings.h +++ b/cobalt/dom/media_source_settings.h
@@ -36,6 +36,7 @@ const = 0; virtual base::Optional<bool> IsAsynchronousReductionEnabled() const = 0; virtual base::Optional<int> GetMinSizeForImmediateJob() const = 0; + virtual base::Optional<int> GetMaxSourceBufferAppendSizeInBytes() const = 0; protected: MediaSourceSettings() = default; @@ -67,6 +68,10 @@ base::AutoLock auto_lock(lock_); return min_size_for_immediate_job_; } + base::Optional<int> GetMaxSourceBufferAppendSizeInBytes() const override { + base::AutoLock auto_lock(lock_); + return max_source_buffer_append_size_in_bytes_; + } // Returns true when the setting associated with `name` is set to `value`. // Returns false when `name` is not associated with any settings, or if @@ -79,6 +84,7 @@ base::Optional<int> minimum_processor_count_to_offload_algorithm_; base::Optional<bool> is_asynchronous_reduction_enabled_; base::Optional<int> min_size_for_immediate_job_; + base::Optional<int> max_source_buffer_append_size_in_bytes_; }; } // namespace dom
diff --git a/cobalt/dom/media_source_settings_test.cc b/cobalt/dom/media_source_settings_test.cc index 27d9e9e..25d7878 100644 --- a/cobalt/dom/media_source_settings_test.cc +++ b/cobalt/dom/media_source_settings_test.cc
@@ -27,6 +27,7 @@ EXPECT_FALSE(impl.GetMinimumProcessorCountToOffloadAlgorithm()); EXPECT_FALSE(impl.IsAsynchronousReductionEnabled()); EXPECT_FALSE(impl.GetMinSizeForImmediateJob()); + EXPECT_FALSE(impl.GetMaxSourceBufferAppendSizeInBytes()); } TEST(MediaSourceSettingsImplTest, SunnyDay) { @@ -37,11 +38,13 @@ impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 101)); ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 1)); ASSERT_TRUE(impl.Set("MediaSource.MinSizeForImmediateJob", 103)); + ASSERT_TRUE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 100000)); EXPECT_EQ(impl.GetSourceBufferEvictExtraInBytes().value(), 100); EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 101); EXPECT_TRUE(impl.IsAsynchronousReductionEnabled().value()); EXPECT_EQ(impl.GetMinSizeForImmediateJob().value(), 103); + EXPECT_EQ(impl.GetMaxSourceBufferAppendSizeInBytes().value(), 100000); } TEST(MediaSourceSettingsImplTest, RainyDay) { @@ -52,11 +55,13 @@ impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", -101)); ASSERT_FALSE(impl.Set("MediaSource.EnableAsynchronousReduction", 2)); ASSERT_FALSE(impl.Set("MediaSource.MinSizeForImmediateJob", -103)); + ASSERT_FALSE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 0)); EXPECT_FALSE(impl.GetSourceBufferEvictExtraInBytes()); EXPECT_FALSE(impl.GetMinimumProcessorCountToOffloadAlgorithm()); EXPECT_FALSE(impl.IsAsynchronousReductionEnabled()); EXPECT_FALSE(impl.GetMinSizeForImmediateJob()); + EXPECT_FALSE(impl.GetMaxSourceBufferAppendSizeInBytes()); } TEST(MediaSourceSettingsImplTest, ZeroValuesWork) { @@ -67,6 +72,7 @@ impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 0)); ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 0)); ASSERT_TRUE(impl.Set("MediaSource.MinSizeForImmediateJob", 0)); + // O is an invalid value for "MediaSource.MaxSourceBufferAppendSizeInBytes". EXPECT_EQ(impl.GetSourceBufferEvictExtraInBytes().value(), 0); EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 0); @@ -82,17 +88,20 @@ impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 0)); ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 0)); ASSERT_TRUE(impl.Set("MediaSource.MinSizeForImmediateJob", 0)); + ASSERT_TRUE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 1)); ASSERT_TRUE(impl.Set("MediaSource.SourceBufferEvictExtraInBytes", 1)); ASSERT_TRUE( impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 1)); ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 1)); ASSERT_TRUE(impl.Set("MediaSource.MinSizeForImmediateJob", 1)); + ASSERT_TRUE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 2)); EXPECT_EQ(impl.GetSourceBufferEvictExtraInBytes().value(), 1); EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 1); EXPECT_TRUE(impl.IsAsynchronousReductionEnabled().value()); EXPECT_EQ(impl.GetMinSizeForImmediateJob().value(), 1); + EXPECT_EQ(impl.GetMaxSourceBufferAppendSizeInBytes().value(), 2); } TEST(MediaSourceSettingsImplTest, InvalidSettingNames) {
diff --git a/cobalt/dom/on_screen_keyboard.cc b/cobalt/dom/on_screen_keyboard.cc index 188aa1e..6f8da1b 100644 --- a/cobalt/dom/on_screen_keyboard.cc +++ b/cobalt/dom/on_screen_keyboard.cc
@@ -23,6 +23,63 @@ namespace cobalt { namespace dom { +namespace { +bool IsValidRGB(int r, int g, int b) { + if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { + return false; + } else { + return true; + } +} + +bool ParseColor(const char* color_str, int& r, int& g, int& b) { + size_t len = strlen(color_str); + if (len == 0) { + return false; + } + + // Handle hexadecimal color notation #RRGGBB + int r_tmp, g_tmp, b_tmp; + bool is_hex = + SbStringScanF(color_str, "#%02x%02x%02x", &r_tmp, &g_tmp, &b_tmp) == 3; + if (is_hex && IsValidRGB(r_tmp, g_tmp, b_tmp)) { + r = r_tmp; + g = g_tmp; + b = b_tmp; + return true; + } + + // Handle rgb color notation rgb(R, G, B) + if (!is_hex && len >= 10 && + SbStringCompareNoCaseN("rgb(", color_str, 4) == 0) { + int rgb_tmp[3] = {-1, -1, -1}; + const char* ptr = color_str + 4; + int i = 0; + while (*ptr) { + if (isdigit(*ptr)) { + char* end; + rgb_tmp[i++] = static_cast<int>(strtol(ptr, &end, 10)); + if (i == 3) { + break; + } + ptr = (const char*)end; + } else if (isspace(*ptr) || *ptr == ',') { + ptr++; + } else { + return false; + } + } + + if (IsValidRGB(rgb_tmp[0], rgb_tmp[1], rgb_tmp[2])) { + r = rgb_tmp[0]; + g = rgb_tmp[1]; + b = rgb_tmp[2]; + return true; + } + } + return false; +} +} // namespace OnScreenKeyboard::OnScreenKeyboard( script::EnvironmentSettings* settings, OnScreenKeyboardBridge* bridge, @@ -48,10 +105,17 @@ bridge_->Show(data_.c_str(), ticket); if (background_color_.has_value()) { - bridge_->SetBackgroundColor(background_color_.value().c_str()); + int r, g, b; + if (ParseColor(background_color_.value().c_str(), r, g, b)) { + bridge_->SetBackgroundColor(static_cast<uint8>(r), static_cast<uint8>(g), + static_cast<uint8>(b)); + } else { + LOG(WARNING) << "Invalid on-screen keyboard background color: " + << background_color_.value(); + } } - if (dark_theme_.has_value()) { - bridge_->SetDarkTheme(dark_theme_.value()); + if (light_theme_.has_value()) { + bridge_->SetLightTheme(light_theme_.value()); } return promise;
diff --git a/cobalt/dom/on_screen_keyboard.h b/cobalt/dom/on_screen_keyboard.h index ce7d0fa..ecad6bf 100644 --- a/cobalt/dom/on_screen_keyboard.h +++ b/cobalt/dom/on_screen_keyboard.h
@@ -106,10 +106,10 @@ return background_color_; } - void set_dark_theme(base::Optional<bool> dark_theme) { - dark_theme_ = dark_theme; + void set_light_theme(base::Optional<bool> light_theme) { + light_theme_ = light_theme; } - base::Optional<bool> dark_theme() const { return dark_theme_; } + base::Optional<bool> light_theme() const { return light_theme_; } // Called by the WebModule to dispatch DOM show, hide, focus, blur and // suggestions updated events. @@ -149,7 +149,7 @@ base::Optional<std::string> background_color_; - base::Optional<bool> dark_theme_; + base::Optional<bool> light_theme_; DISALLOW_COPY_AND_ASSIGN(OnScreenKeyboard); };
diff --git a/cobalt/dom/on_screen_keyboard.idl b/cobalt/dom/on_screen_keyboard.idl index fe13887..9487eec 100644 --- a/cobalt/dom/on_screen_keyboard.idl +++ b/cobalt/dom/on_screen_keyboard.idl
@@ -51,7 +51,7 @@ // 2. rgb color notation rgb(R, G, B), e.g. "rgb(0, 0, 255)". attribute DOMString? backgroundColor; - // This attribute overrides the dark theme of on-screen keyboard. + // This attribute overrides the light theme of on-screen keyboard. // The attribute is only fully supported on Apple TV at the moment. - attribute boolean? darkTheme; + attribute boolean? lightTheme; };
diff --git a/cobalt/dom/on_screen_keyboard_bridge.h b/cobalt/dom/on_screen_keyboard_bridge.h index c5623af..ac6ad1c 100644 --- a/cobalt/dom/on_screen_keyboard_bridge.h +++ b/cobalt/dom/on_screen_keyboard_bridge.h
@@ -17,6 +17,7 @@ #include <string> +#include "base/basictypes.h" #include "cobalt/dom/dom_rect.h" namespace cobalt { @@ -39,8 +40,8 @@ virtual scoped_refptr<DOMRect> BoundingRect() const = 0; virtual void SetKeepFocus(bool keep_focus) = 0; virtual bool IsValidTicket(int ticket) const = 0; - virtual void SetBackgroundColor(const char* background_color) = 0; - virtual void SetDarkTheme(bool dark_theme) = 0; + virtual void SetBackgroundColor(uint8 r, uint8 g, uint8 b) = 0; + virtual void SetLightTheme(bool light_theme) = 0; }; } // namespace dom
diff --git a/cobalt/dom/on_screen_keyboard_test.cc b/cobalt/dom/on_screen_keyboard_test.cc index fd616a3..b567585 100644 --- a/cobalt/dom/on_screen_keyboard_test.cc +++ b/cobalt/dom/on_screen_keyboard_test.cc
@@ -112,9 +112,9 @@ void SetKeepFocus(bool keep_focus) override { SetKeepFocusMock(keep_focus); } - void SetBackgroundColor(const char* background_color) override {} + void SetBackgroundColor(uint8 r, uint8 g, uint8 b) override {} - void SetDarkTheme(bool dark_theme) override {} + void SetLightTheme(bool light_theme) override {} MOCK_METHOD1(ShowMock, void(std::string)); MOCK_METHOD0(HideMock, void()); @@ -386,7 +386,7 @@ let promise; let logString; )"; - EXPECT_TRUE(EvaluateScript(let_script, NULL)); + EXPECT_TRUE(EvaluateScript(let_script)); const char event_script[] = R"( logString = '(empty)'; window.onScreenKeyboard.onshow = function() { @@ -436,7 +436,7 @@ let promise; let logString; )"; - EXPECT_TRUE(EvaluateScript(let_script, NULL)); + EXPECT_TRUE(EvaluateScript(let_script)); const char event_script[] = R"( logString = '(empty)'; window.onScreenKeyboard.onhide = function() { @@ -485,7 +485,7 @@ let promise; let logString; )"; - EXPECT_TRUE(EvaluateScript(let_script, NULL)); + EXPECT_TRUE(EvaluateScript(let_script)); const char event_script[] = R"( logString = '(empty)'; window.onScreenKeyboard.onfocus = function() { @@ -534,7 +534,7 @@ let promise; let logString; )"; - EXPECT_TRUE(EvaluateScript(let_script, NULL)); + EXPECT_TRUE(EvaluateScript(let_script)); const char event_script[] = R"( logString = '(empty)'; window.onScreenKeyboard.onblur = function() { @@ -605,7 +605,7 @@ window.onScreenKeyboard.keepFocus = false; window.onScreenKeyboard.keepFocus = true; )"; - EXPECT_TRUE(EvaluateScript(script, NULL)); + EXPECT_TRUE(EvaluateScript(script)); } TEST_F(OnScreenKeyboardTest, SetBackgroundColor) { @@ -635,21 +635,21 @@ EXPECT_EQ(color_str, result); } -TEST_F(OnScreenKeyboardTest, SetDarkTheme) { +TEST_F(OnScreenKeyboardTest, SetLightTheme) { if (SkipLocale()) return; std::string result; - EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.darkTheme;", &result)); + EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.lightTheme;", &result)); EXPECT_EQ("null", result); - std::string dark_theme_str = "false"; + std::string light_theme_str = "true"; EXPECT_TRUE( - EvaluateScript("window.onScreenKeyboard.darkTheme = " + dark_theme_str + + EvaluateScript("window.onScreenKeyboard.lightTheme = " + light_theme_str + ";" - "window.onScreenKeyboard.darkTheme", + "window.onScreenKeyboard.lightTheme", &result)); - EXPECT_EQ(dark_theme_str, result); + EXPECT_EQ(light_theme_str, result); } } // namespace dom
diff --git a/cobalt/dom/source_buffer.cc b/cobalt/dom/source_buffer.cc index 1f6278b..449eaa1 100644 --- a/cobalt/dom/source_buffer.cc +++ b/cobalt/dom/source_buffer.cc
@@ -103,6 +103,19 @@ return std::max<int>(bytes, 0); } +size_t GetMaxAppendSizeInBytes(script::EnvironmentSettings* settings, + size_t default_value) { + DOMSettings* dom_settings = + base::polymorphic_downcast<DOMSettings*>(settings); + DCHECK(dom_settings); + DCHECK(dom_settings->media_source_settings()); + int bytes = dom_settings->media_source_settings() + ->GetMaxSourceBufferAppendSizeInBytes() + .value_or(default_value); + DCHECK_GT(bytes, 0); + return bytes; +} + } // namespace SourceBuffer::OnInitSegmentReceivedHelper::OnInitSegmentReceivedHelper( @@ -133,13 +146,13 @@ SourceBuffer::SourceBuffer(script::EnvironmentSettings* settings, const std::string& id, MediaSource* media_source, - bool asynchronous_reduction_enabled, ChunkDemuxer* chunk_demuxer, EventQueue* event_queue) : web::EventTarget(settings), on_init_segment_received_helper_(new OnInitSegmentReceivedHelper(this)), id_(id), - asynchronous_reduction_enabled_(asynchronous_reduction_enabled), evict_extra_in_bytes_(GetEvictExtraInBytes(settings)), + max_append_buffer_size_( + GetMaxAppendSizeInBytes(settings, kDefaultMaxAppendBufferSize)), media_source_(media_source), chunk_demuxer_(chunk_demuxer), event_queue_(event_queue), @@ -154,6 +167,7 @@ DCHECK(event_queue); LOG(INFO) << "Evict extra in bytes is set to " << evict_extra_in_bytes_; + LOG(INFO) << "Max append size in bytes is set to " << max_append_buffer_size_; chunk_demuxer_->SetTracksWatcher( id_, @@ -381,10 +395,7 @@ std::unique_ptr<SourceBufferAlgorithm> algorithm( new SourceBufferRemoveAlgorithm( chunk_demuxer_, id_, DoubleToTimeDelta(start), DoubleToTimeDelta(end), - base::Bind(asynchronous_reduction_enabled_ - ? &SourceBuffer::ScheduleAndMaybeDispatchImmediately - : &SourceBuffer::ScheduleEvent, - base::Unretained(this)), + base::Bind(&SourceBuffer::ScheduleEvent, base::Unretained(this)), base::Bind(&SourceBuffer::OnAlgorithmFinalized, base::Unretained(this)))); auto algorithm_runner = @@ -481,16 +492,6 @@ event_queue_->Enqueue(event); } -void SourceBuffer::ScheduleAndMaybeDispatchImmediately(base::Token event_name) { - ScheduleEvent(event_name); - // TODO(b/244773734): Re-enable direct event dispatching - /* - scoped_refptr<web::Event> event = new web::Event(event_name); - event->set_target(this); - event_queue_->EnqueueAndMaybeDispatchImmediately(event); - */ -} - bool SourceBuffer::PrepareAppend(size_t new_data_size, script::ExceptionState* exception_state) { TRACE_EVENT1("cobalt::dom", "SourceBuffer::PrepareAppend()", "new_data_size", @@ -555,15 +556,12 @@ std::unique_ptr<SourceBufferAlgorithm> algorithm( new SourceBufferAppendAlgorithm( media_source_, chunk_demuxer_, id_, pending_append_data_.get(), size, - DoubleToTimeDelta(append_window_start_), + max_append_buffer_size_, DoubleToTimeDelta(append_window_start_), DoubleToTimeDelta(append_window_end_), DoubleToTimeDelta(timestamp_offset_), base::Bind(&SourceBuffer::UpdateTimestampOffset, base::Unretained(this)), - base::Bind(asynchronous_reduction_enabled_ - ? &SourceBuffer::ScheduleAndMaybeDispatchImmediately - : &SourceBuffer::ScheduleEvent, - base::Unretained(this)), + base::Bind(&SourceBuffer::ScheduleEvent, base::Unretained(this)), base::Bind(&SourceBuffer::OnAlgorithmFinalized, base::Unretained(this)), &metrics_));
diff --git a/cobalt/dom/source_buffer.h b/cobalt/dom/source_buffer.h index c7336e6..25b15ac 100644 --- a/cobalt/dom/source_buffer.h +++ b/cobalt/dom/source_buffer.h
@@ -90,8 +90,8 @@ // Custom, not in any spec. // SourceBuffer(script::EnvironmentSettings* settings, const std::string& id, - MediaSource* media_source, bool asynchronous_reduction_enabled, - ChunkDemuxer* chunk_demuxer, EventQueue* event_queue); + MediaSource* media_source, ChunkDemuxer* chunk_demuxer, + EventQueue* event_queue); // Web API: SourceBuffer // @@ -167,7 +167,6 @@ void OnInitSegmentReceived(std::unique_ptr<MediaTracks> tracks); void ScheduleEvent(base::Token event_name); - void ScheduleAndMaybeDispatchImmediately(base::Token event_name); bool PrepareAppend(size_t new_data_size, script::ExceptionState* exception_state); void AppendBufferInternal(const unsigned char* data, size_t size, @@ -185,10 +184,12 @@ const std::string& track_type, const std::string& byte_stream_track_id) const; + static const size_t kDefaultMaxAppendBufferSize = 128 * 1024; + scoped_refptr<OnInitSegmentReceivedHelper> on_init_segment_received_helper_; const std::string id_; - const bool asynchronous_reduction_enabled_; const size_t evict_extra_in_bytes_; + const size_t max_append_buffer_size_; MediaSource* media_source_; ChunkDemuxer* chunk_demuxer_;
diff --git a/cobalt/dom/source_buffer_algorithm.cc b/cobalt/dom/source_buffer_algorithm.cc index 50eec01..a24e51c 100644 --- a/cobalt/dom/source_buffer_algorithm.cc +++ b/cobalt/dom/source_buffer_algorithm.cc
@@ -27,8 +27,8 @@ SourceBufferAppendAlgorithm::SourceBufferAppendAlgorithm( MediaSource* media_source, ::media::ChunkDemuxer* chunk_demuxer, const std::string& id, const uint8_t* buffer, size_t size_in_bytes, - base::TimeDelta append_window_start, base::TimeDelta append_window_end, - base::TimeDelta timestamp_offset, + size_t max_append_size_in_bytes, base::TimeDelta append_window_start, + base::TimeDelta append_window_end, base::TimeDelta timestamp_offset, UpdateTimestampOffsetCB&& update_timestamp_offset_cb, ScheduleEventCB&& schedule_event_cb, base::OnceClosure&& finalized_cb, SourceBufferMetrics* metrics) @@ -36,6 +36,7 @@ chunk_demuxer_(chunk_demuxer), id_(id), buffer_(buffer), + max_append_size_(max_append_size_in_bytes), bytes_remaining_(size_in_bytes), append_window_start_(append_window_start), append_window_end_(append_window_end), @@ -46,6 +47,7 @@ metrics_(metrics) { DCHECK(media_source_); DCHECK(chunk_demuxer_); + DCHECK_GT(static_cast<int>(max_append_size_), 0); if (bytes_remaining_ > 0) { DCHECK(buffer); } @@ -60,9 +62,7 @@ DCHECK(finished); DCHECK(!*finished); - const size_t kMaxAppendSize = 128 * 1024; - - size_t append_size = std::min(bytes_remaining_, kMaxAppendSize); + size_t append_size = std::min(bytes_remaining_, max_append_size_); TRACE_EVENT1("cobalt::dom", "SourceBufferAppendAlgorithm::Process()", "append_size", append_size);
diff --git a/cobalt/dom/source_buffer_algorithm.h b/cobalt/dom/source_buffer_algorithm.h index d9e0f16..3505794 100644 --- a/cobalt/dom/source_buffer_algorithm.h +++ b/cobalt/dom/source_buffer_algorithm.h
@@ -58,8 +58,8 @@ SourceBufferAppendAlgorithm( MediaSource* media_source, ::media::ChunkDemuxer* chunk_demuxer, const std::string& id, const uint8_t* buffer, size_t size_in_bytes, - base::TimeDelta append_window_start, base::TimeDelta append_window_end, - base::TimeDelta timestamp_offset, + size_t max_append_size_in_bytes, base::TimeDelta append_window_start, + base::TimeDelta append_window_end, base::TimeDelta timestamp_offset, UpdateTimestampOffsetCB&& update_timestamp_offset_cb, ScheduleEventCB&& schedule_event_cb, base::OnceClosure&& finalized_cb, SourceBufferMetrics* metrics); @@ -74,6 +74,7 @@ ::media::ChunkDemuxer* const chunk_demuxer_; const std::string id_; const uint8_t* buffer_; + const size_t max_append_size_; size_t bytes_remaining_; const base::TimeDelta append_window_start_; const base::TimeDelta append_window_end_;
diff --git a/cobalt/dom/testing/stub_window.h b/cobalt/dom/testing/stub_window.h index 6651633..9a67b66 100644 --- a/cobalt/dom/testing/stub_window.h +++ b/cobalt/dom/testing/stub_window.h
@@ -91,18 +91,6 @@ on_screen_keyboard_bridge_ = on_screen_keyboard_bridge; } - private: - static void StubLoadCompleteCallback( - const base::Optional<std::string>& error) {} - - void InitializeWebContext() { - web_context_.reset(new web::testing::StubWebContext()); - web_context()->setup_environment_settings( - new dom::testing::StubEnvironmentSettings(options_)); - web_context()->environment_settings()->set_creation_url( - GURL("about:blank")); - } - void InitializeWindow() { loader_factory_.reset(new loader::LoaderFactory( "Test", web_context()->fetcher_factory(), NULL, @@ -143,6 +131,19 @@ window_, web_context()->environment_settings()); } + private: + static void StubLoadCompleteCallback( + const base::Optional<std::string>& error) {} + + void InitializeWebContext() { + web_context_.reset(new web::testing::StubWebContext()); + web_context()->setup_environment_settings( + new dom::testing::StubEnvironmentSettings(options_)); + web_context()->environment_settings()->set_creation_url( + GURL("about:blank")); + } + + OnScreenKeyboardBridge* on_screen_keyboard_bridge_ = nullptr; DOMSettings::Options options_; std::unique_ptr<css_parser::Parser> css_parser_;
diff --git a/cobalt/dom/testing/test_with_javascript.h b/cobalt/dom/testing/test_with_javascript.h index 30204af..e51747f 100644 --- a/cobalt/dom/testing/test_with_javascript.h +++ b/cobalt/dom/testing/test_with_javascript.h
@@ -42,24 +42,38 @@ EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks()); } - StubWindow* stub_window() { return stub_window_.get(); } - web::testing::StubWebContext* stub_web_context() { + StubWindow* stub_window() const { return stub_window_.get(); } + web::testing::StubWebContext* stub_web_context() const { + DCHECK(stub_window_); return stub_window_->web_context(); } - Window* window() { return stub_window_->window().get(); } + Window* window() const { + DCHECK(stub_window_); + return stub_window_->window().get(); + } - bool EvaluateScript(const std::string& js_code, std::string* result) { + web::Context* web_context() const { return stub_web_context(); } + + scoped_refptr<script::GlobalEnvironment> global_environment() const { + DCHECK(web_context()); + return web_context()->global_environment(); + } + + bool EvaluateScript(const std::string& js_code, + std::string* result = nullptr) { + DCHECK(global_environment()); return global_environment()->EvaluateScript( CreateSourceCodeAndPrepareEval(js_code), result); } bool EvaluateScript( const std::string& js_code, - const scoped_refptr<script::Wrappable>& owning_object, - base::Optional<script::ValueHandleHolder::Reference>* result = NULL) { + base::Optional<script::ValueHandleHolder::Reference>* result) { + DCHECK(global_environment()); return global_environment()->EvaluateScript( - CreateSourceCodeAndPrepareEval(js_code), owning_object, result); + CreateSourceCodeAndPrepareEval(js_code), + web_context()->GetWindowOrWorkerGlobalScope(), result); } ::testing::StrictMock<script::testing::MockExceptionState>*
diff --git a/cobalt/extension/crash_handler.h b/cobalt/extension/crash_handler.h index 8cf4732..912caba 100644 --- a/cobalt/extension/crash_handler.h +++ b/cobalt/extension/crash_handler.h
@@ -36,8 +36,15 @@ // The fields below this point were added in version 1 or later. + // Deprecated in version 2 and later. bool (*OverrideCrashpadAnnotations)( CrashpadAnnotations* crashpad_annotations); + + // The fields below this point were added in version 2 or later. + + // Sets a (key, value) pair for the handler to include when annotating a + // crash. Returns true on success and false on failure. + bool (*SetString)(const char* key, const char* value); } CobaltExtensionCrashHandlerApi; #ifdef __cplusplus
diff --git a/cobalt/extension/extension_test.cc b/cobalt/extension/extension_test.cc index cd7158d..58f051e 100644 --- a/cobalt/extension/extension_test.cc +++ b/cobalt/extension/extension_test.cc
@@ -221,9 +221,14 @@ } EXPECT_STREQ(extension_api->name, kExtensionName); - EXPECT_EQ(extension_api->version, 1u); + EXPECT_GE(extension_api->version, 1u); + EXPECT_LE(extension_api->version, 2u); EXPECT_NE(extension_api->OverrideCrashpadAnnotations, nullptr); + if (extension_api->version >= 2) { + EXPECT_NE(extension_api->SetString, nullptr); + } + const ExtensionApi* second_extension_api = static_cast<const ExtensionApi*>(SbSystemGetExtension(kExtensionName)); EXPECT_EQ(second_extension_api, extension_api)
diff --git a/cobalt/extension/on_screen_keyboard.h b/cobalt/extension/on_screen_keyboard.h index a1d922d..315e2b7 100644 --- a/cobalt/extension/on_screen_keyboard.h +++ b/cobalt/extension/on_screen_keyboard.h
@@ -15,8 +15,6 @@ #ifndef COBALT_EXTENSION_ON_SCREEN_KEYBOARD_H_ #define COBALT_EXTENSION_ON_SCREEN_KEYBOARD_H_ -#include <stdint.h> - #include "starboard/system.h" #include "starboard/window.h" @@ -38,16 +36,12 @@ // The fields below this point were added in version 1 or later. - // This function overrides the background color of on-screen keyboard. - // The function is only enabled for Apple TV at the moment. - // background_color should be a string of below formats: - // 1. hex color notation #RRGGBB, e.g. "#0000FF". - // 2. rgb color notation rgb(R, G, B), e.g. "rgb(0, 0, 255)". - void (*SetBackgroundColor)(SbWindow window, const char* background_color); + // This function overrides the background color of on-screen keyboard in RGB + // color space, where r, g, b are between 0 and 255. + void (*SetBackgroundColor)(SbWindow window, uint8_t r, uint8_t g, uint8_t b); - // This function overrides the dark theme of on-screen keyboard. - // The function is only enabled for Apple TV at the moment. - void (*SetDarkTheme)(SbWindow window, bool dark_theme); + // This function overrides the light theme of on-screen keyboard. + void (*SetLightTheme)(SbWindow window, bool light_theme); } CobaltExtensionOnScreenKeyboardApi; #ifdef __cplusplus
diff --git a/cobalt/h5vcc/h5vcc_crash_log.cc b/cobalt/h5vcc/h5vcc_crash_log.cc index 737d64c..a240d92 100644 --- a/cobalt/h5vcc/h5vcc_crash_log.cc +++ b/cobalt/h5vcc/h5vcc_crash_log.cc
@@ -20,6 +20,7 @@ #include "base/atomicops.h" #include "base/memory/singleton.h" #include "base/synchronization/lock.h" +#include "cobalt/extension/crash_handler.h" #if SB_HAS(CORE_DUMP_HANDLER_SUPPORT) #include STARBOARD_CORE_DUMP_HANDLER_INCLUDE @@ -97,6 +98,15 @@ bool H5vccCrashLog::SetString(const std::string& key, const std::string& value) { + auto crash_handler_extension = + static_cast<const CobaltExtensionCrashHandlerApi*>( + SbSystemGetExtension(kCobaltExtensionCrashHandlerName)); + if (crash_handler_extension && crash_handler_extension->version >= 2) { + return crash_handler_extension->SetString(key.c_str(), value.c_str()); + } + // The platform has not implemented a version of the CrashHandler Cobalt + // Extension appropriate for this use case. + // Forward the call to a global singleton so that we keep a consistent crash // log globally. CrashLogDictionary::GetInstance()->SetString(key, value);
diff --git a/cobalt/h5vcc/h5vcc_crash_log.idl b/cobalt/h5vcc/h5vcc_crash_log.idl index 7892219..e93caac 100644 --- a/cobalt/h5vcc/h5vcc_crash_log.idl +++ b/cobalt/h5vcc/h5vcc_crash_log.idl
@@ -56,9 +56,8 @@ boolean ping(DOMString name, DOMString ping_info); // Returns a json string containing the Watchdog violations since the last - // call, up to the 200 most recent. Clears internal cache of Watchdog - // violations to prevent duplicates. Timestamps are stored as strings due to - // int size constraints. + // call, up to 200. Clears internal cache of Watchdog violations to prevent + // duplicates. Timestamps are stored as strings due to int size constraints. // Example json: // { // "test-name":{
diff --git a/cobalt/layout_tests/layout_snapshot.cc b/cobalt/layout_tests/layout_snapshot.cc index 57e3769..88d07f3 100644 --- a/cobalt/layout_tests/layout_snapshot.cc +++ b/cobalt/layout_tests/layout_snapshot.cc
@@ -83,7 +83,7 @@ // Use test runner mode to allow the content itself to dictate when it is // ready for layout should be performed. See cobalt/dom/test_runner.h. - browser::WebModule::Options web_module_options("SnapshotURL"); + browser::WebModule::Options web_module_options; web_module_options.layout_trigger = layout::LayoutManager::kTestRunnerMode; web_module_options.image_cache_capacity = kImageCacheCapacity; web_module_options.provide_screenshot_function = screenshot_provider; @@ -97,7 +97,8 @@ base::Optional<browser::WebModule::LayoutResults> results; // Create the WebModule and wait for a layout to occur. - browser::WebModule web_module( + browser::WebModule web_module("SnapshotURL"); + web_module.Run( url, base::kApplicationStateStarted, base::Bind(&WebModuleOnRenderTreeProducedCallback, &results, &run_loop, base::MessageLoop::current()),
diff --git a/cobalt/layout_tests/web_platform_tests.cc b/cobalt/layout_tests/web_platform_tests.cc index 520ed72..c5406bf 100644 --- a/cobalt/layout_tests/web_platform_tests.cc +++ b/cobalt/layout_tests/web_platform_tests.cc
@@ -209,7 +209,7 @@ web::kCspEnforcementEnable, CspDelegatePermissive::Create); // Use test runner mode to allow the content itself to dictate when it is // ready for layout should be performed. See cobalt/dom/test_runner.h. - browser::WebModule::Options web_module_options("RunWebPlatformTest"); + browser::WebModule::Options web_module_options; web_module_options.layout_trigger = layout::LayoutManager::kTestRunnerMode; // We assume that we won't suspend/resume while running the tests, and so // we take advantage of the convenience of inline script tags. @@ -222,7 +222,8 @@ base::RunLoop run_loop; // Create the WebModule and wait for a layout to occur. - browser::WebModule web_module( + browser::WebModule web_module("RunWebPlatformTest"); + web_module.Run( url, base::kApplicationStateStarted, base::Bind(&WebModuleOnRenderTreeProducedCallback, &results), base::Bind(&WebModuleErrorCallback, &run_loop,
diff --git a/cobalt/loader/loader_factory.cc b/cobalt/loader/loader_factory.cc index ba571ba..0cb575e 100644 --- a/cobalt/loader/loader_factory.cc +++ b/cobalt/loader/loader_factory.cc
@@ -71,7 +71,8 @@ std::unique_ptr<Loader> loader(new Loader( fetcher_creator, - base::Bind(&loader::TextDecoder::Create, link_available_callback), + base::Bind(&loader::TextDecoder::Create, link_available_callback, + loader::TextDecoder::ResponseStartedCallback()), load_complete_callback, base::Bind(&LoaderFactory::OnLoaderDestroyed, base::Unretained(this)), is_suspended_));
diff --git a/cobalt/loader/loader_test.cc b/cobalt/loader/loader_test.cc index fc0b3b6..424f402 100644 --- a/cobalt/loader/loader_test.cc +++ b/cobalt/loader/loader_test.cc
@@ -250,13 +250,13 @@ FileFetcher::Options fetcher_options; TextDecoderCallback text_decoder_callback(&run_loop); LoaderCallback loader_callback(&run_loop); - Loader loader( - base::Bind(&FileFetcher::Create, file_path, fetcher_options), - base::Bind(&loader::TextDecoder::Create, - base::Bind(&TextDecoderCallback::OnDone, - base::Unretained(&text_decoder_callback))), - base::Bind(&LoaderCallback::OnLoadComplete, - base::Unretained(&loader_callback))); + Loader loader(base::Bind(&FileFetcher::Create, file_path, fetcher_options), + base::Bind(&loader::TextDecoder::Create, + base::Bind(&TextDecoderCallback::OnDone, + base::Unretained(&text_decoder_callback)), + loader::TextDecoder::ResponseStartedCallback()), + base::Bind(&LoaderCallback::OnLoadComplete, + base::Unretained(&loader_callback))); // When the message loop runs, the loader will start loading. It'll quit when // loading is finished.
diff --git a/cobalt/loader/script_loader_factory.cc b/cobalt/loader/script_loader_factory.cc index 8fb5cac..0e64cf0 100644 --- a/cobalt/loader/script_loader_factory.cc +++ b/cobalt/loader/script_loader_factory.cc
@@ -47,19 +47,31 @@ const csp::SecurityCallback& url_security_callback, const TextDecoder::TextAvailableCallback& script_available_callback, const Loader::OnCompleteFunction& load_complete_callback) { + return CreateScriptLoader( + url, origin, url_security_callback, script_available_callback, + TextDecoder::ResponseStartedCallback(), load_complete_callback); +} + +std::unique_ptr<Loader> ScriptLoaderFactory::CreateScriptLoader( + const GURL& url, const Origin& origin, + const csp::SecurityCallback& url_security_callback, + const TextDecoder::TextAvailableCallback& script_available_callback, + const TextDecoder::ResponseStartedCallback& response_started_callback, + const Loader::OnCompleteFunction& load_complete_callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); Loader::FetcherCreator fetcher_creator = MakeFetcherCreator(url, url_security_callback, kNoCORSMode, origin, disk_cache::kUncompiledScript); - std::unique_ptr<Loader> loader(new Loader( - fetcher_creator, - base::Bind(&loader::TextDecoder::Create, script_available_callback), - load_complete_callback, - base::Bind(&ScriptLoaderFactory::OnLoaderDestroyed, - base::Unretained(this)), - is_suspended_)); + std::unique_ptr<Loader> loader( + new Loader(fetcher_creator, + base::Bind(&TextDecoder::Create, script_available_callback, + response_started_callback), + load_complete_callback, + base::Bind(&ScriptLoaderFactory::OnLoaderDestroyed, + base::Unretained(this)), + is_suspended_)); OnLoaderCreated(loader.get()); return loader;
diff --git a/cobalt/loader/script_loader_factory.h b/cobalt/loader/script_loader_factory.h index 5fcc8a4..2ae2a40 100644 --- a/cobalt/loader/script_loader_factory.h +++ b/cobalt/loader/script_loader_factory.h
@@ -48,6 +48,13 @@ const TextDecoder::TextAvailableCallback& script_available_callback, const Loader::OnCompleteFunction& load_complete_callback); + std::unique_ptr<Loader> CreateScriptLoader( + const GURL& url, const Origin& origin, + const csp::SecurityCallback& url_security_callback, + const TextDecoder::TextAvailableCallback& script_available_callback, + const TextDecoder::ResponseStartedCallback& response_started_callback, + const Loader::OnCompleteFunction& load_complete_callback); + protected: void OnLoaderCreated(Loader* loader); void OnLoaderDestroyed(Loader* loader);
diff --git a/cobalt/loader/text_decoder.h b/cobalt/loader/text_decoder.h index 07a2492..16ad4ce 100644 --- a/cobalt/loader/text_decoder.h +++ b/cobalt/loader/text_decoder.h
@@ -34,6 +34,9 @@ // results. class TextDecoder : public Decoder { public: + typedef base::Callback<bool( + Fetcher* fetcher, const scoped_refptr<net::HttpResponseHeaders>& headers)> + ResponseStartedCallback; typedef base::Callback<void(const loader::Origin&, std::unique_ptr<std::string>)> TextAvailableCallback; @@ -43,10 +46,24 @@ // This function is used for binding callback for creating TextDecoder. static std::unique_ptr<Decoder> Create( const TextAvailableCallback& text_available_callback, + const ResponseStartedCallback& response_started_callback = + ResponseStartedCallback(), const loader::Decoder::OnCompleteFunction& load_complete_callback = loader::Decoder::OnCompleteFunction()) { - return std::unique_ptr<Decoder>( - new TextDecoder(text_available_callback, load_complete_callback)); + return std::unique_ptr<Decoder>(new TextDecoder(text_available_callback, + response_started_callback, + load_complete_callback)); + } + + LoadResponseType OnResponseStarted( + Fetcher* fetcher, const scoped_refptr<net::HttpResponseHeaders>& headers) + override WARN_UNUSED_RESULT { + if (fetcher && headers && !response_started_callback_.is_null()) { + if (!response_started_callback_.Run(fetcher, headers)) { + return kLoadResponseAbort; + } + } + return kLoadResponseContinue; } // From Decoder. @@ -105,13 +122,16 @@ private: explicit TextDecoder( const TextAvailableCallback& text_available_callback, + const ResponseStartedCallback& response_started_callback, const loader::Decoder::OnCompleteFunction& load_complete_callback) : text_available_callback_(text_available_callback), + response_started_callback_(response_started_callback), load_complete_callback_(load_complete_callback), suspended_(false) {} THREAD_CHECKER(thread_checker_); TextAvailableCallback text_available_callback_; + ResponseStartedCallback response_started_callback_; loader::Decoder::OnCompleteFunction load_complete_callback_; loader::Origin last_url_origin_; std::unique_ptr<std::string> text_;
diff --git a/cobalt/media/base/pipeline.h b/cobalt/media/base/pipeline.h index e729c41..9f9995e 100644 --- a/cobalt/media/base/pipeline.h +++ b/cobalt/media/base/pipeline.h
@@ -57,6 +57,7 @@ typedef ::media::PipelineStatistics PipelineStatistics; typedef ::media::PipelineStatus PipelineStatus; typedef ::media::PipelineStatusCallback PipelineStatusCallback; + typedef ::media::PipelineStatusCB PipelineStatusCB; typedef base::Callback<void(PipelineStatus status, bool is_initial_preroll, const std::string& error_message)> @@ -126,7 +127,7 @@ // It is an error to call this method after the pipeline has already started. virtual void Start(Demuxer* demuxer, const SetDrmSystemReadyCB& set_drm_system_ready_cb, - PipelineStatusCallback ended_cb, const ErrorCB& error_cb, + const PipelineStatusCB& ended_cb, const ErrorCB& error_cb, const SeekCB& seek_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& duration_change_cb, @@ -140,7 +141,7 @@ const OnEncryptedMediaInitDataEncounteredCB& encrypted_media_init_data_encountered_cb, const std::string& source_url, - PipelineStatusCallback ended_cb, const ErrorCB& error_cb, + const PipelineStatusCB& ended_cb, const ErrorCB& error_cb, const SeekCB& seek_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& duration_change_cb,
diff --git a/cobalt/media/base/sbplayer_pipeline.cc b/cobalt/media/base/sbplayer_pipeline.cc index c48b29c..9b9d538 100644 --- a/cobalt/media/base/sbplayer_pipeline.cc +++ b/cobalt/media/base/sbplayer_pipeline.cc
@@ -76,7 +76,7 @@ struct StartTaskParameters { Demuxer* demuxer; SetDrmSystemReadyCB set_drm_system_ready_cb; - PipelineStatusCallback ended_cb; + ::media::PipelineStatusCB ended_cb; ErrorCB error_cb; Pipeline::SeekCB seek_cb; Pipeline::BufferingStateCB buffering_state_cb; @@ -113,7 +113,7 @@ void Start(Demuxer* demuxer, const SetDrmSystemReadyCB& set_drm_system_ready_cb, - PipelineStatusCallback ended_cb, const ErrorCB& error_cb, + const PipelineStatusCB& ended_cb, const ErrorCB& error_cb, const SeekCB& seek_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& duration_change_cb, const base::Closure& output_mode_change_cb, @@ -123,7 +123,7 @@ void Start(const SetDrmSystemReadyCB& set_drm_system_ready_cb, const OnEncryptedMediaInitDataEncounteredCB& encrypted_media_init_data_encountered_cb, - const std::string& source_url, PipelineStatusCallback ended_cb, + const std::string& source_url, const PipelineStatusCB& ended_cb, const ErrorCB& error_cb, const SeekCB& seek_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& duration_change_cb, @@ -265,7 +265,7 @@ // Permanent callbacks passed in via Start(). SetDrmSystemReadyCB set_drm_system_ready_cb_; - PipelineStatusCallback ended_cb_; + PipelineStatusCB ended_cb_; ErrorCB error_cb_; BufferingStateCB buffering_state_cb_; base::Closure duration_change_cb_; @@ -441,7 +441,7 @@ void SbPlayerPipeline::Start(Demuxer* demuxer, const SetDrmSystemReadyCB& set_drm_system_ready_cb, - PipelineStatusCallback ended_cb, + const PipelineStatusCB& ended_cb, const ErrorCB& error_cb, const SeekCB& seek_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& duration_change_cb, @@ -462,7 +462,7 @@ StartTaskParameters parameters; parameters.demuxer = demuxer; parameters.set_drm_system_ready_cb = set_drm_system_ready_cb; - parameters.ended_cb = std::move(ended_cb); + parameters.ended_cb = ended_cb; parameters.error_cb = error_cb; parameters.seek_cb = seek_cb; parameters.buffering_state_cb = buffering_state_cb; @@ -484,7 +484,7 @@ const OnEncryptedMediaInitDataEncounteredCB& on_encrypted_media_init_data_encountered_cb, const std::string& source_url, - PipelineStatusCallback ended_cb, + const PipelineStatusCB& ended_cb, const ErrorCB& error_cb, const SeekCB& seek_cb, const BufferingStateCB& buffering_state_cb, const base::Closure& duration_change_cb, @@ -504,7 +504,7 @@ StartTaskParameters parameters; parameters.demuxer = NULL; parameters.set_drm_system_ready_cb = set_drm_system_ready_cb; - parameters.ended_cb = std::move(ended_cb); + parameters.ended_cb = ended_cb; parameters.error_cb = error_cb; parameters.seek_cb = seek_cb; parameters.buffering_state_cb = buffering_state_cb; @@ -810,7 +810,7 @@ demuxer_ = parameters.demuxer; set_drm_system_ready_cb_ = parameters.set_drm_system_ready_cb; - ended_cb_ = std::move(parameters.ended_cb); + ended_cb_ = parameters.ended_cb; error_cb_ = parameters.error_cb; { base::AutoLock auto_lock(lock_); @@ -1327,7 +1327,7 @@ break; } case kSbPlayerStateEndOfStream: - std::move(ended_cb_).Run(::media::PIPELINE_OK); + ended_cb_.Run(::media::PIPELINE_OK); ended_ = true; break; case kSbPlayerStateDestroyed:
diff --git a/cobalt/media/base/starboard_player.cc b/cobalt/media/base/starboard_player.cc index 7e7da28..3c9d8cf 100644 --- a/cobalt/media/base/starboard_player.cc +++ b/cobalt/media/base/starboard_player.cc
@@ -567,12 +567,6 @@ bool is_visible = SbWindowIsValid(window_); SbMediaAudioCodec audio_codec = audio_sample_info_.codec; - SbMediaVideoCodec video_codec = kSbMediaVideoCodecNone; - // TODO: This is temporary for supporting background media playback. - // Need to be removed with media refactor. - if (is_visible) { - video_codec = video_sample_info_.codec; - } bool has_audio = audio_codec != kSbMediaAudioCodecNone; @@ -1023,8 +1017,8 @@ " kSbPlayerStatePrerolling received %" PRId64 " us\n" " First media sample(s) written [a/v] %" PRId64 "/%" PRId64 " us\n" " kSbPlayerStatePresenting received %" PRId64 " us\n" - " Startup latency statistics (us):\n" - " min: %" PRId64 ", median: %" PRId64 ", average: %" PRId64 + " Startup latency statistics (us):" + " min: %" PRId64 ", median: %" PRId64 ", average: %" PRId64 ", max: %" PRId64, startup_latency, first_events_str.c_str(), player_initialization_time_delta,
diff --git a/cobalt/media/progressive/avc_parser.cc b/cobalt/media/progressive/avc_parser.cc index f9dcc0b..4c447db 100644 --- a/cobalt/media/progressive/avc_parser.cc +++ b/cobalt/media/progressive/avc_parser.cc
@@ -477,6 +477,7 @@ aac.GetChannelLayout(kSbrInMimetype), aac.GetOutputSamplesPerSecond(kSbrInMimetype), aac.codec_specific_data(), ::media::EncryptionScheme::kUnencrypted, base::TimeDelta(), 0); + audio_config_.set_aac_extra_data(aac.codec_specific_data()); } size_t AVCParser::CalculatePrependSize(DemuxerStream::Type type,
diff --git a/cobalt/media_integration_tests/functionality/general_playback.py b/cobalt/media_integration_tests/functionality/general_playback.py index 8b3ea3a..8dcd83d 100644 --- a/cobalt/media_integration_tests/functionality/general_playback.py +++ b/cobalt/media_integration_tests/functionality/general_playback.py
@@ -40,8 +40,7 @@ TEST_PARAMETERS = [ ('H264', PlaybackUrls.H264_ONLY, None), - # TODO(b/223856877) -- find out why Progressive still broken - #('PROGRESSIVE', PlaybackUrls.PROGRESSIVE, None), + ('PROGRESSIVE', PlaybackUrls.PROGRESSIVE, None), ('ENCRYPTED', PlaybackUrls.ENCRYPTED, None), ('VR', PlaybackUrls.VR, None), ('VP9', PlaybackUrls.VP9, MimeStrings.VP9),
diff --git a/cobalt/script/script_value.h b/cobalt/script/script_value.h index e1345e2..25567d7 100644 --- a/cobalt/script/script_value.h +++ b/cobalt/script/script_value.h
@@ -17,6 +17,7 @@ #include <algorithm> #include <memory> +#include <utility> #include "base/basictypes.h" #include "base/logging.h" @@ -171,8 +172,10 @@ : Handle(reference.referenced_value().MakeWeakCopy().release()) {} Handle(const Handle& other) : script_value_(other.script_value_) { - script_value_->PreventGarbageCollection(); - script_value_->reference_count_++; + if (script_value_) { + script_value_->PreventGarbageCollection(); + script_value_->reference_count_++; + } } // We need the default constructor for nullable ScriptValue. Handle() = default;
diff --git a/cobalt/script/v8c/conversion_helpers.h b/cobalt/script/v8c/conversion_helpers.h index 81bf303..d1779af 100644 --- a/cobalt/script/v8c/conversion_helpers.h +++ b/cobalt/script/v8c/conversion_helpers.h
@@ -85,7 +85,8 @@ inline void ToJSValue(v8::Isolate* isolate, const std::string& in_string, v8::Local<v8::Value>* out_value) { v8::MaybeLocal<v8::String> maybe_string = v8::String::NewFromUtf8( - isolate, in_string.data(), v8::NewStringType::kNormal, in_string.size()); + isolate, in_string.data(), v8::NewStringType::kNormal, + static_cast<int>(in_string.size())); v8::Local<v8::Value> string; if (!maybe_string.ToLocal(&string)) { *out_value = v8::Null(isolate); @@ -107,7 +108,8 @@ inline void ToJSValue(v8::Isolate* isolate, const std::vector<uint8_t>& in_data, v8::Local<v8::Value>* out_value) { v8::MaybeLocal<v8::String> maybe_string = v8::String::NewFromOneByte( - isolate, in_data.data(), v8::NewStringType::kNormal, in_data.size()); + isolate, in_data.data(), v8::NewStringType::kNormal, + static_cast<int>(in_data.size())); v8::Local<v8::Value> string; if (!maybe_string.ToLocal(&string)) { *out_value = v8::Null(isolate); @@ -165,12 +167,12 @@ } template <typename T> -inline const double UpperBound() { +inline double UpperBound() { return std::numeric_limits<T>::max(); } template <typename T> -inline const double LowerBound() { +inline double LowerBound() { return std::numeric_limits<T>::min(); } @@ -179,19 +181,19 @@ // step 1 of ConvertToInt, see: // https://heycam.github.io/webidl/#abstract-opdef-converttoint template <> -inline const double UpperBound<int64_t>() { +inline double UpperBound<int64_t>() { const double kInt64UpperBound = static_cast<double>((1ll << 53) - 1); return kInt64UpperBound; } template <> -inline const double LowerBound<int64_t>() { +inline double LowerBound<int64_t>() { const double kInt64LowerBound = static_cast<double>(-(1ll << 53) + 1); return kInt64LowerBound; } template <> -inline const double UpperBound<uint64_t>() { +inline double UpperBound<uint64_t>() { const double kUInt64UpperBound = static_cast<double>((1ll << 53) - 1); return kUInt64UpperBound; } @@ -602,8 +604,7 @@ // 4.3. Let P be the result of calling ToString(i). // 4.4. Call CreateDataProperty(A, P, E). - v8::Maybe<bool> set_result = - array->Set(isolate->GetCurrentContext(), index, element); + array->Set(isolate->GetCurrentContext(), index, element).Check(); // 4.5. Set i to i + 1. }
diff --git a/cobalt/script/v8c/helpers.h b/cobalt/script/v8c/helpers.h index c2bfbef..2529039 100644 --- a/cobalt/script/v8c/helpers.h +++ b/cobalt/script/v8c/helpers.h
@@ -15,6 +15,8 @@ #ifndef COBALT_SCRIPT_V8C_HELPERS_H_ #define COBALT_SCRIPT_V8C_HELPERS_H_ +#include <string> + #include "starboard/common/string.h" #include "v8/include/v8.h" @@ -35,7 +37,7 @@ } return v8::String::NewFromOneByte( isolate, reinterpret_cast<const uint8_t*>(string), - v8::NewStringType::kInternalized, strlen(string)) + v8::NewStringType::kInternalized, static_cast<int>(strlen(string))) .ToLocalChecked(); }
diff --git a/cobalt/script/v8c/v8c_array_buffer.h b/cobalt/script/v8c/v8c_array_buffer.h index 17d468c..e1d1212 100644 --- a/cobalt/script/v8c/v8c_array_buffer.h +++ b/cobalt/script/v8c/v8c_array_buffer.h
@@ -36,7 +36,7 @@ V8cArrayBuffer() = default; V8cArrayBuffer(v8::Isolate* isolate, v8::Local<v8::Value> value) - : isolate_(isolate), ScopedPersistent(isolate, value) { + : ScopedPersistent(isolate, value), isolate_(isolate) { DCHECK(value->IsArrayBuffer()); } @@ -95,8 +95,7 @@ return; } - *out_array_buffer = - std::move(V8cUserObjectHolder<V8cArrayBuffer>(isolate, value)); + *out_array_buffer = V8cUserObjectHolder<V8cArrayBuffer>(isolate, value); } } // namespace v8c
diff --git a/cobalt/script/v8c/v8c_array_buffer_view.h b/cobalt/script/v8c/v8c_array_buffer_view.h index caaf6a2..0c00986 100644 --- a/cobalt/script/v8c/v8c_array_buffer_view.h +++ b/cobalt/script/v8c/v8c_array_buffer_view.h
@@ -36,7 +36,7 @@ // Default constructor should only be used by bindings code. V8cArrayBufferView() = default; V8cArrayBufferView(v8::Isolate* isolate, v8::Local<v8::Value> value) - : isolate_(isolate), ScopedPersistent(isolate, value) { + : ScopedPersistent(isolate, value), isolate_(isolate) { DCHECK(value->IsArrayBufferView()); } @@ -111,7 +111,7 @@ } *out_array_buffer_view = - std::move(V8cUserObjectHolder<V8cArrayBufferView>(isolate, value)); + V8cUserObjectHolder<V8cArrayBufferView>(isolate, value); } } // namespace v8c
diff --git a/cobalt/script/v8c/v8c_data_view.h b/cobalt/script/v8c/v8c_data_view.h index 0a0ae84..d8f56ee 100644 --- a/cobalt/script/v8c/v8c_data_view.h +++ b/cobalt/script/v8c/v8c_data_view.h
@@ -35,7 +35,7 @@ // Default constructor should only be used by bindings code. V8cDataView() = default; V8cDataView(v8::Isolate* isolate, v8::Local<v8::Value> value) - : isolate_(isolate), ScopedPersistent(isolate, value) { + : ScopedPersistent(isolate, value), isolate_(isolate) { DCHECK(value->IsDataView()); } @@ -110,8 +110,7 @@ return; } - *out_array_buffer_view = - std::move(V8cUserObjectHolder<V8cDataView>(isolate, value)); + *out_array_buffer_view = V8cUserObjectHolder<V8cDataView>(isolate, value); } } // namespace v8c
diff --git a/cobalt/script/v8c/v8c_typed_arrays.h b/cobalt/script/v8c/v8c_typed_arrays.h index e8c9474..82e7509 100644 --- a/cobalt/script/v8c/v8c_typed_arrays.h +++ b/cobalt/script/v8c/v8c_typed_arrays.h
@@ -37,7 +37,7 @@ // Default constructor should only be used by bindings code. V8cTypedArray() = default; V8cTypedArray(v8::Isolate* isolate, v8::Local<v8::Value> value) - : isolate_(isolate), ScopedPersistent(isolate, value) { + : ScopedPersistent(isolate, value), isolate_(isolate) { DCHECK(value->IsTypedArray()); } @@ -115,8 +115,8 @@ return; } - *out_typed_array = std::move( - V8cUserObjectHolder<V8cTypedArray>(isolate, value.As<v8::TypedArray>())); + *out_typed_array = + V8cUserObjectHolder<V8cTypedArray>(isolate, value.As<v8::TypedArray>()); } template <typename CType, typename BaseTypeName, typename V8Type, @@ -129,7 +129,7 @@ // Default constructor should only be used by bindings code. V8cTypedArrayImpl() = default; V8cTypedArrayImpl(v8::Isolate* isolate, v8::Local<v8::Value> value) - : isolate_(isolate), ScopedPersistent(isolate, value) { + : ScopedPersistent(isolate, value), isolate_(isolate) { DCHECK(((**value).*(V8ValueIsTypeFunction))()); } @@ -178,42 +178,42 @@ COBALT_SCRIPT_TYPED_ARRAY_LIST(COBALT_SCRIPT_USING_V8C_ARRAY) #undef COBALT_SCRIPT_USING_V8C_ARRAY -#define COBALT_SCRIPT_CONVERSION_BOILERPLATE(array, ctype) \ - template <> \ - struct TypeTraits<array> { \ - using ConversionType = V8cUserObjectHolder<V8c##array>; \ - using ReturnType = const ScriptValue<array>*; \ - }; \ - \ - inline void ToJSValue(v8::Isolate* isolate, \ - const ScriptValue<array>* array_value, \ - v8::Local<v8::Value>* out_value) { \ - if (!array_value) { \ - *out_value = v8::Null(isolate); \ - return; \ - } \ - const auto* v8c_array_value = \ - base::polymorphic_downcast<const V8cUserObjectHolder<V8c##array>*>( \ - array_value); \ - *out_value = v8c_array_value->v8_value(); \ - } \ - \ - inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value, \ - int conversion_flags, \ - ExceptionState* exception_state, \ - V8cUserObjectHolder<V8c##array>* out_array) { \ - DCHECK_EQ(0, conversion_flags); \ - DCHECK(out_array); \ - if (!value->IsObject()) { \ - exception_state->SetSimpleException(kNotObjectType); \ - return; \ - } \ - if (!value->Is##array()) { \ - exception_state->SetSimpleException(kTypeError, \ - "Expected object of type array"); \ - return; \ - } \ - *out_array = std::move(V8cUserObjectHolder<V8c##array>(isolate, value)); \ +#define COBALT_SCRIPT_CONVERSION_BOILERPLATE(array, ctype) \ + template <> \ + struct TypeTraits<array> { \ + using ConversionType = V8cUserObjectHolder<V8c##array>; \ + using ReturnType = const ScriptValue<array>*; \ + }; \ + \ + inline void ToJSValue(v8::Isolate* isolate, \ + const ScriptValue<array>* array_value, \ + v8::Local<v8::Value>* out_value) { \ + if (!array_value) { \ + *out_value = v8::Null(isolate); \ + return; \ + } \ + const auto* v8c_array_value = \ + base::polymorphic_downcast<const V8cUserObjectHolder<V8c##array>*>( \ + array_value); \ + *out_value = v8c_array_value->v8_value(); \ + } \ + \ + inline void FromJSValue(v8::Isolate* isolate, v8::Local<v8::Value> value, \ + int conversion_flags, \ + ExceptionState* exception_state, \ + V8cUserObjectHolder<V8c##array>* out_array) { \ + DCHECK_EQ(0, conversion_flags); \ + DCHECK(out_array); \ + if (!value->IsObject()) { \ + exception_state->SetSimpleException(kNotObjectType); \ + return; \ + } \ + if (!value->Is##array()) { \ + exception_state->SetSimpleException(kTypeError, \ + "Expected object of type array"); \ + return; \ + } \ + *out_array = V8cUserObjectHolder<V8c##array>(isolate, value); \ } COBALT_SCRIPT_TYPED_ARRAY_LIST(COBALT_SCRIPT_CONVERSION_BOILERPLATE) #undef COBALT_SCRIPT_CONVERSION_BOILERPLATE
diff --git a/cobalt/site/docs/development/setup-android.md b/cobalt/site/docs/development/setup-android.md index 2c8bdb5..0382b42 100644 --- a/cobalt/site/docs/development/setup-android.md +++ b/cobalt/site/docs/development/setup-android.md
@@ -17,6 +17,15 @@ 1. Download and install [Android Studio](https://developer.android.com/studio/). +1. To enable parallel gradle builds, add the following to your `~/.bashrc`: + + ``` + export COBALT_GRADLE_BUILD_COUNT=4 + ``` + + 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 @@ -214,6 +223,15 @@ instead of 'cobalt'. Then you can set breakpoints, etc. in the test the same as when debugging Cobalt. +## Debugging (Terminal) + +Use `adb logcat` while Cobalt is running, or use `adb bugreport` shortly after +exiting to view Android logs. You will need to filter or search for +Cobalt-related output. + +As with the Linux build, use the `debug`, `devel`, or `qa` configs to trace +Cobalt's callstacks. + ## Removing the Cobalt Android Environment 1. Unset ANDROID_HOME and or ANDROID_NDK_HOME in your shell and in .bashrc
diff --git a/cobalt/site/docs/development/setup-linux.md b/cobalt/site/docs/development/setup-linux.md index 8f570d6..190cac0 100644 --- a/cobalt/site/docs/development/setup-linux.md +++ b/cobalt/site/docs/development/setup-linux.md
@@ -186,6 +186,14 @@ </tr> </table> +## Debugging Cobalt + +`debug`, `devel`, and `qa` configs of Cobalt expose a feature enabling +developers to trace Cobalt's callstacks per-thread. This is not only a great way +to debug application performance, but also a great way to debug issues and +better understand Cobalt's execution flow in general. + +Simply build and run one of these configs and observe the terminal output. <!-- <aside class="note"> <b>Note:</b> If you plan to upload reviews to the Cobalt repository, you
diff --git a/cobalt/updater/BUILD.gn b/cobalt/updater/BUILD.gn index da5cd31..94e7ae6 100644 --- a/cobalt/updater/BUILD.gn +++ b/cobalt/updater/BUILD.gn
@@ -100,9 +100,11 @@ target(gtest_target_type, "updater_test") { testonly = true + has_pedantic_warnings = true sources = [ "//starboard/common/test_main.cc", + "configurator_test.cc", "utils_test.cc", ]
diff --git a/cobalt/updater/configurator.cc b/cobalt/updater/configurator.cc index 033152a..3383817 100644 --- a/cobalt/updater/configurator.cc +++ b/cobalt/updater/configurator.cc
@@ -32,6 +32,8 @@ const int kDelayOneMinute = 60; const int kDelayOneHour = kDelayOneMinute * 60; const char kDefaultUpdaterChannel[] = "prod"; +const char kOmahaCobaltTrunkAppID[] = "{A9557415-DDCD-4948-8113-C643EFCF710C}"; +const char kOmahaCobaltAppID[] = "{6D4E53F3-CC64-4CB8-B6BD-AB0B8F300E1C}"; std::string GetDeviceProperty(SbSystemPropertyId id) { const size_t kSystemPropertyMaxLength = 1024; @@ -221,9 +223,17 @@ std::vector<uint8_t> Configurator::GetRunActionKeyHash() const { return {}; } +std::string Configurator::GetAppGuidHelper(const std::string& version) { + if (version.find(".lts.") != std::string::npos && + version.find(".master.") == std::string::npos) { + return kOmahaCobaltAppID; + } + return kOmahaCobaltTrunkAppID; +} + std::string Configurator::GetAppGuid() const { - // Omaha console app id for trunk - return "{A9557415-DDCD-4948-8113-C643EFCF710C}"; + const std::string version(COBALT_VERSION); + return GetAppGuidHelper(version); } std::unique_ptr<update_client::ProtocolHandlerFactory>
diff --git a/cobalt/updater/configurator.h b/cobalt/updater/configurator.h index 630861a..992f176 100644 --- a/cobalt/updater/configurator.h +++ b/cobalt/updater/configurator.h
@@ -101,6 +101,8 @@ bool GetUseCompressedUpdates() const override; void SetUseCompressedUpdates(bool use_compressed_updates) override; + // Added for testing purposes. + static std::string GetAppGuidHelper(const std::string&); private: friend class base::RefCountedThreadSafe<Configurator>;
diff --git a/cobalt/updater/configurator_test.cc b/cobalt/updater/configurator_test.cc new file mode 100644 index 0000000..cba7ccf --- /dev/null +++ b/cobalt/updater/configurator_test.cc
@@ -0,0 +1,58 @@ +// Copyright 2022 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/updater/configurator.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +const char kOmahaCobaltTrunkAppID[] = "{A9557415-DDCD-4948-8113-C643EFCF710C}"; +const char kOmahaCobaltAppID[] = "{6D4E53F3-CC64-4CB8-B6BD-AB0B8F300E1C}"; +} // namespace + +namespace cobalt { +namespace updater { + +class ConfiguratorTest : public testing::Test { + protected: + ConfiguratorTest() {} + ~ConfiguratorTest() {} +}; + +TEST_F(ConfiguratorTest, GetAppGuidReturnsTrunkIdWithVersionMaster) { + CHECK_EQ(cobalt::updater::Configurator::GetAppGuidHelper("23.master.0"), + kOmahaCobaltTrunkAppID); +} + +TEST_F(ConfiguratorTest, GetAppGuidReturnsTrunkIdWithVersionMain) { + CHECK_EQ(cobalt::updater::Configurator::GetAppGuidHelper("23.main.0"), + kOmahaCobaltTrunkAppID); +} + +TEST_F(ConfiguratorTest, GetAppGuidReturnsProdIdWithVersionLts) { + CHECK_EQ(cobalt::updater::Configurator::GetAppGuidHelper("23.lts.0"), + kOmahaCobaltAppID); +} + +TEST_F(ConfiguratorTest, GetAppGuidReturnsTrunkIdWithVersionEmpty) { + CHECK_EQ(cobalt::updater::Configurator::GetAppGuidHelper(""), + kOmahaCobaltTrunkAppID); +} + +TEST_F(ConfiguratorTest, GetAppGuidReturnsTrunkIdWithVersionMasterLts) { + CHECK_EQ(cobalt::updater::Configurator::GetAppGuidHelper("23.master.lts.0"), + kOmahaCobaltTrunkAppID); +} + +} // namespace updater +} // namespace cobalt
diff --git a/cobalt/web/agent.cc b/cobalt/web/agent.cc index f52e113..f44a345 100644 --- a/cobalt/web/agent.cc +++ b/cobalt/web/agent.cc
@@ -19,6 +19,7 @@ #include <utility> #include "base/observer_list.h" +#include "base/threading/thread_checker.h" #include "base/trace_event/trace_event.h" #include "cobalt/loader/fetcher_factory.h" #include "cobalt/loader/script_loader_factory.h" @@ -49,7 +50,7 @@ namespace { class Impl : public Context { public: - explicit Impl(const Agent::Options& options); + Impl(const std::string& name, const Agent::Options& options); virtual ~Impl(); void AddEnvironmentSettingsChangeObserver( @@ -222,7 +223,8 @@ environment_settings_change_observers_; }; -Impl::Impl(const Agent::Options& options) : name_(options.name) { +Impl::Impl(const std::string& name, const Agent::Options& options) + : name_(name) { TRACE_EVENT0("cobalt::web", "Agent::Impl::Impl()"); service_worker_jobs_ = options.service_worker_jobs; platform_info_ = options.platform_info; @@ -235,7 +237,7 @@ DCHECK(fetcher_factory_); script_loader_factory_.reset(new loader::ScriptLoaderFactory( - options.name.c_str(), fetcher_factory_.get(), options.thread_priority)); + name.c_str(), fetcher_factory_.get(), options.thread_priority)); DCHECK(script_loader_factory_); javascript_engine_ = @@ -469,9 +471,31 @@ void Agent::WillDestroyCurrentMessageLoop() { context_.reset(); } -Agent::Agent(const Options& options, InitializeCallback initialize_callback, - DestructionObserver* destruction_observer) - : thread_(options.name) { +Agent::Agent(const std::string& name) : thread_(name) {} + +void Agent::Stop() { + DCHECK(message_loop()); + DCHECK(thread_.IsRunning()); + + if (context() && context()->service_worker_jobs()) { + context()->service_worker_jobs()->UnregisterWebContext(context()); + } + + // Ensure that the destruction observer got added before stopping the thread. + destruction_observer_added_.Wait(); + // Stop the thread. This will cause the destruction observer to be notified. + thread_.Stop(); +} + +Agent::~Agent() { + DCHECK(!thread_.IsRunning()); + if (thread_.IsRunning()) { + Stop(); + } +} + +void Agent::Run(const Options& options, InitializeCallback initialize_callback, + DestructionObserver* destruction_observer) { // Start the dedicated thread and create the internal implementation // object on that thread. base::Thread::Options thread_options(base::MessageLoop::TYPE_DEFAULT, @@ -481,8 +505,9 @@ DCHECK(message_loop()); message_loop()->task_runner()->PostTask( - FROM_HERE, base::Bind(&Agent::Initialize, base::Unretained(this), options, - initialize_callback)); + FROM_HERE, + base::Bind(&Agent::InitializeTaskInThread, base::Unretained(this), + options, initialize_callback)); if (destruction_observer) { message_loop()->task_runner()->PostTask( @@ -507,30 +532,17 @@ base::Unretained(&destruction_observer_added_))); } -Agent::~Agent() { - DCHECK(message_loop()); - DCHECK(thread_.IsRunning()); - - if (context() && context()->service_worker_jobs()) { - context()->service_worker_jobs()->UnregisterWebContext(context()); - } - - // Ensure that the destruction observer got added before stopping the thread. - destruction_observer_added_.Wait(); - // Stop the thread. This will cause the destruction observer to be notified. - thread_.Stop(); -} - -void Agent::Initialize(const Options& options, - InitializeCallback initialize_callback) { +void Agent::InitializeTaskInThread(const Options& options, + InitializeCallback initialize_callback) { DCHECK_EQ(base::MessageLoop::current(), message_loop()); - context_.reset(CreateContext(options, thread_.message_loop())); + context_.reset( + CreateContext(thread_.thread_name(), options, thread_.message_loop())); initialize_callback.Run(context_.get()); } -Context* Agent::CreateContext(const Options& options, +Context* Agent::CreateContext(const std::string& name, const Options& options, base::MessageLoop* message_loop) { - auto* context = new Impl(options); + auto* context = new Impl(name, options); context->set_message_loop(message_loop); if (options.service_worker_jobs) { options.service_worker_jobs->RegisterWebContext(context);
diff --git a/cobalt/web/agent.h b/cobalt/web/agent.h index 956a6f6..aa48bb1 100644 --- a/cobalt/web/agent.h +++ b/cobalt/web/agent.h
@@ -40,19 +40,12 @@ class Agent : public base::MessageLoop::DestructionObserver { public: struct Options { - explicit Options(const std::string name) : name(name) {} typedef base::Callback<scoped_refptr<script::Wrappable>( - script::EnvironmentSettings*)> + web::EnvironmentSettings*)> CreateObjectFunction; typedef base::hash_map<std::string, CreateObjectFunction> InjectedGlobalObjectAttributes; - // The name of the Web Agent. This is useful for debugging purposes as - // in the case where multiple Web Agent objects exist, it can be used to - // differentiate which objects belong to which Web Agent. It is used - // to name some CVals. - std::string name; - // Specifies the priority of the web agent's thread. This is the thread // that is responsible for executing JavaScript. base::ThreadPriority thread_priority = base::ThreadPriority::NORMAL; @@ -83,14 +76,17 @@ JavaScriptHeapStatisticsCallback; typedef base::Callback<void(Context*)> InitializeCallback; - Agent(const Options& options, InitializeCallback initialize_callback, - DestructionObserver* destruction_observer = nullptr); + explicit Agent(const std::string& name); ~Agent(); - static Context* CreateContext(const Options& options, + void Run(const Options& options, InitializeCallback initialize_callback, + DestructionObserver* destruction_observer = nullptr); + void Stop(); + + static Context* CreateContext(const std::string& name, const Options& options, base::MessageLoop* message_loop = nullptr); static Context* CreateContext(const std::string& name) { - return CreateContext(Options(name)); + return CreateContext(name, Options()); } Context* context() { @@ -118,8 +114,8 @@ private: // Called by the constructor to create the private implementation object and // perform any other initialization required on the dedicated thread. - void Initialize(const Options& options, - InitializeCallback initialize_callback); + void InitializeTaskInThread(const Options& options, + InitializeCallback initialize_callback); // The thread created and owned by this Web Agent. // All sub-objects of this object are created on this thread, and all public
diff --git a/cobalt/web/blob_test.cc b/cobalt/web/blob_test.cc index f3cb1b3..6ddc919 100644 --- a/cobalt/web/blob_test.cc +++ b/cobalt/web/blob_test.cc
@@ -206,7 +206,7 @@ INSTANTIATE_TEST_CASE_P( BlobTestsWithJavaScript, BlobTestWithJavaScript, - ::testing::ValuesIn(testing::TestWebWithJavaScript::GetWorkerTypes()), + ::testing::ValuesIn(testing::TestWebWithJavaScript::GetWebTypes()), testing::TestWebWithJavaScript::GetTypeName);
diff --git a/cobalt/web/csp_violation_reporter.cc b/cobalt/web/csp_violation_reporter.cc index 2cb1951..63d2cbd 100644 --- a/cobalt/web/csp_violation_reporter.cc +++ b/cobalt/web/csp_violation_reporter.cc
@@ -134,22 +134,16 @@ ViolationEvent violation_data; GatherSecurityPolicyViolationEventData(global_, violation_info, &violation_data); + EventTarget* target = global_; if (global_->IsWindow()) { - global_->AsWindow()->document()->DispatchEvent( - new SecurityPolicyViolationEvent( - violation_data.document_uri, violation_data.referrer, - violation_data.blocked_uri, violation_data.violated_directive, - violation_data.effective_directive, violation_data.original_policy, - violation_data.source_file, violation_data.status_code, - violation_data.line_number, violation_data.column_number)); - } else { - global_->DispatchEvent(new SecurityPolicyViolationEvent( - violation_data.document_uri, violation_data.referrer, - violation_data.blocked_uri, violation_data.violated_directive, - violation_data.effective_directive, violation_data.original_policy, - violation_data.source_file, violation_data.status_code, - violation_data.line_number, violation_data.column_number)); + target = global_->AsWindow()->document(); } + target->DispatchEvent(new SecurityPolicyViolationEvent( + violation_data.document_uri, violation_data.referrer, + violation_data.blocked_uri, violation_data.violated_directive, + violation_data.effective_directive, violation_data.original_policy, + violation_data.source_file, violation_data.status_code, + violation_data.line_number, violation_data.column_number)); if (violation_info.endpoints.empty() || post_sender_.is_null()) { return;
diff --git a/cobalt/web/custom_event_test.cc b/cobalt/web/custom_event_test.cc index 9bf87ae..5d1bded 100644 --- a/cobalt/web/custom_event_test.cc +++ b/cobalt/web/custom_event_test.cc
@@ -109,7 +109,7 @@ INSTANTIATE_TEST_CASE_P( CustomEventTestsWithJavaScript, CustomEventTestWithJavaScript, - ::testing::ValuesIn(testing::TestWebWithJavaScript::GetWorkerTypes()), + ::testing::ValuesIn(testing::TestWebWithJavaScript::GetWebTypes()), testing::TestWebWithJavaScript::GetTypeName); } // namespace web
diff --git a/cobalt/web/message_event.cc b/cobalt/web/message_event.cc index a6e8888..b38a1fe 100644 --- a/cobalt/web/message_event.cc +++ b/cobalt/web/message_event.cc
@@ -29,17 +29,36 @@ #include "starboard/memory.h" #include "v8/include/v8.h" +namespace cobalt { +namespace web { + namespace { const char* const kResponseTypes[] = {"text", "blob", "arraybuffer", "any"}; -COMPILE_ASSERT(arraysize(kResponseTypes) == - cobalt::web::MessageEvent::kResponseTypeMax, +COMPILE_ASSERT(arraysize(kResponseTypes) == MessageEvent::kResponseTypeMax, enum_and_array_size_mismatch); } // namespace -namespace cobalt { -namespace web { +MessageEvent::MessageEvent(const std::string& type, + const MessageEventInit& init_dict) + : Event(type, init_dict), response_type_(kAny) { + if (init_dict.has_data() && init_dict.data()) { + data_ = script::SerializeScriptValue(*(init_dict.data())); + } + if (init_dict.has_origin()) { + origin_ = init_dict.origin(); + } + if (init_dict.has_last_event_id()) { + last_event_id_ = init_dict.last_event_id(); + } + if (init_dict.has_source()) { + source_ = init_dict.source(); + } + if (init_dict.has_ports()) { + ports_ = init_dict.ports(); + } +} // static std::string MessageEvent::GetResponseTypeAsString( @@ -63,7 +82,7 @@ MessageEvent::Response MessageEvent::data( script::EnvironmentSettings* settings) const { if (!data_ && !data_io_buffer_) { - return Response(""); + return Response(script::Handle<script::ValueHandle>()); } script::GlobalEnvironment* global_environment = nullptr; @@ -71,7 +90,7 @@ response_type_ == kAny) { DCHECK(settings); global_environment = - base::polymorphic_downcast<web::EnvironmentSettings*>(settings) + base::polymorphic_downcast<EnvironmentSettings*>(settings) ->context() ->global_environment(); DCHECK(global_environment); @@ -92,8 +111,7 @@ std::move(buffer_copy); if (response_type_ == kBlob) { DCHECK(settings); - scoped_refptr<web::Blob> blob = - new web::Blob(settings, response_buffer); + scoped_refptr<Blob> blob = new Blob(settings, response_buffer); return Response(blob); } return Response(response_buffer); @@ -101,12 +119,14 @@ case kAny: { v8::Isolate* isolate = global_environment->isolate(); script::v8c::EntryScope entry_scope(isolate); + DCHECK(isolate); + DCHECK(data_); return Response(script::Handle<script::ValueHandle>( std::move(script::DeserializeScriptValue(isolate, *data_)))); } default: NOTREACHED() << "Invalid response type."; - return Response(""); + return Response(script::Handle<script::ValueHandle>()); } }
diff --git a/cobalt/web/message_event.h b/cobalt/web/message_event.h index b39a198..ba81c1f 100644 --- a/cobalt/web/message_event.h +++ b/cobalt/web/message_event.h
@@ -20,28 +20,32 @@ #include <string> #include <utility> -#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" #include "base/strings/string_piece.h" #include "cobalt/base/token.h" #include "cobalt/script/array_buffer.h" +#include "cobalt/script/sequence.h" #include "cobalt/script/union_type.h" -#include "cobalt/script/v8c/v8c_value_handle.h" -#include "cobalt/script/wrappable.h" +#include "cobalt/script/value_handle.h" #include "cobalt/web/blob.h" #include "cobalt/web/event.h" +#include "cobalt/web/event_target.h" #include "cobalt/web/message_event_init.h" +#include "cobalt/web/message_port.h" #include "net/base/io_buffer.h" #include "v8/include/v8.h" namespace cobalt { namespace web { -class MessageEvent : public web::Event { +class MessageEvent : public Event { public: - typedef script::UnionType4<std::string, scoped_refptr<web::Blob>, + typedef script::UnionType4<std::string, scoped_refptr<Blob>, script::Handle<script::ArrayBuffer>, script::Handle<script::ValueHandle>> Response; + + // These response types are ordered in the likelihood of being used. // Keeping them in expected order will help make code faster. enum ResponseType { kText, kBlob, kArrayBuffer, kAny, kResponseTypeMax }; @@ -56,14 +60,26 @@ MessageEvent(base::Token type, ResponseType response_type, const scoped_refptr<net::IOBufferWithSize>& data) : Event(type), response_type_(response_type), data_io_buffer_(data) {} - MessageEvent(const std::string& type, const web::MessageEventInit& init_dict) - : Event(type, init_dict), - response_type_(kAny), - data_(script::SerializeScriptValue(*(init_dict.data()))) {} + MessageEvent(const std::string& type, const MessageEventInit& init_dict); Response data(script::EnvironmentSettings* settings = nullptr) const; + const std::string& origin() const { return origin_; } + const std::string& last_event_id() const { return last_event_id_; } + const scoped_refptr<EventTarget>& source() const { return source_; } + script::Sequence<scoped_refptr<MessagePort>> ports() const { return ports_; } // These helper functions are custom, and not in any spec. + void set_origin(const std::string& origin) { origin_ = origin; } + void set_last_event_id(const std::string& last_event_id) { + last_event_id_ = last_event_id; + } + void set_source(const scoped_refptr<EventTarget>& source) { + source_ = source; + } + void set_ports(script::Sequence<scoped_refptr<MessagePort>> ports) { + ports_ = ports; + } + static std::string GetResponseTypeAsString(const ResponseType response_type); static MessageEvent::ResponseType GetResponseType(base::StringPiece to_match); @@ -73,6 +89,10 @@ ResponseType response_type_ = kText; scoped_refptr<net::IOBufferWithSize> data_io_buffer_; std::unique_ptr<script::DataBuffer> data_; + std::string origin_; + std::string last_event_id_; + scoped_refptr<EventTarget> source_; + script::Sequence<scoped_refptr<MessagePort>> ports_; }; } // namespace web
diff --git a/cobalt/web/message_event.idl b/cobalt/web/message_event.idl index 0e15ab7..909fb66 100644 --- a/cobalt/web/message_event.idl +++ b/cobalt/web/message_event.idl
@@ -20,4 +20,9 @@ Constructor(DOMString type, optional MessageEventInit eventInitDict) ] interface MessageEvent : Event { [CallWith = EnvironmentSettings] readonly attribute any data; + readonly attribute USVString origin; + readonly attribute DOMString lastEventId; + readonly attribute EventTarget? source; + // TODO(b/236750294): Make this be FrozenArray<MessagePort> when available. + readonly attribute sequence<MessagePort> ports; };
diff --git a/cobalt/web/message_event_init.idl b/cobalt/web/message_event_init.idl index 9ccf914..edf7e7c 100644 --- a/cobalt/web/message_event_init.idl +++ b/cobalt/web/message_event_init.idl
@@ -12,8 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// https://www.w3.org/TR/html50/webappapis.html#erroreventinit +// https://html.spec.whatwg.org/multipage/comms.html#messageeventinit dictionary MessageEventInit : EventInit { - any data = null; + any data; + USVString origin = ""; + DOMString lastEventId = ""; + EventTarget? source; + sequence<MessagePort> ports; };
diff --git a/cobalt/web/message_event_test.cc b/cobalt/web/message_event_test.cc index d8f6d6d..93893b2 100644 --- a/cobalt/web/message_event_test.cc +++ b/cobalt/web/message_event_test.cc
@@ -19,11 +19,14 @@ #include "base/bind.h" #include "base/logging.h" -#include "cobalt/dom/testing/test_with_javascript.h" +#include "base/memory/scoped_refptr.h" #include "cobalt/script/v8c/entry_scope.h" #include "cobalt/script/value_handle.h" +#include "cobalt/web/blob.h" #include "cobalt/web/message_event_init.h" #include "cobalt/web/testing/gtest_workarounds.h" +#include "cobalt/web/testing/test_with_javascript.h" +#include "net/base/io_buffer.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -31,8 +34,7 @@ namespace web { namespace { -class MessageEventTestWithJavaScript : public dom::testing::TestWithJavaScript { -}; +class MessageEventTestWithJavaScript : public testing::TestWebWithJavaScript {}; } // namespace TEST(MessageEventTest, ConstructorWithEventTypeString) { @@ -49,19 +51,44 @@ EXPECT_FALSE(event->propagation_stopped()); EXPECT_FALSE(event->immediate_propagation_stopped()); MessageEvent::Response event_data = event->data(); - EXPECT_TRUE(event_data.IsType<std::string>()); - EXPECT_EQ("", event_data.AsType<std::string>()); + EXPECT_TRUE(event_data.IsType<script::Handle<script::ValueHandle>>()); + EXPECT_TRUE( + event_data.AsType<script::Handle<script::ValueHandle>>().IsEmpty()); } -TEST_F(MessageEventTestWithJavaScript, - ConstructorWithEventTypeAndDefaultInitDict) { - MessageEventInit init; - base::Optional<script::ValueHandleHolder::Reference> reference; - EvaluateScript("'data_value'", window(), &reference); - init.set_data(&(reference->referenced_value())); - scoped_refptr<MessageEvent> event = new MessageEvent("mytestevent", init); +TEST(MessageEventTest, ConstructorWithText) { + std::string message_string("ConstructorWithTextMessageData"); + scoped_refptr<net::IOBufferWithSize> data = + base::MakeRefCounted<net::IOBufferWithSize>(message_string.size()); + memcpy(data->data(), message_string.c_str(), message_string.size()); + scoped_refptr<MessageEvent> event = + new MessageEvent(base::Tokens::message(), MessageEvent::kText, data); - EXPECT_EQ("mytestevent", event->type()); + EXPECT_EQ("message", event->type()); + EXPECT_EQ(NULL, event->target().get()); + EXPECT_EQ(NULL, event->current_target().get()); + EXPECT_EQ(Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + MessageEvent::Response event_data = event->data(); + EXPECT_TRUE(event_data.IsType<std::string>()); + EXPECT_EQ(message_string.size(), event_data.AsType<std::string>().size()); + EXPECT_EQ("ConstructorWithTextMessageData", event_data.AsType<std::string>()); +} + +TEST_P(MessageEventTestWithJavaScript, ConstructorWithBlob) { + std::string message_string("ConstructorWithBlobMessageData"); + scoped_refptr<net::IOBufferWithSize> data = + base::MakeRefCounted<net::IOBufferWithSize>(message_string.size()); + memcpy(data->data(), message_string.c_str(), message_string.size()); + scoped_refptr<MessageEvent> event = + new MessageEvent(base::Tokens::message(), MessageEvent::kBlob, data); + + EXPECT_EQ("message", event->type()); EXPECT_EQ(NULL, event->target().get()); EXPECT_EQ(NULL, event->current_target().get()); EXPECT_EQ(Event::kNone, event->event_phase()); @@ -72,7 +99,139 @@ EXPECT_FALSE(event->propagation_stopped()); EXPECT_FALSE(event->immediate_propagation_stopped()); MessageEvent::Response event_data = - event->data(window()->environment_settings()); + event->data(web_context()->environment_settings()); + EXPECT_TRUE(event_data.IsType<scoped_refptr<Blob>>()); + EXPECT_EQ(message_string.size(), + event_data.AsType<scoped_refptr<Blob>>()->size()); + EXPECT_EQ("ConstructorWithBlobMessageData", + std::string(reinterpret_cast<const char*>( + event_data.AsType<scoped_refptr<Blob>>()->data()), + static_cast<size_t>( + event_data.AsType<scoped_refptr<Blob>>()->size()))); + EXPECT_TRUE(event_data.AsType<scoped_refptr<Blob>>()->type().empty()); +} + +TEST_P(MessageEventTestWithJavaScript, ConstructorWithArrayBuffer) { + std::string message_string("ConstructorWithArrayBufferMessageData"); + scoped_refptr<net::IOBufferWithSize> data = + base::MakeRefCounted<net::IOBufferWithSize>(message_string.size()); + memcpy(data->data(), message_string.c_str(), message_string.size()); + scoped_refptr<MessageEvent> event = new MessageEvent( + base::Tokens::message(), MessageEvent::kArrayBuffer, data); + + EXPECT_EQ("message", event->type()); + EXPECT_EQ(NULL, event->target().get()); + EXPECT_EQ(NULL, event->current_target().get()); + EXPECT_EQ(Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + MessageEvent::Response event_data = + event->data(web_context()->environment_settings()); + EXPECT_TRUE(event_data.IsType<script::Handle<script::ArrayBuffer>>()); + EXPECT_EQ( + message_string.size(), + event_data.AsType<script::Handle<script::ArrayBuffer>>()->ByteLength()); + EXPECT_EQ( + "ConstructorWithArrayBufferMessageData", + std::string( + reinterpret_cast<const char*>( + event_data.AsType<script::Handle<script::ArrayBuffer>>()->Data()), + static_cast<size_t>( + event_data.AsType<script::Handle<script::ArrayBuffer>>() + ->ByteLength()))); +} + +TEST_P(MessageEventTestWithJavaScript, ConstructorWithAny) { + base::Optional<script::ValueHandleHolder::Reference> reference; + EvaluateScript("'ConstructorWithAnyMessageData'", &reference); + std::unique_ptr<script::DataBuffer> data( + script::SerializeScriptValue(reference->referenced_value())); + EXPECT_NE(nullptr, data.get()); + EXPECT_NE(nullptr, data->ptr); + EXPECT_GT(data->size, 0U); + scoped_refptr<MessageEvent> event = + new MessageEvent(base::Tokens::message(), std::move(data)); + + EXPECT_EQ("message", event->type()); + EXPECT_EQ(NULL, event->target().get()); + EXPECT_EQ(NULL, event->current_target().get()); + EXPECT_EQ(Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + MessageEvent::Response event_data = + event->data(web_context()->environment_settings()); + EXPECT_TRUE(event_data.IsType<script::Handle<script::ValueHandle>>()); + EXPECT_FALSE( + event_data.AsType<script::Handle<script::ValueHandle>>().IsEmpty()); + auto script_value = + event_data.AsType<script::Handle<script::ValueHandle>>().GetScriptValue(); + auto* isolate = script::GetIsolate(*script_value); + script::v8c::EntryScope entry_scope(isolate); + v8::Local<v8::Value> v8_value = script::GetV8Value(*script_value); + std::string actual = + *(v8::String::Utf8Value(isolate, v8_value.As<v8::String>())); + EXPECT_EQ("ConstructorWithAnyMessageData", actual); +} + +TEST_P(MessageEventTestWithJavaScript, + ConstructorWithEventTypeAndDefaultInitDict) { + MessageEventInit init; + scoped_refptr<MessageEvent> event = new MessageEvent("mytestevent", init); + + EXPECT_EQ("mytestevent", event->type()); + EXPECT_EQ(nullptr, event->target().get()); + EXPECT_EQ(nullptr, event->current_target().get()); + EXPECT_EQ(Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + + MessageEvent::Response event_data = + event->data(web_context()->environment_settings()); + EXPECT_TRUE(event_data.IsType<script::Handle<script::ValueHandle>>()); + EXPECT_TRUE( + event_data.AsType<script::Handle<script::ValueHandle>>().IsEmpty()); + + EXPECT_TRUE(event->origin().empty()); + EXPECT_TRUE(event->last_event_id().empty()); + EXPECT_EQ(nullptr, event->source().get()); + EXPECT_TRUE(event->ports().empty()); +} + +TEST_P(MessageEventTestWithJavaScript, ConstructorWithEventTypeAndInitDict) { + MessageEventInit init; + base::Optional<script::ValueHandleHolder::Reference> reference; + EvaluateScript("'data_value'", &reference); + init.set_data(&(reference->referenced_value())); + init.set_origin("OriginString"); + init.set_last_event_id("lastEventIdString"); + init.set_source(web_context()->GetWindowOrWorkerGlobalScope()); + scoped_refptr<MessageEvent> event = new MessageEvent("mytestevent", init); + + EXPECT_EQ("mytestevent", event->type()); + EXPECT_EQ(nullptr, event->target().get()); + EXPECT_EQ(nullptr, event->current_target().get()); + EXPECT_EQ(Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + + MessageEvent::Response event_data = + event->data(web_context()->environment_settings()); EXPECT_TRUE(event_data.IsType<script::Handle<script::ValueHandle>>()); auto script_value = event_data.AsType<script::Handle<script::ValueHandle>>().GetScriptValue(); @@ -82,24 +241,44 @@ std::string actual = *(v8::String::Utf8Value(isolate, v8_value.As<v8::String>())); EXPECT_EQ("data_value", actual); + + EXPECT_EQ("OriginString", event->origin()); + EXPECT_EQ("lastEventIdString", event->last_event_id()); + EXPECT_EQ(web_context()->GetWindowOrWorkerGlobalScope(), + event->source().get()); + EXPECT_TRUE(event->ports().empty()); } -TEST_F(MessageEventTestWithJavaScript, - ConstructorWithEventTypeAndErrorInitDict) { +TEST_P(MessageEventTestWithJavaScript, + ConstructorWithEventTypeAndMessageEventInitDict) { std::string result; EXPECT_TRUE( EvaluateScript("var event = new MessageEvent('dog', " - " {'cancelable':true, " - " 'data':'data_value'});" + " {cancelable: true, " + " origin: 'OriginValue'," + " lastEventId: 'LastEventIdValue'," + " source: this," + " data: {value: 'data_value'}," + " }" + ");" "if (event.type == 'dog' &&" " event.bubbles == false &&" " event.cancelable == true &&" - " event.data == 'data_value') " - " event.data;", + " event.origin == 'OriginValue' &&" + " event.lastEventId == 'LastEventIdValue' &&" + " event.source == this &&" + " event.ports.length == 0 &&" + " event.data.value == 'data_value') " + " event.data.value;", &result)) << "Failed to evaluate script."; EXPECT_EQ("data_value", result); } +INSTANTIATE_TEST_CASE_P( + MessageEventTestsWithJavaScript, MessageEventTestWithJavaScript, + ::testing::ValuesIn(testing::TestWebWithJavaScript::GetWebTypes()), + testing::TestWebWithJavaScript::GetTypeName); + } // namespace web } // namespace cobalt
diff --git a/cobalt/web/message_port.h b/cobalt/web/message_port.h index 183e35a..9d53f49 100644 --- a/cobalt/web/message_port.h +++ b/cobalt/web/message_port.h
@@ -29,7 +29,6 @@ #include "cobalt/web/context.h" #include "cobalt/web/event_target.h" #include "cobalt/web/event_target_listener_info.h" -#include "cobalt/web/message_event.h" namespace cobalt { namespace web {
diff --git a/cobalt/web/message_port.idl b/cobalt/web/message_port.idl index 86b9528..24bab52 100644 --- a/cobalt/web/message_port.idl +++ b/cobalt/web/message_port.idl
@@ -17,7 +17,6 @@ interface MessagePort /* : EventTarget */ { // [RaisesException] void postMessage(any message); - // void postMessage(USVString message, sequence<USVString> transfer); // TODO: Support sequence<object>: b/218501774 // void postMessage(any message, sequence<object> transfer); // TODO: Support overloads with dictionary parameter: b/218506730
diff --git a/cobalt/web/testing/test_with_javascript.h b/cobalt/web/testing/test_with_javascript.h index f37276b..011ab7a 100644 --- a/cobalt/web/testing/test_with_javascript.h +++ b/cobalt/web/testing/test_with_javascript.h
@@ -23,7 +23,6 @@ #include "cobalt/dom/testing/stub_window.h" #include "cobalt/dom/window.h" #include "cobalt/script/wrappable.h" -#include "cobalt/web/window_or_worker_global_scope.h" #include "cobalt/worker/testing/test_with_javascript.h" namespace cobalt { @@ -42,17 +41,14 @@ DCHECK(!this->worker_global_scope()); this->ClearWebContext(); window_.reset(new dom::testing::StubWindow()); + window_->InitializeWindow(); } } - WindowOrWorkerGlobalScope* window_or_worker_global_scope() { - return window_ ? window_->window().get() : this->worker_global_scope(); - } - - scoped_refptr<script::GlobalEnvironment> global_environment() override { - if (window_) return window_->global_environment(); + web::Context* web_context() const override { + if (window_) return window_->web_context(); return worker::testing::TestWithJavaScriptBase< - TypeIdProvider>::global_environment(); + TypeIdProvider>::web_context(); } private: @@ -66,7 +62,7 @@ public: // Return a vector of values for all known worker types, to be used in the // INSTANTIATE_TEST_CASE_P() declaration. - static std::vector<base::TypeId> GetWorkerTypes() { + static std::vector<base::TypeId> GetWebTypes() { std::vector<base::TypeId> worker_types = worker::testing::TestWorkersWithJavaScript::GetWorkerTypes(); worker_types.push_back(base::GetTypeId<dom::Window>());
diff --git a/cobalt/web/url_test.cc b/cobalt/web/url_test.cc index ee6f405..fa0dbcc 100644 --- a/cobalt/web/url_test.cc +++ b/cobalt/web/url_test.cc
@@ -195,7 +195,7 @@ INSTANTIATE_TEST_CASE_P( URLTestsWithJavaScript, URLTestWithJavaScript, - ::testing::ValuesIn(testing::TestWebWithJavaScript::GetWorkerTypes()), + ::testing::ValuesIn(testing::TestWebWithJavaScript::GetWebTypes()), testing::TestWebWithJavaScript::GetTypeName);
diff --git a/cobalt/web/url_utils.cc b/cobalt/web/url_utils.cc index 462c6f4..c69bc2d 100644 --- a/cobalt/web/url_utils.cc +++ b/cobalt/web/url_utils.cc
@@ -126,7 +126,8 @@ // https://www.w3.org/TR/2014/WD-url-1-20141209/#pre-update-steps void URLUtils::RunPreUpdateSteps(const GURL& new_url, const std::string& value) { - DLOG(INFO) << "Update URL to " << new_url.possibly_invalid_spec(); + DLOG(INFO) << "Update URL to " + << (value.empty() ? new_url.possibly_invalid_spec() : value); // 1. If value is not given, let value be the result of serializing the // associated url.
diff --git a/cobalt/webdriver/session_driver.cc b/cobalt/webdriver/session_driver.cc index 1c45c01..b04aa70 100644 --- a/cobalt/webdriver/session_driver.cc +++ b/cobalt/webdriver/session_driver.cc
@@ -14,6 +14,8 @@ #include "cobalt/webdriver/session_driver.h" +#include <utility> + #include "base/logging.h" #include "cobalt/base/log_message_handler.h" @@ -56,13 +58,13 @@ logging_callback_id_(0) { logging_callback_id_ = base::LogMessageHandler::GetInstance()->AddCallback( base::Bind(&SessionDriver::LogMessageHandler, base::Unretained(this))); - window_driver_ = create_window_driver_callback_.Run(GetUniqueWindowId()); + RefreshWindowDriver(); } void SessionDriver::RefreshWindowDriver() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - window_driver_ = - create_window_driver_callback_.Run(window_driver_->window_id()); + window_driver_ = create_window_driver_callback_.Run( + window_driver_ ? window_driver_->window_id() : GetUniqueWindowId()); } SessionDriver::~SessionDriver() {
diff --git a/cobalt/worker/BUILD.gn b/cobalt/worker/BUILD.gn index 8c0077a..cf05426 100644 --- a/cobalt/worker/BUILD.gn +++ b/cobalt/worker/BUILD.gn
@@ -26,7 +26,9 @@ "dedicated_worker.h", "dedicated_worker_global_scope.cc", "dedicated_worker_global_scope.h", + "extendable_event.cc", "extendable_event.h", + "extendable_message_event.cc", "extendable_message_event.h", "navigation_preload_manager.cc", "navigation_preload_manager.h", @@ -80,6 +82,7 @@ sources = [ "dedicated_worker_global_scope_test.cc", + "extendable_message_event_test.cc", "service_worker_global_scope_test.cc", "worker_global_scope_test.cc", "worker_location_test.cc",
diff --git a/cobalt/worker/dedicated_worker.cc b/cobalt/worker/dedicated_worker.cc index 0dff482..1daf030 100644 --- a/cobalt/worker/dedicated_worker.cc +++ b/cobalt/worker/dedicated_worker.cc
@@ -58,7 +58,7 @@ // allow the page to start dedicated workers). // 2. Let outside settings be the current settings object. // 3. Parse the scriptURL argument relative to outside settings. - Worker::Options options(kDedicatedWorkerName); + Worker::Options options; const GURL& base_url = environment_settings()->base_url(); options.url = base_url.Resolve(script_url_); @@ -83,7 +83,7 @@ options.web_options.service_worker_jobs = options.outside_settings->context()->service_worker_jobs(); - worker_.reset(new Worker(options)); + worker_.reset(new Worker(kDedicatedWorkerName, options)); // 10. Return worker. }
diff --git a/cobalt/worker/extendable_event.cc b/cobalt/worker/extendable_event.cc new file mode 100644 index 0000000..6b49b47 --- /dev/null +++ b/cobalt/worker/extendable_event.cc
@@ -0,0 +1,83 @@ +// Copyright 2022 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/worker/extendable_event.h" + +namespace cobalt { +namespace worker { + +void ExtendableEvent::WaitUntil( + script::EnvironmentSettings* settings, + std::unique_ptr<script::Promise<script::ValueHandle*>>& promise, + script::ExceptionState* exception_state) { + // Algorithm for waitUntil(), to add lifetime promise to event. + // https://w3c.github.io/ServiceWorker/#dom-extendableevent-waituntil + + // 1. If event’s isTrusted attribute is false, throw an "InvalidStateError" + // DOMException. + // 2. If event is not active, throw an "InvalidStateError" DOMException. + if (!IsActive()) { + web::DOMException::Raise(web::DOMException::kInvalidStateErr, + exception_state); + return; + } + // 3. Add promise to event’s extend lifetime promises. + // 4. Increment event’s pending promises count by one. + ++pending_promise_count_; + // 5. Upon fulfillment or rejection of promise, queue a microtask to run + // these substeps: + std::unique_ptr<base::OnceCallback<void()>> callback( + new base::OnceCallback<void()>(std::move( + base::BindOnce(&ExtendableEvent::StateChange, base::Unretained(this), + settings, promise.get())))); + promise->AddStateChangeCallback(std::move(callback)); + promise.release(); +} + +void ExtendableEvent::StateChange( + script::EnvironmentSettings* settings, + const script::Promise<script::ValueHandle*>* promise) { + // Implement the microtask called upon fulfillment or rejection of a + // promise, as part of the algorithm for waitUntil(). + // https://w3c.github.io/ServiceWorker/#dom-extendableevent-waituntil + DCHECK(promise); + has_rejected_promise_ |= promise->State() == script::PromiseState::kRejected; + // 5.1. Decrement event’s pending promises count by one. + --pending_promise_count_; + // 5.2. If event’s pending promises count is 0, then: + if (0 == pending_promise_count_) { + if (done_callback_) { + std::move(done_callback_).Run(has_rejected_promise_); + } + web::Context* context = + base::polymorphic_downcast<web::EnvironmentSettings*>(settings) + ->context(); + ServiceWorkerJobs* jobs = context->service_worker_jobs(); + DCHECK(jobs); + // 5.2.1. Let registration be the current global object's associated + // service worker's containing service worker registration. + jobs->message_loop()->task_runner()->PostTask( + FROM_HERE, + base::BindOnce( + &ServiceWorkerJobs::WaitUntilSubSteps, base::Unretained(jobs), + base::Unretained(context->GetWindowOrWorkerGlobalScope() + ->AsServiceWorker() + ->service_worker_object() + ->containing_service_worker_registration()))); + } + delete promise; +} + +} // namespace worker +} // namespace cobalt
diff --git a/cobalt/worker/extendable_event.h b/cobalt/worker/extendable_event.h index e7d7a6a..051e034 100644 --- a/cobalt/worker/extendable_event.h +++ b/cobalt/worker/extendable_event.h
@@ -44,9 +44,9 @@ class ExtendableEvent : public web::Event { public: explicit ExtendableEvent(const std::string& type) : Event(type) {} - explicit ExtendableEvent(base::Token type, - base::OnceCallback<void(bool)> done_callback = - base::OnceCallback<void(bool)>()) + ExtendableEvent(base::Token type, + base::OnceCallback<void(bool)> done_callback = + base::OnceCallback<void(bool)>()) : Event(type), done_callback_(std::move(done_callback)) {} ExtendableEvent(const std::string& type, const ExtendableEventInit& init_dict) : Event(type, init_dict) {} @@ -54,65 +54,10 @@ void WaitUntil( script::EnvironmentSettings* settings, std::unique_ptr<script::Promise<script::ValueHandle*>>& promise, - script::ExceptionState* exception_state) { - // Algorithm for waitUntil(), to add lifetime promise to event. - // https://w3c.github.io/ServiceWorker/#dom-extendableevent-waituntil - - // 1. If event’s isTrusted attribute is false, throw an "InvalidStateError" - // DOMException. - // 2. If event is not active, throw an "InvalidStateError" DOMException. - if (!IsActive()) { - web::DOMException::Raise(web::DOMException::kInvalidStateErr, - exception_state); - return; - } - // 3. Add promise to event’s extend lifetime promises. - // 4. Increment event’s pending promises count by one. - ++pending_promise_count_; - // 5. Upon fulfillment or rejection of promise, queue a microtask to run - // these substeps: - std::unique_ptr<base::OnceCallback<void()>> callback( - new base::OnceCallback<void()>(std::move( - base::BindOnce(&ExtendableEvent::StateChange, - base::Unretained(this), settings, promise.get())))); - promise->AddStateChangeCallback(std::move(callback)); - promise.release(); - } + script::ExceptionState* exception_state); void StateChange(script::EnvironmentSettings* settings, - const script::Promise<script::ValueHandle*>* promise) { - // Implement the microtask called upon fulfillment or rejection of a - // promise, as part of the algorithm for waitUntil(). - // https://w3c.github.io/ServiceWorker/#dom-extendableevent-waituntil - DCHECK(promise); - has_rejected_promise_ |= - promise->State() == script::PromiseState::kRejected; - // 5.1. Decrement event’s pending promises count by one. - --pending_promise_count_; - // 5.2. If event’s pending promises count is 0, then: - if (0 == pending_promise_count_) { - if (done_callback_) { - std::move(done_callback_).Run(has_rejected_promise_); - } - web::Context* context = - base::polymorphic_downcast<web::EnvironmentSettings*>(settings) - ->context(); - ServiceWorkerJobs* jobs = context->service_worker_jobs(); - DCHECK(jobs); - // 5.2.1. Let registration be the current global object's associated - // service worker's containing service worker registration. - jobs->message_loop()->task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&ServiceWorkerJobs::WaitUntilSubSteps, - base::Unretained(jobs), - base::Unretained( - context->GetWindowOrWorkerGlobalScope() - ->AsServiceWorker() - ->service_worker_object() - ->containing_service_worker_registration()))); - } - delete promise; - } + const script::Promise<script::ValueHandle*>* promise); bool IsActive() { // An ExtendableEvent object is said to be active when its timed out flag
diff --git a/cobalt/worker/extendable_event_init.idl b/cobalt/worker/extendable_event_init.idl index d040bfb..5a8c5ed 100644 --- a/cobalt/worker/extendable_event_init.idl +++ b/cobalt/worker/extendable_event_init.idl
@@ -14,6 +14,6 @@ // https://w3c.github.io/ServiceWorker/#dictdef-extendableeventinit -dictionary ExtendableEventInit : EventInit{ +dictionary ExtendableEventInit : EventInit { // Defined for the forward compatibility across the derived events };
diff --git a/cobalt/worker/extendable_message_event.cc b/cobalt/worker/extendable_message_event.cc new file mode 100644 index 0000000..200e2a6 --- /dev/null +++ b/cobalt/worker/extendable_message_event.cc
@@ -0,0 +1,68 @@ +// Copyright 2022 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/worker/extendable_message_event.h" + +#include <string> +#include <utility> + +#include "cobalt/script/environment_settings.h" +#include "cobalt/script/global_environment.h" +#include "cobalt/script/v8c/entry_scope.h" +#include "cobalt/script/value_handle.h" +#include "cobalt/worker/extendable_message_event_init.h" +#include "v8/include/v8.h" + +namespace cobalt { +namespace worker { + +ExtendableMessageEvent::ExtendableMessageEvent( + const std::string& type, const ExtendableMessageEventInit& init_dict) + : ExtendableEvent(type, init_dict) { + if (init_dict.has_data() && init_dict.data()) { + DCHECK(init_dict.data()); + data_ = script::SerializeScriptValue(*(init_dict.data())); + } + if (init_dict.has_origin()) { + origin_ = init_dict.origin(); + } + if (init_dict.has_last_event_id()) { + last_event_id_ = init_dict.last_event_id(); + } + if (init_dict.has_source()) { + source_ = init_dict.source(); + } + if (init_dict.has_ports()) { + ports_ = init_dict.ports(); + } +} + +script::Handle<script::ValueHandle> ExtendableMessageEvent::data( + script::EnvironmentSettings* settings) const { + if (!settings) return script::Handle<script::ValueHandle>(); + script::GlobalEnvironment* global_environment = + base::polymorphic_downcast<web::EnvironmentSettings*>(settings) + ->context() + ->global_environment(); + DCHECK(global_environment); + v8::Isolate* isolate = global_environment->isolate(); + script::v8c::EntryScope entry_scope(isolate); + DCHECK(isolate); + if (!data_) return script::Handle<script::ValueHandle>(); + return script::Handle<script::ValueHandle>( + std::move(script::DeserializeScriptValue(isolate, *data_))); +} + +} // namespace worker +} // namespace cobalt
diff --git a/cobalt/worker/extendable_message_event.h b/cobalt/worker/extendable_message_event.h index c6364a7..475be64 100644 --- a/cobalt/worker/extendable_message_event.h +++ b/cobalt/worker/extendable_message_event.h
@@ -17,57 +17,71 @@ #include <memory> #include <string> +#include <utility> +#include "base/memory/scoped_refptr.h" #include "base/optional.h" #include "cobalt/base/token.h" +#include "cobalt/script/union_type.h" #include "cobalt/script/value_handle.h" #include "cobalt/script/wrappable.h" +#include "cobalt/web/event_target.h" #include "cobalt/web/message_port.h" +#include "cobalt/worker/client.h" #include "cobalt/worker/extendable_event.h" #include "cobalt/worker/extendable_message_event_init.h" +#include "cobalt/worker/service_worker.h" namespace cobalt { namespace worker { class ExtendableMessageEvent : public ExtendableEvent { public: - typedef scoped_refptr<script::Wrappable> SourceType; + using SourceType = + cobalt::script::UnionType3<scoped_refptr<Client>, + scoped_refptr<ServiceWorker>, + scoped_refptr<web::MessagePort>>; explicit ExtendableMessageEvent(const std::string& type) : ExtendableEvent(type) {} explicit ExtendableMessageEvent(base::Token type) : ExtendableEvent(type) {} + ExtendableMessageEvent(base::Token type, + std::unique_ptr<script::DataBuffer> data) + : ExtendableEvent(type), data_(std::move(data)) {} ExtendableMessageEvent(const std::string& type, - const ExtendableMessageEventInit& init_dict) - : ExtendableEvent(type, init_dict) {} + const ExtendableMessageEventInit& init_dict); + script::Handle<script::ValueHandle> data( + script::EnvironmentSettings* settings = nullptr) const; - const script::ValueHandleHolder* data() const { - if (!data_) { - return NULL; - } - - return &(data_->referenced_value()); - } - - std::string origin() const { return origin_; } - std::string last_event_id() const { return last_event_id_; } - - base::Optional<SourceType> source() { return source_; } - + const std::string& origin() const { return origin_; } + const std::string& last_event_id() const { return last_event_id_; } + const scoped_refptr<web::EventTarget>& source() const { return source_; } script::Sequence<scoped_refptr<MessagePort>> ports() const { return ports_; } + // These helper functions are custom, and not in any spec. + void set_origin(const std::string& origin) { origin_ = origin; } + void set_last_event_id(const std::string& last_event_id) { + last_event_id_ = last_event_id; + } + void set_source(const scoped_refptr<web::EventTarget>& source) { + source_ = source; + } + void set_ports(script::Sequence<scoped_refptr<MessagePort>> ports) { + ports_ = ports; + } + DEFINE_WRAPPABLE_TYPE(ExtendableMessageEvent); protected: ~ExtendableMessageEvent() override {} private: - std::unique_ptr<script::ValueHandleHolder::Reference> data_; - - std::string origin_ = "Origin Stub Value"; - std::string last_event_id_ = "Last Event Id Stub Value"; - base::Optional<SourceType> source_; + std::string origin_; + std::string last_event_id_; + scoped_refptr<web::EventTarget> source_; script::Sequence<scoped_refptr<MessagePort>> ports_; + std::unique_ptr<script::DataBuffer> data_; }; } // namespace worker
diff --git a/cobalt/worker/extendable_message_event.idl b/cobalt/worker/extendable_message_event.idl index 1e2d5da..600fa71 100644 --- a/cobalt/worker/extendable_message_event.idl +++ b/cobalt/worker/extendable_message_event.idl
@@ -18,10 +18,10 @@ Exposed = ServiceWorker, Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict) ] interface ExtendableMessageEvent : ExtendableEvent { - readonly attribute any data; + [CallWith = EnvironmentSettings] readonly attribute any data; readonly attribute USVString origin; readonly attribute DOMString lastEventId; - [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source; + readonly attribute EventTarget ? source; // TODO(b/236750294): Make this be FrozenArray<MessagePort> when available. readonly attribute sequence<MessagePort> ports; };
diff --git a/cobalt/worker/extendable_message_event_init.idl b/cobalt/worker/extendable_message_event_init.idl index 25da4cb..82c4e09 100644 --- a/cobalt/worker/extendable_message_event_init.idl +++ b/cobalt/worker/extendable_message_event_init.idl
@@ -15,9 +15,10 @@ // https://w3c.github.io/ServiceWorker/#dictdef-extendablemessageeventinit dictionary ExtendableMessageEventInit : ExtendableEventInit { - any data = null; + any data; USVString origin = ""; DOMString lastEventId = ""; - (Client or ServiceWorker or MessagePort)? source = null; + EventTarget? source; + //(Client or ServiceWorker or MessagePort) ? source = null; sequence<MessagePort> ports; };
diff --git a/cobalt/worker/extendable_message_event_test.cc b/cobalt/worker/extendable_message_event_test.cc new file mode 100644 index 0000000..b5162b7 --- /dev/null +++ b/cobalt/worker/extendable_message_event_test.cc
@@ -0,0 +1,199 @@ +// Copyright 2022 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/worker/extendable_message_event.h" + +#include <memory> +#include <string> + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/scoped_refptr.h" +#include "cobalt/script/testing/fake_script_value.h" +#include "cobalt/script/v8c/entry_scope.h" +#include "cobalt/script/value_handle.h" +#include "cobalt/web/testing/gtest_workarounds.h" +#include "cobalt/web/testing/mock_event_listener.h" +#include "cobalt/worker/extendable_message_event_init.h" +#include "cobalt/worker/testing/test_with_javascript.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cobalt { +namespace worker { + +using script::testing::FakeScriptValue; +using web::testing::MockEventListener; + +namespace { +class ExtendableMessageEventTestWithJavaScript + : public testing::TestServiceWorkerWithJavaScript { + protected: + ExtendableMessageEventTestWithJavaScript() { + fake_event_listener_ = MockEventListener::Create(); + } + + ~ExtendableMessageEventTestWithJavaScript() override {} + + std::unique_ptr<MockEventListener> fake_event_listener_; +}; +} // namespace + +TEST_F(ExtendableMessageEventTestWithJavaScript, + ConstructorWithEventTypeString) { + scoped_refptr<ExtendableMessageEvent> event = + new ExtendableMessageEvent("mytestevent"); + + EXPECT_EQ("mytestevent", event->type()); + EXPECT_EQ(NULL, event->target().get()); + EXPECT_EQ(NULL, event->current_target().get()); + EXPECT_EQ(web::Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + script::Handle<script::ValueHandle> event_data = + event->data(web_context()->environment_settings()); + EXPECT_TRUE(event_data.IsEmpty()); +} + +TEST_F(ExtendableMessageEventTestWithJavaScript, ConstructorWithAny) { + base::Optional<script::ValueHandleHolder::Reference> reference; + EvaluateScript("'ConstructorWithAnyMessageData'", &reference); + std::unique_ptr<script::DataBuffer> data( + script::SerializeScriptValue(reference->referenced_value())); + EXPECT_NE(nullptr, data.get()); + EXPECT_NE(nullptr, data->ptr); + EXPECT_GT(data->size, 0U); + scoped_refptr<ExtendableMessageEvent> event = + new ExtendableMessageEvent(base::Tokens::message(), std::move(data)); + + EXPECT_EQ("message", event->type()); + EXPECT_EQ(NULL, event->target().get()); + EXPECT_EQ(NULL, event->current_target().get()); + EXPECT_EQ(web::Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + script::Handle<script::ValueHandle> event_data = + event->data(web_context()->environment_settings()); + EXPECT_FALSE(event_data.IsEmpty()); + auto script_value = event_data.GetScriptValue(); + auto* isolate = script::GetIsolate(*script_value); + script::v8c::EntryScope entry_scope(isolate); + v8::Local<v8::Value> v8_value = script::GetV8Value(*script_value); + std::string actual = + *(v8::String::Utf8Value(isolate, v8_value.As<v8::String>())); + EXPECT_EQ("ConstructorWithAnyMessageData", actual); +} + +TEST_F(ExtendableMessageEventTestWithJavaScript, + ConstructorWithEventTypeAndDefaultInitDict) { + ExtendableMessageEventInit init; + scoped_refptr<ExtendableMessageEvent> event = + new ExtendableMessageEvent("mytestevent", init); + + EXPECT_EQ("mytestevent", event->type()); + EXPECT_EQ(nullptr, event->target().get()); + EXPECT_EQ(nullptr, event->current_target().get()); + EXPECT_EQ(web::Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + + script::Handle<script::ValueHandle> event_data = + event->data(web_context()->environment_settings()); + EXPECT_TRUE(event_data.IsEmpty()); + EXPECT_TRUE(event->origin().empty()); + EXPECT_TRUE(event->last_event_id().empty()); + EXPECT_EQ(nullptr, event->source().get()); + EXPECT_TRUE(event->ports().empty()); +} + +TEST_F(ExtendableMessageEventTestWithJavaScript, + ConstructorWithEventTypeAndInitDict) { + ExtendableMessageEventInit init; + base::Optional<script::ValueHandleHolder::Reference> reference; + EvaluateScript("'data_value'", &reference); + init.set_data(&(reference->referenced_value())); + init.set_origin("OriginString"); + init.set_last_event_id("lastEventIdString"); + init.set_source(web_context()->GetWindowOrWorkerGlobalScope()); + scoped_refptr<ExtendableMessageEvent> event = + new ExtendableMessageEvent("mytestevent", init); + + EXPECT_EQ("mytestevent", event->type()); + EXPECT_EQ(nullptr, event->target().get()); + EXPECT_EQ(nullptr, event->current_target().get()); + EXPECT_EQ(web::Event::kNone, event->event_phase()); + EXPECT_FALSE(event->bubbles()); + EXPECT_FALSE(event->cancelable()); + EXPECT_FALSE(event->default_prevented()); + EXPECT_FALSE(event->IsBeingDispatched()); + EXPECT_FALSE(event->propagation_stopped()); + EXPECT_FALSE(event->immediate_propagation_stopped()); + + script::Handle<script::ValueHandle> event_data = + event->data(web_context()->environment_settings()); + auto script_value = event_data.GetScriptValue(); + auto* isolate = script::GetIsolate(*script_value); + script::v8c::EntryScope entry_scope(isolate); + v8::Local<v8::Value> v8_value = script::GetV8Value(*script_value); + std::string actual = + *(v8::String::Utf8Value(isolate, v8_value.As<v8::String>())); + EXPECT_EQ("data_value", actual); + + EXPECT_EQ("OriginString", event->origin()); + EXPECT_EQ("lastEventIdString", event->last_event_id()); + EXPECT_EQ(web_context()->GetWindowOrWorkerGlobalScope(), + event->source().get()); + EXPECT_TRUE(event->ports().empty()); +} + +TEST_F(ExtendableMessageEventTestWithJavaScript, + ConstructorWithEventTypeAndExtendableMessageEventInitDict) { + std::string result; + EXPECT_TRUE( + EvaluateScript("var event = new ExtendableMessageEvent('dog', " + " {cancelable: true, " + " origin: 'OriginValue'," + " lastEventId: 'LastEventIdValue'," + " source: this," + " data: {value: 'data_value'}," + " }" + ");" + "if (event.type == 'dog' &&" + " event.bubbles == false &&" + " event.cancelable == true &&" + " event.origin == 'OriginValue' &&" + " event.lastEventId == 'LastEventIdValue' &&" + " event.source == this &&" + " event.ports.length == 0 &&" + " event.data.value == 'data_value') " + " event.data.value;", + &result)) + << "Failed to evaluate script."; + EXPECT_EQ("data_value", result); +} + +} // namespace worker +} // namespace cobalt
diff --git a/cobalt/worker/service_worker.cc b/cobalt/worker/service_worker.cc index 4d6ac58..0756da2 100644 --- a/cobalt/worker/service_worker.cc +++ b/cobalt/worker/service_worker.cc
@@ -17,8 +17,12 @@ #include <memory> #include <utility> +#include "base/bind.h" #include "cobalt/script/environment_settings.h" +#include "cobalt/script/value_handle.h" +#include "cobalt/web/event_target.h" #include "cobalt/web/message_port.h" +#include "cobalt/worker/extendable_message_event.h" #include "cobalt/worker/service_worker_global_scope.h" #include "cobalt/worker/service_worker_object.h" #include "cobalt/worker/service_worker_state.h" @@ -30,8 +34,33 @@ worker::ServiceWorkerObject* worker) : web::EventTarget(settings), worker_(worker), - message_port_(new web::MessagePort(worker->worker_global_scope())), state_(kServiceWorkerStateParsed) {} + +void ServiceWorker::PostMessage(const script::ValueHandleHolder& message) { + // https://w3c.github.io/ServiceWorker/#service-worker-postmessage-options + web::EventTarget* event_target = worker_->worker_global_scope(); + if (!event_target) return; + + base::MessageLoop* message_loop = + event_target->environment_settings()->context()->message_loop(); + if (!message_loop) { + return; + } + std::unique_ptr<script::DataBuffer> data_buffer( + script::SerializeScriptValue(message)); + if (!data_buffer) { + return; + } + message_loop->task_runner()->PostTask( + FROM_HERE, base::BindOnce( + [](web::EventTarget* event_target, + std::unique_ptr<script::DataBuffer> data_buffer) { + event_target->DispatchEvent(new ExtendableMessageEvent( + base::Tokens::message(), std::move(data_buffer))); + }, + base::Unretained(event_target), std::move(data_buffer))); +} + } // namespace worker } // namespace cobalt
diff --git a/cobalt/worker/service_worker.h b/cobalt/worker/service_worker.h index a281746..193a6a4 100644 --- a/cobalt/worker/service_worker.h +++ b/cobalt/worker/service_worker.h
@@ -20,6 +20,7 @@ #include <utility> #include "cobalt/script/environment_settings.h" +#include "cobalt/script/value_handle.h" #include "cobalt/script/wrappable.h" #include "cobalt/web/event_target.h" #include "cobalt/web/event_target_listener_info.h" @@ -43,10 +44,7 @@ // Web API: ServiceWorker // - void PostMessage(const script::ValueHandleHolder& message) { - DCHECK(message_port_); - if (worker_->worker_global_scope()) message_port_->PostMessage(message); - } + void PostMessage(const script::ValueHandleHolder& message); // The scriptURL getter steps are to return the // service worker's serialized script url. @@ -77,13 +75,9 @@ DEFINE_WRAPPABLE_TYPE(ServiceWorker); private: - ~ServiceWorker() override { - message_port_.reset(); - worker_ = nullptr; - } + ~ServiceWorker() override { worker_ = nullptr; } scoped_refptr<ServiceWorkerObject> worker_; - scoped_refptr<web::MessagePort> message_port_; ServiceWorkerState state_; };
diff --git a/cobalt/worker/service_worker_global_scope_test.cc b/cobalt/worker/service_worker_global_scope_test.cc index a2a1c0c..0c56208 100644 --- a/cobalt/worker/service_worker_global_scope_test.cc +++ b/cobalt/worker/service_worker_global_scope_test.cc
@@ -29,6 +29,8 @@ using script::testing::FakeScriptValue; using web::testing::MockEventListener; +namespace { + class ServiceWorkerGlobalScopeTest : public testing::TestServiceWorkerWithJavaScript { protected: @@ -41,6 +43,8 @@ std::unique_ptr<MockEventListener> fake_event_listener_; }; +} // namespace + TEST_F(ServiceWorkerGlobalScopeTest, RegistrationIsObject) { std::string result; EXPECT_TRUE(EvaluateScript("typeof self.registration", &result));
diff --git a/cobalt/worker/service_worker_object.cc b/cobalt/worker/service_worker_object.cc index 436f256..e63c421 100644 --- a/cobalt/worker/service_worker_object.cc +++ b/cobalt/worker/service_worker_object.cc
@@ -58,6 +58,7 @@ DCHECK(message_loop()); DCHECK(web_context_); web_agent_->WaitUntilDone(); + web_agent_->Stop(); web_agent_.reset(); web_context_ = nullptr; } @@ -123,10 +124,11 @@ void ServiceWorkerObject::ObtainWebAgentAndWaitUntilDone() { TRACE_EVENT0("cobalt::worker", "ServiceWorkerObject::ObtainWebAgentAndWaitUntilDone()"); - web_agent_.reset(new web::Agent( + web_agent_.reset(new web::Agent(options_.name)); + web_agent_->Run( options_.web_options, base::Bind(&ServiceWorkerObject::Initialize, base::Unretained(this)), - this)); + this); web_agent_->WaitUntilDone(); }
diff --git a/cobalt/worker/service_worker_object.h b/cobalt/worker/service_worker_object.h index 8b4daa6..a3cf5cb 100644 --- a/cobalt/worker/service_worker_object.h +++ b/cobalt/worker/service_worker_object.h
@@ -56,15 +56,16 @@ public: // Worker Options needed at thread run time. struct Options { - explicit Options( + Options( const std::string& name, network::NetworkModule* network_module, ServiceWorkerRegistrationObject* containing_service_worker_registration) - : web_options(name), + : name(name), containing_service_worker_registration( containing_service_worker_registration) { web_options.network_module = network_module; } + std::string name; web::Agent::Options web_options; ServiceWorkerRegistrationObject* containing_service_worker_registration; };
diff --git a/cobalt/worker/testing/test_with_javascript.h b/cobalt/worker/testing/test_with_javascript.h index f6499d5..72dda4c 100644 --- a/cobalt/worker/testing/test_with_javascript.h +++ b/cobalt/worker/testing/test_with_javascript.h
@@ -83,23 +83,34 @@ web_context_.reset(); } - WorkerGlobalScope* worker_global_scope() { return worker_global_scope_; } - - virtual scoped_refptr<script::GlobalEnvironment> global_environment() { - return web_context_->global_environment(); + WorkerGlobalScope* worker_global_scope() const { + return worker_global_scope_; } - bool EvaluateScript(const std::string& js_code, std::string* result) { - DCHECK(this->global_environment()); - scoped_refptr<script::SourceCode> source_code = - script::SourceCode::CreateSourceCode( - js_code, base::SourceLocation(__FILE__, __LINE__, 1)); + virtual web::Context* web_context() const { + DCHECK(web_context_); + return web_context_.get(); + } - this->global_environment()->EnableEval(); - this->global_environment()->SetReportEvalCallback(base::Closure()); - bool succeeded = - this->global_environment()->EvaluateScript(source_code, result); - return succeeded; + scoped_refptr<script::GlobalEnvironment> global_environment() const { + DCHECK(this->web_context()); + return this->web_context()->global_environment(); + } + + bool EvaluateScript(const std::string& js_code, + std::string* result = nullptr) { + DCHECK(global_environment()); + return global_environment()->EvaluateScript( + CreateSourceCodeAndPrepareEval(js_code), result); + } + + bool EvaluateScript( + const std::string& js_code, + base::Optional<script::ValueHandleHolder::Reference>* result) { + DCHECK(global_environment()); + return global_environment()->EvaluateScript( + CreateSourceCodeAndPrepareEval(js_code), + this->web_context()->GetWindowOrWorkerGlobalScope(), result); } ::testing::StrictMock<script::testing::MockExceptionState>* @@ -108,6 +119,15 @@ } private: + scoped_refptr<script::SourceCode> CreateSourceCodeAndPrepareEval( + const std::string& js_code) { + DCHECK(global_environment()); + global_environment()->EnableEval(); + global_environment()->SetReportEvalCallback(base::Closure()); + return script::SourceCode::CreateSourceCode( + js_code, base::SourceLocation(__FILE__, __LINE__, 1)); + } + std::unique_ptr<web::testing::StubWebContext> web_context_; WorkerGlobalScope* worker_global_scope_ = nullptr; scoped_refptr<DedicatedWorkerGlobalScope> dedicated_worker_global_scope_;
diff --git a/cobalt/worker/worker.cc b/cobalt/worker/worker.cc index a820c8f..870783d 100644 --- a/cobalt/worker/worker.cc +++ b/cobalt/worker/worker.cc
@@ -43,7 +43,7 @@ bool PermitAnyURL(const GURL&, bool) { return true; } } // namespace -Worker::Worker(const Options& options) : options_(options) { +Worker::Worker(const char* name, const Options& options) : options_(options) { // Algorithm for 'run a worker' // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#run-a-worker // 1. Let is shared be true if worker is a SharedWorker object, and false @@ -57,9 +57,15 @@ // 6. Let agent be the result of obtaining a dedicated/shared worker agent // given outside settings and is shared. Run the rest of these steps in // that agent. - web_agent_.reset(new web::Agent( - options.web_options, - base::Bind(&Worker::Initialize, base::Unretained(this)), this)); + std::string agent_name(name); + if (!options.options.name().empty()) { + agent_name.push_back(':'); + agent_name.append(options.options.name()); + } + web_agent_.reset(new web::Agent(agent_name)); + web_agent_->Run(options.web_options, + base::Bind(&Worker::Initialize, base::Unretained(this)), + this); } void Worker::WillDestroyCurrentMessageLoop() { @@ -126,7 +132,7 @@ #endif // ENABLE_DEBUGGER // 10. Set worker global scope's name to the value of options's name member. - dedicated_worker_global_scope->set_name(options_.web_options.name); + dedicated_worker_global_scope->set_name(options_.options.name()); // 11. Append owner to worker global scope's owner set. // 12. If is shared is true, then: // 1. Set worker global scope's constructor origin to outside settings's @@ -170,6 +176,8 @@ loader_ = web_context_->script_loader_factory()->CreateScriptLoader( url, origin, csp_callback, base::Bind(&Worker::OnContentProduced, base::Unretained(this)), + base::Bind(&WorkerGlobalScope::InitializePolicyContainerCallback, + worker_global_scope_), base::Bind(&Worker::OnLoadingComplete, base::Unretained(this))); } @@ -309,6 +317,7 @@ if (web_agent_) { DCHECK(message_loop()); web_agent_->WaitUntilDone(); + web_agent_->Stop(); web_agent_.reset(); web_context_ = nullptr; }
diff --git a/cobalt/worker/worker.h b/cobalt/worker/worker.h index 2c488ec..feea239 100644 --- a/cobalt/worker/worker.h +++ b/cobalt/worker/worker.h
@@ -55,8 +55,6 @@ public: // Worker Options needed at thread run time. struct Options { - explicit Options(const std::string& name) : web_options(name) {} - web::Agent::Options web_options; // True if worker is a SharedWorker object, and false otherwise. @@ -70,7 +68,7 @@ WorkerOptions options; }; - explicit Worker(const Options& options); + Worker(const char* name, const Options& options); ~Worker(); Worker(const Worker&) = delete; Worker& operator=(const Worker&) = delete;
diff --git a/cobalt/worker/worker_global_scope.cc b/cobalt/worker/worker_global_scope.cc index 662aaa5..4c68bbe 100644 --- a/cobalt/worker/worker_global_scope.cc +++ b/cobalt/worker/worker_global_scope.cc
@@ -23,6 +23,7 @@ #include "base/message_loop/message_loop_current.h" #include "base/threading/thread.h" #include "base/trace_event/trace_event.h" +#include "cobalt/loader/net_fetcher.h" #include "cobalt/loader/origin.h" #include "cobalt/script/environment_settings.h" #include "cobalt/web/context.h" @@ -195,6 +196,53 @@ set_navigator_base(navigator_); } +bool WorkerGlobalScope::InitializePolicyContainerCallback( + loader::Fetcher* fetcher, + const scoped_refptr<net::HttpResponseHeaders>& headers) { + DCHECK(headers); + // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#initialize-worker-policy-container + // 1. If workerGlobalScope's url is local but its scheme is not "blob": + // 1. Assert: workerGlobalScope's owner set's size is 1. + // 2. Set workerGlobalScope's policy container to a clone of + // workerGlobalScope's owner set[0]'s relevant settings object's policy + // container. + // 2. Otherwise, set workerGlobalScope's policy container to the result of + // creating a policy container from a fetch response given response and + // environment. + // Steps from create a policy container from a fetch response: + // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#creating-a-policy-container-from-a-fetch-response + // 1. If response's URL's scheme is "blob", then return a clone of response's + // URL's blob URL entry's environment's policy container. + // 2. Let result be a new policy container. + // 3. Set result's CSP list to the result of parsing a response's Content + // Security Policies given response. + // 4. If environment is non-null, then set result's embedder policy to the + // result of obtaining an embedder policy given response and environment. + // Otherwise, set it to "unsafe-none". + // 5. Set result's referrer policy to the result of parsing the + // `Referrer-Policy` header given response. [REFERRERPOLICY] + // 6. Return result. + + // Steps 3-6. Since csp_delegate doesn't fully mirror PolicyContainer, we + // don't create a new one here and return it. Instead we update the existing + // one for this worker and return true for success and false for failure. + csp::ResponseHeaders csp_headers(headers); + if (csp_delegate()->OnReceiveHeaders(csp_headers)) { + return true; + } + // Only NetFetchers are expected to call this, since only they have the + // response headers. + loader::NetFetcher* net_fetcher = + base::polymorphic_downcast<loader::NetFetcher*>(fetcher); + net::URLFetcher* url_fetcher = net_fetcher->url_fetcher(); + LOG(INFO) << "Failure receiving Content Security Policy headers " + "for URL: " + << url_fetcher->GetURL() << "."; + // Return true regardless of CSP headers being received to continue loading + // the response. + return true; +} + void WorkerGlobalScope::ImportScripts(const std::vector<std::string>& urls, script::ExceptionState* exception_state) { ImportScriptsInternal(urls, exception_state, URLLookupCallback(),
diff --git a/cobalt/worker/worker_global_scope.h b/cobalt/worker/worker_global_scope.h index f4e2291..345220b 100644 --- a/cobalt/worker/worker_global_scope.h +++ b/cobalt/worker/worker_global_scope.h
@@ -63,6 +63,13 @@ virtual void Initialize() {} + // https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#initialize-worker-policy-container + // Intended to be called from a loader::Decoder::OnResponseStarted to + // initialize CSP headers once they're fetched. + bool InitializePolicyContainerCallback( + loader::Fetcher* fetcher, + const scoped_refptr<net::HttpResponseHeaders>& headers); + // Web API: WorkerGlobalScope // scoped_refptr<WorkerGlobalScope> self() { return this; }
diff --git a/cobalt/worker/worker_global_scope_test.cc b/cobalt/worker/worker_global_scope_test.cc index 67ee3ed..216da15 100644 --- a/cobalt/worker/worker_global_scope_test.cc +++ b/cobalt/worker/worker_global_scope_test.cc
@@ -20,6 +20,7 @@ #include "cobalt/bindings/testing/utils.h" #include "cobalt/script/testing/fake_script_value.h" #include "cobalt/web/error_event.h" +#include "cobalt/web/message_event.h" #include "cobalt/web/testing/mock_event_listener.h" #include "cobalt/worker/testing/test_with_javascript.h"
diff --git a/glimp/gles/context.cc b/glimp/gles/context.cc index 5a5eb59..ac0b53b 100644 --- a/glimp/gles/context.cc +++ b/glimp/gles/context.cc
@@ -1,5 +1,5 @@ /* - * Copyright 2015 Google Inc. All Rights Reserved. + * 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. @@ -37,6 +37,7 @@ namespace { +std::atomic_int s_context_id_counter_(0); SbOnceControl s_tls_current_context_key_once_control = SB_ONCE_INITIALIZER; SbThreadLocalKey s_tls_current_context_key = kSbThreadLocalKeyInvalid; @@ -54,6 +55,7 @@ Context::Context(nb::scoped_ptr<ContextImpl> context_impl, Context* share_context) : impl_(context_impl.Pass()), + context_id_(s_context_id_counter_++), current_thread_(kSbThreadInvalid), has_been_current_(false), active_texture_(GL_TEXTURE0), @@ -974,7 +976,7 @@ SB_DCHECK(access & GL_MAP_INVALIDATE_BUFFER_BIT) << "glimp requires the GL_MAP_INVALIDATE_BUFFER_BIT flag to be set."; SB_DCHECK(access & GL_MAP_UNSYNCHRONIZED_BIT) - << "glimp requres the GL_MAP_UNSYNCHRONIZED_BIT flag to be set."; + << "glimp requires the GL_MAP_UNSYNCHRONIZED_BIT flag to be set."; SB_DCHECK(!(access & GL_MAP_FLUSH_EXPLICIT_BIT)) << "glimp does not support the GL_MAP_FLUSH_EXPLICIT_BIT flag."; SB_DCHECK(length == bound_buffer->size_in_bytes())
diff --git a/glimp/gles/context.h b/glimp/gles/context.h index 5444618..66e9ed7 100644 --- a/glimp/gles/context.h +++ b/glimp/gles/context.h
@@ -1,5 +1,5 @@ /* - * Copyright 2015 Google Inc. All Rights Reserved. + * 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. @@ -19,6 +19,7 @@ #include <GLES3/gl3.h> +#include <atomic> #include <map> #include <set> #include <string> @@ -58,6 +59,9 @@ // Releases the current thread's current context. static void ReleaseTLSCurrentContext(); + // Returns the unique id of the context instance. + int context_id() const { return context_id_; } + egl::Surface* draw_surface() { return default_draw_framebuffer_->color_attachment_surface(); } @@ -302,6 +306,10 @@ // A reference to the platform-specific implementation aspects of the context. nb::scoped_ptr<ContextImpl> impl_; + // The unique id of context instance. It might be queried from different + // threads. + std::atomic_int context_id_; + // The thread that currently holds this context as its current context. SbThread current_thread_;
diff --git a/net/data/url_request_unittest/redirect302-to-echo-cacheable.mock-http-headers b/net/data/url_request_unittest/redirect302-to-echo-cacheable.mock-http-headers index fce2271..d41294c 100644 --- a/net/data/url_request_unittest/redirect302-to-echo-cacheable.mock-http-headers +++ b/net/data/url_request_unittest/redirect302-to-echo-cacheable.mock-http-headers
@@ -2,3 +2,4 @@ Location: /echo Content-Length: 1 Cache-control: max-age=60000 +Content-Type: example/unit_test
diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc index c8ca20a..2a42726 100644 --- a/net/disk_cache/simple/simple_synchronous_entry.cc +++ b/net/disk_cache/simple/simple_synchronous_entry.cc
@@ -336,6 +336,7 @@ GetFilenameFromEntryFileKeyAndFileIndex(entry_file_key_, i)); #if defined(STARBOARD) ok = false; + // Note: Files can not be renamed on Starboard. #else ok = base::ReplaceFile(old_name, new_name, &out_error) && ok; #endif @@ -350,6 +351,7 @@ path_.AppendASCII(GetSparseFilenameFromEntryFileKey(entry_file_key_)); #if defined(STARBOARD) ok = false; + // Note: Files can not be renamed on Starboard. #else ok = base::ReplaceFile(old_name, new_name, &out_error) && ok; #endif
diff --git a/net/disk_cache/simple/simple_util.cc b/net/disk_cache/simple/simple_util.cc index 5c1f5a7..513de96 100644 --- a/net/disk_cache/simple/simple_util.cc +++ b/net/disk_cache/simple/simple_util.cc
@@ -63,20 +63,30 @@ std::string GetFilenameFromEntryFileKeyAndFileIndex( const SimpleFileTracker::EntryFileKey& key, int file_index) { +#if defined(STARBOARD) + return base::StringPrintf("%016" PRIx64 "_%1d", key.entry_hash, file_index); +#else + // Files are not renamed on Starboard. if (key.doom_generation == 0) return base::StringPrintf("%016" PRIx64 "_%1d", key.entry_hash, file_index); else return base::StringPrintf("todelete_%016" PRIx64 "_%1d_%" PRIu64, key.entry_hash, file_index, key.doom_generation); +#endif } std::string GetSparseFilenameFromEntryFileKey( const SimpleFileTracker::EntryFileKey& key) { +#if defined(STARBOARD) + return base::StringPrintf("%016" PRIx64 "_s", key.entry_hash); +#else + // Files are not renamed on Starboard. if (key.doom_generation == 0) return base::StringPrintf("%016" PRIx64 "_s", key.entry_hash); else return base::StringPrintf("todelete_%016" PRIx64 "_s_%" PRIu64, key.entry_hash, key.doom_generation); +#endif } std::string GetFilenameFromKeyAndFileIndex(const std::string& key,
diff --git a/net/http/http_cache_lookup_manager_unittest.cc b/net/http/http_cache_lookup_manager_unittest.cc index ac7dec9..d3776d7 100644 --- a/net/http/http_cache_lookup_manager_unittest.cc +++ b/net/http/http_cache_lookup_manager_unittest.cc
@@ -37,7 +37,8 @@ std::unique_ptr<MockTransaction> CreateMockTransaction(const GURL& url) { MockTransaction mock_trans = { url.spec().c_str(), "GET", base::Time(), "", LOAD_NORMAL, - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n", base::Time(), "<html><body>Google Blah Blah</body></html>",
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 9f13b95..5758e00 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -68,7 +68,8 @@ static const char* const kMimeTypesCacheAllowlist[] = { "text/html", "text/css", "image/gif", "image/jpeg", "image/png", "image/svg+xml", "image/webp", "font/otf", - "font/ttf", "font/woff", "font/woff2", "text/javascript"}; + "font/ttf", "font/woff", "font/woff2", "text/javascript", + "example/unit_test", "application/javascript"}; #endif constexpr TimeDelta kStaleRevalidateTimeout = TimeDelta::FromSeconds(60); @@ -3085,14 +3086,11 @@ // Only allow caching for specific mime types. std::string mime_type; response_.headers->GetMimeType(&mime_type); - // TODO(b/243727663): Empty mime types should not get cached either. - bool is_allowed_mime_type = mime_type.empty(); - if (!is_allowed_mime_type) { - for (auto allowed_type : kMimeTypesCacheAllowlist) { - if (mime_type.compare(allowed_type) == 0) { - is_allowed_mime_type = true; - break; - } + bool is_allowed_mime_type = false; + for (auto allowed_type : kMimeTypesCacheAllowlist) { + if (mime_type.compare(allowed_type) == 0) { + is_allowed_mime_type = true; + break; } } #else
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 0740dc8..0d887ad 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -369,7 +369,8 @@ base::Time(), "", LOAD_VALIDATE_CACHE, - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test\n", "Cache-Control: max-age=10000\n", base::Time(), "<html><body>Google Blah Blah</body></html>", @@ -437,6 +438,10 @@ // AddHeadersFromString() (_not_ AddHeaderFromString()). #define EXTRA_HEADER EXTRA_HEADER_LINE "\r\n" +// Adds the unit_test MIME type to the EXTRA_HEADER for compatibility +// with http_cache_transaction that now will require a MIME type. +#define MIME_TYPE_EXTRA_HEADER "Content-Type: example/unit_test\r\n" EXTRA_HEADER + static const char kExtraHeaderKey[] = "Extra"; // Static. @@ -477,7 +482,10 @@ ranges.size() != 1) { // This is not a byte range request. We return 200. response_status->assign("HTTP/1.1 200 OK"); - response_headers->assign("Date: Wed, 28 Nov 2007 09:40:09 GMT"); + // Adds the unit_test MIME type to the response_headers for compatibility + // with http_cache_transaction that now will require a MIME type. + response_headers->assign("Date: Wed, 28 Nov 2007 09:40:09 GMT\n" + "Content-Type: example/unit_test"); response_data->assign("Not a range"); return; } @@ -537,7 +545,8 @@ const MockTransaction kRangeGET_TransactionOK = { "http://www.google.com/range", "GET", base::Time(), "Range: bytes = 40-49\r\n" EXTRA_HEADER, LOAD_NORMAL, - "HTTP/1.1 206 Partial Content", + "HTTP/1.1 206 Partial Content\n" + "Content-Type: example/unit_test", "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" "ETag: \"foo\"\n" "Accept-Ranges: bytes\n" @@ -4759,7 +4768,8 @@ MockHttpCache cache; ScopedMockTransaction transaction(kETagGET_Transaction); - transaction.status = "HTTP/1.0 200 OK"; + transaction.status = "HTTP/1.0 200 OK\n" + "Content-Type: example/unit_test\n"; // Write to the cache. RunTransactionTest(cache.http_cache(), transaction); @@ -4782,7 +4792,8 @@ MockHttpCache cache; ScopedMockTransaction transaction(kETagGET_Transaction); - transaction.status = "HTTP/1.0 200 OK"; + transaction.status = "HTTP/1.0 200 OK\n" + "Content-Type: example/unit_test\n"; // Write to the cache. RunTransactionTest(cache.http_cache(), transaction); @@ -4961,7 +4972,8 @@ TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache1) { // First network response for |kUrl|. static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", "body1" @@ -4969,7 +4981,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Last-Modified: Fri, 03 Jul 2009 02:14:27 GMT\n", "body2" @@ -4987,7 +5000,8 @@ TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache2) { // First network response for |kUrl|. static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Etag: \"ETAG1\"\n" "Expires: Wed, 7 Sep 2033 21:46:42 GMT\n", // Should never expire. @@ -4996,7 +5010,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Etag: \"ETAG2\"\n" "Expires: Wed, 7 Sep 2033 21:46:42 GMT\n", // Should never expire. @@ -5015,7 +5030,8 @@ TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache3) { // First network response for |kUrl|. static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Server: server1\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5024,7 +5040,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 304 Not Modified", + "HTTP/1.1 304 Not Modified\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Server: server2\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5035,7 +5052,8 @@ "HTTP/1.1 200 OK", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Server: server2\n" - "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", + "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n" + "Content-Type: example/unit_test\n", "body1" }; @@ -5055,7 +5073,8 @@ const char kUrl[] = "http://foobar.com/main.css"; static const Response kNetResponse = { - "HTTP/1.1 304 Not Modified", + "HTTP/1.1 304 Not Modified\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", "" @@ -5099,7 +5118,8 @@ const char kUrl[] = "http://foobar.com/main.css"; static const Response kNetResponse = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", "foobar!!!" @@ -5140,7 +5160,8 @@ // (the if-modified-since date is 2 days AFTER the cache's modification date). TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache6) { static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Server: server1\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5149,7 +5170,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 304 Not Modified", + "HTTP/1.1 304 Not Modified\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Server: server2\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5170,7 +5192,8 @@ // response (304) to update the cache. TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache7) { static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Etag: \"Foo1\"\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5179,7 +5202,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 304 Not Modified", + "HTTP/1.1 304 Not Modified\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Etag: \"Foo2\"\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5197,7 +5221,8 @@ // and if-modified-since updates the cache. TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache8) { static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Etag: \"Foo1\"\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5206,7 +5231,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Etag: \"Foo2\"\n" "Last-Modified: Fri, 03 Jul 2009 02:14:27 GMT\n", @@ -5225,7 +5251,8 @@ // and if-modified-since does not update the cache with only one match. TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache9) { static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Etag: \"Foo1\"\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5234,7 +5261,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Etag: \"Foo2\"\n" "Last-Modified: Fri, 03 Jul 2009 02:14:27 GMT\n", @@ -5254,7 +5282,8 @@ // and if-modified-since does not update the cache with only one match. TEST_F(HttpCacheTest, ConditionalizedRequestUpdatesCache10) { static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Etag: \"Foo1\"\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", @@ -5263,7 +5292,8 @@ // Second network response for |kUrl|. static const Response kNetResponse2 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" "Etag: \"Foo2\"\n" "Last-Modified: Fri, 03 Jul 2009 02:14:27 GMT\n", @@ -5654,7 +5684,9 @@ RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); - EXPECT_EQ("HTTP/1.1 200 OK\nContent-Length: 42\n", headers); + EXPECT_EQ("HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test\n" + "Content-Length: 42\n", headers); RemoveMockTransaction(&transaction); } @@ -7050,7 +7082,8 @@ TEST_F(HttpCacheTest, RangeGET_301) { MockHttpCache cache; ScopedMockTransaction transaction(kRangeGET_TransactionOK); - transaction.status = "HTTP/1.1 301 Moved Permanently"; + transaction.status = "HTTP/1.1 301 Moved Permanently\n" + "Content-Type: example/unit_test"; transaction.response_headers = "Location: http://www.bar.com/\n"; transaction.data = ""; transaction.handler = NULL; @@ -8394,6 +8427,7 @@ ScopedMockTransaction transaction(kRangeGET_TransactionOK); std::string raw_headers("HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test\n" "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" "ETag: \"foo\"\n" "Accept-Ranges: bytes\n" @@ -8411,6 +8445,7 @@ "HTTP/1.1 200 OK\n" "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" "Accept-Ranges: bytes\n" + "Content-Type: example/unit_test\n" "ETag: \"foo\"\n" "Content-Length: 80\n"); @@ -8552,7 +8587,8 @@ // The server will return 200 instead of a byte range. std::string expected_headers( "HTTP/1.1 200 OK\n" - "Date: Wed, 28 Nov 2007 09:40:09 GMT\n"); + "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" + "Content-Type: example/unit_test\n"); EXPECT_EQ(expected_headers, headers); EXPECT_EQ(2, cache.network_layer()->transaction_count()); @@ -8607,6 +8643,7 @@ AddMockTransaction(&kRangeGET_TransactionOK); std::string raw_headers("HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test\n" "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" "ETag: \"foo\"\n" "Accept-Ranges: bytes\n" @@ -8699,7 +8736,7 @@ // Now make a regular request. std::string headers; - transaction.request_headers = EXTRA_HEADER; + transaction.request_headers = MIME_TYPE_EXTRA_HEADER; transaction.data = "Not a range"; RangeTransactionServer handler; handler.set_bad_200(true); @@ -8720,6 +8757,7 @@ ScopedMockTransaction transaction(kRangeGET_TransactionOK); std::string raw_headers("HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test\n" "Last-Modified: Sat, 18 Apr 2009 01:10:43 GMT\n" "ETag: \"foo\"\n" "Accept-Ranges: bytes\n" @@ -8842,7 +8880,8 @@ MockHttpCache cache; ScopedMockTransaction kTestTransaction(kSimpleGET_Transaction); - kTestTransaction.status = "HTTP/1.1 301 Moved Permanently"; + kTestTransaction.status = "HTTP/1.1 301 Moved Permanently\n" + "Content-Type: example/unit_test"; kTestTransaction.response_headers = "Location: http://www.bar.com/\n"; MockHttpRequest request(kTestTransaction); @@ -9138,7 +9177,8 @@ request.data = kData; static const Response kNetResponse1 = { - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Fri, 12 Jun 2009 21:46:42 GMT\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", kData @@ -9154,7 +9194,8 @@ request.load_flags = LOAD_VALIDATE_CACHE; static const Response kNetResponse2 = { - "HTTP/1.1 304 Not Modified", + "HTTP/1.1 304 Not Modified\n" + "Content-Type: example/unit_test", "Date: Wed, 22 Jul 2009 03:15:26 GMT\n", "" }; @@ -9178,6 +9219,7 @@ EXPECT_EQ("HTTP/1.1 200 OK\n" "Date: Wed, 22 Jul 2009 03:15:26 GMT\n" + "Content-Type: example/unit_test\n" "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n", ToSimpleString(response.headers)); @@ -9673,6 +9715,7 @@ AddMockTransaction(&kRangeGET_TransactionOK); std::string raw_headers("HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test\n" "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" "ETag: \"foo\"\n" "Accept-Ranges: bytes\n" @@ -10091,6 +10134,7 @@ AddMockTransaction(&kRangeGET_TransactionOK); std::string raw_headers("HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test\n" "Last-Modified: Sat, 18 Apr 2007 01:10:43 GMT\n" "ETag: \"foo\"\n" "Accept-Ranges: bytes\n"
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc index 9b9c92c..8914895 100644 --- a/net/http/http_transaction_test_util.cc +++ b/net/http/http_transaction_test_util.cc
@@ -48,7 +48,8 @@ base::Time(), "", LOAD_NORMAL, - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Cache-Control: max-age=10000\n", base::Time(), "<html><body>Google Blah Blah</body></html>", @@ -67,7 +68,8 @@ base::Time(), "", LOAD_NORMAL, - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "", base::Time(), "<html><body>Google Blah Blah</body></html>", @@ -86,7 +88,8 @@ base::Time(), "", LOAD_NORMAL, - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n", base::Time(), @@ -106,7 +109,8 @@ base::Time(), "", LOAD_NORMAL, - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Cache-Control: max-age=10000\n" "Etag: \"foopy\"\n", base::Time(), @@ -126,7 +130,8 @@ base::Time(), "Range: 0-100\r\n", LOAD_NORMAL, - "HTTP/1.1 200 OK", + "HTTP/1.1 200 OK\n" + "Content-Type: example/unit_test", "Cache-Control: max-age=10000\n", base::Time(), "<html><body>Google Blah Blah</body></html>",
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index b4a9ab4..e55c504 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -1156,12 +1156,6 @@ raw_header_size_ = GetTotalReceivedBytes(); ConvertRealLoadTimesToBlockingTimes(&load_timing_info_); -#if defined (STARBOARD) - load_timing_info_.encoded_body_size = static_cast<uint64_t>(GetTotalReceivedBytes()); - if (!load_timing_info_callback_.is_null()) { - load_timing_info_callback_.Run(load_timing_info_); - } -#endif // defined(STARBOARD) } } @@ -1171,6 +1165,13 @@ if (has_notified_completion_) return; + #if defined (STARBOARD) + load_timing_info_.encoded_body_size = static_cast<uint64_t>(GetTotalReceivedBytes()); + if (load_timing_info_callback_) { + load_timing_info_callback_.Run(load_timing_info_); + } + #endif // defined(STARBOARD) + is_pending_ = false; is_redirecting_ = false; has_notified_completion_ = true;
diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc index fc7b92b..e0f4358 100644 --- a/net/url_request/url_request_http_job_unittest.cc +++ b/net/url_request/url_request_http_job_unittest.cc
@@ -494,6 +494,7 @@ { MockWrite writes[] = {MockWrite(kSimpleGetMockWrite)}; MockRead reads[] = {MockRead("HTTP/1.1 200 OK\r\n" + "Content-Type: example/unit_test\r\n" "Content-Length: 12\r\n\r\n"), MockRead("Test Content")};
diff --git a/starboard/android/apk/app/CMakeLists.txt b/starboard/android/apk/app/CMakeLists.txt index d5d598f..5b1cb17 100644 --- a/starboard/android/apk/app/CMakeLists.txt +++ b/starboard/android/apk/app/CMakeLists.txt
@@ -38,6 +38,13 @@ ) endif() +# Abort gracefully if the config has not been generated. This should only happen +# when building from Android Studio which builds all supported ABIs by default. +if(NOT EXISTS "${COBALT_PRODUCT_DIR}") + message(WARNING "android-${COBALT_ARCH}_${COBALT_CONFIG} not configured. Please run GN. Skipping config.") + return() +endif() + # If COBALT_CONTENT_DIR isn't set for a particular deploy target use the # 'content/data' directory. if(NOT COBALT_CONTENT_DIR) @@ -47,9 +54,9 @@ endif() # If COBALT_LIBRARY_DIR isn't set for a particular deploy target use the -# toplevel lib/ subdirectory. +# product root. if(NOT COBALT_LIBRARY_DIR) - set(COBALT_LIBRARY_DIR ${COBALT_PRODUCT_DIR}/lib) + set(COBALT_LIBRARY_DIR ${COBALT_PRODUCT_DIR}) endif() # For platform deploy builds, use the -n parameter to skip Cobalt ninja and @@ -76,9 +83,11 @@ # ("cobalt_content" never gets created, so this runs every time.) add_custom_command(OUTPUT cobalt_content DEPENDS coat_lib + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/../../../../${COBALT_CONFIG} COMMAND ${CMAKE_COMMAND} -E create_symlink ${COBALT_CONTENT_DIR} - ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/../../../../cobalt_content + ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/../../../../${COBALT_CONFIG}/cobalt_content ) # We need a target (not a file) for the phony native dependency below.
diff --git a/starboard/android/apk/app/build.gradle b/starboard/android/apk/app/build.gradle index 2712f25..c78527f 100644 --- a/starboard/android/apk/app/build.gradle +++ b/starboard/android/apk/app/build.gradle
@@ -140,16 +140,16 @@ } // Add the directories symlinked by the CMake "cobalt_content" custom command. debug { - assets.srcDir "${buildDir}/intermediates/cxx/cobalt_content" + assets.srcDir "${buildDir}/intermediates/cxx/debug/cobalt_content" } devel { - assets.srcDir "${buildDir}/intermediates/cxx/cobalt_content" + assets.srcDir "${buildDir}/intermediates/cxx/devel/cobalt_content" } qa { - assets.srcDir "${buildDir}/intermediates/cxx/cobalt_content" + assets.srcDir "${buildDir}/intermediates/cxx/qa/cobalt_content" } release { - assets.srcDir "${buildDir}/intermediates/cxx/cobalt_content" + assets.srcDir "${buildDir}/intermediates/cxx/gold/cobalt_content" } } externalNativeBuild {
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java b/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java index eeed7a7..1478b37 100644 --- a/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java +++ b/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
@@ -781,6 +781,10 @@ Log.e(TAG, "Failed to set operating rate with invalid fps " + mFps); return; } + if (mMediaCodec == null) { + Log.e(TAG, "Failed to set operating rate when media codec is null."); + return; + } double operatingRate = mPlaybackRate * mFps; Bundle b = new Bundle(); b.putFloat(MediaFormat.KEY_OPERATING_RATE, (float) operatingRate);
diff --git a/starboard/android/apk/build.gradle b/starboard/android/apk/build.gradle index 3db6ad6..1247002 100644 --- a/starboard/android/apk/build.gradle +++ b/starboard/android/apk/build.gradle
@@ -42,17 +42,16 @@ } } -task clean(type: Delete) { - delete rootProject.buildDir -} - // Move the 'buildDir' for all projects into sub-directories of a shared top-level build directory, // which is either the root's original 'buildDir' or a custom location when building for platform // deploy. Note that the platform deploy action sets a custom 'cobaltGradleDir' property rather // than setting 'buildDir' directly on the command line since Gradle tries to get smart about // 'buildDir' which can end up putting it at the wrong depth in the file system. -def rootBuildDir = hasProperty('cobaltGradleDir') ? new File(cobaltGradleDir, 'build') : buildDir -allprojects { buildDir = new File(rootBuildDir, project.name).canonicalFile } +allprojects { buildDir = new File(gradle.ext.rootBuildDir, project.name).canonicalFile } + +task clean(type: Delete) { + delete gradle.ext.rootBuildDir +} // Android Studio Gradle plugin 3.5+ builds all supported ABIs for a connected device. Override the // property it sets to build just the first one, which is the preferred ABI for the device.
diff --git a/starboard/android/apk/cobalt-gradle.sh b/starboard/android/apk/cobalt-gradle.sh deleted file mode 100755 index a5b430f..0000000 --- a/starboard/android/apk/cobalt-gradle.sh +++ /dev/null
@@ -1,70 +0,0 @@ -#!/bin/bash -# Copyright 2016 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. - -# Helper to set ANDROID_HOME and ANDROID_NDK_HOME from command-line args -# before running gradlew, as specified by leading --sdk and --ndk args. -# -# Also resets hung gradle builds when specified by a leading --reset arg. - -GRADLE_ARGS=() -while [ "$1" ]; do - case "$1" in - --sdk) shift; ANDROID_HOME="$1" ;; - --cache) shift; mkdir -p "$1"; - GRADLE_ARGS+=("--project-cache-dir" $(cd "$1"; pwd)) ;; - --reset) RESET_GRADLE=1 ;; - *) break ;; - esac - shift -done -GRADLE_ARGS+=("$@") - -# Cleanup Gradle from previous builds. Used as part of the GYP step. -if [[ "${RESET_GRADLE}" ]]; then - echo "Cleaning Gradle daemons and locks." - # If there are any lock files, kill any hung processes still waiting on them. - if compgen -G '/var/lock/cobalt-gradle.lock.*'; then - lsof -t /var/lock/cobalt-gradle.lock.* | xargs -rt kill - fi - # Stop the Gradle daemon (if still running). - $(dirname "$0")/gradlew --stop - # Remove Gradle caches (including its lock files). - rm -rf ${HOME}/.gradle/caches - # Show the gradle version, which will cause it to download if needed. - $(dirname "$0")/gradlew -v - # After resetting, exit without running any gradle tasks. - exit -fi - -export ANDROID_HOME -echo "ANDROID_HOME=${ANDROID_HOME}" - -# Allow parallel gradle builds, as defined by a COBALT_GRADLE_BUILD_COUNT envvar -# or default to 1 if that's not set (so buildbot only runs 1 gradle at a time). -BUCKETS=${COBALT_GRADLE_BUILD_COUNT:-1} -if [ "$BUCKETS" -eq 1 ]; then - echo "Gradle daemon and parallel gradle disabled for Cobalt build" - GRADLE_ARGS+=( - "-Dorg.gradle.parallel=false" - "-Dorg.gradle.workers.max=1" - "-Dorg.gradle.daemon=false" - ) -fi - -MD5=$(echo "${GRADLE_ARGS[@]}" | md5sum) -LOCKNUM=$(( ${BUCKETS} * 0x${MD5:0:6} / 0x1000000 )) - -echo "TASK: ${GRADLE_ARGS[-1]}" -flock /var/lock/cobalt-gradle.lock.${LOCKNUM} $(dirname "$0")/gradlew "${GRADLE_ARGS[@]}"
diff --git a/starboard/android/apk/settings.gradle b/starboard/android/apk/settings.gradle index 4fe2070..3b60efd 100644 --- a/starboard/android/apk/settings.gradle +++ b/starboard/android/apk/settings.gradle
@@ -15,3 +15,7 @@ include ':app' println "GRADLE VERSION: $gradle.gradleVersion" + +gradle.ext.rootBuildDir = hasProperty('cobaltGradleDir') + ? new File(cobaltGradleDir, 'build') + : new File(rootDir, "/../../../out/android_studio/gradle/build").canonicalFile
diff --git a/starboard/android/shared/install_target.gni b/starboard/android/shared/install_target.gni index 0a635e1..6eae3d3 100644 --- a/starboard/android/shared/install_target.gni +++ b/starboard/android/shared/install_target.gni
@@ -16,6 +16,16 @@ import("//starboard/android/shared/toolchain/toolchain.gni") import("//starboard/build/config/install.gni") +declare_args() { + # Must be set to a positive integer. Needs to be a string due to us not being + # able to cast to an integer in GN. + num_gradle_workers = getenv("COBALT_GRADLE_BUILD_COUNT") +} + +if (num_gradle_workers == "") { + num_gradle_workers = "1" +} + template("install_target") { not_needed(invoker, [ "type" ]) @@ -36,10 +46,10 @@ gradle_build_type = build_type } - bash_script = "//starboard/android/apk/cobalt-gradle.sh" + gradle_wrapper = "//starboard/android/apk/gradlew" sources = [ - bash_script, + gradle_wrapper, target_output, ] sources += apk_sources @@ -52,14 +62,16 @@ cobalt_gradle_dir = rebase_path(gradle_files_dir) cobalt_product_dir = rebase_path(root_out_dir) cobalt_library_dir = rebase_path(root_out_dir) + project_cache_dir = + rebase_path("$root_build_dir/gradle/$installable_target_name/cache") + use_parallel_build = num_gradle_workers != "1" script = "//starboard/build/run_bash.py" args = [ - rebase_path(bash_script, root_build_dir), - "--sdk", - android_sdk_path, - "--cache", - rebase_path("$root_build_dir/gradle/$installable_target_name/cache"), + "env", + "ANDROID_HOME=${android_sdk_path}", + rebase_path(gradle_wrapper, root_build_dir), + "--project-cache-dir=$project_cache_dir", "--project-dir", cobalt_project_dir, "-P", @@ -79,6 +91,9 @@ "-P", "enableVulkan=$enable_vulkan", "assembleCobalt_$gradle_build_type", + "-Dorg.gradle.workers.max=$num_gradle_workers", + "-Dorg.gradle.workers.parallel=$use_parallel_build", + "-Dorg.gradle.workers.daemon=$use_parallel_build", ] }
diff --git a/starboard/build/install/no_install.gni b/starboard/build/install/no_install.gni index f2ca601..8d8c448 100644 --- a/starboard/build/install/no_install.gni +++ b/starboard/build/install/no_install.gni
@@ -19,6 +19,7 @@ [ "testonly", "installable_target_name", + "deps", ]) forward_variables_from(invoker, [ @@ -27,5 +28,8 @@ ]) group(target_name) { deps = [ ":$installable_target_name" ] + if (defined(invoker.deps)) { + deps += invoker.deps + } } }
diff --git a/starboard/elf_loader/sandbox.cc b/starboard/elf_loader/sandbox.cc index 019309f..2f2eb05 100644 --- a/starboard/elf_loader/sandbox.cc +++ b/starboard/elf_loader/sandbox.cc
@@ -79,13 +79,16 @@ if (!get_user_agent_func) { SB_LOG(ERROR) << "Failed to get user agent string"; } else { - CrashpadAnnotations cobalt_version_info; - memset(&cobalt_version_info, 0, sizeof(CrashpadAnnotations)); - starboard::strlcpy(cobalt_version_info.user_agent_string, - get_user_agent_func(), USER_AGENT_STRING_MAX_SIZE); - third_party::crashpad::wrapper::AddAnnotationsToCrashpad( - cobalt_version_info); - SB_DLOG(INFO) << "Added user agent string to Crashpad."; + std::vector<char> buffer(USER_AGENT_STRING_MAX_SIZE); + starboard::strlcpy(buffer.data(), get_user_agent_func(), + USER_AGENT_STRING_MAX_SIZE); + if (third_party::crashpad::wrapper::InsertCrashpadAnnotation( + third_party::crashpad::wrapper::kCrashpadUserAgentStringKey, + buffer.data())) { + SB_DLOG(INFO) << "Added user agent string to Crashpad."; + } else { + SB_DLOG(INFO) << "Failed to add user agent string to Crashpad."; + } } if (!g_sb_event_func) {
diff --git a/starboard/loader_app/loader_app.cc b/starboard/loader_app/loader_app.cc index 8bae605..fcb2975 100644 --- a/starboard/loader_app/loader_app.cc +++ b/starboard/loader_app/loader_app.cc
@@ -160,13 +160,16 @@ if (!get_user_agent_func) { SB_LOG(ERROR) << "Failed to get user agent string"; } else { - CrashpadAnnotations cobalt_version_info; - memset(&cobalt_version_info, 0, sizeof(CrashpadAnnotations)); - starboard::strlcpy(cobalt_version_info.user_agent_string, - get_user_agent_func(), USER_AGENT_STRING_MAX_SIZE); - third_party::crashpad::wrapper::AddAnnotationsToCrashpad( - cobalt_version_info); - SB_DLOG(INFO) << "Added user agent string to Crashpad."; + std::vector<char> buffer(USER_AGENT_STRING_MAX_SIZE); + starboard::strlcpy(buffer.data(), get_user_agent_func(), + USER_AGENT_STRING_MAX_SIZE); + if (third_party::crashpad::wrapper::InsertCrashpadAnnotation( + third_party::crashpad::wrapper::kCrashpadUserAgentStringKey, + buffer.data())) { + SB_DLOG(INFO) << "Added user agent string to Crashpad."; + } else { + SB_DLOG(INFO) << "Failed to add user agent string to Crashpad."; + } } g_sb_event_func = reinterpret_cast<void (*)(const SbEvent*)>(
diff --git a/starboard/loader_app/slot_management.cc b/starboard/loader_app/slot_management.cc index 9f76b11..fc5549a 100644 --- a/starboard/loader_app/slot_management.cc +++ b/starboard/loader_app/slot_management.cc
@@ -28,6 +28,7 @@ #include "starboard/loader_app/installation_manager.h" #include "starboard/memory.h" #include "starboard/string.h" +#include "third_party/crashpad/wrapper/annotations.h" #include "third_party/crashpad/wrapper/wrapper.h" namespace starboard { @@ -315,13 +316,16 @@ if (!get_user_agent_func) { SB_LOG(ERROR) << "Failed to get user agent string"; } else { - CrashpadAnnotations cobalt_version_info; - memset(&cobalt_version_info, 0, sizeof(CrashpadAnnotations)); - starboard::strlcpy(cobalt_version_info.user_agent_string, - get_user_agent_func(), USER_AGENT_STRING_MAX_SIZE); - third_party::crashpad::wrapper::AddAnnotationsToCrashpad( - cobalt_version_info); - SB_DLOG(INFO) << "Added user agent string to Crashpad."; + std::vector<char> buffer(USER_AGENT_STRING_MAX_SIZE); + starboard::strlcpy(buffer.data(), get_user_agent_func(), + USER_AGENT_STRING_MAX_SIZE); + if (third_party::crashpad::wrapper::InsertCrashpadAnnotation( + third_party::crashpad::wrapper::kCrashpadUserAgentStringKey, + buffer.data())) { + SB_DLOG(INFO) << "Added user agent string to Crashpad."; + } else { + SB_DLOG(INFO) << "Failed to add user agent string to Crashpad."; + } } SB_DLOG(INFO) << "Successfully loaded Cobalt!\n";
diff --git a/starboard/shared/ffmpeg/ffmpeg_demuxer_impl.cc b/starboard/shared/ffmpeg/ffmpeg_demuxer_impl.cc index 0e6cf9a..ef15ed2 100644 --- a/starboard/shared/ffmpeg/ffmpeg_demuxer_impl.cc +++ b/starboard/shared/ffmpeg/ffmpeg_demuxer_impl.cc
@@ -247,6 +247,65 @@ } } +// Attempts to parse a codec profile from |extradata|. Upon success, +// |out_profile| is populated with the profile and true is returned. Upon +// failure, false is returned and |out_profile| is not modified. +bool TryParseH264Profile(const uint8_t* extradata, + size_t extradata_size, + CobaltExtensionDemuxerVideoCodecProfile& out_profile) { + if (extradata_size < 2) { + return false; + } + const uint8_t version = extradata[0]; + if (version != 1) { + return false; + } + const int profile = extradata[1]; + switch (profile) { + case FF_PROFILE_H264_BASELINE: + out_profile = kCobaltExtensionDemuxerH264ProfileBaseline; + return true; + case FF_PROFILE_H264_MAIN: + out_profile = kCobaltExtensionDemuxerH264ProfileMain; + return true; + case FF_PROFILE_H264_EXTENDED: + out_profile = kCobaltExtensionDemuxerH264ProfileExtended; + return true; + case FF_PROFILE_H264_HIGH: + out_profile = kCobaltExtensionDemuxerH264ProfileHigh; + return true; + case FF_PROFILE_H264_HIGH_10: + out_profile = kCobaltExtensionDemuxerH264ProfileHigh10Profile; + return true; + case FF_PROFILE_H264_HIGH_422: + out_profile = kCobaltExtensionDemuxerH264ProfileHigh422Profile; + return true; + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: + out_profile = kCobaltExtensionDemuxerH264ProfileHigh444PredictiveProfile; + return true; + default: + SB_LOG(ERROR) << "Unknown H264 profile: " << profile; + return false; + } +} + +// Attempts to parse a codec profile from |extradata|. Upon success, +// |out_profile| is populated with the profile and true is returned. Upon +// failure, false is returned and |out_profile| is not modified. +bool TryParseH265Profile(const uint8_t* extradata, + size_t extradata_size, + int& out_profile) { + if (extradata_size < 2) { + return false; + } + const uint8_t version = extradata[0]; + if (version != 1) { + return false; + } + out_profile = extradata[1] & 0x1F; + return true; +} + int AVIOReadOperation(void* opaque, uint8_t* buf, int buf_size) { auto* data_source = static_cast<CobaltExtensionDemuxerDataSource*>(opaque); const int bytes_read = @@ -898,8 +957,15 @@ config->profile = ProfileIDToVideoCodecProfile(codec_context->profile); if (config->profile == kCobaltExtensionDemuxerVideoCodecProfileUnknown && codec_context->extradata && codec_context->extradata_size) { - // TODO(b/231631898): handle the extra data here, if necessary. - SB_LOG(ERROR) << "Extra data is not currently handled."; + CobaltExtensionDemuxerVideoCodecProfile profile = + kCobaltExtensionDemuxerVideoCodecProfileUnknown; + // Attempt to populate profile based on extradata. + if (TryParseH264Profile(codec_context->extradata, + codec_context->extradata_size, profile)) { + config->profile = profile; + } else { + SB_LOG(ERROR) << "Could not parse H264 profile from extradata."; + } } break; } @@ -915,8 +981,11 @@ #endif // FF_PROFILE_HEVC_REXT ) && codec_context->extradata && codec_context->extradata_size) { - // TODO(b/231631898): handle the extra data here, if necessary. - SB_LOG(ERROR) << "Extra data is not currently handled."; + // Attempt to populate hevc_profile based on extradata. + if (!TryParseH265Profile(codec_context->extradata, + codec_context->extradata_size, hevc_profile)) { + SB_LOG(ERROR) << "Could not parse H265 profile from extradata."; + } } else { hevc_profile = codec_context->profile; }
diff --git a/starboard/shared/starboard/crash_handler.cc b/starboard/shared/starboard/crash_handler.cc index 572a022..0d6ec2d 100644 --- a/starboard/shared/starboard/crash_handler.cc +++ b/starboard/shared/starboard/crash_handler.cc
@@ -25,14 +25,16 @@ namespace { bool OverrideCrashpadAnnotations(CrashpadAnnotations* crashpad_annotations) { - CrashpadAnnotations annotations; - memset(&annotations, 0, sizeof(CrashpadAnnotations)); - memcpy(&annotations, crashpad_annotations, sizeof(CrashpadAnnotations)); - return third_party::crashpad::wrapper::AddAnnotationsToCrashpad(annotations); + return false; // Deprecated +} + +bool SetString(const char* key, const char* value) { + return third_party::crashpad::wrapper::InsertCrashpadAnnotation(key, value); } const CobaltExtensionCrashHandlerApi kCrashHandlerApi = { - kCobaltExtensionCrashHandlerName, 1, &OverrideCrashpadAnnotations, + kCobaltExtensionCrashHandlerName, 2, &OverrideCrashpadAnnotations, + &SetString, }; } // namespace
diff --git a/starboard/shared/starboard/player/filter/video_renderer_internal_impl.cc b/starboard/shared/starboard/player/filter/video_renderer_internal_impl.cc index b07a4fe..0e11da1 100644 --- a/starboard/shared/starboard/player/filter/video_renderer_internal_impl.cc +++ b/starboard/shared/starboard/player/filter/video_renderer_internal_impl.cc
@@ -122,7 +122,6 @@ #if SB_PLAYER_FILTER_ENABLE_STATE_CHECK first_input_written_at_ = SbTimeGetMonotonicNow(); #endif // SB_PLAYER_FILTER_ENABLE_STATE_CHECK - absolute_time_of_first_input_ = SbTimeGetMonotonicNow(); } SB_DCHECK(need_more_input_.load());
diff --git a/starboard/shared/starboard/player/filter/video_renderer_internal_impl.h b/starboard/shared/starboard/player/filter/video_renderer_internal_impl.h index ee8bad0..a2fd2e4 100644 --- a/starboard/shared/starboard/player/filter/video_renderer_internal_impl.h +++ b/starboard/shared/starboard/player/filter/video_renderer_internal_impl.h
@@ -92,7 +92,6 @@ PrerolledCB prerolled_cb_; EndedCB ended_cb_; - SbTimeMonotonic absolute_time_of_first_input_ = 0; // Our owner will attempt to seek to time 0 when playback begins. In // general, seeking could require a full reset of the underlying decoder on // some platforms, so we make an effort to improve playback startup
diff --git a/starboard/shared/win32/audio_decoder.cc b/starboard/shared/win32/audio_decoder.cc index d404441..0b54739 100644 --- a/starboard/shared/win32/audio_decoder.cc +++ b/starboard/shared/win32/audio_decoder.cc
@@ -61,9 +61,19 @@ : audio_codec_(audio_codec), audio_sample_info_(audio_sample_info), drm_system_(drm_system), - sample_type_(kSbMediaAudioSampleTypeFloat32), + sample_type_((audio_codec == kSbMediaAudioCodecAc3 || + audio_codec == kSbMediaAudioCodecEac3) + ? +#if SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES) + kSbMediaAudioSampleTypeInt16 +#else + kSbMediaAudioSampleTypeInt16Deprecated +#endif // SB_HAS_QUIRK(SUPPORT_INT16_AUDIO_SAMPLES) + : kSbMediaAudioSampleTypeFloat32), stream_ended_(false) { - SB_DCHECK(audio_codec == kSbMediaAudioCodecAac); + SB_DCHECK(audio_codec == kSbMediaAudioCodecAac || + audio_codec == kSbMediaAudioCodecAc3 || + audio_codec == kSbMediaAudioCodecEac3); } AudioDecoder::~AudioDecoder() {
diff --git a/starboard/shared/win32/audio_transform.cc b/starboard/shared/win32/audio_transform.cc index 5a03f94..81aebd0 100644 --- a/starboard/shared/win32/audio_transform.cc +++ b/starboard/shared/win32/audio_transform.cc
@@ -14,9 +14,12 @@ #include "starboard/shared/win32/audio_transform.h" +#include <mfapi.h> + #include <vector> #include "starboard/memory.h" +#include "starboard/shared/uwp/wasapi_include.h" #include "starboard/shared/win32/error_utils.h" #include "starboard/shared/win32/media_common.h" #include "starboard/shared/win32/media_foundation_utils.h" @@ -40,6 +43,12 @@ case kSbMediaAudioCodecOpus: { return MFAudioFormat_Opus; } + case kSbMediaAudioCodecAc3: { + return MFAudioFormat_Dolby_AC3; + } + case kSbMediaAudioCodecEac3: { + return MFAudioFormat_Dolby_DDPlus; + } default: { SB_NOTIMPLEMENTED(); return MFAudioFormat_PCM; @@ -47,9 +56,55 @@ } } +GUID ConvertToWin32TransformType(SbMediaAudioCodec codec) { + switch (codec) { + case kSbMediaAudioCodecAac: { + return CLSID_MSAACDecMFT; + } + case kSbMediaAudioCodecAc3: + case kSbMediaAudioCodecEac3: { + return CLSID_MSDDPlusDecMFT; + } + default: { + SB_NOTIMPLEMENTED(); + return MFAudioFormat_Float; + } + } +} + +GUID ConvertToWin32OutputFormat(SbMediaAudioCodec codec) { + switch (codec) { + case kSbMediaAudioCodecAac: + case kSbMediaAudioCodecOpus: + case kSbMediaAudioCodecNone: { + return MFAudioFormat_Float; + } + case kSbMediaAudioCodecAc3: { + return MFAudioFormat_Dolby_AC3_SPDIF; + } + case kSbMediaAudioCodecEac3: { + return KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS; + } + default: { + SB_NOTIMPLEMENTED(); + return MFAudioFormat_Float; + } + } +} + class WinAudioFormat { public: explicit WinAudioFormat(const SbMediaAudioSampleInfo& audio_sample_info) { + if (audio_sample_info.codec == kSbMediaAudioCodecAac) { + CreateAacAudioFormat(audio_sample_info); + } else { + SB_DCHECK(audio_sample_info.codec == kSbMediaAudioCodecAc3 || + audio_sample_info.codec == kSbMediaAudioCodecEac3); + CreateAc3AudioFormat(audio_sample_info); + } + } + + void CreateAacAudioFormat(const SbMediaAudioSampleInfo& audio_sample_info) { // The HEAACWAVEFORMAT structure has many specializations with varying data // appended at the end. // The "-1" is used to account for pbAudioSpecificConfig[1] at the end of @@ -78,11 +133,32 @@ if (audio_sample_info.audio_specific_config_size > 0) { memcpy(wave_format->pbAudioSpecificConfig, - audio_sample_info.audio_specific_config, - audio_sample_info.audio_specific_config_size); + audio_sample_info.audio_specific_config, + audio_sample_info.audio_specific_config_size); } } + void CreateAc3AudioFormat(const SbMediaAudioSampleInfo& audio_sample_info) { + format_buffer_.resize(sizeof(WAVEFORMATEXTENSIBLE)); + WAVEFORMATEXTENSIBLE* wave_format = + reinterpret_cast<WAVEFORMATEXTENSIBLE*>(format_buffer_.data()); + + wave_format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wave_format->Format.nChannels = audio_sample_info.number_of_channels; + wave_format->Format.wBitsPerSample = audio_sample_info.bits_per_sample; + wave_format->Format.nSamplesPerSec = audio_sample_info.samples_per_second; + wave_format->Format.nBlockAlign = audio_sample_info.block_alignment; + wave_format->Format.nAvgBytesPerSec = 0; + wave_format->Format.cbSize = + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wave_format->Samples.wValidBitsPerSample = + wave_format->Format.wBitsPerSample; + wave_format->dwChannelMask = audio_sample_info.number_of_channels > 2 + ? KSAUDIO_SPEAKER_5POINT1 + : KSAUDIO_SPEAKER_STEREO; + wave_format->SubFormat = ConvertToWin32AudioCodec(audio_sample_info.codec); + } + WAVEFORMATEX* WaveFormatData() { return reinterpret_cast<WAVEFORMATEX*>(format_buffer_.data()); } @@ -97,8 +173,12 @@ scoped_ptr<MediaTransform> CreateAudioTransform( const SbMediaAudioSampleInfo& audio, SbMediaAudioCodec codec) { + SB_DCHECK(codec == kSbMediaAudioCodecAac || codec == kSbMediaAudioCodecAc3 || + codec == kSbMediaAudioCodecEac3); ComPtr<IMFTransform> transform; - HRESULT hr = CreateDecoderTransform(CLSID_MSAACDecMFT, &transform); + HRESULT hr = + CreateDecoderTransform(ConvertToWin32TransformType(codec), &transform); + CheckResult(hr); ComPtr<IMFMediaType> input_type; @@ -123,7 +203,7 @@ scoped_ptr<MediaTransform> output(new MediaTransform(transform)); output->SetInputType(selected); - output->SetOutputTypeBySubType(MFAudioFormat_Float); + output->SetOutputTypeBySubType(ConvertToWin32OutputFormat(codec)); return output.Pass(); }
diff --git a/starboard/shared/win32/win32_audio_decoder.cc b/starboard/shared/win32/win32_audio_decoder.cc index df49374..fdfb0c0 100644 --- a/starboard/shared/win32/win32_audio_decoder.cc +++ b/starboard/shared/win32/win32_audio_decoder.cc
@@ -19,6 +19,7 @@ #include "starboard/atomic.h" #include "starboard/shared/starboard/thread_checker.h" +#include "starboard/shared/uwp/wasapi_include.h" #include "starboard/shared/win32/atomic_queue.h" #include "starboard/shared/win32/audio_decoder.h" #include "starboard/shared/win32/audio_transform.h" @@ -35,10 +36,23 @@ using ::starboard::shared::win32::CreateAudioTransform; const size_t kAacSamplesPerFrame = 1024; -// We are using float samples on Xb1. -const size_t kBytesPerSample = sizeof(float); +// We are using float samples for AAC on Xb1. +const size_t kAacBytesPerSample = sizeof(float); namespace { +size_t GetExpectedBufferSize(SbMediaAudioCodec codec, int num_channels) { + switch (codec) { + case kSbMediaAudioCodecAac: + return num_channels * kAacSamplesPerFrame * kAacBytesPerSample; + case kSbMediaAudioCodecAc3: + return kAc3BufferSize; + case kSbMediaAudioCodecEac3: + return kEac3BufferSize; + default: + SB_NOTREACHED(); + return size_t(0); + } +} class AbstractWin32AudioDecoderImpl : public AbstractWin32AudioDecoder { public: @@ -53,12 +67,27 @@ sample_type_(sample_type), number_of_channels_(audio_sample_info.number_of_channels), heaac_detected_(false), - samples_per_second_( - static_cast<int>(audio_sample_info.samples_per_second)) { + expected_buffer_size_( + GetExpectedBufferSize(codec, + audio_sample_info.number_of_channels)) { scoped_ptr<MediaTransform> audio_decoder = CreateAudioTransform(audio_sample_info, codec_); impl_.reset( new DecryptingDecoder("audio", audio_decoder.Pass(), drm_system)); + switch (codec) { + case kSbMediaAudioCodecAc3: + samples_per_second_ = kAc3SamplesPerSecond; + number_of_channels_ = kIec60958Channels; + break; + case kSbMediaAudioCodecEac3: + samples_per_second_ = kEac3SamplesPerSecond; + number_of_channels_ = kIec60958Channels; + break; + default: + samples_per_second_ = + static_cast<int>(audio_sample_info.samples_per_second); + number_of_channels_ = audio_sample_info.number_of_channels; + } } void Consume(ComPtr<IMFSample> sample) { @@ -86,13 +115,18 @@ const uint8_t* data = reinterpret_cast<uint8_t*>(buffer); const size_t data_size = static_cast<size_t>(length); - const size_t expect_size_in_bytes = - number_of_channels_ * kAacSamplesPerFrame * kBytesPerSample; - if (data_size / expect_size_in_bytes == 2) { + if (codec_ == kSbMediaAudioCodecAac && + (data_size / expected_buffer_size_ == 2)) { heaac_detected_.store(true); } - const size_t decoded_data_size = std::max(expect_size_in_bytes, data_size); + const size_t decoded_data_size = std::max(expected_buffer_size_, data_size); + + if (codec_ == kSbMediaAudioCodecAc3) { + SB_DCHECK(decoded_data_size == kAc3BufferSize); + } else if (codec_ == kSbMediaAudioCodecEac3) { + SB_DCHECK(decoded_data_size == kEac3BufferSize); + } DecodedAudioPtr data_ptr( new DecodedAudio(number_of_channels_, sample_type_, audio_frame_fmt_, @@ -109,12 +143,14 @@ bool TryWrite(const scoped_refptr<InputBuffer>& buff) override { SB_DCHECK(thread_checker_.CalledOnValidThread()); - // The incoming audio is in ADTS format which has a 7 bytes header. But - // the audio decoder is configured to accept raw AAC. So we have to adjust - // the data, size, and subsample mapping to skip the ADTS header. - const int kADTSHeaderSize = 7; - const bool write_ok = impl_->TryWriteInputBuffer(buff, kADTSHeaderSize); - return write_ok; + if (codec_ == kSbMediaAudioCodecAac) { + // The incoming audio is in ADTS format which has a 7 bytes header. But + // the audio decoder is configured to accept raw AAC. So we have to + // adjust the data, size, and subsample mapping to skip the ADTS header. + const int kADTSHeaderSize = 7; + return impl_->TryWriteInputBuffer(buff, kADTSHeaderSize); + } + return impl_->TryWriteInputBuffer(buff, 0); } void WriteEndOfStream() override { @@ -182,6 +218,7 @@ uint16_t number_of_channels_; atomic_bool heaac_detected_; int samples_per_second_; + const size_t expected_buffer_size_; }; } // anonymous namespace.
diff --git a/starboard/tools/testing/sharding_configuration.json b/starboard/tools/testing/sharding_configuration.json index 7dbbc2b..0641b05 100644 --- a/starboard/tools/testing/sharding_configuration.json +++ b/starboard/tools/testing/sharding_configuration.json
@@ -56,5 +56,94 @@ "net_unittests": [2, 2], "player_filter_tests": [2, 2] } + ], + "raspi-2":[ + { + "base_unittests": [1, 6], + "layout_tests": [5, 6], + "net_unittests": [2, 6], + "player_filter_tests": [1, 6], + "renderer_test": [6, 6] + }, + { + "base_unittests": [2, 6], + "layout_tests": [4, 6], + "net_unittests": [1, 6], + "nplb": [1, 5], + "player_filter_tests": [5, 6], + "renderer_test": [5, 6] + }, + { + "base_unittests": [3, 6], + "layout_tests": [6, 6], + "net_unittests": [4, 6], + "nplb": [4, 5], + "player_filter_tests": [3, 6], + "renderer_test": [1, 6] + }, + { + "base_unittests": [5, 6], + "layout_tests": [3, 6], + "net_unittests": [5, 6], + "nplb": [2, 5], + "player_filter_tests": [2, 6], + "renderer_test": [2, 6] + }, + { + "base_unittests": [6, 6], + "layout_tests": [1, 6], + "net_unittests": [3, 6], + "nplb": [3, 5], + "player_filter_tests": [4, 6], + "renderer_test": [4, 6] + }, + { + "app_key_files_test": "*", + "app_key_test": "*", + "audio_test": "*", + "base_test": "*", + "base_unittests": [4, 6], + "bindings_test": "*", + "browser_test": "*", + "crypto_unittests": "*", + "csp_test": "*", + "css_parser_test": "*", + "cssom_test": "*", + "cwrappers_test": "*", + "dom_parser_test": "*", + "dom_test": "*", + "drain_file_test": "*", + "elf_loader_test": "*", + "extension_test": "*", + "graphics_system_test": "*", + "installation_manager_test": "*", + "layout_test": "*", + "layout_tests": [2, 6], + "loader_test": "*", + "math_test": "*", + "media_capture_test": "*", + "media_session_test": "*", + "media_stream_test": "*", + "memory_store_test": "*", + "nb_test": "*", + "net_unittests": [6, 6], + "network_test": "*", + "nplb": [5, 5], + "player_filter_tests": [6, 6], + "poem_unittests": "*", + "render_tree_test": "*", + "renderer_test": [3, 6], + "slot_management_test": "*", + "starboard_platform_tests": "*", + "storage_test": "*", + "text_encoding_test": "*", + "web_animations_test": "*", + "web_test": "*", + "webdriver_test": "*", + "websocket_test": "*", + "worker_test": "*", + "xhr_test": "*", + "zip_unittests": "*" + } ] }
diff --git a/starboard/tools/testing/test_runner.py b/starboard/tools/testing/test_runner.py index fe2fde7..2fc8f24 100755 --- a/starboard/tools/testing/test_runner.py +++ b/starboard/tools/testing/test_runner.py
@@ -428,7 +428,7 @@ if gtest_filter_value: test_params.append("--gtest_filter=" + gtest_filter_value) - if shard_index and shard_count: + if shard_count is not None: test_params.append("--gtest_total_shards={}".format(shard_count)) test_params.append("--gtest_shard_index={}".format(shard_index))
diff --git a/starboard/win/shared/BUILD.gn b/starboard/win/shared/BUILD.gn index 5f20368..162b1c5 100644 --- a/starboard/win/shared/BUILD.gn +++ b/starboard/win/shared/BUILD.gn
@@ -180,6 +180,7 @@ "//starboard/shared/stub/window_set_on_screen_keyboard_keep_focus.cc", "//starboard/shared/stub/window_show_on_screen_keyboard.cc", "//starboard/shared/stub/window_update_on_screen_keyboard_suggestions.cc", + "//starboard/shared/uwp/wasapi_include.h", "//starboard/shared/win32/adapter_utils.cc", "//starboard/shared/win32/adapter_utils.h", "//starboard/shared/win32/atomic_public.h",
diff --git a/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp index d50e5f3..18d2410 100644 --- a/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp +++ b/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -75,7 +75,7 @@ " float3 j = pow(SRGB_OETF(i), gamma);\n" " float3 adj = (minLNits + (maxLNits - minLNits) * j) / kRefWhiteLevelSRGB;\n" " float3 cri_float = (float3)cri;\n" - " float3 ret = lerp(adj, L, cri_float);\n" + " float3 ret = lerp(L, adj, cri_float);\n" " return ret;\n" "}\n" "//input: normalized L in units of RefWhite (1.0=100nits), output: normalized E\n" @@ -97,7 +97,7 @@ "{\n" " PS_OUTPUT output;\n" " \n" - " float3 input_colors = gl_Color[0].rgb;\n" + " float3 input_colors = max(gl_Color[0].rgb, 0);\n" " float3 lin_osd_graphics = SRGB_EOTF(input_colors);\n" " lin_osd_graphics = mul(BT709_TO_BT2020, lin_osd_graphics);\n" " lin_osd_graphics *= kMaxNits/kRefWhiteLevelSRGB;\n"
diff --git a/third_party/crashpad/client/BUILD.gn b/third_party/crashpad/client/BUILD.gn index 19aa8db..6ecd5c5 100644 --- a/third_party/crashpad/client/BUILD.gn +++ b/third_party/crashpad/client/BUILD.gn
@@ -90,12 +90,13 @@ "../util", ] + deps = [] + if (crashpad_is_in_starboard) { public_deps += [ "//starboard/elf_loader:evergreen_info" ] + deps += [ "../wrapper/proto:crashpad_annotations_proto" ] } - deps = [] - if (crashpad_is_win) { libs = [ "rpcrt4.lib" ] cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union
diff --git a/third_party/crashpad/client/crashpad_client.h b/third_party/crashpad/client/crashpad_client.h index 9dd12dd..4cf5a0e 100644 --- a/third_party/crashpad/client/crashpad_client.h +++ b/third_party/crashpad/client/crashpad_client.h
@@ -41,7 +41,6 @@ #if defined(STARBOARD) #include "starboard/elf_loader/evergreen_info.h" #include "third_party/crashpad/snapshot/sanitized/sanitization_information.h" -#include "third_party/crashpad/wrapper/annotations.h" #endif namespace crashpad { @@ -391,14 +390,17 @@ //! \return `true` on success, `false` on failure with a message logged. static bool SendEvergreenInfoToHandler(EvergreenInfo evergreen_info); - //! \brief Sends mapping info to the handler + //! \brief Inserts annotation mapping info for the handler //! - //! A handler must have already been installed before calling this method. - //! \param[in] annotations A CrashpadAnnotations struct, whose information - //! was created on Evergreen startup. + //! A signal handler must have already been installed before calling this + //! method. Whether or not the annotation is sent to the Crashpad handler, + //! or just prepared to be sent, depends on whether the Crashpad handler is + //! started at launch or at crash. + //! \param[in] key The annotation's key. + //! \param[in] value The annotation's value. //! //! \return `true` on success, `false` on failure with a message logged. - static bool SendAnnotationsToHandler(CrashpadAnnotations annotations); + static bool InsertAnnotationForHandler(const char* key, const char* value); //! \brief Sends mapping info to the handler //!
diff --git a/third_party/crashpad/client/crashpad_client_linux.cc b/third_party/crashpad/client/crashpad_client_linux.cc index 5738668..1b579bf 100644 --- a/third_party/crashpad/client/crashpad_client_linux.cc +++ b/third_party/crashpad/client/crashpad_client_linux.cc
@@ -26,6 +26,7 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" #include "client/client_argv_handling.h" +#include "starboard/common/mutex.h" #include "third_party/lss/lss.h" #include "util/file/file_io.h" #include "util/file/filesystem.h" @@ -37,6 +38,15 @@ #include "util/misc/from_pointer_cast.h" #include "util/posix/double_fork_and_exec.h" #include "util/posix/signals.h" +// TODO(b/201538792): resolve conflict between mini_chromium and base functions. +#ifdef LogMessage +#define LOG_MESSAGE_DEFINED +#undef LogMessage +#endif +#include "third_party/crashpad/wrapper/proto/crashpad_annotations.pb.h" +#ifdef LOG_MESSAGE_DEFINED +#define LogMessage MLogMessage +#endif namespace crashpad { @@ -44,9 +54,7 @@ #if defined(STARBOARD) constexpr char kEvergreenInfoKey[] = "evergreen-information"; -constexpr char kProductKey[] = "annotation=prod"; -constexpr char kVersionKey[] = "annotation=ver"; -constexpr char kUAKey[] = "annotation=user_agent_string"; +constexpr char kAnnotationKey[] = "annotation=%s"; #endif std::string FormatArgumentInt(const std::string& name, int value) { @@ -183,10 +191,10 @@ return SendEvergreenInfoImpl(); } - bool SendAnnotations(CrashpadAnnotations annotations) { - annotations_ = annotations; - return SendAnnotationsImpl(); + bool InsertAnnotation(const char* key, const char* value) { + return InsertAnnotationImpl(key, value); } + #endif // The base implementation for all signal handlers, suitable for calling @@ -227,7 +235,6 @@ #if defined(STARBOARD) const EvergreenInfo& GetEvergreenInfo() { return evergreen_info_; } - const CrashpadAnnotations& GetAnnotations() { return annotations_; } const SanitizationInformation& GetSanitizationInformation() { return sanitization_information_; } @@ -239,7 +246,7 @@ #if defined(STARBOARD) virtual bool SendEvergreenInfoImpl() = 0; - virtual bool SendAnnotationsImpl() = 0; + virtual bool InsertAnnotationImpl(const char* key, const char* value) = 0; #endif virtual void HandleCrashImpl() = 0; @@ -262,7 +269,6 @@ #if defined(STARBOARD) EvergreenInfo evergreen_info_; - CrashpadAnnotations annotations_; SanitizationInformation sanitization_information_; #endif @@ -297,12 +303,18 @@ argv_strings_.push_back(FormatArgumentAddress("trace-parent-with-exception", &GetExceptionInfo())); +#if defined(STARBOARD) + argv_strings_.push_back("--handler-started-at-crash"); +#endif + StringVectorToCStringVector(argv_strings_, &argv_); return Install(unhandled_signals); } #if defined(STARBOARD) bool SendEvergreenInfoImpl() override { + starboard::ScopedLock scoped_lock(argv_lock_); + bool updated = false; for (auto& s : argv_strings_) { if (s.compare(2, strlen(kEvergreenInfoKey), kEvergreenInfoKey) == 0) { @@ -324,27 +336,19 @@ return true; } - bool SendAnnotationsImpl() override { - bool updated_product = false; - bool updated_version = false; - bool updated_user_agent_string = false; + bool InsertAnnotationImpl(const char* key, const char* value) override { + starboard::ScopedLock scoped_lock(argv_lock_); + + std::string formatted_key = base::StringPrintf(kAnnotationKey, key); + bool updated_annotation = false; for (auto& s : argv_strings_) { - if (UpdateAnnotation(s, kProductKey, GetAnnotations().product)) { - updated_product = true; - } else if (UpdateAnnotation(s, kVersionKey, GetAnnotations().version)) { - updated_version = true; - } else if (UpdateAnnotation(s, kUAKey, GetAnnotations().user_agent_string)) { - updated_user_agent_string = true; + if (UpdateAnnotation(s, formatted_key, value)) { + updated_annotation = true; } } - if (!updated_product) { - AddAnnotation(argv_strings_, kProductKey, GetAnnotations().product); - } - if (!updated_version) { - AddAnnotation(argv_strings_, kVersionKey, GetAnnotations().version); - } - if (!updated_user_agent_string) { - AddAnnotation(argv_strings_, kUAKey, GetAnnotations().user_agent_string); + + if (!updated_annotation) { + AddAnnotation(argv_strings_, formatted_key, value); } StringVectorToCStringVector(argv_strings_, &argv_); @@ -382,6 +386,10 @@ std::vector<std::string> argv_strings_; std::vector<const char*> argv_; +#if defined(STARBOARD) + // Protects access to both argv_strings_ and argv_. + starboard::Mutex argv_lock_; +#endif std::vector<std::string> envp_strings_; std::vector<const char*> envp_; bool set_envp_ = false; @@ -446,6 +454,10 @@ } #if defined(STARBOARD) + char* GetSerializedAnnotations() { + return serialized_annotations_.data(); + } + bool SendEvergreenInfoImpl() override { ExceptionHandlerClient client(sock_to_handler_.get(), true); ExceptionHandlerProtocol::ClientInformation info = {}; @@ -455,13 +467,36 @@ return true; } - bool SendAnnotationsImpl() override { + bool InsertAnnotationImpl(const char* key, const char* value) override { + starboard::ScopedLock scoped_lock(annotations_lock_); + + std::string key_str(key); + std::string value_str(value); + + if (strcmp(key, "ver") == 0) { + annotations_.set_ver(value_str); + } else if (strcmp(key, "prod") == 0) { + annotations_.set_prod(value_str); + } else if (strcmp(key, "user_agent_string") == 0) { + annotations_.set_user_agent_string(value_str); + } else { + (*annotations_.mutable_runtime_annotations())[key_str] = value_str; + } + + serialized_annotations_.resize(annotations_.ByteSize()); + annotations_.SerializeToArray(serialized_annotations_.data(), + annotations_.ByteSize()); + ExceptionHandlerClient client(sock_to_handler_.get(), true); ExceptionHandlerProtocol::ClientInformation info = {}; - info.annotations_address = FromPointerCast<VMAddress>(&GetAnnotations()); + info.serialized_annotations_address = FromPointerCast<VMAddress>( + GetSerializedAnnotations()); + info.serialized_annotations_size = serialized_annotations_.size(); client.SendAnnotations(info); + return true; } + #endif void HandleCrashImpl() override { @@ -471,9 +506,12 @@ #if defined(STARBOARD) info.sanitization_information_address = FromPointerCast<VMAddress>(&GetSanitizationInformation()); - info.annotations_address = FromPointerCast<VMAddress>(&GetAnnotations()); + info.serialized_annotations_address = FromPointerCast<VMAddress>( + GetSerializedAnnotations()); + info.serialized_annotations_size = serialized_annotations_.size(); info.evergreen_information_address = FromPointerCast<VMAddress>(&GetEvergreenInfo()); + info.handler_start_type = ExceptionHandlerProtocol::kStartAtLaunch; #endif #if defined(OS_CHROMEOS) @@ -497,6 +535,13 @@ ScopedFileHandle sock_to_handler_; pid_t handler_pid_ = -1; +#if defined(STARBOARD) + crashpad::wrapper::CrashpadAnnotations annotations_; + std::vector<char> serialized_annotations_; + + // Protects access to both annotations_ and serialized_annotations_; + starboard::Mutex annotations_lock_; +#endif #if defined(OS_CHROMEOS) // An optional UNIX timestamp passed to us from Chrome. @@ -694,14 +739,14 @@ return SignalHandler::Get()->SendEvergreenInfo(evergreen_info); } -bool CrashpadClient::SendAnnotationsToHandler( - CrashpadAnnotations annotations) { +bool CrashpadClient::InsertAnnotationForHandler( + const char* key, const char* value) { if (!SignalHandler::Get()) { DLOG(ERROR) << "Crashpad isn't enabled"; return false; } - return SignalHandler::Get()->SendAnnotations(annotations); + return SignalHandler::Get()->InsertAnnotation(key, value); } bool CrashpadClient::SendSanitizationInformationToHandler(
diff --git a/third_party/crashpad/handler/handler_main.cc b/third_party/crashpad/handler/handler_main.cc index 51bd64e..cbf9bb5 100644 --- a/third_party/crashpad/handler/handler_main.cc +++ b/third_party/crashpad/handler/handler_main.cc
@@ -172,6 +172,9 @@ #if defined(STARBOARD) " --evergreen-information=EVERGREEN_INFORMATION_ADDRESS\n" " the address of a EvegreenInfo struct.\n" +" --handler-started-at-crash\n" +" the handler was started at time of crash, as\n" +" opposed to time of launch\n" #endif " --url=URL send crash reports to this Breakpad server URL,\n" " only if uploads are enabled for the database\n" @@ -214,6 +217,7 @@ bool shared_client_connection; #if defined(STARBOARD) VMAddress evergreen_information_address; + bool handler_started_at_crash = false; #endif // defined(STARBOARD) #if defined(OS_ANDROID) bool write_minidump_to_log; @@ -590,6 +594,7 @@ kOptionTraceParentWithException, #if defined(STARBOARD) kOptionEvergreenInformaton, + kOptionHandlerStartedAtCrash, #endif // defined(STARBOARD) #endif kOptionURL, @@ -676,6 +681,10 @@ required_argument, nullptr, kOptionEvergreenInformaton}, + {"handler-started-at-crash", + no_argument, + nullptr, + kOptionHandlerStartedAtCrash}, #endif {"url", required_argument, nullptr, kOptionURL}, #if defined(OS_CHROMEOS) @@ -850,6 +859,10 @@ } break; } + case kOptionHandlerStartedAtCrash: { + options.handler_started_at_crash = true; + break; + } #endif // defined(STARBOARD) #endif // OS_LINUX || OS_ANDROID case kOptionURL: { @@ -1070,6 +1083,9 @@ #if defined(STARBOARD) info.evergreen_information_address = options.evergreen_information_address; + if (options.handler_started_at_crash) { + info.handler_start_type = ExceptionHandlerProtocol::kStartAtCrash; + } #endif // defined(STARBOARD) return exception_handler->HandleException(getppid(), geteuid(), info) ? EXIT_SUCCESS
diff --git a/third_party/crashpad/handler/linux/capture_snapshot.cc b/third_party/crashpad/handler/linux/capture_snapshot.cc index 8fb0735..59350fd 100644 --- a/third_party/crashpad/handler/linux/capture_snapshot.cc +++ b/third_party/crashpad/handler/linux/capture_snapshot.cc
@@ -31,19 +31,15 @@ VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, std::unique_ptr<ProcessSnapshotLinux>* snapshot, - std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot -#if defined(STARBOARD) - , - VMAddress evergreen_information_address, - VMAddress annotations_address -#endif - ) { + std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot) { std::unique_ptr<ProcessSnapshotLinux> process_snapshot( new ProcessSnapshotLinux()); #if defined(STARBOARD) if (!process_snapshot->Initialize(connection, info.evergreen_information_address, - info.annotations_address)) { + info.serialized_annotations_address, + info.serialized_annotations_size, + info.handler_start_type)) { #else if (!process_snapshot->Initialize(connection)) { #endif
diff --git a/third_party/crashpad/handler/linux/capture_snapshot.h b/third_party/crashpad/handler/linux/capture_snapshot.h index 51eca35..b01e316 100644 --- a/third_party/crashpad/handler/linux/capture_snapshot.h +++ b/third_party/crashpad/handler/linux/capture_snapshot.h
@@ -64,13 +64,7 @@ VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, std::unique_ptr<ProcessSnapshotLinux>* process_snapshot, - std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot -#if defined(STARBOARD) - , - VMAddress evergreen_information_address, - VMAddress annotations_address -#endif - ); + std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot); } // namespace crashpad
diff --git a/third_party/crashpad/handler/linux/crash_report_exception_handler.cc b/third_party/crashpad/handler/linux/crash_report_exception_handler.cc index b0f68ce..9a86073 100644 --- a/third_party/crashpad/handler/linux/crash_report_exception_handler.cc +++ b/third_party/crashpad/handler/linux/crash_report_exception_handler.cc
@@ -89,7 +89,8 @@ bool CrashReportExceptionHandler::AddAnnotations( const ExceptionHandlerProtocol::ClientInformation& info) { - annotations_address_ = info.annotations_address; + serialized_annotations_address_ = info.serialized_annotations_address; + serialized_annotations_size_ = info.serialized_annotations_size; return true; } #endif @@ -153,13 +154,7 @@ requesting_thread_stack_address, requesting_thread_id, &process_snapshot, - &sanitized_snapshot -#if defined(STARBOARD) - , - evergreen_info_, - annotations_address_ -#endif - )) { + &sanitized_snapshot)) { return false; }
diff --git a/third_party/crashpad/handler/linux/crash_report_exception_handler.h b/third_party/crashpad/handler/linux/crash_report_exception_handler.h index 5cca2ad..7a32ac0 100644 --- a/third_party/crashpad/handler/linux/crash_report_exception_handler.h +++ b/third_party/crashpad/handler/linux/crash_report_exception_handler.h
@@ -122,7 +122,8 @@ const UserStreamDataSources* user_stream_data_sources_; // weak #if defined(STARBOARD) VMAddress evergreen_info_; - VMAddress annotations_address_; + VMAddress serialized_annotations_address_; + int serialized_annotations_size_; #endif DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler);
diff --git a/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc b/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc index 5fe900b..48fdb11 100644 --- a/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc +++ b/third_party/crashpad/snapshot/linux/process_snapshot_linux.cc
@@ -20,7 +20,16 @@ #include "util/linux/exception_information.h" #if defined(STARBOARD) -#include "third_party/crashpad/wrapper/annotations.h" +#include "third_party/crashpad/util/linux/exception_handler_protocol.h" +// TODO(b/201538792): resolve conflict between mini_chromium and base functions. +#ifdef LogMessage +#define LOG_MESSAGE_DEFINED +#undef LogMessage +#endif +#include "third_party/crashpad/wrapper/proto/crashpad_annotations.pb.h" +#ifdef LOG_MESSAGE_DEFINED +#define LogMessage MLogMessage +#endif #endif namespace crashpad { @@ -56,7 +65,9 @@ #if defined(STARBOARD) bool ProcessSnapshotLinux::Initialize(PtraceConnection* connection, VMAddress evergreen_information_address, - VMAddress annotations_address) { + VMAddress serialized_annotations_address, + int serialized_annotations_size, + ExceptionHandlerProtocol::HandlerStartType handler_start_type) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); if (gettimeofday(&snapshot_time_, nullptr) != 0) { @@ -70,15 +81,10 @@ return false; } - CrashpadAnnotations annotations; - if (!memory_range_.Read( - annotations_address, sizeof(CrashpadAnnotations), &annotations)) { - LOG(ERROR) << "Could not read annotations"; + if (handler_start_type == ExceptionHandlerProtocol::kStartAtCrash) { + LOG(INFO) << "Annotations do not need to be read from client process"; } else { - AddAnnotation("user_agent_string", - std::string(annotations.user_agent_string)); - AddAnnotation("prod", std::string(annotations.product)); - AddAnnotation("ver", std::string(annotations.version)); + AddAnnotations(serialized_annotations_address, serialized_annotations_size); } system_.Initialize(&process_reader_, &snapshot_time_); @@ -90,6 +96,33 @@ INITIALIZATION_STATE_SET_VALID(initialized_); return true; } + +void ProcessSnapshotLinux::AddAnnotations( + VMAddress serialized_annotations_address, int serialized_annotations_size) { + std::vector<char> buffer(serialized_annotations_size); + if (!memory_range_.Read(serialized_annotations_address, + serialized_annotations_size, + buffer.data())) { + LOG(ERROR) << "Could not read annotations"; + return; + } + + crashpad::wrapper::CrashpadAnnotations annotations; + if (!annotations.ParseFromArray(buffer.data(), serialized_annotations_size)) { + LOG(ERROR) << "Could not parse annotations"; + return; + } + + AddAnnotation("user_agent_string", + std::string(annotations.user_agent_string())); + AddAnnotation("prod", std::string(annotations.prod())); + AddAnnotation("ver", std::string(annotations.ver())); + + for (auto& runtime_annotation : annotations.runtime_annotations()) { + AddAnnotation(runtime_annotation.first, runtime_annotation.second); + } + LOG(INFO) << "Annotations successfully added from client process"; +} #endif pid_t ProcessSnapshotLinux::FindThreadWithStackAddress(
diff --git a/third_party/crashpad/snapshot/linux/process_snapshot_linux.h b/third_party/crashpad/snapshot/linux/process_snapshot_linux.h index 8cd9ef5..0d20528 100644 --- a/third_party/crashpad/snapshot/linux/process_snapshot_linux.h +++ b/third_party/crashpad/snapshot/linux/process_snapshot_linux.h
@@ -45,6 +45,7 @@ #if defined(STARBOARD) #include "snapshot/module_snapshot_evergreen.h" #include "starboard/elf_loader/evergreen_info.h" +#include "third_party/crashpad/util/linux/exception_handler_protocol.h" #endif namespace crashpad { @@ -77,7 +78,9 @@ //! an appropriate message logged. bool Initialize(PtraceConnection* connnection, VMAddress evergreen_information_address, - VMAddress annotations_address); + VMAddress serialized_annotations_address, + int serialized_annotations_size, + ExceptionHandlerProtocol::HandlerStartType handler_start_type); #endif //! \brief Finds the thread whose stack contains \a stack_address. @@ -158,6 +161,8 @@ void InitializeModules(); #if defined(STARBOARD) void InitializeModules(VMAddress evergreen_information_address); + void AddAnnotations(VMAddress serialized_annotations_address, + int serialized_annotations_size); #endif void InitializeAnnotations();
diff --git a/third_party/crashpad/util/linux/exception_handler_protocol.cc b/third_party/crashpad/util/linux/exception_handler_protocol.cc index b139017..5f58721 100644 --- a/third_party/crashpad/util/linux/exception_handler_protocol.cc +++ b/third_party/crashpad/util/linux/exception_handler_protocol.cc
@@ -26,7 +26,9 @@ #if defined(STARBOARD) , evergreen_information_address(0), - annotations_address(0) + serialized_annotations_address(0), + serialized_annotations_size(0), + handler_start_type(kStartAtLaunch) #endif { }
diff --git a/third_party/crashpad/util/linux/exception_handler_protocol.h b/third_party/crashpad/util/linux/exception_handler_protocol.h index 4cc1662..4f94bd9 100644 --- a/third_party/crashpad/util/linux/exception_handler_protocol.h +++ b/third_party/crashpad/util/linux/exception_handler_protocol.h
@@ -38,6 +38,12 @@ //! \brief A boolean status suitable for communication between processes. enum Bool : char { kBoolFalse, kBoolTrue }; +#if defined(STARBOARD) + //! \brief Describes when, in the client process lifecycle, the Crashpad + //! handler was or will be started. + enum HandlerStartType : char { kStartAtCrash, kStartAtLaunch }; +#endif + //! \brief Information about a client registered with an //! ExceptionHandlerServer. struct ClientInformation { @@ -57,9 +63,15 @@ //! struct, or 0 if there is no such struct. VMAddress evergreen_information_address; - //! \brief The address in the client's address space of an - //! CrashpadAnnotations struct, or 0 if there is no such struct. - VMAddress annotations_address; + //! \brief The address in the client's address space of a character array + //! containing a serialized CrashpadAnnotations proto, or 0 if there is + //! no such address. + VMAddress serialized_annotations_address; + + //! \brief The byte size of the serialized annotations. + int serialized_annotations_size; + + HandlerStartType handler_start_type; #endif #if defined(OS_LINUX)
diff --git a/third_party/crashpad/wrapper/proto/crashpad_annotations.proto b/third_party/crashpad/wrapper/proto/crashpad_annotations.proto index eb739bc..8eb6205 100644 --- a/third_party/crashpad/wrapper/proto/crashpad_annotations.proto +++ b/third_party/crashpad/wrapper/proto/crashpad_annotations.proto
@@ -22,10 +22,10 @@ // Next id: 5 message CrashpadAnnotations { // The product name. - string product = 1; + string prod = 1; // The product version. - string version = 2; + string ver = 2; // The User-Agent string that identifies brand, model, etc. string user_agent_string = 3;
diff --git a/third_party/crashpad/wrapper/wrapper.cc b/third_party/crashpad/wrapper/wrapper.cc index 8f19a70..700f9b7 100644 --- a/third_party/crashpad/wrapper/wrapper.cc +++ b/third_party/crashpad/wrapper/wrapper.cc
@@ -33,8 +33,11 @@ namespace crashpad { namespace wrapper { -namespace { +const char kCrashpadVersionKey[] = "ver"; +const char kCrashpadProductKey[] = "prod"; +const char kCrashpadUserAgentStringKey[] = "user_agent_string"; +namespace { // TODO: Get evergreen information from installation. const std::string kCrashpadVersion = "1.0.0.0"; #if defined(STARBOARD_BUILD_TYPE_GOLD) @@ -215,9 +218,9 @@ return client->SendEvergreenInfoToHandler(evergreen_info); } -bool AddAnnotationsToCrashpad(CrashpadAnnotations annotations) { +bool InsertCrashpadAnnotation(const char* key, const char* value) { ::crashpad::CrashpadClient* client = GetCrashpadClient(); - return client->SendAnnotationsToHandler(annotations); + return client->InsertAnnotationForHandler(key, value); } } // namespace wrapper
diff --git a/third_party/crashpad/wrapper/wrapper.h b/third_party/crashpad/wrapper/wrapper.h index 4def1a8..be60fec 100644 --- a/third_party/crashpad/wrapper/wrapper.h +++ b/third_party/crashpad/wrapper/wrapper.h
@@ -16,17 +16,28 @@ #define THIRD_PARTY_CRASHPAD_WRAPPER_WRAPPER_H_ #include "starboard/elf_loader/evergreen_info.h" // nogncheck -#include "third_party/crashpad/wrapper/annotations.h" namespace third_party { namespace crashpad { namespace wrapper { +// The key name used in Crashpad for the version annotation. +extern const char kCrashpadVersionKey[]; + +// The key name used in Crashpad for the version annotation. +extern const char kCrashpadProductKey[]; + +// The key name used in Crashpad for the user_agent_string annotation. +extern const char kCrashpadUserAgentStringKey[]; + void InstallCrashpadHandler(bool start_at_crash); bool AddEvergreenInfoToCrashpad(EvergreenInfo evergreen_info); -bool AddAnnotationsToCrashpad(CrashpadAnnotations annotations); +// Associates the given value with the given key in Crashpad's map of +// annotations, updating the existing value if the map already contains the +// key. Returns true on success and false on failure. +bool InsertCrashpadAnnotation(const char* key, const char* value); } // namespace wrapper } // namespace crashpad
diff --git a/third_party/crashpad/wrapper/wrapper_stub.cc b/third_party/crashpad/wrapper/wrapper_stub.cc index bf3c093..f96dd94 100644 --- a/third_party/crashpad/wrapper/wrapper_stub.cc +++ b/third_party/crashpad/wrapper/wrapper_stub.cc
@@ -18,13 +18,17 @@ namespace crashpad { namespace wrapper { +const char kCrashpadVersionKey[] = ""; +const char kCrashpadProductKey[] = ""; +const char kCrashpadUserAgentStringKey[] = ""; + void InstallCrashpadHandler(bool start_at_crash) {} bool AddEvergreenInfoToCrashpad(EvergreenInfo evergreen_info) { return false; } -bool AddAnnotationsToCrashpad(CrashpadAnnotations annotations) { +bool InsertCrashpadAnnotation(const char* key, const char* value) { return false; }