blob: 6b36ed89fefdb2f5e7d12c980feb717fa83635c0 [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;
25use compos_common::CURRENT_DIR;
Alan Stokesa2869d22021-09-22 09:06:41 +010026use std::sync::{Arc, Mutex, Weak};
Alan Stokes6b2d0a82021-09-29 11:30:39 +010027use virtualizationservice::IVirtualizationService::IVirtualizationService;
Alan Stokesa2869d22021-09-22 09:06:41 +010028
Alan Stokes69c610f2021-09-27 14:03:31 +010029pub struct InstanceManager {
30 service: Strong<dyn IVirtualizationService>,
31 state: Mutex<State>,
32}
Alan Stokesa2869d22021-09-22 09:06:41 +010033
34impl InstanceManager {
Alan Stokes69c610f2021-09-27 14:03:31 +010035 pub fn new(service: Strong<dyn IVirtualizationService>) -> Self {
36 Self { service, state: Default::default() }
37 }
38
Alan Stokesa2869d22021-09-22 09:06:41 +010039 pub fn get_running_service(&self) -> Result<Strong<dyn ICompOsService>> {
Alan Stokes69c610f2021-09-27 14:03:31 +010040 let mut state = self.state.lock().unwrap();
Alan Stokesa2869d22021-09-22 09:06:41 +010041 let instance = state.get_running_instance().context("No running instance")?;
Alan Stokes6b2d0a82021-09-29 11:30:39 +010042 Ok(instance.get_service())
Alan Stokesa2869d22021-09-22 09:06:41 +010043 }
44
45 pub fn start_current_instance(&self) -> Result<Arc<CompOsInstance>> {
Alan Stokes69c610f2021-09-27 14:03:31 +010046 let mut state = self.state.lock().unwrap();
Alan Stokesa2869d22021-09-22 09:06:41 +010047 state.mark_starting()?;
48 // Don't hold the lock while we start the instance to avoid blocking other callers.
49 drop(state);
50
51 let instance = self.try_start_current_instance();
52
Alan Stokes69c610f2021-09-27 14:03:31 +010053 let mut state = self.state.lock().unwrap();
Alan Stokesa2869d22021-09-22 09:06:41 +010054 if let Ok(ref instance) = instance {
55 state.mark_started(instance)?;
56 } else {
57 state.mark_stopped();
58 }
59 instance
60 }
61
62 fn try_start_current_instance(&self) -> Result<Arc<CompOsInstance>> {
Alan Stokes6b2d0a82021-09-29 11:30:39 +010063 let instance_starter = InstanceStarter::new(CURRENT_DIR);
64 let compos_instance = instance_starter.create_or_start_instance(&*self.service)?;
Alan Stokes69c610f2021-09-27 14:03:31 +010065
66 Ok(Arc::new(compos_instance))
67 }
68}
69
Alan Stokesa2869d22021-09-22 09:06:41 +010070// Ensures we only run one instance at a time.
71// Valid states:
72// Starting: is_starting is true, running_instance is None.
73// Started: is_starting is false, running_instance is Some(x) and there is a strong ref to x.
74// 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 +010075// The panic calls here should never happen, unless the code above in InstanceManager is buggy.
76// In particular nothing the client does should be able to trigger them.
Alan Stokesa2869d22021-09-22 09:06:41 +010077#[derive(Default)]
78struct State {
79 running_instance: Option<Weak<CompOsInstance>>,
80 is_starting: bool,
81}
82
83impl State {
84 // Move to Starting iff we are Stopped.
85 fn mark_starting(&mut self) -> Result<()> {
86 if self.is_starting {
87 bail!("An instance is already starting");
88 }
89 if let Some(weak) = &self.running_instance {
90 if weak.strong_count() != 0 {
91 bail!("An instance is already running");
92 }
93 }
94 self.running_instance = None;
95 self.is_starting = true;
96 Ok(())
97 }
98
99 // Move from Starting to Stopped.
100 fn mark_stopped(&mut self) {
101 if !self.is_starting || self.running_instance.is_some() {
102 panic!("Tried to mark stopped when not starting");
103 }
104 self.is_starting = false;
105 }
106
107 // Move from Starting to Started.
108 fn mark_started(&mut self, instance: &Arc<CompOsInstance>) -> Result<()> {
109 if !self.is_starting {
110 panic!("Tried to mark started when not starting")
111 }
112 if self.running_instance.is_some() {
113 panic!("Attempted to mark started when already started");
114 }
115 self.is_starting = false;
116 self.running_instance = Some(Arc::downgrade(instance));
117 Ok(())
118 }
119
120 // Return the running instance if we are in the Started state.
121 fn get_running_instance(&mut self) -> Option<Arc<CompOsInstance>> {
122 if self.is_starting {
123 return None;
124 }
125 let instance = self.running_instance.as_ref()?.upgrade();
126 if instance.is_none() {
127 // No point keeping an orphaned weak reference
128 self.running_instance = None;
129 }
130 instance
131 }
132}