Merge "[API] Add vm_payload API to get APK contents path"
diff --git a/microdroid/vm_payload/Android.bp b/microdroid/vm_payload/Android.bp
index dc314ce..eeca1c1 100644
--- a/microdroid/vm_payload/Android.bp
+++ b/microdroid/vm_payload/Android.bp
@@ -13,6 +13,7 @@
         "libandroid_logger",
         "libanyhow",
         "libbinder_rs",
+        "liblazy_static",
         "liblog_rust",
         "librpcbinder_rs",
     ],
diff --git a/microdroid/vm_payload/include/vm_payload.h b/microdroid/vm_payload/include/vm_payload.h
index dc01662..2aeb44e 100644
--- a/microdroid/vm_payload/include/vm_payload.h
+++ b/microdroid/vm_payload/include/vm_payload.h
@@ -96,6 +96,17 @@
  */
 bool AVmPayload_getDiceAttestationCdi(void *data, size_t size, size_t *total);
 
+/**
+ * Gets the path to the APK contents. It is a directory, under which are
+ * the unzipped contents of the APK containing the payload, all read-only
+ * but accessible to the payload.
+ *
+ * \return the path to the APK contents. The returned string should not be
+ * deleted or freed by the application. The string remains valid for the
+ * lifetime of the VM.
+ */
+const char *AVmPayload_getApkContentsPath(void);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/microdroid/vm_payload/src/vm_payload_service.rs b/microdroid/vm_payload/src/vm_payload_service.rs
index bec4fde..b0dd891 100644
--- a/microdroid/vm_payload/src/vm_payload_service.rs
+++ b/microdroid/vm_payload/src/vm_payload_service.rs
@@ -15,12 +15,19 @@
 //! This module handles the interaction with virtual machine payload service.
 
 use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
-    IVmPayloadService, VM_PAYLOAD_SERVICE_NAME};
+    IVmPayloadService, VM_PAYLOAD_SERVICE_NAME, VM_APK_CONTENTS_PATH};
 use anyhow::{Context, Result};
 use binder::{wait_for_interface, Strong, unstable_api::{AIBinder, new_spibinder}};
+use lazy_static::lazy_static;
 use log::{error, info, Level};
 use rpcbinder::run_vsock_rpc_server;
-use std::os::raw::c_void;
+use std::ffi::CString;
+use std::os::raw::{c_char, c_void};
+
+lazy_static! {
+    static ref VM_APK_CONTENTS_PATH_C: CString =
+        CString::new(VM_APK_CONTENTS_PATH).expect("CString::new failed");
+}
 
 /// Notifies the host that the payload is ready.
 /// Returns true if the notification succeeds else false.
@@ -185,6 +192,12 @@
     }
 }
 
+/// Gets the path to the APK contents.
+#[no_mangle]
+pub extern "C" fn AVmPayload_getApkContentsPath() -> *const c_char {
+    (*VM_APK_CONTENTS_PATH_C).as_ptr()
+}
+
 fn try_get_dice_attestation_cdi() -> Result<Vec<u8>> {
     get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
 }
diff --git a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
index 4dd3db6..4823bb8 100644
--- a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
+++ b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
@@ -24,6 +24,9 @@
     /** Name of the service IVmPayloadService. */
     const String VM_PAYLOAD_SERVICE_NAME = "virtual_machine_payload_service";
 
+    /** Path to the APK contents path. */
+    const String VM_APK_CONTENTS_PATH = "/mnt/apk";
+
     /** Notifies that the payload is ready to serve. */
     void notifyPayloadReady();
 
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index e42f159..b8e85e7 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -33,6 +33,7 @@
     VirtualMachineCpuStatus::VirtualMachineCpuStatus,
     VirtualMachineMemStatus::VirtualMachineMemStatus,
 };
+use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::VM_APK_CONTENTS_PATH;
 use anyhow::{anyhow, bail, ensure, Context, Error, Result};
 use apkverify::{get_public_key_der, verify, V4Signature};
 use binder::{ProcessState, Strong};
@@ -398,7 +399,7 @@
         MountForExec::Allowed,
         "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
         Path::new("/dev/block/mapper/microdroid-apk"),
-        Path::new("/mnt/apk"),
+        Path::new(VM_APK_CONTENTS_PATH),
         Some(APK_MOUNT_DONE_PROP),
     )
     .context("Failed to run zipfuse")?;
@@ -824,7 +825,7 @@
     let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
     let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
     let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
-    let path = format!("/mnt/apk/lib/{}/{}", abi, name);
+    let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
 
     let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
     if !metadata.is_file() {
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index ebb2bcf..e8c435f 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -33,4 +33,7 @@
 
     /* get the VM's boot certificate chain (BCC). */
     byte[] getBcc();
+
+    /* get the APK contents path. */
+    String getApkContentsPath();
 }
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 5c9cf42..c4296df 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -111,6 +111,7 @@
         assertThat(testResults.mAddInteger).isEqualTo(123 + 456);
         assertThat(testResults.mAppRunProp).isEqualTo("true");
         assertThat(testResults.mSublibRunProp).isEqualTo("true");
+        assertThat(testResults.mApkContentsPath).isEqualTo("/mnt/apk");
     }
 
     @Test
@@ -538,6 +539,7 @@
         String mAppRunProp;
         String mSublibRunProp;
         String mExtraApkTestProp;
+        String mApkContentsPath;
     }
 
     private TestResults runVmTestService(VirtualMachine vm) throws Exception {
@@ -557,6 +559,7 @@
                                     testService.readProperty("debug.microdroid.app.sublib.run");
                             testResults.mExtraApkTestProp =
                                     testService.readProperty("debug.microdroid.test.extra_apk");
+                            testResults.mApkContentsPath = testService.getApkContentsPath();
                         } catch (Exception e) {
                             testResults.mException = e;
                         }
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index d57d224..1a3e940 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -112,6 +112,17 @@
             }
             return ndk::ScopedAStatus::ok();
         }
+
+        ndk::ScopedAStatus getApkContentsPath(std::string* out) override {
+            const char* path_c = AVmPayload_getApkContentsPath();
+            if (path_c == nullptr) {
+                return ndk::ScopedAStatus::
+                        fromServiceSpecificErrorWithMessage(0, "Failed to get APK contents path");
+            }
+            std::string path(path_c);
+            *out = path;
+            return ndk::ScopedAStatus::ok();
+        }
     };
     auto testService = ndk::SharedRefBase::make<TestService>();