2 * Android driver initialisation functions
4 * Copyright 1996, 2013, 2017 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSSTRUCT
22 #define NONAMELESSUNION
34 #include "wine/server.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(android
);
39 unsigned int screen_width
= 0;
40 unsigned int screen_height
= 0;
41 RECT virtual_screen_rect
= { 0, 0, 0, 0 };
43 static const unsigned int screen_bpp
= 32; /* we don't support other modes */
45 static RECT monitor_rc_work
;
46 static int device_init_done
;
47 static BOOL force_display_devices_refresh
;
51 struct gdi_physdev dev
;
54 static const struct user_driver_funcs android_drv_funcs
;
57 /******************************************************************************
60 void init_monitors( int width
, int height
)
62 static const WCHAR trayW
[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
64 HWND hwnd
= FindWindowW( trayW
, NULL
);
66 virtual_screen_rect
.right
= width
;
67 virtual_screen_rect
.bottom
= height
;
68 monitor_rc_work
= virtual_screen_rect
;
70 if (!hwnd
|| !IsWindowVisible( hwnd
)) return;
71 if (!GetWindowRect( hwnd
, &rect
)) return;
72 if (rect
.top
) monitor_rc_work
.bottom
= rect
.top
;
73 else monitor_rc_work
.top
= rect
.bottom
;
74 TRACE( "found tray %p %s work area %s\n", hwnd
,
75 wine_dbgstr_rect( &rect
), wine_dbgstr_rect( &monitor_rc_work
));
77 if (*p_java_vm
) /* if we're notified from Java thread, update registry */
79 UINT32 num_path
, num_mode
;
80 force_display_devices_refresh
= TRUE
;
81 /* trigger refresh in win32u */
82 NtUserGetDisplayConfigBufferSizes( QDC_ONLY_ACTIVE_PATHS
, &num_path
, &num_mode
);
87 /******************************************************************************
90 void set_screen_dpi( DWORD dpi
)
92 static const WCHAR dpi_key_name
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s',0};
93 static const WCHAR dpi_value_name
[] = {'L','o','g','P','i','x','e','l','s',0};
96 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG
, dpi_key_name
, &hkey
))
98 RegSetValueExW( hkey
, dpi_value_name
, 0, REG_DWORD
, (void *)&dpi
, sizeof(DWORD
) );
103 /**********************************************************************
104 * fetch_display_metrics
106 static void fetch_display_metrics(void)
108 if (*p_java_vm
) return; /* for Java threads it will be set when the top view is created */
110 SERVER_START_REQ( get_window_rectangles
)
112 req
->handle
= wine_server_user_handle( GetDesktopWindow() );
113 req
->relative
= COORDS_CLIENT
;
114 if (!wine_server_call( req
))
116 screen_width
= reply
->window
.right
;
117 screen_height
= reply
->window
.bottom
;
122 init_monitors( screen_width
, screen_height
);
123 TRACE( "screen %ux%u\n", screen_width
, screen_height
);
127 /**********************************************************************
130 * Perform initializations needed upon creation of the first device.
132 static void device_init(void)
134 device_init_done
= TRUE
;
135 fetch_display_metrics();
139 /******************************************************************************
140 * create_android_physdev
142 static ANDROID_PDEVICE
*create_android_physdev(void)
144 ANDROID_PDEVICE
*physdev
;
146 if (!device_init_done
) device_init();
148 if (!(physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) ))) return NULL
;
152 /**********************************************************************
155 static BOOL CDECL
ANDROID_CreateDC( PHYSDEV
*pdev
, LPCWSTR device
, LPCWSTR output
,
156 const DEVMODEW
*initData
)
158 ANDROID_PDEVICE
*physdev
= create_android_physdev();
160 if (!physdev
) return FALSE
;
162 push_dc_driver( pdev
, &physdev
->dev
, &android_drv_funcs
.dc_funcs
);
167 /**********************************************************************
168 * ANDROID_CreateCompatibleDC
170 static BOOL CDECL
ANDROID_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
172 ANDROID_PDEVICE
*physdev
= create_android_physdev();
174 if (!physdev
) return FALSE
;
176 push_dc_driver( pdev
, &physdev
->dev
, &android_drv_funcs
.dc_funcs
);
181 /**********************************************************************
184 static BOOL CDECL
ANDROID_DeleteDC( PHYSDEV dev
)
186 HeapFree( GetProcessHeap(), 0, dev
);
191 /***********************************************************************
192 * ANDROID_ChangeDisplaySettingsEx
194 LONG
ANDROID_ChangeDisplaySettingsEx( LPCWSTR devname
, LPDEVMODEW devmode
,
195 HWND hwnd
, DWORD flags
, LPVOID lpvoid
)
197 FIXME( "(%s,%p,%p,0x%08x,%p)\n", debugstr_w( devname
), devmode
, hwnd
, flags
, lpvoid
);
198 return DISP_CHANGE_SUCCESSFUL
;
202 /***********************************************************************
203 * ANDROID_UpdateDisplayDevices
205 void ANDROID_UpdateDisplayDevices( const struct gdi_device_manager
*device_manager
,
206 BOOL force
, void *param
)
208 if (force
|| force_display_devices_refresh
)
210 struct gdi_monitor gdi_monitor
=
212 .rc_monitor
= virtual_screen_rect
,
213 .rc_work
= monitor_rc_work
,
214 .state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
216 device_manager
->add_monitor( &gdi_monitor
, param
);
217 force_display_devices_refresh
= FALSE
;
222 /***********************************************************************
223 * ANDROID_EnumDisplaySettingsEx
225 BOOL
ANDROID_EnumDisplaySettingsEx( LPCWSTR name
, DWORD n
, LPDEVMODEW devmode
, DWORD flags
)
227 static const WCHAR dev_name
[CCHDEVICENAME
] =
228 { 'W','i','n','e',' ','A','n','d','r','o','i','d',' ','d','r','i','v','e','r',0 };
230 devmode
->dmSize
= offsetof( DEVMODEW
, dmICMMethod
);
231 devmode
->dmSpecVersion
= DM_SPECVERSION
;
232 devmode
->dmDriverVersion
= DM_SPECVERSION
;
233 memcpy( devmode
->dmDeviceName
, dev_name
, sizeof(dev_name
) );
234 devmode
->dmDriverExtra
= 0;
235 devmode
->u2
.dmDisplayFlags
= 0;
236 devmode
->dmDisplayFrequency
= 0;
237 devmode
->u1
.s2
.dmPosition
.x
= 0;
238 devmode
->u1
.s2
.dmPosition
.y
= 0;
239 devmode
->u1
.s2
.dmDisplayOrientation
= 0;
240 devmode
->u1
.s2
.dmDisplayFixedOutput
= 0;
242 if (n
== ENUM_CURRENT_SETTINGS
|| n
== ENUM_REGISTRY_SETTINGS
) n
= 0;
245 devmode
->dmPelsWidth
= screen_width
;
246 devmode
->dmPelsHeight
= screen_height
;
247 devmode
->dmBitsPerPel
= screen_bpp
;
248 devmode
->dmDisplayFrequency
= 60;
249 devmode
->dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
;
250 TRACE( "mode %d -- %dx%d %d bpp @%d Hz\n", n
,
251 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
,
252 devmode
->dmBitsPerPel
, devmode
->dmDisplayFrequency
);
255 TRACE( "mode %d -- not present\n", n
);
256 SetLastError( ERROR_NO_MORE_FILES
);
261 /**********************************************************************
262 * ANDROID_wine_get_wgl_driver
264 static struct opengl_funcs
*ANDROID_wine_get_wgl_driver( UINT version
)
266 return get_wgl_driver( version
);
270 static const struct user_driver_funcs android_drv_funcs
=
272 .dc_funcs
.pCreateCompatibleDC
= ANDROID_CreateCompatibleDC
,
273 .dc_funcs
.pCreateDC
= ANDROID_CreateDC
,
274 .dc_funcs
.pDeleteDC
= ANDROID_DeleteDC
,
275 .dc_funcs
.priority
= GDI_PRIORITY_GRAPHICS_DRV
,
277 .pGetKeyNameText
= ANDROID_GetKeyNameText
,
278 .pMapVirtualKeyEx
= ANDROID_MapVirtualKeyEx
,
279 .pVkKeyScanEx
= ANDROID_VkKeyScanEx
,
280 .pSetCursor
= ANDROID_SetCursor
,
281 .pChangeDisplaySettingsEx
= ANDROID_ChangeDisplaySettingsEx
,
282 .pEnumDisplaySettingsEx
= ANDROID_EnumDisplaySettingsEx
,
283 .pUpdateDisplayDevices
= ANDROID_UpdateDisplayDevices
,
284 .pCreateWindow
= ANDROID_CreateWindow
,
285 .pDestroyWindow
= ANDROID_DestroyWindow
,
286 .pMsgWaitForMultipleObjectsEx
= ANDROID_MsgWaitForMultipleObjectsEx
,
287 .pSetCapture
= ANDROID_SetCapture
,
288 .pSetLayeredWindowAttributes
= ANDROID_SetLayeredWindowAttributes
,
289 .pSetParent
= ANDROID_SetParent
,
290 .pSetWindowRgn
= ANDROID_SetWindowRgn
,
291 .pSetWindowStyle
= ANDROID_SetWindowStyle
,
292 .pShowWindow
= ANDROID_ShowWindow
,
293 .pUpdateLayeredWindow
= ANDROID_UpdateLayeredWindow
,
294 .pWindowMessage
= ANDROID_WindowMessage
,
295 .pWindowPosChanging
= ANDROID_WindowPosChanging
,
296 .pWindowPosChanged
= ANDROID_WindowPosChanged
,
297 .pwine_get_wgl_driver
= ANDROID_wine_get_wgl_driver
,
301 static const JNINativeMethod methods
[] =
303 { "wine_desktop_changed", "(II)V", desktop_changed
},
304 { "wine_config_changed", "(I)V", config_changed
},
305 { "wine_surface_changed", "(ILandroid/view/Surface;Z)V", surface_changed
},
306 { "wine_motion_event", "(IIIIII)Z", motion_event
},
307 { "wine_keyboard_event", "(IIII)Z", keyboard_event
},
310 #define DECL_FUNCPTR(f) typeof(f) * p##f = NULL
311 #define LOAD_FUNCPTR(lib, func) do { \
312 if ((p##func = dlsym( lib, #func )) == NULL) \
313 { ERR( "can't find symbol %s\n", #func); return; } \
316 DECL_FUNCPTR( __android_log_print
);
317 DECL_FUNCPTR( ANativeWindow_fromSurface
);
318 DECL_FUNCPTR( ANativeWindow_release
);
319 DECL_FUNCPTR( hw_get_module
);
322 #define DT_GNU_HASH 0x6ffffef5
325 static unsigned int gnu_hash( const char *name
)
327 unsigned int h
= 5381;
328 while (*name
) h
= h
* 33 + (unsigned char)*name
++;
332 static unsigned int hash_symbol( const char *name
)
334 unsigned int hi
, hash
= 0;
337 hash
= (hash
<< 4) + (unsigned char)*name
++;
338 hi
= hash
& 0xf0000000;
345 static void *find_symbol( const struct dl_phdr_info
* info
, const char *var
, int type
)
347 const ElfW(Dyn
) *dyn
= NULL
;
348 const ElfW(Phdr
) *ph
;
349 const ElfW(Sym
) *symtab
= NULL
;
350 const Elf32_Word
*hashtab
= NULL
;
351 const Elf32_Word
*gnu_hashtab
= NULL
;
352 const char *strings
= NULL
;
355 for (ph
= info
->dlpi_phdr
; ph
< &info
->dlpi_phdr
[info
->dlpi_phnum
]; ++ph
)
357 if (PT_DYNAMIC
== ph
->p_type
)
359 dyn
= (const ElfW(Dyn
) *)(info
->dlpi_addr
+ ph
->p_vaddr
);
363 if (!dyn
) return NULL
;
367 if (dyn
->d_tag
== DT_STRTAB
)
368 strings
= (const char*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
369 if (dyn
->d_tag
== DT_SYMTAB
)
370 symtab
= (const ElfW(Sym
) *)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
371 if (dyn
->d_tag
== DT_HASH
)
372 hashtab
= (const Elf32_Word
*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
373 if (dyn
->d_tag
== DT_GNU_HASH
)
374 gnu_hashtab
= (const Elf32_Word
*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
378 if (!symtab
|| !strings
) return NULL
;
380 if (gnu_hashtab
) /* new style hash table */
382 const unsigned int hash
= gnu_hash(var
);
383 const Elf32_Word nbuckets
= gnu_hashtab
[0];
384 const Elf32_Word symbias
= gnu_hashtab
[1];
385 const Elf32_Word nwords
= gnu_hashtab
[2];
386 const ElfW(Addr
) *bitmask
= (const ElfW(Addr
) *)(gnu_hashtab
+ 4);
387 const Elf32_Word
*buckets
= (const Elf32_Word
*)(bitmask
+ nwords
);
388 const Elf32_Word
*chains
= buckets
+ nbuckets
- symbias
;
390 if (!(idx
= buckets
[hash
% nbuckets
])) return NULL
;
393 if ((chains
[idx
] & ~1u) == (hash
& ~1u) &&
394 ELF32_ST_BIND(symtab
[idx
].st_info
) == STB_GLOBAL
&&
395 ELF32_ST_TYPE(symtab
[idx
].st_info
) == type
&&
396 !strcmp( strings
+ symtab
[idx
].st_name
, var
))
397 return (void *)(info
->dlpi_addr
+ symtab
[idx
].st_value
);
398 } while (!(chains
[idx
++] & 1u));
400 else if (hashtab
) /* old style hash table */
402 const unsigned int hash
= hash_symbol( var
);
403 const Elf32_Word nbuckets
= hashtab
[0];
404 const Elf32_Word
*buckets
= hashtab
+ 2;
405 const Elf32_Word
*chains
= buckets
+ nbuckets
;
407 for (idx
= buckets
[hash
% nbuckets
]; idx
; idx
= chains
[idx
])
409 if (ELF32_ST_BIND(symtab
[idx
].st_info
) == STB_GLOBAL
&&
410 ELF32_ST_TYPE(symtab
[idx
].st_info
) == type
&&
411 !strcmp( strings
+ symtab
[idx
].st_name
, var
))
412 return (void *)(info
->dlpi_addr
+ symtab
[idx
].st_value
);
418 static int enum_libs( struct dl_phdr_info
* info
, size_t size
, void* data
)
422 if (!info
->dlpi_name
) return 0;
423 if (!(p
= strrchr( info
->dlpi_name
, '/' ))) return 0;
424 if (strcmp( p
, "/libhardware.so" )) return 0;
425 TRACE( "found libhardware at %p\n", info
->dlpi_phdr
);
426 phw_get_module
= find_symbol( info
, "hw_get_module", STT_FUNC
);
430 static void load_hardware_libs(void)
432 const struct hw_module_t
*module
;
436 if ((libhardware
= dlopen( "libhardware.so", RTLD_GLOBAL
)))
438 LOAD_FUNCPTR( libhardware
, hw_get_module
);
442 /* Android >= N disallows loading libhardware, so we load libandroid (which imports
443 * libhardware), and then we can find libhardware in the list of loaded libraries.
445 if (!dlopen( "libandroid.so", RTLD_GLOBAL
))
447 ERR( "failed to load libandroid.so: %s\n", dlerror() );
450 dl_iterate_phdr( enum_libs
, 0 );
453 ERR( "failed to find hw_get_module\n" );
458 if ((ret
= phw_get_module( GRALLOC_HARDWARE_MODULE_ID
, &module
)))
460 ERR( "failed to load gralloc module err %d\n", ret
);
464 init_gralloc( module
);
467 static void load_android_libs(void)
469 void *libandroid
, *liblog
;
471 if (!(libandroid
= dlopen( "libandroid.so", RTLD_GLOBAL
)))
473 ERR( "failed to load libandroid.so: %s\n", dlerror() );
476 if (!(liblog
= dlopen( "liblog.so", RTLD_GLOBAL
)))
478 ERR( "failed to load liblog.so: %s\n", dlerror() );
481 LOAD_FUNCPTR( liblog
, __android_log_print
);
482 LOAD_FUNCPTR( libandroid
, ANativeWindow_fromSurface
);
483 LOAD_FUNCPTR( libandroid
, ANativeWindow_release
);
489 JavaVM
**p_java_vm
= NULL
;
490 jobject
*p_java_object
= NULL
;
491 unsigned short *p_java_gdt_sel
= NULL
;
493 static BOOL
process_attach(void)
501 if (!(ntdll
= dlopen( "ntdll.so", RTLD_NOW
))) return FALSE
;
503 p_java_vm
= dlsym( ntdll
, "java_vm" );
504 p_java_object
= dlsym( ntdll
, "java_object" );
505 p_java_gdt_sel
= dlsym( ntdll
, "java_gdt_sel" );
507 object
= *p_java_object
;
509 load_hardware_libs();
511 if ((java_vm
= *p_java_vm
)) /* running under Java */
515 __asm__( "mov %%fs,%0" : "=r" (old_fs
) );
518 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
519 class = (*jni_env
)->GetObjectClass( jni_env
, object
);
520 (*jni_env
)->RegisterNatives( jni_env
, class, methods
, ARRAY_SIZE( methods
));
521 (*jni_env
)->DeleteLocalRef( jni_env
, class );
523 /* the Java VM hijacks %fs for its own purposes, restore it */
524 __asm__( "mov %0,%%fs" :: "r" (old_fs
) );
527 __wine_set_user_driver( &android_drv_funcs
, WINE_GDI_DRIVER_VERSION
);
531 /***********************************************************************
532 * dll initialisation routine
534 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, LPVOID reserved
)
538 case DLL_PROCESS_ATTACH
:
539 DisableThreadLibraryCalls( inst
);
540 return process_attach();