Skip to content

Commit ea88658

Browse files
committed
fix(android): Fix JNI signature mismatch causing SIGSEGV on Android 11+
- Fixed initialize() function to return jstring instead of void to match Java signature - Changed jstring_to_string() to return Option<String> instead of panicking on error - Updated all call sites to handle the Option return type safely This resolves the crash on newer Android versions where JNI signature mismatch was causing segmentation faults during app initialization.
1 parent c640979 commit ea88658

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

aw-server/src/android/mod.rs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ pub mod android {
8282
output.into_raw()
8383
}
8484

85-
unsafe fn jstring_to_string(env: &JNIEnv, string: JString) -> String {
86-
let c_str = CStr::from_ptr(env.get_string(string).expect("invalid string").as_ptr());
87-
String::from(c_str.to_str().unwrap())
85+
unsafe fn jstring_to_string(env: &JNIEnv, string: JString) -> Option<String> {
86+
let java_str = env.get_string(string).ok()?;
87+
let c_str = CStr::from_ptr(java_str.as_ptr());
88+
c_str.to_str().ok().map(String::from)
8889
}
8990

9091
unsafe fn string_to_jstring(env: &JNIEnv, string: String) -> jstring {
@@ -136,7 +137,7 @@ pub mod android {
136137
pub unsafe extern "C" fn Java_net_activitywatch_android_RustInterface_initialize(
137138
env: JNIEnv,
138139
_: JClass,
139-
) {
140+
) -> jstring {
140141
if !INITIALIZED {
141142
android_logger::init_once(
142143
Config::default()
@@ -154,9 +155,8 @@ pub mod android {
154155
}
155156
INITIALIZED = true;
156157

157-
// Without this it might not work due to weird error probably arising from Rust optimizing away the JNIEnv:
158-
// JNI DETECTED ERROR IN APPLICATION: use of deleted weak global reference
159-
string_to_jstring(&env, "test".to_string());
158+
// Return a string as expected by Java
159+
string_to_jstring(&env, "initialized".to_string())
160160
}
161161

162162
#[no_mangle]
@@ -165,9 +165,16 @@ pub mod android {
165165
_: JClass,
166166
java_dir: JString,
167167
) {
168-
let path = &jstring_to_string(&env, java_dir);
169-
debug!("Setting android data dir as {}", path);
170-
dirs::set_android_data_dir(path);
168+
match jstring_to_string(&env, java_dir) {
169+
Some(path) => {
170+
debug!("Setting android data dir as {}", path);
171+
dirs::set_android_data_dir(&path);
172+
}
173+
None => {
174+
// Failed to convert string - do nothing and return
175+
return;
176+
}
177+
}
171178
}
172179

173180
#[no_mangle]
@@ -185,7 +192,10 @@ pub mod android {
185192
_: JClass,
186193
java_bucket: JString,
187194
) -> jstring {
188-
let bucket = jstring_to_string(&env, java_bucket);
195+
let bucket = match jstring_to_string(&env, java_bucket) {
196+
Some(s) => s,
197+
None => return create_error_object(&env, "Failed to parse bucket string".to_string()),
198+
};
189199
let bucket_json: Bucket = match serde_json::from_str(&bucket) {
190200
Ok(json) => json,
191201
Err(err) => return create_error_object(&env, err.to_string()),
@@ -207,8 +217,16 @@ pub mod android {
207217
java_event: JString,
208218
java_pulsetime: jdouble,
209219
) -> jstring {
210-
let bucket_id = jstring_to_string(&env, java_bucket_id);
211-
let event = jstring_to_string(&env, java_event);
220+
let bucket_id = match jstring_to_string(&env, java_bucket_id) {
221+
Some(s) => s,
222+
None => {
223+
return create_error_object(&env, "Failed to parse bucket_id string".to_string())
224+
}
225+
};
226+
let event = match jstring_to_string(&env, java_event) {
227+
Some(s) => s,
228+
None => return create_error_object(&env, "Failed to parse event string".to_string()),
229+
};
212230
let pulsetime = java_pulsetime as f64;
213231
let event_json: Event = match serde_json::from_str(&event) {
214232
Ok(json) => json,
@@ -233,7 +251,12 @@ pub mod android {
233251
java_bucket_id: JString,
234252
java_limit: jint,
235253
) -> jstring {
236-
let bucket_id = jstring_to_string(&env, java_bucket_id);
254+
let bucket_id = match jstring_to_string(&env, java_bucket_id) {
255+
Some(s) => s,
256+
None => {
257+
return create_error_object(&env, "Failed to parse bucket_id string".to_string())
258+
}
259+
};
237260
let limit = java_limit as u64;
238261
match openDatastore().get_events(&bucket_id, None, None, Some(limit)) {
239262
Ok(events) => string_to_jstring(&env, json!(events).to_string()),

0 commit comments

Comments
 (0)