Skip to content

Commit

Permalink
Enable Java impls for Cobalt's Mojo interfaces (youtube#4909)
Browse files Browse the repository at this point in the history
A Java implementation for the CrashAnnotator interface is added as an
example. It is still stubbed, but now in Java; a quick follow-up will
implement it using StarboardBridge.setCrashContext.

The Mojo Java Bindings API doc was used as a reference.

b/383301493
  • Loading branch information
hlwarriner authored Feb 14, 2025
1 parent ab26b08 commit dc0f4c3
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 2 deletions.
6 changes: 6 additions & 0 deletions build/build_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,12 @@
#define BUILDFLAG_INTERNAL_ENABLE_COBALT_HACKS() (0)
#endif

#if defined(ENABLE_BUILFLAG_IS_ANDROIDTV)
#define BUILDFLAG_INTERNAL_IS_ANDROIDTV() (1)
#else
#define BUILDFLAG_INTERNAL_IS_ANDROIDTV() (0)
#endif

// Compiler detection. Note: clang masquerades as GCC on POSIX and as MSVC on
// Windows.
#if defined(__GNUC__)
Expand Down
26 changes: 26 additions & 0 deletions cobalt/android/BUILD.gn
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
import("//starboard/build/buildflags.gni")
import("//third_party/icu/config.gni")

cobalt_manifest = "$target_gen_dir/cobalt_manifest/AndroidManifest.xml"
Expand Down Expand Up @@ -39,6 +40,12 @@ generate_jni("jni_headers") {
"apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java",
"apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java",
]

if (!use_evergreen) {
sources += [
"apk/app/src/main/java/dev/cobalt/browser/CobaltInterfaceRegistrar.java",
]
}
}

