blob: f017f67bcd2a64f9aba8ea13b2551f492bb4edbf [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
17use crate::fd_server_helper::FdServerConfig;
18use crate::instance_starter::CompOsInstance;
19use crate::odrefresh;
20use crate::service::open_dir;
21use android_system_composd::aidl::android::system::composd::{
22 ICompilationTask::ICompilationTask, ICompilationTaskCallback::ICompilationTaskCallback,
23};
24use android_system_composd::binder::{Interface, Result as BinderResult, Strong};
25use anyhow::{bail, Result};
26use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
27use log::{error, warn};
28use num_traits::FromPrimitive;
29use rustutils::system_properties;
30use std::os::unix::io::AsRawFd;
31use std::path::{Path, PathBuf};
32use std::sync::{Arc, Mutex};
33use std::thread;
34
35#[derive(Clone)]
36pub struct OdrefreshTask {
37 running_task: Arc<Mutex<Option<RunningTask>>>,
38}
39
40impl Interface for OdrefreshTask {}
41
42impl ICompilationTask for OdrefreshTask {
43 fn cancel(&self) -> BinderResult<()> {
44 let task = self.take();
45 // Drop the VM, which should end compilation - and cause our thread to exit
46 drop(task);
47 Ok(())
48 }
49}
50
51impl OdrefreshTask {
52 /// Return the current running task, if any, removing it from this CompilationTask.
53 /// Once removed, meaning the task has ended or been canceled, further calls will always return
54 /// None.
55 fn take(&self) -> Option<RunningTask> {
56 self.running_task.lock().unwrap().take()
57 }
58
59 pub fn start(
60 comp_os: Arc<CompOsInstance>,
61 output_dir_path: PathBuf,
62 callback: &Strong<dyn ICompilationTaskCallback>,
63 ) -> Result<OdrefreshTask> {
64 let service = comp_os.get_service();
65 let task = RunningTask { comp_os, callback: callback.clone() };
66 let task = OdrefreshTask { running_task: Arc::new(Mutex::new(Some(task))) };
67
68 task.clone().start_thread(service, output_dir_path);
69
70 Ok(task)
71 }
72
73 fn start_thread(self, service: Strong<dyn ICompOsService>, output_dir_path: PathBuf) {
74 thread::spawn(move || {
75 let exit_code = try_odrefresh(service, &output_dir_path);
76
77 let task = self.take();
78 // We don't do the callback if cancel has already happened.
79 if let Some(task) = task {
80 let result = match exit_code {
81 Ok(odrefresh::ExitCode::CompilationSuccess) => task.callback.onSuccess(),
82 Ok(exit_code) => {
83 error!("Unexpected odrefresh result: {:?}", exit_code);
84 task.callback.onFailure()
85 }
86 Err(e) => {
87 error!("Running odrefresh failed: {:?}", e);
88 task.callback.onFailure()
89 }
90 };
91 if let Err(e) = result {
92 warn!("Failed to deliver callback: {:?}", e);
93 }
94 }
95 });
96 }
97}
98
99fn try_odrefresh(
100 service: Strong<dyn ICompOsService>,
101 output_dir_path: &Path,
102) -> Result<odrefresh::ExitCode> {
103 let output_dir = open_dir(output_dir_path)?;
104 let system_dir = open_dir(Path::new("/system"))?;
105
106 // Spawn a fd_server to serve the FDs.
107 let fd_server_config = FdServerConfig {
108 ro_dir_fds: vec![system_dir.as_raw_fd()],
109 rw_dir_fds: vec![output_dir.as_raw_fd()],
110 ..Default::default()
111 };
112 let fd_server_raii = fd_server_config.into_fd_server()?;
113
114 let zygote_arch = system_properties::read("ro.zygote")?;
115 let exit_code =
116 service.odrefresh(system_dir.as_raw_fd(), output_dir.as_raw_fd(), &zygote_arch)?.exitCode;
117
118 drop(fd_server_raii);
119 if let Some(exit_code) = FromPrimitive::from_i8(exit_code) {
120 Ok(exit_code)
121 } else {
122 bail!("odrefresh exited with {}", exit_code)
123 }
124}
125
126struct RunningTask {
127 callback: Strong<dyn ICompilationTaskCallback>,
128 #[allow(dead_code)] // Keeps the CompOS VM alive
129 comp_os: Arc<CompOsInstance>,
130}