• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 //! compsvc is a service to run compilation tasks in a PVM upon request. It is able to set up
18 //! file descriptors backed by authfs (via authfs_service) and pass the file descriptors to the
19 //! actual compiler.
20 
21 use anyhow::{bail, Context, Result};
22 use binder_common::new_binder_exception;
23 use log::error;
24 use rustutils::system_properties;
25 use std::default::Default;
26 use std::fs::read_dir;
27 use std::iter::zip;
28 use std::path::{Path, PathBuf};
29 use std::sync::RwLock;
30 
31 use crate::artifact_signer::ArtifactSigner;
32 use crate::compilation::{odrefresh, OdrefreshContext};
33 use crate::compos_key;
34 use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
35     BnCompOsService, CompilationMode::CompilationMode, ICompOsService,
36 };
37 use compos_aidl_interface::binder::{
38     BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong,
39 };
40 use compos_common::binder::to_binder_result;
41 use compos_common::odrefresh::{is_system_property_interesting, ODREFRESH_PATH};
42 
43 const AUTHFS_SERVICE_NAME: &str = "authfs_service";
44 
45 /// Constructs a binder object that implements ICompOsService.
new_binder() -> Result<Strong<dyn ICompOsService>>46 pub fn new_binder() -> Result<Strong<dyn ICompOsService>> {
47     let service = CompOsService {
48         odrefresh_path: PathBuf::from(ODREFRESH_PATH),
49         initialized: RwLock::new(None),
50     };
51     Ok(BnCompOsService::new_binder(service, BinderFeatures::default()))
52 }
53 
54 struct CompOsService {
55     odrefresh_path: PathBuf,
56 
57     /// A locked protected tri-state.
58     ///  * None: uninitialized
59     ///  * Some(true): initialized successfully
60     ///  * Some(false): failed to initialize
61     initialized: RwLock<Option<bool>>,
62 }
63 
64 impl Interface for CompOsService {}
65 
66 impl ICompOsService for CompOsService {
initializeSystemProperties(&self, names: &[String], values: &[String]) -> BinderResult<()>67     fn initializeSystemProperties(&self, names: &[String], values: &[String]) -> BinderResult<()> {
68         let mut initialized = self.initialized.write().unwrap();
69         if initialized.is_some() {
70             return Err(new_binder_exception(
71                 ExceptionCode::ILLEGAL_STATE,
72                 format!("Already initialized: {:?}", initialized),
73             ));
74         }
75         *initialized = Some(false);
76 
77         if names.len() != values.len() {
78             return Err(new_binder_exception(
79                 ExceptionCode::ILLEGAL_ARGUMENT,
80                 format!(
81                     "Received inconsistent number of keys ({}) and values ({})",
82                     names.len(),
83                     values.len()
84                 ),
85             ));
86         }
87         for (name, value) in zip(names, values) {
88             if !is_system_property_interesting(name) {
89                 return Err(new_binder_exception(
90                     ExceptionCode::ILLEGAL_ARGUMENT,
91                     format!("Received invalid system property {}", &name),
92                 ));
93             }
94             let result = system_properties::write(name, value);
95             if result.is_err() {
96                 error!("Failed to setprop {}", &name);
97                 return to_binder_result(result);
98             }
99         }
100         *initialized = Some(true);
101         Ok(())
102     }
103 
odrefresh( &self, compilation_mode: CompilationMode, system_dir_fd: i32, output_dir_fd: i32, staging_dir_fd: i32, target_dir_name: &str, zygote_arch: &str, system_server_compiler_filter: &str, ) -> BinderResult<i8>104     fn odrefresh(
105         &self,
106         compilation_mode: CompilationMode,
107         system_dir_fd: i32,
108         output_dir_fd: i32,
109         staging_dir_fd: i32,
110         target_dir_name: &str,
111         zygote_arch: &str,
112         system_server_compiler_filter: &str,
113     ) -> BinderResult<i8> {
114         let initialized = *self.initialized.read().unwrap();
115         if !initialized.unwrap_or(false) {
116             return Err(new_binder_exception(
117                 ExceptionCode::ILLEGAL_STATE,
118                 "Service has not been initialized",
119             ));
120         }
121 
122         let context = to_binder_result(OdrefreshContext::new(
123             compilation_mode,
124             system_dir_fd,
125             output_dir_fd,
126             staging_dir_fd,
127             target_dir_name,
128             zygote_arch,
129             system_server_compiler_filter,
130         ))?;
131 
132         let authfs_service = authfs_aidl_interface::binder::get_interface(AUTHFS_SERVICE_NAME)?;
133         let exit_code = to_binder_result(
134             odrefresh(&self.odrefresh_path, context, authfs_service, |output_dir| {
135                 // authfs only shows us the files we created, so it's ok to just sign everything
136                 // under the output directory.
137                 let mut artifact_signer = ArtifactSigner::new(&output_dir);
138                 add_artifacts(&output_dir, &mut artifact_signer)?;
139 
140                 artifact_signer.write_info_and_signature(&output_dir.join("compos.info"))
141             })
142             .context("odrefresh failed"),
143         )?;
144         Ok(exit_code as i8)
145     }
146 
getPublicKey(&self) -> BinderResult<Vec<u8>>147     fn getPublicKey(&self) -> BinderResult<Vec<u8>> {
148         to_binder_result(compos_key::get_public_key())
149     }
150 }
151 
add_artifacts(target_dir: &Path, artifact_signer: &mut ArtifactSigner) -> Result<()>152 fn add_artifacts(target_dir: &Path, artifact_signer: &mut ArtifactSigner) -> Result<()> {
153     for entry in
154         read_dir(&target_dir).with_context(|| format!("Traversing {}", target_dir.display()))?
155     {
156         let entry = entry?;
157         let file_type = entry.file_type()?;
158         if file_type.is_dir() {
159             add_artifacts(&entry.path(), artifact_signer)?;
160         } else if file_type.is_file() {
161             artifact_signer.add_artifact(&entry.path())?;
162         } else {
163             // authfs shouldn't create anything else, but just in case
164             bail!("Unexpected file type in artifacts: {:?}", entry);
165         }
166     }
167     Ok(())
168 }
169