🔷

Cobalt ブラウザの設計が変わったっぽいので、最新版をビルドする

に公開

概要

注意事項

2025/07/21 の時点でリリースされていないバージョンに関する話題となります。
情報不足のため、本記事の情報は変更され使えなくなる可能性があります。

main ブランチの以下のコミットを対象としています。

$ git log -n1 1a8503595eaff31dc51de4767aaf6f2e42ee2c14
commit 1a8503595eaff31dc51de4767aaf6f2e42ee2c14
Author: Bo-Rong Chen <borongchen@google.com>
Date:   Tue Jul 15 10:46:36 2025 -0700

    [POSIX] Implement statvfs in Starboard API (#6340)

以下のタグも似たようなバージョンのものなので試しています。
https://github.com/youtube/cobalt/releases/tag/kimono_6.15.300

$ git log -n1 kimono_6.15.300
commit a0d9d911a831534eb15822f3c2ffee2e1c681863 (HEAD, tag: kimono_6.15.300)
Author: cobalt-github-releaser-bot <95661244+cobalt-github-releaser-bot@users.noreply.github.com>
Date:   Tue Jul 22 20:53:46 2025 -0700

    Cherry pick PR #6460: Use a copy of ContextLifecycleObserver for exit notifications (#6553)

kimono が何なのか分からない状態で記事を書いています。

Cobalt とは

A high-performance, small-footprint platform that implements a subset of HTML5/CSS/JS to run applications, including the YouTube TV app.

https://developers.google.com/youtube/cobalt/docs/overview

YouTube TV という組み込み環境向けの YouTube をさまざまな環境で動かすための Chromium ベースのブラウザです。移植層は Starboard と呼ばれ、組み込みを行う人は Starboard をカスタマイズするだけで好きな環境に YouTube TV を組み込めます。

最近の動向

現在リリースされている Cobalt は Chromium ベースであるものの、Chromium に関連するコードの多くは一旦削除され、再構成されていました。ブラウザの機能も最小限に抑えることで、軽量なブラウザを再現していますが、一方で大幅な機能削減のため、ほとんどのウェブサイトでは表示が崩れます。

現在の最新の実装では、改めて Chromium のコードを残すような状態で Cobalt が再設計されています。機能の削減も大幅には行われておらず、多くのウェブサイトの表示が可能になっています。

手順

ドキュメント整備前のためか公式 Web サイト上のどこにもありませんが、手順は Chromium と同様です。

環境

ビルド環境: Ubuntu 20.04 (Docker, x64)
実行環境(Linux): Ubuntu 22.04 (X11, x64)
実行環境(Android): Android 12 (Tablet, arm32)

ソースコードの取得

depot_tools を準備します。自動で更新しようとするため、DEPOT_TOOLS_UPDATE=0 を設定します。
Cobalt のバージョンと depot_tools のバージョンに大きな差があると、期待する挙動にならないことがあります。

$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git /opt/depot_tools
$ export PATH=/opt/depot_tools:$PATH
$ export DEPOT_TOOLS_UPDATE=0

作業ディレクトリ(以降 /mnt/work/cobalt とします)に移動し、リポジトリをダウンロードするための .gclient を作成します。

solutions = [
  {
    "url": "https://github.com/youtube/cobalt.git@1a8503595eaff31dc51de4767aaf6f2e42ee2c14",
    "managed": False,
    "name": "src",
    "deps_file": "DEPS",
    "custom_deps": {},
  },
]
target_os = ["linux", "android"]

gclient sync で Cobalt と関連するサブリポジトリをダウンロードします。
うまく動かない場合は、depot_tools のバージョンを Cobalt のリポジトリに含まれるものと同じにしたり、Python のバージョンを変えてみたりしてください。
バージョン更新後改めて取得するには、不要なディレクトリの削除と更新を行うために gclient sync -j 4 -D --force とします

$ cd /mnt/work/cobalt
$ gclient sync -j 4

ビルドツールのインストール

スクリプト内部で apt-get が走るので sudo 権限が必要になります。

$ bash src/build/install-build-deps.sh --backwards-compatible \
  --no-prompt --syms --android --lib32 --arm --chromeos-fonts

ビルドと実行 (Linux x64)

次のステップでビルドします。

  • ビルドディレクトリを作成し、args.gn を設定する
  • gn gen を実行し ninja ファイルを作成する
  • ninja または autoninja でビルド実行

args.gn の設定

$ mkdir -p src/out/default-linux
$ cd src/out/default-linux
$ vim args.gn
...
$ gn gen .

args.gn に何を書くかについてですが、//cobalt/build/configs/linux-x64x11/args.gn に基本設定が書かれているので、これをベースに設定します。
import 文で基本設定をインポートし、必要に応じて設定を追加します。

target_platform = "linux-x64x11"  # starboard/build/platforms.py から探す!
target_os = "linux"
target_cpu = "x64"

is_component_build = false
use_v8_context_snapshot = false
enable_plugins = false
enable_pdf = false

import("//cobalt/build/configs/linux-x64x11/args.gn")

target_platform, target_os, target_cpu はターゲット環境の設定です。
それ以外はワークアラウンドです。後の更新で修正されるでしょう

  • is_component_build = false
    • GLES周りでリンクエラーが発生するため、その抑制。is_component_build = true にすると、より多くの shared object に分割しようとします。
  • use_v8_context_snapshot = false
    • 同じくリンクエラー対策。ビルドも時間掛かるので機能ごと無効化します
  • enable_plugins = false, enable_pdf = false
    • //ppapi/proxy/BUILD.gn:9:1 辺りのエラー対策。プラグインや PDF 関連の機能を無効化します。

ビルド

$ cd src/out/default-linux
$ autoninja cobalt

起動

EGL_BAD_MATCH が発生しがちなので、 Xephyr を経由して起動すると良いです。

別ターミナルで、以下コマンドを実行して Xephyr を起動します。

$ Xephyr :9 -softCursor -screen 1920x1080

以下コマンドで Cobalt を起動します。画面は Xephyr に表示されるはずです。

$ DISPLAY=:9 ./cobalt --data-path=/tmp/cobalt

kimono_6.15.300 版を実行すると何故かツールバーが表示されるので、以下の引数で無効化します。

$ DISPLAY=:9 ./cobalt --content-shell-hide-toolbar --data-path=/tmp/cobalt

URL を指定するときは、コマンドライン引数に追記します。

$ DISPLAY=:9 ./cobalt --content-shell-hide-toolbar  --data-path=/tmp/cobalt http://abehiroshi.la.coocan.jp/

ビルドと実行 (Anrdoid arm32)

Linux と同様の手順です。gn gen で ninja を生成します。

$ mkdir -p src/out/default-android
$ cd src/out/default-android
$ vim args.gn
...
$ gn gen .

Android は、//cobalt/build/configs/android-arm/args.gn を参照します

is_component_build = false

import("//cobalt/build/configs/android-arm/args.gn")

ビルドターゲットは cobalt_apk です。

$ cd src/out/default-android
$ autoninja cobalt/android:cobalt_apk

ビルドが成功したら apk が生成されるので adb を使ってインストールします。

$ adb install -g -r ./src/out/default-android/apks/Cobalt.apk

トラブルシューティング

ビルド

Channel::SupportsChannelUpgrade でビルドが失敗する

この部分でビルドが失敗したので、以下のような変更が必要でした。(1a850359ビルド時)

--- a/mojo/core/channel_posix.cc
+++ b/mojo/core/channel_posix.cc
@@ -711,6 +711,14 @@ void Channel::OfferChannelUpgrade() {
 }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
         // BUILDFLAG(IS_ANDROID)
+#else
+// static
+bool Channel::SupportsChannelUpgrade() {
+  return false;
+}
+
+void Channel::OfferChannelUpgrade() {
+}
 #endif  // !BUILDFLAG(IS_NACL)
 
 }  // namespace core

