aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ports/libsimpleservo/src/jniapi.rs98
1 files changed, 92 insertions, 6 deletions
diff --git a/ports/libsimpleservo/src/jniapi.rs b/ports/libsimpleservo/src/jniapi.rs
index a41dbb61088..70a65652727 100644
--- a/ports/libsimpleservo/src/jniapi.rs
+++ b/ports/libsimpleservo/src/jniapi.rs
@@ -10,11 +10,13 @@ use gl_glue;
use jni::{JNIEnv, JavaVM};
use jni::objects::{GlobalRef, JClass, JObject, JString, JValue};
use jni::sys::{jboolean, jfloat, jint, jstring, JNI_TRUE};
+use libc::{pipe, dup2, read};
use log::Level;
use std;
use std::borrow::Cow;
-use std::os::raw::c_void;
+use std::os::raw::{c_char, c_int, c_void};
use std::sync::{Arc, Mutex};
+use std::thread;
struct HostCallbacks {
callbacks: GlobalRef,
@@ -61,11 +63,19 @@ pub fn Java_com_mozilla_servoview_JNIServo_init(
// Note: Android debug logs are stripped from a release build.
// debug!() will only show in a debug build. Use info!() if logs
// should show up in adb logcat with a release build.
- let mut filter = Filter::default()
- .with_min_level(Level::Debug)
- .with_allowed_module_path("simpleservo::api")
- .with_allowed_module_path("simpleservo::jniapi")
- .with_allowed_module_path("simpleservo::gl_glue::egl");
+ let filters = [
+ "simpleservo::api",
+ "simpleservo::jniapi",
+ "simpleservo::gl_glue::egl",
+ // Show JS errors by default.
+ "script::dom::bindings::error",
+ // Show GL errors by default.
+ "canvas::webgl_thread",
+ ];
+ let mut filter = Filter::default().with_min_level(Level::Debug);
+ for &module in &filters {
+ filter = filter.with_allowed_module_path(module);
+ }
let log_str = env.get_string(log_str).ok();
let log_str = log_str.as_ref().map_or(Cow::Borrowed(""), |s| s.to_string_lossy());
for module in log_str.split(',') {
@@ -77,6 +87,7 @@ pub fn Java_com_mozilla_servoview_JNIServo_init(
info!("init");
initialize_android_glue(&env, activity);
+ redirect_stdout_to_logcat();
let args = env.get_string(args)
.expect("Couldn't get java string")
@@ -434,3 +445,78 @@ fn initialize_android_glue(env: &JNIEnv, activity: JObject) {
ANDROID_APP = Box::into_raw(Box::new(app));
}
}
+
+extern {
+ pub fn __android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int;
+}
+
+fn redirect_stdout_to_logcat() {
+ // The first step is to redirect stdout and stderr to the logs.
+ // We redirect stdout and stderr to a custom descriptor.
+ let mut pfd: [c_int; 2] = [0, 0];
+ unsafe {
+ pipe(pfd.as_mut_ptr());
+ dup2(pfd[1], 1);
+ dup2(pfd[1], 2);
+ }
+
+ let descriptor = pfd[0];
+
+ // Then we spawn a thread whose only job is to read from the other side of the
+ // pipe and redirect to the logs.
+ let _detached = thread::spawn(move || {
+ const BUF_LENGTH: usize = 512;
+ let mut buf = vec![b'\0' as c_char; BUF_LENGTH];
+
+ // Always keep at least one null terminator
+ const BUF_AVAILABLE: usize = BUF_LENGTH - 1;
+ let buf = &mut buf[..BUF_AVAILABLE];
+
+ let mut cursor = 0_usize;
+
+ let tag = b"simpleservo\0".as_ptr() as _;
+
+ loop {
+ let result = {
+ let read_into = &mut buf[cursor..];
+ unsafe {
+ read(descriptor, read_into.as_mut_ptr() as *mut _, read_into.len())
+ }
+ };
+
+ let end = if result == 0 {
+ return;
+ } else if result < 0 {
+ return; /* TODO: report problem */
+ } else {
+ result as usize + cursor
+ };
+
+ if let Some(last_newline_pos) = buf.iter().rposition(|&c| c == b'\n' as c_char) {
+ buf[last_newline_pos] = b'\0' as c_char;
+ unsafe {
+ __android_log_write(3, tag, buf.as_ptr());
+ }
+ if last_newline_pos < buf.len() - 1 {
+ let pos_after_newline = last_newline_pos + 1;
+ let len_not_logged_yet = buf[pos_after_newline..].len();
+ for j in 0..len_not_logged_yet as usize {
+ buf[j] = buf[pos_after_newline + j];
+ }
+ cursor = len_not_logged_yet;
+ } else {
+ cursor = 0;
+ }
+ } else if cursor == BUF_AVAILABLE {
+ // No newline found but the buffer is full, flush it anyway.
+ // `buf.as_ptr()` is null-terminated by BUF_LENGTH being 1 less than BUF_AVAILABLE.
+ unsafe {
+ __android_log_write(3, tag, buf.as_ptr());
+ }
+ cursor = 0;
+ } else {
+ cursor = end;
+ }
+ }
+ });
+}