[PATCH v3 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. -- v3: 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 preserves WINEDEBUG-based filtering through __WINE_GET_DEBUGGING(), while avoiding dependencies on Wine thread state. 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 | 69 +++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 0032224560d..1c42d07eab0 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -46,6 +46,28 @@ #include <dlfcn.h> +#define ANDROID_LOG_ERR ANDROID_LOG_ERROR +#define ANDROID_LOG_TRACE ANDROID_LOG_VERBOSE +#define ANDROID_LOG_FIXME 16 + +#define LOG(level, fmt, ...) \ + do { \ + if (!(__wine_dbch_android.flags & (1 << __WINE_DBCL_INIT)) || \ + __WINE_GET_DEBUGGING(_ ## level, &__wine_dbch_android)) \ + { \ + 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 +282,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 +382,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 +391,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 +402,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 +438,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 +465,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 +478,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 +512,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 +553,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 +584,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 +605,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 +624,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 +665,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 +755,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 +778,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 +886,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 +922,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 +940,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 +962,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 +1054,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/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 1c42d07eab0..86e98ef4097 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -79,6 +79,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) @@ -451,41 +453,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 */ @@ -1016,9 +1009,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 86e98ef4097..72099b076bf 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -239,12 +239,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) ); } @@ -257,10 +257,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 ); } @@ -268,7 +268,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]; @@ -534,15 +534,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) { @@ -553,19 +553,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; @@ -579,15 +579,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; @@ -600,16 +600,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; @@ -621,19 +621,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; @@ -732,7 +732,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; @@ -755,7 +755,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; @@ -778,7 +778,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; @@ -798,7 +798,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; @@ -885,7 +885,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; @@ -904,7 +904,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; @@ -917,15 +917,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; @@ -939,7 +939,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; @@ -957,27 +957,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 */ @@ -1010,7 +1010,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); @@ -1029,8 +1029,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
No that's even worse. On the Java side I'd suggest to use `__android_log_print directly`, or if you really need some wrappers, make it clear that these are not the standard debug macros.
Got it, simplified. Dropped the TRACE/WARN/FIXME/ERR overrides and switched this to a local LOG() helper using __android_log_print. No more reuse or renaming of the standard debug macros; the Android-side logging is now explicit and separate. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_137855
Alexandre Julliard (@julliard) commented about dlls/wineandroid.drv/device.c:
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
Why is this needed? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138018
On Tue Apr 28 16:37:09 2026 +0000, Alexandre Julliard wrote:
Why is this needed? It is needed to trigger reading WINEDEBUG before triggering any logging. `LOG` macro has this part: `if (!(__wine_dbch_android.flags & (1 << __WINE_DBCL_INIT)) || __WINE_GET_DEBUGGING(_ ## level, &__wine_dbch_android))`, so this way we make sure it is being initialized at the earliest possible point of our code.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138118
On Wed Apr 29 02:48:22 2026 +0000, Twaik Yont wrote:
It is needed to trigger reading WINEDEBUG before triggering any logging. `LOG` macro has this part: `if (!(__wine_dbch_android.flags & (1 << __WINE_DBCL_INIT)) || __WINE_GET_DEBUGGING(_ ## level, &__wine_dbch_android))`, so this way we make sure it is being initialized at the earliest possible point of our code. You should be using __wine_dbg_get_channel_flags in the macro instead.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138142
On Wed Apr 29 08:31:28 2026 +0000, Alexandre Julliard wrote:
You should be using __wine_dbg_get_channel_flags in the macro instead. Unfortunately, if __wine_dbch_android is not initialized, calling __wine_dbg_get_channel_flags() may trigger init_options(), which requires a valid Wine TEB and will crash otherwise. So it’s not safe to call it inside the LOG macro, which may run in pure Java contexts without a Wine TEB (as required on newer Android setups). That’s why it’s initialized explicitly at a safe point. In future commits I will pass `__wine_dbch_android` to Java process as is so it will be fine.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138152
On Wed Apr 29 09:11:16 2026 +0000, Twaik Yont wrote:
Unfortunately, if __wine_dbch_android is not initialized, calling __wine_dbg_get_channel_flags() may trigger init_options(), which requires a valid Wine TEB and will crash otherwise. So it’s not safe to call it inside the LOG macro, which may run in pure Java contexts without a Wine TEB (as required on newer Android setups). That’s why it’s initialized explicitly at a safe point. In future commits I will pass `__wine_dbch_android` to Java process as is so it will be fine. init_options() doesn't require a TEB.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138154
On Wed Apr 29 09:17:23 2026 +0000, Alexandre Julliard wrote:
init_options() doesn't require a TEB. It calls `NtCurrentTeb()`.
`dlls/ntdll/thread.c` ``` static void init_options(void) { unsigned int offset = page_size * (sizeof(void *) / 4); debug_options = (struct __wine_debug_channel *)((char *)NtCurrentTeb()->Peb + offset); while (debug_options[nb_debug_options].name[0]) nb_debug_options++; } ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138162
On Wed Apr 29 09:46:10 2026 +0000, Twaik Yont wrote:
It calls `NtCurrentTeb()`. `dlls/ntdll/thread.c` ``` static void init_options(void) { unsigned int offset = page_size * (sizeof(void *) / 4); debug_options = (struct __wine_debug_channel *)((char *)NtCurrentTeb()->Peb + offset); while (debug_options[nb_debug_options].name[0]) nb_debug_options++; } ``` That's the PE version, but you are running on the Unix side, the code is in dlls/ntdll/unix/debug.c.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138164
On Wed Apr 29 09:50:13 2026 +0000, Alexandre Julliard wrote:
That's the PE version, but you are running on the Unix side, the code is in dlls/ntdll/unix/debug.c. Ok, sorry, I was wrong about that.
The early call is just to ensure the channel is initialized once on the Wine side, so the `LOG` macro can rely on the lightweight `__WINE_GET_DEBUGGING()` checks. I plan to move this into the createDesktopView startup path (through ioctl) in follow-up commits, so the logging flags can be synchronized between the Java and Wine processes. In follow-up commits, the Java-invoked code will only interact with Wine through the new transport layer, without invoking any functions outside of `wineandroid.so`. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138177
On Wed Apr 29 10:38:04 2026 +0000, Twaik Yont wrote:
Ok, sorry, I was wrong about that. The early call is just to ensure the channel is initialized once on the Wine side, so the `LOG` macro can rely on the lightweight `__WINE_GET_DEBUGGING()` checks. I plan to move this into the createDesktopView startup path (through ioctl) in follow-up commits, so the logging flags can be synchronized between the Java and Wine processes. In follow-up commits, the Java-invoked code will only interact with Wine through the new transport layer, without invoking any functions outside of `wineandroid.so`. It seems odd to want to avoid ntdll functions but still use debug channels. I'd suggest to define Android-specific logging flags instead.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138439
On Thu Apr 30 20:32:48 2026 +0000, Alexandre Julliard wrote:
It seems odd to want to avoid ntdll functions but still use debug channels. I'd suggest to define Android-specific logging flags instead. I’m not trying to rely on ntdll debug channels as such, but rather to avoid emitting logs unconditionally.
Even though logcat logging is cheaper than writing to a pty or a file, it’s still not free, and more importantly it quickly becomes very noisy. If everything is logged unconditionally, it becomes harder to follow specific events during debugging. So the goal here is mainly to keep the same filtering semantics and avoid printing logs unless they are explicitly enabled, rather than to reuse Wine debug channels directly. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138508
On Fri May 1 08:13:02 2026 +0000, Twaik Yont wrote:
I’m not trying to rely on ntdll debug channels as such, but rather to avoid emitting logs unconditionally. Even though logcat logging is cheaper than writing to a pty or a file, it’s still not free, and more importantly it quickly becomes very noisy. If everything is logged unconditionally, it becomes harder to follow specific events during debugging. So the goal here is mainly to keep the same filtering semantics and avoid printing logs unless they are explicitly enabled, rather than to reuse Wine debug channels directly. Yes, that's what I meant. Instead of using Wine debug channels where all you really need is a couple of flags, just use a couple of flags.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138509
On Fri May 1 08:37:08 2026 +0000, Alexandre Julliard wrote:
Yes, that's what I meant. Instead of using Wine debug channels where all you really need is a couple of flags, just use a couple of flags. I’d prefer to keep this change minimal and avoid adding a separate logging configuration/synchronization layer.
__WINE_GET_DEBUGGING itself is just a lightweight bit check on the channel flags and does not call into any ntdll code once the channel is initialized. Because of that, it’s effectively just a cheap runtime check. The idea here is to reuse that state directly instead of reimplementing a parallel set of flags. In follow-up work I plan to pass the channel flags structure to the Java side as-is, so the logging behavior can stay in sync without additional code for mapping or synchronization. I’m not trying to argue against your suggestion, just to explain the reasoning before changing the behavior. If you’d still prefer separate Android-side flags, I can switch to that. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138510
On Fri May 1 08:52:37 2026 +0000, Twaik Yont wrote:
I’d prefer to keep this change minimal and avoid adding a separate logging configuration/synchronization layer. __WINE_GET_DEBUGGING itself is just a lightweight bit check on the channel flags and does not call into any ntdll code once the channel is initialized. Because of that, it’s effectively just a cheap runtime check. The idea here is to reuse that state directly instead of reimplementing a parallel set of flags. In follow-up work I plan to pass the channel flags structure to the Java side as-is, so the logging behavior can stay in sync without additional code for mapping or synchronization. I’m not trying to argue against your suggestion, just to explain the reasoning before changing the behavior. If you’d still prefer separate Android-side flags, I can switch to that. Seems like I can simply pass the flags instead of the whole channel structure, without hurting the code.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10710#note_138511
participants (3)
-
Alexandre Julliard (@julliard) -
Twaik Yont -
Twaik Yont (@twaik)