blob: 6291d59eee2a243c4c791efd91b2e89e76ae61c5 [file] [log] [blame]
Alan Stokesa2869d22021-09-22 09:06:41 +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
Alan Stokes6b2d0a82021-09-29 11:30:39 +010017//! Manages running instances of the CompOS VM. At most one instance should be running at
18//! a time, started on demand.
Alan Stokesa2869d22021-09-22 09:06:41 +010019
Alan Stokes6b2d0a82021-09-29 11:30:39 +010020use crate::instance_starter::{CompOsInstance, InstanceStarter};
21use android_system_virtualizationservice::aidl::android::system::virtualizationservice;
Alan Stokesa2869d22021-09-22 09:06:41 +010022use anyhow::{bail, Context, Result};
23use compos_aidl_interface::aidl::com::android::compos::ICompOsService::ICompOsService;
Alan Stokes6b2d0a82021-09-29 11:30:39 +010024use compos_aidl_interface::binder::Strong;
Alan Stokesd21764c2021-10-25 15:33:40 +010025use compos_common::compos_client::VmParameters;
Alan Stokes388b88a2021-10-13 16:03:17 +010026use compos_common::{CURRENT_INSTANCE_DIR, TEST_INSTANCE_DIR};
Alan Stokesa2869d22021-09-22 09:06:41 +010027use std::sync::{Arc, Mutex, Weak};
Alan Stokes6b2d0a82021-09-29 11:30:39 +010028use virtualizationservice::IVirtualizationService::IVirtualizationService;
Alan Stokesa2869d22021-09-22 09:06:41 +010029
Alan Stokes69c610f2021-09-27 14:03:31 +010030pub struct InstanceManager {
31 service: Strong<dyn IVirtualizationService>,
32 state: Mutex<State>,
33}
Alan Stokesa2869d22021-09-22 09:06:41 +010034
35impl InstanceManager {
Alan Stokes69c610f2021-09-27 14:03:31 +010036 pub fn new(service: Strong<dyn IVirtualizationService>) -> Self {
37 Self { service, state: Default::default() }
38 }
39
Alan Stokesa2869d22021-09-22 09:06:41 +010040 pub fn get_running_service(&self) -> Result<Strong<dyn ICompOsService>> {
Alan Stokes69c610f2021-09-27 14:03:31 +010041 let mut state = self.state.lock().unwrap();
Alan Stokesa2869d22021-09-22 09:06:41 +010042 let instance = state.get_running_instance().context("No running instance")?;
Alan Stokes6b2d0a82021-09-29 11:30:39 +010043 Ok(instance.get_service())
Alan Stokesa2869d22021-09-22 09:06:41 +010044 }
45
Alan Stokes388b88a2021-10-13 16:03:17 +010046 #[allow(dead_code)] // TODO: Make use of this
Alan Stokesa2869d22021-09-22 09:06:41 +010047 pub fn start_current_instance(&self) -> Result<Arc<CompOsInstance>> {
Alan Stokesd21764c2021-10-25 15:33:40 +010048 self.start_instance(CURRENT_INSTANCE_DIR, VmParameters::default())
Alan Stokes388b88a2021-10-13 16:03:17 +010049 }
50
51 pub fn start_test_instance(&self) -> Result<Arc<CompOsInstance>> {
Alan Stokesd21764c2021-10-25 15:33:40 +010052 let vm_parameters = VmParameters { debug_mode: true };
53 self.start_instance(TEST_INSTANCE_DIR, vm_parameters)
Alan Stokes388b88a2021-10-13 16:03:17 +010054 }
55
Alan Stokesd21764c2021-10-25 15:33:40 +010056 fn start_instance(
57 &self,
58 instance_name: &str,
59 vm_parameters: VmParameters,
60 ) -> Result<Arc<CompOsInstance>> {
Alan Stokes69c610f2021-09-27 14:03:31 +010061 let mut state = self.state.lock().unwrap();
Alan Stokesa2869d22021-09-22 09:06:41 +010062 state.mark_starting()?;
63 // Don't hold the lock while we start the instance to avoid blocking other callers.
64 drop(state);
65
Alan Stokesd21764c2021-10-25 15:33:40 +010066 let instance_starter = InstanceStarter::new(instance_name, vm_parameters);
67 let instance = self.try_start_instance(instance_starter);
Alan Stokesa2869d22021-09-22 09:06:41 +010068
Alan Stokes69c610f2021-09-27 14:03:31 +010069 let mut state = self.state.lock().unwrap();
Alan Stokesa2869d22021-09-22 09:06:41 +010070 if let Ok(ref instance) = instance {
71 state.mark_started(instance)?;
72 } else {
73 state.mark_stopped();
74 }
75 instance
76 }
77
Alan Stokesd21764c2021-10-25 15:33:40 +010078 fn try_start_instance(&self, instance_starter: InstanceStarter) -> Result<Arc<CompOsInstance>> {
Alan Stokes6b2d0a82021-09-29 11:30:39 +010079 let compos_instance = instance_starter.create_or_start_instance(&*self.service)?;
Alan Stokes69c610f2021-09-27 14:03:31 +010080 Ok(Arc::new(compos_instance))
81 }
82}
83
Alan Stokesa2869d22021-09-22 09:06:41 +010084// Ensures we only run one instance at a time.
85// Valid states:
86// Starting: is_starting is true, running_instance is None.
87// Started: is_starting is false, running_instance is Some(x) and there is a strong ref to x.
88// Stopped: is_starting is false and running_instance is None or a weak ref to a dropped instance.
Alan Stokes69c610f2021-09-27 14:03:31 +010089// The panic calls here should never happen, unless the code above in InstanceManager is buggy.
90// In particular nothing the client does should be able to trigger them.
Alan Stokesa2869d22021-09-22 09:06:41 +010091#[derive(Default)]
92struct State {
93 running_instance: Option<Weak<CompOsInstance>>,
94 is_starting: bool,
95}
96
97impl State {
98 // Move to Starting iff we are Stopped.
99 fn mark_starting(&mut self) -> Result<()> {
100 if self.is_starting {
101 bail!("An instance is already starting");
102 }
103 if let Some(weak) = &self.running_instance {
104 if weak.strong_count() != 0 {
105 bail!("An instance is already running");
106 }
107 }
108 self.running_instance = None;
109 self.is_starting = true;
110 Ok(())
111 }
112
113 // Move from Starting to Stopped.
114 fn mark_stopped(&mut self) {
115 if !self.is_starting || self.running_instance.is_some() {
116 panic!("Tried to mark stopped when not starting");
117 }
118 self.is_starting = false;
119 }
120
121 // Move from Starting to Started.
122 fn mark_started(&mut self, instance: &Arc<CompOsInstance>) -> Result<()> {
123 if !self.is_starting {
124 panic!("Tried to mark started when not starting")
125 }
126 if self.running_instance.is_some() {
127 panic!("Attempted to mark started when already started");
128 }
129 self.is_starting = false;
130 self.running_instance = Some(Arc::downgrade(instance));
131 Ok(())
132 }
133
134 // Return the running instance if we are in the Started state.
135 fn get_running_instance(&mut self) -> Option<Arc<CompOsInstance>> {
136 if self.is_starting {
137 return None;
138 }
139 let instance = self.running_instance.as_ref()?.upgrade();
140 if instance.is_none() {
141 // No point keeping an orphaned weak reference
142 self.running_instance = None;
143 }
144 instance
145 }
146}