[PATCH v13 0/12] MR10569: wineandroid: rework Android integration and switch to split process model
This series reworks the wineandroid driver and moves it away from the current “Wine inside JVM process” model to a split architecture where the Android activity (UI) and Wine run in separate processes. The existing model relies on running Wine inside the JVM process and interacting with Android through JNI callbacks and APC/unixlib-based dispatch. This approach no longer works reliably on modern Android: - Android 10+ applies seccomp restrictions to app processes, making a number of required syscalls unavailable inside the activity process, while processes started via fork/exec are not subject to the same limitations. - The implementation depends on Wine thread context (TEB), signal handling, and register state assumptions that conflict with the JVM runtime (e.g. segment register usage on x86), requiring fragile workarounds. - Due to sandboxing, it is difficult to reliably debug or even observe all failure modes, and future Android changes are likely to tighten these restrictions further. At the same time, downstream projects such as MiceWine, Winlator, Termux’s Wine environment, GameHub and GameNative already use a model where the UI (activity) and Wine run in separate processes and communicate via IPC, which has proven to work reliably on current Android systems. This series implements that model in wineandroid: - Wine is now started in a separate process via fork/exec instead of running inside the JVM process. - Android-facing code no longer depends on the Wine APC/unixlib execution path and runs on the UI thread where appropriate (e.g. native window registration). - ioctl handling is reworked to remove reliance on Wine thread context, with explicit JNIEnv usage and fd-based reply plumbing. - Environment setup and initialization are moved to the Java side, simplifying the native startup path. - Logging for ioctl paths is routed through Android logcat without depending on a Wine TEB. The changes are split into multiple bisect-safe commits to keep intermediate states functional while migrating the code step by step. With Wine running in a separate process, it is no longer subject to JVM seccomp restrictions, and there are no longer conflicts between JVM and Wine execution contexts (signals, thread state, register usage, etc.). <details> <summary>Old message</summary> wineandroid: move ioctl handling to dedicated Java-only thread Move ioctl handling out of the Wine APC/unixlib execution path into a dedicated Java-only thread without Wine context. On Android 10+ a number of syscalls are restricted inside the activity process via seccomp, while processes started via fork/exec are not subject to the same limitations. Decoupling ioctl handling from the Wine context is required to eventually run this code outside of the activity process. This change introduces a new transport and execution model where ioctl dispatch no longer depends on Wine thread state, preparing for moving the Android backend into a separate process. The refactor is intentionally split into multiple bisect-safe commits to keep intermediate states functional while gradually migrating the dispatch path. Since this is a fairly large chunk of work, I’d like to make sure we’re aligned before continuing. </details> -- v13: wineandroid: split Android driver and Wine into separate processes wineandroid: terminate activity when desktop client disconnects wineandroid: make JNI initialization work with direct JVM loading wineandroid: create desktop view via ioctl and pass event pipe wineandroid: return ioctl errors directly wineandroid: remove unixlib/ntoskrnl ioctl path wineandroid: switch dequeueBuffer to socket transport wineandroid: switch ioctl dispatch to socket transport on main thread looper wineandroid: pass JNIEnv explicitly through ioctl handlers wineandroid: add reply_fd plumbing to ioctl path wineandroid: move native window registration to surface_changed wineandroid: use Android logging for ioctl dispatch paths https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Route logging in ioctl dispatch handlers in device.c through __android_log_print and map Wine debug classes to Android log priorities. Use local logging helpers that check __WINE_GET_DEBUGGING directly, with messages emitted unconditionally before the debug channel is initialized. This change is limited to ioctl dispatch paths and does not affect other Wine logging. This prepares the ioctl dispatch code for execution without a Wine TEB, where the standard Wine debug infrastructure cannot be relied on. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 69 ++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 0032224560d..c66d9c6c8a3 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -46,6 +46,30 @@ #include <dlfcn.h> +#define __LOG(cls, prio, ...) \ + do { \ + if (!(__wine_dbch_android.flags & (1 << __WINE_DBCL_INIT)) || \ + __WINE_GET_DEBUGGING(cls, &__wine_dbch_android)) \ + p__android_log_print(ANDROID_LOG_##prio, "wine", __VA_ARGS__); \ + } while (0) + +#define _TRACE(...) __LOG(_TRACE, VERBOSE, __VA_ARGS__) +#define _WARN(...) __LOG(_WARN, WARN, __VA_ARGS__) +#define _FIXME(...) __LOG(_FIXME, WARN, "FIXME: " __VA_ARGS__) +#define _ERR(...) __LOG(_ERR, ERROR, __VA_ARGS__) + +static inline const char *_wine_dbgstr_rect( const RECT *rect ) +{ + enum { N = 4 }; + static __thread char buf[N][64]; + static __thread int idx; + char *ret = buf[idx++ % N]; + + if (!rect) return "(null)"; + snprintf( ret, 64, "(%d,%d)-(%d,%d)", (int)rect->left, (int)rect->top, (int)rect->right, (int)rect->bottom ); + return ret; +} + WINE_DEFAULT_DEBUG_CHANNEL(android); #ifndef SYNC_IOC_WAIT @@ -260,7 +284,7 @@ static struct native_win_data *get_native_win_data( HWND hwnd, BOOL opengl ) struct native_win_data *data = data_map[data_map_idx( hwnd, opengl )]; if (data && data->hwnd == hwnd && !data->opengl == !opengl) return data; - WARN( "unknown win %p opengl %u\n", hwnd, opengl ); + _WARN( "unknown win %p opengl %u\n", hwnd, opengl ); return NULL; } @@ -360,7 +384,7 @@ static int register_buffer( struct native_win_data *win, struct AHardwareBuffer i = win->buffer_lru[NB_CACHED_BUFFERS - 1]; assert( i < NB_CACHED_BUFFERS ); - TRACE( "%p %p evicting buffer %p id %d from cache\n", + _TRACE( "%p %p evicting buffer %p id %d from cache\n", win->hwnd, win->parent, win->buffers[i], i ); pAHardwareBuffer_release(win->buffers[i]); } @@ -369,7 +393,7 @@ static int register_buffer( struct native_win_data *win, struct AHardwareBuffer pAHardwareBuffer_acquire(buffer); *is_new = 1; - TRACE( "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i ); + _TRACE( "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i ); done: insert_buffer_lru( win, i ); @@ -380,7 +404,7 @@ static struct ANativeWindowBuffer *get_registered_buffer( struct native_win_data { if (id < 0 || id >= NB_CACHED_BUFFERS || !win->buffers[id]) { - ERR( "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent ); + _ERR( "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent ); return NULL; } return anwb_from_ahb(win->buffers[id]); @@ -416,7 +440,7 @@ static struct native_win_data *create_native_win_data( HWND hwnd, BOOL opengl ) if (data) { - WARN( "data for %p not freed correctly\n", data->hwnd ); + _WARN( "data for %p not freed correctly\n", data->hwnd ); free_native_win_data( data ); } if (!(data = calloc( 1, sizeof(*data) ))) return NULL; @@ -443,7 +467,7 @@ NTSTATUS android_register_window( void *arg ) { pANativeWindow_release( win ); if (data) NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 ); - TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win ); + _TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win ); return 0; } @@ -456,7 +480,7 @@ NTSTATUS android_register_window( void *arg ) win->setSwapInterval( win, data->swap_interval ); unwrap_java_call(); NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 ); - TRACE( "%p -> %p win %p\n", hwnd, data, win ); + _TRACE( "%p -> %p win %p\n", hwnd, data, win ); return 0; } @@ -490,7 +514,7 @@ static NTSTATUS android_error_to_status( int err ) case -EBADMSG: return STATUS_INVALID_DEVICE_REQUEST; case -EWOULDBLOCK: return STATUS_DEVICE_NOT_READY; default: - FIXME( "unmapped error %d\n", err ); + _FIXME( "unmapped error %d\n", err ); return STATUS_UNSUCCESSFUL; } } @@ -531,7 +555,7 @@ static jobject load_java_method( jmethodID *method, const char *name, const char unwrap_java_call(); if (!*method) { - FIXME( "method %s not found\n", name ); + _FIXME( "method %s not found\n", name ); return NULL; } } @@ -562,7 +586,7 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd), res->hdr.opengl ))) return STATUS_NO_MEMORY; - TRACE( "hwnd %08x opengl %u parent %08x\n", res->hdr.hwnd, res->hdr.opengl, res->parent ); + _TRACE( "hwnd %08x opengl %u parent %08x\n", res->hdr.hwnd, res->hdr.opengl, res->parent ); if (!(object = load_java_method( &method, "createWindow", "(IZZI)V" ))) return STATUS_NOT_SUPPORTED; @@ -583,7 +607,7 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, win_data = get_ioctl_native_win_data( &res->hdr ); - TRACE( "hwnd %08x opengl %u\n", res->hdr.hwnd, res->hdr.opengl ); + _TRACE( "hwnd %08x opengl %u\n", res->hdr.hwnd, res->hdr.opengl ); if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED; @@ -602,9 +626,9 @@ static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_siz if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; - TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n", - res->hdr.hwnd, wine_dbgstr_rect(&res->window_rect), wine_dbgstr_rect(&res->client_rect), - wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner ); + _TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n", + res->hdr.hwnd, _wine_dbgstr_rect(&res->window_rect), _wine_dbgstr_rect(&res->client_rect), + _wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner ); if (!(object = load_java_method( &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" ))) return STATUS_NOT_SUPPORTED; @@ -643,17 +667,17 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, unwrap_java_call(); if (ret) { - ERR( "%08x failed %d\n", res->hdr.hwnd, ret ); + _ERR( "%08x failed %d\n", res->hdr.hwnd, ret ); return android_error_to_status( ret ); } if (!buffer) { - TRACE( "got invalid buffer\n" ); + _TRACE( "got invalid buffer\n" ); return STATUS_UNSUCCESSFUL; } - TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence ); + _TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence ); ahb = pANativeWindowBuffer_getHardwareBuffer( buffer ); res->buffer_id = register_buffer( win_data, ahb, &is_new ); @@ -733,7 +757,7 @@ static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, U if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE; - TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); + _TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); wrap_java_call(); ret = parent->cancelBuffer( parent, buffer, -1 ); unwrap_java_call(); @@ -756,7 +780,7 @@ static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, UL if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE; - TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); + _TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); wrap_java_call(); ret = parent->queueBuffer( parent, buffer, -1 ); unwrap_java_call(); @@ -900,7 +924,7 @@ static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; - TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent ); + _TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent ); if (!(object = load_java_method( &method, "setParent", "(II)V" ))) return STATUS_NOT_SUPPORTED; @@ -918,7 +942,7 @@ static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULO if (res->hdr.hwnd && !get_ioctl_native_win_data( &res->hdr )) return STATUS_INVALID_HANDLE; - TRACE( "hwnd %08x\n", res->hdr.hwnd ); + _TRACE( "hwnd %08x\n", res->hdr.hwnd ); InterlockedExchangePointer( (void **)&capture_window, LongToHandle( res->hdr.hwnd )); return STATUS_SUCCESS; @@ -940,7 +964,7 @@ static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULON if (in_size != offsetof( struct ioctl_android_set_cursor, bits[size] )) return STATUS_INVALID_PARAMETER; - TRACE( "hwnd %08x size %d\n", res->hdr.hwnd, size ); + _TRACE( "hwnd %08x size %d\n", res->hdr.hwnd, size ); if (!(object = load_java_method( &method, "setCursor", "(IIIII[I)V" ))) return STATUS_NOT_SUPPORTED; @@ -1032,6 +1056,7 @@ void start_android_device(void) void *ret_ptr; ULONG ret_len; struct dispatch_callback_params params = {.callback = start_device_callback}; + __wine_dbg_get_channel_flags(&__wine_dbch_android); // force lazy init of debug channel flags for use outside Wine thread context if (KeUserDispatchCallback( ¶ms, sizeof(params), &ret_ptr, &ret_len )) return; if (ret_len == sizeof(thread)) thread = *(HANDLE *)ret_ptr; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Move native window registration from the APC/unixlib callback path to the direct JNI surface_changed callback, so it runs on the Android UI thread. Replace the APC-based register_window_callback mechanism with a direct call to register_native_window(), and remove the associated unixlib plumbing. Serialize native window registration with ioctl dispatch using a shared lock to avoid races between the GUI thread and the ioctl handling thread. Keep WM_ANDROID_REFRESH posted from process_events() after updating the window state. This removes the dependency on the Wine thread/APC execution path for this callback and relocates it to the Android GUI thread. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 3 --- dlls/wineandroid.drv/device.c | 33 ++++++++++++++------------------- dlls/wineandroid.drv/dllmain.c | 13 +------------ dlls/wineandroid.drv/init.c | 6 +----- dlls/wineandroid.drv/unixlib.h | 17 ----------------- dlls/wineandroid.drv/window.c | 13 +++++++------ 6 files changed, 23 insertions(+), 62 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 0bd25de8e9e..f30cf849c41 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -119,8 +119,6 @@ extern BOOL has_client_surface( HWND hwnd ); extern NTSTATUS android_dispatch_ioctl( void *arg ); extern NTSTATUS android_java_init( void *arg ); extern NTSTATUS android_java_uninit( void *arg ); -extern NTSTATUS android_register_window( void *arg ); -extern PNTAPCFUNC register_window_callback; extern UINT64 start_device_callback; extern unsigned int screen_width; @@ -175,7 +173,6 @@ union event_data { enum event_type type; HWND hwnd; - ANativeWindow *window; BOOL client; unsigned int width; unsigned int height; diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index c66d9c6c8a3..10c3d5e2f91 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -81,6 +81,8 @@ static JNIEnv *jni_env; static HWND capture_window; static HWND desktop_window; +static pthread_mutex_t dispatch_ioctl_lock = PTHREAD_MUTEX_INITIALIZER; + #define ANDROIDCONTROLTYPE ((ULONG)'A') #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS) @@ -453,41 +455,32 @@ static struct native_win_data *create_native_win_data( HWND hwnd, BOOL opengl ) return data; } -NTSTATUS android_register_window( void *arg ) +/* register a native window received from the UI thread for use in ioctls */ +void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl ) { - struct register_window_params *params = arg; - HWND hwnd = (HWND)params->arg1; - struct ANativeWindow *win = (struct ANativeWindow *)params->arg2; - BOOL opengl = params->arg3; - struct native_win_data *data = get_native_win_data( hwnd, opengl ); + struct native_win_data *data = NULL; + + pthread_mutex_lock(&dispatch_ioctl_lock); + data = get_native_win_data( hwnd, opengl ); - if (!win) return 0; /* do nothing and hold on to the window until we get a new surface */ + if (!win) goto end; /* do nothing and hold on to the window until we get a new surface */ if (!data || data->parent == win) { pANativeWindow_release( win ); - if (data) NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 ); _TRACE( "%p -> %p win %p (unchanged)\n", hwnd, data, win ); - return 0; + goto end; } release_native_window( data ); data->parent = win; data->generation++; - wrap_java_call(); if (data->api) win->perform( win, NATIVE_WINDOW_API_CONNECT, data->api ); win->perform( win, NATIVE_WINDOW_SET_BUFFERS_FORMAT, data->buffer_format ); win->setSwapInterval( win, data->swap_interval ); - unwrap_java_call(); - NtUserPostMessage( hwnd, WM_ANDROID_REFRESH, opengl, 0 ); _TRACE( "%p -> %p win %p\n", hwnd, data, win ); - return 0; -} - -/* register a native window received from the Java side for use in ioctls */ -void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl ) -{ - NtQueueApcThread( thread, register_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, opengl ); +end: + pthread_mutex_unlock(&dispatch_ioctl_lock); } /* get the capture window stored in the desktop process */ @@ -1018,9 +1011,11 @@ NTSTATUS android_dispatch_ioctl( void *arg ) if (in_size >= sizeof(*header)) { irp->IoStatus.Information = 0; + pthread_mutex_lock(&dispatch_ioctl_lock); irp->IoStatus.Status = func( irp->AssociatedIrp.SystemBuffer, in_size, irpsp->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus.Information ); + pthread_mutex_unlock(&dispatch_ioctl_lock); } else irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } diff --git a/dlls/wineandroid.drv/dllmain.c b/dlls/wineandroid.drv/dllmain.c index 7f6d04e83df..dd2493c6f55 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -90,26 +90,15 @@ static NTSTATUS WINAPI android_start_device(void *param, ULONG size) } -static void CALLBACK register_window_callback( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 ) -{ - struct register_window_params params = { .arg1 = arg1, .arg2 = arg2, .arg3 = arg3 }; - ANDROID_CALL( register_window, ¶ms ); -} - - /*********************************************************************** * dll initialisation routine */ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) { - struct init_params params; - if (reason != DLL_PROCESS_ATTACH) return TRUE; DisableThreadLibraryCalls( inst ); if (__wine_init_unix_call()) return FALSE; - params.register_window_callback = register_window_callback; - params.start_device_callback = (UINT_PTR)android_start_device; - return !ANDROID_CALL( init, ¶ms ); + return !ANDROID_CALL( init, (void *)(UINT_PTR)android_start_device ); } diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 0dbd6c11785..8e6c700870a 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -50,7 +50,6 @@ static const unsigned int screen_bpp = 32; /* we don't support other modes */ static RECT monitor_rc_work; static int device_init_done; -PNTAPCFUNC register_window_callback; UINT64 start_device_callback; typedef struct @@ -386,7 +385,6 @@ static void load_android_libs(void) static HRESULT android_init( void *arg ) { - struct init_params *params = arg; pthread_mutexattr_t attr; jclass class; JNIEnv *jni_env; @@ -398,8 +396,7 @@ static HRESULT android_init( void *arg ) pthread_mutex_init( &win_data_mutex, &attr ); pthread_mutexattr_destroy( &attr ); - register_window_callback = params->register_window_callback; - start_device_callback = params->start_device_callback; + start_device_callback = (UINT64)(UINT_PTR)arg; if (java_vm) /* running under Java */ { @@ -426,7 +423,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = android_init, android_java_init, android_java_uninit, - android_register_window, }; diff --git a/dlls/wineandroid.drv/unixlib.h b/dlls/wineandroid.drv/unixlib.h index 39a4df58283..7549541e48e 100644 --- a/dlls/wineandroid.drv/unixlib.h +++ b/dlls/wineandroid.drv/unixlib.h @@ -25,24 +25,7 @@ enum android_funcs unix_init, unix_java_init, unix_java_uninit, - unix_register_window, unix_funcs_count }; #define ANDROID_CALL(func, params) WINE_UNIX_CALL( unix_ ## func, params ) - -/* android_init params */ -struct init_params -{ - PNTAPCFUNC register_window_callback; - UINT64 start_device_callback; -}; - - -/* android_register_window params */ -struct register_window_params -{ - UINT_PTR arg1; - UINT_PTR arg2; - UINT_PTR arg3; -}; diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 97eb3004ba8..b3f3aeea955 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -246,11 +246,12 @@ void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, jbool if (win->query( win, NATIVE_WINDOW_WIDTH, &width ) < 0) width = 0; if (win->query( win, NATIVE_WINDOW_HEIGHT, &height ) < 0) height = 0; - data.surface.window = win; data.surface.width = width; data.surface.height = height; - p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %s %ux%u", - data.surface.hwnd, client ? "client" : "whole", width, height ); + p__android_log_print( ANDROID_LOG_INFO, "wine", "surface_changed: %p %p %s %ux%u", + data.surface.hwnd, win, client ? "client" : "whole", width, height ); + + register_native_window( data.surface.hwnd, win, data.surface.client ); } data.type = SURFACE_CHANGED; send_event( &data ); @@ -452,11 +453,11 @@ static int process_events( DWORD mask ) break; case SURFACE_CHANGED: - TRACE("SURFACE_CHANGED %p %p %s size %ux%u\n", event->data.surface.hwnd, - event->data.surface.window, event->data.surface.client ? "client" : "whole", + TRACE("SURFACE_CHANGED %p %s size %ux%u\n", event->data.surface.hwnd, + event->data.surface.client ? "client" : "whole", event->data.surface.width, event->data.surface.height ); - register_native_window( event->data.surface.hwnd, event->data.surface.window, event->data.surface.client ); + NtUserPostMessage( event->data.surface.hwnd, WM_ANDROID_REFRESH, event->data.surface.client, 0 ); break; case MOTION_EVENT: -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Add an optional reply_fd parameter to all android ioctl handlers and propagate it through android_dispatch_ioctl and android_ioctl, including all ioctl call sites. This prepares the ioctl path for passing file descriptors alongside regular responses. The new parameter is not used yet and all callers pass NULL, so there is no change in behavior. This change is intentionally kept separate since it is mechanically large but conceptually simple, making subsequent functional changes easier to review. This is a preparatory change with no functional impact. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 55 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 10c3d5e2f91..d856ae85401 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -567,7 +567,7 @@ static void create_desktop_view(void) unwrap_java_call(); } -static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -589,7 +589,7 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U return STATUS_SUCCESS; } -static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -611,7 +611,7 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, return STATUS_SUCCESS; } -static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -635,7 +635,7 @@ static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_siz return STATUS_SUCCESS; } -static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ANativeWindow *parent; struct ioctl_android_dequeueBuffer *res = data; @@ -734,7 +734,7 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, return STATUS_SUCCESS; } -static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_cancelBuffer *res = data; struct ANativeWindow *parent; @@ -757,7 +757,7 @@ static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, U return android_error_to_status( ret ); } -static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_queueBuffer *res = data; struct ANativeWindow *parent; @@ -780,7 +780,7 @@ static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, UL return android_error_to_status( ret ); } -static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_query *res = data; struct ANativeWindow *parent; @@ -800,7 +800,7 @@ static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PT return android_error_to_status( ret ); } -static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_perform *res = data; struct ANativeWindow *parent; @@ -887,7 +887,7 @@ static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_ return android_error_to_status( ret ); } -static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_swap_interval *res = data; struct ANativeWindow *parent; @@ -906,7 +906,7 @@ static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size return android_error_to_status( ret ); } -static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -927,7 +927,7 @@ static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size return STATUS_SUCCESS; } -static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_capture *res = data; @@ -941,7 +941,7 @@ static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULO return STATUS_SUCCESS; } -static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) +static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -979,7 +979,7 @@ static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULON return STATUS_SUCCESS; } -typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ); +typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ); static const ioctl_func ioctl_funcs[] = { createWindow_ioctl, /* IOCTL_CREATE_WINDOW */ @@ -1010,11 +1010,12 @@ NTSTATUS android_dispatch_ioctl( void *arg ) if (in_size >= sizeof(*header)) { + int reply_fd = -1; irp->IoStatus.Information = 0; pthread_mutex_lock(&dispatch_ioctl_lock); irp->IoStatus.Status = func( irp->AssociatedIrp.SystemBuffer, in_size, irpsp->Parameters.DeviceIoControl.OutputBufferLength, - &irp->IoStatus.Information ); + &irp->IoStatus.Information, &reply_fd ); pthread_mutex_unlock(&dispatch_ioctl_lock); } else irp->IoStatus.Status = STATUS_INVALID_PARAMETER; @@ -1060,7 +1061,7 @@ void start_android_device(void) /* Client-side ioctl support */ -static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size ) +static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *reply_fd ) { static const WCHAR deviceW[] = { '\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d', 0 }; static HANDLE device; @@ -1120,7 +1121,7 @@ static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuff res.buffer_id = -1; res.generation = 0; - ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size ); + ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size, NULL ); if (ret) return ret; if (size < sizeof(res)) return -EINVAL; @@ -1176,7 +1177,7 @@ static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffe cancel.hdr.hwnd = HandleToLong( win->hwnd ); cancel.hdr.opengl = win->opengl; wait_fence_and_close( fence ); - return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL ); + return android_ioctl( IOCTL_CANCEL_BUFFER, &cancel, sizeof(cancel), NULL, NULL, NULL ); } static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence ) @@ -1195,7 +1196,7 @@ static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer queue.hdr.hwnd = HandleToLong( win->hwnd ); queue.hdr.opengl = win->opengl; wait_fence_and_close( fence ); - return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL ); + return android_ioctl( IOCTL_QUEUE_BUFFER, &queue, sizeof(queue), NULL, NULL, NULL ); } static int dequeueBuffer_DEPRECATED( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer ) @@ -1230,7 +1231,7 @@ static int setSwapInterval( struct ANativeWindow *window, int interval ) swap.hdr.hwnd = HandleToLong( win->hwnd ); swap.hdr.opengl = win->opengl; swap.interval = interval; - return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL ); + return android_ioctl( IOCTL_SET_SWAP_INT, &swap, sizeof(swap), NULL, NULL, NULL ); } static int query( const ANativeWindow *window, int what, int *value ) @@ -1243,7 +1244,7 @@ static int query( const ANativeWindow *window, int what, int *value ) query.hdr.hwnd = HandleToLong( win->hwnd ); query.hdr.opengl = win->opengl; query.what = what; - ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size ); + ret = android_ioctl( IOCTL_QUERY, &query, sizeof(query), &query, &size, NULL ); TRACE( "hwnd %p what %d got %d -> %p\n", win->hwnd, what, query.value, value ); if (!ret) *value = query.value; return ret; @@ -1385,7 +1386,7 @@ static int perform( ANativeWindow *window, int operation, ... ) break; } va_end( args ); - return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL ); + return android_ioctl( IOCTL_PERFORM, &perf, sizeof(perf), NULL, NULL, NULL ); } struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl ) @@ -1418,7 +1419,7 @@ struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl ) req.hdr.opengl = win->opengl; req.parent = get_ioctl_win_parent( NtUserGetAncestor( hwnd, GA_PARENT )); req.is_desktop = hwnd == desktop_window; - android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL ); + android_ioctl( IOCTL_CREATE_WINDOW, &req, sizeof(req), NULL, NULL, NULL ); return &win->win; } @@ -1451,7 +1452,7 @@ void destroy_ioctl_window( HWND hwnd, BOOL opengl ) req.hdr.hwnd = HandleToLong( hwnd ); req.hdr.opengl = opengl; - android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL ); + android_ioctl( IOCTL_DESTROY_WINDOW, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_window_pos_changed( HWND hwnd, const struct window_rects *rects, @@ -1468,7 +1469,7 @@ int ioctl_window_pos_changed( HWND hwnd, const struct window_rects *rects, req.flags = flags; req.after = HandleToLong( after ); req.owner = HandleToLong( owner ); - return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL ); + return android_ioctl( IOCTL_WINDOW_POS_CHANGED, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_set_window_parent( HWND hwnd, HWND parent ) @@ -1478,7 +1479,7 @@ int ioctl_set_window_parent( HWND hwnd, HWND parent ) req.hdr.hwnd = HandleToLong( hwnd ); req.hdr.opengl = FALSE; req.parent = get_ioctl_win_parent( parent ); - return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL ); + return android_ioctl( IOCTL_SET_WINDOW_PARENT, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_set_capture( HWND hwnd ) @@ -1487,7 +1488,7 @@ int ioctl_set_capture( HWND hwnd ) req.hdr.hwnd = HandleToLong( hwnd ); req.hdr.opengl = FALSE; - return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL ); + return android_ioctl( IOCTL_SET_CAPTURE, &req, sizeof(req), NULL, NULL, NULL ); } int ioctl_set_cursor( int id, int width, int height, @@ -1506,7 +1507,7 @@ int ioctl_set_cursor( int id, int width, int height, req->hotspotx = hotspotx; req->hotspoty = hotspoty; memcpy( req->bits, bits, width * height * sizeof(req->bits[0]) ); - ret = android_ioctl( IOCTL_SET_CURSOR, req, size, NULL, NULL ); + ret = android_ioctl( IOCTL_SET_CURSOR, req, size, NULL, NULL, NULL ); free( req ); return ret; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Pass JNIEnv *env explicitly through the ioctl dispatch path and all ioctl handlers, and stop relying on the global jni_env variable in these code paths. Update all JNI call sites in the ioctl dispatch and related functions to use the passed env parameter, including method lookup and CallVoidMethod invocations, bringing these JNI interaction paths closer to the canonical usage pattern where JNIEnv is strictly per-thread and not stored globally. Other uses of the global jni_env remain and will be addressed in follow-up changes. This change is mechanically large but does not introduce functional changes, and is kept separate to simplify review of subsequent changes. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 88 +++++++++++++++++------------------ 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index d856ae85401..1295b8ec252 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -241,12 +241,12 @@ static inline BOOL is_in_desktop_process(void) static WORD orig_fs, java_fs; static inline void wrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (java_fs) ); } static inline void unwrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (orig_fs) ); } -static inline void init_java_thread( JavaVM *java_vm ) +static inline void init_java_thread( JavaVM *java_vm, JNIEnv** env ) { java_fs = java_gdt_sel; __asm__( "mov %%fs,%0" : "=r" (orig_fs) ); __asm__( "mov %0,%%fs" :: "r" (java_fs) ); - (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); + (*java_vm)->AttachCurrentThread( java_vm, env, 0 ); if (!java_gdt_sel) __asm__( "mov %%fs,%0" : "=r" (java_fs) ); __asm__( "mov %0,%%fs" :: "r" (orig_fs) ); } @@ -259,10 +259,10 @@ static void *orig_teb, *java_teb; static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); } static inline void wrap_java_call(void) { arch_prctl( ARCH_SET_GS, java_teb ); } static inline void unwrap_java_call(void) { arch_prctl( ARCH_SET_GS, orig_teb ); } -static inline void init_java_thread( JavaVM *java_vm ) +static inline void init_java_thread( JavaVM *java_vm, JNIEnv** env ) { arch_prctl( ARCH_GET_GS, &orig_teb ); - (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); + (*java_vm)->AttachCurrentThread( java_vm, env, 0 ); arch_prctl( ARCH_GET_GS, &java_teb ); arch_prctl( ARCH_SET_GS, orig_teb ); } @@ -270,7 +270,7 @@ static inline void init_java_thread( JavaVM *java_vm ) #else static inline void wrap_java_call(void) { } static inline void unwrap_java_call(void) { } -static inline void init_java_thread( JavaVM *java_vm ) { (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); } +static inline void init_java_thread( JavaVM *java_vm, JNIEnv** env ) { (*java_vm)->AttachCurrentThread( java_vm, env, 0 ); } #endif /* __i386__ */ static struct native_win_data *data_map[65536]; @@ -536,15 +536,15 @@ static int status_to_android_error( unsigned int status ) } } -static jobject load_java_method( jmethodID *method, const char *name, const char *args ) +static jobject load_java_method( JNIEnv* env, jmethodID *method, const char *name, const char *args ) { if (!*method) { jclass class; wrap_java_call(); - class = (*jni_env)->GetObjectClass( jni_env, java_object ); - *method = (*jni_env)->GetMethodID( jni_env, class, name, args ); + class = (*env)->GetObjectClass( env, java_object ); + *method = (*env)->GetMethodID( env, class, name, args ); unwrap_java_call(); if (!*method) { @@ -555,19 +555,19 @@ static jobject load_java_method( jmethodID *method, const char *name, const char return java_object; } -static void create_desktop_view(void) +static void create_desktop_view( JNIEnv* env ) { static jmethodID method; jobject object; - if (!(object = load_java_method( &method, "createDesktopView", "()V" ))) return; + if (!(object = load_java_method( env, &method, "createDesktopView", "()V" ))) return; wrap_java_call(); - (*jni_env)->CallVoidMethod( jni_env, object, method ); + (*env)->CallVoidMethod( env, object, method ); unwrap_java_call(); } -static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS createWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -581,15 +581,15 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U _TRACE( "hwnd %08x opengl %u parent %08x\n", res->hdr.hwnd, res->hdr.opengl, res->parent ); - if (!(object = load_java_method( &method, "createWindow", "(IZZI)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( env, &method, "createWindow", "(IZZI)V" ))) return STATUS_NOT_SUPPORTED; wrap_java_call(); - (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->is_desktop, res->hdr.opengl, res->parent ); + (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->is_desktop, res->hdr.opengl, res->parent ); unwrap_java_call(); return STATUS_SUCCESS; } -static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS destroyWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -602,16 +602,16 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, _TRACE( "hwnd %08x opengl %u\n", res->hdr.hwnd, res->hdr.opengl ); - if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( env, &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED; wrap_java_call(); - (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd ); + (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd ); unwrap_java_call(); if (win_data) free_native_win_data( win_data ); return STATUS_SUCCESS; } -static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS windowPosChanged_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -623,19 +623,19 @@ static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_siz res->hdr.hwnd, _wine_dbgstr_rect(&res->window_rect), _wine_dbgstr_rect(&res->client_rect), _wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner ); - if (!(object = load_java_method( &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" ))) + if (!(object = load_java_method( env, &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" ))) return STATUS_NOT_SUPPORTED; wrap_java_call(); - (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style, - res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom, - res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom, - res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom ); + (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style, + res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom, + res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom, + res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom ); unwrap_java_call(); return STATUS_SUCCESS; } -static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ANativeWindow *parent; struct ioctl_android_dequeueBuffer *res = data; @@ -734,7 +734,7 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, return STATUS_SUCCESS; } -static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS cancelBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_cancelBuffer *res = data; struct ANativeWindow *parent; @@ -757,7 +757,7 @@ static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, U return android_error_to_status( ret ); } -static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS queueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_queueBuffer *res = data; struct ANativeWindow *parent; @@ -780,7 +780,7 @@ static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, UL return android_error_to_status( ret ); } -static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS query_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_query *res = data; struct ANativeWindow *parent; @@ -800,7 +800,7 @@ static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PT return android_error_to_status( ret ); } -static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS perform_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_perform *res = data; struct ANativeWindow *parent; @@ -887,7 +887,7 @@ static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_ return android_error_to_status( ret ); } -static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS setSwapInterval_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_swap_interval *res = data; struct ANativeWindow *parent; @@ -906,7 +906,7 @@ static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size return android_error_to_status( ret ); } -static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS setWindowParent_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -919,15 +919,15 @@ static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size _TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent ); - if (!(object = load_java_method( &method, "setParent", "(II)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( env, &method, "setParent", "(II)V" ))) return STATUS_NOT_SUPPORTED; wrap_java_call(); - (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent ); + (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->parent ); unwrap_java_call(); return STATUS_SUCCESS; } -static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS setCapture_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_capture *res = data; @@ -941,7 +941,7 @@ static NTSTATUS setCapture_ioctl( void *data, DWORD in_size, DWORD out_size, ULO return STATUS_SUCCESS; } -static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static NTSTATUS setCursor_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; @@ -959,27 +959,27 @@ static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULON _TRACE( "hwnd %08x size %d\n", res->hdr.hwnd, size ); - if (!(object = load_java_method( &method, "setCursor", "(IIIII[I)V" ))) + if (!(object = load_java_method( env, &method, "setCursor", "(IIIII[I)V" ))) return STATUS_NOT_SUPPORTED; wrap_java_call(); if (size) { - jintArray array = (*jni_env)->NewIntArray( jni_env, size ); - (*jni_env)->SetIntArrayRegion( jni_env, array, 0, size, (jint *)res->bits ); - (*jni_env)->CallVoidMethod( jni_env, object, method, 0, res->width, res->height, + jintArray array = (*env)->NewIntArray( env, size ); + (*env)->SetIntArrayRegion( env, array, 0, size, (jint *)res->bits ); + (*env)->CallVoidMethod( env, object, method, 0, res->width, res->height, res->hotspotx, res->hotspoty, array ); - (*jni_env)->DeleteLocalRef( jni_env, array ); + (*env)->DeleteLocalRef( env, array ); } - else (*jni_env)->CallVoidMethod( jni_env, object, method, res->id, 0, 0, 0, 0, NULL ); + else (*env)->CallVoidMethod( env, object, method, res->id, 0, 0, 0, 0, NULL ); unwrap_java_call(); return STATUS_SUCCESS; } -typedef NTSTATUS (*ioctl_func)( void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ); +typedef NTSTATUS (*ioctl_func)( JNIEnv* env, void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ); static const ioctl_func ioctl_funcs[] = { createWindow_ioctl, /* IOCTL_CREATE_WINDOW */ @@ -1013,7 +1013,7 @@ NTSTATUS android_dispatch_ioctl( void *arg ) int reply_fd = -1; irp->IoStatus.Information = 0; pthread_mutex_lock(&dispatch_ioctl_lock); - irp->IoStatus.Status = func( irp->AssociatedIrp.SystemBuffer, in_size, + irp->IoStatus.Status = func( jni_env, irp->AssociatedIrp.SystemBuffer, in_size, irpsp->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus.Information, &reply_fd ); pthread_mutex_unlock(&dispatch_ioctl_lock); @@ -1032,8 +1032,8 @@ NTSTATUS android_java_init( void *arg ) { if (!java_vm) return STATUS_UNSUCCESSFUL; /* not running under Java */ - init_java_thread( java_vm ); - create_desktop_view(); + init_java_thread( java_vm, &jni_env ); + create_desktop_view( jni_env ); return STATUS_SUCCESS; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Implement ioctl handling over a UNIX SEQPACKET socket integrated with the Android main thread ALooper. Ioctls are now dispatched directly from ALooper callbacks using a JNI-attached environment captured during looper initialization, removing the need for a dedicated dispatch thread. A temporary bootstrap thread is used to obtain the main thread looper without interfering with the current Wine/JVM execution context. Keep dequeueBuffer on the old transport for bisect safety, as it still depends on wine_server_fd_to_handle() and requires a Wine TEB. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/WineActivity.java | 35 ++- dlls/wineandroid.drv/android.h | 7 + dlls/wineandroid.drv/device.c | 301 +++++++++++++++++++++---- dlls/wineandroid.drv/init.c | 11 + 4 files changed, 302 insertions(+), 52 deletions(-) diff --git a/dlls/wineandroid.drv/WineActivity.java b/dlls/wineandroid.drv/WineActivity.java index 6488188b93a..1ee99b8a037 100644 --- a/dlls/wineandroid.drv/WineActivity.java +++ b/dlls/wineandroid.drv/WineActivity.java @@ -30,6 +30,8 @@ import android.graphics.SurfaceTexture; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.preference.PreferenceManager; import android.system.ErrnoException; import android.util.Log; @@ -52,6 +54,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.concurrent.CountDownLatch; import static android.system.Os.setenv; import static android.system.Os.getenv; @@ -59,6 +62,7 @@ public class WineActivity extends Activity { private native String wine_init( String[] cmdline ); + private native void wine_looper_init(); public native void wine_desktop_changed( int width, int height ); public native void wine_config_changed( int dpi ); public native void wine_surface_changed( int hwnd, Surface surface, boolean opengl ); @@ -73,6 +77,8 @@ public class WineActivity extends Activity protected WineWindow message_window; private PointerIcon current_cursor; + private static final Handler uiHandler = new Handler(Looper.getMainLooper()); + @Override public void onCreate(Bundle savedInstanceState) { @@ -834,31 +840,40 @@ public void window_pos_changed( int hwnd, int flags, int insert_after, int owner win.pos_changed( flags, insert_after, owner, style, window_rect, client_rect, visible_rect ); } + /* Always post to the UI thread handler instead of using runOnUiThread(). + * runOnUiThread() may execute the runnable immediately if already on the + * UI thread, which can break assumptions about ordering and lead to crashes. + * We need deferred execution to preserve the original asynchronous behavior. + */ + private void postToUiThread(Runnable r) { + uiHandler.post(r); + } + public void createDesktopView() { - runOnUiThread( new Runnable() { public void run() { create_desktop_view(); }} ); + postToUiThread( new Runnable() { public void run() { create_desktop_view(); }} ); } public void createWindow( final int hwnd, final boolean is_desktop, final boolean opengl, final int parent ) { - runOnUiThread( new Runnable() { public void run() { create_window( hwnd, is_desktop, opengl, parent ); }} ); + postToUiThread( new Runnable() { public void run() { create_window( hwnd, is_desktop, opengl, parent ); }} ); } public void destroyWindow( final int hwnd ) { - runOnUiThread( new Runnable() { public void run() { destroy_window( hwnd ); }} ); + postToUiThread( new Runnable() { public void run() { destroy_window( hwnd ); }} ); } public void setParent( final int hwnd, final int parent ) { - runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd, parent ); }} ); + postToUiThread( new Runnable() { public void run() { set_window_parent( hwnd, parent ); }} ); } public void setCursor( final int id, final int width, final int height, final int hotspotx, final int hotspoty, final int bits[] ) { if (Build.VERSION.SDK_INT < 24) return; - runOnUiThread( new Runnable() { public void run() { set_cursor( id, width, height, hotspotx, hotspoty, bits ); }} ); + postToUiThread( new Runnable() { public void run() { set_cursor( id, width, height, hotspotx, hotspoty, bits ); }} ); } public void windowPosChanged( final int hwnd, final int flags, final int insert_after, @@ -873,8 +888,16 @@ public void windowPosChanged( final int hwnd, final int flags, final int insert_ final Rect window_rect = new Rect( window_left, window_top, window_right, window_bottom ); final Rect client_rect = new Rect( client_left, client_top, client_right, client_bottom ); final Rect visible_rect = new Rect( visible_left, visible_top, visible_right, visible_bottom ); - runOnUiThread( new Runnable() { + postToUiThread( new Runnable() { public void run() { window_pos_changed( hwnd, flags, insert_after, owner, style, window_rect, client_rect, visible_rect ); }} ); } + + private void obtainLooper() { + CountDownLatch latch = new CountDownLatch(1); + runOnUiThread( new Runnable() { public void run() { + try { wine_looper_init(); } finally { latch.countDown(); } + }}); + try { latch.await(); } catch ( Exception e ) {} + } } diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index f30cf849c41..4882ca91f8b 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -28,6 +28,7 @@ #include <jni.h> #include <android/log.h> #include <android/input.h> +#include <android/looper.h> #include <android/native_window_jni.h> #include "windef.h" @@ -58,6 +59,11 @@ DECL_FUNCPTR( AHardwareBuffer_unlock ); DECL_FUNCPTR( AHardwareBuffer_recvHandleFromUnixSocket ); DECL_FUNCPTR( AHardwareBuffer_sendHandleToUnixSocket ); DECL_FUNCPTR( ANativeWindowBuffer_getHardwareBuffer ); +DECL_FUNCPTR( ALooper_acquire ); +DECL_FUNCPTR( ALooper_forThread ); +DECL_FUNCPTR( ALooper_addFd ); +DECL_FUNCPTR( ALooper_removeFd ); +DECL_FUNCPTR( ALooper_release ); #endif #undef DECL_FUNCPTR @@ -137,6 +143,7 @@ extern void set_screen_dpi( DWORD dpi ); extern void update_keyboard_lock_state( WORD vkey, UINT state ); /* JNI entry points */ +extern void looper_init( JNIEnv *env, jobject obj ); extern void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height ); extern void config_changed( JNIEnv *env, jobject obj, jint dpi ); extern void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 1295b8ec252..798b23ef790 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -32,6 +32,8 @@ #include <stdarg.h> #include <sys/ioctl.h> #include <sys/socket.h> +#include <sys/un.h> +#include <sys/uio.h> #include <unistd.h> #include "ntstatus.h" @@ -135,6 +137,14 @@ struct native_win_wrapper LONG ref; }; +#define IPC_SOCKET_NAME "\0\\Device\\WineAndroid" +#define IPC_SOCKET_ADDR_LEN ((socklen_t)(offsetof(struct sockaddr_un, sun_path) + sizeof(IPC_SOCKET_NAME) - 1)) + +static const struct sockaddr_un ipc_addr = { + .sun_family = AF_UNIX, + .sun_path = IPC_SOCKET_NAME, +}; + struct ioctl_header { int hwnd; @@ -542,10 +552,8 @@ static jobject load_java_method( JNIEnv* env, jmethodID *method, const char *nam { jclass class; - wrap_java_call(); class = (*env)->GetObjectClass( env, java_object ); *method = (*env)->GetMethodID( env, class, name, args ); - unwrap_java_call(); if (!*method) { _FIXME( "method %s not found\n", name ); @@ -560,10 +568,11 @@ static void create_desktop_view( JNIEnv* env ) static jmethodID method; jobject object; - if (!(object = load_java_method( env, &method, "createDesktopView", "()V" ))) return; - wrap_java_call(); + if (!(object = load_java_method( env, &method, "createDesktopView", "()V" ))) goto end; + (*env)->CallVoidMethod( env, object, method ); +end: unwrap_java_call(); } @@ -583,9 +592,7 @@ static NTSTATUS createWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWOR if (!(object = load_java_method( env, &method, "createWindow", "(IZZI)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->is_desktop, res->hdr.opengl, res->parent ); - unwrap_java_call(); return STATUS_SUCCESS; } @@ -604,9 +611,7 @@ static NTSTATUS destroyWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWO if (!(object = load_java_method( env, &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd ); - unwrap_java_call(); if (win_data) free_native_win_data( win_data ); return STATUS_SUCCESS; } @@ -626,12 +631,10 @@ static NTSTATUS windowPosChanged_ioctl( JNIEnv* env, void *data, DWORD in_size, if (!(object = load_java_method( env, &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style, res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom, res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom, res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom ); - unwrap_java_call(); return STATUS_SUCCESS; } @@ -751,9 +754,7 @@ static NTSTATUS cancelBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWOR if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE; _TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); - wrap_java_call(); ret = parent->cancelBuffer( parent, buffer, -1 ); - unwrap_java_call(); return android_error_to_status( ret ); } @@ -774,9 +775,7 @@ static NTSTATUS queueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE; _TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); - wrap_java_call(); ret = parent->queueBuffer( parent, buffer, -1 ); - unwrap_java_call(); return android_error_to_status( ret ); } @@ -794,9 +793,7 @@ static NTSTATUS query_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_s if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY; *ret_size = sizeof( *res ); - wrap_java_call(); ret = parent->query( parent, res->what, &res->value ); - unwrap_java_call(); return android_error_to_status( ret ); } @@ -815,57 +812,39 @@ static NTSTATUS perform_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out switch (res->operation) { case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - wrap_java_call(); ret = parent->perform( parent, res->operation, res->args[0] ); - unwrap_java_call(); if (!ret) win_data->buffer_format = res->args[0]; break; case NATIVE_WINDOW_API_CONNECT: - wrap_java_call(); ret = parent->perform( parent, res->operation, res->args[0] ); - unwrap_java_call(); if (!ret) win_data->api = res->args[0]; break; case NATIVE_WINDOW_API_DISCONNECT: - wrap_java_call(); ret = parent->perform( parent, res->operation, res->args[0] ); - unwrap_java_call(); if (!ret) win_data->api = 0; break; case NATIVE_WINDOW_SET_USAGE: case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: case NATIVE_WINDOW_SET_SCALING_MODE: - wrap_java_call(); ret = parent->perform( parent, res->operation, res->args[0] ); - unwrap_java_call(); break; case NATIVE_WINDOW_SET_BUFFER_COUNT: - wrap_java_call(); ret = parent->perform( parent, res->operation, (size_t)res->args[0] ); - unwrap_java_call(); break; case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: - wrap_java_call(); ret = parent->perform( parent, res->operation, res->args[0], res->args[1] ); - unwrap_java_call(); break; case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - wrap_java_call(); ret = parent->perform( parent, res->operation, res->args[0], res->args[1], res->args[2] ); - unwrap_java_call(); break; case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: - wrap_java_call(); ret = parent->perform( parent, res->operation, res->args[0] | ((int64_t)res->args[1] << 32) ); - unwrap_java_call(); break; case NATIVE_WINDOW_CONNECT: case NATIVE_WINDOW_DISCONNECT: case NATIVE_WINDOW_UNLOCK_AND_POST: - wrap_java_call(); ret = parent->perform( parent, res->operation ); - unwrap_java_call(); break; case NATIVE_WINDOW_SET_CROP: { @@ -874,9 +853,7 @@ static NTSTATUS perform_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out rect.top = res->args[1]; rect.right = res->args[2]; rect.bottom = res->args[3]; - wrap_java_call(); ret = parent->perform( parent, res->operation, &rect ); - unwrap_java_call(); break; } case NATIVE_WINDOW_LOCK: @@ -900,9 +877,7 @@ static NTSTATUS setSwapInterval_ioctl( JNIEnv* env, void *data, DWORD in_size, D win_data->swap_interval = res->interval; if (!(parent = win_data->parent)) return STATUS_SUCCESS; - wrap_java_call(); ret = parent->setSwapInterval( parent, res->interval ); - unwrap_java_call(); return android_error_to_status( ret ); } @@ -921,9 +896,7 @@ static NTSTATUS setWindowParent_ioctl( JNIEnv* env, void *data, DWORD in_size, D if (!(object = load_java_method( env, &method, "setParent", "(II)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->parent ); - unwrap_java_call(); return STATUS_SUCCESS; } @@ -962,8 +935,6 @@ static NTSTATUS setCursor_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD o if (!(object = load_java_method( env, &method, "setCursor", "(IIIII[I)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); - if (size) { jintArray array = (*env)->NewIntArray( env, size ); @@ -974,8 +945,6 @@ static NTSTATUS setCursor_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD o } else (*env)->CallVoidMethod( env, object, method, res->id, 0, 0, 0, 0, NULL ); - unwrap_java_call(); - return STATUS_SUCCESS; } @@ -1047,21 +1016,201 @@ NTSTATUS android_java_uninit( void *arg ) return STATUS_SUCCESS; } +static ALooper *looper; +static JNIEnv *looper_env; /* JNIEnv for the main thread looper. Must only be used from that thread. */ + +void looper_init( JNIEnv* env, jobject obj ) +{ + looper_env = env; + if (!(looper = pALooper_forThread())) + { + _ERR("No looper for current thread\n"); + abort(); + } + pALooper_acquire( looper ); +} + +/* Handle a single ioctl request from a client socket. + * Returns 0 if a request was handled successfully and the caller may + * continue draining the socket, -1 if there is nothing more to read + * for now, and 1 if the client fd should be closed. + */ +static int handle_ioctl_message( JNIEnv *env, int fd ) +{ + char buffer[1024], control[CMSG_SPACE(sizeof(int))]; + int code = 0, status = -EINVAL, reply_fd = -1; + ULONG_PTR reply_size = 0; + ssize_t ret; + struct iovec iov[2] = { { &code, sizeof(code) }, { buffer, sizeof(buffer) } }; + struct iovec reply_iov[2] = { { &status, sizeof(status) }, { buffer, 0 } }; + struct msghdr msg = { NULL, 0, iov, 2, NULL, 0, 0 }; + struct msghdr reply = { NULL, 0, reply_iov, 2, NULL, 0, 0 }; + struct cmsghdr *cmsg; + + ret = recvmsg( fd, &msg, MSG_DONTWAIT ); + if (ret < 0) + { + if (errno == EINTR) return 0; + if (errno == EAGAIN || errno == EWOULDBLOCK) return -1; + return 1; + } + + if (!ret || ret < sizeof(code)) return 1; + ret -= sizeof(code); + + if ((unsigned int)code < NB_IOCTLS) + { + if (ret >= sizeof(struct ioctl_header)) + { + pthread_mutex_lock( &dispatch_ioctl_lock ); + status = status_to_android_error( + ioctl_funcs[code]( env, buffer, ret, sizeof(buffer), &reply_size, &reply_fd ) ); + pthread_mutex_unlock( &dispatch_ioctl_lock ); + } + } + else + { + _FIXME( "ioctl %x not supported\n", code ); + status = -ENOTSUP; + } + + reply_iov[1].iov_len = reply_size; + if (reply_fd != -1) + { + reply.msg_control = control; + reply.msg_controllen = sizeof(control); + cmsg = CMSG_FIRSTHDR( &reply ); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN( sizeof(reply_fd) ); + memcpy( CMSG_DATA(cmsg), &reply_fd, sizeof(reply_fd) ); + reply.msg_controllen = cmsg->cmsg_len; + } + + ret = sendmsg( fd, &reply, 0 ); + if (reply_fd != -1) close( reply_fd ); + return ret < 0 ? 1 : 0; +} + +static int looper_handle_client( int fd, int events, void *data ) +{ + for (;;) + { + int ret = (events & (ALOOPER_EVENT_HANGUP | ALOOPER_EVENT_ERROR)) ? 1 : handle_ioctl_message( looper_env, fd ); + + if (!ret) continue; + + if (ret > 0) + { + pALooper_removeFd( looper, fd ); + close( fd ); + } + break; + } + + return 1; +} + +static int looper_handle_listen( int fd, int events, void *data ) +{ + for (;;) + { + int client = accept4( fd, NULL, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK ); + + if (client < 0) + { + if (errno == EINTR) continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) break; + _ERR( "accept4 failed: %s\n", strerror( errno ) ); + break; + } + + if (pALooper_addFd( looper, client, client, ALOOPER_EVENT_INPUT | ALOOPER_EVENT_HANGUP | ALOOPER_EVENT_ERROR, looper_handle_client, NULL ) != 1) { + _ERR("Failed to add client to ALooper\n"); + close( client ); + } + } + + return 1; +} + +static void *bootstrap_looper_thread( void *arg ) +{ + JNIEnv *env; + jmethodID method = NULL; + jobject object = NULL; + int sockfd; + + if (!java_vm || (*java_vm)->AttachCurrentThread( java_vm, &env, 0 ) != JNI_OK) + { + _ERR( "Failed to attach current thread\n" ); + return NULL; + } + + if (!(object = load_java_method( env, &method, "obtainLooper", "()V" ))) + { + _ERR( "Failed to obtain looper\n"); + abort(); + } + (*env)->CallVoidMethod( env, object, method ); + + sockfd = socket( AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0 ); + if (sockfd < 0) + { + _ERR( "Failed to open server socket: %s\n", strerror( errno ) ); + abort(); + } + + if (bind( sockfd, (const struct sockaddr *)&ipc_addr, IPC_SOCKET_ADDR_LEN ) < 0 || + listen( sockfd, 32 ) < 0) + { + _ERR( "Failed to bind server socket: %s\n", strerror( errno ) ); + close(sockfd); + abort(); + } + + if (pALooper_addFd( looper, sockfd, sockfd, ALOOPER_EVENT_INPUT, looper_handle_listen, NULL ) != 1) { + _ERR("Failed to add listening socket to main looper\n"); + close(sockfd); + abort(); + } + + (*java_vm)->DetachCurrentThread( java_vm ); + return NULL; +} + void start_android_device(void) { void *ret_ptr; ULONG ret_len; struct dispatch_callback_params params = {.callback = start_device_callback}; + pthread_t t; + __wine_dbg_get_channel_flags(&__wine_dbch_android); // force lazy init of debug channel flags for use outside Wine thread context + + /* Use a temporary bootstrap thread to request the main thread looper + * without interfering with the current Wine/JVM execution context + * (including register and thread-state assumptions). Actual ioctl + * dispatch then runs from the main thread looper. + */ + if (!pthread_create( &t, NULL, bootstrap_looper_thread, NULL )) + pthread_join(t, NULL); + else + { + _ERR("Failed to spawn looper bootstrap thread\n"); + abort(); + } + if (KeUserDispatchCallback( ¶ms, sizeof(params), &ret_ptr, &ret_len )) return; if (ret_len == sizeof(thread)) thread = *(HANDLE *)ret_ptr; + return; } /* Client-side ioctl support */ -static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *reply_fd ) +static int android_ioctl_old( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *reply_fd ) { static const WCHAR deviceW[] = { '\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d', 0 }; static HANDLE device; @@ -1095,6 +1244,66 @@ static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void return status_to_android_error( status ); } +static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *recv_fd ) +{ + static int device_fd = -1; + static pthread_mutex_t device_mutex = PTHREAD_MUTEX_INITIALIZER; + int status, err = -ENOENT; + ssize_t ret; + char control[CMSG_SPACE(sizeof(int))]; + struct iovec iov[2] = { { &status, sizeof(status) }, { out, out_size ? *out_size : 0 } }; + struct msghdr msg = { NULL, 0, iov, (out && out_size) ? 2 : 1, + recv_fd ? control : NULL, recv_fd ? sizeof(control) : 0, 0 }; + struct cmsghdr *cmsg; + + pthread_mutex_lock( &device_mutex ); + + if (recv_fd) *recv_fd = -1; + + if (device_fd == -1) + { + device_fd = socket( AF_UNIX, SOCK_SEQPACKET, 0 ); + if (device_fd < 0) goto done; + if (connect( device_fd, (const struct sockaddr *)&ipc_addr, IPC_SOCKET_ADDR_LEN ) < 0) + { + close( device_fd ); + device_fd = -1; + goto done; + } + } + + ret = writev( device_fd, (struct iovec[]){ { &code, sizeof(code) }, { in, in_size } }, 2 ); + if (ret <= 0 || ret != sizeof(code) + in_size) goto disconnected; + + ret = recvmsg( device_fd, &msg, 0 ); + if (ret <= 0 || ret < sizeof(status)) goto disconnected; + + if (out && out_size) *out_size = ret - sizeof(status); + err = status; + + if (recv_fd) + for (cmsg = CMSG_FIRSTHDR( &msg ); cmsg; cmsg = CMSG_NXTHDR( &msg, cmsg )) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS && + cmsg->cmsg_len >= CMSG_LEN(sizeof(int))) + { + memcpy( recv_fd, CMSG_DATA(cmsg), sizeof(int) ); + break; + } + + goto done; + +disconnected: + close( device_fd ); + device_fd = -1; + WARN( "parent process is gone\n" ); + NtTerminateProcess( 0, 1 ); + err = -ENOENT; + +done: + pthread_mutex_unlock( &device_mutex ); + return err; +} + static void win_incRef( struct android_native_base_t *base ) { struct native_win_wrapper *win = (struct native_win_wrapper *)base; @@ -1121,7 +1330,7 @@ static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuff res.buffer_id = -1; res.generation = 0; - ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size, NULL ); + ret = android_ioctl_old( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size, NULL ); if (ret) return ret; if (size < sizeof(res)) return -EINVAL; diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 8e6c700870a..e6efec88998 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -326,6 +326,7 @@ static const struct user_driver_funcs android_drv_funcs = static const JNINativeMethod methods[] = { + { "wine_looper_init", "()V", looper_init }, { "wine_desktop_changed", "(II)V", desktop_changed }, { "wine_config_changed", "(I)V", config_changed }, { "wine_surface_changed", "(ILandroid/view/Surface;Z)V", surface_changed }, @@ -350,6 +351,11 @@ DECL_FUNCPTR( AHardwareBuffer_unlock ); DECL_FUNCPTR( AHardwareBuffer_recvHandleFromUnixSocket ); DECL_FUNCPTR( AHardwareBuffer_sendHandleToUnixSocket ); DECL_FUNCPTR( ANativeWindowBuffer_getHardwareBuffer ); +DECL_FUNCPTR( ALooper_acquire ); +DECL_FUNCPTR( ALooper_forThread ); +DECL_FUNCPTR( ALooper_addFd ); +DECL_FUNCPTR( ALooper_removeFd ); +DECL_FUNCPTR( ALooper_release ); static void load_android_libs(void) { @@ -378,6 +384,11 @@ static void load_android_libs(void) LOAD_FUNCPTR( libandroid, AHardwareBuffer_recvHandleFromUnixSocket ); LOAD_FUNCPTR( libandroid, AHardwareBuffer_sendHandleToUnixSocket ); LOAD_FUNCPTR( libandroid, ANativeWindowBuffer_getHardwareBuffer ); + LOAD_FUNCPTR( libandroid, ALooper_acquire ); + LOAD_FUNCPTR( libandroid, ALooper_forThread ); + LOAD_FUNCPTR( libandroid, ALooper_addFd ); + LOAD_FUNCPTR( libandroid, ALooper_removeFd ); + LOAD_FUNCPTR( libandroid, ALooper_release ); } #undef DECL_FUNCPTR -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Switch dequeueBuffer to the socket-based ioctl transport. Replace the HANDLE duplication path using NtDuplicateObject and wineserver with direct fd passing over a UNIX socket. The ioctl is now handled entirely on the new dispatch thread and no longer depends on Wine TEB-based handle conversion. This completes the dequeueBuffer transition that was previously kept on the old transport for bisect safety. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 58 +++++------------------------------ 1 file changed, 8 insertions(+), 50 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 798b23ef790..378328311a4 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -178,8 +178,6 @@ struct ioctl_android_window_pos_changed struct ioctl_android_dequeueBuffer { struct ioctl_header hdr; - HANDLE handle; - DWORD pid; int buffer_id; int generation; }; @@ -653,14 +651,11 @@ static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWO if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY; - res->handle = 0; res->buffer_id = -1; res->generation = 0; *ret_size = sizeof(*res); - wrap_java_call(); ret = parent->dequeueBuffer( parent, &buffer, &fence ); - unwrap_java_call(); if (ret) { _ERR( "%08x failed %d\n", res->hdr.hwnd, ret ); @@ -678,15 +673,10 @@ static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWO res->buffer_id = register_buffer( win_data, ahb, &is_new ); res->generation = win_data->generation; - res->handle = 0; if (is_new) { int sv[2] = { -1, -1 }; - HANDLE local = 0; - OBJECT_ATTRIBUTES attr = { .Length = sizeof(attr) }; - CLIENT_ID cid = { .UniqueProcess = UlongToHandle( res->pid ) }; - HANDLE process; if (!ahb) { @@ -700,37 +690,16 @@ static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWO return STATUS_UNSUCCESSFUL; } - if (NtOpenProcess( &process, PROCESS_DUP_HANDLE, &attr, &cid )) - { - close( sv[0] ); - close( sv[1] ); - wait_fence_and_close( fence ); - return STATUS_UNSUCCESSFUL; - } - - if (!wine_server_fd_to_handle( dup(sv[1]), GENERIC_READ | SYNCHRONIZE, 0, &local )) - { - NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), local, process, &res->handle, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ); - if (status && local) NtClose( local ); - } - - NtClose( process ); - close( sv[1] ); - - if (!res->handle) - { - close( sv[0] ); - wait_fence_and_close( fence ); - return STATUS_UNSUCCESSFUL; - } - ret = pAHardwareBuffer_sendHandleToUnixSocket( ahb, sv[0] ); close( sv[0] ); if (ret) { + close( sv[1] ); wait_fence_and_close( fence ); return android_error_to_status( ret ); } + + *reply_fd = sv[1]; } wait_fence_and_close( fence ); @@ -1321,35 +1290,24 @@ static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuff struct native_win_wrapper *win = (struct native_win_wrapper *)window; struct ioctl_android_dequeueBuffer res = {0}; DWORD size = sizeof(res); - int ret; + int ret, buffer_fd = -1; res.hdr.hwnd = HandleToLong( win->hwnd ); res.hdr.opengl = win->opengl; - res.pid = GetCurrentProcessId(); - res.handle = 0; res.buffer_id = -1; res.generation = 0; - ret = android_ioctl_old( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size, NULL ); + ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size, &buffer_fd ); if (ret) return ret; if (size < sizeof(res)) return -EINVAL; if (res.buffer_id < 0 || res.buffer_id >= NB_CACHED_BUFFERS) return -EINVAL; - if (res.handle) + if (buffer_fd != -1) { AHardwareBuffer *ahb = NULL; - int fd; - - if (wine_server_handle_to_fd( res.handle, GENERIC_READ | SYNCHRONIZE, &fd, NULL )) - { - NtClose( res.handle ); - return -EINVAL; - } - NtClose( res.handle ); - - ret = pAHardwareBuffer_recvHandleFromUnixSocket( fd, &ahb ); - close( fd ); + ret = pAHardwareBuffer_recvHandleFromUnixSocket( buffer_fd, &ahb ); + close( buffer_fd ); if (ret) return ret; if (win->buffers[res.buffer_id].self) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Remove the old wineandroid ioctl transport based on unixlib calls and the ntoskrnl device/IRP dispatch path. This drops the android_dispatch_ioctl entrypoint, the driver creation code, and the unixlib call table, along with the associated device thread and callback-based startup path. With the socket-based dispatch thread now handling all ioctls, the old HANDLE-based transport is no longer needed. Also remove the remaining artifacts of the old execution model, including the global JNIEnv, thread tracking, and the wrap_java_call/unwrap_java_call helpers used to work around JVM/Wine TLS conflicts. Simplify initialization accordingly by using __wine_unix_lib_init() directly, making dllmain.c consistent with winex11.drv. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 11 +-- dlls/wineandroid.drv/device.c | 147 +-------------------------------- dlls/wineandroid.drv/dllmain.c | 73 +--------------- dlls/wineandroid.drv/init.c | 16 +--- dlls/wineandroid.drv/unixlib.h | 31 ------- 5 files changed, 8 insertions(+), 270 deletions(-) delete mode 100644 dlls/wineandroid.drv/unixlib.h diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 4882ca91f8b..c79ce31a046 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -35,7 +35,8 @@ #include "winbase.h" #include "ntgdi.h" #include "wine/gdi_driver.h" -#include "unixlib.h" +#include "ntuser.h" +#include "wine/unixlib.h" #include "android_native.h" @@ -120,13 +121,6 @@ extern void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_h extern ANativeWindow *get_client_window( HWND hwnd ); extern BOOL has_client_surface( HWND hwnd ); -/* unixlib interface */ - -extern NTSTATUS android_dispatch_ioctl( void *arg ); -extern NTSTATUS android_java_init( void *arg ); -extern NTSTATUS android_java_uninit( void *arg ); -extern UINT64 start_device_callback; - extern unsigned int screen_width; extern unsigned int screen_height; extern RECT virtual_screen_rect; @@ -203,7 +197,6 @@ int send_event( const union event_data *data ); extern JavaVM *java_vm; extern jobject java_object; -extern unsigned short java_gdt_sel; /* string helpers */ diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 378328311a4..d95001c2e13 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -78,8 +78,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(android); #define SYNC_IOC_WAIT _IOW('>', 0, __s32) #endif -static HANDLE thread; -static JNIEnv *jni_env; static HWND capture_window; static HWND desktop_window; @@ -238,49 +236,6 @@ struct ioctl_android_set_cursor int bits[1]; }; - -static inline BOOL is_in_desktop_process(void) -{ - return thread != NULL; -} - -#ifdef __i386__ /* the Java VM uses %fs/%gs for its own purposes, so we need to wrap the calls */ - -static WORD orig_fs, java_fs; -static inline void wrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (java_fs) ); } -static inline void unwrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (orig_fs) ); } -static inline void init_java_thread( JavaVM *java_vm, JNIEnv** env ) -{ - java_fs = java_gdt_sel; - __asm__( "mov %%fs,%0" : "=r" (orig_fs) ); - __asm__( "mov %0,%%fs" :: "r" (java_fs) ); - (*java_vm)->AttachCurrentThread( java_vm, env, 0 ); - if (!java_gdt_sel) __asm__( "mov %%fs,%0" : "=r" (java_fs) ); - __asm__( "mov %0,%%fs" :: "r" (orig_fs) ); -} - -#elif defined(__x86_64__) - -#include <asm/prctl.h> -#include <asm/unistd.h> -static void *orig_teb, *java_teb; -static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); } -static inline void wrap_java_call(void) { arch_prctl( ARCH_SET_GS, java_teb ); } -static inline void unwrap_java_call(void) { arch_prctl( ARCH_SET_GS, orig_teb ); } -static inline void init_java_thread( JavaVM *java_vm, JNIEnv** env ) -{ - arch_prctl( ARCH_GET_GS, &orig_teb ); - (*java_vm)->AttachCurrentThread( java_vm, env, 0 ); - arch_prctl( ARCH_GET_GS, &java_teb ); - arch_prctl( ARCH_SET_GS, orig_teb ); -} - -#else -static inline void wrap_java_call(void) { } -static inline void unwrap_java_call(void) { } -static inline void init_java_thread( JavaVM *java_vm, JNIEnv** env ) { (*java_vm)->AttachCurrentThread( java_vm, env, 0 ); } -#endif /* __i386__ */ - static struct native_win_data *data_map[65536]; static unsigned int data_map_idx( HWND hwnd, BOOL opengl ) @@ -566,12 +521,9 @@ static void create_desktop_view( JNIEnv* env ) static jmethodID method; jobject object; - wrap_java_call(); - if (!(object = load_java_method( env, &method, "createDesktopView", "()V" ))) goto end; + if (!(object = load_java_method( env, &method, "createDesktopView", "()V" ))) return; (*env)->CallVoidMethod( env, object, method ); -end: - unwrap_java_call(); } static NTSTATUS createWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) @@ -934,57 +886,6 @@ static const ioctl_func ioctl_funcs[] = setCursor_ioctl, /* IOCTL_SET_CURSOR */ }; -NTSTATUS android_dispatch_ioctl( void *arg ) -{ - IRP *irp = arg; - IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); - DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2; - - if (code < NB_IOCTLS) - { - struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer; - DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength; - ioctl_func func = ioctl_funcs[code]; - - if (in_size >= sizeof(*header)) - { - int reply_fd = -1; - irp->IoStatus.Information = 0; - pthread_mutex_lock(&dispatch_ioctl_lock); - irp->IoStatus.Status = func( jni_env, irp->AssociatedIrp.SystemBuffer, in_size, - irpsp->Parameters.DeviceIoControl.OutputBufferLength, - &irp->IoStatus.Information, &reply_fd ); - pthread_mutex_unlock(&dispatch_ioctl_lock); - } - else irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - } - else - { - FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); - irp->IoStatus.Status = STATUS_NOT_SUPPORTED; - } - return STATUS_SUCCESS; -} - -NTSTATUS android_java_init( void *arg ) -{ - if (!java_vm) return STATUS_UNSUCCESSFUL; /* not running under Java */ - - init_java_thread( java_vm, &jni_env ); - create_desktop_view( jni_env ); - return STATUS_SUCCESS; -} - -NTSTATUS android_java_uninit( void *arg ) -{ - if (!java_vm) return STATUS_UNSUCCESSFUL; /* not running under Java */ - - wrap_java_call(); - (*java_vm)->DetachCurrentThread( java_vm ); - unwrap_java_call(); - return STATUS_SUCCESS; -} - static ALooper *looper; static JNIEnv *looper_env; /* JNIEnv for the main thread looper. Must only be used from that thread. */ @@ -1144,15 +1045,14 @@ static void *bootstrap_looper_thread( void *arg ) abort(); } + create_desktop_view( env ); + (*java_vm)->DetachCurrentThread( java_vm ); return NULL; } void start_android_device(void) { - void *ret_ptr; - ULONG ret_len; - struct dispatch_callback_params params = {.callback = start_device_callback}; pthread_t t; __wine_dbg_get_channel_flags(&__wine_dbch_android); // force lazy init of debug channel flags for use outside Wine thread context @@ -1169,50 +1069,12 @@ void start_android_device(void) _ERR("Failed to spawn looper bootstrap thread\n"); abort(); } - - if (KeUserDispatchCallback( ¶ms, sizeof(params), &ret_ptr, &ret_len )) return; - if (ret_len == sizeof(thread)) thread = *(HANDLE *)ret_ptr; - return; } /* Client-side ioctl support */ -static int android_ioctl_old( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *reply_fd ) -{ - static const WCHAR deviceW[] = { '\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d', 0 }; - static HANDLE device; - IO_STATUS_BLOCK iosb; - NTSTATUS status; - - if (!device) - { - OBJECT_ATTRIBUTES attr; - UNICODE_STRING name = RTL_CONSTANT_STRING( deviceW ); - IO_STATUS_BLOCK io; - NTSTATUS status; - HANDLE file; - - InitializeObjectAttributes( &attr, &name, OBJ_CASE_INSENSITIVE, NULL, NULL ); - status = NtCreateFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io, NULL, 0, - FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, - FILE_NON_DIRECTORY_FILE, NULL, 0 ); - if (status) return -ENOENT; - if (InterlockedCompareExchangePointer( &device, file, NULL )) NtClose( file ); - } - - status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code), - in, in_size, out, out_size ? *out_size : 0 ); - if (status == STATUS_FILE_DELETED) - { - WARN( "parent process is gone\n" ); - NtTerminateProcess( 0, 1 ); - } - if (out_size) *out_size = iosb.Information; - return status_to_android_error( status ); -} - static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *recv_fd ) { static int device_fd = -1; @@ -1684,8 +1546,5 @@ int ioctl_set_cursor( int id, int width, int height, */ void ANDROID_SetDesktopWindow( HWND hwnd ) { - if (!is_in_desktop_process()) - return; - TRACE( "%p\n", hwnd ); desktop_window = hwnd; } diff --git a/dlls/wineandroid.drv/dllmain.c b/dlls/wineandroid.drv/dllmain.c index dd2493c6f55..b83f35e84ba 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -19,76 +19,9 @@ */ #include <stdarg.h> -#include "ntstatus.h" #include "windef.h" #include "winbase.h" -#include "winternl.h" -#include "winioctl.h" -#include "ddk/wdm.h" -#include "unixlib.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(android); - - -extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ); -static HANDLE stop_event; - - -static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp ) -{ - NTSTATUS status = ANDROID_CALL( dispatch_ioctl, irp ); - IoCompleteRequest( irp, IO_NO_INCREMENT ); - return status; -} - -static NTSTATUS CALLBACK init_android_driver( DRIVER_OBJECT *driver, UNICODE_STRING *name ) -{ - UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Device\\WineAndroid" ); - DEVICE_OBJECT *device; - - driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ioctl_callback; - - return IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device ); -} - -static DWORD CALLBACK device_thread( void *arg ) -{ - HANDLE start_event = arg; - UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Driver\\WineAndroid" ); - NTSTATUS status; - DWORD ret; - - TRACE( "starting process %lx\n", GetCurrentProcessId() ); - - if (ANDROID_CALL( java_init, NULL )) return 0; /* not running under Java */ - - if ((status = IoCreateDriver( &nameW, init_android_driver ))) - { - FIXME( "failed to create driver error %lx\n", status ); - return status; - } - - stop_event = CreateEventW( NULL, TRUE, FALSE, NULL ); - SetEvent( start_event ); - - ret = wine_ntoskrnl_main_loop( stop_event ); - - ANDROID_CALL( java_uninit, NULL ); - return ret; -} - -static NTSTATUS WINAPI android_start_device(void *param, ULONG size) -{ - HANDLE handles[2]; - - handles[0] = CreateEventW( NULL, TRUE, FALSE, NULL ); - handles[1] = CreateThread( NULL, 0, device_thread, handles[0], 0, NULL ); - WaitForMultipleObjects( 2, handles, FALSE, INFINITE ); - CloseHandle( handles[0] ); - return NtCallbackReturn( &handles[1], sizeof(handles[1]), STATUS_SUCCESS ); -} - +#include "wine/unixlib.h" /*********************************************************************** * dll initialisation routine @@ -98,7 +31,5 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) if (reason != DLL_PROCESS_ATTACH) return TRUE; DisableThreadLibraryCalls( inst ); - if (__wine_init_unix_call()) return FALSE; - - return !ANDROID_CALL( init, (void *)(UINT_PTR)android_start_device ); + return !__wine_init_unix_call(); } diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index e6efec88998..4ad3b42b0f5 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -50,8 +50,6 @@ static const unsigned int screen_bpp = 32; /* we don't support other modes */ static RECT monitor_rc_work; static int device_init_done; -UINT64 start_device_callback; - typedef struct { struct gdi_physdev dev; @@ -394,7 +392,7 @@ static void load_android_libs(void) #undef DECL_FUNCPTR #undef LOAD_FUNCPTR -static HRESULT android_init( void *arg ) +NTSTATUS __wine_unix_lib_init(void) { pthread_mutexattr_t attr; jclass class; @@ -407,8 +405,6 @@ static HRESULT android_init( void *arg ) pthread_mutex_init( &win_data_mutex, &attr ); pthread_mutexattr_destroy( &attr ); - start_device_callback = (UINT64)(UINT_PTR)arg; - if (java_vm) /* running under Java */ { #ifdef __i386__ @@ -428,13 +424,3 @@ static HRESULT android_init( void *arg ) return STATUS_SUCCESS; } -const unixlib_entry_t __wine_unix_call_funcs[] = -{ - android_dispatch_ioctl, - android_init, - android_java_init, - android_java_uninit, -}; - - -C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count ); diff --git a/dlls/wineandroid.drv/unixlib.h b/dlls/wineandroid.drv/unixlib.h deleted file mode 100644 index 7549541e48e..00000000000 --- a/dlls/wineandroid.drv/unixlib.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 Jacek Caban for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "ntuser.h" -#include "wine/unixlib.h" - -enum android_funcs -{ - unix_dispatch_ioctl, - unix_init, - unix_java_init, - unix_java_uninit, - unix_funcs_count -}; - -#define ANDROID_CALL(func, params) WINE_UNIX_CALL( unix_ ## func, params ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Return ioctl handler errors directly instead of converting them between Android errno values and NTSTATUS. The socket-based ioctl path no longer goes through Wine's device/IRP infrastructure, so the old android_error_to_status() and status_to_android_error() mappings are no longer needed. Make the handlers return their native error values directly and pass them through handle_ioctl_message() unchanged. This simplifies the ioctl path and removes the leftover error mapping layer from the old transport model. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 183 ++++++++++++---------------------- 1 file changed, 66 insertions(+), 117 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index d95001c2e13..fc9fecf231b 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -36,7 +36,6 @@ #include <sys/uio.h> #include <unistd.h> -#include "ntstatus.h" #include "windef.h" #include "winbase.h" #include "winternl.h" @@ -452,53 +451,6 @@ HWND get_capture_window(void) return capture_window; } -static NTSTATUS android_error_to_status( int err ) -{ - switch (err) - { - case 0: return STATUS_SUCCESS; - case -ENOMEM: return STATUS_NO_MEMORY; - case -ENOSYS: return STATUS_NOT_SUPPORTED; - case -EINVAL: return STATUS_INVALID_PARAMETER; - case -ENOENT: return STATUS_INVALID_HANDLE; - case -EPERM: return STATUS_ACCESS_DENIED; - case -ENODEV: return STATUS_NO_SUCH_DEVICE; - case -EEXIST: return STATUS_DUPLICATE_NAME; - case -EPIPE: return STATUS_PIPE_DISCONNECTED; - case -ENODATA: return STATUS_NO_MORE_FILES; - case -ETIMEDOUT: return STATUS_IO_TIMEOUT; - case -EBADMSG: return STATUS_INVALID_DEVICE_REQUEST; - case -EWOULDBLOCK: return STATUS_DEVICE_NOT_READY; - default: - _FIXME( "unmapped error %d\n", err ); - return STATUS_UNSUCCESSFUL; - } -} - -static int status_to_android_error( unsigned int status ) -{ - switch (status) - { - case STATUS_SUCCESS: return 0; - case STATUS_NO_MEMORY: return -ENOMEM; - case STATUS_NOT_SUPPORTED: return -ENOSYS; - case STATUS_INVALID_PARAMETER: return -EINVAL; - case STATUS_BUFFER_OVERFLOW: return -EINVAL; - case STATUS_INVALID_HANDLE: return -ENOENT; - case STATUS_ACCESS_DENIED: return -EPERM; - case STATUS_NO_SUCH_DEVICE: return -ENODEV; - case STATUS_DUPLICATE_NAME: return -EEXIST; - case STATUS_PIPE_DISCONNECTED: return -EPIPE; - case STATUS_NO_MORE_FILES: return -ENODATA; - case STATUS_IO_TIMEOUT: return -ETIMEDOUT; - case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG; - case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK; - default: - FIXME( "unmapped status %08x\n", status ); - return -EINVAL; - } -} - static jobject load_java_method( JNIEnv* env, jmethodID *method, const char *name, const char *args ) { if (!*method) @@ -526,69 +478,69 @@ static void create_desktop_view( JNIEnv* env ) (*env)->CallVoidMethod( env, object, method ); } -static NTSTATUS createWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int createWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; struct ioctl_android_create_window *res = data; struct native_win_data *win_data; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; if (!(win_data = create_native_win_data( LongToHandle(res->hdr.hwnd), res->hdr.opengl ))) - return STATUS_NO_MEMORY; + return -ENOMEM; _TRACE( "hwnd %08x opengl %u parent %08x\n", res->hdr.hwnd, res->hdr.opengl, res->parent ); - if (!(object = load_java_method( env, &method, "createWindow", "(IZZI)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( env, &method, "createWindow", "(IZZI)V" ))) return -ENOSYS; (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->is_desktop, res->hdr.opengl, res->parent ); - return STATUS_SUCCESS; + return 0; } -static NTSTATUS destroyWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int destroyWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; struct ioctl_android_destroy_window *res = data; struct native_win_data *win_data; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; win_data = get_ioctl_native_win_data( &res->hdr ); _TRACE( "hwnd %08x opengl %u\n", res->hdr.hwnd, res->hdr.opengl ); - if (!(object = load_java_method( env, &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( env, &method, "destroyWindow", "(I)V" ))) return -ENOSYS; (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd ); if (win_data) free_native_win_data( win_data ); - return STATUS_SUCCESS; + return 0; } -static NTSTATUS windowPosChanged_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int windowPosChanged_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; struct ioctl_android_window_pos_changed *res = data; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; _TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n", res->hdr.hwnd, _wine_dbgstr_rect(&res->window_rect), _wine_dbgstr_rect(&res->client_rect), _wine_dbgstr_rect(&res->visible_rect), res->style, res->flags, res->after, res->owner ); if (!(object = load_java_method( env, &method, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" ))) - return STATUS_NOT_SUPPORTED; + return -ENOSYS; (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->flags, res->after, res->owner, res->style, res->window_rect.left, res->window_rect.top, res->window_rect.right, res->window_rect.bottom, res->client_rect.left, res->client_rect.top, res->client_rect.right, res->client_rect.bottom, res->visible_rect.left, res->visible_rect.top, res->visible_rect.right, res->visible_rect.bottom ); - return STATUS_SUCCESS; + return 0; } -static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ANativeWindow *parent; struct ioctl_android_dequeueBuffer *res = data; @@ -597,11 +549,10 @@ static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWO AHardwareBuffer *ahb = NULL; int fence, ret, is_new; - if (out_size < sizeof( *res )) return STATUS_BUFFER_OVERFLOW; - if (in_size < sizeof(res->hdr)) return STATUS_INVALID_PARAMETER; + if (out_size < sizeof( *res ) || in_size < sizeof(res->hdr)) return -EINVAL; - if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; - if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY; + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return -ENOENT; + if (!(parent = win_data->parent)) return -EWOULDBLOCK; res->buffer_id = -1; res->generation = 0; @@ -611,7 +562,7 @@ static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWO if (ret) { _ERR( "%08x failed %d\n", res->hdr.hwnd, ret ); - return android_error_to_status( ret ); + return ret; } if (!buffer) @@ -648,17 +599,17 @@ static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWO { close( sv[1] ); wait_fence_and_close( fence ); - return android_error_to_status( ret ); + return ret; } *reply_fd = sv[1]; } wait_fence_and_close( fence ); - return STATUS_SUCCESS; + return 0; } -static NTSTATUS cancelBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int cancelBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_cancelBuffer *res = data; struct ANativeWindow *parent; @@ -666,20 +617,20 @@ static NTSTATUS cancelBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWOR struct native_win_data *win_data; int ret; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; - if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; - if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY; - if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */ + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return -ENOENT; + if (!(parent = win_data->parent)) return -EWOULDBLOCK; + if (res->generation != win_data->generation) return 0; /* obsolete buffer, ignore */ - if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE; + if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return -ENOENT; _TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); ret = parent->cancelBuffer( parent, buffer, -1 ); - return android_error_to_status( ret ); + return ret; } -static NTSTATUS queueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int queueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_queueBuffer *res = data; struct ANativeWindow *parent; @@ -687,48 +638,47 @@ static NTSTATUS queueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD struct native_win_data *win_data; int ret; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; - if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; - if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY; - if (res->generation != win_data->generation) return STATUS_SUCCESS; /* obsolete buffer, ignore */ + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return -ENOENT; + if (!(parent = win_data->parent)) return -EWOULDBLOCK; + if (res->generation != win_data->generation) return 0; /* obsolete buffer, ignore */ - if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE; + if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return -ENOENT; _TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer ); ret = parent->queueBuffer( parent, buffer, -1 ); - return android_error_to_status( ret ); + return ret; } -static NTSTATUS query_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int query_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_query *res = data; struct ANativeWindow *parent; struct native_win_data *win_data; int ret; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; - if (out_size < sizeof(*res)) return STATUS_BUFFER_OVERFLOW; + if (in_size < sizeof(*res) || out_size < sizeof(*res)) return -EINVAL; - if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; - if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY; + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return -ENOENT; + if (!(parent = win_data->parent)) return -EWOULDBLOCK; *ret_size = sizeof( *res ); ret = parent->query( parent, res->what, &res->value ); - return android_error_to_status( ret ); + return ret; } -static NTSTATUS perform_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int perform_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_perform *res = data; struct ANativeWindow *parent; struct native_win_data *win_data; int ret = -ENOENT; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; - if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; - if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY; + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return -ENOENT; + if (!(parent = win_data->parent)) return -EWOULDBLOCK; switch (res->operation) { @@ -782,79 +732,79 @@ static NTSTATUS perform_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out FIXME( "unsupported perform op %d\n", res->operation ); break; } - return android_error_to_status( ret ); + return ret; } -static NTSTATUS setSwapInterval_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int setSwapInterval_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_swap_interval *res = data; struct ANativeWindow *parent; struct native_win_data *win_data; int ret; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; - if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return -ENOENT; win_data->swap_interval = res->interval; - if (!(parent = win_data->parent)) return STATUS_SUCCESS; + if (!(parent = win_data->parent)) return 0; ret = parent->setSwapInterval( parent, res->interval ); - return android_error_to_status( ret ); + return ret; } -static NTSTATUS setWindowParent_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int setWindowParent_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; struct ioctl_android_set_window_parent *res = data; struct native_win_data *win_data; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; - if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE; + if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return -ENOENT; _TRACE( "hwnd %08x parent %08x\n", res->hdr.hwnd, res->parent ); - if (!(object = load_java_method( env, &method, "setParent", "(II)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( env, &method, "setParent", "(II)V" ))) return -ENOSYS; (*env)->CallVoidMethod( env, object, method, res->hdr.hwnd, res->parent ); - return STATUS_SUCCESS; + return 0; } -static NTSTATUS setCapture_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int setCapture_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { struct ioctl_android_set_capture *res = data; - if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; + if (in_size < sizeof(*res)) return -EINVAL; - if (res->hdr.hwnd && !get_ioctl_native_win_data( &res->hdr )) return STATUS_INVALID_HANDLE; + if (res->hdr.hwnd && !get_ioctl_native_win_data( &res->hdr )) return -ENOENT; _TRACE( "hwnd %08x\n", res->hdr.hwnd ); InterlockedExchangePointer( (void **)&capture_window, LongToHandle( res->hdr.hwnd )); - return STATUS_SUCCESS; + return 0; } -static NTSTATUS setCursor_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) +static int setCursor_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { static jmethodID method; jobject object; int size; struct ioctl_android_set_cursor *res = data; - if (in_size < offsetof( struct ioctl_android_set_cursor, bits )) return STATUS_INVALID_PARAMETER; + if (in_size < offsetof( struct ioctl_android_set_cursor, bits )) return -EINVAL; if (res->width < 0 || res->height < 0 || res->width > 256 || res->height > 256) - return STATUS_INVALID_PARAMETER; + return -EINVAL; size = res->width * res->height; if (in_size != offsetof( struct ioctl_android_set_cursor, bits[size] )) - return STATUS_INVALID_PARAMETER; + return -EINVAL; _TRACE( "hwnd %08x size %d\n", res->hdr.hwnd, size ); if (!(object = load_java_method( env, &method, "setCursor", "(IIIII[I)V" ))) - return STATUS_NOT_SUPPORTED; + return -ENOSYS; if (size) { @@ -866,10 +816,10 @@ static NTSTATUS setCursor_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD o } else (*env)->CallVoidMethod( env, object, method, res->id, 0, 0, 0, 0, NULL ); - return STATUS_SUCCESS; + return 0; } -typedef NTSTATUS (*ioctl_func)( JNIEnv* env, void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ); +typedef int (*ioctl_func)( JNIEnv* env, void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ); static const ioctl_func ioctl_funcs[] = { createWindow_ioctl, /* IOCTL_CREATE_WINDOW */ @@ -933,8 +883,7 @@ static int handle_ioctl_message( JNIEnv *env, int fd ) if (ret >= sizeof(struct ioctl_header)) { pthread_mutex_lock( &dispatch_ioctl_lock ); - status = status_to_android_error( - ioctl_funcs[code]( env, buffer, ret, sizeof(buffer), &reply_size, &reply_fd ) ); + status = ioctl_funcs[code]( env, buffer, ret, sizeof(buffer), &reply_size, &reply_fd ); pthread_mutex_unlock( &dispatch_ioctl_lock ); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Move desktop view creation and event pipe setup to a dedicated ioctl. The dispatch thread now creates the pipe and returns the read end to the caller, while keeping the write end locally. This makes ownership of the event path explicit and prepares it to be transferred cleanly through the transport. Also pass the Wine debug channel state together with the request so the dispatch side can preserve the caller's logging configuration. This prepares the event path for the upcoming process split. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 1 + dlls/wineandroid.drv/device.c | 35 ++++++++++++++++++++++++++++------ dlls/wineandroid.drv/window.c | 22 ++++++++++----------- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index c79ce31a046..853c8318601 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -82,6 +82,7 @@ extern UINT ANDROID_OpenGLInit( UINT version, const struct opengl_funcs *opengl_ */ extern void start_android_device(void); +extern void createDesktopView( int *event_source ); extern void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL client ); extern struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl ); extern struct ANativeWindow *grab_ioctl_window( struct ANativeWindow *window ); diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index fc9fecf231b..fe16634ce67 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -80,6 +80,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(android); static HWND capture_window; static HWND desktop_window; +int event_sink = -1; static pthread_mutex_t dispatch_ioctl_lock = PTHREAD_MUTEX_INITIALIZER; #define ANDROIDCONTROLTYPE ((ULONG)'A') @@ -87,6 +88,7 @@ static pthread_mutex_t dispatch_ioctl_lock = PTHREAD_MUTEX_INITIALIZER; enum android_ioctl { + IOCTL_CREATE_DESKTOP_VIEW, IOCTL_CREATE_WINDOW, IOCTL_DESTROY_WINDOW, IOCTL_WINDOW_POS_CHANGED, @@ -468,14 +470,32 @@ static jobject load_java_method( JNIEnv* env, jmethodID *method, const char *nam return java_object; } -static void create_desktop_view( JNIEnv* env ) +static int createDesktopView_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) { + static int event_pipe[2]; static jmethodID method; jobject object; + struct __wine_debug_channel *res = data; - if (!(object = load_java_method( env, &method, "createDesktopView", "()V" ))) return; + if (in_size < sizeof(*res)) return -EINVAL; + + if (event_sink != -1) close(event_sink); + + if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1) + { + _ERR( "could not create data event pipe\n" ); + return -1; + } + + event_sink = event_pipe[1]; + *reply_fd = event_pipe[0]; + + __wine_dbch_android = *res; // Copy logging levels from client + + if (!(object = load_java_method( env, &method, "createDesktopView", "()V" ))) return -ENOSYS; (*env)->CallVoidMethod( env, object, method ); + return 0; } static int createWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ) @@ -822,6 +842,7 @@ static int setCursor_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_si typedef int (*ioctl_func)( JNIEnv* env, void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size, int *reply_fd ); static const ioctl_func ioctl_funcs[] = { + createDesktopView_ioctl, /* IOCTL_CREATE_DESKTOP_VIEW */ createWindow_ioctl, /* IOCTL_CREATE_WINDOW */ destroyWindow_ioctl, /* IOCTL_DESTROY_WINDOW */ windowPosChanged_ioctl, /* IOCTL_WINDOW_POS_CHANGED */ @@ -994,8 +1015,6 @@ static void *bootstrap_looper_thread( void *arg ) abort(); } - create_desktop_view( env ); - (*java_vm)->DetachCurrentThread( java_vm ); return NULL; } @@ -1004,8 +1023,6 @@ void start_android_device(void) { pthread_t t; - __wine_dbg_get_channel_flags(&__wine_dbch_android); // force lazy init of debug channel flags for use outside Wine thread context - /* Use a temporary bootstrap thread to request the main thread looper * without interfering with the current Wine/JVM execution context * (including register and thread-state assumptions). Actual ioctl @@ -1096,6 +1113,12 @@ static void win_decRef( struct android_native_base_t *base ) InterlockedDecrement( &win->ref ); } +void createDesktopView( int *event_source ) +{ + __wine_dbg_get_channel_flags(&__wine_dbch_android); // force lazy init of debug channel flags for use outside Wine thread context + android_ioctl( IOCTL_CREATE_DESKTOP_VIEW, &__wine_dbch_android, sizeof(__wine_dbch_android), NULL, NULL, event_source ); +} + static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer, int *fence ) { struct native_win_wrapper *win = (struct native_win_wrapper *)window; diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index b3f3aeea955..98a0e3dd066 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -173,9 +173,11 @@ struct java_event static struct list event_queue = LIST_INIT( event_queue ); static struct java_event *current_event; -static int event_pipe[2]; +static int event_source; static DWORD desktop_tid; +extern int event_sink; + /*********************************************************************** * send_event */ @@ -183,7 +185,7 @@ int send_event( const union event_data *data ) { int res; - if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data)) + if ((res = write( event_sink, data, sizeof(*data) )) != sizeof(*data)) { p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" ); return -1; @@ -343,12 +345,7 @@ static void init_event_queue(void) HANDLE handle; int ret; - if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1) - { - ERR( "could not create data\n" ); - NtTerminateProcess( 0, 1 ); - } - if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle )) + if (wine_server_fd_to_handle( event_source, GENERIC_READ | SYNCHRONIZE, 0, &handle )) { ERR( "Can't allocate handle for event fd\n" ); NtTerminateProcess( 0, 1 ); @@ -383,7 +380,7 @@ static void pull_events(void) { if (!(event = malloc( sizeof(*event) ))) break; - res = read( event_pipe[0], &event->data, sizeof(event->data) ); + res = read( event_source, &event->data, sizeof(event->data) ); if (res != sizeof(event->data)) break; list_add_tail( &event_queue, &event->entry ); } @@ -515,7 +512,7 @@ static int process_events( DWORD mask ) next = LIST_ENTRY( event_queue.next, struct java_event, entry ); } current_event = previous; - return list_empty( &event_queue ) && !check_fd_events( event_pipe[0], POLLIN ); + return list_empty( &event_queue ) && !check_fd_events( event_source, POLLIN ); } @@ -531,7 +528,7 @@ static int wait_events( int timeout ) struct pollfd pollfd; int ret; - pollfd.fd = event_pipe[0]; + pollfd.fd = event_source; pollfd.events = POLLIN | POLLHUP; ret = poll( &pollfd, 1, timeout ); if (ret == -1 && errno == EINTR) continue; @@ -1238,8 +1235,9 @@ BOOL has_client_surface( HWND hwnd ) */ BOOL ANDROID_CreateDesktop( const WCHAR *name, UINT width, UINT height ) { - init_event_queue(); start_android_device(); + createDesktopView( &event_source ); + init_event_queue(); /* wait until we receive the surface changed event */ while (!screen_width) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Adjust the JNI initialization order so wineandroid.so can be loaded directly by the JVM. Load the required native libraries explicitly from Java with System.load() in dependency order, avoiding reliance on LD_LIBRARY_PATH tricks for transitive dependency resolution. This prepares the Android startup path for the upcoming process split while keeping the transition bisect-safe. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/WineActivity.java | 3 ++- dlls/wineandroid.drv/init.c | 35 +++++++++++++------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/dlls/wineandroid.drv/WineActivity.java b/dlls/wineandroid.drv/WineActivity.java index 1ee99b8a037..23b06386652 100644 --- a/dlls/wineandroid.drv/WineActivity.java +++ b/dlls/wineandroid.drv/WineActivity.java @@ -165,7 +165,8 @@ private void loadWine( String cmdline ) createProgressDialog( 0, "Setting up the Windows environment..." ); - System.load( dlldir.toString() + get_so_dir(wine_abi) + "/ntdll.so" ); + for ( String lib : new String[] { "ntdll.so", "win32u.so", "wineandroid.so" } ) + System.load( dlldir.toString() + get_so_dir(wine_abi) + "/" + lib ); prefix.mkdirs(); runWine( loader.toString(), cmdline ); diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 4ad3b42b0f5..88565dd258d 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -39,6 +39,10 @@ #include "wine/server.h" #include "wine/debug.h" +#ifndef WINE_JAVA_CLASS +#define WINE_JAVA_CLASS "org/winehq/wine/WineActivity" +#endif + WINE_DEFAULT_DEBUG_CHANNEL(android); unsigned int screen_width = 0; @@ -395,8 +399,6 @@ static void load_android_libs(void) NTSTATUS __wine_unix_lib_init(void) { pthread_mutexattr_t attr; - jclass class; - JNIEnv *jni_env; load_android_libs(); @@ -405,22 +407,21 @@ NTSTATUS __wine_unix_lib_init(void) pthread_mutex_init( &win_data_mutex, &attr ); pthread_mutexattr_destroy( &attr ); - if (java_vm) /* running under Java */ - { -#ifdef __i386__ - WORD old_fs; - __asm__( "mov %%fs,%0" : "=r" (old_fs) ); -#endif - (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); - class = (*jni_env)->GetObjectClass( jni_env, java_object ); - (*jni_env)->RegisterNatives( jni_env, class, methods, ARRAY_SIZE( methods )); - (*jni_env)->DeleteLocalRef( jni_env, class ); -#ifdef __i386__ - /* the Java VM hijacks %fs for its own purposes, restore it */ - __asm__( "mov %0,%%fs" :: "r" (old_fs) ); -#endif - } __wine_set_user_driver( &android_drv_funcs, WINE_GDI_DRIVER_VERSION ); return STATUS_SUCCESS; } +jint JNI_OnLoad( JavaVM *vm, void *reserved ) +{ + JNIEnv *env; + jclass class; + + load_android_libs(); + + java_vm = vm; + if ((*vm)->AttachCurrentThread( vm, &env, NULL ) != JNI_OK) return JNI_ERR; + if (!(class = (*env)->FindClass( env, WINE_JAVA_CLASS ))) return JNI_ERR; + (*env)->RegisterNatives( env, class, methods, ARRAY_SIZE( methods )); + (*env)->DeleteLocalRef( env, class ); + return JNI_VERSION_1_6; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Track the client connection that creates the desktop view and treat it as the lifetime owner of the Android activity. When this client (typically explorer.exe) disconnects, terminate the process to avoid leaving the activity running without an associated desktop process, which would otherwise result in a stuck or unresponsive UI. This matches the intended 1:1 relationship between the activity and the Wine desktop process and ensures that all associated resources are cleaned up when the desktop client exits. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index fe16634ce67..b1bba845532 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -73,6 +73,8 @@ static inline const char *_wine_dbgstr_rect( const RECT *rect ) WINE_DEFAULT_DEBUG_CHANNEL(android); +static int desktop_client_fd = -1; + #ifndef SYNC_IOC_WAIT #define SYNC_IOC_WAIT _IOW('>', 0, __s32) #endif @@ -905,6 +907,8 @@ static int handle_ioctl_message( JNIEnv *env, int fd ) { pthread_mutex_lock( &dispatch_ioctl_lock ); status = ioctl_funcs[code]( env, buffer, ret, sizeof(buffer), &reply_size, &reply_fd ); + if (IOCTL_CREATE_DESKTOP_VIEW == code) // special case: desktop client + desktop_client_fd = fd; pthread_mutex_unlock( &dispatch_ioctl_lock ); } } @@ -944,6 +948,8 @@ static int looper_handle_client( int fd, int events, void *data ) { pALooper_removeFd( looper, fd ); close( fd ); + if (fd == desktop_client_fd) // our explorer process died + _exit(0); } break; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Move the Android JNI startup entry point from ntdll to wineandroid.drv and use it to initialize the Android-facing driver side in the JVM process. WineActivity now starts the Wine process separately, while the JVM process keeps only the Android driver side. This follows the same client/server-style separation as winex11 and winewayland, where Wine runs as a client of an external display server. With Wine now running in its own process, it is no longer subject to the seccomp restrictions imposed on the JVM process and does not interfere with the JVM runtime context (signals, thread state, register usage, etc.). The old Android-specific JNI bootstrap code is removed from ntdll. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/ntdll/unix/loader.c | 106 ------------------------- dlls/wineandroid.drv/WineActivity.java | 36 +++++---- dlls/wineandroid.drv/android.h | 5 +- dlls/wineandroid.drv/device.c | 53 ++----------- dlls/wineandroid.drv/init.c | 9 ++- dlls/wineandroid.drv/window.c | 3 +- 6 files changed, 37 insertions(+), 175 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 8d062ffdda0..e1c4fb96772 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -77,9 +77,6 @@ #else extern char **environ; #endif -#ifdef __ANDROID__ -# include <jni.h> -#endif #include "ntstatus.h" #include "windef.h" @@ -1875,109 +1872,6 @@ static void start_main_thread(void) server_init_process_done(); } -#ifdef __ANDROID__ - -#ifndef WINE_JAVA_CLASS -#define WINE_JAVA_CLASS "org/winehq/wine/WineActivity" -#endif - -DECLSPEC_EXPORT JavaVM *java_vm = NULL; -DECLSPEC_EXPORT jobject java_object = 0; -DECLSPEC_EXPORT unsigned short java_gdt_sel = 0; - -/* main Wine initialisation */ -static jstring wine_init_jni( JNIEnv *env, jobject obj, jobjectArray cmdline ) -{ - char **argv; - char *str; - char error[1024], *winedebuglog = NULL; - int i, argc, length; - void (*update_func)( const char * ); - - /* get the command line array */ - - argc = (*env)->GetArrayLength( env, cmdline ); - for (i = length = 0; i < argc; i++) - { - jobject str_obj = (*env)->GetObjectArrayElement( env, cmdline, i ); - length += (*env)->GetStringUTFLength( env, str_obj ) + 1; - } - - argv = malloc( (argc + 1) * sizeof(*argv) + length ); - str = (char *)(argv + argc + 1); - for (i = 0; i < argc; i++) - { - jobject str_obj = (*env)->GetObjectArrayElement( env, cmdline, i ); - length = (*env)->GetStringUTFLength( env, str_obj ); - (*env)->GetStringUTFRegion( env, str_obj, 0, - (*env)->GetStringLength( env, str_obj ), str ); - argv[i] = str; - str[length] = 0; - str += length + 1; - } - argv[argc] = NULL; - - /* set the environment variables */ - - // Activity always modifies LD_LIBRARY_PATH in order to load libraries - // from custom location in JVM process. - update_func = dlsym( RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH" ); - if (update_func) update_func( getenv("LD_LIBRARY_PATH") ); - - winedebuglog = getenv("WINEDEBUGLOG"); - if (winedebuglog) - { - int fd = open( winedebuglog, O_WRONLY | O_CREAT | O_APPEND, 0666 ); - if (fd != -1) - { - dup2( fd, 2 ); - close( fd ); - } - } - - java_object = (*env)->NewGlobalRef( env, obj ); - - main_argc = argc; - main_argv = argv; - - init_paths(); - init_environment(); - -#ifdef __i386__ - { - unsigned short java_fs; - __asm__( "mov %%fs,%0" : "=r" (java_fs) ); - if (!(java_fs & 4)) java_gdt_sel = java_fs; - __asm__( "mov %0,%%fs" :: "r" (0) ); - start_main_thread(); - __asm__( "mov %0,%%fs" :: "r" (java_fs) ); - } -#else - start_main_thread(); -#endif - return (*env)->NewStringUTF( env, error ); -} - -jint JNI_OnLoad( JavaVM *vm, void *reserved ) -{ - static const JNINativeMethod method = - { - "wine_init", "([Ljava/lang/String;)Ljava/lang/String;", wine_init_jni - }; - - JNIEnv *env; - jclass class; - - virtual_init(); - - java_vm = vm; - if ((*vm)->AttachCurrentThread( vm, &env, NULL ) != JNI_OK) return JNI_ERR; - if (!(class = (*env)->FindClass( env, WINE_JAVA_CLASS ))) return JNI_ERR; - (*env)->RegisterNatives( env, class, &method, 1 ); - return JNI_VERSION_1_6; -} - -#endif /* __ANDROID__ */ #ifdef __APPLE__ static void *apple_wine_thread( void *arg ) diff --git a/dlls/wineandroid.drv/WineActivity.java b/dlls/wineandroid.drv/WineActivity.java index 23b06386652..bf2408b4410 100644 --- a/dlls/wineandroid.drv/WineActivity.java +++ b/dlls/wineandroid.drv/WineActivity.java @@ -61,8 +61,7 @@ public class WineActivity extends Activity { - private native String wine_init( String[] cmdline ); - private native void wine_looper_init(); + private native void wine_init(); public native void wine_desktop_changed( int width, int height ); public native void wine_config_changed( int dpi ); public native void wine_surface_changed( int hwnd, Surface surface, boolean opengl ); @@ -138,6 +137,7 @@ private void loadWine( String cmdline ) File dlldir = new File( libdir, "wine" ); File prefix = new File( getFilesDir(), "prefix" ); File loader = new File( dlldir, get_so_dir(wine_abi) + "/wine" ); + File log = null; String locale = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry() + ".UTF-8"; @@ -156,7 +156,7 @@ private void loadWine( String cmdline ) if (winedebug == null) winedebug = readFileString( new File( getFilesDir(), "winedebug" )); if (winedebug != null) { - File log = new File( getFilesDir(), "log" ); + log = new File( getFilesDir(), "log" ); putenv( "WINEDEBUG", winedebug ); putenv( "WINEDEBUGLOG", log.toString() ); Log.i( LOGTAG, "logging to " + log.toString() ); @@ -169,18 +169,32 @@ private void loadWine( String cmdline ) System.load( dlldir.toString() + get_so_dir(wine_abi) + "/" + lib ); prefix.mkdirs(); - runWine( loader.toString(), cmdline ); + runWine( loader.toString(), cmdline, log ); } - private final void runWine( String loader, String cmdline ) + private final void runWine( String loader, String cmdline, File log ) { + CountDownLatch latch = new CountDownLatch(1); String[] cmd = { loader, "c:\\windows\\system32\\explorer.exe", "/desktop=shell,,android", cmdline }; - String err = wine_init( cmd ); - Log.e( LOGTAG, err ); + runOnUiThread( new Runnable() { public void run() { + try { wine_init(); } finally { latch.countDown(); } + }}); + try { latch.await(); } catch ( Exception e ) {} + + try { + new ProcessBuilder(cmd) + .redirectErrorStream(true) + .redirectOutput(ProcessBuilder.Redirect.appendTo( + log != null ? log : new File("/dev/null") + )) + .start(); + } catch (IOException e) { + Log.e("WineError", "Failed to exec " + String.join(" ", cmd) + ": " + e); + } } private void createProgressDialog( final int max, final String message ) @@ -893,12 +907,4 @@ public void windowPosChanged( final int hwnd, final int flags, final int insert_ public void run() { window_pos_changed( hwnd, flags, insert_after, owner, style, window_rect, client_rect, visible_rect ); }} ); } - - private void obtainLooper() { - CountDownLatch latch = new CountDownLatch(1); - runOnUiThread( new Runnable() { public void run() { - try { wine_looper_init(); } finally { latch.countDown(); } - }}); - try { latch.await(); } catch ( Exception e ) {} - } } diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 853c8318601..cc558aa01f6 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -81,7 +81,6 @@ extern UINT ANDROID_OpenGLInit( UINT version, const struct opengl_funcs *opengl_ * Android pseudo-device */ -extern void start_android_device(void); extern void createDesktopView( int *event_source ); extern void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL client ); extern struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl ); @@ -139,6 +138,7 @@ extern void update_keyboard_lock_state( WORD vkey, UINT state ); /* JNI entry points */ extern void looper_init( JNIEnv *env, jobject obj ); +extern void wine_init_jni( JNIEnv *env, jobject obj ); extern void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height ); extern void config_changed( JNIEnv *env, jobject obj, jint dpi ); extern void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, @@ -196,8 +196,7 @@ union event_data int send_event( const union event_data *data ); -extern JavaVM *java_vm; -extern jobject java_object; +extern int event_source; /* string helpers */ diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index b1bba845532..e6c1948ed7a 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -74,6 +74,7 @@ static inline const char *_wine_dbgstr_rect( const RECT *rect ) WINE_DEFAULT_DEBUG_CHANNEL(android); static int desktop_client_fd = -1; +static jobject java_object; #ifndef SYNC_IOC_WAIT #define SYNC_IOC_WAIT _IOW('>', 0, __s32) @@ -862,17 +863,6 @@ static const ioctl_func ioctl_funcs[] = static ALooper *looper; static JNIEnv *looper_env; /* JNIEnv for the main thread looper. Must only be used from that thread. */ -void looper_init( JNIEnv* env, jobject obj ) -{ - looper_env = env; - if (!(looper = pALooper_forThread())) - { - _ERR("No looper for current thread\n"); - abort(); - } - pALooper_acquire( looper ); -} - /* Handle a single ioctl request from a client socket. * Returns 0 if a request was handled successfully and the caller may * continue draining the socket, -1 if there is nothing more to read @@ -980,25 +970,19 @@ static int looper_handle_listen( int fd, int events, void *data ) return 1; } -static void *bootstrap_looper_thread( void *arg ) +/* main Wine initialisation */ +void wine_init_jni( JNIEnv *env, jobject obj ) { - JNIEnv *env; - jmethodID method = NULL; - jobject object = NULL; int sockfd; - if (!java_vm || (*java_vm)->AttachCurrentThread( java_vm, &env, 0 ) != JNI_OK) - { - _ERR( "Failed to attach current thread\n" ); - return NULL; - } - - if (!(object = load_java_method( env, &method, "obtainLooper", "()V" ))) + java_object = (*env)->NewGlobalRef( env, obj ); + looper_env = env; + if (!(looper = pALooper_forThread())) { - _ERR( "Failed to obtain looper\n"); + _ERR("No looper for current thread\n"); abort(); } - (*env)->CallVoidMethod( env, object, method ); + pALooper_acquire( looper ); sockfd = socket( AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0 ); if (sockfd < 0) @@ -1020,27 +1004,6 @@ static void *bootstrap_looper_thread( void *arg ) close(sockfd); abort(); } - - (*java_vm)->DetachCurrentThread( java_vm ); - return NULL; -} - -void start_android_device(void) -{ - pthread_t t; - - /* Use a temporary bootstrap thread to request the main thread looper - * without interfering with the current Wine/JVM execution context - * (including register and thread-state assumptions). Actual ioctl - * dispatch then runs from the main thread looper. - */ - if (!pthread_create( &t, NULL, bootstrap_looper_thread, NULL )) - pthread_join(t, NULL); - else - { - _ERR("Failed to spawn looper bootstrap thread\n"); - abort(); - } } diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 88565dd258d..df0cb2b72ec 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -26,6 +26,8 @@ #include "config.h" +#include <fcntl.h> +#include <unistd.h> #include <stdarg.h> #include <string.h> #include <dlfcn.h> @@ -87,7 +89,7 @@ void init_monitors( int width, int height ) wine_dbgstr_rect( &rect ), wine_dbgstr_rect( &monitor_rc_work )); /* if we're notified from Java thread, update registry */ - if (java_vm) NtUserCallNoParam( NtUserCallNoParam_DisplayModeChanged ); + if (event_source != -1) NtUserCallNoParam( NtUserCallNoParam_DisplayModeChanged ); } @@ -171,7 +173,7 @@ void set_screen_dpi( DWORD dpi ) */ static void fetch_display_metrics(void) { - if (java_vm) return; /* for Java threads it will be set when the top view is created */ + if (event_source != -1) return; /* for Java threads it will be set when the top view is created */ SERVER_START_REQ( get_window_rectangles ) { @@ -328,12 +330,12 @@ static const struct user_driver_funcs android_drv_funcs = static const JNINativeMethod methods[] = { - { "wine_looper_init", "()V", looper_init }, { "wine_desktop_changed", "(II)V", desktop_changed }, { "wine_config_changed", "(I)V", config_changed }, { "wine_surface_changed", "(ILandroid/view/Surface;Z)V", surface_changed }, { "wine_motion_event", "(IIIIII)Z", motion_event }, { "wine_keyboard_event", "(IIII)Z", keyboard_event }, + { "wine_init", "()V", wine_init_jni } }; #define DECL_FUNCPTR(f) typeof(f) * p##f = NULL @@ -418,7 +420,6 @@ jint JNI_OnLoad( JavaVM *vm, void *reserved ) load_android_libs(); - java_vm = vm; if ((*vm)->AttachCurrentThread( vm, &env, NULL ) != JNI_OK) return JNI_ERR; if (!(class = (*env)->FindClass( env, WINE_JAVA_CLASS ))) return JNI_ERR; (*env)->RegisterNatives( env, class, methods, ARRAY_SIZE( methods )); diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 98a0e3dd066..db9294ee0d1 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -173,7 +173,7 @@ struct java_event static struct list event_queue = LIST_INIT( event_queue ); static struct java_event *current_event; -static int event_source; +int event_source = -1; static DWORD desktop_tid; extern int event_sink; @@ -1235,7 +1235,6 @@ BOOL has_client_surface( HWND hwnd ) */ BOOL ANDROID_CreateDesktop( const WCHAR *name, UINT width, UINT height ) { - start_android_device(); createDesktopView( &event_source ); init_event_queue(); /* wait until we receive the surface changed event */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
participants (2)
-
Twaik Yont -
Twaik Yont (@twaik)