起動

以下はすべてではありません。コンテンツによっては頻繁にクラッシュします。簡単な修正例を挙げます。

GetInputDeviceInfo で SIGSEGV

# Received signal 11 SEGV_MAPERR 000000000028
# #0 0x55a3de3eb5cc base::debug::CollectStackTrace()
# #1 0x55a3de3bf51a base::debug::StackTrace::StackTrace()
# #2 0x55a3de3bf4d5 base::debug::StackTrace::StackTrace()
# #3 0x55a3de3eb013 base::debug::(anonymous namespace)::StackDumpSignalHandler()
# #4 0x74d758842520 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x4251f)
# #5 0x74d759b7b8dc starboard::shared::dev_input::(anonymous namespace)::ControllerTuning::GetMinimumFlat()
# #6 0x74d759b774bb starboard::shared::dev_input::(anonymous namespace)::GetInputDeviceAbsoluteAxisInfo()
# #7 0x74d759b76f9b starboard::shared::dev_input::(anonymous namespace)::GetInputDeviceInfo()
# #8 0x74d759b759db starboard::shared::dev_input::(anonymous namespace)::GetInputDevices()
# #9 0x74d759b755d3 starboard::shared::dev_input::(anonymous namespace)::DevInputImpl::DevInputImpl()
# #10 0x74d759b7557c starboard::shared::dev_input::DevInput::Create()
# #11 0x74d759b248ee starboard::shared::x11::ApplicationX11::CreateWindow()
# #12 0x74d759b3974d SbWindowCreate

