[PATCH v4 0/3] MR10710: wineandroid: prepare ioctl dispatch for Java-only thread execution (part of !10569)
Part of !10569. This series prepares wineandroid ioctl dispatch paths for execution on Java-originated threads that do not have a Wine TEB. It does three things: * pass JNIEnv explicitly through the ioctl dispatch path instead of relying on the global jni_env value in handlers * move native window registration from the APC/unixlib callback path to the direct JNI surface_changed callback on the Android UI thread * make logging in device.c context-aware so the same code remains safe both on Wine threads and on Java-only threads The JNIEnv change is a preparatory refactoring. It does not by itself complete the thread model transition, but it removes one of the major implicit dependencies on Wine thread context and makes follow-up changes smaller and easier to review. Moving native window registration to surface_changed removes another dependency on APC-based execution in the desktop process and puts window attachment on the thread that actually receives the Android surface callbacks. A shared lock is used to serialize registration against ioctl dispatch. Finally, logging in device.c is made context-aware. Upcoming changes will run parts of ioctl dispatch on Java-only threads, where the standard Wine TRACE/WARN/FIXME/ERR macros are unsafe because they depend on Wine TEB state. The local logging wrapper preserves normal Wine logging semantics on Wine threads and falls back to Android logging on non-Wine threads, allowing the existing code to keep using the standard logging macros without invasive per-call-site changes. Taken together, these patches remove several implicit Wine-thread-only assumptions from wineandroid ioctl dispatch code and prepare the path for running more of it directly on Java-side threads. -- v4: wineandroid: pass JNIEnv explicitly through ioctl handlers wineandroid: move native window registration to surface_changed wineandroid: use Android logging for ioctl paths https://gitlab.winehq.org/wine/wine/-/merge_requests/10710
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Replace use of Wine debug macros (TRACE/WARN/FIXME/ERR) in wineandroid ioctl-related code with a local LOG() helper based on __android_log_print. This is a preparatory change for moving ioctl dispatch to Android-managed threads, where no Wine TEB is available and the standard Wine debug macros are not safe to use. The new logging path uses debug channel flags initialized on the Wine side and relies on lightweight flag checks to preserve WINEDEBUG-based filtering, without invoking Wine debug helpers at runtime. Also replace wine_dbgstr_rect() with local formatting helpers. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 70 +++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 0032224560d..622404d5d5d 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -46,6 +46,29 @@ #include <dlfcn.h> +#define ANDROID_LOG_ERR ANDROID_LOG_ERROR +#define ANDROID_LOG_TRACE ANDROID_LOG_VERBOSE +#define ANDROID_LOG_FIXME 16 + +static int log_flags; + +#define LOG(level, fmt, ...) \ + do { \ + if (!(log_flags & (1 << __WINE_DBCL_INIT)) || (log_flags & (1 << __WINE_DBCL_ ## level))) \ + { \ + int prio = (ANDROID_LOG_ ## level == ANDROID_LOG_FIXME) ? \ + ANDROID_LOG_WARN : ANDROID_LOG_ ## level; \ + p__android_log_print(prio, "wineandroid.drv", "%s: %s" fmt, \ + __func__, \ + (ANDROID_LOG_ ## level == ANDROID_LOG_FIXME) ? "FIXME: " : "", \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define DBGSTR_RECT_FMT "(%d,%d)-(%d,%d)" +#define DBGSTR_RECT(rect) (int)(rect)->left, (int)(rect)->top, (int)(rect)->right, (int)(rect)->bottom + + WINE_DEFAULT_DEBUG_CHANNEL(android); #ifndef SYNC_IOC_WAIT @@ -260,7 +283,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 ); + LOG( WARN, "unknown win %p opengl %u\n", hwnd, opengl ); return NULL; } @@ -360,7 +383,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", + LOG( 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 +392,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 ); + LOG( TRACE, "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i ); done: insert_buffer_lru( win, i ); @@ -380,7 +403,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 ); + LOG( ERR, "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent ); return NULL; } return anwb_from_ahb(win->buffers[id]); @@ -416,7 +439,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 ); + LOG( 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 +466,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 ); + LOG( TRACE, "%p -> %p win %p (unchanged)\n", hwnd, data, win ); return 0; } @@ -456,7 +479,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 ); + LOG( TRACE, "%p -> %p win %p\n", hwnd, data, win ); return 0; } @@ -490,7 +513,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 ); + LOG( FIXME, "unmapped error %d\n", err ); return STATUS_UNSUCCESSFUL; } } @@ -531,7 +554,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 ); + LOG( FIXME, "method %s not found\n", name ); return NULL; } } @@ -562,7 +585,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 ); + LOG( 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 +606,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 ); + LOG( 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 +625,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 ); + LOG( TRACE, "hwnd %08x win " DBGSTR_RECT_FMT " client " DBGSTR_RECT_FMT " visible " DBGSTR_RECT_FMT " style %08x flags %08x after %08x owner %08x\n", + res->hdr.hwnd, DBGSTR_RECT(&res->window_rect), DBGSTR_RECT(&res->client_rect), + 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 +666,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 ); + LOG( ERR, "%08x failed %d\n", res->hdr.hwnd, ret ); return android_error_to_status( ret ); } if (!buffer) { - TRACE( "got invalid buffer\n" ); + LOG( TRACE, "got invalid buffer\n" ); return STATUS_UNSUCCESSFUL; } - TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence ); + LOG( 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 +756,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 ); + LOG( TRACE, "%08x buffer %p\n", res->hdr.hwnd, buffer ); wrap_java_call(); ret = parent->cancelBuffer( parent, buffer, -1 ); unwrap_java_call(); @@ -756,7 +779,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 ); + LOG( TRACE, "%08x buffer %p\n", res->hdr.hwnd, buffer ); wrap_java_call(); ret = parent->queueBuffer( parent, buffer, -1 ); unwrap_java_call(); @@ -864,7 +887,7 @@ static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_ } case NATIVE_WINDOW_LOCK: default: - FIXME( "unsupported perform op %d\n", res->operation ); + LOG( FIXME, "unsupported perform op %d\n", res->operation ); break; } return android_error_to_status( ret ); @@ -900,7 +923,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 ); + LOG( 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 +941,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 ); + LOG( TRACE, "hwnd %08x\n", res->hdr.hwnd ); InterlockedExchangePointer( (void **)&capture_window, LongToHandle( res->hdr.hwnd )); return STATUS_SUCCESS; @@ -940,7 +963,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 ); + LOG( 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 +1055,7 @@ void start_android_device(void) void *ret_ptr; ULONG ret_len; struct dispatch_callback_params params = {.callback = start_device_callback}; + log_flags = __wine_dbg_get_channel_flags(&__wine_dbch_android); 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/10710
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 622404d5d5d..14594afd644 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -80,6 +80,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) @@ -452,41 +454,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 ); LOG( 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 ); LOG( 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 */ @@ -1017,9 +1010,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/10710
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, aligning these JNI interaction paths with 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, so this is a preparatory refactoring, not the final thread-safety fix. 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 14594afd644..d78913af830 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -240,12 +240,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) ); } @@ -258,10 +258,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 ); } @@ -269,7 +269,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]; @@ -535,15 +535,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) { @@ -554,19 +554,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 ) +static NTSTATUS createWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { static jmethodID method; jobject object; @@ -580,15 +580,15 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U LOG( 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 ) +static NTSTATUS destroyWindow_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { static jmethodID method; jobject object; @@ -601,16 +601,16 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, LOG( 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 ) +static NTSTATUS windowPosChanged_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { static jmethodID method; jobject object; @@ -622,19 +622,19 @@ static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_siz res->hdr.hwnd, DBGSTR_RECT(&res->window_rect), DBGSTR_RECT(&res->client_rect), 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 ) +static NTSTATUS dequeueBuffer_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { struct ANativeWindow *parent; struct ioctl_android_dequeueBuffer *res = data; @@ -733,7 +733,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( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { struct ioctl_android_cancelBuffer *res = data; struct ANativeWindow *parent; @@ -756,7 +756,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( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { struct ioctl_android_queueBuffer *res = data; struct ANativeWindow *parent; @@ -779,7 +779,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( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { struct ioctl_android_query *res = data; struct ANativeWindow *parent; @@ -799,7 +799,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( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { struct ioctl_android_perform *res = data; struct ANativeWindow *parent; @@ -886,7 +886,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( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { struct ioctl_android_set_swap_interval *res = data; struct ANativeWindow *parent; @@ -905,7 +905,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( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { static jmethodID method; jobject object; @@ -918,15 +918,15 @@ static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size LOG( 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 ) +static NTSTATUS setCapture_ioctl( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { struct ioctl_android_set_capture *res = data; @@ -940,7 +940,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( JNIEnv* env, void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ) { static jmethodID method; jobject object; @@ -958,27 +958,27 @@ static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULON LOG( 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 ); +typedef NTSTATUS (*ioctl_func)( JNIEnv* env, void *in, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size ); static const ioctl_func ioctl_funcs[] = { createWindow_ioctl, /* IOCTL_CREATE_WINDOW */ @@ -1011,7 +1011,7 @@ NTSTATUS android_dispatch_ioctl( void *arg ) { 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 ); pthread_mutex_unlock(&dispatch_ioctl_lock); @@ -1030,8 +1030,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/10710
On Fri May 1 09:09:14 2026 +0000, Twaik Yont wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/10710/diffs?diff_id=264686&start_sha=e33782efc85bf57e3a1e3c680234053bae4e7e94#6934de5ce9de7113645219cac6147b37aeb1f6ec_1052_1053) Done, it now only checks the flags, without touching debug channels after the initial initialization on the Wine side.
There isn’t a real separation yet, but this will be wired up properly in follow-up changes. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138514
participants (2)
-
Twaik Yont -
Twaik Yont (@twaik)