blob: df375e40d1367fbc740ed4f0535b6f9d94eeb18c [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]);
Andrew Walbran320b5602021-03-04 16:11:12 +000038 eprintln!(" {} list", args[0]);
Andrew Walbranea9fa482021-03-04 16:11:12 +000039 exit(1);
40 }
41
42 // We need to start the thread pool for Binder to work properly, especially link_to_death.
43 ProcessState::start_thread_pool();
44
Andrew Walbran320b5602021-03-04 16:11:12 +000045 let virt_manager = get_interface(VIRT_MANAGER_BINDER_SERVICE_IDENTIFIER)
46 .context("Failed to find Virt Manager service")?;
47
Andrew Walbranea9fa482021-03-04 16:11:12 +000048 match args[1].as_ref() {
Andrew Walbran320b5602021-03-04 16:11:12 +000049 "run" if args.len() == 3 => command_run(virt_manager, &args[2]),
50 "list" if args.len() == 2 => command_list(virt_manager),
Andrew Walbranea9fa482021-03-04 16:11:12 +000051 command => bail!("Invalid command '{}' or wrong number of arguments", command),
52 }
53}
54
55/// Run a VM from the given configuration file.
Andrew Walbran320b5602021-03-04 16:11:12 +000056fn command_run(virt_manager: Strong<dyn IVirtManager>, config_filename: &str) -> Result<(), Error> {
57 let vm = virt_manager.startVm(config_filename).context("Failed to start VM")?;
58 let cid = vm.getCid().context("Failed to get CID")?;
Andrew Walbranea9fa482021-03-04 16:11:12 +000059 println!("Started VM from {} with CID {}.", config_filename, cid);
60
61 // Wait until the VM dies. If we just returned immediately then the IVirtualMachine Binder
62 // object would be dropped and the VM would be killed.
63 wait_for_death(&mut vm.as_binder())?;
64 println!("VM died");
65 Ok(())
66}
67
Andrew Walbran320b5602021-03-04 16:11:12 +000068/// List the VMs currently running.
69fn command_list(virt_manager: Strong<dyn IVirtManager>) -> Result<(), Error> {
70 let vms = virt_manager.debugListVms().context("Failed to get list of VMs")?;
71 println!("Running VMs: {:#?}", vms);
72 Ok(())
73}
74
Andrew Walbranea9fa482021-03-04 16:11:12 +000075/// Block until the given Binder object dies.
76fn wait_for_death(binder: &mut impl IBinder) -> Result<(), Error> {
77 let dead = AtomicFlag::default();
78 let mut death_recipient = {
79 let dead = dead.clone();
80 DeathRecipient::new(move || {
81 dead.raise();
82 })
83 };
84 binder.link_to_death(&mut death_recipient)?;
85 dead.wait();
86 Ok(())
87}