Import Cobalt 20.lts.3.244012
diff --git a/src/cobalt/CHANGELOG.md b/src/cobalt/CHANGELOG.md
index 70b84b5..aa05c04 100644
--- a/src/cobalt/CHANGELOG.md
+++ b/src/cobalt/CHANGELOG.md
@@ -180,6 +180,12 @@
minimum framerate causing Cobalt to rerender the display even if nothing has
changed after the specified interval.
+### Version 20.lts.3
+ - **Improvements and Bug Fixes**
+
+ - Fix a bug where deep links that are fired before the WebModule is loaded
+ were ignored. Now Cobalt stores the last deep link fired before WebModule
+ is loaded & handles the deep link once the WebModule is loaded.
## Version 19
- **Add support for V8 JavaScript Engine**
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 4bc47a5..e912fc3 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-238772
\ No newline at end of file
+244012
\ No newline at end of file
diff --git a/src/cobalt/build/cobalt_configuration.gypi b/src/cobalt/build/cobalt_configuration.gypi
index 9feeca1..05ff945 100644
--- a/src/cobalt/build/cobalt_configuration.gypi
+++ b/src/cobalt/build/cobalt_configuration.gypi
@@ -230,7 +230,7 @@
# Set to "true" to enable v8 snapshot generation at Cobalt build time.
'cobalt_v8_buildtime_snapshot%': '<(cobalt_v8_buildtime_snapshot)',
- 'cobalt_enable_quic': 1,
+ 'cobalt_enable_quic%': 1,
# Cache parameters
diff --git a/src/cobalt/tools/automated_testing/cobalt_runner.py b/src/cobalt/tools/automated_testing/cobalt_runner.py
index c710a3a..0e6f30e 100644
--- a/src/cobalt/tools/automated_testing/cobalt_runner.py
+++ b/src/cobalt/tools/automated_testing/cobalt_runner.py
@@ -11,6 +11,7 @@
import thread
import threading
import time
+import traceback
import _env # pylint: disable=unused-import
from cobalt.tools.automated_testing import c_val_names
@@ -251,9 +252,18 @@
def _KillLauncher(self):
"""Kills the launcher and its attached Cobalt instance."""
- self.ExecuteJavaScript('window.close();')
+ wait_for_runner_thread = True
+ if self.CanExecuteJavaScript():
+ try:
+ self.ExecuteJavaScript('window.close();')
+ except Exception:
+ wait_for_runner_thread = False
+ sys.stderr.write(
+ '***An exception was raised while trying to close the app:')
+ traceback.print_exc(file=sys.stderr)
- self.runner_thread.join(COBALT_EXIT_TIMEOUT_SECONDS)
+ if wait_for_runner_thread:
+ self.runner_thread.join(COBALT_EXIT_TIMEOUT_SECONDS)
if self.runner_thread.isAlive():
sys.stderr.write(
'***Runner thread still alive after sending graceful shutdown command, try again by killing app***\n'
@@ -309,6 +319,9 @@
thread.interrupt_main()
return 0
+ def CanExecuteJavaScript(self):
+ return self.webdriver is not None
+
def ExecuteJavaScript(self, js_code):
return self.webdriver.execute_script(js_code)
@@ -496,7 +509,7 @@
device_params.config = args.config
device_params.device_id = args.device_id
device_params.out_directory = args.out_directory
- if args.target_params == None:
+ if args.target_params is None:
device_params.target_params = []
else:
device_params.target_params = [args.target_params]
diff --git a/src/starboard/__init__.py b/src/starboard/__init__.py
index b2efd6d..1710e45 100644
--- a/src/starboard/__init__.py
+++ b/src/starboard/__init__.py
@@ -12,6 +12,7 @@
# 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.
+
"""Initialization for the starboard package."""
# Provide a holder for the config package to insert an adapter for platforms
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
index 63d27d8..1c597b2 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
@@ -101,6 +101,7 @@
public static final String VIDEO_H265 = "video/hevc";
public static final String VIDEO_VP8 = "video/x-vnd.on2.vp8";
public static final String VIDEO_VP9 = "video/x-vnd.on2.vp9";
+ public static final String VIDEO_AV1 = "video/av01";
}
private BitrateAdjustmentTypes mBitrateAdjustmentType = BitrateAdjustmentTypes.NO_ADJUSTMENT;
@@ -858,6 +859,7 @@
break;
case MimeTypes.VIDEO_H265:
case MimeTypes.VIDEO_VP9:
+ case MimeTypes.VIDEO_AV1:
maxPixels = maxWidth * maxHeight;
minCompressionRatio = 4;
break;
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
index ee85466..24fe96f 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaDrmBridge.java
@@ -110,10 +110,12 @@
this.mErrorMessage = errorMessage;
}
+ @UsedByNative
public boolean isSuccess() {
return mIsSuccess;
}
+ @UsedByNative
public String getErrorMessage() {
return mErrorMessage;
}
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java
index 315e679..c471b0c 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/storage/CobaltStorageLoader.java
@@ -16,8 +16,8 @@
import static dev.cobalt.util.Log.TAG;
+import android.os.FileObserver;
import android.support.annotation.Nullable;
-import android.text.TextUtils;
import com.google.protobuf.InvalidProtocolBufferException;
import dev.cobalt.storage.StorageProto.Storage;
import dev.cobalt.util.Log;
@@ -27,9 +27,13 @@
import java.io.IOException;
import java.util.Arrays;
-/** A class to load Cobalt storage from the file system. */
+/**
+ * A class to load Cobalt storage from the file system.
+ */
public class CobaltStorageLoader {
+
private final File filesDir;
+ private final StorageFileObserver fileObserver;
private static final String STORAGE_NAME_PREFIX = ".starboard";
private static final String STORAGE_NAME_SUFFIX = ".storage";
@@ -45,6 +49,7 @@
throw new IllegalArgumentException("A valid filesDir object is required");
}
this.filesDir = filesDir;
+ this.fileObserver = StorageFileObserver.create(filesDir);
}
/**
@@ -57,14 +62,20 @@
if (fileName == null) {
return Storage.getDefaultInstance();
}
- byte[] storageBlob = getStorageBlob(fileName);
+ Storage storage = loadStorageFile(new File(filesDir, fileName));
+ return (storage != null) ? storage : Storage.getDefaultInstance();
+ }
+
+ @Nullable
+ private static Storage loadStorageFile(File file) {
+ byte[] storageBlob = getStorageBlob(file);
if (storageBlob == null) {
Log.e(TAG, "Failed to get storage blob");
- return Storage.getDefaultInstance();
+ return null;
}
if (!validateStorageBlob(storageBlob)) {
Log.e(TAG, "Invalid storage blob");
- return Storage.getDefaultInstance();
+ return null;
}
storageBlob = Arrays.copyOfRange(storageBlob, STORAGE_HEADER.length(), storageBlob.length);
try {
@@ -72,10 +83,10 @@
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Failed parsing the blob", e);
}
- return Storage.getDefaultInstance();
+ return null;
}
- private boolean validateStorageBlob(byte[] storageBlob) {
+ private static boolean validateStorageBlob(byte[] storageBlob) {
if (storageBlob == null || storageBlob.length < STORAGE_HEADER.length()) {
return false;
}
@@ -84,12 +95,8 @@
}
@Nullable
- private byte[] getStorageBlob(String fileName) {
- if (TextUtils.isEmpty(fileName)) {
- Log.e(TAG, "Invalid empty file name");
- return null;
- }
- try (FileInputStream in = new FileInputStream(new File(filesDir, fileName));
+ private static byte[] getStorageBlob(File file) {
+ try (FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
byte[] buffer = new byte[8192];
int len;
@@ -111,7 +118,7 @@
return null;
}
for (String fileName : fileNames) {
- if (fileName.startsWith(STORAGE_NAME_PREFIX) && fileName.endsWith(STORAGE_NAME_SUFFIX)) {
+ if (isStorageFile(fileName)) {
File storageFile = new File(filesDir, fileName);
if (storageFile.length() > 0) {
return fileName;
@@ -121,4 +128,73 @@
Log.w(TAG, "Failed to find storage file name");
return null;
}
+
+ private static boolean isStorageFile(String fileName) {
+ return fileName != null
+ && fileName.startsWith(STORAGE_NAME_PREFIX)
+ && fileName.endsWith(STORAGE_NAME_SUFFIX);
+ }
+
+ /**
+ * Set the observer to be notified when storage changes.
+ *
+ * @param storageObserver will be called when storage changes.
+ */
+ public void setObserver(@Nullable CobaltStorageObserver storageObserver) {
+ fileObserver.setStorageObserver(storageObserver);
+ }
+
+ /**
+ * Observer that is called when Cobalt storage changes.
+ */
+ public interface CobaltStorageObserver {
+
+ /**
+ * Called when Cobalt storage changes.
+ *
+ * <p>This method is invoked on a special thread. It runs independently of any threads, so take
+ * care to use appropriate synchronization! Consider using Handler#post(Runnable) to shift event
+ * handling work to the main thread to avoid concurrency problems.
+ *
+ * @param snapshot the Cobalt storage as a proto message.
+ */
+ void onCobaltStorageChanged(Storage snapshot);
+ }
+
+ private static class StorageFileObserver extends FileObserver {
+
+ private final File filesDir;
+ private CobaltStorageObserver storageObserver = null;
+
+ static StorageFileObserver create(File filesDir) {
+ return new StorageFileObserver(filesDir.getAbsolutePath());
+ }
+
+ StorageFileObserver(String filesDirPath) {
+ super(filesDirPath, MOVED_TO);
+ this.filesDir = new File(filesDirPath);
+ }
+
+ void setStorageObserver(@Nullable CobaltStorageObserver storageObserver) {
+ if (this.storageObserver != null) {
+ stopWatching();
+ }
+ this.storageObserver = storageObserver;
+ if (this.storageObserver != null) {
+ startWatching();
+ }
+ }
+
+ @Override
+ public void onEvent(int event, @Nullable String fileName) {
+ // Expect a MOVED_TO event since SbStorageWrite() creates a temp file then moves it in place.
+ if (event != MOVED_TO || storageObserver == null || !isStorageFile(fileName)) {
+ return;
+ }
+ Storage storage = loadStorageFile(new File(filesDir, fileName));
+ if (storage != null) {
+ storageObserver.onCobaltStorageChanged(storage);
+ }
+ }
+ }
}
diff --git a/src/starboard/android/shared/cobalt/configuration.gypi b/src/starboard/android/shared/cobalt/configuration.gypi
index 35647ce..27b99cd 100644
--- a/src/starboard/android/shared/cobalt/configuration.gypi
+++ b/src/starboard/android/shared/cobalt/configuration.gypi
@@ -22,6 +22,8 @@
'enable_account_manager': 1,
'enable_map_to_mesh': 1,
+ 'cobalt_enable_quic': 0,
+
# Some Android devices do not advertise their support for
# EGL_SWAP_BEHAVIOR_PRESERVED_BIT properly, so, we play it safe and disable
# relying on it for Android.
diff --git a/src/starboard/android/shared/media_common.h b/src/starboard/android/shared/media_common.h
index 9e47335..2402f6a 100644
--- a/src/starboard/android/shared/media_common.h
+++ b/src/starboard/android/shared/media_common.h
@@ -59,6 +59,8 @@
return "video/x-vnd.on2.vp9";
} else if (video_codec == kSbMediaVideoCodecH264) {
return "video/avc";
+ } else if (video_codec == kSbMediaVideoCodecAv1) {
+ return "video/av01";
}
return NULL;
}
diff --git a/src/starboard/android/shared/player_create.cc b/src/starboard/android/shared/player_create.cc
index ffa2260..7edd8d6 100644
--- a/src/starboard/android/shared/player_create.cc
+++ b/src/starboard/android/shared/player_create.cc
@@ -76,7 +76,8 @@
if (video_codec != kSbMediaVideoCodecNone &&
video_codec != kSbMediaVideoCodecH264 &&
- video_codec != kSbMediaVideoCodecVp9) {
+ video_codec != kSbMediaVideoCodecVp9 &&
+ video_codec != kSbMediaVideoCodecAv1) {
SB_LOG(ERROR) << "Unsupported video codec " << video_codec;
return kSbPlayerInvalid;
}
diff --git a/src/starboard/tools/port_symlink.py b/src/starboard/tools/port_symlink.py
new file mode 100644
index 0000000..a4a8762
--- /dev/null
+++ b/src/starboard/tools/port_symlink.py
@@ -0,0 +1,6 @@
+"""A redirect for new build code to find the old port_symlink.py location."""
+
+import os
+
+execfile(os.path.join(os.path.dirname(__file__), os.pardir, 'build',
+ 'port_symlink.py'))