Merge "[LSC] Add LOCAL_LICENSE_KINDS to packages/modules/Virtualization"
diff --git a/binder_common/lazy_service.rs b/binder_common/lazy_service.rs
index a2b85db..9d605b6 100644
--- a/binder_common/lazy_service.rs
+++ b/binder_common/lazy_service.rs
@@ -17,7 +17,7 @@
 //! Rust API for lazy (aka dynamic) AIDL services.
 //! See https://source.android.com/devices/architecture/aidl/dynamic-aidl.
 
-use binder::public_api::force_lazy_services_persist;
+use binder::force_lazy_services_persist;
 use lazy_static::lazy_static;
 use std::sync::Mutex;
 
diff --git a/binder_common/lib.rs b/binder_common/lib.rs
index fa91f5a..fd81da5 100644
--- a/binder_common/lib.rs
+++ b/binder_common/lib.rs
@@ -20,7 +20,7 @@
 pub mod rpc_client;
 pub mod rpc_server;
 
-use binder::public_api::{ExceptionCode, Status};
+use binder::{ExceptionCode, Status};
 use std::ffi::CString;
 
 /// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
diff --git a/binder_common/rpc_client.rs b/binder_common/rpc_client.rs
index 262a689..1aabe84 100644
--- a/binder_common/rpc_client.rs
+++ b/binder_common/rpc_client.rs
@@ -16,14 +16,14 @@
 
 //! Helpers for implementing an RPC Binder client.
 
-use binder::public_api::{StatusCode, Strong};
 use binder::unstable_api::{new_spibinder, AIBinder};