generate_jni("content_shell_jni_headers") {
Expand Down Expand Up @@ -130,6 +137,17 @@ android_library("cobalt_main_java") {
"//ui/android:ui_no_recycler_view_java",
"//url:gurl_java",
]

if (!use_evergreen) {
deps += [
"//cobalt/browser/crash_annotator/public/mojom:mojom_java",
"//mojo/public/java:base_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
"//services/service_manager/public/java:service_manager_java",
]
}

sources = [
"apk/app/src/main/java/dev/cobalt/coat/ArtworkDownloader.java",
"apk/app/src/main/java/dev/cobalt/coat/ArtworkDownloaderDefault.java",
Expand Down Expand Up @@ -183,6 +201,14 @@ android_library("cobalt_main_java") {
"apk/app/src/main/java/dev/cobalt/util/UsedByNative.java",
]

if (!use_evergreen) {
sources += [
"apk/app/src/main/java/dev/cobalt/browser/CobaltInterfaceRegistrar.java",
"apk/app/src/main/java/dev/cobalt/browser/crashannotator/CrashAnnotatorImpl.java",
"apk/app/src/main/java/dev/cobalt/browser/crashannotator/CrashAnnotatorImplFactory.java",
]
}

annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2025 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.

package dev.cobalt.browser;

import dev.cobalt.browser.crashannotator.CrashAnnotatorImplFactory;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.content_public.browser.InterfaceRegistrar;
import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.crashannotator.mojom.CrashAnnotator;
import org.chromium.services.service_manager.InterfaceRegistry;

/** Registers Mojo interface implementations exposed to C++ code at the Cobalt layer. */
class CobaltInterfaceRegistrar {
@CalledByNative
private static void registerMojoInterfaces() {
InterfaceRegistrar.Registry.addRenderFrameHostRegistrar(
new CobaltRenderFrameHostInterfaceRegistrar());
}

private static class CobaltRenderFrameHostInterfaceRegistrar
implements InterfaceRegistrar<RenderFrameHost> {
@Override
public void registerInterfaces(
InterfaceRegistry registry,
final RenderFrameHost renderFrameHost) {
registry.addInterface(
CrashAnnotator.MANAGER,
new CrashAnnotatorImplFactory(renderFrameHost));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2025 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.

package dev.cobalt.browser.crashannotator;

import static dev.cobalt.util.Log.TAG;

import dev.cobalt.util.Log;
import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.crashannotator.mojom.CrashAnnotator;
import org.chromium.mojo.system.MojoException;

/** Implements the CrashAnnotator Mojo interface in Java. */
public class CrashAnnotatorImpl implements CrashAnnotator {
// TODO(cobalt, b/383301493): confirm that this member is needed for proper
// lifetime management.
private final RenderFrameHost mRenderFrameHost;

public CrashAnnotatorImpl(RenderFrameHost renderFrameHost) {
mRenderFrameHost = renderFrameHost;
}

@Override
public void setString(String key,
String value,
SetString_Response callback) {
// TODO(cobalt, b/383301493): actually implement this by calling
// StarboardBridge.setCrashContext().
Log.i(TAG, "Java CrashAnnotator impl key=%s value=%s", key, value);
callback.call(false);
}

/** This abstract method must be overridden. */
@Override
public void close() {}

/** This abstract method must be overridden. */
@Override
public void onConnectionError(MojoException e) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2025 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.

package dev.cobalt.browser.crashannotator;

import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.crashannotator.mojom.CrashAnnotator;
import org.chromium.services.service_manager.InterfaceFactory;

/** Creates instances of CrashAnnotator Mojo interface implementations. */
public class CrashAnnotatorImplFactory implements InterfaceFactory {
private final RenderFrameHost mRenderFrameHost;

public CrashAnnotatorImplFactory(RenderFrameHost renderFrameHost) {
mRenderFrameHost = renderFrameHost;
}

@Override
public CrashAnnotator createImpl() {
return new CrashAnnotatorImpl(mRenderFrameHost);
}
}
16 changes: 15 additions & 1 deletion cobalt/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import("//starboard/build/buildflags.gni")

source_set("browser") {
# TODO(cobalt, b/375655377): remove testonly declaration, needed because of
# content_shell_lib.
Expand All @@ -26,9 +28,15 @@ source_set("browser") {
"cobalt_web_contents_observer.h",
]

if (is_androidtv) {
sources += [
"android/mojo/cobalt_interface_registrar_android.cc",
"android/mojo/cobalt_interface_registrar_android.h",
]
}

deps = [
":embed_polyfilled_javascript",
"//cobalt/browser/crash_annotator",
"//cobalt/browser/crash_annotator/public/mojom",
"//cobalt/browser/h5vcc_runtime",
"//cobalt/browser/h5vcc_runtime/public/mojom",
Expand All @@ -39,6 +47,12 @@ source_set("browser") {
"//content/public/browser",
"//content/shell:content_shell_lib",
]

if (is_androidtv) {
deps += [ "//cobalt/android:jni_headers" ]
} else {
deps += [ "//cobalt/browser/crash_annotator" ]
}
}

config("embed_polyfilled_javascript_config") {
Expand Down
31 changes: 31 additions & 0 deletions cobalt/browser/android/mojo/cobalt_interface_registrar_android.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2025 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/browser/android/mojo/cobalt_interface_registrar_android.h"

#include <jni.h>

#include "base/android/jni_android.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "cobalt/android/jni_headers/CobaltInterfaceRegistrar_jni.h"

namespace cobalt {

void RegisterCobaltJavaMojoInterfaces() {
Java_CobaltInterfaceRegistrar_registerMojoInterfaces(
base::android::AttachCurrentThread());
}

} // namespace cobalt
25 changes: 25 additions & 0 deletions cobalt/browser/android/mojo/cobalt_interface_registrar_android.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2025 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.

#ifndef COBALT_BROWSER_ANDROID_MOJO_COBALT_INTERFACE_REGISTRAR_ANDROID_H_
#define COBALT_BROWSER_ANDROID_MOJO_COBALT_INTERFACE_REGISTRAR_ANDROID_H_

namespace cobalt {

// Registers Cobalt's Java Mojo interfaces with its independent registrar.
void RegisterCobaltJavaMojoInterfaces();

} // namespace cobalt

#endif // COBALT_BROWSER_ANDROID_MOJO_COBALT_INTERFACE_REGISTRAR_ANDROID_H_
22 changes: 21 additions & 1 deletion cobalt/browser/cobalt_browser_interface_binders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,40 @@
#include "cobalt/browser/cobalt_browser_interface_binders.h"

#include "base/functional/bind.h"
#include "cobalt/browser/crash_annotator/crash_annotator_impl.h"
#include "cobalt/browser/crash_annotator/public/mojom/crash_annotator.mojom.h"
#include "cobalt/browser/h5vcc_runtime/h5vcc_runtime_impl.h"
#include "cobalt/browser/h5vcc_runtime/public/mojom/h5vcc_runtime.mojom.h"
#include "cobalt/browser/h5vcc_system/h5vcc_system_impl.h"
#include "cobalt/browser/h5vcc_system/public/mojom/h5vcc_system.mojom.h"

#if BUILDFLAG(IS_ANDROIDTV)
#include "content/public/browser/render_frame_host.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#else
#include "cobalt/browser/crash_annotator/crash_annotator_impl.h"
#endif // BUILDFLAG(IS_ANDROIDTV)

namespace cobalt {

#if BUILDFLAG(IS_ANDROIDTV)
template <typename Interface>
void ForwardToJavaFrame(content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<Interface> receiver) {
render_frame_host->GetJavaInterfaces()->GetInterface(std::move(receiver));
}
#endif // BUILDFLAG(IS_ANDROIDTV)

void PopulateCobaltFrameBinders(
content::RenderFrameHost* render_frame_host,
mojo::BinderMapWithContext<content::RenderFrameHost*>* binder_map) {
// We want to use the Java Mojo implementation for 1P ATV only.
#if BUILDFLAG(IS_ANDROIDTV)
binder_map->Add<crash_annotator::mojom::CrashAnnotator>(base::BindRepeating(
&ForwardToJavaFrame<crash_annotator::mojom::CrashAnnotator>));
#else
binder_map->Add<crash_annotator::mojom::CrashAnnotator>(
base::BindRepeating(&crash_annotator::CrashAnnotatorImpl::Create));
#endif // BUILDFLAG(IS_ANDROIDTV)
binder_map->Add<h5vcc_system::mojom::H5vccSystem>(
base::BindRepeating(&h5vcc_system::H5vccSystemImpl::Create));
binder_map->Add<h5vcc_runtime::mojom::H5vccRuntime>(
Expand Down
17 changes: 17 additions & 0 deletions cobalt/browser/cobalt_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@

#include "base/logging.h"

#if BUILDFLAG(IS_ANDROIDTV)
#include "cobalt/browser/android/mojo/cobalt_interface_registrar_android.h"
#endif

namespace cobalt {

// TODO(b/390021478): When CobaltContentBrowserClient stops deriving from
Expand All @@ -45,6 +49,19 @@ class CobaltBrowserMainParts : public content::ShellBrowserMainParts {
// when called from ChromeBrowserMainParts::PreCreateThreadsImpl().
return ShellBrowserMainParts::PreCreateThreads();
}

// TODO(cobalt, b/383301493): we should consider moving any ATV-specific
// behaviors into an ATV implementation of BrowserMainParts. For example, see
// Chrome's ChromeBrowserMainPartsAndroid.
#if BUILDFLAG(IS_ANDROIDTV)
void PostCreateThreads() override {
// TODO(cobalt, b/383301493): this looks like a reasonable stage at which to
// register these interfaces and it seems to work. But we may want to
// consider if there's a more suitable stage.
RegisterCobaltJavaMojoInterfaces();
ShellBrowserMainParts::PostCreateThreads();
}
#endif // BUILDFLAG(IS_ANDROIDTV)
};

std::string GetCobaltUserAgent() {
Expand Down
1 change: 1 addition & 0 deletions cobalt/browser/crash_annotator/public/mojom/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
import("//mojo/public/tools/bindings/mojom.gni")

mojom("mojom") {
generate_java = true
sources = [ "crash_annotator.mojom" ]
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

[JavaPackage="org.chromium.crashannotator.mojom"]
module crash_annotator.mojom;

// The browser process must provide an implementation of this interface so that
Expand Down
3 changes: 3 additions & 0 deletions cobalt/build/configs/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,7 @@ config("buildflag_defines") {
if (enable_cobalt_hacks) {
defines += [ "ENABLE_BUILDFLAG_ENABLE_COBALT_HACKS" ]
}
if (is_androidtv) {
defines += [ "ENABLE_BUILFLAG_IS_ANDROIDTV" ]
}
}
3 changes: 3 additions & 0 deletions starboard/build/buildflags.gni
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ declare_args() {
use_starboard_media = is_cobalt
use_evergreen = false
}

# Differentiates our 1P ATV platform from 3P AOSP.
is_androidtv = is_android && !use_evergreen

0 comments on commit dc0f4c3

Please sign in to comment.