[PATCH 0/7] MR10569: 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. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Pass the client pid explicitly in ioctl_android_dequeueBuffer and remove the extra client_id plumbing from the ioctl dispatch path. The pid is only needed for dequeueBuffer handle duplication, so there is no need to thread it through ioctl dispatch state or the Java createWindow/setParent calls. This simplifies the dispatch path and makes pid handling explicit at the single call site that requires it. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/WineActivity.java | 12 ++++++------ dlls/wineandroid.drv/device.c | 27 +++++++++----------------- dlls/wineandroid.drv/dllmain.c | 3 +-- dlls/wineandroid.drv/unixlib.h | 8 -------- 4 files changed, 16 insertions(+), 34 deletions(-) diff --git a/dlls/wineandroid.drv/WineActivity.java b/dlls/wineandroid.drv/WineActivity.java index 2eee16b2dc1..424f8a6a82e 100644 --- a/dlls/wineandroid.drv/WineActivity.java +++ b/dlls/wineandroid.drv/WineActivity.java @@ -798,7 +798,7 @@ public void create_desktop_view() wine_config_changed( getResources().getConfiguration().densityDpi ); } - public void create_window( int hwnd, boolean is_desktop, boolean opengl, int parent, float scale, int pid ) + public void create_window( int hwnd, boolean is_desktop, boolean opengl, int parent, float scale ) { WineWindow win = get_window( hwnd ); if (win == null) @@ -822,7 +822,7 @@ public void destroy_window( int hwnd ) if (win != null) win.destroy(); } - public void set_window_parent( int hwnd, int parent, float scale, int pid ) + public void set_window_parent( int hwnd, int parent, float scale ) { WineWindow win = get_window( hwnd ); if (win == null) return; @@ -855,9 +855,9 @@ public void createDesktopView() runOnUiThread( new Runnable() { public void run() { create_desktop_view(); }} ); } - public void createWindow( final int hwnd, final boolean is_desktop, final boolean opengl, final int parent, final float scale, final int pid ) + public void createWindow( final int hwnd, final boolean is_desktop, final boolean opengl, final int parent, final float scale ) { - runOnUiThread( new Runnable() { public void run() { create_window( hwnd, is_desktop, opengl, parent, scale, pid ); }} ); + runOnUiThread( new Runnable() { public void run() { create_window( hwnd, is_desktop, opengl, parent, scale ); }} ); } public void destroyWindow( final int hwnd ) @@ -865,9 +865,9 @@ public void destroyWindow( final int hwnd ) runOnUiThread( new Runnable() { public void run() { destroy_window( hwnd ); }} ); } - public void setParent( final int hwnd, final int parent, final float scale, final int pid ) + public void setParent( final int hwnd, final int parent, final float scale ) { - runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd, parent, scale, pid ); }} ); + runOnUiThread( new Runnable() { public void run() { set_window_parent( hwnd, parent, scale ); }} ); } public void setCursor( final int id, final int width, final int height, diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 3d77033a980..b3a502bd5cc 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -156,6 +156,7 @@ struct ioctl_android_window_pos_changed struct ioctl_android_dequeueBuffer { struct ioctl_header hdr; + DWORD pid; HANDLE handle; int buffer_id; int generation; @@ -224,12 +225,6 @@ static inline BOOL is_in_desktop_process(void) return thread != NULL; } -static inline DWORD current_client_id(void) -{ - DWORD client_id = NtUserGetThreadInfo()->driver_data; - return client_id ? client_id : GetCurrentProcessId(); -} - #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; @@ -610,7 +605,6 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U jobject object; struct ioctl_android_create_window *res = data; struct native_win_data *win_data; - DWORD pid = current_client_id(); if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; @@ -619,10 +613,10 @@ 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", "(IZZIFI)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( &method, "createWindow", "(IZZIF)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, res->scale, pid ); + (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->is_desktop, res->hdr.opengl, res->parent, res->scale ); unwrap_java_call(); return STATUS_SUCCESS; } @@ -720,7 +714,7 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, int sv[2] = { -1, -1 }; HANDLE local = 0; OBJECT_ATTRIBUTES attr = { .Length = sizeof(attr) }; - CLIENT_ID cid = { .UniqueProcess = UlongToHandle( current_client_id() ) }; + CLIENT_ID cid = { .UniqueProcess = UlongToHandle( res->pid ) }; HANDLE process; if (!ahb) @@ -950,7 +944,6 @@ static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size jobject object; struct ioctl_android_set_window_parent *res = data; struct native_win_data *win_data; - DWORD pid = current_client_id(); if (in_size < sizeof(*res)) return STATUS_INVALID_PARAMETER; @@ -958,10 +951,10 @@ 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", "(IIFI)V" ))) return STATUS_NOT_SUPPORTED; + if (!(object = load_java_method( &method, "setParent", "(IIF)V" ))) return STATUS_NOT_SUPPORTED; wrap_java_call(); - (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, res->scale, pid ); + (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, res->scale ); unwrap_java_call(); return STATUS_SUCCESS; } @@ -1037,8 +1030,7 @@ static const ioctl_func ioctl_funcs[] = NTSTATUS android_dispatch_ioctl( void *arg ) { - struct ioctl_params *params = arg; - IRP *irp = params->irp; + IRP *irp = arg; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); DWORD code = (irpsp->Parameters.DeviceIoControl.IoControlCode - ANDROID_IOCTL(0)) >> 2; @@ -1051,11 +1043,9 @@ NTSTATUS android_dispatch_ioctl( void *arg ) if (in_size >= sizeof(*header)) { irp->IoStatus.Information = 0; - NtUserGetThreadInfo()->driver_data = params->client_id; irp->IoStatus.Status = func( irp->AssociatedIrp.SystemBuffer, in_size, irpsp->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus.Information ); - NtUserGetThreadInfo()->driver_data = 0; } else irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } @@ -1158,11 +1148,12 @@ static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuff 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( IOCTL_DEQUEUE_BUFFER, &res, sizeof(res.hdr), &res, &size ); + ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, size, &res, &size ); if (ret) return ret; if (size < sizeof(res)) return -EINVAL; diff --git a/dlls/wineandroid.drv/dllmain.c b/dlls/wineandroid.drv/dllmain.c index d9cd94338a0..7f6d04e83df 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -37,8 +37,7 @@ static HANDLE stop_event; static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp ) { - struct ioctl_params params = { .irp = irp, .client_id = HandleToUlong(PsGetCurrentProcessId()) }; - NTSTATUS status = ANDROID_CALL( dispatch_ioctl, ¶ms ); + NTSTATUS status = ANDROID_CALL( dispatch_ioctl, irp ); IoCompleteRequest( irp, IO_NO_INCREMENT ); return status; } diff --git a/dlls/wineandroid.drv/unixlib.h b/dlls/wineandroid.drv/unixlib.h index 46c59f8f201..39a4df58283 100644 --- a/dlls/wineandroid.drv/unixlib.h +++ b/dlls/wineandroid.drv/unixlib.h @@ -39,14 +39,6 @@ struct init_params }; -/* android_ioctl params */ -struct ioctl_params -{ - struct _IRP *irp; - DWORD client_id; -}; - - /* android_register_window params */ struct register_window_params { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Route ioctl dispatch related logging in device.c through __android_log_print and map WINEDEBUG levels to Android log priorities. Initialize a per-module verbosity level from the Wine debug channel and use it to filter logcat output, preserving the effective debug level without relying on Wine debug macros at call sites. This prepares the ioctl dispatch path for execution outside of the Wine context (e.g. on the Android activity thread), where the standard Wine debug infrastructure is not available. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 1 + dlls/wineandroid.drv/device.c | 89 ++++++++++++++++++++++++---------- dlls/wineandroid.drv/init.c | 1 + 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 3107136cb7e..773c602514f 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -119,6 +119,7 @@ enum android_window_messages WM_ANDROID_REFRESH = WM_WINE_FIRST_DRIVER_MSG, }; +extern void init_android_log_verbosity(void); extern void init_ahardwarebuffers(void); extern HWND get_capture_window(void); extern void init_monitors( int width, int height ); diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index b3a502bd5cc..da73298fd72 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -48,6 +48,45 @@ WINE_DEFAULT_DEBUG_CHANNEL(android); +static int android_log_verbosity = ANDROID_LOG_VERBOSE; + +void init_android_log_verbosity(void) +{ + struct __wine_debug_channel *ch = &__wine_dbch_android; + + if (__WINE_IS_DEBUG_ON(_TRACE, ch)) + android_log_verbosity = ANDROID_LOG_VERBOSE; + else if (__WINE_IS_DEBUG_ON(_FIXME, ch)) + android_log_verbosity = ANDROID_LOG_WARN; + else if (__WINE_IS_DEBUG_ON(_WARN, ch)) + android_log_verbosity = ANDROID_LOG_WARN; + else if (__WINE_IS_DEBUG_ON(_ERR, ch)) + android_log_verbosity = ANDROID_LOG_ERROR; + else + android_log_verbosity = ANDROID_LOG_SILENT; +} + +#define __LOG(prio, ...) \ + do { if ((ANDROID_LOG_ ## prio) >= android_log_verbosity) \ + p__android_log_print( ANDROID_LOG_ ## prio, "wine", __VA_ARGS__ ); } while (0) +#define _INFO(...) __LOG(INFO, __VA_ARGS__) +#define _DEBUG(...) __LOG(DEBUG, __VA_ARGS__) +#define _WARN(...) __LOG(WARN, __VA_ARGS__) +#define _FIXME(...) __LOG(WARN, "FIXME: " __VA_ARGS__) +#define _TRACE(...) __LOG(VERBOSE, __VA_ARGS__) +#define _ERR(...) __LOG(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; +} + #define DECL_FUNCPTR(f) static typeof(f) * p##f = NULL struct AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(struct ANativeWindowBuffer* anwb) __INTRODUCED_IN(26); @@ -275,7 +314,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; } @@ -375,7 +414,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]); } @@ -384,7 +423,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 ); @@ -395,7 +434,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]); @@ -431,7 +470,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; @@ -458,7 +497,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; } @@ -471,7 +510,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; } @@ -537,7 +576,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; } } @@ -561,7 +600,7 @@ static int status_to_android_error( unsigned int status ) case STATUS_INVALID_DEVICE_REQUEST: return -EBADMSG; case STATUS_DEVICE_NOT_READY: return -EWOULDBLOCK; default: - FIXME( "unmapped status %08x\n", status ); + _FIXME( "unmapped status %08x\n", status ); return -EINVAL; } } @@ -580,7 +619,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; } } @@ -611,7 +650,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", "(IZZIF)V" ))) return STATUS_NOT_SUPPORTED; @@ -632,7 +671,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; @@ -651,9 +690,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; @@ -692,17 +731,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 ); @@ -782,7 +821,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(); @@ -805,7 +844,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(); @@ -913,7 +952,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 ); + _FIXME( "unsupported perform op %d\n", res->operation ); break; } return android_error_to_status( ret ); @@ -949,7 +988,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", "(IIF)V" ))) return STATUS_NOT_SUPPORTED; @@ -967,7 +1006,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; @@ -989,7 +1028,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; @@ -1051,7 +1090,7 @@ NTSTATUS android_dispatch_ioctl( void *arg ) } else { - FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); + _FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); irp->IoStatus.Status = STATUS_NOT_SUPPORTED; } return STATUS_SUCCESS; diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 303655cde58..e8cb360d032 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -386,6 +386,7 @@ static HRESULT android_init( void *arg ) object = *p_java_object; + init_android_log_verbosity(); init_ahardwarebuffers(); pthread_mutexattr_init( &attr ); -- 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. Keep WM_ANDROID_REFRESH posted from process_events() after updating the native window state. Add a temporary serialization lock around ioctl dispatch and native window registration to keep intermediate migration commits bisectable while moving this code away from the old APC execution path. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 2 -- dlls/wineandroid.drv/device.c | 38 +++++++++++++++++----------------- dlls/wineandroid.drv/dllmain.c | 8 ------- dlls/wineandroid.drv/init.c | 3 --- dlls/wineandroid.drv/unixlib.h | 11 ---------- dlls/wineandroid.drv/window.c | 3 ++- 6 files changed, 21 insertions(+), 44 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 773c602514f..077d11ae7c9 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -105,8 +105,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; diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index da73298fd72..94bc7fe3a85 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -109,6 +109,8 @@ static JNIEnv *jni_env; static HWND capture_window; static HWND desktop_window; +static pthread_mutex_t dispatch_ioctl_lock = PTHREAD_MUTEX_INITIALIZER; // Temporary lock for bisect-safe serialization of dispatch-related state during the APC-to-JNI registration migration. + #define ANDROIDCONTROLTYPE ((ULONG)'A') #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS) @@ -397,6 +399,7 @@ static void insert_buffer_lru( struct native_win_data *win, int index ) win->buffer_lru[0] = index; } +/* Called from JNI surface_changed() on the Java thread */ static int register_buffer( struct native_win_data *win, struct AHardwareBuffer *buffer, int *is_new ) { unsigned int i; @@ -483,41 +486,36 @@ 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 Java side 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; - if (!win) return 0; /* do nothing and hold on to the window until we get a new surface */ + pthread_mutex_lock(&dispatch_ioctl_lock); + data = get_native_win_data( hwnd, opengl ); + + if (!win) { + pthread_mutex_unlock(&dispatch_ioctl_lock); + return; /* 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; + pthread_mutex_unlock(&dispatch_ioctl_lock); + return; } 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 ); + pthread_mutex_unlock(&dispatch_ioctl_lock); + return; } #define LOAD_FUNCPTR(lib, func) do { \ @@ -1082,9 +1080,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..d1775c4f4e4 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -90,13 +90,6 @@ 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 */ @@ -109,7 +102,6 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) 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 ); } diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index e8cb360d032..f4faaca2216 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -48,7 +48,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 @@ -394,7 +393,6 @@ 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; if ((java_vm = *p_java_vm)) /* running under Java */ @@ -423,7 +421,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..bc15911ebd9 100644 --- a/dlls/wineandroid.drv/unixlib.h +++ b/dlls/wineandroid.drv/unixlib.h @@ -25,7 +25,6 @@ enum android_funcs unix_init, unix_java_init, unix_java_uninit, - unix_register_window, unix_funcs_count }; @@ -34,15 +33,5 @@ enum android_funcs /* 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 41439c2f697..7cafea756b4 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -252,6 +252,7 @@ void surface_changed( JNIEnv *env, jobject obj, jint win, jobject surface, jbool 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 ); + register_native_window( data.surface.hwnd, data.surface.window, data.surface.client ); } data.type = SURFACE_CHANGED; send_event( &data ); @@ -457,7 +458,7 @@ static int process_events( DWORD mask ) event->data.surface.window, 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. 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 is a preparatory change with no functional impact. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 57 ++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 94bc7fe3a85..4fba423af6f 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -636,7 +636,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; @@ -658,7 +658,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; @@ -680,7 +680,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; @@ -704,7 +704,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; @@ -803,7 +803,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; @@ -826,7 +826,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; @@ -849,7 +849,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; @@ -869,7 +869,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; @@ -956,7 +956,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; @@ -975,7 +975,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; @@ -996,7 +996,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; @@ -1010,7 +1010,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; @@ -1048,7 +1048,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 */ @@ -1076,6 +1076,7 @@ NTSTATUS android_dispatch_ioctl( void *arg ) struct ioctl_header *header = irp->AssociatedIrp.SystemBuffer; DWORD in_size = irpsp->Parameters.DeviceIoControl.InputBufferLength; ioctl_func func = ioctl_funcs[code]; + int reply_fd = -1; if (in_size >= sizeof(*header)) { @@ -1083,7 +1084,7 @@ NTSTATUS android_dispatch_ioctl( void *arg ) 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; @@ -1132,7 +1133,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 *recv_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; @@ -1155,6 +1156,8 @@ static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void if (InterlockedCompareExchangePointer( &device, file, NULL )) NtClose( file ); } + if (recv_fd) *recv_fd = -1; + status = NtDeviceIoControlFile( device, NULL, NULL, NULL, &iosb, ANDROID_IOCTL(code), in, in_size, out, out_size ? *out_size : 0 ); if (status == STATUS_FILE_DELETED) @@ -1192,7 +1195,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; @@ -1248,7 +1251,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 ) @@ -1267,7 +1270,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 ) @@ -1302,7 +1305,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 ) @@ -1315,7 +1318,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; @@ -1457,7 +1460,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, float scale ) @@ -1491,7 +1494,7 @@ struct ANativeWindow *create_ioctl_window( HWND hwnd, BOOL opengl, float scale ) req.parent = get_ioctl_win_parent( NtUserGetAncestor( hwnd, GA_PARENT )); req.scale = scale; 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; } @@ -1524,7 +1527,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, @@ -1541,7 +1544,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, float scale ) @@ -1552,7 +1555,7 @@ int ioctl_set_window_parent( HWND hwnd, HWND parent, float scale ) req.hdr.opengl = FALSE; req.parent = get_ioctl_win_parent( parent ); req.scale = scale; - 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 ) @@ -1561,7 +1564,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, @@ -1580,7 +1583,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> Add a socket-based backend for android ioctl dispatch. This introduces a listener thread implementation based on a Unix seqpacket socket with epoll, along with a new android_ioctl_new() client-side path supporting regular replies and optional file descriptor passing via SCM_RIGHTS. The new backend is not wired up yet and is currently unused. Existing ioctl handling remains unchanged. This is a preparatory step for migrating ioctl dispatch to a socket-based transport. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 224 ++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 4fba423af6f..02ccf2760cd 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -32,6 +32,9 @@ #include <stdarg.h> #include <sys/ioctl.h> #include <sys/socket.h> +#include <sys/un.h> +#include <sys/epoll.h> +#include <sys/uio.h> #include <unistd.h> #include "ntstatus.h" @@ -163,6 +166,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; @@ -1120,6 +1131,159 @@ NTSTATUS android_java_uninit( void *arg ) return STATUS_SUCCESS; } +static void *ioctl_thread_proc(void *arg) +{ + JavaVM *java_vm; + int listen_fd, epoll_fd; + + if (!(java_vm = *p_java_vm)) return NULL; /* not running under Java */ + init_java_thread( java_vm ); + create_desktop_view(); + + listen_fd = socket( AF_UNIX, SOCK_SEQPACKET, 0 ); + if (listen_fd < 0) { + _ERR( "Failed to open server socket: %s\n", strerror(errno) ); + return NULL; + } + + if (bind( listen_fd, (const struct sockaddr *)&ipc_addr, IPC_SOCKET_ADDR_LEN ) < 0 || + listen( listen_fd, 32 ) < 0) + { + _ERR( "Failed to bind server socket: %s\n", strerror(errno) ); + close( listen_fd ); + return NULL; + } + + epoll_fd = epoll_create1( EPOLL_CLOEXEC ); + if (epoll_fd < 0) + { + _ERR( "Failed to create server epoll: %s\n", strerror(errno) ); + close( listen_fd ); + return NULL; + } + + if (epoll_ctl( epoll_fd, EPOLL_CTL_ADD, listen_fd, + &(struct epoll_event){ .events = EPOLLIN, .data.fd = listen_fd } ) < 0) + { + close( epoll_fd ); + close( listen_fd ); + return NULL; + } + + for (;;) + { + struct epoll_event events[16]; + int i, count = epoll_wait( epoll_fd, events, ARRAY_SIZE(events), -1 ); + + if (count < 0) + { + if (errno == EINTR) continue; + break; + } + + for (i = 0; i < count; i++) + { + int fd = events[i].data.fd; + + if (fd == listen_fd) + { + int client = accept( listen_fd, NULL, NULL ); + if (client < 0) + { + if (errno == EINTR) continue; + continue; + } + + if (epoll_ctl( epoll_fd, EPOLL_CTL_ADD, client, + &(struct epoll_event){ .events = EPOLLIN, .data.fd = client } ) < 0) + close( client ); + continue; + } + + if (events[i].events & (EPOLLHUP | EPOLLERR)) + { + epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL ); + close( fd ); + continue; + } + + for (;;) + { + 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) continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) break; + epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL ); + close( fd ); + break; + } + + if (!ret || ret < sizeof(code)) + { + epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL ); + close( fd ); + break; + } + + 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]( 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; + } + + if (sendmsg( fd, &reply, 0 ) < 0) + { + if (reply_fd != -1) close( reply_fd ); + epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL ); + close( fd ); + break; + } + + if (reply_fd != -1) close( reply_fd ); + } + } + } + + close( epoll_fd ); + close( listen_fd ); + (*java_vm)->DetachCurrentThread( java_vm ); + return NULL; +} + void start_android_device(void) { void *ret_ptr; @@ -1169,6 +1333,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_new( 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; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Remove the legacy ioctl backend startup via KeUserDispatchCallback and switch fully to the socket-based transport. A dedicated listener thread is now started directly with pthread_create, and the desktop process is tracked via an explicit in_desktop_process flag. dequeueBuffer is updated to use file descriptor passing via SCM_RIGHTS, and all handle-based duplication logic is removed. The old ioctl implementation is kept as android_ioctl_old() but is no longer used. This completes the transition away from the legacy backend startup path. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 98 +++++++---------------------------- 1 file changed, 20 insertions(+), 78 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 02ccf2760cd..14fbf4c190b 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -107,7 +107,7 @@ DECL_FUNCPTR( ANativeWindowBuffer_getHardwareBuffer ); #define SYNC_IOC_WAIT _IOW('>', 0, __s32) #endif -static HANDLE thread; +static BOOL in_desktop_process; static JNIEnv *jni_env; static HWND capture_window; static HWND desktop_window; @@ -208,8 +208,6 @@ struct ioctl_android_window_pos_changed struct ioctl_android_dequeueBuffer { struct ioctl_header hdr; - DWORD pid; - HANDLE handle; int buffer_id; int generation; }; @@ -271,13 +269,7 @@ 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 */ +#if 0 /* 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) ); } @@ -292,7 +284,7 @@ static inline void init_java_thread( JavaVM *java_vm ) __asm__( "mov %0,%%fs" :: "r" (orig_fs) ); } -#elif defined(__x86_64__) +#elif 0 #include <asm/prctl.h> #include <asm/unistd.h> @@ -730,7 +722,6 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, 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); @@ -755,15 +746,10 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, 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) { @@ -777,37 +763,16 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, 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 ); @@ -1110,24 +1075,11 @@ NTSTATUS android_dispatch_ioctl( void *arg ) NTSTATUS android_java_init( void *arg ) { - JavaVM *java_vm; - - if (!(java_vm = *p_java_vm)) return STATUS_UNSUCCESSFUL; /* not running under Java */ - - init_java_thread( java_vm ); - create_desktop_view(); - return STATUS_SUCCESS; + return STATUS_UNSUCCESSFUL; } NTSTATUS android_java_uninit( void *arg ) { - JavaVM *java_vm; - - if (!(java_vm = *p_java_vm)) return STATUS_UNSUCCESSFUL; /* not running under Java */ - - wrap_java_call(); - (*java_vm)->DetachCurrentThread( java_vm ); - unwrap_java_call(); return STATUS_SUCCESS; } @@ -1137,6 +1089,7 @@ static void *ioctl_thread_proc(void *arg) int listen_fd, epoll_fd; if (!(java_vm = *p_java_vm)) return NULL; /* not running under Java */ + in_desktop_process = TRUE; init_java_thread( java_vm ); create_desktop_view(); @@ -1286,18 +1239,17 @@ static void *ioctl_thread_proc(void *arg) void start_android_device(void) { - void *ret_ptr; - ULONG ret_len; - struct dispatch_callback_params params = {.callback = start_device_callback}; - if (KeUserDispatchCallback( ¶ms, sizeof(params), &ret_ptr, &ret_len )) return; - if (ret_len == sizeof(thread)) thread = *(HANDLE *)ret_ptr; + pthread_t t; + + if (pthread_create( &t, NULL, ioctl_thread_proc, NULL ) == 0) + pthread_detach( t ); } /* Client-side ioctl support */ -static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *recv_fd ) +static int android_ioctl_old( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *recv_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; @@ -1333,7 +1285,7 @@ static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void return status_to_android_error( status ); } -static int android_ioctl_new( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *recv_fd ) +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; @@ -1410,35 +1362,25 @@ 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( 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) @@ -1817,7 +1759,7 @@ int ioctl_set_cursor( int id, int width, int height, */ void ANDROID_SetDesktopWindow( HWND hwnd ) { - if (!is_in_desktop_process()) + if (!in_desktop_process) return; TRACE( "%p\n", hwnd ); desktop_window = hwnd; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Remove the legacy unixlib-based ioctl backend and related plumbing. This drops android_dispatch_ioctl, android_java_init/uninit, the KeUserDispatchCallback startup path, and the associated ntoskrnl driver integration. The unixlib interface is reduced to a single init entry point, and DllMain is simplified accordingly. All ioctl handling is now performed exclusively via the socket-based backend introduced earlier. This completes the removal of the legacy ioctl transport and associated Wine-specific execution context handling. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 7 -- dlls/wineandroid.drv/device.c | 168 +-------------------------------- dlls/wineandroid.drv/dllmain.c | 74 +-------------- dlls/wineandroid.drv/init.c | 7 -- dlls/wineandroid.drv/unixlib.h | 11 --- 5 files changed, 2 insertions(+), 265 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 077d11ae7c9..9ccbc92ee11 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -100,13 +100,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; diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 14fbf4c190b..7757237f720 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -107,7 +107,6 @@ DECL_FUNCPTR( ANativeWindowBuffer_getHardwareBuffer ); #define SYNC_IOC_WAIT _IOW('>', 0, __s32) #endif -static BOOL in_desktop_process; static JNIEnv *jni_env; static HWND capture_window; static HWND desktop_window; @@ -269,43 +268,6 @@ struct ioctl_android_set_cursor int bits[1]; }; -#if 0 /* 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 ) -{ - java_fs = *p_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 ); - if (!*p_java_gdt_sel) __asm__( "mov %%fs,%0" : "=r" (java_fs) ); - __asm__( "mov %0,%%fs" :: "r" (orig_fs) ); -} - -#elif 0 - -#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 ) -{ - arch_prctl( ARCH_GET_GS, &orig_teb ); - (*java_vm)->AttachCurrentThread( java_vm, &jni_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 ) { (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); } -#endif /* __i386__ */ - static struct native_win_data *data_map[65536]; static unsigned int data_map_idx( HWND hwnd, BOOL opengl ) @@ -614,10 +576,8 @@ static jobject load_java_method( jmethodID *method, const char *name, const char { jclass class; - wrap_java_call(); class = (*jni_env)->GetObjectClass( jni_env, object ); *method = (*jni_env)->GetMethodID( jni_env, class, name, args ); - unwrap_java_call(); if (!*method) { _FIXME( "method %s not found\n", name ); @@ -634,9 +594,7 @@ static void create_desktop_view(void) if (!(object = load_java_method( &method, "createDesktopView", "()V" ))) return; - wrap_java_call(); (*jni_env)->CallVoidMethod( jni_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 ) @@ -655,9 +613,7 @@ static NTSTATUS createWindow_ioctl( void *data, DWORD in_size, DWORD out_size, U if (!(object = load_java_method( &method, "createWindow", "(IZZIF)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, res->scale ); - unwrap_java_call(); return STATUS_SUCCESS; } @@ -676,9 +632,7 @@ static NTSTATUS destroyWindow_ioctl( void *data, DWORD in_size, DWORD out_size, if (!(object = load_java_method( &method, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd ); - unwrap_java_call(); if (win_data) free_native_win_data( win_data ); return STATUS_SUCCESS; } @@ -698,12 +652,10 @@ static NTSTATUS windowPosChanged_ioctl( void *data, DWORD in_size, DWORD out_siz if (!(object = load_java_method( &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 ); - unwrap_java_call(); return STATUS_SUCCESS; } @@ -726,9 +678,7 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, 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 ); @@ -796,9 +746,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 ); - wrap_java_call(); ret = parent->cancelBuffer( parent, buffer, -1 ); - unwrap_java_call(); return android_error_to_status( ret ); } @@ -819,9 +767,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 ); - wrap_java_call(); ret = parent->queueBuffer( parent, buffer, -1 ); - unwrap_java_call(); return android_error_to_status( ret ); } @@ -839,9 +785,7 @@ static NTSTATUS query_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PT 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 ); } @@ -860,57 +804,39 @@ static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_ 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: { @@ -919,9 +845,7 @@ static NTSTATUS perform_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_ 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: @@ -945,9 +869,7 @@ static NTSTATUS setSwapInterval_ioctl( void *data, DWORD in_size, DWORD out_size 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 ); } @@ -966,9 +888,7 @@ static NTSTATUS setWindowParent_ioctl( void *data, DWORD in_size, DWORD out_size if (!(object = load_java_method( &method, "setParent", "(IIF)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); (*jni_env)->CallVoidMethod( jni_env, object, method, res->hdr.hwnd, res->parent, res->scale ); - unwrap_java_call(); return STATUS_SUCCESS; } @@ -1007,8 +927,6 @@ static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULON if (!(object = load_java_method( &method, "setCursor", "(IIIII[I)V" ))) return STATUS_NOT_SUPPORTED; - wrap_java_call(); - if (size) { jintArray array = (*jni_env)->NewIntArray( jni_env, size ); @@ -1019,8 +937,6 @@ static NTSTATUS setCursor_ioctl( void *data, DWORD in_size, DWORD out_size, ULON } else (*jni_env)->CallVoidMethod( jni_env, object, method, res->id, 0, 0, 0, 0, 0 ); - unwrap_java_call(); - return STATUS_SUCCESS; } @@ -1041,56 +957,13 @@ 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]; - int reply_fd = -1; - - 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, &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 ) -{ - return STATUS_UNSUCCESSFUL; -} - -NTSTATUS android_java_uninit( void *arg ) -{ - return STATUS_SUCCESS; -} - static void *ioctl_thread_proc(void *arg) { JavaVM *java_vm; int listen_fd, epoll_fd; if (!(java_vm = *p_java_vm)) return NULL; /* not running under Java */ - in_desktop_process = TRUE; - init_java_thread( java_vm ); + (*java_vm)->AttachCurrentThread( java_vm, &jni_env, 0 ); create_desktop_view(); listen_fd = socket( AF_UNIX, SOCK_SEQPACKET, 0 ); @@ -1249,42 +1122,6 @@ void start_android_device(void) /* Client-side ioctl support */ -static int android_ioctl_old( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size, int *recv_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 ); - } - - if (recv_fd) *recv_fd = -1; - - 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; @@ -1759,8 +1596,5 @@ int ioctl_set_cursor( int id, int width, int height, */ void ANDROID_SetDesktopWindow( HWND hwnd ) { - if (!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 d1775c4f4e4..bbf546c9552 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -19,89 +19,17 @@ */ #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 ); -} - /*********************************************************************** * 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.start_device_callback = (UINT_PTR)android_start_device; - return !ANDROID_CALL( init, ¶ms ); + return !__wine_init_unix_call() && !WINE_UNIX_CALL( unix_init, NULL ); } diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index f4faaca2216..14f4596e331 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -369,7 +369,6 @@ unsigned short *p_java_gdt_sel = NULL; static HRESULT android_init( void *arg ) { - struct init_params *params = arg; pthread_mutexattr_t attr; jclass class; jobject object; @@ -393,8 +392,6 @@ static HRESULT android_init( void *arg ) pthread_mutex_init( &win_data_mutex, &attr ); pthread_mutexattr_destroy( &attr ); - start_device_callback = params->start_device_callback; - if ((java_vm = *p_java_vm)) /* running under Java */ { #ifdef __i386__ @@ -417,11 +414,7 @@ static HRESULT android_init( void *arg ) 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 index bc15911ebd9..ec11eb67d18 100644 --- a/dlls/wineandroid.drv/unixlib.h +++ b/dlls/wineandroid.drv/unixlib.h @@ -21,17 +21,6 @@ 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 ) - -/* android_init params */ -struct init_params -{ - UINT64 start_device_callback; -}; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10569
I'm trying to add an additional Unix-side .so build to `dlls/wineandroid.drv` (for `dlopen`ing inside activity), and I'm not sure what the correct approach is within the Wine build system. From what I can tell, each `Makefile.in` only supports a single `UNIXLIB`. Also, since this directory uses a nonstandard `Makefile.in` processed by custom makedep logic, it doesn't seem possible to define extra independent targets. `SUBDIRS` doesn't appear to be supported here either. I also tried adding another "dll" without `MODULE`, just defining an `UNIXLIB`, but it still ends up linking against `ntdll.so` automatically, which is not what I want. What I need is a simple standalone `.so`, not tied to Wine's usual module/unixlib assumptions. I would prefer not to introduce ndk-build or CMake for this, and I'm also unsure what the correct way would be to define and especially install such an additional artifact within the existing build system. What is the recommended way to add an extra `.so` in this case? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569#note_135137
I'd suggest to find another way. If there's really a need for a library unrelated to Wine (why?), that should probably be part of the packaging script. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569#note_135139
Thanks for the suggestion. The main reason for building this .so within the Wine build system is to have build-time validation and to avoid relying on the `LD_LIBRARY_PATH` hack, since in practice it relies on hidden linker APIs which are not part of the public contract, are unstable across Android releases, and may break unexpectedly. As mentioned in the PR, the goal here is to separate Wine from the JVM/activity process. This helps avoid both: * JVM-imposed restrictions (for example seccomp), * and ABI conflicts (like the register clobbering issue that required `wrap_java_call`). This is meant to avoid both existing and potential future issues in that area. Also, this is roughly the approach used by projects like Termux Wine setups, GameHub, GameNative, and Winlator, where Wine runs outside of the JVM context. That seems to be why they don't run into the same ABI and seccomp-related problems. Given that context, is there a recommended way to integrate such a .so into the build, or is packaging still considered the only acceptable approach? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569#note_135147
It's hard to tell without seeing the code, but I'd suggest to keep the existing approach of doing that sort of things in ntdll.so. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569#note_135148
I did try keeping this inside ntdll.so, but when testing on Android 10 I ran into a SIGSYS caused by a `modify_ldt` syscall being blocked by seccomp. This suggests that on newer Android versions this approach may run into restrictions from the system sandbox. I wasn’t able to find a reliable workaround for that issue, so it makes me a bit concerned that similar seccomp-related limitations could affect other parts as well. That’s part of why I’m exploring splitting this out instead of keeping running `explorer.exe /desktop=shell` inside of activity. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569#note_135155
One more detail regarding this. Since I couldn't find a viable replacement for modify_ldt (or confirm whether one exists at all on Android), I wasn't able to fully evaluate what other syscalls might be restricted in the same way. From testing, it also appears that these seccomp restrictions do not apply to processes started via execve (i.e. they are not inherited), which is part of why I'm considering that approach as a more robust alternative. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569#note_135157
It looks like I may be able to avoid the LD_LIBRARY_PATH workaround by explicitly loading ``` System.load(dlldir.toString() + get_so_dir(wine_abi) + "/ntdll.so"); System.load(dlldir.toString() + get_so_dir(wine_abi) + "/win32u.so"); System.load(dlldir.toString() + get_so_dir(wine_abi) + "/wineandroid.so"); ``` from Java first. That should let me reach the JNI_OnLoad of wineandroid.so without depending on linker search path hacks. From the JNI entry points, I should then be able to do a fork+execve of the normal wine/wine-preloader process, which would no longer be subject to the same seccomp issues. In that model, this would become a more standard Wine instance that talks to a server, similar in spirit to winex11 or winewayland, except that the server side would now live inside the activity process. Assuming this MR is accepted in principle, that is the direction I intend to continue exploring. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10569#note_135161
participants (3)
-
Alexandre Julliard (@julliard) -
Twaik Yont -
Twaik Yont (@twaik)