mirror of
https://github.com/ruffle-rs/ruffle-android.git
synced 2024-11-23 05:39:38 +00:00
Add a (super ugly) panic screen
Some checks failed
Build / build-native-libs (arm64-v8a, aarch64-linux-android) (push) Failing after 1s
Build / build-native-libs (armeabi-v7a, armv7-linux-androideabi) (push) Failing after 1s
Build / build-native-libs (x86, i686-linux-android) (push) Failing after 1s
Build / build-native-libs (x86_64, x86_64-linux-android) (push) Failing after 2s
Build / build-apks (push) Has been skipped
Build / Android Tests (26) (push) Has been skipped
Build / Android Tests (34) (push) Has been skipped
Lint & Format / rust (push) Failing after 2s
Lint & Format / android (push) Failing after 1s
Some checks failed
Build / build-native-libs (arm64-v8a, aarch64-linux-android) (push) Failing after 1s
Build / build-native-libs (armeabi-v7a, armv7-linux-androideabi) (push) Failing after 1s
Build / build-native-libs (x86, i686-linux-android) (push) Failing after 1s
Build / build-native-libs (x86_64, x86_64-linux-android) (push) Failing after 2s
Build / build-apks (push) Has been skipped
Build / Android Tests (26) (push) Has been skipped
Build / Android Tests (34) (push) Has been skipped
Lint & Format / rust (push) Failing after 2s
Lint & Format / android (push) Failing after 1s
This commit is contained in:
parent
fd9c1b656e
commit
0319ac9dad
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -1926,16 +1926,6 @@ version = "0.4.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log-panics"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68f9dd8546191c1850ecf67d22f5ff00a935b890d0e84713159a55495cc2ac5f"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lru"
|
name = "lru"
|
||||||
version = "0.12.4"
|
version = "0.12.4"
|
||||||
@ -2769,9 +2759,9 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"android-activity",
|
"android-activity",
|
||||||
"android_logger",
|
"android_logger",
|
||||||
|
"backtrace",
|
||||||
"jni",
|
"jni",
|
||||||
"log",
|
"log",
|
||||||
"log-panics",
|
|
||||||
"ndk",
|
"ndk",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"ruffle_core",
|
"ruffle_core",
|
||||||
|
@ -40,10 +40,10 @@ ruffle_video_software = { git = "https://github.com/ruffle-rs/ruffle.git", branc
|
|||||||
ruffle_frontend_utils = { git = "https://github.com/ruffle-rs/ruffle.git", branch = "master" }
|
ruffle_frontend_utils = { git = "https://github.com/ruffle-rs/ruffle.git", branch = "master" }
|
||||||
|
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
log-panics = { version = "2.1.0", features = ["with-backtrace"]}
|
|
||||||
|
|
||||||
# Redirect tracing to log
|
# Redirect tracing to log
|
||||||
tracing = {version = "0.1.40", features = ["log", "log-always"]}
|
tracing = {version = "0.1.40", features = ["log", "log-always"]}
|
||||||
|
backtrace = "0.3.74"
|
||||||
|
|
||||||
url = "2.5.2"
|
url = "2.5.2"
|
||||||
webbrowser = "1.0.1"
|
webbrowser = "1.0.1"
|
||||||
|
@ -24,6 +24,11 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".PanicActivity"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:exported="false">
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".PlayerActivity"
|
android:name=".PlayerActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
20
app/src/main/java/rs/ruffle/PanicActivity.kt
Normal file
20
app/src/main/java/rs/ruffle/PanicActivity.kt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package rs.ruffle
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import rs.ruffle.ui.theme.RuffleTheme
|
||||||
|
|
||||||
|
class PanicActivity : ComponentActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
enableEdgeToEdge()
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setContent {
|
||||||
|
RuffleTheme {
|
||||||
|
PanicScreen(message = intent.getStringExtra("message") ?: "Unknown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
app/src/main/java/rs/ruffle/PanicScreen.kt
Normal file
77
app/src/main/java/rs/ruffle/PanicScreen.kt
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package rs.ruffle
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import rs.ruffle.ui.theme.RuffleTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PanicScreen(message: String) {
|
||||||
|
Scaffold { innerPadding ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(innerPadding)
|
||||||
|
.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.wrapContentSize(align = Alignment.Center),
|
||||||
|
style = MaterialTheme.typography.headlineLarge,
|
||||||
|
text = "Ruffle Panicked :("
|
||||||
|
)
|
||||||
|
SelectionContainer {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentSize(align = Alignment.Center)
|
||||||
|
.padding(horizontal = 8.dp, vertical = 20.dp)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.horizontalScroll(rememberScrollState()),
|
||||||
|
text = message,
|
||||||
|
softWrap = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Panic - Light", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
|
@Preview(name = "Panic - Dark", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
|
@Composable
|
||||||
|
fun PanicScreenPreview() {
|
||||||
|
RuffleTheme {
|
||||||
|
PanicScreen(
|
||||||
|
message = """Error: panicked at core/src/display_object/movie_clip.rs:477:9:
|
||||||
|
assertion `left == right` failed: Called replace_movie on a clip with LoaderInfo set
|
||||||
|
left: Some(LoaderInfoObject(LoaderInfoObject { ptr: 0x31b30a8 }))
|
||||||
|
right: None
|
||||||
|
at n.wbg.__wbg_new_796382978dfd4fb0 (https://unpkg.com/@ruffle-rs/ruffle/core.ruffle.90db0a0ab193ed0c601b.js:1:83857)
|
||||||
|
at ruffle_web.wasm.js_sys::Error::new::hfb561c222a4e70eb (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[12733]:0x98671a)
|
||||||
|
at ruffle_web.wasm.core::ops::function::FnOnce::call_once{{vtable.shim}}::h8a2a563fa204b611 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[9789]:0x9164aa)
|
||||||
|
at ruffle_web.wasm.std::panicking::rust_panic_with_hook::h33fe77d38d305ca3 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[6355]:0x8070ed)
|
||||||
|
at ruffle_web.wasm.core::panicking::panic_fmt::hde8b7aa66e2831e1 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[9511]:0x9071fd)
|
||||||
|
at ruffle_web.wasm.core::panicking::assert_failed_inner::hc95b7725cb4077cb (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[4402]:0x73cb5e)
|
||||||
|
at ruffle_web.wasm.ruffle_core::display_object::movie_clip::MovieClip::replace_with_movie::haf940b0718ed269c (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[2052]:0x50a035)
|
||||||
|
at ruffle_web.wasm.ruffle_core::loader::Loader::movie_loader::{{closure}}::h566c935379317178 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[1053]:0x2bc268)
|
||||||
|
at ruffle_web.wasm.<ruffle_web::navigator::WebNavigatorBackend as ruffle_core::backend::navigator::NavigatorBackend>::spawn_future::{{closure}}::h13f3540dbe40e875 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[1520]:0x419980)
|
||||||
|
at ruffle_web.wasm.wasm_bindgen_futures::queue::Queue::new::{{closure}}::hf37247571cf9bbf7 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[3648]:0x6ba342)"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import android.net.Uri
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Build.VERSION_CODES
|
import android.os.Build.VERSION_CODES
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
@ -230,6 +231,14 @@ class PlayerActivity : GameActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
nativeInit { message ->
|
||||||
|
Log.e("ruffle", "Handling panic: $message")
|
||||||
|
startActivity(
|
||||||
|
Intent(this, PanicActivity::class.java).apply {
|
||||||
|
putExtra("message", message)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
// When true, the app will fit inside any system UI windows.
|
// When true, the app will fit inside any system UI windows.
|
||||||
// When false, we render behind any system UI windows.
|
// When false, we render behind any system UI windows.
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
@ -264,11 +273,10 @@ class PlayerActivity : GameActivity() {
|
|||||||
init {
|
init {
|
||||||
// load the native activity
|
// load the native activity
|
||||||
System.loadLibrary("ruffle_android")
|
System.loadLibrary("ruffle_android")
|
||||||
nativeInit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun nativeInit()
|
private external fun nativeInit(crashCallback: CrashCallback)
|
||||||
|
|
||||||
private fun <T> gatherAllDescendantsOfType(v: View, t: Class<*>): List<T> {
|
private fun <T> gatherAllDescendantsOfType(v: View, t: Class<*>): List<T> {
|
||||||
val result: MutableList<T> = ArrayList()
|
val result: MutableList<T> = ArrayList()
|
||||||
@ -282,4 +290,8 @@ class PlayerActivity : GameActivity() {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun interface CrashCallback {
|
||||||
|
fun onCrash(message: String)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,8 +172,7 @@ impl JavaInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(env: &mut JNIEnv, class: &JClass) {
|
pub fn init(env: &mut JNIEnv, class: &JClass) {
|
||||||
JAVA_INTERFACE
|
let _ = JAVA_INTERFACE.set(JavaInterface {
|
||||||
.set(JavaInterface {
|
|
||||||
get_surface_width: env
|
get_surface_width: env
|
||||||
.get_method_id(class, "getSurfaceWidth", "()I")
|
.get_method_id(class, "getSurfaceWidth", "()I")
|
||||||
.expect("getSurfaceWidth must exist"),
|
.expect("getSurfaceWidth must exist"),
|
||||||
@ -198,7 +197,6 @@ impl JavaInterface {
|
|||||||
get_android_data_storage_dir: env
|
get_android_data_storage_dir: env
|
||||||
.get_method_id(class, "getAndroidDataStorageDir", "()Ljava/lang/String;")
|
.get_method_id(class, "getAndroidDataStorageDir", "()Ljava/lang/String;")
|
||||||
.expect("getAndroidDataStorageDir must exist"),
|
.expect("getAndroidDataStorageDir must exist"),
|
||||||
})
|
});
|
||||||
.unwrap_or_else(|_| panic!("Init cannot be called more than once!"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
80
src/lib.rs
80
src/lib.rs
@ -18,13 +18,16 @@ use std::sync::mpsc::Sender;
|
|||||||
use std::sync::{mpsc, MutexGuard};
|
use std::sync::{mpsc, MutexGuard};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{
|
use std::{
|
||||||
|
panic,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
|
thread,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
use wgpu::rwh::{AndroidDisplayHandle, HasWindowHandle, RawDisplayHandle};
|
use wgpu::rwh::{AndroidDisplayHandle, HasWindowHandle, RawDisplayHandle};
|
||||||
|
|
||||||
use android_activity::input::{InputEvent, KeyAction, MotionAction};
|
use android_activity::input::{InputEvent, KeyAction, MotionAction};
|
||||||
use android_activity::{AndroidApp, AndroidAppWaker, InputStatus, MainEvent, PollEvent};
|
use android_activity::{AndroidApp, AndroidAppWaker, InputStatus, MainEvent, PollEvent};
|
||||||
|
use backtrace::Backtrace;
|
||||||
use jni::objects::JClass;
|
use jni::objects::JClass;
|
||||||
|
|
||||||
use audio::AAudioAudioBackend;
|
use audio::AAudioAudioBackend;
|
||||||
@ -565,7 +568,69 @@ pub unsafe extern "C" fn Java_rs_ruffle_PlayerActivity_clearContextMenu(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(clippy::missing_safety_doc)]
|
#[allow(clippy::missing_safety_doc)]
|
||||||
pub unsafe extern "C" fn Java_rs_ruffle_PlayerActivity_nativeInit(mut env: JNIEnv, class: JClass) {
|
pub unsafe extern "C" fn Java_rs_ruffle_PlayerActivity_nativeInit(
|
||||||
|
mut env: JNIEnv,
|
||||||
|
class: JClass,
|
||||||
|
crash_callback: JObject,
|
||||||
|
) {
|
||||||
|
let crash_callback = env.new_global_ref(crash_callback).unwrap();
|
||||||
|
let jvm = env.get_java_vm().unwrap();
|
||||||
|
|
||||||
|
android_logger::init_once(
|
||||||
|
android_logger::Config::default()
|
||||||
|
.with_max_level(log::LevelFilter::Info)
|
||||||
|
.with_tag("ruffle")
|
||||||
|
.with_filter(
|
||||||
|
android_logger::FilterBuilder::new()
|
||||||
|
.parse("warn,ruffle=info")
|
||||||
|
.build(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
panic::set_hook(Box::new(move |info| {
|
||||||
|
let backtrace = Backtrace::new();
|
||||||
|
let thread = thread::current();
|
||||||
|
let thread = thread.name().unwrap_or("<unnamed>");
|
||||||
|
let message = match info.payload().downcast_ref::<&'static str>() {
|
||||||
|
Some(s) => *s,
|
||||||
|
None => match info.payload().downcast_ref::<String>() {
|
||||||
|
Some(s) => &**s,
|
||||||
|
None => "Box<Any>",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let full = match info.location() {
|
||||||
|
Some(location) => format!(
|
||||||
|
"thread '{}' panicked at '{}': {}:{}\n{:?}",
|
||||||
|
thread,
|
||||||
|
message,
|
||||||
|
location.file(),
|
||||||
|
location.line(),
|
||||||
|
backtrace
|
||||||
|
),
|
||||||
|
None => format!(
|
||||||
|
"thread '{}' panicked at '{}'\n{:?}",
|
||||||
|
thread, message, backtrace
|
||||||
|
),
|
||||||
|
};
|
||||||
|
log::error!(target: "panic","{}", full);
|
||||||
|
|
||||||
|
let mut env = jvm.attach_current_thread().unwrap();
|
||||||
|
if env.exception_check().unwrap() {
|
||||||
|
// There's a pending exception, java will discover this on their own
|
||||||
|
} else {
|
||||||
|
let java_message = env.new_string(full).unwrap();
|
||||||
|
let crash_callback = env.new_global_ref(&crash_callback).unwrap();
|
||||||
|
env.call_method(
|
||||||
|
crash_callback,
|
||||||
|
"onCrash",
|
||||||
|
"(Ljava/lang/String;)V",
|
||||||
|
&[(&java_message).into()],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
JavaInterface::init(&mut env, &class)
|
JavaInterface::init(&mut env, &class)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,19 +656,6 @@ fn get_view_size() -> Result<(i32, i32), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn android_main(app: AndroidApp) {
|
fn android_main(app: AndroidApp) {
|
||||||
android_logger::init_once(
|
|
||||||
android_logger::Config::default()
|
|
||||||
.with_max_level(log::LevelFilter::Info)
|
|
||||||
.with_tag("ruffle")
|
|
||||||
.with_filter(
|
|
||||||
android_logger::FilterBuilder::new()
|
|
||||||
.parse("warn,ruffle=info")
|
|
||||||
.build(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
log_panics::init();
|
|
||||||
|
|
||||||
log::info!("Starting android_main...");
|
log::info!("Starting android_main...");
|
||||||
run(app);
|
run(app);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user