Merge "[LSC] Add LOCAL_LICENSE_KINDS to packages/modules/Virtualization"
diff --git a/authfs/src/main.rs b/authfs/src/main.rs
index 858b099..3bd96f4 100644
--- a/authfs/src/main.rs
+++ b/authfs/src/main.rs
@@ -272,6 +272,8 @@
Path::new("/system/framework/telephony-common.jar"),
Path::new("/system/framework/voip-common.jar"),
Path::new("/system/etc/boot-image.prof"),
+ Path::new("/system/etc/classpaths/bootclasspath.pb"),
+ Path::new("/system/etc/classpaths/systemserverclasspath.pb"),
Path::new("/system/etc/dirty-image-objects"),
];
diff --git a/compos/Android.bp b/compos/Android.bp
index 280956e..ab55efb 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -25,6 +25,7 @@
"libnix",
"libodsign_proto_rust",
"libprotobuf",
+ "libregex",
"libring",
"libscopeguard",
],
diff --git a/compos/aidl/com/android/compos/ICompOsService.aidl b/compos/aidl/com/android/compos/ICompOsService.aidl
index ad37806..1a28a18 100644
--- a/compos/aidl/com/android/compos/ICompOsService.aidl
+++ b/compos/aidl/com/android/compos/ICompOsService.aidl
@@ -33,15 +33,6 @@
void initializeSigningKey(in byte[] keyBlob);
/**
- * Initializes the classpaths necessary for preparing and running compilation.
- *
- * TODO(198211396): Implement properly. We can't simply accepting the classpaths from Android
- * since they are not derived from staged APEX (besides security reasons).
- */
- void initializeClasspaths(String bootClasspath, String dex2oatBootClasspath,
- String systemServerClasspath, String standaloneSystemServerJars);
-
- /**
* Run odrefresh in the VM context.
*
* The execution is based on the VM's APEX mounts, files on Android's /system (by accessing
diff --git a/compos/apk/assets/vm_config.json b/compos/apk/assets/vm_config.json
index d008c12..0e97228 100644
--- a/compos/apk/assets/vm_config.json
+++ b/compos/apk/assets/vm_config.json
@@ -18,7 +18,10 @@
"name": "com.android.compos"
},
{
+ "name": "com.android.sdkext"
+ },
+ {
"name": "{CLASSPATH}"
}
]
-}
\ No newline at end of file
+}
diff --git a/compos/apk/assets/vm_config_staged.json b/compos/apk/assets/vm_config_staged.json
index e42ebe0..5820982 100644
--- a/compos/apk/assets/vm_config_staged.json
+++ b/compos/apk/assets/vm_config_staged.json
@@ -19,7 +19,10 @@
"name": "com.android.compos"
},
{
+ "name": "com.android.sdkext"
+ },
+ {
"name": "{CLASSPATH}"
}
]
-}
\ No newline at end of file
+}
diff --git a/compos/apk/assets/vm_test_config.json b/compos/apk/assets/vm_test_config.json
index 9fd55b7..16d1037 100644
--- a/compos/apk/assets/vm_test_config.json
+++ b/compos/apk/assets/vm_test_config.json
@@ -1,21 +1,24 @@
{
- "version": 1,
- "os": {
- "name": "microdroid"
+ "version": 1,
+ "os": {
+ "name": "microdroid"
+ },
+ "task": {
+ "type": "executable",
+ "command": "/apex/com.android.compos/bin/compsvc"
+ },
+ "apexes": [
+ {
+ "name": "com.android.art"
},
- "task": {
- "type": "executable",
- "command": "/apex/com.android.compos/bin/compsvc"
+ {
+ "name": "com.android.compos"
},
- "apexes": [
- {
- "name": "com.android.art"
- },
- {
- "name": "com.android.compos"
- },
- {
- "name": "{CLASSPATH}"
- }
- ]
-}
\ No newline at end of file
+ {
+ "name": "com.android.sdkext"
+ },
+ {
+ "name": "{CLASSPATH}"
+ }
+ ]
+}
diff --git a/compos/composd/src/instance_starter.rs b/compos/composd/src/instance_starter.rs
index 729e5b6..6946c11 100644
--- a/compos/composd/src/instance_starter.rs
+++ b/compos/composd/src/instance_starter.rs
@@ -29,7 +29,6 @@
COMPOS_DATA_ROOT, IDSIG_FILE, INSTANCE_IMAGE_FILE, PRIVATE_KEY_BLOB_FILE, PUBLIC_KEY_FILE,
};
use log::{info, warn};
-use std::env;
use std::fs;
use std::path::{Path, PathBuf};
@@ -111,8 +110,7 @@
// If we get this far then the instance image is valid in the current context (e.g. the
// current set of APEXes) and the key blob can be successfully decrypted by the VM. So the
// files have not been tampered with and we're good to go.
-
- Self::initialize_service(service, &key_blob)?;
+ service.initializeSigningKey(&key_blob).context("Loading signing key")?;
Ok(compos_instance)
}
@@ -145,28 +143,11 @@
// Unlike when starting an existing instance, we don't need to verify the key, since we
// just generated it and have it in memory.
-
- Self::initialize_service(service, &key_data.keyBlob)?;
+ service.initializeSigningKey(&key_data.keyBlob).context("Loading signing key")?;
Ok(compos_instance)
}
- fn initialize_service(service: &Strong<dyn ICompOsService>, key_blob: &[u8]) -> Result<()> {
- // Key blob is assumed to be verified/trusted.
- service.initializeSigningKey(key_blob).context("Loading signing key")?;
-
- // TODO(198211396): Implement correctly.
- service
- .initializeClasspaths(
- &env::var("BOOTCLASSPATH")?,
- &env::var("DEX2OATBOOTCLASSPATH")?,
- &env::var("SYSTEMSERVERCLASSPATH")?,
- &env::var("STANDALONE_SYSTEMSERVER_JARS")?,
- )
- .context("Initializing *CLASSPATH")?;
- Ok(())
- }
-
fn start_vm(
&self,
virtualization_service: &dyn IVirtualizationService,
diff --git a/compos/src/compilation.rs b/compos/src/compilation.rs
index 2ca4dd4..af7a9b4 100644
--- a/compos/src/compilation.rs
+++ b/compos/src/compilation.rs
@@ -15,12 +15,15 @@
*/
use anyhow::{anyhow, bail, Context, Result};
-use log::{debug, error, info};
+use log::{debug, error, info, warn};
use minijail::{self, Minijail};
+use regex::Regex;
use std::env;
+use std::ffi::OsString;
use std::fs::{read_dir, File};
use std::os::unix::io::{AsRawFd, RawFd};
use std::path::{self, Path, PathBuf};
+use std::process::Command;
use crate::artifact_signer::ArtifactSigner;
use crate::compos_key_service::Signer;
@@ -129,6 +132,8 @@
let staging_dir = mountpoint.join(context.staging_dir_fd.to_string());
+ set_classpaths(&android_root)?;
+
let args = vec![
"odrefresh".to_string(),
format!("--zygote-arch={}", context.zygote_arch),
@@ -164,6 +169,53 @@
Ok(exit_code)
}
+fn set_classpaths(android_root: &Path) -> Result<()> {
+ let export_lines = run_derive_classpath(android_root)?;
+ load_classpath_vars(&export_lines)
+}
+
+fn run_derive_classpath(android_root: &Path) -> Result<String> {
+ let classpaths_root = android_root.join("etc/classpaths");
+
+ let mut bootclasspath_arg = OsString::new();
+ bootclasspath_arg.push("--bootclasspath-fragment=");
+ bootclasspath_arg.push(classpaths_root.join("bootclasspath.pb"));
+
+ let mut systemserverclasspath_arg = OsString::new();
+ systemserverclasspath_arg.push("--systemserverclasspath-fragment=");
+ systemserverclasspath_arg.push(classpaths_root.join("systemserverclasspath.pb"));
+
+ let result = Command::new("/apex/com.android.sdkext/bin/derive_classpath")
+ .arg(bootclasspath_arg)
+ .arg(systemserverclasspath_arg)
+ .arg("/proc/self/fd/1")
+ .output()
+ .context("Failed to run derive_classpath")?;
+
+ if !result.status.success() {
+ bail!("derive_classpath returned {}", result.status);
+ }
+
+ String::from_utf8(result.stdout).context("Converting derive_classpath output")
+}
+
+fn load_classpath_vars(export_lines: &str) -> Result<()> {
+ // Each line should be in the format "export <var name> <value>"
+ let pattern = Regex::new(r"^export ([^ ]+) ([^ ]+)$").context("Failed to construct Regex")?;
+ for line in export_lines.lines() {
+ if let Some(captures) = pattern.captures(line) {
+ let name = &captures[1];
+ let value = &captures[2];
+ // TODO(b/213416778) Don't modify our env, construct a fresh one for odrefresh
+ env::set_var(name, value);
+ } else {
+ warn!("Malformed line from derive_classpath: {}", line);
+ }
+ }
+
+ Ok(())
+}
+
fn add_artifacts(target_dir: &Path, artifact_signer: &mut ArtifactSigner) -> Result<()> {
for entry in
read_dir(&target_dir).with_context(|| format!("Traversing {}", target_dir.display()))?
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index 3e9fc34..ef3ae2a 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -23,7 +23,6 @@
use compos_common::binder::to_binder_result;
use log::warn;
use std::default::Default;
-use std::env;
use std::path::PathBuf;
use std::sync::RwLock;
@@ -95,21 +94,6 @@
}
}
- fn initializeClasspaths(
- &self,
- boot_classpath: &str,
- dex2oat_boot_classpath: &str,
- system_server_classpath: &str,
- standalone_systemserver_jars: &str,
- ) -> BinderResult<()> {
- // TODO(198211396): Implement correctly.
- env::set_var("BOOTCLASSPATH", boot_classpath);
- env::set_var("DEX2OATBOOTCLASSPATH", dex2oat_boot_classpath);
- env::set_var("SYSTEMSERVERCLASSPATH", system_server_classpath);
- env::set_var("STANDALONE_SYSTEMSERVER_JARS", standalone_systemserver_jars);
- Ok(())
- }
-
fn odrefresh(
&self,
system_dir_fd: i32,
diff --git a/microdroid/build.prop b/microdroid/build.prop
index 4ae50c0..8cbabff 100644
--- a/microdroid/build.prop
+++ b/microdroid/build.prop
@@ -4,8 +4,10 @@
service.adb.listen_addrs=vsock:5555
# TODO(b/189164487): support build related properties
-ro.build.version.release=11
-ro.build.version.security_patch=2021-07-05
+ro.build.version.codename=Tiramisu
+ro.build.version.release=12
+ro.build.version.sdk=32
+ro.build.version.security_patch=2021-12-05
# Payload metadata partition
apexd.payload_metadata.path=/dev/block/by-name/payload-metadata
diff --git a/microdroid/uboot-env-x86_64.txt b/microdroid/uboot-env-x86_64.txt
index 0064cac..07a9b18 100644
--- a/microdroid/uboot-env-x86_64.txt
+++ b/microdroid/uboot-env-x86_64.txt
@@ -13,3 +13,6 @@
# loadaddr variable.
loadaddr=0x02000000
fdtaddr=0x40000000
+
+# Microdroid doesn't use keymint yet
+android_keymint_needed=N
diff --git a/microdroid/uboot-env.txt b/microdroid/uboot-env.txt
index b5f3968..0385b50 100644
--- a/microdroid/uboot-env.txt
+++ b/microdroid/uboot-env.txt
@@ -7,3 +7,6 @@
bootdelay=0
fdtaddr=0x80000000
+
+# Microdroid doesn't use keymint yet
+android_keymint_needed=N
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index 277432b..c3ab39a 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -36,6 +36,7 @@
"libmicrodroid_metadata",
"libmicrodroid_payload_config",
"libonce_cell",
+ "libregex",
"librustutils",
"libselinux_bindgen",
"libserde",
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index bbd7fec..a8c22cd 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -22,16 +22,18 @@
use android_system_virtualizationservice::binder::ParcelFileDescriptor;
use anyhow::{anyhow, bail, Context, Result};
use binder::wait_for_interface;
-use log::{error, info};
+use log::{info, warn};
use microdroid_metadata::{ApexPayload, ApkPayload, Metadata};
use microdroid_payload_config::{ApexConfig, VmPayloadConfig};
use once_cell::sync::OnceCell;
use packagemanager_aidl::aidl::android::content::pm::IPackageManagerNative::IPackageManagerNative;
+use regex::Regex;
use serde::Deserialize;
use serde_xml_rs::from_reader;
-use std::env;
+use std::collections::HashSet;
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
+use std::process::Command;
use vmconfig::open_parcel_file;
/// The list of APEXes which microdroid requires.
@@ -71,21 +73,16 @@
let mut apex_info_list: ApexInfoList = from_reader(apex_info_list)
.context(format!("Failed to parse {}", APEX_INFO_LIST_PATH))?;
- // For active APEXes, we refer env variables to see if it contributes to classpath
- // TODO(b/210472252): Don't hard code the env variable names
- let boot_classpath_apexes = find_apex_names_in_classpath_env("BOOTCLASSPATH");
- let systemserver_classpath_apexes =
- find_apex_names_in_classpath_env("SYSTEMSERVERCLASSPATH");
- let dex2oatboot_classpath_apexes =
- find_apex_names_in_classpath_env("DEX2OATBOOTCLASSPATH");
- let standalone_jar_apexes =
- find_apex_names_in_classpath_env("STANDALONE_SYSTEMSERVER_JARS");
+ // For active APEXes, we run derive_classpath and parse its output to see if it
+ // contributes to the classpath(s). (This allows us to handle any new classpath env
+ // vars seamlessly.)
+ let classpath_vars = run_derive_classpath()?;
+ let classpath_apexes = find_apex_names_in_classpath(&classpath_vars)?;
+
for apex_info in apex_info_list.list.iter_mut() {
- apex_info.has_classpath_jar = boot_classpath_apexes.contains(&apex_info.name)
- || systemserver_classpath_apexes.contains(&apex_info.name)
- || dex2oatboot_classpath_apexes.contains(&apex_info.name)
- || standalone_jar_apexes.contains(&apex_info.name);
+ apex_info.has_classpath_jar = classpath_apexes.contains(&apex_info.name);
}
+
Ok(apex_info_list)
})
}
@@ -263,22 +260,41 @@
Ok(DiskImage { image: None, partitions, writable: false })
}
-fn find_apex_names_in_classpath_env(classpath_env_var: &str) -> Vec<String> {
- let val = env::var(classpath_env_var).unwrap_or_else(|e| {
- error!("Reading {} failed: {}", classpath_env_var, e);
- String::from("")
- });
- val.split(':')
- .filter_map(|path| {
- Path::new(path)
- .strip_prefix("/apex/")
- .map(|stripped| {
- let first = stripped.iter().next().unwrap();
- first.to_str().unwrap().to_string()
- })
- .ok()
- })
- .collect()
+fn run_derive_classpath() -> Result<String> {
+ let result = Command::new("/apex/com.android.sdkext/bin/derive_classpath")
+ .arg("/proc/self/fd/1")
+ .output()
+ .context("Failed to run derive_classpath")?;
+
+ if !result.status.success() {
+ bail!("derive_classpath returned {}", result.status);
+ }
+
+ String::from_utf8(result.stdout).context("Converting derive_classpath output")
+}
+
+fn find_apex_names_in_classpath(classpath_vars: &str) -> Result<HashSet<String>> {
+ // Each line should be in the format "export <var name> <paths>", where <paths> is a
+ // colon-separated list of paths to JARs. We don't care about the var names, and we're only
+ // interested in paths that look like "/apex/<apex name>/<anything>" so we know which APEXes
+ // contribute to at least one var.
+ let mut apexes = HashSet::new();
+
+ let pattern = Regex::new(r"^export [^ ]+ ([^ ]+)$").context("Failed to construct Regex")?;
+ for line in classpath_vars.lines() {
+ if let Some(captures) = pattern.captures(line) {
+ if let Some(paths) = captures.get(1) {
+ apexes.extend(paths.as_str().split(':').filter_map(|path| {
+ let path = path.strip_prefix("/apex/")?;
+ Some(path[..path.find('/')?].to_owned())
+ }));
+ continue;
+ }
+ }
+ warn!("Malformed line from derive_classpath: {}", line);
+ }
+
+ Ok(apexes)
}
// Collect APEX names from config
@@ -359,13 +375,16 @@
mod tests {
use super::*;
#[test]
- fn test_find_apex_names_in_classpath_env() {
- let key = "TEST_BOOTCLASSPATH";
- let classpath = "/apex/com.android.foo/javalib/foo.jar:/system/framework/framework.jar:/apex/com.android.bar/javalib/bar.jar";
- env::set_var(key, classpath);
- assert_eq!(
- find_apex_names_in_classpath_env(key),
- vec!["com.android.foo".to_owned(), "com.android.bar".to_owned()]
- );
+ fn test_find_apex_names_in_classpath() {
+ let vars = r#"
+export FOO /apex/unterminated
+export BAR /apex/valid.apex/something
+wrong
+export EMPTY
+export OTHER /foo/bar:/baz:/apex/second.valid.apex/:gibberish:"#;
+ let expected = vec!["valid.apex", "second.valid.apex"];
+ let expected: HashSet<_> = expected.into_iter().map(ToString::to_string).collect();
+
+ assert_eq!(find_apex_names_in_classpath(vars).unwrap(), expected);
}
}