+use binder::{StatusCode, Strong};
 
 /// Connects to a binder RPC server.
 pub fn connect_rpc_binder<T: binder::FromIBinder + ?Sized>(
     cid: u32,
     port: u32,
-) -> binder::Result<Strong<T>> {
+) -> Result<Strong<T>, StatusCode> {
     // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can be
     // safely taken by new_spibinder.
     let ibinder = unsafe {
diff --git a/binder_common/rpc_server.rs b/binder_common/rpc_server.rs
index 36075cf..5c9d2a0 100644
--- a/binder_common/rpc_server.rs
+++ b/binder_common/rpc_server.rs
@@ -16,8 +16,8 @@
 
 //! Helpers for implementing an RPC Binder server.
 
-use binder::public_api::SpIBinder;
 use binder::unstable_api::AsNative;
+use binder::SpIBinder;
 use std::os::raw;
 
 /// Run a binder RPC server, serving the supplied binder service implementation on the given vsock
diff --git a/compos/aidl/com/android/compos/FdAnnotation.aidl b/compos/aidl/com/android/compos/FdAnnotation.aidl
deleted file mode 100644
index b910391..0000000
--- a/compos/aidl/com/android/compos/FdAnnotation.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compos;
-
-/** {@hide} */
-parcelable FdAnnotation {
-    /**
-     * Input file descriptor numbers to be passed to the program.  This is currently assumed to be
-     * same as the file descriptor number used in the backend server.
-     */
-    int[] input_fds;
-
-    /**
-     * Output file descriptor numbers to be passed to the program.  This is currently assumed to be
-     * same as the file descriptor number used in the backend server.
-     */
-    int[] output_fds;
-}
diff --git a/compos/aidl/com/android/compos/ICompOsService.aidl b/compos/aidl/com/android/compos/ICompOsService.aidl
index b2b961a..39e9d61 100644
--- a/compos/aidl/com/android/compos/ICompOsService.aidl
+++ b/compos/aidl/com/android/compos/ICompOsService.aidl
@@ -17,7 +17,6 @@
 package com.android.compos;
 
 import com.android.compos.CompOsKeyData;
-import com.android.compos.FdAnnotation;
 
 /** {@hide} */
 interface ICompOsService {
@@ -51,21 +50,6 @@
             String zygoteArch, String systemServerCompilerFilter);
 
     /**
-     * Runs dexopt compilation encoded in the marshaled dexopt arguments.
-     *
-     * To keep ART indepdendantly updatable, the compilation arguments are not stabilized. As a
-     * result, the arguments are marshaled into byte array.  Upon received, the service asks ART to
-     * return relevant information (since ART is able to unmarshal its own encoding), in order to
-     * set up the execution context (mainly file descriptors for compiler input and output) then
-     * invokes the compiler.
-     *
-     * @param marshaledArguments The marshaled dexopt arguments.
-     * @param fd_annotation Additional file descriptor information of the execution.
-     * @return exit code
-     */
-    byte compile(in byte[] marshaledArguments, in FdAnnotation fd_annotation);
-
-    /**
      * Generate a new public/private key pair suitable for signing CompOs output files.
      *
      * @return a certificate for the public key and the encrypted private key
diff --git a/compos/common/binder.rs b/compos/common/binder.rs
index 6bd3957..ae857e0 100644
--- a/compos/common/binder.rs
+++ b/compos/common/binder.rs
@@ -17,7 +17,7 @@
 //! Helper for converting Error types to what Binder expects
 
 use anyhow::Result;
-use binder::public_api::{ExceptionCode, Result as BinderResult};
+use binder::{ExceptionCode, Result as BinderResult};
 use binder_common::new_binder_exception;
 use log::warn;
 use std::fmt::Debug;
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index 356cc7e..b4af9b5 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -32,7 +32,6 @@
 use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::IAuthFsService;
 use compos_aidl_interface::aidl::com::android::compos::{
     CompOsKeyData::CompOsKeyData,
-    FdAnnotation::FdAnnotation,
     ICompOsService::{BnCompOsService, ICompOsService},
 };
 use compos_aidl_interface::binder::{
@@ -113,10 +112,6 @@
         Ok(exit_code as i8)
     }
 
-    fn compile(&self, _marshaled: &[u8], _fd_annotation: &FdAnnotation) -> BinderResult<i8> {
-        Err(new_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION, "Not yet implemented"))
-    }
-
     fn generateSigningKey(&self) -> BinderResult<CompOsKeyData> {
         to_binder_result(self.key_service.generate())
     }
diff --git a/microdroid_manager/src/payload.rs b/microdroid_manager/src/payload.rs
index 8ec6f74..b731d33 100644
--- a/microdroid_manager/src/payload.rs
+++ b/microdroid_manager/src/payload.rs
@@ -14,6 +14,8 @@
 
 //! Routines for handling payload
 
+mod apex;
+
 use crate::instance::ApexData;
 use crate::ioutil::wait_for_file;
 use anyhow::Result;
@@ -61,5 +63,3 @@
         ..Default::default()
     }
 }
-
-mod apex;
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index cdcb2bd..208d61f 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -21,4 +21,7 @@
 
     /* add two integers. */
     int addInteger(int a, int b);
+
+    /* read a system property. */
+    String readProperty(String prop);
 }
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index 69638d8..6aa7566 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -97,15 +97,6 @@
         final String label = "u:object_r:system_file:s0";
         assertThat(runOnMicrodroid("ls", "-Z", testLib), is(label + " " + testLib));
 
-        // Check if the command in vm_config.json was executed by examining the side effect of the
-        // command
-        assertThat(runOnMicrodroid("getprop", "debug.microdroid.app.run"), is("true"));
-        assertThat(runOnMicrodroid("getprop", "debug.microdroid.app.sublib.run"), is("true"));
-
-        // Check that keystore was found by the payload. Wait until the property is set.
-        tryRunOnMicrodroid("watch -e \"getprop debug.microdroid.test.keystore | grep '^$'\"");
-        assertThat(runOnMicrodroid("getprop", "debug.microdroid.test.keystore"), is("PASS"));
-
         // Check that no denials have happened so far
         assertThat(runOnMicrodroid("logcat -d -e 'avc:[[:space:]]{1,2}denied'"), is(""));
 
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 32c47dd..6cd16c2 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -9,6 +9,7 @@
     static_libs: [
         "androidx.test.runner",
         "androidx.test.ext.junit",
+        "com.android.microdroid.testservice-java",
     ],
     libs: ["android.system.virtualmachine"],
     jni_libs: ["MicrodroidTestNativeLib"],
@@ -29,6 +30,11 @@
         "libbinder_rpc_unstable",
         "MicrodroidTestNativeLibSub",
     ],
