blob: da6be7c23660c2d968f77cffd8de0385d86572f1 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "patchpanel/patchpanel_daemon.h"
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdint.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <algorithm>
#include <set>
#include <utility>
#include <base/files/scoped_file.h>
#include <base/functional/bind.h>
#include <base/logging.h>
#include <base/notreached.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/task/single_thread_task_runner.h>
#include <brillo/key_value_store.h>
#include <metrics/metrics_library.h>
#include <shill/net/process_manager.h>
#include "patchpanel/ipc.h"
#include "patchpanel/metrics.h"
#include "patchpanel/proto_utils.h"
#include "patchpanel/shill_client.h"
namespace patchpanel {
PatchpanelDaemon::PatchpanelDaemon(const base::FilePath& cmd_path)
: DBusServiceDaemon(kPatchPanelServiceName),
cmd_path_(cmd_path),
system_(std::make_unique<System>()),
process_manager_(shill::ProcessManager::GetInstance()),
metrics_(std::make_unique<MetricsLibrary>()) {}
std::map<const std::string, bool> PatchpanelDaemon::cached_feature_enabled_ =
{};
bool PatchpanelDaemon::ShouldEnableFeature(
int min_android_sdk_version,
int min_chrome_milestone,
const std::vector<std::string>& supported_boards,
const std::string& feature_name) {
static const char kLsbReleasePath[] = "/etc/lsb-release";
const auto& cached_result = cached_feature_enabled_.find(feature_name);
if (cached_result != cached_feature_enabled_.end())
return cached_result->second;
auto check = [min_android_sdk_version, min_chrome_milestone,
&supported_boards, &feature_name]() {
brillo::KeyValueStore store;
if (!store.Load(base::FilePath(kLsbReleasePath))) {
LOG(ERROR) << "Could not read lsb-release";
return false;
}
std::string value;
if (!store.GetString("CHROMEOS_ARC_ANDROID_SDK_VERSION", &value)) {
LOG(ERROR) << feature_name
<< " disabled - cannot determine Android SDK version";
return false;
}
int ver = 0;
if (!base::StringToInt(value.c_str(), &ver)) {
LOG(ERROR) << feature_name << " disabled - invalid Android SDK version";
return false;
}
if (ver < min_android_sdk_version) {
LOG(INFO) << feature_name << " disabled for Android SDK " << value;
return false;
}
if (!store.GetString("CHROMEOS_RELEASE_CHROME_MILESTONE", &value)) {
LOG(ERROR) << feature_name
<< " disabled - cannot determine ChromeOS milestone";
return false;
}
if (!base::StringToInt(value.c_str(), &ver)) {
LOG(ERROR) << feature_name << " disabled - invalid ChromeOS milestone";
return false;
}
if (ver < min_chrome_milestone) {
LOG(INFO) << feature_name << " disabled for ChromeOS milestone " << value;
return false;
}
if (!store.GetString("CHROMEOS_RELEASE_BOARD", &value)) {
LOG(ERROR) << feature_name << " disabled - cannot determine board";
return false;
}
if (!supported_boards.empty() &&
std::find(supported_boards.begin(), supported_boards.end(), value) ==
supported_boards.end()) {
LOG(INFO) << feature_name << " disabled for board " << value;
return false;
}
return true;
};
bool result = check();
cached_feature_enabled_.emplace(feature_name, result);
return result;
}
void PatchpanelDaemon::RegisterDBusObjectsAsync(
brillo::dbus_utils::AsyncEventSequencer* sequencer) {
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
// Initialize |process_manager_| before creating subprocesses.
process_manager_->Init();
auto rtnl_client = RTNLClient::Create();
if (!rtnl_client) {
LOG(ERROR) << "Failed to create RTNLClient, abort registering the adaptor";
return;
}
adaptor_ = std::make_unique<PatchpanelAdaptor>(
cmd_path_, bus_, system_.get(), process_manager_, metrics_.get(),
std::move(rtnl_client));
adaptor_->RegisterAsync(
sequencer->GetHandler("RegisterAsync() failed", true));
}
void PatchpanelDaemon::OnShutdown(int* exit_code) {
LOG(INFO) << "Shutting down and cleaning up";
adaptor_.reset();
// Stop |process_manager_| after subprocesses are finished.
process_manager_->Stop();
if (bus_) {
bus_->ShutdownAndBlock();
}
brillo::DBusDaemon::OnShutdown(exit_code);
}
} // namespace patchpanel