blob: a02ce0c8cbf6836f4cf4741dbf32754495fd29dd [file] [log] [blame]
// Copyright 2019 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 "ml/util.h"
#include <memory>
#include <string>
#include <vector>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/memory/free_deleter.h>
#include <base/process/process.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
namespace ml {
namespace {
constexpr char kDlcBasePath[] = "/run/imageloader";
// Extracts the value from a value string of /proc/[pid]/status.
// Only works for value strings in the form of "value kB".
// Returns true if value could be extracted, false otherwise.
bool GetValueFromProcStatusValueStr(const std::string& value_str,
size_t* value) {
const std::vector<base::StringPiece> split_value_str = base::SplitStringPiece(
value_str, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (split_value_str.size() != 2 || split_value_str[1] != "kB")
return false;
return StringToSizeT(split_value_str[0], value);
}
} // namespace
bool MemoryUsage::operator==(const MemoryUsage& other) const {
return this->VmRSSKb == other.VmRSSKb && this->VmSwapKb == other.VmSwapKb;
}
bool GetProcessMemoryUsageFromFile(MemoryUsage* memory_usage,
const base::FilePath& file_path) {
std::string status_data;
if (!ReadFileToString(file_path, &status_data)) {
LOG(WARNING) << "Can not open status file";
return false;
}
base::StringPairs key_value_pairs;
base::SplitStringIntoKeyValuePairs(status_data, ':', '\n', &key_value_pairs);
bool vmrss_found = false;
bool vmswap_found = false;
for (auto& pair : key_value_pairs) {
std::string& key = pair.first;
std::string& value_str = pair.second;
base::TrimWhitespaceASCII(key, base::TRIM_ALL, &key);
if (key == "VmRSS") {
if (vmrss_found)
return false; // Duplicates should not happen.
base::TrimWhitespaceASCII(value_str, base::TRIM_ALL, &value_str);
if (!GetValueFromProcStatusValueStr(value_str, &memory_usage->VmRSSKb))
return false;
vmrss_found = true;
}
if (key == "VmSwap") {
if (vmswap_found)
return false; // Duplicates should not happen.
base::TrimWhitespaceASCII(value_str, base::TRIM_ALL, &value_str);
if (!GetValueFromProcStatusValueStr(value_str, &memory_usage->VmSwapKb))
return false;
vmswap_found = true;
}
}
return vmrss_found && vmswap_found;
}
bool GetProcessMemoryUsage(MemoryUsage* memory_usage, pid_t pid) {
const base::FilePath status_file_path = base::FilePath("/proc")
.Append(base::NumberToString(pid))
.Append("status");
return GetProcessMemoryUsageFromFile(memory_usage, status_file_path);
}
bool GetProcessMemoryUsage(MemoryUsage* memory_usage) {
return GetProcessMemoryUsage(memory_usage, base::Process::Current().Pid());
}
bool GetTotalProcessMemoryUsage(size_t* total_memory) {
MemoryUsage memory_usage;
if (GetProcessMemoryUsage(&memory_usage)) {
*total_memory = memory_usage.VmRSSKb + memory_usage.VmSwapKb;
return true;
}
return false;
}
// Gives resolved path using realpath(3), or empty Optional upon error. Leaves
// realpath's errno unchanged.
base::Optional<base::FilePath> GetRealPath(const base::FilePath& path) {
const std::unique_ptr<char, base::FreeDeleter> result(
realpath(path.value().c_str(), nullptr));
if (!result) {
return {};
}
return base::FilePath(result.get());
}
bool IsDlcPathValid(const base::FilePath& path) {
return base::StartsWith(path.value(), kDlcBasePath);
}
} // namespace ml