+    static_libs: [
+        "libfsverity_digests_proto_cc",
+        "liblog",
+        "libprotobuf-cpp-lite-ndk",
+    ],
 }
 
 cc_library_shared {
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 b03a915..032ecfd 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -17,8 +17,10 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeNoException;
 import static org.junit.Assume.assumeThat;
 
@@ -26,6 +28,7 @@
 
 import android.content.Context;
 import android.os.Build;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.system.virtualmachine.VirtualMachine;
 import android.system.virtualmachine.VirtualMachineCallback;
@@ -36,6 +39,8 @@
 
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.microdroid.testservice.ITestService;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -49,6 +54,7 @@
 import java.nio.file.Files;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 @RunWith(JUnit4.class)
@@ -132,9 +138,10 @@
     private static final int MIN_MEM_X86_64 = 196;
 
     @Test
-    public void startAndStop() throws VirtualMachineException, InterruptedException {
+    public void connectToVmService() throws VirtualMachineException, InterruptedException {
         VirtualMachineConfig.Builder builder =
-                new VirtualMachineConfig.Builder(mInner.mContext, "assets/vm_config.json");
+                new VirtualMachineConfig.Builder(mInner.mContext,
+                        "assets/vm_config_extra_apk.json");
         if (Build.SUPPORTED_ABIS.length > 0) {
             String primaryAbi = Build.SUPPORTED_ABIS[0];
             switch(primaryAbi) {
@@ -148,24 +155,55 @@
         }
         VirtualMachineConfig config = builder.build();
 
-        mInner.mVm = mInner.mVmm.getOrCreate("test_vm", config);
+        mInner.mVm = mInner.mVmm.getOrCreate("test_vm_extra_apk", config);
         VmEventListener listener =
                 new VmEventListener() {
                     private boolean mPayloadReadyCalled = false;
                     private boolean mPayloadStartedCalled = false;
 
-                    @Override
-                    public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
-                        mPayloadStartedCalled = true;
+                    private void testVMService(Future<IBinder> service) {
+                        try {
+                            IBinder binder = service.get();
+
+                            ITestService testService = ITestService.Stub.asInterface(binder);
+                            assertEquals(
+                                    testService.addInteger(123, 456),
+                                    123 + 456);
+                            assertEquals(
+                                    testService.readProperty("debug.microdroid.app.run"),
+                                    "true");
+                            assertEquals(
+                                    testService.readProperty("debug.microdroid.app.sublib.run"),
+                                    "true");
+                            assertEquals(
+                                    testService.readProperty("debug.microdroid.test.keystore"),
+                                    "PASS");
+                            assertEquals(
+                                    testService.readProperty("debug.microdroid.test.extra_apk"),
+                                    "PASS");
+                        } catch (Exception e) {
+                            fail("Exception while testing service: " + e.toString());
+                        }
                     }
 
                     @Override
                     public void onPayloadReady(VirtualMachine vm) {
                         mPayloadReadyCalled = true;
+                        try {
+                            testVMService(vm.connectToVsockServer(ITestService.SERVICE_PORT));
+                        } catch (Exception e) {
+                            fail("Exception while connecting to service: " + e.toString());
+                        }
+
                         forceStop(vm);
                     }
 
                     @Override
+                    public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
+                        mPayloadStartedCalled = true;
+                    }
+
+                    @Override
                     public void onDied(VirtualMachine vm, @DeathReason int reason) {
                         assertTrue(mPayloadReadyCalled);
                         assertTrue(mPayloadStartedCalled);
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index f56b261..c748b2a 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -16,11 +16,14 @@
 #include <aidl/android/system/keystore2/IKeystoreService.h>
 #include <aidl/android/system/virtualmachineservice/IVirtualMachineService.h>
 #include <aidl/com/android/microdroid/testservice/BnTestService.h>
+#include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/result.h>
 #include <android-base/unique_fd.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_manager.h>
 #include <fcntl.h>
+#include <fsverity_digests.pb.h>
 #include <linux/vm_sockets.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -29,6 +32,7 @@
 #include <unistd.h>
 
 #include <binder_rpc_unstable.hpp>
+#include <string>
 
 using aidl::android::hardware::security::keymint::Algorithm;
 using aidl::android::hardware::security::keymint::Digest;
@@ -191,8 +195,8 @@
         outcome << "PASS";
     } else {
         outcome << "FAIL: " << result.error();
-        // Pollute stdout with the error in case the property is truncated.
-        std::cout << "[" << name << "] test failed: " << result.error() << "\n";
+        // Pollute stderr with the error in case the property is truncated.
+        std::cerr << "[" << name << "] test failed: " << result.error() << "\n";
     }
     __system_property_set(property.c_str(), outcome.str().c_str());
     return result;
@@ -204,6 +208,17 @@
             *out = a + b;
             return ndk::ScopedAStatus::ok();
         }
+
+        ndk::ScopedAStatus readProperty(const std::string& prop, std::string* out) override {
+            *out = android::base::GetProperty(prop, "");
+            if (out->empty()) {
+                std::string msg = "cannot find property " + prop;
+                return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+                                                                        msg.c_str());
+            }
+
+            return ndk::ScopedAStatus::ok();
+        }
     };
     auto testService = ndk::SharedRefBase::make<TestService>();
 
@@ -230,6 +245,21 @@
     return {};
 }
 
