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;
}