blob: ac5531a463c0d187479cddf0288ca87b06624376 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "host/libs/vm_manager/vm_manager.h"
#include <memory>
#include <glog/logging.h>
#include <sys/utsname.h>
#include "common/libs/utils/users.h"
#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/vm_manager/qemu_manager.h"
#include "host/libs/vm_manager/crosvm_manager.h"
namespace vm_manager {
VmManager::VmManager(const vsoc::CuttlefishConfig* config)
: config_(config) {}
namespace{
template <typename T>
VmManager* GetManagerSingleton(const vsoc::CuttlefishConfig* config) {
static std::shared_ptr<VmManager> vm_manager(new T(config));
return vm_manager.get();
}
}
std::map<std::string, VmManager::VmManagerHelper>
VmManager::vm_manager_helpers_ = {
{
QemuManager::name(),
{
[](const vsoc::CuttlefishConfig* config) {
return GetManagerSingleton<QemuManager>(config);
},
[]() { return vsoc::HostSupportsQemuCli(); },
[](vsoc::CuttlefishConfig* c) {
return QemuManager::ConfigureGpu(c);
},
[](vsoc::CuttlefishConfig* c) {
return QemuManager::ConfigureBootDevices(c);
}
},
},
{
CrosvmManager::name(),
{
[](const vsoc::CuttlefishConfig* config) {
return GetManagerSingleton<CrosvmManager>(config);
},
// Same as Qemu for the time being
[]() { return vsoc::HostSupportsQemuCli(); },
[](vsoc::CuttlefishConfig* c) {
return CrosvmManager::ConfigureGpu(c);
},
[](vsoc::CuttlefishConfig* c) {
return CrosvmManager::ConfigureBootDevices(c);
}
}
}
};
VmManager* VmManager::Get(const std::string& vm_manager_name,
const vsoc::CuttlefishConfig* config) {
if (VmManager::IsValidName(vm_manager_name)) {
return vm_manager_helpers_[vm_manager_name].builder(config);
}
LOG(ERROR) << "Requested invalid VmManager: " << vm_manager_name;
return nullptr;
}
bool VmManager::IsValidName(const std::string& name) {
return vm_manager_helpers_.count(name) > 0;
}
bool VmManager::IsVmManagerSupported(const std::string& name) {
return VmManager::IsValidName(name) &&
vm_manager_helpers_[name].support_checker();
}
bool VmManager::ConfigureGpuMode(vsoc::CuttlefishConfig* config) {
auto it = vm_manager_helpers_.find(config->vm_manager());
if (it == vm_manager_helpers_.end()) {
return false;
}
return it->second.configure_gpu_mode(config);
}
void VmManager::ConfigureBootDevices(vsoc::CuttlefishConfig* config) {
auto it = vm_manager_helpers_.find(config->vm_manager());
if (it == vm_manager_helpers_.end()) {
return;
}
it->second.configure_boot_devices(config);
}
std::vector<std::string> VmManager::GetValidNames() {
std::vector<std::string> ret = {};
for (const auto& key_val: vm_manager_helpers_) {
ret.push_back(key_val.first);
}
return ret;
}
bool VmManager::UserInGroup(const std::string& group,
std::vector<std::string>* config_commands) {
if (!cvd::InGroup(group)) {
LOG(ERROR) << "User must be a member of " << group;
config_commands->push_back("# Add your user to the " + group + " group:");
config_commands->push_back("sudo usermod -aG " + group + " $USER");
return false;
}
return true;
}
bool VmManager::LinuxVersionAtLeast4_8(std::vector<std::string>* config_commands) {
struct utsname info;
if (!uname(&info)) {
char* digit = strtok(info.release, "+.-");
int major = atoi(digit);
if (digit) {
digit = strtok(NULL, "+.-");
int minor = atoi(digit);
if (major > 4 || (major == 4 && minor >= 8)) {
return true;
}
}
}
LOG(ERROR) << "Kernel version must be >=4.8";
config_commands->push_back("# Please upgrade your kernel to >=4.8");
return false;
}
bool VmManager::ValidateHostConfiguration(
std::vector<std::string>* config_commands) const {
// the check for cvdnetwork needs to happen even if the user is not in kvm, so
// we can't just say UserInGroup("kvm") && UserInGroup("cvdnetwork")
auto in_kvm = VmManager::UserInGroup("kvm", config_commands);
auto in_cvdnetwork = VmManager::UserInGroup("cvdnetwork", config_commands);
auto linux_ver_4_8 = VmManager::LinuxVersionAtLeast4_8(config_commands);
return in_kvm && in_cvdnetwork && linux_ver_4_8;
}
} // namespace vm_manager