diff --git a/src/android/com/unprompted/tildefriends/TildeFriendsActivity.java b/src/android/com/unprompted/tildefriends/TildeFriendsActivity.java index aa62cf76b..4bdb460f7 100644 --- a/src/android/com/unprompted/tildefriends/TildeFriendsActivity.java +++ b/src/android/com/unprompted/tildefriends/TildeFriendsActivity.java @@ -385,8 +385,11 @@ public class TildeFriendsActivity extends Activity { public void onServiceConnected(ComponentName name, IBinder binder) { Log.w("tildefriends", "onServiceConnected"); Parcel data = Parcel.obtain(); - ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(pipe_fd); - data.writeParcelable(pfd, 0); + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(pipe_fd)) { + data.writeParcelable(pfd, 0); + } catch (java.io.IOException e) { + Log.w("tildefriends", "IOException: " + e); + } try { binder.transact(TildeFriendsSandboxService.START_CALL, data, null, IBinder.FLAG_ONEWAY); } catch (RemoteException e) { diff --git a/src/packetstream.c b/src/packetstream.c index 9ce1cd8ec..1fcda91cf 100644 --- a/src/packetstream.c +++ b/src/packetstream.c @@ -12,6 +12,8 @@ typedef struct _tf_packetstream_t { tf_packetstream_onreceive_t* onreceive; void* onreceive_user_data; + tf_packetstream_on_close_t* on_close; + void* on_close_user_data; uv_pipe_t stream; char* buffer; size_t buffer_size; @@ -30,6 +32,8 @@ void tf_packetstream_destroy(tf_packetstream_t* stream) { stream->onreceive = NULL; stream->onreceive_user_data = NULL; + stream->on_close = NULL; + stream->on_close_user_data = NULL; stream->destroyed = true; if (stream->buffer) { @@ -110,6 +114,14 @@ static void _packetstream_on_read(uv_stream_t* handle, ssize_t count, const uv_b } else { + tf_packetstream_on_close_t* on_close = stream->on_close; + void* user_data = stream->on_close_user_data; + stream->on_close = NULL; + stream->on_close_user_data = NULL; + if (on_close) + { + on_close(user_data); + } tf_packetstream_close(stream); } tf_free(buffer->base); @@ -150,7 +162,7 @@ void tf_packetstream_send(tf_packetstream_t* stream, int packet_type, const char int result = uv_write(request, (uv_stream_t*)&stream->stream, &write_buffer, 1, _packetstream_on_write); if (result) { - tf_printf("uv_write: %s\n", uv_strerror(result)); + tf_printf("tf_packetstream_send: uv_write: %s\n", uv_strerror(result)); tf_free(request); } } @@ -162,6 +174,12 @@ void tf_packetstream_set_on_receive(tf_packetstream_t* stream, tf_packetstream_o stream->onreceive_user_data = user_data; } +void tf_packetstream_set_on_close(tf_packetstream_t* stream, tf_packetstream_on_close_t* callback, void* user_data) +{ + stream->on_close = callback; + stream->on_close_user_data = user_data; +} + static void _tf_packetstream_handle_closed(uv_handle_t* handle) { tf_packetstream_t* packetstream = handle->data; diff --git a/src/packetstream.h b/src/packetstream.h index 89df51a2d..47d227977 100644 --- a/src/packetstream.h +++ b/src/packetstream.h @@ -23,6 +23,12 @@ typedef struct _tf_packetstream_t tf_packetstream_t; */ typedef void(tf_packetstream_onreceive_t)(int packet_type, const char* begin, size_t length, void* user_data); +/** +** A function called when a packetstream reads EOF. +** @param user_data User data. +*/ +typedef void(tf_packetstream_on_close_t)(void* user_data); + /** ** Create a packet stream. ** @return The packet stream. @@ -58,6 +64,14 @@ void tf_packetstream_send(tf_packetstream_t* stream, int packet_type, const char */ void tf_packetstream_set_on_receive(tf_packetstream_t* stream, tf_packetstream_onreceive_t* callback, void* user_data); +/** +** Register a callback for when a stream reads EOF. +** @param stream The packet stream. +** @param callback The callback. +** @param user_data User data to pass to the callback. +*/ +void tf_packetstream_set_on_close(tf_packetstream_t* stream, tf_packetstream_on_close_t* callback, void* user_data); + /** ** Close a packet stream. ** @param stream The packet stream. diff --git a/src/taskstub.js.c b/src/taskstub.js.c index 8d7633d65..5df8a8ff8 100644 --- a/src/taskstub.js.c +++ b/src/taskstub.js.c @@ -62,6 +62,7 @@ static JSValue _taskstub_set_on_print(JSContext* context, JSValueConst this_val, static JSValue _taskstub_loadFile(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static void _taskstub_on_process_exit(uv_process_t* process, int64_t status, int terminationSignal); static void _taskstub_finalizer(JSRuntime* runtime, JSValue value); +static void _taskstub_cleanup(tf_taskstub_t* stub); static void _tf_taskstub_run_sandbox_thread(void* data) { @@ -74,12 +75,60 @@ static void _tf_taskstub_run_sandbox_thread(void* data) tf_task_destroy(task); } +static void _taskstub_on_handle_close(uv_handle_t* handle) +{ + tf_taskstub_t* stub = handle->data; + tf_task_remove_child(stub->_owner, stub); + handle->data = NULL; + _taskstub_cleanup(stub); +} + +static void _tf_taskstub_on_exit(tf_taskstub_t* stub, int64_t status, int termination_signal) +{ + JSContext* context = tf_task_get_context(stub->_owner); + if (!JS_IsUndefined(stub->_on_exit)) + { + JSValue ref = JS_DupValue(context, stub->_on_exit); + JSValue argv[] = { JS_NewInt64(context, status), JS_NewInt32(context, termination_signal) }; + JSValue result = JS_Call(context, stub->_on_exit, JS_NULL, 2, argv); + tf_util_report_error(context, result); + JS_FreeValue(context, result); + JS_FreeValue(context, argv[0]); + JS_FreeValue(context, argv[1]); + JS_FreeValue(context, ref); + } + if (stub->_stream) + { + tf_packetstream_destroy(stub->_stream); + stub->_stream = NULL; + } + tf_task_remove_child(stub->_owner, stub); + if (stub->_process.data) + { + uv_close((uv_handle_t*)&stub->_process, _taskstub_on_handle_close); + } + else + { + _taskstub_cleanup(stub); + } +} + +static void _tf_taskstub_packetstream_close(void* user_data) +{ + tf_taskstub_t* stub = user_data; + if (!stub->_process.data) + { + _tf_taskstub_on_exit(stub, -1, -1); + } +} + static JSValue _taskstub_create(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_task_t* parent = tf_task_get(context); tf_taskstub_t* stub = tf_malloc(sizeof(tf_taskstub_t)); memset(stub, 0, sizeof(*stub)); stub->_stream = tf_packetstream_create(); + tf_packetstream_set_on_close(stub->_stream, _tf_taskstub_packetstream_close, stub); JSValue taskObject = JS_NewObjectClass(context, _classId); JS_SetOpaque(taskObject, stub); @@ -314,35 +363,10 @@ static void _taskstub_finalizer(JSRuntime* runtime, JSValue value) _taskstub_cleanup(stub); } -static void _taskstub_on_handle_close(uv_handle_t* handle) -{ - tf_taskstub_t* stub = handle->data; - tf_task_remove_child(stub->_owner, stub); - handle->data = NULL; - _taskstub_cleanup(stub); -} - -static void _taskstub_on_process_exit(uv_process_t* process, int64_t status, int terminationSignal) +static void _taskstub_on_process_exit(uv_process_t* process, int64_t status, int termination_signal) { tf_taskstub_t* stub = process->data; - JSContext* context = tf_task_get_context(stub->_owner); - if (!JS_IsUndefined(stub->_on_exit)) - { - JSValue ref = JS_DupValue(context, stub->_on_exit); - JSValue argv[] = { JS_NewInt64(context, status), JS_NewInt32(context, terminationSignal) }; - JSValue result = JS_Call(context, stub->_on_exit, JS_NULL, 2, argv); - tf_util_report_error(context, result); - JS_FreeValue(context, result); - JS_FreeValue(context, argv[0]); - JS_FreeValue(context, argv[1]); - JS_FreeValue(context, ref); - } - if (stub->_stream) - { - tf_packetstream_destroy(stub->_stream); - stub->_stream = NULL; - } - uv_close((uv_handle_t*)process, _taskstub_on_handle_close); + _tf_taskstub_on_exit(stub, status, termination_signal); } static JSValue _taskstub_getExports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)