blob: 16e9cecb7d31090ea4877d08a04174232494d6b2 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "runtime_probe/functions/edid.h"
#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/json/json_reader.h>
#include <base/json/json_writer.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringprintf.h>
#include <base/values.h>
#include <pcrecpp.h>
#include <numeric>
#include <utility>
#include "runtime_probe/utils/edid.h"
#include "runtime_probe/utils/file_utils.h"
namespace runtime_probe {
namespace {
constexpr char kSysfsDrmPath[] = "/sys/class/drm/*";
} // namespace
std::unique_ptr<EdidFunction> EdidFunction::FromKwargsValue(
const base::Value& dict_value) {
if (dict_value.DictSize() != 0)
return nullptr;
auto instance = std::make_unique<EdidFunction>();
bool result = true;
result &= PARSE_ARGUMENT(dir_path, {kSysfsDrmPath});
if (!result)
return nullptr;
return instance;
}
EdidFunction::DataType EdidFunction::Eval() const {
auto json_output = InvokeHelperToJSON();
if (!json_output) {
LOG(ERROR) << "Failed to invoke helper to retrieve edid results.";
return {};
}
if (!json_output->is_list()) {
LOG(ERROR) << "Failed to parse json output as list.";
return {};
}
return DataType(json_output->TakeList());
}
int EdidFunction::EvalInHelper(std::string* output) const {
base::Value result(base::Value::Type::LIST);
// Store paths which have been evaluated.
base::Value evaluated_path(base::Value::Type::DICTIONARY);
for (const auto& dir_path : dir_path_) {
for (const auto& edid_path : GetEdidPaths(base::FilePath(dir_path))) {
if (evaluated_path.FindKey(edid_path.value()))
continue;
auto node_res = EvalInHelperByPath(edid_path);
if (node_res.DictEmpty()) {
evaluated_path.SetBoolKey(edid_path.value(), false);
continue;
}
evaluated_path.SetBoolKey(edid_path.value(), true);
result.Append(std::move(node_res));
}
}
if (!base::JSONWriter::Write(result, output)) {
LOG(ERROR) << "Failed to serialize edid probed result to json string";
return -1;
}
return 0;
}
std::vector<base::FilePath> EdidFunction::GetEdidPaths(
const base::FilePath& glob_path) const {
std::vector<base::FilePath> edid_list;
const auto glob_root = glob_path.DirName();
const auto glob_pattern = glob_path.BaseName();
base::FileEnumerator drm_it(glob_root, false,
base::FileEnumerator::FileType::DIRECTORIES,
glob_pattern.value());
while (true) {
const auto drm_path = drm_it.Next();
if (drm_path.empty())
break;
const auto edid_path = drm_path.Append("edid");
if (base::PathExists(edid_path)) {
edid_list.push_back(edid_path);
}
}
return edid_list;
}
base::Value EdidFunction::EvalInHelperByPath(
const base::FilePath& edid_path) const {
VLOG(2) << "Processing the node \"" << edid_path.value() << "\"";
std::string raw_bytes;
if (!base::ReadFileToString(edid_path, &raw_bytes))
return base::Value(base::Value::Type::DICTIONARY);
if (raw_bytes.length() == 0) {
return base::Value(base::Value::Type::DICTIONARY);
}
base::Value res(base::Value::Type::DICTIONARY);
auto edid =
Edid::From(std::vector<uint8_t>(raw_bytes.begin(), raw_bytes.end()));
if (!edid) {
return res;
}
res.SetStringKey("vendor", edid->vendor);
res.SetStringKey("product_id", base::StringPrintf("%04x", edid->product_id));
res.SetIntKey("width", edid->width);
res.SetIntKey("height", edid->height);
res.SetStringKey("path", edid_path.value());
return res;
}
} // namespace runtime_probe