Merge changes Ia0d74953,I22651063

* changes:
  Add more detailed boot time benchmarks
  Factor out statistics codes
diff --git a/libs/binder_common/rpc_server.rs b/libs/binder_common/rpc_server.rs
index 5c9d2a0..4261358 100644
--- a/libs/binder_common/rpc_server.rs
+++ b/libs/binder_common/rpc_server.rs
@@ -18,14 +18,17 @@
 
 use binder::unstable_api::AsNative;
 use binder::SpIBinder;
-use std::os::raw;
+use std::{os::raw, ptr::null_mut};
 
-/// Run a binder RPC server, serving the supplied binder service implementation on the given vsock
+/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
 /// port.
-/// If and when the server is ready for connections (it is listening on the port) on_ready
-/// is called to allow appropriate action to be taken - e.g. to notify clients they
-/// may now attempt to connect.
+///
+/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
+/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
+/// attempt to connect.
+///
 /// The current thread is joined to the binder thread pool to handle incoming messages.
+///
 /// Returns true if the server has shutdown normally, false if it failed in some way.
 pub fn run_rpc_server<F>(service: SpIBinder, port: u32, on_ready: F) -> bool
 where
@@ -79,3 +82,46 @@
         }
     }
 }
+
+type RpcServerFactoryRef<'a> = &'a mut (dyn FnMut(u32) -> Option<SpIBinder> + Send + Sync);
+
+/// Runs a binder RPC server, using the given factory function to construct a binder service
+/// implementation for each connection.
+///
+/// The current thread is joined to the binder thread pool to handle incoming messages.
+///
+/// Returns true if the server has shutdown normally, false if it failed in some way.
+pub fn run_rpc_server_with_factory(
+    port: u32,
+    mut factory: impl FnMut(u32) -> Option<SpIBinder> + Send + Sync,
+) -> bool {
+    // Double reference the factory because trait objects aren't FFI safe.
+    // NB: The type annotation is necessary to ensure that we have a `dyn` rather than an `impl`.
+    let mut factory_ref: RpcServerFactoryRef = &mut factory;
+    let context = &mut factory_ref as *mut RpcServerFactoryRef as *mut raw::c_void;
+
+    // SAFETY: `factory_wrapper` is only ever called by `RunRpcServerWithFactory`, with context
+    // taking the pointer value above (so a properly aligned non-null pointer to an initialized
+    // `RpcServerFactoryRef`), within the lifetime of `factory_ref` (i.e. no more calls will be made
+    // after `RunRpcServerWithFactory` returns).
+    unsafe {
+        binder_rpc_unstable_bindgen::RunRpcServerWithFactory(Some(factory_wrapper), context, port)
+    }
+}
+
+unsafe extern "C" fn factory_wrapper(
+    cid: u32,
+    context: *mut raw::c_void,
+) -> *mut binder_rpc_unstable_bindgen::AIBinder {
+    // SAFETY: `context` was created from an `&mut RpcServerFactoryRef` by
+    // `run_rpc_server_with_factory`, and we are still within the lifetime of the value it is
+    // pointing to.
+    let factory_ptr = context as *mut RpcServerFactoryRef;
+    let factory = factory_ptr.as_mut().unwrap();
+
+    if let Some(mut service) = factory(cid) {
+        service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder
+    } else {
+        null_mut()
+    }
+}
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 24288ee..b7f34e7 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -22,8 +22,6 @@
         ":test.com.android.virt.pem",
         ":test2.com.android.virt.pem",
         ":test-payload-metadata",
-        ":com.android.adbd{.apex}",
-        ":com.android.os.statsd{.apex}",
     ],
     data_native_bins: [
         "sepolicy-analyze",
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
index c4ea80a..07b8679 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidTestCase.java
@@ -39,6 +39,7 @@
 import com.android.tradefed.util.CommandResult;
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.RunUtil;
+import com.android.tradefed.util.xml.AbstractXmlParser;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -49,7 +50,10 @@
 import org.junit.Test;
 import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -175,9 +179,55 @@
         }
     }
 
+    static class ActiveApexInfo {
+        public String name;
+        public String path;
+        ActiveApexInfo(String name, String path) {
+            this.name = name;
+            this.path = path;
+        }
+    }
+
+    static class ActiveApexInfoList {
+        private List<ActiveApexInfo> mList;
+        ActiveApexInfoList(List<ActiveApexInfo> list) {
+            this.mList = list;
+        }
+        ActiveApexInfo get(String apexName) {
+            for (ActiveApexInfo info: mList) {
+                if (info.name.equals(apexName)) {
+                    return info;
+                }
+            }
+            return null;
+        }
+    }
+
+    private ActiveApexInfoList getActiveApexInfoList() throws Exception {
+        String apexInfoListXml = getDevice().pullFileContents("/apex/apex-info-list.xml");
+        List<ActiveApexInfo> list = new ArrayList<>();
+        new AbstractXmlParser() {
+            @Override
+            protected DefaultHandler createXmlHandler() {
+                return new DefaultHandler() {
+                    @Override
+                    public void startElement(String uri, String localName, String qName,
+                            Attributes attributes) {
+                        if (localName.equals("apex-info")
+                                && attributes.getValue("isActive").equals("true")) {
+                            list.add(new ActiveApexInfo(attributes.getValue("moduleName"),
+                                    attributes.getValue("modulePath")));
+                        }
+                    }
+                };
+            }
+        }.parse(new ByteArrayInputStream(apexInfoListXml.getBytes()));
+        return new ActiveApexInfoList(list);
+    }
+
     private String runMicrodroidWithResignedImages(File key, Map<String, File> keyOverrides,
             boolean isProtected, boolean daemonize, String consolePath)
