https://bugs.winehq.org/show_bug.cgi?id=56843
Bug ID: 56843 Summary: wineandroid: fixing output on recent android versions. Product: Wine Version: unspecified Hardware: aarch64 OS: Android Status: UNCONFIRMED Severity: normal Priority: P2 Component: -unknown Assignee: wine-bugs@winehq.org Reporter: twaikyont@gmail.com
Currently wineandroid relies on Gralloc V1 which is not an option on recent android versions.
There is other acceptable solution.
You can pass Surface through Binder API so you will get ANativeWindow (or at least Surface which can be converted to ANativeWindow) directly from Activity instead of creating it with broken `alloc_win_data`.
Binder API is not available in regular processes, but you can use it in Java. You can start java code from your Wine apk installed to system like ``` export CLASSPATH=<path to apk> export LD_PRELOAD=<path to apk>!/lib/<ABI>/libwine.so # wher ABI is something you can get with `Build.SUPPORTED_ABIS[0]` /system/bin/app_process / your.class.name :0 ``` And JVM will start the `static void main(String[] args);` from `your.class.name`. Getting path to apk will be like ``` /** * Get the apk path of this application. * @param context any context (e.g. an Activity or a Service) * @return full apk file path, or null if an exception happened (it should not happen) */ public static String getApkName(Context context) { String packageName = context.getPackageName(); PackageManager pm = context.getPackageManager(); try { return pm.getApplicationInfo(packageName, 0).publicSourceDir; } catch (Throwable x) { } return null; } ```
`main` function can be fully native so you can simply pass control to native code right after starting process. Of course wine's main executable should be built as a library to let JVM load it via `System.loadLibrary`
C version of `main` can not use Java's `args` so it should be converted like ``` JNIEXPORT jboolean JNICALL Java_wine_CmdEntryPoint_start(JNIEnv *env, __unused jclass cls, jobjectArray args) { pthread_t t; // execv's argv array is a bit incompatible with Java's String[], so we do some converting here... int argc = (*env)->GetArrayLength(env, args) + 1; // Leading executable path char** argv = (char**) calloc(argc, sizeof(char*));
argv[0] = (char*) "wine"; for(int i=1; i<argc; i++) { jstring js = (jstring)((*env)->GetObjectArrayElement(env, args, i - 1)); const char *pjc = (*env)->GetStringUTFChars(env, js, JNI_FALSE); argv[i] = (char *) calloc(strlen(pjc) + 1, sizeof(char)); //Extra char for the terminating NULL strcpy((char *) argv[i], pjc); (*env)->ReleaseStringUTFChars(env, js, pjc); }
return main(argc, argv); }
```
After this point you will be able to use java code and java Android APIs.
Next step is obtaining Binder connection to your activity. It is not very straightforward but it is possible. Full code will be pretty much long so I will simply put links to my project which works on Android 8+.
Pay attention to functions sendBroadcast and createContext (createContext is used in static block in the end of file). It requires exposing some private Android APIs, but it is not restricted if you are using app_process this way.
https://github.com/termux/termux-x11/blob/master/app/src/main/java/com/termu...
Make sure you are creating thread with performing `Looper.prepareMainLooper();` and `Looper.loop()` to make sure Binder background requests will work fine in static block (to make sure it will work before JVM invokes `main` function, just for case it is `native`).
Next step will be acquiring Surface from Wine's activity. Of course you can create AIDL with single function like `Surface getSurface(int hwnd);` and obtain Surface directly from `alloc_win_data` or simillar function via JNI. But in my cases it did not work. I mean sending request from my process to Activity which should respond with Surface object did not work. But I succeeded passing Surface by sending requst from Activity to my process containing Surface in arguments like `void pushSurface(in Surface surface, int hwnd);`.
Binder request from Activity to your process will work in different thread asyncronously so `alloc_win_data` should send surface request to activity and wait for Binder response or timeout.
I hope I explained everything with enough details. Thank you for your hard work.
https://bugs.winehq.org/show_bug.cgi?id=56843
--- Comment #1 from twaik twaikyont@gmail.com --- Any news? Sorry for up.
https://bugs.winehq.org/show_bug.cgi?id=56843
Fabian Maurer dark.shadow4@web.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |dark.shadow4@web.de
https://bugs.winehq.org/show_bug.cgi?id=56843
André Z. nerv@dawncrow.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |nerv@dawncrow.de
https://bugs.winehq.org/show_bug.cgi?id=56843
twaik twaikyont@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |INVALID
--- Comment #2 from twaik twaikyont@gmail.com --- Ok, I was wrong about how it works, I tried to read wineandroid.drv sources again and failed to understand how ioctl window is transfered between processes.