blob: cbcae8f2fcb584fa048b2e8acb0d9a76e04b6d7b [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 Hsieh9ed27182021-08-25 15:52:42 -070017//! pvm_exec is a proxy/wrapper command to run compilation task remotely. The most important task
Victor Hsieh272aa242021-02-01 14:19:20 -080018//! for this program is to run a `fd_server` that serves remote file read/write requests.
19//!
Victor Hsieh9ed27182021-08-25 15:52:42 -070020//! It currently works as a command line wrapper to make it easy to schedule an existing dex2oat
21//! task to run in the VM.
Victor Hsieh272aa242021-02-01 14:19:20 -080022//!
Victor Hsieh9ed27182021-08-25 15:52:42 -070023//! Example:
24//! $ adb shell exec 3</input/dex 4<>/output/oat ... pvm_exec --in-fd 3 --out-fd 4 -- dex2oat64 ...
25//!
26//! Note the immediate argument "dex2oat64" right after "--" is not really used. It is only for
27//! ergonomics.
Victor Hsieh272aa242021-02-01 14:19:20 -080028
29use anyhow::{bail, Context, Result};
Victor Hsieha7d37862021-06-04 17:14:20 -070030use binder::unstable_api::{new_spibinder, AIBinder};
31use binder::FromIBinder;
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -070032use clap::{value_t, App, Arg};
Victor Hsieh9ed27182021-08-25 15:52:42 -070033use log::{debug, error, warn};
Victor Hsieh272aa242021-02-01 14:19:20 -080034use minijail::Minijail;
35use nix::fcntl::{fcntl, FcntlArg::F_GETFD};
Victor Hsieh272aa242021-02-01 14:19:20 -080036use std::os::unix::io::RawFd;
37use std::path::Path;
38use std::process::exit;
39
40use compos_aidl_interface::aidl::com::android::compos::{
Victor Hsieh13333e82021-09-03 15:17:32 -070041 FdAnnotation::FdAnnotation, ICompOsService::ICompOsService,
Victor Hsieh272aa242021-02-01 14:19:20 -080042};
43use compos_aidl_interface::binder::Strong;
44
Victor Hsieha7d37862021-06-04 17:14:20 -070045mod common;
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -070046use common::VSOCK_PORT;
Victor Hsieh272aa242021-02-01 14:19:20 -080047
Victor Hsieha7d37862021-06-04 17:14:20 -070048const FD_SERVER_BIN: &str = "/apex/com.android.virt/bin/fd_server";
49
Victor Hsieha64194b2021-08-06 17:43:36 -070050fn get_rpc_binder(cid: u32) -> Result<Strong<dyn ICompOsService>> {
Victor Hsieha7d37862021-06-04 17:14:20 -070051 // SAFETY: AIBinder returned by RpcClient has correct reference count, and the ownership can be
52 // safely taken by new_spibinder.
53 let ibinder = unsafe {
54 new_spibinder(binder_rpc_unstable_bindgen::RpcClient(cid, VSOCK_PORT) as *mut AIBinder)
55 };
56 if let Some(ibinder) = ibinder {
Victor Hsieha64194b2021-08-06 17:43:36 -070057 <dyn ICompOsService>::try_from(ibinder).context("Cannot connect to RPC service")
Victor Hsieha7d37862021-06-04 17:14:20 -070058 } else {
59 bail!("Invalid raw AIBinder")
60 }
Victor Hsieh272aa242021-02-01 14:19:20 -080061}
62
Victor Hsieh13333e82021-09-03 15:17:32 -070063fn spawn_fd_server(fd_annotation: &FdAnnotation, debuggable: bool) -> Result<Minijail> {
Victor Hsieh272aa242021-02-01 14:19:20 -080064 let mut inheritable_fds = if debuggable {
65 vec![1, 2] // inherit/redirect stdout/stderr for debugging
66 } else {
67 vec![]
68 };
69
Victor Hsieha7d37862021-06-04 17:14:20 -070070 let mut args = vec![FD_SERVER_BIN.to_string(), "--rpc-binder".to_string()];
Victor Hsieh13333e82021-09-03 15:17:32 -070071 for fd in &fd_annotation.input_fds {
Victor Hsieh272aa242021-02-01 14:19:20 -080072 args.push("--ro-fds".to_string());
Victor Hsieh13333e82021-09-03 15:17:32 -070073 args.push(fd.to_string());
74 inheritable_fds.push(*fd);
Victor Hsieh272aa242021-02-01 14:19:20 -080075 }
Victor Hsieh13333e82021-09-03 15:17:32 -070076 for fd in &fd_annotation.output_fds {
Victor Hsieh272aa242021-02-01 14:19:20 -080077 args.push("--rw-fds".to_string());
Victor Hsieh13333e82021-09-03 15:17:32 -070078 args.push(fd.to_string());
79 inheritable_fds.push(*fd);
Victor Hsieh272aa242021-02-01 14:19:20 -080080 }
81
82 let jail = Minijail::new()?;
83 let _pid = jail.run(Path::new(FD_SERVER_BIN), &inheritable_fds, &args)?;
84 Ok(jail)
85}
86
87fn is_fd_valid(fd: RawFd) -> Result<bool> {
88 let retval = fcntl(fd, F_GETFD)?;
89 Ok(retval >= 0)
90}
91
92fn parse_arg_fd(arg: &str) -> Result<RawFd> {
93 let fd = arg.parse::<RawFd>()?;
94 if !is_fd_valid(fd)? {
95 bail!("Bad FD: {}", fd);
96 }
97 Ok(fd)
98}
99
100struct Config {
101 args: Vec<String>,
Victor Hsieh13333e82021-09-03 15:17:32 -0700102 fd_annotation: FdAnnotation,
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700103 cid: u32,
Victor Hsieh272aa242021-02-01 14:19:20 -0800104 debuggable: bool,
105}
106
107fn parse_args() -> Result<Config> {
108 #[rustfmt::skip]
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700109 let matches = App::new("pvm_exec")
110 .arg(Arg::with_name("in-fd")
Victor Hsieh272aa242021-02-01 14:19:20 -0800111 .long("in-fd")
112 .takes_value(true)
113 .multiple(true)
114 .use_delimiter(true))
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700115 .arg(Arg::with_name("out-fd")
Victor Hsieh272aa242021-02-01 14:19:20 -0800116 .long("out-fd")
117 .takes_value(true)
118 .multiple(true)
119 .use_delimiter(true))
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700120 .arg(Arg::with_name("cid")
Victor Hsieha7d37862021-06-04 17:14:20 -0700121 .takes_value(true)
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700122 .required(true)
Victor Hsieha7d37862021-06-04 17:14:20 -0700123 .long("cid"))
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700124 .arg(Arg::with_name("debug")
Victor Hsieh272aa242021-02-01 14:19:20 -0800125 .long("debug"))
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700126 .arg(Arg::with_name("args")
Victor Hsieh272aa242021-02-01 14:19:20 -0800127 .last(true)
128 .required(true)
129 .multiple(true))
130 .get_matches();
131
Victor Hsieh13333e82021-09-03 15:17:32 -0700132 let results: Result<Vec<_>> =
133 matches.values_of("in-fd").unwrap_or_default().map(parse_arg_fd).collect();
134 let input_fds = results?;
Victor Hsieh272aa242021-02-01 14:19:20 -0800135
Victor Hsieh13333e82021-09-03 15:17:32 -0700136 let results: Result<Vec<_>> =
137 matches.values_of("out-fd").unwrap_or_default().map(parse_arg_fd).collect();
138 let output_fds = results?;
Victor Hsieh272aa242021-02-01 14:19:20 -0800139
140 let args: Vec<_> = matches.values_of("args").unwrap().map(|s| s.to_string()).collect();
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700141 let cid = value_t!(matches, "cid", u32)?;
Victor Hsieh272aa242021-02-01 14:19:20 -0800142 let debuggable = matches.is_present("debug");
143
Victor Hsieh13333e82021-09-03 15:17:32 -0700144 Ok(Config { args, fd_annotation: FdAnnotation { input_fds, output_fds }, cid, debuggable })
Victor Hsieh272aa242021-02-01 14:19:20 -0800145}
146
147fn main() -> Result<()> {
Victor Hsieh4a654592021-08-19 09:08:19 -0700148 let debuggable = env!("TARGET_BUILD_VARIANT") != "user";
149 let log_level = if debuggable { log::Level::Trace } else { log::Level::Info };
150 android_logger::init_once(
151 android_logger::Config::default().with_tag("pvm_exec").with_min_level(log_level),
152 );
153
Victor Hsieh272aa242021-02-01 14:19:20 -0800154 // 1. Parse the command line arguments for collect execution data.
Victor Hsieh13333e82021-09-03 15:17:32 -0700155 let Config { args, fd_annotation, cid, debuggable } = parse_args()?;
Victor Hsieh272aa242021-02-01 14:19:20 -0800156
157 // 2. Spawn and configure a fd_server to serve remote read/write requests.
Victor Hsieh13333e82021-09-03 15:17:32 -0700158 let fd_server_jail = spawn_fd_server(&fd_annotation, debuggable)?;
Victor Hsieh272aa242021-02-01 14:19:20 -0800159 let fd_server_lifetime = scopeguard::guard(fd_server_jail, |fd_server_jail| {
160 if let Err(e) = fd_server_jail.kill() {
161 if !matches!(e, minijail::Error::Killed(_)) {
162 warn!("Failed to kill fd_server: {}", e);
163 }
164 }
165 });
166
167 // 3. Send the command line args to the remote to execute.
Victor Hsieh9ebf7ee2021-09-03 16:14:14 -0700168 let service = get_rpc_binder(cid)?;
Victor Hsieh13333e82021-09-03 15:17:32 -0700169 let result = service.compile(&args, &fd_annotation).context("Binder call failed")?;
Victor Hsieh9ed27182021-08-25 15:52:42 -0700170
171 // TODO: store/use the signature
172 debug!(
173 "Signature length: oat {}, vdex {}, image {}",
174 result.oatSignature.len(),
175 result.vdexSignature.len(),
176 result.imageSignature.len()
177 );
Victor Hsieh272aa242021-02-01 14:19:20 -0800178
179 // Be explicit about the lifetime, which should last at least until the task is finished.
180 drop(fd_server_lifetime);
181
Victor Hsieh9ed27182021-08-25 15:52:42 -0700182 if result.exitCode > 0 {
183 error!("remote execution failed with exit code {}", result.exitCode);
184 exit(result.exitCode as i32);
Victor Hsieh272aa242021-02-01 14:19:20 -0800185 }
186 Ok(())
187}