compsvc/pvm_exec: Support RPC binder

Bug: 190547489
Bug: 189947807
Test: [VM shell] /apex/com.android.compos/bin/compsvc \
          /system/bin/touch --rpc-binder
      [Android shell] /apex/com.android.compos/bin/pvm_exec --cid $CID \
              touch /data/local/tmp/foo
      # IPC did go through, but there is some unrelated problem in the
      # service, which can be fixed separately.

Change-Id: Ie3cdd58be1f98f8084b2b63dd325b76546bc5cf9
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index ddfcea0..16c3510 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -29,7 +29,8 @@
 //!     - actual task
 
 use anyhow::{bail, Context, Result};
-use log::error;
+use binder::unstable_api::AsNative;
+use log::{debug, error};
 use minijail::{self, Minijail};
 use std::path::PathBuf;
 
@@ -42,7 +43,9 @@
     StatusCode, Strong,
 };
 
-const SERVICE_NAME: &str = "compsvc";
+mod common;
+use common::{SERVICE_NAME, VSOCK_PORT};
+
 const WORKER_BIN: &str = "/apex/com.android.compos/bin/compsvc_worker";
 // TODO: Replace with a valid directory setup in the VM.
 const AUTHFS_MOUNTPOINT: &str = "/data/local/tmp/authfs_mnt";
@@ -50,6 +53,7 @@
 struct CompService {
     worker_bin: PathBuf,
     task_bin: String,
+    rpc_binder: bool,
     debuggable: bool,
 }
 
@@ -128,11 +132,14 @@
              .long("debug"))
         .arg(clap::Arg::with_name("task_bin")
              .required(true))
+        .arg(clap::Arg::with_name("rpc_binder")
+             .long("rpc-binder"))
         .get_matches();
 
     Ok(CompService {
         task_bin: matches.value_of("task_bin").unwrap().to_string(),
         worker_bin: PathBuf::from(WORKER_BIN),
+        rpc_binder: matches.is_present("rpc_binder"),
         debuggable: matches.is_present("debug"),
     })
 }
@@ -144,10 +151,29 @@
 
     let service = parse_args()?;
 
-    ProcessState::start_thread_pool();
-    // TODO: switch to remote binder
-    add_service(SERVICE_NAME, CompService::new_binder(service).as_binder())
-        .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?;
-    ProcessState::join_thread_pool();
-    bail!("Unexpected exit after join_thread_pool")
+    if service.rpc_binder {
+        let mut service = CompService::new_binder(service).as_binder();
+        debug!("compsvc is starting as a rpc service.");
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        let retval = unsafe {
+            binder_rpc_unstable_bindgen::RunRpcServer(
+                service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder,
+                VSOCK_PORT,
+            )
+        };
+        if retval {
+            debug!("RPC server has shut down gracefully");
+            Ok(())
+        } else {
+            bail!("Premature termination of RPC server");
+        }
+    } else {
+        ProcessState::start_thread_pool();
+        debug!("compsvc is starting as a local service.");
+        add_service(SERVICE_NAME, CompService::new_binder(service).as_binder())
+            .with_context(|| format!("Failed to register service {}", SERVICE_NAME))?;
+        ProcessState::join_thread_pool();
+        bail!("Unexpected exit after join_thread_pool")
+    }
 }