Skip to content

Commit

Permalink
Create StarboardBridge native class with jni_generator (#4606)
Browse files Browse the repository at this point in the history
b/372559388

This PR configures jni_generator for cobalt_apk_java. 
It creates the corresponding native class StarboardBridge for
cobalt/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java,
adhering to Chromium's JNI standards.
The StarboardBridge native class is implemented as a singleton and is
initialized with the same JNIEnv and jobject used when calling the
Starboard custom JniEnvExt::Initialize function.
Additionally, it updates the JNI function calls in
starboard/android/shared/application_android.cc to align with Chromium's
modern JNI standards.


This PR amends the reverted PR
#4545

There was an issue in the reverted PR that there are old annotations
@UsedByNative embeded in the inner function calls in getResourceOverlay,
somehow making the app not able to launch..
Culprit ->

https://github.com/youtube/cobalt/pull/4545/files#diff-22285847addbd15025f71dadd357129f86573e042655067048f94fae301fb1d3R480.

We can not blindly replace @UsedByNative with @CalledByNative, when
switching to @CalledByNative, we should make sure to replace all
occurrence of @UserByNative inside, and implement the new JNI template
functions. I don't get why compiler didn't complain about the
getResourceOverlay issue tho.
  • Loading branch information
haozheng-cobalt authored Dec 19, 2024
1 parent 9158f9a commit 1322f53
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 33 deletions.
9 changes: 9 additions & 0 deletions cobalt/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,21 @@ jinja_template("cobalt_manifest") {
variables = [ "manifest_package=dev.cobalt.coat" ]
}

generate_jni("jni_headers") {
sources = [ "apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java" ]
}

# TODO(cobalt): Re-enable or remove disabled java files.
android_library("cobalt_apk_java") {
testonly = true
resources_package = "dev.cobalt.coat"
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]

deps = [
":cobalt_java_resources",
":jni_headers",
"//base:base_java",
"//base:jni_java",
"//base:process_launcher_java",
"//build/android:build_java",
"//components/embedder_support/android:view_java",
Expand All @@ -57,6 +65,7 @@ android_library("cobalt_apk_java") {
"//ui/android:ui_no_recycler_view_java",
"//url:gurl_java",
]

sources = [
"apk/app/src/app/java/dev/cobalt/app/CobaltApplication.java",
"apk/app/src/app/java/dev/cobalt/app/MainActivity.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;

/** Implementation of the required JNI methods called by the Starboard C++ code. */
@JNINamespace("starboard::android::shared")
public class StarboardBridge {

/** Interface to be implemented by the Android Application hosting the starboard app. */
Expand Down Expand Up @@ -144,7 +148,19 @@ public StarboardBridge(

private native void closeNativeStarboard(long nativeApp);

private native long nativeCurrentMonotonicTime();
@NativeMethods
interface Natives {
void onStop();

long currentMonotonicTime();

// TODO(cobalt, b/372559388): move below native methods to the Natives interface.
// boolean initJNI();

// long startNativeStarboard();

// void closeNativeStarboard(long nativeApp);
}

protected void onActivityStart(Activity activity) {
Log.e(TAG, "onActivityStart ran");
Expand All @@ -163,8 +179,6 @@ protected void onActivityStop(Activity activity) {
afterStopped();
}

private native void nativeOnStop();

protected void onActivityDestroy(Activity activity) {
if (applicationStopped) {
// We can't restart the starboard app, so kill the process for a clean start next time.
Expand Down Expand Up @@ -240,13 +254,13 @@ protected void afterStopped() {
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative
protected void applicationStarted() {
applicationReady = true;
}

@SuppressWarnings("unused")
@UsedByNative
@CalledByNative
protected void applicationStopping() {
applicationReady = false;
applicationStopped = true;
Expand Down Expand Up @@ -362,6 +376,9 @@ protected String getCacheAbsolutePath() {
*/
@SuppressWarnings("unused")
@UsedByNative
// TODO: (cobalt b/372559388) Migrate complicated returned type functions to JNI zero.
// The @UsedByNative annotation has strict signature parsing rules,
// and Pair<byte[], byte[]> is not be supported well.
Pair<byte[], byte[]> getLocalInterfaceAddressAndNetmask(boolean wantIPv6) {
try {
Enumeration<NetworkInterface> it = NetworkInterface.getNetworkInterfaces();
Expand Down Expand Up @@ -780,12 +797,12 @@ public byte[] sendToCobaltService(String serviceName, byte [] data) {

/** Returns the application start timestamp. */
@SuppressWarnings("unused")
@UsedByNative
@CalledByNative
protected long getAppStartTimestamp() {
Activity activity = activityHolder.get();
if (activity instanceof CobaltActivity) {
long javaStartTimestamp = ((CobaltActivity) activity).getAppStartTimestamp();
long cppTimestamp = nativeCurrentMonotonicTime();
long cppTimestamp = StarboardBridgeJni.get().currentMonotonicTime();
long javaStopTimestamp = System.nanoTime();
return cppTimestamp
- (javaStopTimestamp - javaStartTimestamp) / timeNanosecondsPerMicrosecond;
Expand Down
4 changes: 4 additions & 0 deletions starboard/android/shared/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ static_library("starboard_platform") {
#"speech_synthesis_internal.cc",
#"speech_synthesis_is_supported.cc",
#"speech_synthesis_speak.cc",
"starboard_bridge.cc",
"starboard_bridge.h",
"system_get_extensions.cc",
"system_get_locale_id.cc",
"system_get_path.cc",
Expand Down Expand Up @@ -316,12 +318,14 @@ static_library("starboard_platform") {
public_deps = [
":starboard_base_symbolize",
":starboard_jni_state",
"//cobalt/android:jni_headers",
"//starboard/common",
"//starboard/shared/starboard/media:media_util",
"//starboard/shared/starboard/player/filter:filter_based_player_sources",
]

deps = [
"//base",
"//third_party/libevent",
"//third_party/opus",
]
Expand Down
7 changes: 7 additions & 0 deletions starboard/android/shared/android_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "starboard/crashpad_wrapper/wrapper.h" // nogncheck
#endif

#include "starboard/android/shared/starboard_bridge.h"

namespace starboard {
namespace android {
namespace shared {
Expand Down Expand Up @@ -292,10 +294,15 @@ void StarboardThreadLaunch() {
}
#endif // SB_IS(EVERGREEN_COMPATIBLE)

// TODO(cobalt, b/372559388): consolidate this function when fully deprecate
// JniEnvExt.
extern "C" SB_EXPORT_PLATFORM void Java_dev_cobalt_coat_StarboardBridge_initJNI(
JniEnvExt* env,
jobject starboard_bridge) {
JniEnvExt::Initialize(env, starboard_bridge);

// Initialize the singleton instance of StarboardBridge
StarboardBridge::GetInstance()->Initialize(env, starboard_bridge);
}

extern "C" SB_EXPORT_PLATFORM jlong
Expand Down
33 changes: 7 additions & 26 deletions starboard/android/shared/application_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <string>
#include <vector>

#include "base/android/jni_android.h"
#include "starboard/extension/accessibility.h"

#include "starboard/android/shared/file_internal.h"
Expand All @@ -44,14 +45,6 @@
namespace starboard {
namespace android {
namespace shared {
namespace {
int64_t GetAppStartTimestamp() {
JniEnvExt* env = JniEnvExt::Get();
jlong app_start_timestamp =
env->CallStarboardLongMethodOrAbort("getAppStartTimestamp", "()J");
return app_start_timestamp;
}
} // namespace

// TODO(cobalt, b/378708359): Remove this dummy init.
void stubSbEventHandle(const SbEvent* event) {
Expand All @@ -74,14 +67,16 @@ ApplicationAndroid::ApplicationAndroid(
jobject local_ref = env->CallStarboardObjectMethodOrAbort(
"getResourceOverlay", "()Ldev/cobalt/coat/ResourceOverlay;");
resource_overlay_ = env->ConvertLocalRefToGlobalRef(local_ref);

SbAudioSinkPrivate::Initialize();
app_start_timestamp_ = GetAppStartTimestamp();
env->CallStarboardVoidMethodOrAbort("applicationStarted", "()V");

app_start_timestamp_ = starboard_bridge_->GetAppStartTimestamp();

starboard_bridge_->ApplicationStarted();
}

ApplicationAndroid::~ApplicationAndroid() {
JniEnvExt* env = JniEnvExt::Get();
env->CallStarboardVoidMethodOrAbort("applicationStopping", "()V");
starboard_bridge_->ApplicationStopping();

// The application is exiting.
// Release the global reference.
Expand All @@ -94,12 +89,6 @@ ApplicationAndroid::~ApplicationAndroid() {
JniEnvExt::OnThreadShutdown();
}

extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_coat_StarboardBridge_nativeOnStop(JniEnvExt* env) {
SbAudioSinkPrivate::TearDown();
SbFileAndroidTeardown();
}

extern "C" SB_EXPORT_PLATFORM jboolean
Java_dev_cobalt_coat_StarboardBridge_nativeOnSearchRequested(
JniEnvExt* env,
Expand All @@ -108,14 +97,6 @@ Java_dev_cobalt_coat_StarboardBridge_nativeOnSearchRequested(
return true;
}

extern "C" SB_EXPORT_PLATFORM jlong
Java_dev_cobalt_coat_StarboardBridge_nativeCurrentMonotonicTime(
JNIEnv* env,
jobject jcaller,
jboolean online) {
return CurrentMonotonicTime();
}

extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_coat_CobaltSystemConfigChangeReceiver_nativeDateTimeConfigurationChanged(
JNIEnv* env,
Expand Down
6 changes: 6 additions & 0 deletions starboard/android/shared/application_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "starboard/shared/starboard/queue_application.h"
#include "starboard/types.h"

#include "starboard/android/shared/starboard_bridge.h"

namespace starboard {
namespace android {
namespace shared {
Expand Down Expand Up @@ -66,6 +68,10 @@ class ApplicationAndroid
void WakeSystemEventWait() override {}

private:
// starboard_bridge_ is a global singleton, use a raw pointer to not interfere
// with it's lifecycle management.
const raw_ptr<StarboardBridge> starboard_bridge_ =
StarboardBridge::GetInstance();
jobject resource_overlay_;

Mutex overlay_mutex_;
Expand Down
67 changes: 67 additions & 0 deletions starboard/android/shared/starboard_bridge.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2024 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 "starboard/android/shared/starboard_bridge.h"

#include "starboard/android/shared/file_internal.h"
#include "starboard/common/time.h"
#include "starboard/media.h"
#include "starboard/shared/starboard/audio_sink/audio_sink_internal.h"

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

namespace starboard {
namespace android {
namespace shared {

extern "C" SB_EXPORT_PLATFORM void JNI_StarboardBridge_OnStop(JNIEnv* env) {
SbAudioSinkPrivate::TearDown();
SbFileAndroidTeardown();
}

extern "C" SB_EXPORT_PLATFORM jlong
JNI_StarboardBridge_CurrentMonotonicTime(JNIEnv* env) {
return CurrentMonotonicTime();
}

// static
StarboardBridge* StarboardBridge::GetInstance() {
return base::Singleton<StarboardBridge>::get();
}

void StarboardBridge::Initialize(JNIEnv* env, jobject obj) {
j_starboard_bridge_.Reset(env, obj);
}

long StarboardBridge::GetAppStartTimestamp() {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
return Java_StarboardBridge_getAppStartTimestamp(env, j_starboard_bridge_);
}

void StarboardBridge::ApplicationStarted() {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
return Java_StarboardBridge_applicationStarted(env, j_starboard_bridge_);
}

void StarboardBridge::ApplicationStopping() {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
return Java_StarboardBridge_applicationStopping(env, j_starboard_bridge_);
}
} // namespace shared
} // namespace android
} // namespace starboard
60 changes: 60 additions & 0 deletions starboard/android/shared/starboard_bridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2024 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 STARBOARD_ANDROID_SHARED_STARBOARD_BRIDGE_H_
#define STARBOARD_ANDROID_SHARED_STARBOARD_BRIDGE_H_

#include <jni.h>

#include "base/android/scoped_java_ref.h"
#include "base/memory/singleton.h"

namespace starboard {
namespace android {
namespace shared {

// This class serves as a bridge between the native code and Android
// StarboardBridge Java class.
class StarboardBridge {
public:
// Returns the singleton.
static StarboardBridge* GetInstance();

void Initialize(JNIEnv* env, jobject obj);

long GetAppStartTimestamp();

void ApplicationStarted();

void ApplicationStopping();

private:
StarboardBridge() = default;
~StarboardBridge() = default;

// Prevent copy construction and assignment
StarboardBridge(const StarboardBridge&) = delete;
StarboardBridge& operator=(const StarboardBridge&) = delete;

friend struct base::DefaultSingletonTraits<StarboardBridge>;

// Java StarboardBridge instance.
base::android::ScopedJavaGlobalRef<jobject> j_starboard_bridge_;
};

} // namespace shared
} // namespace android
} // namespace starboard

#endif // STARBOARD_ANDROID_SHARED_STARBOARD_BRIDGE_H_

0 comments on commit 1322f53

Please sign in to comment.