ゲームコントローラーを接続している場合は外しておく。
心当たりがない場合は、以下のようにログを仕込めば名前を確認できます。

//starboard/shared/linux/dev_input/dev_input.cc
void GetInputDeviceInfo(InputDeviceInfo* info) {
  char device_name[1024];
  if (ioctl(info->fd, EVIOCGNAME(sizeof(device_name)), device_name) >= 0) {
    size_t length = strnlen(device_name, sizeof(device_name));
    info->name.assign(device_name, length);
  }

  // Log the device name.
  SB_LOG(INFO) << __FUNCTION__ << ": "
             << "@@@@@@@@ input device: \"" << info->name << "\"";

  info->tuning = DeviceMap::Get()->GetControllerTuning(info->name);  // << SIGSEGV

Check failed: surface_ozone.

https://example.com を開いても発生する場合、少し前に以下のようなのエラーが出ていませんか?
Xephyr が正しく使えているか確認してください。

[24349:Chrome_InProcGpuThread/24361:0723/035448.346343:ERROR:gl_display.cc(520)] EGL Driver message (Error) eglCreateWindowSurface: eglCreateWindowSurface failed
[24349:Chrome_InProcGpuThread/24361:0723/035448.346382:ERROR:gl_surface_egl.cc(481)] eglCreateWindowSurface failed with error EGL_BAD_MATCH

EGL の Surface の作成に失敗してビットマップによるソフトウェアレンダリングに移行しようとしているのですが、ソフトウェアレンダリングが未実装であるため、上記のようなエラーが発生しているようです。

また、ソフトウェアレンダリングを必要とするコンテンツ(https://youtube.com など?)が存在するため、そのようなコンテンツを開いても Check failed: surface_ozone. が発生します。このケースは諦めました。

Fails to find on path connection IDs

[128464:NetworkService/128488:0727/171351.031395:FATAL:quic_connection.cc(2958)] Fails to find on path connection IDs
[NetworkService/128488:0727/081351.633604(UTC):FATAL:immediate_crash.h(153)] Check failed: false. 

QUIC は使えないようです。
無効化するためのコマンドライン引数はありませんが、API はあるので少しだけですがソースコードを修正します。

--- a/cobalt/browser/cobalt_content_browser_client.cc
+++ b/cobalt/browser/cobalt_content_browser_client.cc
@@ -54,6 +54,8 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
 
+#include "services/network/public/mojom/network_service.mojom.h"
+
 #if BUILDFLAG(IS_ANDROID)
 #include "base/android/locale_utils.h"
 #endif  // BUILDFLAG(IS_ANDROID)
@@ -350,6 +352,12 @@ bool CobaltContentBrowserClient::WillCreateURLLoaderFactory(
   return true;
 }
 
+void CobaltContentBrowserClient::OnNetworkServiceCreated(
+    network::mojom::NetworkService* network_service) {
+  ShellContentBrowserClient::OnNetworkServiceCreated(network_service);
+  network_service->DisableQuic();
+}
+
 void CobaltContentBrowserClient::SetUpCobaltFeaturesAndParams(
     base::FeatureList* feature_list) {
   // All Cobalt features are associated with the same field trial. This is for
diff --git a/cobalt/browser/cobalt_content_browser_client.h b/cobalt/browser/cobalt_content_browser_client.h
index 224ff5b640a..5b2275824b3 100644
--- a/cobalt/browser/cobalt_content_browser_client.h
+++ b/cobalt/browser/cobalt_content_browser_client.h
@@ -122,6 +122,8 @@ class CobaltContentBrowserClient : public content::ShellContentBrowserClient {
       bool* disable_secure_dns,
       network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
 
+  void OnNetworkServiceCreated(network::mojom::NetworkService* network_service) override;
+
  private:
   void CreateVideoGeometrySetterService();

Discussion