blob: fe83ba25c9e8ffbd5f0f15cd821a407d2aaca10d [file] [log] [blame]
Victor Hsieh272aa242021-02-01 14:19:20 -08001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Victor Hsieh51789de2021-08-06 16:50:49 -070017//! compsvc is a service to run compilation tasks in a PVM upon request. It is able to set up
Victor Hsiehebb1d902021-08-06 13:00:18 -070018//! file descriptors backed by authfs (via authfs_service) and pass the file descriptors to the
Victor Hsieh51789de2021-08-06 16:50:49 -070019//! actual compiler.
Victor Hsieh272aa242021-02-01 14:19:20 -080020
Victor Hsiehec38ae22022-02-10 00:06:26 +000021use anyhow::{bail, Context, Result};
Alan Stokes0fc6ce52022-08-02 17:01:48 +010022use log::{error, info};
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070023use rustutils::system_properties;
Victor Hsieh9ed27182021-08-25 15:52:42 -070024use std::default::Default;
Victor Hsiehec38ae22022-02-10 00:06:26 +000025use std::fs::read_dir;
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070026use std::iter::zip;
Victor Hsiehec38ae22022-02-10 00:06:26 +000027use std::path::{Path, PathBuf};
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070028use std::sync::RwLock;
Victor Hsieh272aa242021-02-01 14:19:20 -080029
Victor Hsiehec38ae22022-02-10 00:06:26 +000030use crate::artifact_signer::ArtifactSigner;
Victor Hsiehe7698672022-09-23 16:22:28 -070031use crate::compilation::odrefresh;
Alan Stokes16fb8552022-02-10 15:07:27 +000032use crate::compos_key;
Alice Wang15ae7b92022-10-24 14:36:59 +000033use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::{
34 IAuthFsService, AUTHFS_SERVICE_SOCKET_NAME,
35};
Alan Stokes17cead42023-08-11 10:17:51 +010036use binder::{
37 BinderFeatures, ExceptionCode, Interface, IntoBinderResult, Result as BinderResult, Strong,
38};
Alan Stokes6542fdd2022-02-17 15:21:46 +000039use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
Victor Hsiehe7698672022-09-23 16:22:28 -070040 BnCompOsService, ICompOsService, OdrefreshArgs::OdrefreshArgs,
Victor Hsieh272aa242021-02-01 14:19:20 -080041};
Alan Stokes6542fdd2022-02-17 15:21:46 +000042use compos_common::binder::to_binder_result;
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070043use compos_common::odrefresh::{is_system_property_interesting, ODREFRESH_PATH};
David Brazdila2125dd2022-12-14 16:37:44 +000044use rpcbinder::RpcSession;
Alan Stokes9e2c5d52021-07-21 11:29:10 +010045
Victor Hsieha64194b2021-08-06 17:43:36 -070046/// Constructs a binder object that implements ICompOsService.
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -070047pub fn new_binder() -> Result<Strong<dyn ICompOsService>> {
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070048 let service = CompOsService {
49 odrefresh_path: PathBuf::from(ODREFRESH_PATH),
50 initialized: RwLock::new(None),
51 };
Victor Hsieha64194b2021-08-06 17:43:36 -070052 Ok(BnCompOsService::new_binder(service, BinderFeatures::default()))
Alan Stokes9e2c5d52021-07-21 11:29:10 +010053}
54
Victor Hsieha64194b2021-08-06 17:43:36 -070055struct CompOsService {
Victor Hsiehf9968692021-11-18 11:34:39 -080056 odrefresh_path: PathBuf,
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070057
58 /// A locked protected tri-state.
59 /// * None: uninitialized
60 /// * Some(true): initialized successfully
61 /// * Some(false): failed to initialize
62 initialized: RwLock<Option<bool>>,
Victor Hsieh272aa242021-02-01 14:19:20 -080063}
64
Victor Hsieha64194b2021-08-06 17:43:36 -070065impl Interface for CompOsService {}
Victor Hsieh272aa242021-02-01 14:19:20 -080066
Victor Hsieha64194b2021-08-06 17:43:36 -070067impl ICompOsService for CompOsService {
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070068 fn initializeSystemProperties(&self, names: &[String], values: &[String]) -> BinderResult<()> {
69 let mut initialized = self.initialized.write().unwrap();
70 if initialized.is_some() {
Alan Stokes17cead42023-08-11 10:17:51 +010071 return Err(format!("Already initialized: {initialized:?}"))
72 .or_binder_exception(ExceptionCode::ILLEGAL_STATE);
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070073 }
74 *initialized = Some(false);
75
76 if names.len() != values.len() {
Alan Stokes17cead42023-08-11 10:17:51 +010077 return Err(format!(
78 "Received inconsistent number of keys ({}) and values ({})",
79 names.len(),
80 values.len()
81 ))
82 .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT);
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070083 }
84 for (name, value) in zip(names, values) {
85 if !is_system_property_interesting(name) {
Alan Stokes17cead42023-08-11 10:17:51 +010086 return Err(format!("Received invalid system property {name}"))
87 .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT);
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070088 }
89 let result = system_properties::write(name, value);
90 if result.is_err() {
91 error!("Failed to setprop {}", &name);
92 return to_binder_result(result);
93 }
94 }
95 *initialized = Some(true);
96 Ok(())
97 }
98
Victor Hsiehe7698672022-09-23 16:22:28 -070099 fn odrefresh(&self, args: &OdrefreshArgs) -> BinderResult<i8> {
Victor Hsiehcb6d66b2022-05-10 16:12:06 -0700100 let initialized = *self.initialized.read().unwrap();
101 if !initialized.unwrap_or(false) {
Alan Stokes17cead42023-08-11 10:17:51 +0100102 return Err("Service has not been initialized")
103 .or_binder_exception(ExceptionCode::ILLEGAL_STATE);
Victor Hsiehcb6d66b2022-05-10 16:12:06 -0700104 }
105
Victor Hsiehe7698672022-09-23 16:22:28 -0700106 to_binder_result(self.do_odrefresh(args))
Victor Hsiehf9968692021-11-18 11:34:39 -0800107 }
108
Alan Stokes16fb8552022-02-10 15:07:27 +0000109 fn getPublicKey(&self) -> BinderResult<Vec<u8>> {
110 to_binder_result(compos_key::get_public_key())
111 }
Alan Stokes5430eca2022-03-21 14:02:09 +0000112
113 fn getAttestationChain(&self) -> BinderResult<Vec<u8>> {
114 to_binder_result(compos_key::get_attestation_chain())
115 }
Alan Stokes71403772022-06-21 14:56:28 +0100116
117 fn quit(&self) -> BinderResult<()> {
Alan Stokes71403772022-06-21 14:56:28 +0100118 // When our process exits, Microdroid will shut down the VM.
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100119 info!("Received quit request, exiting");
Alan Stokes71403772022-06-21 14:56:28 +0100120 std::process::exit(0);
121 }
Victor Hsieh272aa242021-02-01 14:19:20 -0800122}
Victor Hsiehebb1d902021-08-06 13:00:18 -0700123
Alan Stokes01b3ef02022-09-22 17:43:24 +0100124impl CompOsService {
Victor Hsiehe7698672022-09-23 16:22:28 -0700125 fn do_odrefresh(&self, args: &OdrefreshArgs) -> Result<i8> {
Alice Wang15ae7b92022-10-24 14:36:59 +0000126 log::debug!("Prepare to connect to {}", AUTHFS_SERVICE_SOCKET_NAME);
David Brazdila2125dd2022-12-14 16:37:44 +0000127 let authfs_service: Strong<dyn IAuthFsService> = RpcSession::new()
128 .setup_unix_domain_client(AUTHFS_SERVICE_SOCKET_NAME)
129 .with_context(|| format!("Failed to connect to {}", AUTHFS_SERVICE_SOCKET_NAME))?;
Victor Hsiehe7698672022-09-23 16:22:28 -0700130 let exit_code = odrefresh(&self.odrefresh_path, args, authfs_service, |output_dir| {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100131 // authfs only shows us the files we created, so it's ok to just sign everything
132 // under the output directory.
133 let mut artifact_signer = ArtifactSigner::new(&output_dir);
134 add_artifacts(&output_dir, &mut artifact_signer)?;
135
136 artifact_signer.write_info_and_signature(&output_dir.join("compos.info"))
137 })
138 .context("odrefresh failed")?;
139 Ok(exit_code as i8)
140 }
141}
142
Victor Hsiehec38ae22022-02-10 00:06:26 +0000143fn add_artifacts(target_dir: &Path, artifact_signer: &mut ArtifactSigner) -> Result<()> {
144 for entry in
Chris Wailes9b866f02022-11-16 15:17:16 -0800145 read_dir(target_dir).with_context(|| format!("Traversing {}", target_dir.display()))?
Victor Hsiehec38ae22022-02-10 00:06:26 +0000146 {
147 let entry = entry?;
148 let file_type = entry.file_type()?;
149 if file_type.is_dir() {
150 add_artifacts(&entry.path(), artifact_signer)?;
151 } else if file_type.is_file() {
152 artifact_signer.add_artifact(&entry.path())?;
153 } else {
154 // authfs shouldn't create anything else, but just in case
155 bail!("Unexpected file type in artifacts: {:?}", entry);
156 }
157 }
158 Ok(())
159}