blob: 8fd574c2e4b69729d4ea62ac699c16d8e2c40485 [file] [log] [blame]
Alan Stokes8c840442021-11-26 15:54:30 +00001/*
2 * Copyright 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
Alan Stokesda596932021-12-15 17:48:55 +000017//! Handle running odrefresh in the VM, with an async interface to allow cancellation
18
19use crate::fd_server_helper::FdServerConfig;
Alan Stokes8c840442021-11-26 15:54:30 +000020use crate::instance_starter::CompOsInstance;
Alan Stokes8c840442021-11-26 15:54:30 +000021use android_system_composd::aidl::android::system::composd::{
Alan Stokes81c96f32022-04-07 14:13:19 +010022 ICompilationTask::ICompilationTask,
23 ICompilationTaskCallback::{FailureReason::FailureReason, ICompilationTaskCallback},
Alan Stokes8c840442021-11-26 15:54:30 +000024};
25use android_system_composd::binder::{Interface, Result as BinderResult, Strong};
Alan Stokes126fd512021-12-16 15:00:01 +000026use anyhow::{Context, Result};
Alan Stokes2d2e4db2022-01-28 16:41:52 +000027use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
28 CompilationMode::CompilationMode, ICompOsService,
29};
Victor Hsiehcb6d66b2022-05-10 16:12:06 -070030use compos_common::odrefresh::{
31 is_system_property_interesting, ExitCode, ODREFRESH_OUTPUT_ROOT_DIR,
32};
Alan Stokes454069c2022-02-03 11:21:19 +000033use log::{error, info, warn};
Alan Stokesda596932021-12-15 17:48:55 +000034use rustutils::system_properties;
Alan Stokes35bac3c2021-12-16 14:37:24 +000035use std::fs::{remove_dir_all, File, OpenOptions};
Alan Stokesda596932021-12-15 17:48:55 +000036use std::os::unix::fs::OpenOptionsExt;
37use std::os::unix::io::AsRawFd;
38use std::path::Path;
Alan Stokes8c840442021-11-26 15:54:30 +000039use std::sync::{Arc, Mutex};
40use std::thread;
41
42#[derive(Clone)]
43pub struct OdrefreshTask {
44 running_task: Arc<Mutex<Option<RunningTask>>>,
45}
46
47impl Interface for OdrefreshTask {}
48
49impl ICompilationTask for OdrefreshTask {
50 fn cancel(&self) -> BinderResult<()> {
51 let task = self.take();
Alan Stokes0fc6ce52022-08-02 17:01:48 +010052 // Drop the VM, which should end compilation - and cause our thread to exit.
53 // Note that we don't do a graceful shutdown here; we've been asked to give up our resources
54 // ASAP, and the VM has not failed so we don't need to ensure VM logs are written.
Alan Stokes8c840442021-11-26 15:54:30 +000055 drop(task);
56 Ok(())
57 }
58}
59
Alan Stokesda596932021-12-15 17:48:55 +000060struct RunningTask {
61 callback: Strong<dyn ICompilationTaskCallback>,
62 #[allow(dead_code)] // Keeps the CompOS VM alive
Alan Stokes93863602022-08-03 17:23:25 +010063 comp_os: CompOsInstance,
Alan Stokesda596932021-12-15 17:48:55 +000064}
65
Alan Stokes8c840442021-11-26 15:54:30 +000066impl OdrefreshTask {
67 /// Return the current running task, if any, removing it from this CompilationTask.
68 /// Once removed, meaning the task has ended or been canceled, further calls will always return
69 /// None.
70 fn take(&self) -> Option<RunningTask> {
71 self.running_task.lock().unwrap().take()
72 }
73
74 pub fn start(
Alan Stokes93863602022-08-03 17:23:25 +010075 comp_os: CompOsInstance,
Alan Stokes2d2e4db2022-01-28 16:41:52 +000076 compilation_mode: CompilationMode,
Alan Stokesac9aa1a2021-12-14 11:32:13 +000077 target_dir_name: String,
Alan Stokes8c840442021-11-26 15:54:30 +000078 callback: &Strong<dyn ICompilationTaskCallback>,
79 ) -> Result<OdrefreshTask> {
80 let service = comp_os.get_service();
81 let task = RunningTask { comp_os, callback: callback.clone() };
82 let task = OdrefreshTask { running_task: Arc::new(Mutex::new(Some(task))) };
83
Alan Stokes2d2e4db2022-01-28 16:41:52 +000084 task.clone().start_thread(service, compilation_mode, target_dir_name);
Alan Stokes8c840442021-11-26 15:54:30 +000085
86 Ok(task)
87 }
88
Alan Stokes2d2e4db2022-01-28 16:41:52 +000089 fn start_thread(
90 self,
91 service: Strong<dyn ICompOsService>,
92 compilation_mode: CompilationMode,
93 target_dir_name: String,
94 ) {
Alan Stokes8c840442021-11-26 15:54:30 +000095 thread::spawn(move || {
Alan Stokes2d2e4db2022-01-28 16:41:52 +000096 let exit_code = run_in_vm(service, compilation_mode, &target_dir_name);
Alan Stokes8c840442021-11-26 15:54:30 +000097
98 let task = self.take();
99 // We don't do the callback if cancel has already happened.
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100100 if let Some(RunningTask { callback, comp_os }) = task {
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100101 // Make sure we keep our service alive until we have called the callback.
Alan Stokes93863602022-08-03 17:23:25 +0100102 let lazy_service_guard = comp_os.shutdown();
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100103
Alan Stokes8c840442021-11-26 15:54:30 +0000104 let result = match exit_code {
Alan Stokes454069c2022-02-03 11:21:19 +0000105 Ok(ExitCode::CompilationSuccess) => {
106 info!("CompilationSuccess");
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100107 callback.onSuccess()
Alan Stokes454069c2022-02-03 11:21:19 +0000108 }
Alan Stokes8c840442021-11-26 15:54:30 +0000109 Ok(exit_code) => {
Alan Stokes81c96f32022-04-07 14:13:19 +0100110 let message = format!("Unexpected odrefresh result: {:?}", exit_code);
111 error!("{}", message);
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100112 callback.onFailure(FailureReason::UnexpectedCompilationResult, &message)
Alan Stokes8c840442021-11-26 15:54:30 +0000113 }
114 Err(e) => {
Alan Stokes81c96f32022-04-07 14:13:19 +0100115 let message = format!("Running odrefresh failed: {:?}", e);
116 error!("{}", message);
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100117 callback.onFailure(FailureReason::CompilationFailed, &message)
Alan Stokes8c840442021-11-26 15:54:30 +0000118 }
119 };
120 if let Err(e) = result {
121 warn!("Failed to deliver callback: {:?}", e);
122 }
Alan Stokes0fc6ce52022-08-02 17:01:48 +0100123 drop(lazy_service_guard);
Alan Stokes8c840442021-11-26 15:54:30 +0000124 }
125 });
126 }
127}
128
Alan Stokes2d2e4db2022-01-28 16:41:52 +0000129fn run_in_vm(
130 service: Strong<dyn ICompOsService>,
131 compilation_mode: CompilationMode,
132 target_dir_name: &str,
133) -> Result<ExitCode> {
Victor Hsiehcb6d66b2022-05-10 16:12:06 -0700134 let mut names = Vec::new();
135 let mut values = Vec::new();
136 system_properties::foreach(|name, value| {
137 if is_system_property_interesting(name) {
138 names.push(name.to_owned());
139 values.push(value.to_owned());
140 }
141 })?;
142 service.initializeSystemProperties(&names, &values).context("initialize system properties")?;
143
Alan Stokes16fb8552022-02-10 15:07:27 +0000144 let output_root = Path::new(ODREFRESH_OUTPUT_ROOT_DIR);
Alan Stokes35bac3c2021-12-16 14:37:24 +0000145
146 // We need to remove the target directory because odrefresh running in compos will create it
147 // (and can't see the existing one, since authfs doesn't show it existing files in an output
148 // directory).
149 let target_path = output_root.join(target_dir_name);
Alan Stokesa4542ec2021-12-20 09:39:33 +0000150 if target_path.exists() {
151 remove_dir_all(&target_path)
152 .with_context(|| format!("Failed to delete {}", target_path.display()))?;
153 }
Alan Stokes35bac3c2021-12-16 14:37:24 +0000154
Alan Stokesda596932021-12-15 17:48:55 +0000155 let staging_dir = open_dir(composd_native::palette_create_odrefresh_staging_directory()?)?;
156 let system_dir = open_dir(Path::new("/system"))?;
Alan Stokes35bac3c2021-12-16 14:37:24 +0000157 let output_dir = open_dir(output_root)?;
Alan Stokesda596932021-12-15 17:48:55 +0000158
159 // Spawn a fd_server to serve the FDs.
160 let fd_server_config = FdServerConfig {
161 ro_dir_fds: vec![system_dir.as_raw_fd()],
162 rw_dir_fds: vec![staging_dir.as_raw_fd(), output_dir.as_raw_fd()],
163 ..Default::default()
164 };
165 let fd_server_raii = fd_server_config.into_fd_server()?;
166
Andrew Walbran014efb52022-02-03 17:43:11 +0000167 let zygote_arch = system_properties::read("ro.zygote")?.context("ro.zygote not set")?;
Victor Hsieh9bfbc5f2021-12-16 11:45:10 -0800168 let system_server_compiler_filter =
Andrew Walbran014efb52022-02-03 17:43:11 +0000169 system_properties::read("dalvik.vm.systemservercompilerfilter")?.unwrap_or_default();
Alan Stokesda596932021-12-15 17:48:55 +0000170 let exit_code = service.odrefresh(
Alan Stokes2d2e4db2022-01-28 16:41:52 +0000171 compilation_mode,
Alan Stokesda596932021-12-15 17:48:55 +0000172 system_dir.as_raw_fd(),
173 output_dir.as_raw_fd(),
174 staging_dir.as_raw_fd(),
175 target_dir_name,
176 &zygote_arch,
Victor Hsieh9bfbc5f2021-12-16 11:45:10 -0800177 &system_server_compiler_filter,
Alan Stokesda596932021-12-15 17:48:55 +0000178 )?;
179
180 drop(fd_server_raii);
Alan Stokes126fd512021-12-16 15:00:01 +0000181 ExitCode::from_i32(exit_code.into())
Alan Stokesda596932021-12-15 17:48:55 +0000182}
183
184/// Returns an owned FD of the directory. It currently returns a `File` as a FD owner, but
185/// it's better to use `std::os::unix::io::OwnedFd` once/if it becomes standard.
186fn open_dir(path: &Path) -> Result<File> {
187 OpenOptions::new()
188 .custom_flags(libc::O_DIRECTORY)
189 .read(true) // O_DIRECTORY can only be opened with read
190 .open(path)
191 .with_context(|| format!("Failed to open {:?} directory as path fd", path))
Alan Stokes8c840442021-11-26 15:54:30 +0000192}