blob: 1e642cbf6417929c42bfd255f78bb86b75b9412c [file] [log] [blame]
Andrew Walbranea9fa482021-03-04 16:11:12 +00001// Copyright 2021, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Android VM control tool.
16
17mod sync;
18
19use android_system_virtmanager::aidl::android::system::virtmanager::IVirtManager::IVirtManager;
20use android_system_virtmanager::binder::{get_interface, ProcessState, Strong};
21use anyhow::{bail, Context, Error};
22// TODO: Import these via android_system_virtmanager::binder once https://r.android.com/1619403 is
23// submitted.
24use binder::{DeathRecipient, IBinder};
25use std::env;
26use std::process::exit;
27use sync::AtomicFlag;
28
29const VIRT_MANAGER_BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtmanager";
30
31fn main() -> Result<(), Error> {
32 env_logger::init();
33
34 let args: Vec<_> = env::args().collect();
35 if args.len() < 2 {
36 eprintln!("Usage:");
37 eprintln!(" {} run <vm_config.json>", args[0]);
38 exit(1);
39 }
40
41 // We need to start the thread pool for Binder to work properly, especially link_to_death.
42 ProcessState::start_thread_pool();
43
44 match args[1].as_ref() {
45 "run" if args.len() == 3 => command_run(&args[2]),
46 command => bail!("Invalid command '{}' or wrong number of arguments", command),
47 }
48}
49
50/// Run a VM from the given configuration file.
51fn command_run(config_filename: &str) -> Result<(), Error> {
52 let virt_manager: Strong<dyn IVirtManager> =
53 get_interface(VIRT_MANAGER_BINDER_SERVICE_IDENTIFIER)
54 .with_context(|| "Failed to find Virt Manager service")?;
55 let vm = virt_manager.startVm(config_filename).with_context(|| "Failed to start VM")?;
56 let cid = vm.getCid().with_context(|| "Failed to get CID")?;
57 println!("Started VM from {} with CID {}.", config_filename, cid);
58
59 // Wait until the VM dies. If we just returned immediately then the IVirtualMachine Binder
60 // object would be dropped and the VM would be killed.
61 wait_for_death(&mut vm.as_binder())?;
62 println!("VM died");
63 Ok(())
64}
65
66/// Block until the given Binder object dies.
67fn wait_for_death(binder: &mut impl IBinder) -> Result<(), Error> {
68 let dead = AtomicFlag::default();
69 let mut death_recipient = {
70 let dead = dead.clone();
71 DeathRecipient::new(move || {
72 dead.raise();
73 })
74 };
75 binder.link_to_death(&mut death_recipient)?;
76 dead.wait();
77 Ok(())
78}