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
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
35 #define WIN32_NO_STATUS
40 #include "wine/server.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(android
);
45 unsigned int screen_width
= 0;
46 unsigned int screen_height
= 0;
47 RECT virtual_screen_rect
= { 0, 0, 0, 0 };
49 static const unsigned int screen_bpp
= 32; /* we don't support other modes */
51 static RECT monitor_rc_work
;
52 static int device_init_done
;
53 static BOOL force_display_devices_refresh
;
55 PNTAPCFUNC register_window_callback
;
59 struct gdi_physdev dev
;
62 static const struct user_driver_funcs android_drv_funcs
;
65 /******************************************************************************
68 void init_monitors( int width
, int height
)
70 static const WCHAR trayW
[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0};
75 RtlInitUnicodeString( &name
, trayW
);
76 hwnd
= NtUserFindWindowEx( 0, 0, &name
, NULL
, 0 );
78 virtual_screen_rect
.right
= width
;
79 virtual_screen_rect
.bottom
= height
;
80 monitor_rc_work
= virtual_screen_rect
;
82 if (!hwnd
|| !NtUserIsWindowVisible( hwnd
)) return;
83 if (!NtUserGetWindowRect( hwnd
, &rect
)) return;
84 if (rect
.top
) monitor_rc_work
.bottom
= rect
.top
;
85 else monitor_rc_work
.top
= rect
.bottom
;
86 TRACE( "found tray %p %s work area %s\n", hwnd
,
87 wine_dbgstr_rect( &rect
), wine_dbgstr_rect( &monitor_rc_work
));
89 if (*p_java_vm
) /* if we're notified from Java thread, update registry */
91 UINT32 num_path
, num_mode
;
92 force_display_devices_refresh
= TRUE
;
93 /* trigger refresh in win32u */
94 NtUserGetDisplayConfigBufferSizes( QDC_ONLY_ACTIVE_PATHS
, &num_path
, &num_mode
);
99 /* wrapper for NtCreateKey that creates the key recursively if necessary */
100 static HKEY
reg_create_key( const WCHAR
*name
, ULONG name_len
)
102 UNICODE_STRING nameW
= { name_len
, name_len
, (WCHAR
*)name
};
103 OBJECT_ATTRIBUTES attr
;
107 attr
.Length
= sizeof(attr
);
108 attr
.RootDirectory
= 0;
109 attr
.ObjectName
= &nameW
;
111 attr
.SecurityDescriptor
= NULL
;
112 attr
.SecurityQualityOfService
= NULL
;
114 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, 0, NULL
);
115 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
117 static const WCHAR registry_rootW
[] = { '\\','R','e','g','i','s','t','r','y','\\' };
118 DWORD pos
= 0, i
= 0, len
= name_len
/ sizeof(WCHAR
);
120 /* don't try to create registry root */
121 if (len
> ARRAY_SIZE(registry_rootW
) &&
122 !memcmp( name
, registry_rootW
, sizeof(registry_rootW
) ))
123 i
+= ARRAY_SIZE(registry_rootW
);
125 while (i
< len
&& name
[i
] != '\\') i
++;
126 if (i
== len
) return 0;
129 nameW
.Buffer
= (WCHAR
*)name
+ pos
;
130 nameW
.Length
= (i
- pos
) * sizeof(WCHAR
);
131 status
= NtCreateKey( &ret
, MAXIMUM_ALLOWED
, &attr
, 0, NULL
, 0, NULL
);
133 if (attr
.RootDirectory
) NtClose( attr
.RootDirectory
);
134 if (status
) return 0;
136 attr
.RootDirectory
= ret
;
137 while (i
< len
&& name
[i
] == '\\') i
++;
139 while (i
< len
&& name
[i
] != '\\') i
++;
146 /******************************************************************************
149 void set_screen_dpi( DWORD dpi
)
151 static const WCHAR dpi_value_name
[] = {'L','o','g','P','i','x','e','l','s',0};
152 static const WCHAR dpi_key_name
[] =
154 '\\','R','e','g','i','s','t','r','y',
155 '\\','M','a','c','h','i','n','e',
156 '\\','S','y','s','t','e','m',
157 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
158 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
159 '\\','C','u','r','r','e','n','t',
160 '\\','S','o','f','t','w','a','r','e',
161 '\\','F','o','n','t','s'
165 if ((hkey
= reg_create_key( dpi_key_name
, sizeof(dpi_key_name
))))
168 RtlInitUnicodeString( &name
, dpi_value_name
);
169 NtSetValueKey( hkey
, &name
, 0, REG_DWORD
, &dpi
, sizeof(dpi
) );
174 /**********************************************************************
175 * fetch_display_metrics
177 static void fetch_display_metrics(void)
179 if (*p_java_vm
) return; /* for Java threads it will be set when the top view is created */
181 SERVER_START_REQ( get_window_rectangles
)
183 req
->handle
= wine_server_user_handle( NtUserGetDesktopWindow() );
184 req
->relative
= COORDS_CLIENT
;
185 if (!wine_server_call( req
))
187 screen_width
= reply
->window
.right
;
188 screen_height
= reply
->window
.bottom
;
193 init_monitors( screen_width
, screen_height
);
194 TRACE( "screen %ux%u\n", screen_width
, screen_height
);
198 /**********************************************************************
201 * Perform initializations needed upon creation of the first device.
203 static void device_init(void)
205 device_init_done
= TRUE
;
206 fetch_display_metrics();
210 /******************************************************************************
211 * create_android_physdev
213 static ANDROID_PDEVICE
*create_android_physdev(void)
215 ANDROID_PDEVICE
*physdev
;
217 if (!device_init_done
) device_init();
219 if (!(physdev
= calloc( 1, sizeof(*physdev
) ))) return NULL
;
223 /**********************************************************************
226 static BOOL CDECL
ANDROID_CreateDC( PHYSDEV
*pdev
, LPCWSTR device
, LPCWSTR output
,
227 const DEVMODEW
*initData
)
229 ANDROID_PDEVICE
*physdev
= create_android_physdev();
231 if (!physdev
) return FALSE
;
233 push_dc_driver( pdev
, &physdev
->dev
, &android_drv_funcs
.dc_funcs
);
238 /**********************************************************************
239 * ANDROID_CreateCompatibleDC
241 static BOOL CDECL
ANDROID_CreateCompatibleDC( PHYSDEV orig
, PHYSDEV
*pdev
)
243 ANDROID_PDEVICE
*physdev
= create_android_physdev();
245 if (!physdev
) return FALSE
;
247 push_dc_driver( pdev
, &physdev
->dev
, &android_drv_funcs
.dc_funcs
);
252 /**********************************************************************
255 static BOOL CDECL
ANDROID_DeleteDC( PHYSDEV dev
)
262 /***********************************************************************
263 * ANDROID_ChangeDisplaySettings
265 LONG
ANDROID_ChangeDisplaySettings( LPDEVMODEW displays
, HWND hwnd
, DWORD flags
, LPVOID lpvoid
)
267 FIXME( "(%p,%p,0x%08x,%p)\n", displays
, hwnd
, flags
, lpvoid
);
268 return DISP_CHANGE_SUCCESSFUL
;
272 /***********************************************************************
273 * ANDROID_UpdateDisplayDevices
275 BOOL
ANDROID_UpdateDisplayDevices( const struct gdi_device_manager
*device_manager
, BOOL force
, void *param
)
277 if (force
|| force_display_devices_refresh
)
279 static const struct gdi_gpu gpu
;
280 static const struct gdi_adapter adapter
=
282 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
284 struct gdi_monitor gdi_monitor
=
286 .rc_monitor
= virtual_screen_rect
,
287 .rc_work
= monitor_rc_work
,
288 .state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
290 const DEVMODEW mode
=
292 .dmFields
= DM_DISPLAYORIENTATION
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
293 .dmBitsPerPel
= screen_bpp
, .dmPelsWidth
= screen_width
, .dmPelsHeight
= screen_height
, .dmDisplayFrequency
= 60,
295 device_manager
->add_gpu( &gpu
, param
);
296 device_manager
->add_adapter( &adapter
, param
);
297 device_manager
->add_monitor( &gdi_monitor
, param
);
298 device_manager
->add_mode( &mode
, param
);
299 force_display_devices_refresh
= FALSE
;
306 /***********************************************************************
307 * ANDROID_GetCurrentDisplaySettings
309 BOOL
ANDROID_GetCurrentDisplaySettings( LPCWSTR name
, LPDEVMODEW devmode
)
311 devmode
->u2
.dmDisplayFlags
= 0;
312 devmode
->u1
.s2
.dmPosition
.x
= 0;
313 devmode
->u1
.s2
.dmPosition
.y
= 0;
314 devmode
->u1
.s2
.dmDisplayOrientation
= 0;
315 devmode
->u1
.s2
.dmDisplayFixedOutput
= 0;
316 devmode
->dmPelsWidth
= screen_width
;
317 devmode
->dmPelsHeight
= screen_height
;
318 devmode
->dmBitsPerPel
= screen_bpp
;
319 devmode
->dmDisplayFrequency
= 60;
320 devmode
->dmFields
= DM_POSITION
| DM_DISPLAYORIENTATION
| DM_PELSWIDTH
| DM_PELSHEIGHT
|
321 DM_BITSPERPEL
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
;
322 TRACE( "current mode -- %dx%d %d bpp @%d Hz\n",
323 devmode
->dmPelsWidth
, devmode
->dmPelsHeight
,
324 devmode
->dmBitsPerPel
, devmode
->dmDisplayFrequency
);
329 /**********************************************************************
330 * ANDROID_wine_get_wgl_driver
332 static struct opengl_funcs
*ANDROID_wine_get_wgl_driver( UINT version
)
334 return get_wgl_driver( version
);
338 static const struct user_driver_funcs android_drv_funcs
=
340 .dc_funcs
.pCreateCompatibleDC
= ANDROID_CreateCompatibleDC
,
341 .dc_funcs
.pCreateDC
= ANDROID_CreateDC
,
342 .dc_funcs
.pDeleteDC
= ANDROID_DeleteDC
,
343 .dc_funcs
.priority
= GDI_PRIORITY_GRAPHICS_DRV
,
345 .pGetKeyNameText
= ANDROID_GetKeyNameText
,
346 .pMapVirtualKeyEx
= ANDROID_MapVirtualKeyEx
,
347 .pVkKeyScanEx
= ANDROID_VkKeyScanEx
,
348 .pSetCursor
= ANDROID_SetCursor
,
349 .pChangeDisplaySettings
= ANDROID_ChangeDisplaySettings
,
350 .pGetCurrentDisplaySettings
= ANDROID_GetCurrentDisplaySettings
,
351 .pUpdateDisplayDevices
= ANDROID_UpdateDisplayDevices
,
352 .pCreateWindow
= ANDROID_CreateWindow
,
353 .pDesktopWindowProc
= ANDROID_DesktopWindowProc
,
354 .pDestroyWindow
= ANDROID_DestroyWindow
,
355 .pMsgWaitForMultipleObjectsEx
= ANDROID_MsgWaitForMultipleObjectsEx
,
356 .pSetCapture
= ANDROID_SetCapture
,
357 .pSetLayeredWindowAttributes
= ANDROID_SetLayeredWindowAttributes
,
358 .pSetParent
= ANDROID_SetParent
,
359 .pSetWindowRgn
= ANDROID_SetWindowRgn
,
360 .pSetWindowStyle
= ANDROID_SetWindowStyle
,
361 .pShowWindow
= ANDROID_ShowWindow
,
362 .pUpdateLayeredWindow
= ANDROID_UpdateLayeredWindow
,
363 .pWindowMessage
= ANDROID_WindowMessage
,
364 .pWindowPosChanging
= ANDROID_WindowPosChanging
,
365 .pWindowPosChanged
= ANDROID_WindowPosChanged
,
366 .pwine_get_wgl_driver
= ANDROID_wine_get_wgl_driver
,
370 static const JNINativeMethod methods
[] =
372 { "wine_desktop_changed", "(II)V", desktop_changed
},
373 { "wine_config_changed", "(I)V", config_changed
},
374 { "wine_surface_changed", "(ILandroid/view/Surface;Z)V", surface_changed
},
375 { "wine_motion_event", "(IIIIII)Z", motion_event
},
376 { "wine_keyboard_event", "(IIII)Z", keyboard_event
},
379 #define DECL_FUNCPTR(f) typeof(f) * p##f = NULL
380 #define LOAD_FUNCPTR(lib, func) do { \
381 if ((p##func = dlsym( lib, #func )) == NULL) \
382 { ERR( "can't find symbol %s\n", #func); return; } \
385 DECL_FUNCPTR( __android_log_print
);
386 DECL_FUNCPTR( ANativeWindow_fromSurface
);
387 DECL_FUNCPTR( ANativeWindow_release
);
388 DECL_FUNCPTR( hw_get_module
);
391 #define DT_GNU_HASH 0x6ffffef5
394 static unsigned int gnu_hash( const char *name
)
396 unsigned int h
= 5381;
397 while (*name
) h
= h
* 33 + (unsigned char)*name
++;
401 static unsigned int hash_symbol( const char *name
)
403 unsigned int hi
, hash
= 0;
406 hash
= (hash
<< 4) + (unsigned char)*name
++;
407 hi
= hash
& 0xf0000000;
414 static void *find_symbol( const struct dl_phdr_info
* info
, const char *var
, int type
)
416 const ElfW(Dyn
) *dyn
= NULL
;
417 const ElfW(Phdr
) *ph
;
418 const ElfW(Sym
) *symtab
= NULL
;
419 const Elf32_Word
*hashtab
= NULL
;
420 const Elf32_Word
*gnu_hashtab
= NULL
;
421 const char *strings
= NULL
;
424 for (ph
= info
->dlpi_phdr
; ph
< &info
->dlpi_phdr
[info
->dlpi_phnum
]; ++ph
)
426 if (PT_DYNAMIC
== ph
->p_type
)
428 dyn
= (const ElfW(Dyn
) *)(info
->dlpi_addr
+ ph
->p_vaddr
);
432 if (!dyn
) return NULL
;
436 if (dyn
->d_tag
== DT_STRTAB
)
437 strings
= (const char*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
438 if (dyn
->d_tag
== DT_SYMTAB
)
439 symtab
= (const ElfW(Sym
) *)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
440 if (dyn
->d_tag
== DT_HASH
)
441 hashtab
= (const Elf32_Word
*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
442 if (dyn
->d_tag
== DT_GNU_HASH
)
443 gnu_hashtab
= (const Elf32_Word
*)(info
->dlpi_addr
+ dyn
->d_un
.d_ptr
);
447 if (!symtab
|| !strings
) return NULL
;
449 if (gnu_hashtab
) /* new style hash table */
451 const unsigned int hash
= gnu_hash(var
);
452 const Elf32_Word nbuckets
= gnu_hashtab
[0];
453 const Elf32_Word symbias
= gnu_hashtab
[1];
454 const Elf32_Word nwords
= gnu_hashtab
[2];
455 const ElfW(Addr
) *bitmask
= (const ElfW(Addr
) *)(gnu_hashtab
+ 4);
456 const Elf32_Word
*buckets
= (const Elf32_Word
*)(bitmask
+ nwords
);
457 const Elf32_Word
*chains
= buckets
+ nbuckets
- symbias
;
459 if (!(idx
= buckets
[hash
% nbuckets
])) return NULL
;
462 if ((chains
[idx
] & ~1u) == (hash
& ~1u) &&
463 ELF32_ST_BIND(symtab
[idx
].st_info
) == STB_GLOBAL
&&
464 ELF32_ST_TYPE(symtab
[idx
].st_info
) == type
&&
465 !strcmp( strings
+ symtab
[idx
].st_name
, var
))
466 return (void *)(info
->dlpi_addr
+ symtab
[idx
].st_value
);
467 } while (!(chains
[idx
++] & 1u));
469 else if (hashtab
) /* old style hash table */
471 const unsigned int hash
= hash_symbol( var
);
472 const Elf32_Word nbuckets
= hashtab
[0];
473 const Elf32_Word
*buckets
= hashtab
+ 2;
474 const Elf32_Word
*chains
= buckets
+ nbuckets
;
476 for (idx
= buckets
[hash
% nbuckets
]; idx
; idx
= chains
[idx
])
478 if (ELF32_ST_BIND(symtab
[idx
].st_info
) == STB_GLOBAL
&&
479 ELF32_ST_TYPE(symtab
[idx
].st_info
) == type
&&
480 !strcmp( strings
+ symtab
[idx
].st_name
, var
))
481 return (void *)(info
->dlpi_addr
+ symtab
[idx
].st_value
);
487 static int enum_libs( struct dl_phdr_info
* info
, size_t size
, void* data
)
491 if (!info
->dlpi_name
) return 0;
492 if (!(p
= strrchr( info
->dlpi_name
, '/' ))) return 0;
493 if (strcmp( p
, "/libhardware.so" )) return 0;
494 TRACE( "found libhardware at %p\n", info
->dlpi_phdr
);
495 phw_get_module
= find_symbol( info
, "hw_get_module", STT_FUNC
);
499 static void load_hardware_libs(void)
501 const struct hw_module_t
*module
;
505 if ((libhardware
= dlopen( "libhardware.so", RTLD_GLOBAL
)))
507 LOAD_FUNCPTR( libhardware
, hw_get_module
);
511 /* Android >= N disallows loading libhardware, so we load libandroid (which imports
512 * libhardware), and then we can find libhardware in the list of loaded libraries.
514 if (!dlopen( "libandroid.so", RTLD_GLOBAL
))
516 ERR( "failed to load libandroid.so: %s\n", dlerror() );
519 dl_iterate_phdr( enum_libs
, 0 );
522 ERR( "failed to find hw_get_module\n" );
527 if ((ret
= phw_get_module( GRALLOC_HARDWARE_MODULE_ID
, &module
)))
529 ERR( "failed to load gralloc module err %d\n", ret
);
533 init_gralloc( module
);
536 static void load_android_libs(void)
538 void *libandroid
, *liblog
;
540 if (!(libandroid
= dlopen( "libandroid.so", RTLD_GLOBAL
)))
542 ERR( "failed to load libandroid.so: %s\n", dlerror() );
545 if (!(liblog
= dlopen( "liblog.so", RTLD_GLOBAL
)))
547 ERR( "failed to load liblog.so: %s\n", dlerror() );
550 LOAD_FUNCPTR( liblog
, __android_log_print
);
551 LOAD_FUNCPTR( libandroid
, ANativeWindow_fromSurface
);
552 LOAD_FUNCPTR( libandroid
, ANativeWindow_release
);
558 JavaVM
**p_java_vm
= NULL
;
559 jobject
*p_java_object
= NULL
;
560 unsigned short *p_java_gdt_sel
= NULL
;
562 static HRESULT
android_init( void *arg
)
564 struct init_params
*params
= arg
;
565 pthread_mutexattr_t attr
;
572 if (!(ntdll
= dlopen( "ntdll.so", RTLD_NOW
))) return STATUS_UNSUCCESSFUL
;
574 p_java_vm
= dlsym( ntdll
, "java_vm" );
575 p_java_object
= dlsym( ntdll
, "java_object" );
576 p_java_gdt_sel
= dlsym( ntdll
, "java_gdt_sel" );
578 object
= *p_java_object
;
580 load_hardware_libs();
582 pthread_mutexattr_init( &attr
);
583 pthread_mutexattr_settype( &attr
, PTHREAD_MUTEX_RECURSIVE
);
584 pthread_mutex_init( &drawable_mutex
, &attr
);
585 pthread_mutex_init( &win_data_mutex
, &attr
);
586 pthread_mutexattr_destroy( &attr
);
588 register_window_callback
= params
->register_window_callback
;
590 if ((java_vm
= *p_java_vm
)) /* running under Java */
594 __asm__( "mov %%fs,%0" : "=r" (old_fs
) );
597 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
598 class = (*jni_env
)->GetObjectClass( jni_env
, object
);
599 (*jni_env
)->RegisterNatives( jni_env
, class, methods
, ARRAY_SIZE( methods
));
600 (*jni_env
)->DeleteLocalRef( jni_env
, class );
602 /* the Java VM hijacks %fs for its own purposes, restore it */
603 __asm__( "mov %0,%%fs" :: "r" (old_fs
) );
606 __wine_set_user_driver( &android_drv_funcs
, WINE_GDI_DRIVER_VERSION
);
607 return STATUS_SUCCESS
;
610 const unixlib_entry_t __wine_unix_call_funcs
[] =
612 android_create_desktop
,
613 android_dispatch_ioctl
,
617 android_register_window
,
621 C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs
) == unix_funcs_count
);