-            throws DeviceNotAvailableException, IOException, JSONException {
+            throws Exception {
         CommandRunner android = new CommandRunner(getDevice());
 
         File virtApexDir = FileUtil.createTempDir("virt_apex");
@@ -207,11 +257,10 @@
         final String payloadMetadataPath = TEST_ROOT + "payload-metadata.img";
         getDevice().pushFile(findTestFile("test-payload-metadata.img"), payloadMetadataPath);
 
-        // push APEXes required for the VM.
-        final String statsdApexPath = TEST_ROOT + "com.android.os.statsd.apex";
-        final String adbdApexPath = TEST_ROOT + "com.android.adbd.apex";
-        getDevice().pushFile(findTestFile("com.android.os.statsd.apex"), statsdApexPath);
-        getDevice().pushFile(findTestFile("com.android.adbd.apex"), adbdApexPath);
+        // get paths to the two APEXes required for the VM.
+        ActiveApexInfoList list = getActiveApexInfoList();
+        final String statsdApexPath = list.get("com.android.os.statsd").path;
+        final String adbdApexPath = list.get("com.android.adbd").path;
 
         // Since Java APP can't start a VM with a custom image, here, we start a VM using `vm run`
         // command with a VM Raw config which is equiv. to what virtualizationservice creates with
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index 0c9496a..0a5436b 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -26,7 +26,6 @@
         "libandroid_logger",
         "libanyhow",
         "libbinder_common",
-        "libbinder_rpc_unstable_bindgen",
         "libbinder_rs",
         "libcommand_fds",
         "libdisk",
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index e2e76d5..cc8d8a3 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -19,7 +19,6 @@
 use crate::payload::add_microdroid_images;
 use crate::{Cid, FIRST_GUEST_CID, SYSPROP_LAST_CID};
 use crate::selinux::{SeContext, getfilecon};
-use ::binder::unstable_api::AsNative;
 use android_os_permissions_aidl::aidl::android::os::IPermissionController;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
     DeathReason::DeathReason,
@@ -36,8 +35,8 @@
     VirtualMachineState::VirtualMachineState,
 };
 use android_system_virtualizationservice::binder::{
-    self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, StatusCode, Strong,
-    ThreadState,
+    self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, SpIBinder, Status,
+    StatusCode, Strong, ThreadState,
 };
 use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::{
     IVirtualMachineService::{
@@ -46,7 +45,7 @@
     },
 };
 use anyhow::{anyhow, bail, Context, Result};
-use binder_common::{lazy_service::LazyServiceGuard, new_binder_exception};
+use binder_common::{lazy_service::LazyServiceGuard, new_binder_exception, rpc_server::run_rpc_server_with_factory};
 use disk::QcowFile;
 use idsig::{HashAlgorithm, V4Signature};
 use log::{debug, error, info, warn, trace};
@@ -59,10 +58,8 @@
 use std::fs::{create_dir, File, OpenOptions};
 use std::io::{Error, ErrorKind, Write, Read};
 use std::num::NonZeroU32;
-use std::os::raw;
 use std::os::unix::io::{FromRawFd, IntoRawFd};
 use std::path::{Path, PathBuf};
-use std::ptr::null_mut;
 use std::sync::{Arc, Mutex, Weak};
 use tombstoned_client::{TombstonedConnection, DebuggerdDumpType};
 use vmconfig::VmConfig;
@@ -330,28 +327,16 @@
 
         // binder server for vm
         // reference to state (not the state itself) is copied
-        let mut state = service.state.clone();
+        let state = service.state.clone();
         std::thread::spawn(move || {
-            let state_ptr = &mut state as *mut _ as *mut raw::c_void;
-
-            debug!("virtual machine service is starting as an RPC service.");
-            // SAFETY: factory function is only ever called by RunRpcServerWithFactory, within the
-            // lifetime of the state, with context taking the pointer value above (so a properly
-            // aligned non-null pointer to an initialized instance).
-            let retval = unsafe {
-                binder_rpc_unstable_bindgen::RunRpcServerWithFactory(
-                    Some(VirtualMachineService::factory),
-                    state_ptr,
-                    VM_BINDER_SERVICE_PORT as u32,
-                )
-            };
-            if retval {
+            debug!("VirtualMachineService is starting as an RPC service.");
+            if run_rpc_server_with_factory(VM_BINDER_SERVICE_PORT as u32, |cid| {
+                VirtualMachineService::factory(cid, &state)
+            }) {
                 debug!("RPC server has shut down gracefully");
             } else {
-                bail!("Premature termination of RPC server");
+                panic!("Premature termination of RPC server");
             }
-
-            Ok(retval)
         });
         service
     }
@@ -1143,20 +1128,14 @@
 }
 
 impl VirtualMachineService {
-    // SAFETY: Service ownership is held by state, and the binder objects are threadsafe.
-    pub unsafe extern "C" fn factory(
-        cid: Cid,
-        context: *mut raw::c_void,
-    ) -> *mut binder_rpc_unstable_bindgen::AIBinder {
-        let state_ptr = context as *mut Arc<Mutex<State>>;
-        let state = state_ptr.as_ref().unwrap();
+    fn factory(cid: Cid, state: &Arc<Mutex<State>>) -> Option<SpIBinder> {
         if let Some(vm) = state.lock().unwrap().get_vm(cid) {
             let mut vm_service = vm.vm_service.lock().unwrap();
             let service = vm_service.get_or_insert_with(|| Self::new_binder(state.clone(), cid));
-            service.as_binder().as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder
+            Some(service.as_binder())
         } else {
             error!("connection from cid={} is not from a guest VM", cid);
-            null_mut()
+            None
         }
     }