Make SecurityException being detected in nativeSpawn

When android.permission.MANAGE_VIRTUAL_MACHINE isn't granted to the app,
framework API should throw SecurityException for permission check. After
granting CAP_SYS_NICE to virtmgr, connection is not made between virtmgr
and Java framework side. This change does sending any single character
from virtmgr through readyFd-waitFd pipe, so that nativeSpawn function
of framework side can detect if connection is healthy, before trying to
create actual binder connection. And this health check can leave more
descriptive error with throwing Security Exception.

Bug: 328051532
Test: atest MicrodroidTestAppNoPerm
Test: atest MicrodroidTestApp
Change-Id: Iee246a136459fbf30e21a480fc9f8a786711324f
diff --git a/java/framework/src/android/system/virtualmachine/VirtualizationService.java b/java/framework/src/android/system/virtualmachine/VirtualizationService.java
index 9063fa6..83b64ee 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualizationService.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualizationService.java
@@ -69,9 +69,7 @@
 
         IBinder binder = nativeConnect(mClientFd.getFd());
         if (binder == null) {
-            throw new SecurityException(
-                    "Could not connect to Virtualization Manager. Please consider checking"
-                            + " android.permission.MANAGE_VIRTUAL_MACHINE permission");
+            throw new VirtualMachineException("Could not connect to Virtualization Manager");
         }
         mBinder = IVirtualizationService.Stub.asInterface(binder);
     }
diff --git a/java/jni/android_system_virtualmachine_VirtualizationService.cpp b/java/jni/android_system_virtualmachine_VirtualizationService.cpp
index 4f02112..ced2079 100644
--- a/java/jni/android_system_virtualmachine_VirtualizationService.cpp
+++ b/java/jni/android_system_virtualmachine_VirtualizationService.cpp
@@ -67,10 +67,16 @@
 
     // Wait for the server to signal its readiness by closing its end of the pipe.
     char buf;
-    if (read(waitFd.get(), &buf, sizeof(buf)) < 0) {
+    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();
diff --git a/virtualizationmanager/src/main.rs b/virtualizationmanager/src/main.rs
index b2a734a..a31fd0a 100644
--- a/virtualizationmanager/src/main.rs
+++ b/virtualizationmanager/src/main.rs
@@ -30,10 +30,10 @@
 use lazy_static::lazy_static;
 use log::{info, LevelFilter};
 use rpcbinder::{FileDescriptorTransportMode, RpcServer};
-use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};
+use std::os::unix::io::{AsFd, FromRawFd, OwnedFd, RawFd};
 use clap::Parser;
 use nix::fcntl::{fcntl, F_GETFD, F_SETFD, FdFlag};
-use nix::unistd::{Pid, Uid};
+use nix::unistd::{write, Pid, Uid};
 use std::os::unix::raw::{pid_t, uid_t};
 
 const LOG_TAG: &str = "virtmgr";
@@ -138,6 +138,8 @@
     info!("Started VirtualizationService RpcServer. Ready to accept connections");
 
     // Signal readiness to the caller by closing our end of the pipe.
+    write(ready_fd.as_fd(), "o".as_bytes())
+        .expect("Failed to write a single character through ready_fd");
     drop(ready_fd);
 
     server.join();