[PATCH v5 0/9] MR9977: wineandroid: Fix build issues and early runtime regressions on modern Android toolchains
This merge request contains a set of incremental Android-specific fixes aimed at restoring buildability and removing several early runtime regressions when building Wine with modern Android NDK toolchains. The changes are intentionally minimal and focused on correctness and cleanup rather than adding new functionality. Build-related fixes: - Fix missing ffs() declaration by including <strings.h>. - Fix mismatched ANDROID_WindowPosChanged prototype. - Remove leftover drawable_mutex declarations after OpenGL refactoring. - Avoid unsupported pthread mutex attributes on Android. - Export Java-related globals to ensure they remain visible for dlsym with newer NDKs. - Force --rosegment for wine-preloader when supported to avoid excessive ELF size. Runtime-related fixes: - Fix WineAndroid device access by switching to a consistent \Device\WineAndroid path and aligning driver/device object creation. - Fix start_device_callback assignment type to match expected storage. Status: These changes improve build reliability and eliminate some immediate runtime failures, but they do not make wineandroid fully functional yet. This MR is part of an ongoing bring-up effort for modern Android versions and focuses on getting the simplest pieces building and initializing correctly before further functional work. P.S. I am not intending to post further changes until this MR is being merged. These changes are pretty much simple but fundamental for future changes. -- v5: wineandroid: force --rosegment for wine-preloader wineandroid: Fix WineAndroid device access path ntdll: Export Java globals for dlsym lookup winepulse: Do not use pthread mutex attributes on Android win32u: Fix wineandroid build after OpenGL drawable refactoring wineandroid: Fix start_device_callback assignment type https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> ffs() is used in unix_private.h without a visible prototype, which causes build failures with compilers enforcing ISO C99 or later rules. Include <strings.h> to ensure ffs() is properly declared. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/ntdll/unix/unix_private.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 8d77d726a33..8b633dfdd68 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -23,6 +23,7 @@ #include <pthread.h> #include <signal.h> +#include <strings.h> #include "unixlib.h" #include "wine/unixlib.h" #include "wine/server.h" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> The ANDROID_WindowPosChanged prototype in android.h was not updated along with its implementation in e28867deb16579e541397a8e0c90153c94c82b90. Fix the declaration to match the current function signature. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 07c0f9ea7b7..98e5136ec07 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -95,7 +95,7 @@ extern UINT ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ); extern LRESULT ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ); extern BOOL ANDROID_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects ); extern BOOL ANDROID_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface ); -extern void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, BOOL fullscreen, +extern void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, const struct window_rects *new_rects, struct window_surface *surface ); extern ANativeWindow *get_client_window( HWND hwnd ); extern BOOL has_client_surface( HWND hwnd ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Commit 392d6163614065edab50d5d629ff9f145e0a1012 removed the drawable_mutex definition and all its users in the Android OpenGL driver, but left behind the public declaration and initialization. Remove the leftover extern declaration from android.h and the corresponding pthread_mutex_init() call from init.c. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/android.h | 1 - dlls/wineandroid.drv/init.c | 1 - 2 files changed, 2 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 98e5136ec07..1ed83406cff 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -53,7 +53,6 @@ DECL_FUNCPTR( ANativeWindow_release ); * OpenGL driver */ -extern pthread_mutex_t drawable_mutex; extern UINT ANDROID_OpenGLInit( UINT version, const struct opengl_funcs *opengl_funcs, const struct opengl_driver_funcs **driver_funcs ); diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 472de7b8317..9ceacacd51a 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -537,7 +537,6 @@ static HRESULT android_init( void *arg ) pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); - pthread_mutex_init( &drawable_mutex, &attr ); pthread_mutex_init( &win_data_mutex, &attr ); pthread_mutexattr_destroy( &attr ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Newer compilers warn or error when assigning a function pointer to an integer-typed field without an explicit cast. Cast android_start_device when assigning it to start_device_callback to satisfy the expected UINT64 type. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/dllmain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/wineandroid.drv/dllmain.c b/dlls/wineandroid.drv/dllmain.c index c8495d679f9..97655914543 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -123,6 +123,6 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) if (__wine_init_unix_call()) return FALSE; params.register_window_callback = register_window_callback; - params.start_device_callback = android_start_device; + params.start_device_callback = (UINT64) (UINT_PTR) android_start_device; return !ANDROID_CALL( init, ¶ms ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> After commit 7557d83c074a958ea042c3b86e11cd3b5670ec66, the Android OpenGL driver fails to build because set_window_opengl_drawable() is no longer visible. Export set_window_opengl_drawable() on Android to restore the wineandroid.drv build, while keeping the existing internal linkage for non-Android platforms. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/win32u/opengl.c | 2 +- include/wine/opengl_driver.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index 8e5b708a500..2d9b6c757d5 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -1352,7 +1352,7 @@ static int win32u_wglGetPixelFormat( HDC hdc ) return format > 0 ? format : 0; } -static void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable, BOOL current ) +void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *new_drawable, BOOL current ) { struct opengl_drawable *old_drawable = NULL; WND *win; diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index f740303f4de..7f21430f121 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -209,6 +209,8 @@ W32KAPI void *opengl_drawable_create( UINT size, const struct opengl_drawable_fu W32KAPI void opengl_drawable_add_ref( struct opengl_drawable *drawable ); W32KAPI void opengl_drawable_release( struct opengl_drawable *drawable ); +W32KAPI void set_window_opengl_drawable( HWND hwnd, struct opengl_drawable *drawable, BOOL current ); + /* interface between win32u and the user drivers */ struct opengl_driver_funcs { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Android only provides pthread_mutexattr_setprotocol() starting with API 28 and does not support robust mutexes. Initialize pulse_mutex without special attributes on Android and keep the existing mutex setup on other platforms. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/winepulse.drv/pulse.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 7c8d872c604..5e90879f80a 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -240,6 +240,7 @@ static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, static NTSTATUS pulse_process_attach(void *args) { +#ifndef __ANDROID__ pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); @@ -248,6 +249,9 @@ static NTSTATUS pulse_process_attach(void *args) if (pthread_mutex_init(&pulse_mutex, &attr) != 0) pthread_mutex_init(&pulse_mutex, NULL); +#else + pthread_mutex_init(&pulse_mutex, NULL); +#endif #ifdef _WIN64 if (NtCurrentTeb()->WowTebOffset) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> The java_vm, java_object and java_gdt_sel globals are looked up via dlsym, but can end up with hidden visibility and therefore missing from the dynamic symbol table. Explicitly export these symbols to ensure they remain visible to dlsym. This appears to be required with newer Android NDK toolchains, likely related to changes in symbol visibility handling (for example Android NDK r22). Reference: https://github.com/android/ndk/wiki/Changelog-r22 Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/ntdll/unix/loader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index c9696fef115..5b765d7a869 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1809,9 +1809,9 @@ static void start_main_thread(void) #define WINE_JAVA_CLASS "org/winehq/wine/WineActivity" #endif -JavaVM *java_vm = NULL; -jobject java_object = 0; -unsigned short java_gdt_sel = 0; +DECLSPEC_EXPORT JavaVM *java_vm = NULL; +DECLSPEC_EXPORT jobject java_object = 0; +DECLSPEC_EXPORT unsigned short java_gdt_sel = 0; /* main Wine initialisation */ static jstring wine_init_jni( JNIEnv *env, jobject obj, jobjectArray cmdline, jobjectArray environment ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Following an earlier change, the \\.\WineAndroid path and the corresponding \??\WineAndroid symbolic link no longer resolved correctly. Open the WineAndroid device directly via \Device\WineAndroid, create the driver and device objects using explicit kernel object names, and update the ioctl path to match. Use RTL_CONSTANT_STRING for allocation-free UNICODE_STRING initialization. Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- dlls/wineandroid.drv/device.c | 5 ++--- dlls/wineandroid.drv/dllmain.c | 17 +++-------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c index 1c7985ca1a5..d936c95b15a 100644 --- a/dlls/wineandroid.drv/device.c +++ b/dlls/wineandroid.drv/device.c @@ -1188,7 +1188,7 @@ void start_android_device(void) static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void *out, DWORD *out_size ) { - static const WCHAR deviceW[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 }; + 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; @@ -1196,12 +1196,11 @@ static int android_ioctl( enum android_ioctl code, void *in, DWORD in_size, void if (!device) { OBJECT_ATTRIBUTES attr; - UNICODE_STRING name; + UNICODE_STRING name = RTL_CONSTANT_STRING( deviceW ); IO_STATUS_BLOCK io; NTSTATUS status; HANDLE file; - RtlInitUnicodeString( &name, deviceW ); 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, diff --git a/dlls/wineandroid.drv/dllmain.c b/dlls/wineandroid.drv/dllmain.c index 97655914543..5e4dbbb7d7b 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -46,28 +46,18 @@ static NTSTATUS WINAPI ioctl_callback( DEVICE_OBJECT *device, IRP *irp ) static NTSTATUS CALLBACK init_android_driver( DRIVER_OBJECT *driver, UNICODE_STRING *name ) { - static const WCHAR device_nameW[] = {'\\','D','e','v','i','c','e','\\','W','i','n','e','A','n','d','r','o','i','d',0 }; - static const WCHAR device_linkW[] = {'\\','?','?','\\','W','i','n','e','A','n','d','r','o','i','d',0 }; - - UNICODE_STRING nameW, linkW; + UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Device\\WineAndroid" ); DEVICE_OBJECT *device; - NTSTATUS status; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ioctl_callback; - RtlInitUnicodeString( &nameW, device_nameW ); - RtlInitUnicodeString( &linkW, device_linkW ); - - if ((status = IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device ))) return status; - return IoCreateSymbolicLink( &linkW, &nameW ); + return IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device ); } static DWORD CALLBACK device_thread( void *arg ) { - static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','W','i','n','e','A','n','d','r','o','i','d',0 }; - HANDLE start_event = arg; - UNICODE_STRING nameW; + UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Driver\\WineAndroid" ); NTSTATUS status; DWORD ret; @@ -75,7 +65,6 @@ static DWORD CALLBACK device_thread( void *arg ) if (ANDROID_CALL( java_init, NULL )) return 0; /* not running under Java */ - RtlInitUnicodeString( &nameW, driver_nameW ); if ((status = IoCreateDriver( &nameW, init_android_driver ))) { FIXME( "failed to create driver error %lx\n", status ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
From: Twaik Yont <9674930+twaik@users.noreply.github.com> Without rosegment the linker may produce an excessively large preloader ELF (around 2GB) due to the resulting segment layout. Enabling rosegment keeps the wine-preloader output size reasonable. Keep this flag limited to wine-preloader to avoid affecting other binaries. Reference: https://github.com/android/ndk/wiki/Changelog-r22 Signed-off-by: Twaik Yont <9674930+twaik@users.noreply.github.com> --- configure | 30 ++++++++++++++++++++++++++++++ configure.ac | 1 + 2 files changed, 31 insertions(+) diff --git a/configure b/configure index 29dbfa40ba1..4ead1e784d3 100755 --- a/configure +++ b/configure @@ -11935,6 +11935,36 @@ then : WINELOADER_LDFLAGS="-Wl,--export-dynamic" fi WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7d400000" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--rosegment" >&5 +printf %s "checking whether the compiler supports -Wl,--rosegment... " >&6; } +if test ${ac_cv_cflags__Wl___rosegment+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_wine_try_cflags_saved=$CFLAGS +CFLAGS="$CFLAGS -Wl,--rosegment" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(int argc, char **argv) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_cflags__Wl___rosegment=yes +else case e in #( + e) ac_cv_cflags__Wl___rosegment=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +CFLAGS=$ac_wine_try_cflags_saved ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___rosegment" >&5 +printf "%s\n" "$ac_cv_cflags__Wl___rosegment" >&6; } +if test "x$ac_cv_cflags__Wl___rosegment" = xyes +then : + WINEPRELOADER_LDFLAGS="$WINEPRELOADER_LDFLAGS -Wl,--rosegment" +fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lGLESv2" >&5 printf %s "checking for -lGLESv2... " >&6; } diff --git a/configure.ac b/configure.ac index da4a0af4a60..5213a94f0e7 100644 --- a/configure.ac +++ b/configure.ac @@ -1001,6 +1001,7 @@ case $host_os in WINE_TRY_CFLAGS([-Wl,-z,defs],[UNIXLDFLAGS="$UNIXLDFLAGS -Wl,-z,defs"]) WINE_TRY_CFLAGS([-fPIC -Wl,--export-dynamic],[WINELOADER_LDFLAGS="-Wl,--export-dynamic"]) WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7d400000" + WINE_TRY_CFLAGS([-Wl,--rosegment], [WINEPRELOADER_LDFLAGS="$WINEPRELOADER_LDFLAGS -Wl,--rosegment"]) WINE_CHECK_SONAME(GLESv2,glFlush) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
On Wed Jan 28 10:44:37 2026 +0000, Twaik Yont wrote:
changed this line in [version 5 of the diff](/wine/wine/-/merge_requests/9977/diffs?diff_id=240736&start_sha=28b4b88eac14ca7c1a74862c6dcf51c4143ab82e#de822bbc033a67408ed1f90c5562be312923946e_115_115) Done.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9977#note_128250
On Wed Jan 28 10:48:54 2026 +0000, Rémi Bernon wrote:
Looks okay to me otherwise, although I don't know much about some of the other changes here. Thanks for taking a look. I attempted to document the individual changes in the commit messages, but please let me know if any part needs further clarification.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9977#note_128252
This merge request was approved by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9977
participants (3)
-
Rémi Bernon (@rbernon) -
Twaik Yont -
Twaik Yont (@twaik)