blob: 4fc086d158a9fb5d2967774534e7e9a05d7cc144 [file] [log] [blame]
//
// Copyright (C) 2023 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/commands/secure_env/snapshot_control.h"
#include <unistd.h>
#include <mutex>
#include <thread>
#include "common/libs/fs/shared_buf.h"
#include "host/libs/command_util/runner/defs.h"
#include "host/libs/command_util/util.h"
#include "host/libs/config/cuttlefish_config.h"
#include "run_cvd.pb.h"
namespace cuttlefish {
Result<std::unique_ptr<SnapshotController>>
SnapshotController::CreateSnapshotController(
const SharedFD& channel_to_run_cvd) {
auto* config = CuttlefishConfig::Get();
CF_EXPECT(config != nullptr, "Failed to get cuttlefish config.");
CF_EXPECT(channel_to_run_cvd->IsOpen(),
"Failed to open suspend/resume control socket.");
SnapshotController* new_controller =
new SnapshotController(channel_to_run_cvd, config->IsCrosvm());
CF_EXPECT(new_controller != nullptr,
"Memory allocation for SnapshotController failed.");
return std::unique_ptr<SnapshotController>(new_controller);
}
SnapshotController::SnapshotController(const SharedFD& fd, const bool is_crosvm)
: channel_to_run_cvd_(fd), is_crosvm_(is_crosvm), suspended_{false} {}
bool SnapshotController::ResumeAndNotify() {
std::unique_lock writer_lock(reader_writer_mutex_, std::defer_lock);
if (!writer_lock.try_lock()) {
return false;
}
suspended_ = false;
writer_lock.unlock();
suspended_cv_.notify_all();
return true;
}
bool SnapshotController::TrySuspend() {
std::unique_lock writer_lock(reader_writer_mutex_, std::defer_lock);
if (!writer_lock.try_lock()) {
return false;
}
suspended_ = true;
return true;
}
Result<void> SnapshotController::ControllerLoop() {
LOG(INFO) << "run_cvd connected to secure_env";
CF_EXPECT(channel_to_run_cvd_->IsOpen());
while (true) {
auto launcher_action =
CF_EXPECT(ReadLauncherActionFromFd(channel_to_run_cvd_),
"Failed to read LauncherAction from run_cvd");
CF_EXPECT(launcher_action.action == LauncherAction::kExtended);
const auto action_type = launcher_action.type;
CF_EXPECTF(action_type == ExtendedActionType::kSuspend ||
action_type == ExtendedActionType::kResume,
"Unsupported ExtendedActionType \"{}\"", action_type);
auto response = LauncherResponse::kError;
if (action_type == ExtendedActionType::kSuspend) {
if (TrySuspend()) {
response = LauncherResponse::kSuccess;
}
} else {
if (ResumeAndNotify()) {
response = LauncherResponse::kSuccess;
}
}
const auto n_written =
channel_to_run_cvd_->Write(&response, sizeof(response));
CF_EXPECT_EQ(n_written, sizeof(response));
}
return {};
}
void SnapshotController::WaitInitializedOrResumed() {
std::shared_lock reader_lock(reader_writer_mutex_);
std::atomic<bool>* suspended_atomic_ptr = &suspended_;
suspended_cv_.wait(reader_lock, [suspended_atomic_ptr]() {
return !(suspended_atomic_ptr->load());
});
}
} // namespace cuttlefish