Framework JNI uses libvmclient to connect to virtmgr

libvmclient, as its name shows, is a library designed as a client-side
library for AVF. It is responsible for spawning virtmgr and make a
connection to it.

However, the library wasn't used for the Java APIs. For those APIs, the
JNI part (libvirtualization_jni) implemented the almost identical
routine for spawning virtmgr.

This change de-duplicates the code in the JNI part by exposing an FFI
for libvmclient and let the JNI part use it.

Note that the JNI part had more checks at the end of the connection
establishment. That part is copied over to libvmclient.

Bug: N/A
Test: watch TH

Change-Id: Ib6b0f3a180a7dbd4c797188e98d4b0e66f76423b
diff --git a/libs/libvirtualization_jni/Android.bp b/libs/libvirtualization_jni/Android.bp
index 4a569d4..9dc86b0 100644
--- a/libs/libvirtualization_jni/Android.bp
+++ b/libs/libvirtualization_jni/Android.bp
@@ -16,7 +16,10 @@
         "liblog",
         "libnativehelper",
     ],
-    static_libs: ["libavf_cc_flags"],
+    static_libs: [
+        "libavf_cc_flags",
+        "libvmclient.ffi",
+    ],
 }
 
 cc_library_shared {
diff --git a/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp b/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp
index 0538c9e..f0c9b4f 100644
--- a/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp
+++ b/libs/libvirtualization_jni/android_system_virtualmachine_VirtualizationService.cpp
@@ -19,6 +19,7 @@
 #include <android-base/unique_fd.h>
 #include <android/avf_cc_flags.h>
 #include <android/binder_ibinder_jni.h>
+#include <errno.h>
 #include <jni.h>
 #include <log/log.h>
 #include <poll.h>
@@ -29,57 +30,25 @@
 
 using namespace android::base;
 
-static constexpr const char VIRTMGR_PATH[] = "/apex/com.android.virt/bin/virtmgr";
 static constexpr size_t VIRTMGR_THREADS = 2;
 
+void error_callback(int code, const char* msg, void* ctx) {
+    JNIEnv* env = reinterpret_cast<JNIEnv*>(ctx);
+    if (code == EPERM || code == EACCES) {
+        env->ThrowNew(env->FindClass("java/lang/SecurityException"),
+                      "Virtmgr didn't send any data through pipe. Please consider checking if "
+                      "android.permission.MANAGE_VIRTUAL_MACHINE permission is granted");
+        return;
+    }
+    env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"), msg);
+}
+
+extern "C" int get_virtualization_service(decltype(error_callback)*, void*);
+
 extern "C" JNIEXPORT jint JNICALL
 Java_android_system_virtualmachine_VirtualizationService_nativeSpawn(
         JNIEnv* env, [[maybe_unused]] jclass clazz) {
-    unique_fd serverFd, clientFd;
-    if (!Socketpair(SOCK_STREAM, &serverFd, &clientFd)) {
-        env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
-                      ("Failed to create socketpair: " + std::string(strerror(errno))).c_str());
-        return -1;
-    }
-
-    unique_fd waitFd, readyFd;
-    if (!Pipe(&waitFd, &readyFd, 0)) {
-        env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
-                      ("Failed to create pipe: " + std::string(strerror(errno))).c_str());
-        return -1;
-    }
-
-    if (fork() == 0) {
-        // Close client's FDs.
-        clientFd.reset();
-        waitFd.reset();
-
-        auto strServerFd = std::to_string(serverFd.get());
-        auto strReadyFd = std::to_string(readyFd.get());
-
-        execl(VIRTMGR_PATH, VIRTMGR_PATH, "--rpc-server-fd", strServerFd.c_str(), "--ready-fd",
-              strReadyFd.c_str(), NULL);
-    }
-
-    // Close virtmgr's FDs.
-    serverFd.reset();
-    readyFd.reset();
-
-    // Wait for the server to signal its readiness by closing its end of the pipe.
-    char buf;
-    int ret = read(waitFd.get(), &buf, sizeof(buf));
-    if (ret < 0) {
-        env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
-                      "Failed to wait for VirtualizationService to be ready");
-        return -1;
-    } else if (ret < 1) {
-        env->ThrowNew(env->FindClass("java/lang/SecurityException"),
-                      "Virtmgr didn't send any data through pipe. Please consider checking if "
-                      "android.permission.MANAGE_VIRTUAL_MACHINE permission is granted");
-        return -1;
-    }
-
-    return clientFd.release();
+    return get_virtualization_service(error_callback, env);
 }
 
 extern "C" JNIEXPORT jobject JNICALL