blob: 9b41104dc3fb322296af99fdb4af7cfc60b42717 [file] [log] [blame]
Alan Stokesb2cc79e2021-09-14 14:08:46 +01001/*
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//! Simple command-line tool to drive composd for testing and debugging.
18
19use android_system_composd::{
Alan Stokes9ca14ca2021-10-20 14:25:57 +010020 aidl::android::system::composd::{
Alan Stokes6fc18372021-11-25 17:50:27 +000021 ICompilationTask::ICompilationTask,
Alan Stokes9ca14ca2021-10-20 14:25:57 +010022 ICompilationTaskCallback::{BnCompilationTaskCallback, ICompilationTaskCallback},
23 IIsolatedCompilationService::IIsolatedCompilationService,
24 },
Alan Stokesdcb96022021-10-26 15:23:31 +010025 binder::{
26 wait_for_interface, BinderFeatures, DeathRecipient, IBinder, Interface, ProcessState,
Alan Stokes6fc18372021-11-25 17:50:27 +000027 Result as BinderResult, Strong,
Alan Stokesdcb96022021-10-26 15:23:31 +010028 },
Alan Stokesb2cc79e2021-09-14 14:08:46 +010029};
Alan Stokes9ca14ca2021-10-20 14:25:57 +010030use anyhow::{bail, Context, Result};
Alan Stokes17aed5c2021-10-20 14:25:57 +010031use compos_common::timeouts::timeouts;
Alan Stokes71cc11e2022-01-17 10:39:05 +000032use std::fs::File;
33use std::io::Write;
Alan Stokes9ca14ca2021-10-20 14:25:57 +010034use std::sync::{Arc, Condvar, Mutex};
35use std::time::Duration;
Alan Stokesb2cc79e2021-09-14 14:08:46 +010036
37fn main() -> Result<()> {
Alan Stokes388b88a2021-10-13 16:03:17 +010038 let app = clap::App::new("composd_cmd").arg(
Alan Stokesda596932021-12-15 17:48:55 +000039 clap::Arg::with_name("command")
40 .index(1)
41 .takes_value(true)
42 .required(true)
Alan Stokes71cc11e2022-01-17 10:39:05 +000043 .possible_values(&["staged-apex-compile", "test-compile", "dice"]),
Alan Stokes388b88a2021-10-13 16:03:17 +010044 );
45 let args = app.get_matches();
46 let command = args.value_of("command").unwrap();
47
Alan Stokesb2cc79e2021-09-14 14:08:46 +010048 ProcessState::start_thread_pool();
49
Alan Stokes388b88a2021-10-13 16:03:17 +010050 match command {
Alan Stokes6fc18372021-11-25 17:50:27 +000051 "staged-apex-compile" => run_staged_apex_compile()?,
Alan Stokes768ba9c2021-12-20 14:32:12 +000052 "test-compile" => run_test_compile()?,
Alan Stokes71cc11e2022-01-17 10:39:05 +000053 "dice" => write_dice()?,
Alan Stokes388b88a2021-10-13 16:03:17 +010054 _ => panic!("Unexpected command {}", command),
55 }
Alan Stokesb2cc79e2021-09-14 14:08:46 +010056
57 println!("All Ok!");
58
59 Ok(())
60}
Alan Stokes9ca14ca2021-10-20 14:25:57 +010061
62struct Callback(Arc<State>);
63
64#[derive(Default)]
65struct State {
66 mutex: Mutex<Option<Outcome>>,
67 completed: Condvar,
68}
69
70#[derive(Copy, Clone)]
71enum Outcome {
72 Succeeded,
73 Failed,
74}
75
76impl Interface for Callback {}
77
78impl ICompilationTaskCallback for Callback {
79 fn onSuccess(&self) -> BinderResult<()> {
80 self.0.set_outcome(Outcome::Succeeded);
81 Ok(())
82 }
83
84 fn onFailure(&self) -> BinderResult<()> {
85 self.0.set_outcome(Outcome::Failed);
86 Ok(())
87 }
88}
89
90impl State {
91 fn set_outcome(&self, outcome: Outcome) {
92 let mut guard = self.mutex.lock().unwrap();
93 *guard = Some(outcome);
94 drop(guard);
95 self.completed.notify_all();
96 }
97
98 fn wait(&self, duration: Duration) -> Result<Outcome> {
99 let (outcome, result) = self
100 .completed
101 .wait_timeout_while(self.mutex.lock().unwrap(), duration, |outcome| outcome.is_none())
102 .unwrap();
103 if result.timed_out() {
104 bail!("Timed out waiting for compilation")
105 }
106 Ok(outcome.unwrap())
107 }
108}
109
Alan Stokes6fc18372021-11-25 17:50:27 +0000110fn run_staged_apex_compile() -> Result<()> {
111 run_async_compilation(|service, callback| service.startStagedApexCompile(callback))
112}
113
Alan Stokes768ba9c2021-12-20 14:32:12 +0000114fn run_test_compile() -> Result<()> {
Alan Stokes6fc18372021-11-25 17:50:27 +0000115 run_async_compilation(|service, callback| service.startTestCompile(callback))
116}
117
Alan Stokes71cc11e2022-01-17 10:39:05 +0000118fn write_dice() -> Result<()> {
119 let service = wait_for_interface::<dyn IIsolatedCompilationService>("android.system.composd")
120 .context("Failed to connect to composd service")?;
121
122 let bcc = service.getBcc()?;
123 let mut file =
124 File::create("/data/misc/apexdata/com.android.compos/bcc").context("Creating bcc file")?;
125 file.write_all(&bcc).context("Writing bcc")
126}
127
Alan Stokes6fc18372021-11-25 17:50:27 +0000128fn run_async_compilation<F>(start_compile_fn: F) -> Result<()>
129where
130 F: FnOnce(
131 &dyn IIsolatedCompilationService,
132 &Strong<dyn ICompilationTaskCallback>,
133 ) -> BinderResult<Strong<dyn ICompilationTask>>,
134{
Alan Stokes9ca14ca2021-10-20 14:25:57 +0100135 let service = wait_for_interface::<dyn IIsolatedCompilationService>("android.system.composd")
136 .context("Failed to connect to composd service")?;
137
138 let state = Arc::new(State::default());
139 let callback = Callback(state.clone());
140 let callback = BnCompilationTaskCallback::new_binder(callback, BinderFeatures::default());
Alan Stokes6fc18372021-11-25 17:50:27 +0000141 let task = start_compile_fn(&*service, &callback).context("Compilation failed")?;
Alan Stokes9ca14ca2021-10-20 14:25:57 +0100142
143 // Make sure composd keeps going even if we don't hold a reference to its service.
144 drop(service);
145
Alan Stokesdcb96022021-10-26 15:23:31 +0100146 let state_clone = state.clone();
147 let mut death_recipient = DeathRecipient::new(move || {
148 eprintln!("CompilationTask died");
149 state_clone.set_outcome(Outcome::Failed);
150 });
151 // Note that dropping death_recipient cancels this, so we can't use a temporary here.
152 task.as_binder().link_to_death(&mut death_recipient)?;
Alan Stokes9ca14ca2021-10-20 14:25:57 +0100153
154 println!("Waiting");
155
Alan Stokes17aed5c2021-10-20 14:25:57 +0100156 match state.wait(timeouts()?.odrefresh_max_execution_time) {
Alan Stokes9ca14ca2021-10-20 14:25:57 +0100157 Ok(Outcome::Succeeded) => Ok(()),
158 Ok(Outcome::Failed) => bail!("Compilation failed"),
159 Err(e) => {
160 if let Err(e) = task.cancel() {
161 eprintln!("Failed to cancel compilation: {:?}", e);
162 }
163 Err(e)
164 }
165 }
166}