2 * Android pseudo-device handling
4 * Copyright 2014-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
31 #include <sys/ioctl.h>
35 #define WIN32_NO_STATUS
42 #include "wine/server.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(android
);
48 #define SYNC_IOC_WAIT _IOW('>', 0, __s32)
52 static JNIEnv
*jni_env
;
53 static HWND capture_window
;
55 #define ANDROIDCONTROLTYPE ((ULONG)'A')
56 #define ANDROID_IOCTL(n) CTL_CODE(ANDROIDCONTROLTYPE, n, METHOD_BUFFERED, FILE_READ_ACCESS)
62 IOCTL_WINDOW_POS_CHANGED
,
63 IOCTL_SET_WINDOW_PARENT
,
75 #define NB_CACHED_BUFFERS 4
77 struct native_buffer_wrapper
;
79 /* buffer for storing a variable-size native handle inside an ioctl structure */
80 union native_handle_buffer
82 native_handle_t handle
;
86 /* data about the native window in the context of the Java process */
87 struct native_win_data
89 struct ANativeWindow
*parent
;
90 struct ANativeWindowBuffer
*buffers
[NB_CACHED_BUFFERS
];
91 void *mappings
[NB_CACHED_BUFFERS
];
98 int buffer_lru
[NB_CACHED_BUFFERS
];
101 /* wrapper for a native window in the context of the client (non-Java) process */
102 struct native_win_wrapper
104 struct ANativeWindow win
;
105 struct native_buffer_wrapper
*buffers
[NB_CACHED_BUFFERS
];
106 struct ANativeWindowBuffer
*locked_buffer
;
112 /* wrapper for a native buffer in the context of the client (non-Java) process */
113 struct native_buffer_wrapper
115 struct ANativeWindowBuffer buffer
;
121 union native_handle_buffer native_handle
;
130 struct ioctl_android_create_window
132 struct ioctl_header hdr
;
137 struct ioctl_android_destroy_window
139 struct ioctl_header hdr
;
142 struct ioctl_android_window_pos_changed
144 struct ioctl_header hdr
;
154 struct ioctl_android_dequeueBuffer
156 struct ioctl_header hdr
;
165 union native_handle_buffer native_handle
;
168 struct ioctl_android_queueBuffer
170 struct ioctl_header hdr
;
175 struct ioctl_android_cancelBuffer
177 struct ioctl_header hdr
;
182 struct ioctl_android_query
184 struct ioctl_header hdr
;
189 struct ioctl_android_perform
191 struct ioctl_header hdr
;
196 struct ioctl_android_set_swap_interval
198 struct ioctl_header hdr
;
202 struct ioctl_android_set_window_parent
204 struct ioctl_header hdr
;
209 struct ioctl_android_set_capture
211 struct ioctl_header hdr
;
214 struct ioctl_android_set_cursor
216 struct ioctl_header hdr
;
225 static struct gralloc_module_t
*gralloc_module
;
226 static struct gralloc1_device
*gralloc1_device
;
227 static BOOL gralloc1_caps
[GRALLOC1_LAST_CAPABILITY
+ 1];
229 static gralloc1_error_t (*gralloc1_retain
)( gralloc1_device_t
*device
, buffer_handle_t buffer
);
230 static gralloc1_error_t (*gralloc1_release
)( gralloc1_device_t
*device
, buffer_handle_t buffer
);
231 static gralloc1_error_t (*gralloc1_lock
)( gralloc1_device_t
*device
, buffer_handle_t buffer
,
232 uint64_t producerUsage
, uint64_t consumerUsage
,
233 const gralloc1_rect_t
*accessRegion
, void **outData
,
234 int32_t acquireFence
);
235 static gralloc1_error_t (*gralloc1_unlock
)( gralloc1_device_t
*device
, buffer_handle_t buffer
,
236 int32_t *outReleaseFence
);
238 static inline BOOL
is_in_desktop_process(void)
240 return thread
!= NULL
;
243 static inline DWORD
current_client_id(void)
245 DWORD client_id
= NtUserGetThreadInfo()->driver_data
;
246 return client_id
? client_id
: GetCurrentProcessId();
249 static inline BOOL
is_client_in_process(void)
251 return current_client_id() == GetCurrentProcessId();
254 #ifdef __i386__ /* the Java VM uses %fs/%gs for its own purposes, so we need to wrap the calls */
256 static WORD orig_fs
, java_fs
;
257 static inline void wrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (java_fs
) ); }
258 static inline void unwrap_java_call(void) { __asm__( "mov %0,%%fs" :: "r" (orig_fs
) ); }
259 static inline void init_java_thread( JavaVM
*java_vm
)
261 java_fs
= *p_java_gdt_sel
;
262 __asm__( "mov %%fs,%0" : "=r" (orig_fs
) );
263 __asm__( "mov %0,%%fs" :: "r" (java_fs
) );
264 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
265 if (!*p_java_gdt_sel
) __asm__( "mov %%fs,%0" : "=r" (java_fs
) );
266 __asm__( "mov %0,%%fs" :: "r" (orig_fs
) );
269 #elif defined(__x86_64__)
271 #include <asm/prctl.h>
272 #include <asm/unistd.h>
273 static void *orig_teb
, *java_teb
;
274 static inline int arch_prctl( int func
, void *ptr
) { return syscall( __NR_arch_prctl
, func
, ptr
); }
275 static inline void wrap_java_call(void) { arch_prctl( ARCH_SET_GS
, java_teb
); }
276 static inline void unwrap_java_call(void) { arch_prctl( ARCH_SET_GS
, orig_teb
); }
277 static inline void init_java_thread( JavaVM
*java_vm
)
279 arch_prctl( ARCH_GET_GS
, &orig_teb
);
280 (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 );
281 arch_prctl( ARCH_GET_GS
, &java_teb
);
282 arch_prctl( ARCH_SET_GS
, orig_teb
);
286 static inline void wrap_java_call(void) { }
287 static inline void unwrap_java_call(void) { }
288 static inline void init_java_thread( JavaVM
*java_vm
) { (*java_vm
)->AttachCurrentThread( java_vm
, &jni_env
, 0 ); }
289 #endif /* __i386__ */
291 static struct native_win_data
*data_map
[65536];
293 static unsigned int data_map_idx( HWND hwnd
, BOOL opengl
)
295 /* window handles are always even, so use low-order bit for opengl flag */
296 return LOWORD(hwnd
) + !!opengl
;
299 static struct native_win_data
*get_native_win_data( HWND hwnd
, BOOL opengl
)
301 struct native_win_data
*data
= data_map
[data_map_idx( hwnd
, opengl
)];
303 if (data
&& data
->hwnd
== hwnd
&& !data
->opengl
== !opengl
) return data
;
304 WARN( "unknown win %p opengl %u\n", hwnd
, opengl
);
308 static struct native_win_data
*get_ioctl_native_win_data( const struct ioctl_header
*hdr
)
310 return get_native_win_data( LongToHandle(hdr
->hwnd
), hdr
->opengl
);
313 static int get_ioctl_win_parent( HWND parent
)
315 if (parent
!= NtUserGetDesktopWindow() && !NtUserGetAncestor( parent
, GA_PARENT
))
316 return HandleToLong( HWND_MESSAGE
);
317 return HandleToLong( parent
);
320 static void wait_fence_and_close( int fence
)
322 __s32 timeout
= 1000; /* FIXME: should be -1 for infinite timeout */
324 if (fence
== -1) return;
325 ioctl( fence
, SYNC_IOC_WAIT
, &timeout
);
329 static int duplicate_fd( HANDLE client
, int fd
)
331 HANDLE handle
, ret
= 0;
333 if (!wine_server_fd_to_handle( dup(fd
), GENERIC_READ
| SYNCHRONIZE
, 0, &handle
))
334 NtDuplicateObject( GetCurrentProcess(), handle
, client
, &ret
,
335 0, 0, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
338 return HandleToLong( ret
);
341 static int map_native_handle( union native_handle_buffer
*dest
, const native_handle_t
*src
,
342 HANDLE mapping
, HANDLE client
)
344 const size_t size
= offsetof( native_handle_t
, data
[src
->numFds
+ src
->numInts
] );
347 if (mapping
) /* only duplicate the mapping handle */
350 if (!NtDuplicateObject( GetCurrentProcess(), mapping
, client
, &ret
,
351 0, 0, DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
))
353 dest
->handle
.numFds
= 0;
354 dest
->handle
.numInts
= 1;
355 dest
->handle
.data
[0] = HandleToLong( ret
);
358 if (is_client_in_process()) /* transfer the actual handle pointer */
360 dest
->handle
.numFds
= 0;
361 dest
->handle
.numInts
= sizeof(src
) / sizeof(int);
362 memcpy( dest
->handle
.data
, &src
, sizeof(src
) );
365 if (size
> sizeof(*dest
)) return -ENOSPC
;
366 memcpy( dest
, src
, size
);
367 /* transfer file descriptors to the client process */
368 for (i
= 0; i
< dest
->handle
.numFds
; i
++)
369 dest
->handle
.data
[i
] = duplicate_fd( client
, src
->data
[i
] );
373 static native_handle_t
*unmap_native_handle( const native_handle_t
*src
)
375 const size_t size
= offsetof( native_handle_t
, data
[src
->numFds
+ src
->numInts
] );
376 native_handle_t
*dest
;
379 if (!is_in_desktop_process())
381 dest
= malloc( size
);
382 memcpy( dest
, src
, size
);
383 /* fetch file descriptors passed from the server process */
384 for (i
= 0; i
< dest
->numFds
; i
++)
385 wine_server_handle_to_fd( LongToHandle(src
->data
[i
]), GENERIC_READ
| SYNCHRONIZE
,
386 &dest
->data
[i
], NULL
);
388 else memcpy( &dest
, src
->data
, sizeof(dest
) );
392 static void close_native_handle( native_handle_t
*handle
)
396 for (i
= 0; i
< handle
->numFds
; i
++) close( handle
->data
[i
] );
400 /* insert a buffer index at the head of the LRU list */
401 static void insert_buffer_lru( struct native_win_data
*win
, int index
)
405 for (i
= 0; i
< NB_CACHED_BUFFERS
; i
++)
407 if (win
->buffer_lru
[i
] == index
) break;
408 if (win
->buffer_lru
[i
] == -1) break;
411 assert( i
< NB_CACHED_BUFFERS
);
412 memmove( win
->buffer_lru
+ 1, win
->buffer_lru
, i
* sizeof(win
->buffer_lru
[0]) );
413 win
->buffer_lru
[0] = index
;
416 static int register_buffer( struct native_win_data
*win
, struct ANativeWindowBuffer
*buffer
,
417 HANDLE
*mapping
, int *is_new
)
422 for (i
= 0; i
< NB_CACHED_BUFFERS
; i
++)
424 if (win
->buffers
[i
] == buffer
) goto done
;
425 if (!win
->buffers
[i
]) break;
428 if (i
== NB_CACHED_BUFFERS
)
430 /* reuse the least recently used buffer */
431 i
= win
->buffer_lru
[NB_CACHED_BUFFERS
- 1];
432 assert( i
< NB_CACHED_BUFFERS
);
434 TRACE( "%p %p evicting buffer %p id %d from cache\n",
435 win
->hwnd
, win
->parent
, win
->buffers
[i
], i
);
436 win
->buffers
[i
]->common
.decRef( &win
->buffers
[i
]->common
);
437 if (win
->mappings
[i
]) NtUnmapViewOfSection( GetCurrentProcess(), win
->mappings
[i
] );
440 win
->buffers
[i
] = buffer
;
441 win
->mappings
[i
] = NULL
;
445 OBJECT_ATTRIBUTES attr
;
448 size
.QuadPart
= buffer
->stride
* buffer
->height
* 4;
449 InitializeObjectAttributes( &attr
, NULL
, OBJ_OPENIF
, NULL
, NULL
);
450 NtCreateSection( mapping
,
451 STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
| SECTION_MAP_READ
| SECTION_MAP_WRITE
,
452 &attr
, &size
, PAGE_READWRITE
, 0, INVALID_HANDLE_VALUE
);
453 NtMapViewOfSection( *mapping
, GetCurrentProcess(), &win
->mappings
[i
], 0, 0,
454 NULL
, &count
, ViewShare
, 0, PAGE_READONLY
);
456 buffer
->common
.incRef( &buffer
->common
);
458 TRACE( "%p %p %p -> %d\n", win
->hwnd
, win
->parent
, buffer
, i
);
461 insert_buffer_lru( win
, i
);
465 static struct ANativeWindowBuffer
*get_registered_buffer( struct native_win_data
*win
, int id
)
467 if (id
< 0 || id
>= NB_CACHED_BUFFERS
|| !win
->buffers
[id
])
469 ERR( "unknown buffer %d for %p %p\n", id
, win
->hwnd
, win
->parent
);
472 return win
->buffers
[id
];
475 static void release_native_window( struct native_win_data
*data
)
479 if (data
->parent
) pANativeWindow_release( data
->parent
);
480 for (i
= 0; i
< NB_CACHED_BUFFERS
; i
++)
482 if (data
->buffers
[i
]) data
->buffers
[i
]->common
.decRef( &data
->buffers
[i
]->common
);
483 if (data
->mappings
[i
]) NtUnmapViewOfSection( GetCurrentProcess(), data
->mappings
[i
] );
484 data
->buffer_lru
[i
] = -1;
486 memset( data
->buffers
, 0, sizeof(data
->buffers
) );
487 memset( data
->mappings
, 0, sizeof(data
->mappings
) );
490 static void free_native_win_data( struct native_win_data
*data
)
492 unsigned int idx
= data_map_idx( data
->hwnd
, data
->opengl
);
494 InterlockedCompareExchangePointer( (void **)&capture_window
, 0, data
->hwnd
);
495 release_native_window( data
);
497 data_map
[idx
] = NULL
;
500 static struct native_win_data
*create_native_win_data( HWND hwnd
, BOOL opengl
)
502 unsigned int i
, idx
= data_map_idx( hwnd
, opengl
);
503 struct native_win_data
*data
= data_map
[idx
];
507 WARN( "data for %p not freed correctly\n", data
->hwnd
);
508 free_native_win_data( data
);
510 if (!(data
= calloc( 1, sizeof(*data
) ))) return NULL
;
512 data
->opengl
= opengl
;
513 if (!opengl
) data
->api
= NATIVE_WINDOW_API_CPU
;
514 data
->buffer_format
= PF_BGRA_8888
;
515 data_map
[idx
] = data
;
516 for (i
= 0; i
< NB_CACHED_BUFFERS
; i
++) data
->buffer_lru
[i
] = -1;
520 NTSTATUS
android_register_window( void *arg
)
522 struct register_window_params
*params
= arg
;
523 HWND hwnd
= (HWND
)params
->arg1
;
524 struct ANativeWindow
*win
= (struct ANativeWindow
*)params
->arg2
;
525 BOOL opengl
= params
->arg3
;
526 struct native_win_data
*data
= get_native_win_data( hwnd
, opengl
);
528 if (!win
) return 0; /* do nothing and hold on to the window until we get a new surface */
530 if (!data
|| data
->parent
== win
)
532 pANativeWindow_release( win
);
533 if (data
) NtUserPostMessage( hwnd
, WM_ANDROID_REFRESH
, opengl
, 0 );
534 TRACE( "%p -> %p win %p (unchanged)\n", hwnd
, data
, win
);
538 release_native_window( data
);
542 if (data
->api
) win
->perform( win
, NATIVE_WINDOW_API_CONNECT
, data
->api
);
543 win
->perform( win
, NATIVE_WINDOW_SET_BUFFERS_FORMAT
, data
->buffer_format
);
544 win
->setSwapInterval( win
, data
->swap_interval
);
546 NtUserPostMessage( hwnd
, WM_ANDROID_REFRESH
, opengl
, 0 );
547 TRACE( "%p -> %p win %p\n", hwnd
, data
, win
);
551 /* register a native window received from the Java side for use in ioctls */
552 void register_native_window( HWND hwnd
, struct ANativeWindow
*win
, BOOL opengl
)
554 NtQueueApcThread( thread
, register_window_callback
, (ULONG_PTR
)hwnd
, (ULONG_PTR
)win
, opengl
);
557 void init_gralloc( const struct hw_module_t
*module
)
559 struct hw_device_t
*device
;
562 TRACE( "got module %p ver %u.%u id %s name %s author %s\n",
563 module
, module
->module_api_version
>> 8, module
->module_api_version
& 0xff,
564 debugstr_a(module
->id
), debugstr_a(module
->name
), debugstr_a(module
->author
) );
566 switch (module
->module_api_version
>> 8)
569 gralloc_module
= (struct gralloc_module_t
*)module
;
572 if (!(ret
= module
->methods
->open( module
, GRALLOC_HARDWARE_MODULE_ID
, &device
)))
575 uint32_t i
, count
= ARRAY_SIZE(caps
);
577 gralloc1_device
= (struct gralloc1_device
*)device
;
578 gralloc1_retain
= gralloc1_device
->getFunction( gralloc1_device
, GRALLOC1_FUNCTION_RETAIN
);
579 gralloc1_release
= gralloc1_device
->getFunction( gralloc1_device
, GRALLOC1_FUNCTION_RELEASE
);
580 gralloc1_lock
= gralloc1_device
->getFunction( gralloc1_device
, GRALLOC1_FUNCTION_LOCK
);
581 gralloc1_unlock
= gralloc1_device
->getFunction( gralloc1_device
, GRALLOC1_FUNCTION_UNLOCK
);
582 TRACE( "got device version %u funcs %p %p %p %p\n", device
->version
,
583 gralloc1_retain
, gralloc1_release
, gralloc1_lock
, gralloc1_unlock
);
585 gralloc1_device
->getCapabilities( gralloc1_device
, &count
, caps
);
586 if (count
== ARRAY_SIZE(caps
)) ERR( "too many gralloc capabilities\n" );
587 for (i
= 0; i
< count
; i
++)
588 if (caps
[i
] < ARRAY_SIZE(gralloc1_caps
)) gralloc1_caps
[caps
[i
]] = TRUE
;
590 else ERR( "failed to open gralloc err %d\n", ret
);
593 ERR( "unknown gralloc module version %u\n", module
->module_api_version
>> 8 );
598 static int gralloc_grab_buffer( struct ANativeWindowBuffer
*buffer
)
601 return gralloc1_retain( gralloc1_device
, buffer
->handle
);
603 return gralloc_module
->registerBuffer( gralloc_module
, buffer
->handle
);
607 static void gralloc_release_buffer( struct ANativeWindowBuffer
*buffer
)
609 if (gralloc1_device
) gralloc1_release( gralloc1_device
, buffer
->handle
);
610 else if (gralloc_module
) gralloc_module
->unregisterBuffer( gralloc_module
, buffer
->handle
);
612 if (!gralloc1_caps
[GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE
])
613 close_native_handle( (native_handle_t
*)buffer
->handle
);
616 static int gralloc_lock( struct ANativeWindowBuffer
*buffer
, void **bits
)
620 gralloc1_rect_t rect
= { 0, 0, buffer
->width
, buffer
->height
};
621 return gralloc1_lock( gralloc1_device
, buffer
->handle
,
622 GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN
|
623 GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN
,
624 GRALLOC1_CONSUMER_USAGE_NONE
, &rect
, bits
, -1 );
627 return gralloc_module
->lock( gralloc_module
, buffer
->handle
,
628 GRALLOC_USAGE_SW_READ_OFTEN
| GRALLOC_USAGE_SW_WRITE_OFTEN
,
629 0, 0, buffer
->width
, buffer
->height
, bits
);
631 *bits
= ((struct native_buffer_wrapper
*)buffer
)->bits
;
635 static void gralloc_unlock( struct ANativeWindowBuffer
*buffer
)
640 gralloc1_unlock( gralloc1_device
, buffer
->handle
, &fence
);
641 wait_fence_and_close( fence
);
643 else if (gralloc_module
) gralloc_module
->unlock( gralloc_module
, buffer
->handle
);
646 /* get the capture window stored in the desktop process */
647 HWND
get_capture_window(void)
649 return capture_window
;
652 static NTSTATUS
android_error_to_status( int err
)
656 case 0: return STATUS_SUCCESS
;
657 case -ENOMEM
: return STATUS_NO_MEMORY
;
658 case -ENOSYS
: return STATUS_NOT_SUPPORTED
;
659 case -EINVAL
: return STATUS_INVALID_PARAMETER
;
660 case -ENOENT
: return STATUS_INVALID_HANDLE
;
661 case -EPERM
: return STATUS_ACCESS_DENIED
;
662 case -ENODEV
: return STATUS_NO_SUCH_DEVICE
;
663 case -EEXIST
: return STATUS_DUPLICATE_NAME
;
664 case -EPIPE
: return STATUS_PIPE_DISCONNECTED
;
665 case -ENODATA
: return STATUS_NO_MORE_FILES
;
666 case -ETIMEDOUT
: return STATUS_IO_TIMEOUT
;
667 case -EBADMSG
: return STATUS_INVALID_DEVICE_REQUEST
;
668 case -EWOULDBLOCK
: return STATUS_DEVICE_NOT_READY
;
670 FIXME( "unmapped error %d\n", err
);
671 return STATUS_UNSUCCESSFUL
;
675 static int status_to_android_error( unsigned int status
)
679 case STATUS_SUCCESS
: return 0;
680 case STATUS_NO_MEMORY
: return -ENOMEM
;
681 case STATUS_NOT_SUPPORTED
: return -ENOSYS
;
682 case STATUS_INVALID_PARAMETER
: return -EINVAL
;
683 case STATUS_BUFFER_OVERFLOW
: return -EINVAL
;
684 case STATUS_INVALID_HANDLE
: return -ENOENT
;
685 case STATUS_ACCESS_DENIED
: return -EPERM
;
686 case STATUS_NO_SUCH_DEVICE
: return -ENODEV
;
687 case STATUS_DUPLICATE_NAME
: return -EEXIST
;
688 case STATUS_PIPE_DISCONNECTED
: return -EPIPE
;
689 case STATUS_NO_MORE_FILES
: return -ENODATA
;
690 case STATUS_IO_TIMEOUT
: return -ETIMEDOUT
;
691 case STATUS_INVALID_DEVICE_REQUEST
: return -EBADMSG
;
692 case STATUS_DEVICE_NOT_READY
: return -EWOULDBLOCK
;
694 FIXME( "unmapped status %08x\n", status
);
699 static jobject
load_java_method( jmethodID
*method
, const char *name
, const char *args
)
701 jobject object
= *p_java_object
;
708 class = (*jni_env
)->GetObjectClass( jni_env
, object
);
709 *method
= (*jni_env
)->GetMethodID( jni_env
, class, name
, args
);
713 FIXME( "method %s not found\n", name
);
720 static void create_desktop_window( HWND hwnd
)
722 static jmethodID method
;
725 if (!(object
= load_java_method( &method
, "createDesktopWindow", "(I)V" ))) return;
728 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, HandleToLong( hwnd
));
732 static NTSTATUS
createWindow_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
734 static jmethodID method
;
736 struct ioctl_android_create_window
*res
= data
;
737 struct native_win_data
*win_data
;
738 DWORD pid
= current_client_id();
740 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
742 if (!(win_data
= create_native_win_data( LongToHandle(res
->hdr
.hwnd
), res
->hdr
.opengl
)))
743 return STATUS_NO_MEMORY
;
745 TRACE( "hwnd %08x opengl %u parent %08x\n", res
->hdr
.hwnd
, res
->hdr
.opengl
, res
->parent
);
747 if (!(object
= load_java_method( &method
, "createWindow", "(IZIFI)V" ))) return STATUS_NOT_SUPPORTED
;
750 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
, res
->hdr
.opengl
, res
->parent
, res
->scale
, pid
);
752 return STATUS_SUCCESS
;
755 static NTSTATUS
destroyWindow_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
757 static jmethodID method
;
759 struct ioctl_android_destroy_window
*res
= data
;
760 struct native_win_data
*win_data
;
762 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
764 win_data
= get_ioctl_native_win_data( &res
->hdr
);
766 TRACE( "hwnd %08x opengl %u\n", res
->hdr
.hwnd
, res
->hdr
.opengl
);
768 if (!(object
= load_java_method( &method
, "destroyWindow", "(I)V" ))) return STATUS_NOT_SUPPORTED
;
771 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
);
773 if (win_data
) free_native_win_data( win_data
);
774 return STATUS_SUCCESS
;
777 static NTSTATUS
windowPosChanged_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
779 static jmethodID method
;
781 struct ioctl_android_window_pos_changed
*res
= data
;
783 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
785 TRACE( "hwnd %08x win %s client %s visible %s style %08x flags %08x after %08x owner %08x\n",
786 res
->hdr
.hwnd
, wine_dbgstr_rect(&res
->window_rect
), wine_dbgstr_rect(&res
->client_rect
),
787 wine_dbgstr_rect(&res
->visible_rect
), res
->style
, res
->flags
, res
->after
, res
->owner
);
789 if (!(object
= load_java_method( &method
, "windowPosChanged", "(IIIIIIIIIIIIIIIII)V" )))
790 return STATUS_NOT_SUPPORTED
;
793 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
, res
->flags
, res
->after
, res
->owner
, res
->style
,
794 res
->window_rect
.left
, res
->window_rect
.top
, res
->window_rect
.right
, res
->window_rect
.bottom
,
795 res
->client_rect
.left
, res
->client_rect
.top
, res
->client_rect
.right
, res
->client_rect
.bottom
,
796 res
->visible_rect
.left
, res
->visible_rect
.top
, res
->visible_rect
.right
, res
->visible_rect
.bottom
);
798 return STATUS_SUCCESS
;
801 static NTSTATUS
dequeueBuffer_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
803 struct ANativeWindow
*parent
;
804 struct ioctl_android_dequeueBuffer
*res
= data
;
805 struct native_win_data
*win_data
;
806 struct ANativeWindowBuffer
*buffer
;
807 int fence
, ret
, is_new
;
809 if (out_size
< sizeof( *res
)) return STATUS_BUFFER_OVERFLOW
;
811 if (in_size
< offsetof( struct ioctl_android_dequeueBuffer
, native_handle
))
812 return STATUS_INVALID_PARAMETER
;
814 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
815 if (!(parent
= win_data
->parent
)) return STATUS_DEVICE_NOT_READY
;
817 *ret_size
= offsetof( struct ioctl_android_dequeueBuffer
, native_handle
);
819 ret
= parent
->dequeueBuffer( parent
, &buffer
, &fence
);
825 TRACE( "%08x got buffer %p fence %d\n", res
->hdr
.hwnd
, buffer
, fence
);
826 res
->width
= buffer
->width
;
827 res
->height
= buffer
->height
;
828 res
->stride
= buffer
->stride
;
829 res
->format
= buffer
->format
;
830 res
->usage
= buffer
->usage
;
831 res
->buffer_id
= register_buffer( win_data
, buffer
, res
->win32
? &mapping
: NULL
, &is_new
);
832 res
->generation
= win_data
->generation
;
835 OBJECT_ATTRIBUTES attr
= { .Length
= sizeof(attr
) };
836 CLIENT_ID cid
= { .UniqueProcess
= UlongToHandle( current_client_id() ) };
838 NtOpenProcess( &process
, PROCESS_DUP_HANDLE
, &attr
, &cid
);
839 map_native_handle( &res
->native_handle
, buffer
->handle
, mapping
, process
);
841 *ret_size
= sizeof( *res
);
843 wait_fence_and_close( fence
);
844 return STATUS_SUCCESS
;
846 ERR( "%08x failed %d\n", res
->hdr
.hwnd
, ret
);
847 return android_error_to_status( ret
);
850 static NTSTATUS
cancelBuffer_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
852 struct ioctl_android_cancelBuffer
*res
= data
;
853 struct ANativeWindow
*parent
;
854 struct ANativeWindowBuffer
*buffer
;
855 struct native_win_data
*win_data
;
858 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
860 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
861 if (!(parent
= win_data
->parent
)) return STATUS_DEVICE_NOT_READY
;
862 if (res
->generation
!= win_data
->generation
) return STATUS_SUCCESS
; /* obsolete buffer, ignore */
864 if (!(buffer
= get_registered_buffer( win_data
, res
->buffer_id
))) return STATUS_INVALID_HANDLE
;
866 TRACE( "%08x buffer %p\n", res
->hdr
.hwnd
, buffer
);
868 ret
= parent
->cancelBuffer( parent
, buffer
, -1 );
870 return android_error_to_status( ret
);
873 static NTSTATUS
queueBuffer_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
875 struct ioctl_android_queueBuffer
*res
= data
;
876 struct ANativeWindow
*parent
;
877 struct ANativeWindowBuffer
*buffer
;
878 struct native_win_data
*win_data
;
881 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
883 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
884 if (!(parent
= win_data
->parent
)) return STATUS_DEVICE_NOT_READY
;
885 if (res
->generation
!= win_data
->generation
) return STATUS_SUCCESS
; /* obsolete buffer, ignore */
887 if (!(buffer
= get_registered_buffer( win_data
, res
->buffer_id
))) return STATUS_INVALID_HANDLE
;
889 TRACE( "%08x buffer %p mapping %p\n", res
->hdr
.hwnd
, buffer
, win_data
->mappings
[res
->buffer_id
] );
890 if (win_data
->mappings
[res
->buffer_id
])
893 ret
= gralloc_lock( buffer
, &bits
);
894 if (ret
) return android_error_to_status( ret
);
895 memcpy( bits
, win_data
->mappings
[res
->buffer_id
], buffer
->stride
* buffer
->height
* 4 );
896 gralloc_unlock( buffer
);
899 ret
= parent
->queueBuffer( parent
, buffer
, -1 );
901 return android_error_to_status( ret
);
904 static NTSTATUS
query_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
906 struct ioctl_android_query
*res
= data
;
907 struct ANativeWindow
*parent
;
908 struct native_win_data
*win_data
;
911 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
912 if (out_size
< sizeof(*res
)) return STATUS_BUFFER_OVERFLOW
;
914 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
915 if (!(parent
= win_data
->parent
)) return STATUS_DEVICE_NOT_READY
;
917 *ret_size
= sizeof( *res
);
919 ret
= parent
->query( parent
, res
->what
, &res
->value
);
921 return android_error_to_status( ret
);
924 static NTSTATUS
perform_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
926 struct ioctl_android_perform
*res
= data
;
927 struct ANativeWindow
*parent
;
928 struct native_win_data
*win_data
;
931 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
933 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
934 if (!(parent
= win_data
->parent
)) return STATUS_DEVICE_NOT_READY
;
936 switch (res
->operation
)
938 case NATIVE_WINDOW_SET_BUFFERS_FORMAT
:
940 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
942 if (!ret
) win_data
->buffer_format
= res
->args
[0];
944 case NATIVE_WINDOW_API_CONNECT
:
946 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
948 if (!ret
) win_data
->api
= res
->args
[0];
950 case NATIVE_WINDOW_API_DISCONNECT
:
952 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
954 if (!ret
) win_data
->api
= 0;
956 case NATIVE_WINDOW_SET_USAGE
:
957 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
:
958 case NATIVE_WINDOW_SET_SCALING_MODE
:
960 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] );
963 case NATIVE_WINDOW_SET_BUFFER_COUNT
:
965 ret
= parent
->perform( parent
, res
->operation
, (size_t)res
->args
[0] );
968 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
:
969 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS
:
971 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0], res
->args
[1] );
974 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
:
976 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0], res
->args
[1], res
->args
[2] );
979 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
:
981 ret
= parent
->perform( parent
, res
->operation
, res
->args
[0] | ((int64_t)res
->args
[1] << 32) );
984 case NATIVE_WINDOW_CONNECT
:
985 case NATIVE_WINDOW_DISCONNECT
:
986 case NATIVE_WINDOW_UNLOCK_AND_POST
:
988 ret
= parent
->perform( parent
, res
->operation
);
991 case NATIVE_WINDOW_SET_CROP
:
993 android_native_rect_t rect
;
994 rect
.left
= res
->args
[0];
995 rect
.top
= res
->args
[1];
996 rect
.right
= res
->args
[2];
997 rect
.bottom
= res
->args
[3];
999 ret
= parent
->perform( parent
, res
->operation
, &rect
);
1003 case NATIVE_WINDOW_LOCK
:
1005 FIXME( "unsupported perform op %d\n", res
->operation
);
1008 return android_error_to_status( ret
);
1011 static NTSTATUS
setSwapInterval_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
1013 struct ioctl_android_set_swap_interval
*res
= data
;
1014 struct ANativeWindow
*parent
;
1015 struct native_win_data
*win_data
;
1018 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
1020 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
1021 win_data
->swap_interval
= res
->interval
;
1023 if (!(parent
= win_data
->parent
)) return STATUS_SUCCESS
;
1025 ret
= parent
->setSwapInterval( parent
, res
->interval
);
1027 return android_error_to_status( ret
);
1030 static NTSTATUS
setWindowParent_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
1032 static jmethodID method
;
1034 struct ioctl_android_set_window_parent
*res
= data
;
1035 struct native_win_data
*win_data
;
1036 DWORD pid
= current_client_id();
1038 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
1040 if (!(win_data
= get_ioctl_native_win_data( &res
->hdr
))) return STATUS_INVALID_HANDLE
;
1042 TRACE( "hwnd %08x parent %08x\n", res
->hdr
.hwnd
, res
->parent
);
1044 if (!(object
= load_java_method( &method
, "setParent", "(IIFI)V" ))) return STATUS_NOT_SUPPORTED
;
1047 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->hdr
.hwnd
, res
->parent
, res
->scale
, pid
);
1049 return STATUS_SUCCESS
;
1052 static NTSTATUS
setCapture_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
1054 struct ioctl_android_set_capture
*res
= data
;
1056 if (in_size
< sizeof(*res
)) return STATUS_INVALID_PARAMETER
;
1058 if (res
->hdr
.hwnd
&& !get_ioctl_native_win_data( &res
->hdr
)) return STATUS_INVALID_HANDLE
;
1060 TRACE( "hwnd %08x\n", res
->hdr
.hwnd
);
1062 InterlockedExchangePointer( (void **)&capture_window
, LongToHandle( res
->hdr
.hwnd
));
1063 return STATUS_SUCCESS
;
1066 static NTSTATUS
setCursor_ioctl( void *data
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
)
1068 static jmethodID method
;
1071 struct ioctl_android_set_cursor
*res
= data
;
1073 if (in_size
< offsetof( struct ioctl_android_set_cursor
, bits
)) return STATUS_INVALID_PARAMETER
;
1075 if (res
->width
< 0 || res
->height
< 0 || res
->width
> 256 || res
->height
> 256)
1076 return STATUS_INVALID_PARAMETER
;
1078 size
= res
->width
* res
->height
;
1079 if (in_size
!= offsetof( struct ioctl_android_set_cursor
, bits
[size
] ))
1080 return STATUS_INVALID_PARAMETER
;
1082 TRACE( "hwnd %08x size %d\n", res
->hdr
.hwnd
, size
);
1084 if (!(object
= load_java_method( &method
, "setCursor", "(IIIII[I)V" )))
1085 return STATUS_NOT_SUPPORTED
;
1091 jintArray array
= (*jni_env
)->NewIntArray( jni_env
, size
);
1092 (*jni_env
)->SetIntArrayRegion( jni_env
, array
, 0, size
, (jint
*)res
->bits
);
1093 (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, 0, res
->width
, res
->height
,
1094 res
->hotspotx
, res
->hotspoty
, array
);
1095 (*jni_env
)->DeleteLocalRef( jni_env
, array
);
1097 else (*jni_env
)->CallVoidMethod( jni_env
, object
, method
, res
->id
, 0, 0, 0, 0, 0 );
1101 return STATUS_SUCCESS
;
1104 typedef NTSTATUS (*ioctl_func
)( void *in
, DWORD in_size
, DWORD out_size
, ULONG_PTR
*ret_size
);
1105 static const ioctl_func ioctl_funcs
[] =
1107 createWindow_ioctl
, /* IOCTL_CREATE_WINDOW */
1108 destroyWindow_ioctl
, /* IOCTL_DESTROY_WINDOW */
1109 windowPosChanged_ioctl
, /* IOCTL_WINDOW_POS_CHANGED */
1110 setWindowParent_ioctl
, /* IOCTL_SET_WINDOW_PARENT */
1111 dequeueBuffer_ioctl
, /* IOCTL_DEQUEUE_BUFFER */
1112 queueBuffer_ioctl
, /* IOCTL_QUEUE_BUFFER */
1113 cancelBuffer_ioctl
, /* IOCTL_CANCEL_BUFFER */
1114 query_ioctl
, /* IOCTL_QUERY */
1115 perform_ioctl
, /* IOCTL_PERFORM */
1116 setSwapInterval_ioctl
, /* IOCTL_SET_SWAP_INT */
1117 setCapture_ioctl
, /* IOCTL_SET_CAPTURE */
1118 setCursor_ioctl
, /* IOCTL_SET_CURSOR */
1121 NTSTATUS
android_dispatch_ioctl( void *arg
)
1123 struct ioctl_params
*params
= arg
;
1124 IRP
*irp
= params
->irp
;
1125 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
1126 DWORD code
= (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
- ANDROID_IOCTL(0)) >> 2;
1128 if (code
< NB_IOCTLS
)
1130 struct ioctl_header
*header
= irp
->AssociatedIrp
.SystemBuffer
;
1131 DWORD in_size
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
1132 ioctl_func func
= ioctl_funcs
[code
];
1134 if (in_size
>= sizeof(*header
))
1136 irp
->IoStatus
.Information
= 0;
1137 NtUserGetThreadInfo()->driver_data
= params
->client_id
;
1138 irp
->IoStatus
.Status
= func( irp
->AssociatedIrp
.SystemBuffer
, in_size
,
1139 irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
,
1140 &irp
->IoStatus
.Information
);
1141 NtUserGetThreadInfo()->driver_data
= 0;
1143 else irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1147 FIXME( "ioctl %x not supported\n", (int)irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
1148 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1150 return STATUS_SUCCESS
;
1153 NTSTATUS
android_java_init( void *arg
)
1157 if (!(java_vm
= *p_java_vm
)) return STATUS_UNSUCCESSFUL
; /* not running under Java */
1159 init_java_thread( java_vm
);
1160 create_desktop_window( NtUserGetDesktopWindow() );
1161 return STATUS_SUCCESS
;
1164 NTSTATUS
android_java_uninit( void *arg
)
1168 if (!(java_vm
= *p_java_vm
)) return STATUS_UNSUCCESSFUL
; /* not running under Java */
1171 (*java_vm
)->DetachCurrentThread( java_vm
);
1173 return STATUS_SUCCESS
;
1176 void start_android_device(void)
1180 thread
= ULongToHandle( KeUserModeCallback( client_start_device
, NULL
, 0, &ret_ptr
, &ret_len
));
1184 /* Client-side ioctl support */
1187 static int android_ioctl( enum android_ioctl code
, void *in
, DWORD in_size
, void *out
, DWORD
*out_size
)
1189 static const WCHAR deviceW
[] = {'\\','\\','.','\\','W','i','n','e','A','n','d','r','o','i','d',0 };
1190 static HANDLE device
;
1191 IO_STATUS_BLOCK iosb
;
1196 OBJECT_ATTRIBUTES attr
;
1197 UNICODE_STRING name
;
1202 RtlInitUnicodeString( &name
, deviceW
);
1203 InitializeObjectAttributes( &attr
, &name
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1204 status
= NtCreateFile( &file
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
, NULL
, 0,
1205 FILE_SHARE_READ
| FILE_SHARE_WRITE
, FILE_OPEN
,
1206 FILE_NON_DIRECTORY_FILE
, NULL
, 0 );
1207 if (status
) return -ENOENT
;
1208 if (InterlockedCompareExchangePointer( &device
, file
, NULL
)) NtClose( file
);
1211 status
= NtDeviceIoControlFile( device
, NULL
, NULL
, NULL
, &iosb
, ANDROID_IOCTL(code
),
1212 in
, in_size
, out
, out_size
? *out_size
: 0 );
1213 if (status
== STATUS_FILE_DELETED
)
1215 WARN( "parent process is gone\n" );
1216 NtTerminateProcess( 0, 1 );
1218 if (out_size
) *out_size
= iosb
.Information
;
1219 return status_to_android_error( status
);
1222 static void win_incRef( struct android_native_base_t
*base
)
1224 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)base
;
1225 InterlockedIncrement( &win
->ref
);
1228 static void win_decRef( struct android_native_base_t
*base
)
1230 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)base
;
1231 InterlockedDecrement( &win
->ref
);
1234 static void buffer_incRef( struct android_native_base_t
*base
)
1236 struct native_buffer_wrapper
*buffer
= (struct native_buffer_wrapper
*)base
;
1237 InterlockedIncrement( &buffer
->ref
);
1240 static void buffer_decRef( struct android_native_base_t
*base
)
1242 struct native_buffer_wrapper
*buffer
= (struct native_buffer_wrapper
*)base
;
1244 if (!InterlockedDecrement( &buffer
->ref
))
1246 if (!is_in_desktop_process()) gralloc_release_buffer( &buffer
->buffer
);
1247 if (buffer
->bits
) NtUnmapViewOfSection( GetCurrentProcess(), buffer
->bits
);
1252 static int dequeueBuffer( struct ANativeWindow
*window
, struct ANativeWindowBuffer
**buffer
, int *fence
)
1254 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1255 struct ioctl_android_dequeueBuffer res
;
1256 DWORD size
= sizeof(res
);
1257 int ret
, use_win32
= !gralloc_module
&& !gralloc1_device
;
1259 res
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1260 res
.hdr
.opengl
= win
->opengl
;
1261 res
.win32
= use_win32
;
1262 ret
= android_ioctl( IOCTL_DEQUEUE_BUFFER
,
1263 &res
, offsetof( struct ioctl_android_dequeueBuffer
, native_handle
),
1265 if (ret
) return ret
;
1267 /* if we received the native handle, this is a new buffer */
1268 if (size
> offsetof( struct ioctl_android_dequeueBuffer
, native_handle
))
1270 struct native_buffer_wrapper
*buf
= calloc( 1, sizeof(*buf
) );
1272 buf
->buffer
.common
.magic
= ANDROID_NATIVE_BUFFER_MAGIC
;
1273 buf
->buffer
.common
.version
= sizeof( buf
->buffer
);
1274 buf
->buffer
.common
.incRef
= buffer_incRef
;
1275 buf
->buffer
.common
.decRef
= buffer_decRef
;
1276 buf
->buffer
.width
= res
.width
;
1277 buf
->buffer
.height
= res
.height
;
1278 buf
->buffer
.stride
= res
.stride
;
1279 buf
->buffer
.format
= res
.format
;
1280 buf
->buffer
.usage
= res
.usage
;
1281 buf
->buffer
.handle
= unmap_native_handle( &res
.native_handle
.handle
);
1283 buf
->hwnd
= win
->hwnd
;
1284 buf
->buffer_id
= res
.buffer_id
;
1285 buf
->generation
= res
.generation
;
1286 if (win
->buffers
[res
.buffer_id
])
1287 win
->buffers
[res
.buffer_id
]->buffer
.common
.decRef(&win
->buffers
[res
.buffer_id
]->buffer
.common
);
1288 win
->buffers
[res
.buffer_id
] = buf
;
1292 LARGE_INTEGER zero
= { .QuadPart
= 0 };
1294 HANDLE mapping
= LongToHandle( res
.native_handle
.handle
.data
[0] );
1295 NtMapViewOfSection( mapping
, GetCurrentProcess(), &buf
->bits
, 0, 0, &zero
, &count
,
1296 ViewShare
, 0, PAGE_READWRITE
);
1299 else if (!is_in_desktop_process())
1301 if ((ret
= gralloc_grab_buffer( &buf
->buffer
)) < 0)
1302 WARN( "hwnd %p, buffer %p failed to register %d %s\n",
1303 win
->hwnd
, &buf
->buffer
, ret
, strerror(-ret
) );
1307 *buffer
= &win
->buffers
[res
.buffer_id
]->buffer
;
1310 TRACE( "hwnd %p, buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1311 win
->hwnd
, *buffer
, res
.width
, res
.height
, res
.stride
, res
.format
, res
.usage
, *fence
);
1315 static int cancelBuffer( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
, int fence
)
1317 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1318 struct native_buffer_wrapper
*buf
= (struct native_buffer_wrapper
*)buffer
;
1319 struct ioctl_android_cancelBuffer cancel
;
1321 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1322 win
->hwnd
, buffer
, buffer
->width
, buffer
->height
,
1323 buffer
->stride
, buffer
->format
, buffer
->usage
, fence
);
1324 cancel
.buffer_id
= buf
->buffer_id
;
1325 cancel
.generation
= buf
->generation
;
1326 cancel
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1327 cancel
.hdr
.opengl
= win
->opengl
;
1328 wait_fence_and_close( fence
);
1329 return android_ioctl( IOCTL_CANCEL_BUFFER
, &cancel
, sizeof(cancel
), NULL
, NULL
);
1332 static int queueBuffer( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
, int fence
)
1334 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1335 struct native_buffer_wrapper
*buf
= (struct native_buffer_wrapper
*)buffer
;
1336 struct ioctl_android_queueBuffer queue
;
1338 TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
1339 win
->hwnd
, buffer
, buffer
->width
, buffer
->height
,
1340 buffer
->stride
, buffer
->format
, buffer
->usage
, fence
);
1341 queue
.buffer_id
= buf
->buffer_id
;
1342 queue
.generation
= buf
->generation
;
1343 queue
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1344 queue
.hdr
.opengl
= win
->opengl
;
1345 wait_fence_and_close( fence
);
1346 return android_ioctl( IOCTL_QUEUE_BUFFER
, &queue
, sizeof(queue
), NULL
, NULL
);
1349 static int dequeueBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
**buffer
)
1351 int fence
, ret
= dequeueBuffer( window
, buffer
, &fence
);
1353 if (!ret
) wait_fence_and_close( fence
);
1357 static int cancelBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
)
1359 return cancelBuffer( window
, buffer
, -1 );
1362 static int lockBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
)
1364 return 0; /* nothing to do */
1367 static int queueBuffer_DEPRECATED( struct ANativeWindow
*window
, struct ANativeWindowBuffer
*buffer
)
1369 return queueBuffer( window
, buffer
, -1 );
1372 static int setSwapInterval( struct ANativeWindow
*window
, int interval
)
1374 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1375 struct ioctl_android_set_swap_interval swap
;
1377 TRACE( "hwnd %p interval %d\n", win
->hwnd
, interval
);
1378 swap
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1379 swap
.hdr
.opengl
= win
->opengl
;
1380 swap
.interval
= interval
;
1381 return android_ioctl( IOCTL_SET_SWAP_INT
, &swap
, sizeof(swap
), NULL
, NULL
);
1384 static int query( const ANativeWindow
*window
, int what
, int *value
)
1386 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1387 struct ioctl_android_query query
;
1388 DWORD size
= sizeof( query
);
1391 query
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1392 query
.hdr
.opengl
= win
->opengl
;
1394 ret
= android_ioctl( IOCTL_QUERY
, &query
, sizeof(query
), &query
, &size
);
1395 TRACE( "hwnd %p what %d got %d -> %p\n", win
->hwnd
, what
, query
.value
, value
);
1396 if (!ret
) *value
= query
.value
;
1400 static int perform( ANativeWindow
*window
, int operation
, ... )
1402 static const char * const names
[] =
1404 "SET_USAGE", "CONNECT", "DISCONNECT", "SET_CROP", "SET_BUFFER_COUNT", "SET_BUFFERS_GEOMETRY",
1405 "SET_BUFFERS_TRANSFORM", "SET_BUFFERS_TIMESTAMP", "SET_BUFFERS_DIMENSIONS", "SET_BUFFERS_FORMAT",
1406 "SET_SCALING_MODE", "LOCK", "UNLOCK_AND_POST", "API_CONNECT", "API_DISCONNECT",
1407 "SET_BUFFERS_USER_DIMENSIONS", "SET_POST_TRANSFORM_CROP"
1410 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1411 struct ioctl_android_perform perf
;
1414 perf
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1415 perf
.hdr
.opengl
= win
->opengl
;
1416 perf
.operation
= operation
;
1417 memset( perf
.args
, 0, sizeof(perf
.args
) );
1419 va_start( args
, operation
);
1422 case NATIVE_WINDOW_SET_USAGE
:
1423 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
:
1424 case NATIVE_WINDOW_SET_BUFFERS_FORMAT
:
1425 case NATIVE_WINDOW_SET_SCALING_MODE
:
1426 case NATIVE_WINDOW_API_CONNECT
:
1427 case NATIVE_WINDOW_API_DISCONNECT
:
1428 perf
.args
[0] = va_arg( args
, int );
1429 TRACE( "hwnd %p %s arg %d\n", win
->hwnd
, names
[operation
], perf
.args
[0] );
1431 case NATIVE_WINDOW_SET_BUFFER_COUNT
:
1432 perf
.args
[0] = va_arg( args
, size_t );
1433 TRACE( "hwnd %p %s count %d\n", win
->hwnd
, names
[operation
], perf
.args
[0] );
1435 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS
:
1436 case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS
:
1437 perf
.args
[0] = va_arg( args
, int );
1438 perf
.args
[1] = va_arg( args
, int );
1439 TRACE( "hwnd %p %s arg %dx%d\n", win
->hwnd
, names
[operation
], perf
.args
[0], perf
.args
[1] );
1441 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
:
1442 perf
.args
[0] = va_arg( args
, int );
1443 perf
.args
[1] = va_arg( args
, int );
1444 perf
.args
[2] = va_arg( args
, int );
1445 TRACE( "hwnd %p %s arg %dx%d %d\n", win
->hwnd
, names
[operation
],
1446 perf
.args
[0], perf
.args
[1], perf
.args
[2] );
1448 case NATIVE_WINDOW_SET_CROP
:
1450 android_native_rect_t
*rect
= va_arg( args
, android_native_rect_t
* );
1451 perf
.args
[0] = rect
->left
;
1452 perf
.args
[1] = rect
->top
;
1453 perf
.args
[2] = rect
->right
;
1454 perf
.args
[3] = rect
->bottom
;
1455 TRACE( "hwnd %p %s rect %d,%d-%d,%d\n", win
->hwnd
, names
[operation
],
1456 perf
.args
[0], perf
.args
[1], perf
.args
[2], perf
.args
[3] );
1459 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
:
1461 int64_t timestamp
= va_arg( args
, int64_t );
1462 perf
.args
[0] = timestamp
;
1463 perf
.args
[1] = timestamp
>> 32;
1464 TRACE( "hwnd %p %s arg %08x%08x\n", win
->hwnd
, names
[operation
], perf
.args
[1], perf
.args
[0] );
1467 case NATIVE_WINDOW_LOCK
:
1469 struct ANativeWindowBuffer
*buffer
;
1470 struct ANativeWindow_Buffer
*buffer_ret
= va_arg( args
, ANativeWindow_Buffer
* );
1471 ARect
*bounds
= va_arg( args
, ARect
* );
1472 int ret
= window
->dequeueBuffer_DEPRECATED( window
, &buffer
);
1475 if ((ret
= gralloc_lock( buffer
, &buffer_ret
->bits
)))
1477 WARN( "gralloc->lock %p failed %d %s\n", win
->hwnd
, ret
, strerror(-ret
) );
1478 window
->cancelBuffer( window
, buffer
, -1 );
1483 buffer_ret
->width
= buffer
->width
;
1484 buffer_ret
->height
= buffer
->height
;
1485 buffer_ret
->stride
= buffer
->stride
;
1486 buffer_ret
->format
= buffer
->format
;
1487 win
->locked_buffer
= buffer
;
1492 bounds
->right
= buffer
->width
;
1493 bounds
->bottom
= buffer
->height
;
1497 TRACE( "hwnd %p %s bits %p ret %d %s\n", win
->hwnd
, names
[operation
], buffer_ret
->bits
, ret
, strerror(-ret
) );
1500 case NATIVE_WINDOW_UNLOCK_AND_POST
:
1503 if (win
->locked_buffer
)
1505 gralloc_unlock( win
->locked_buffer
);
1506 ret
= window
->queueBuffer( window
, win
->locked_buffer
, -1 );
1507 win
->locked_buffer
= NULL
;
1510 TRACE( "hwnd %p %s ret %d\n", win
->hwnd
, names
[operation
], ret
);
1513 case NATIVE_WINDOW_CONNECT
:
1514 case NATIVE_WINDOW_DISCONNECT
:
1515 TRACE( "hwnd %p %s\n", win
->hwnd
, names
[operation
] );
1517 case NATIVE_WINDOW_SET_POST_TRANSFORM_CROP
:
1519 FIXME( "unsupported perform hwnd %p op %d %s\n", win
->hwnd
, operation
,
1520 operation
< ARRAY_SIZE( names
) ? names
[operation
] : "???" );
1524 return android_ioctl( IOCTL_PERFORM
, &perf
, sizeof(perf
), NULL
, NULL
);
1527 struct ANativeWindow
*create_ioctl_window( HWND hwnd
, BOOL opengl
, float scale
)
1529 struct ioctl_android_create_window req
;
1530 struct native_win_wrapper
*win
= calloc( 1, sizeof(*win
) );
1532 if (!win
) return NULL
;
1534 win
->win
.common
.magic
= ANDROID_NATIVE_WINDOW_MAGIC
;
1535 win
->win
.common
.version
= sizeof(ANativeWindow
);
1536 win
->win
.common
.incRef
= win_incRef
;
1537 win
->win
.common
.decRef
= win_decRef
;
1538 win
->win
.setSwapInterval
= setSwapInterval
;
1539 win
->win
.dequeueBuffer_DEPRECATED
= dequeueBuffer_DEPRECATED
;
1540 win
->win
.lockBuffer_DEPRECATED
= lockBuffer_DEPRECATED
;
1541 win
->win
.queueBuffer_DEPRECATED
= queueBuffer_DEPRECATED
;
1542 win
->win
.query
= query
;
1543 win
->win
.perform
= perform
;
1544 win
->win
.cancelBuffer_DEPRECATED
= cancelBuffer_DEPRECATED
;
1545 win
->win
.dequeueBuffer
= dequeueBuffer
;
1546 win
->win
.queueBuffer
= queueBuffer
;
1547 win
->win
.cancelBuffer
= cancelBuffer
;
1550 win
->opengl
= opengl
;
1551 TRACE( "-> %p %p opengl=%u\n", win
, win
->hwnd
, opengl
);
1553 req
.hdr
.hwnd
= HandleToLong( win
->hwnd
);
1554 req
.hdr
.opengl
= win
->opengl
;
1555 req
.parent
= get_ioctl_win_parent( NtUserGetAncestor( hwnd
, GA_PARENT
));
1557 android_ioctl( IOCTL_CREATE_WINDOW
, &req
, sizeof(req
), NULL
, NULL
);
1562 struct ANativeWindow
*grab_ioctl_window( struct ANativeWindow
*window
)
1564 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1565 InterlockedIncrement( &win
->ref
);
1569 void release_ioctl_window( struct ANativeWindow
*window
)
1571 struct native_win_wrapper
*win
= (struct native_win_wrapper
*)window
;
1574 if (InterlockedDecrement( &win
->ref
) > 0) return;
1576 TRACE( "%p %p\n", win
, win
->hwnd
);
1577 for (i
= 0; i
< ARRAY_SIZE( win
->buffers
); i
++)
1578 if (win
->buffers
[i
]) win
->buffers
[i
]->buffer
.common
.decRef( &win
->buffers
[i
]->buffer
.common
);
1580 destroy_ioctl_window( win
->hwnd
, win
->opengl
);
1584 void destroy_ioctl_window( HWND hwnd
, BOOL opengl
)
1586 struct ioctl_android_destroy_window req
;
1588 req
.hdr
.hwnd
= HandleToLong( hwnd
);
1589 req
.hdr
.opengl
= opengl
;
1590 android_ioctl( IOCTL_DESTROY_WINDOW
, &req
, sizeof(req
), NULL
, NULL
);
1593 int ioctl_window_pos_changed( HWND hwnd
, const RECT
*window_rect
, const RECT
*client_rect
,
1594 const RECT
*visible_rect
, UINT style
, UINT flags
, HWND after
, HWND owner
)
1596 struct ioctl_android_window_pos_changed req
;
1598 req
.hdr
.hwnd
= HandleToLong( hwnd
);
1599 req
.hdr
.opengl
= FALSE
;
1600 req
.window_rect
= *window_rect
;
1601 req
.client_rect
= *client_rect
;
1602 req
.visible_rect
= *visible_rect
;
1605 req
.after
= HandleToLong( after
);
1606 req
.owner
= HandleToLong( owner
);
1607 return android_ioctl( IOCTL_WINDOW_POS_CHANGED
, &req
, sizeof(req
), NULL
, NULL
);
1610 int ioctl_set_window_parent( HWND hwnd
, HWND parent
, float scale
)
1612 struct ioctl_android_set_window_parent req
;
1614 req
.hdr
.hwnd
= HandleToLong( hwnd
);
1615 req
.hdr
.opengl
= FALSE
;
1616 req
.parent
= get_ioctl_win_parent( parent
);
1618 return android_ioctl( IOCTL_SET_WINDOW_PARENT
, &req
, sizeof(req
), NULL
, NULL
);
1621 int ioctl_set_capture( HWND hwnd
)
1623 struct ioctl_android_set_capture req
;
1625 req
.hdr
.hwnd
= HandleToLong( hwnd
);
1626 req
.hdr
.opengl
= FALSE
;
1627 return android_ioctl( IOCTL_SET_CAPTURE
, &req
, sizeof(req
), NULL
, NULL
);
1630 int ioctl_set_cursor( int id
, int width
, int height
,
1631 int hotspotx
, int hotspoty
, const unsigned int *bits
)
1633 struct ioctl_android_set_cursor
*req
;
1634 unsigned int size
= offsetof( struct ioctl_android_set_cursor
, bits
[width
* height
] );
1637 if (!(req
= malloc( size
))) return -ENOMEM
;
1638 req
->hdr
.hwnd
= 0; /* unused */
1639 req
->hdr
.opengl
= FALSE
;
1642 req
->height
= height
;
1643 req
->hotspotx
= hotspotx
;
1644 req
->hotspoty
= hotspoty
;
1645 memcpy( req
->bits
, bits
, width
* height
* sizeof(req
->bits
[0]) );
1646 ret
= android_ioctl( IOCTL_SET_CURSOR
, req
, size
, NULL
, NULL
);