+Result<void> verify_apk() {
+    const char* path = "/mnt/extra-apk/0/assets/build_manifest.pb";
+
+    std::string str;
+    if (!android::base::ReadFileToString(path, &str)) {
+        return ErrnoError() << "failed to read build_manifest.pb";
+    }
+
+    if (!android::security::fsverity::FSVerityDigests().ParseFromString(str)) {
+        return Error() << "invalid build_manifest.pb";
+    }
+
+    return {};
+}
+
 } // Anonymous namespace
 
 extern "C" int android_native_main(int argc, char* argv[]) {
@@ -249,6 +279,9 @@
     testlib_sub();
     printf("\n");
 
+    // Extra apks may be missing; this is not a fatal error
+    report_test("extra_apk", verify_apk());
+
     __system_property_set("debug.microdroid.app.run", "true");
     if (!report_test("keystore", test_keystore()).ok()) return 1;
 
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index a8c22cd..84d3b2f 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -374,6 +374,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
+
     #[test]
     fn test_find_apex_names_in_classpath() {
         let vars = r#"
@@ -387,4 +388,35 @@
 
         assert_eq!(find_apex_names_in_classpath(vars).unwrap(), expected);
     }
+
+    #[test]
+    fn test_collect_apex_names() {
+        let apex_list = ApexInfoList {
+            list: vec![
+                ApexInfo {
+                    name: "hasnt_classpath".to_string(),
+                    path: PathBuf::from("path0"),
+                    has_classpath_jar: false,
+                },
+                ApexInfo {
+                    name: "has_classpath".to_string(),
+                    path: PathBuf::from("path1"),
+                    has_classpath_jar: true,
+                },
+            ],
+        };
+        let apexes = vec![
+            ApexConfig { name: "config_name".to_string() },
+            ApexConfig { name: "{CLASSPATH}".to_string() },
+        ];
+        assert_eq!(
+            collect_apex_names(&apex_list, &apexes, DebugLevel::FULL),
+            vec![
+                "com.android.adbd".to_string(),
+                "com.android.os.statsd".to_string(),
+                "config_name".to_string(),
+                "has_classpath".to_string(),
+            ]
+        );
+    }
 }