blob: a84ac04dc715918b22aeacf787cdd0efd61974c3 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 "src/ledger/bin/testing/ledger_memory_usage.h"
#include <lib/zx/object.h>
#include <lib/zx/process.h>
#include <src/lib/fxl/logging.h>
#include <src/lib/fxl/strings/string_view.h>
#include <task-utils/walker.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <string>
namespace ledger {
namespace {
constexpr fxl::StringView kLedgerBinaryName = "ledger.cmx";
// Retrieves the name of the task with the given handle. Returns true on
// success, or false otherwise.
bool GetTaskName(zx::unowned<zx::process>& task, std::string* name) {
char task_name[ZX_MAX_NAME_LEN];
zx_status_t status =
task->get_property(ZX_PROP_NAME, task_name, ZX_MAX_NAME_LEN);
if (status != ZX_OK) {
// Failed to get the name of task.
return false;
}
*name = std::string(task_name);
return true;
}
// Retrieves the private bytes used by the given task. Returns true on success,
// or false otherwise.
bool GetMemoryUsageForTask(zx::process& task, uint64_t* memory) {
zx_info_task_stats_t info;
zx_status_t status =
task.get_info(ZX_INFO_TASK_STATS, &info, sizeof(info), nullptr, nullptr);
if (status != ZX_OK) {
return false;
}
*memory = info.mem_private_bytes;
return true;
}
// |Walker| is a |TaskEnumerator| used to find the Ledger process and the
// corresponding handle.
class Walker final : public TaskEnumerator {
public:
Walker() = default;
~Walker() = default;
// TaskEnumerator:
zx_status_t OnProcess(int depth, zx_handle_t task, zx_koid_t koid,
zx_koid_t /*pkoid*/) override {
zx::unowned<zx::process> unowned_task(task);
std::string process_name;
FXL_CHECK(GetTaskName(unowned_task, &process_name));
if (process_name == kLedgerBinaryName) {
if (ledger_handle_.is_valid()) {
// This is the second Ledger process we find: interrupt the iteration by
// returning a status different than |ZK_OK|.
return ZX_ERR_ALREADY_EXISTS;
}
// This process corresponds to Ledger.
FXL_CHECK(unowned_task->duplicate(ZX_RIGHT_SAME_RIGHTS,
&ledger_handle_) == ZX_OK);
}
return ZX_OK;
}
// Returns the handle of the Ledger process, or an invalid handle if it was
// not found. This method should be called only after a successful termination
// of |Walker::WalkRootJobTree()|. The caller takes ownership of the returned
// handle, meaning that this method can only be called once.
zx::process TakeLedgerHandle() { return std::move(ledger_handle_); }
protected:
// TaskEnumerator:
bool has_on_process() const override { return true; }
private:
zx::process ledger_handle_;
};
} // namespace
LedgerMemoryEstimator::LedgerMemoryEstimator() = default;
LedgerMemoryEstimator::~LedgerMemoryEstimator() = default;
bool LedgerMemoryEstimator::Init() {
FXL_DCHECK(!ledger_task_.is_valid()) << "Init should only be called once";
Walker walker;
zx_status_t status = walker.WalkRootJobTree();
if (status == ZX_ERR_ALREADY_EXISTS) {
// TODO(nellyv): Update so that we know how which Ledger corresponds to the
// test being executed.
FXL_LOG(ERROR) << "More than one Ledger processes are running.";
return false;
}
ledger_task_ = walker.TakeLedgerHandle();
if (!ledger_task_.is_valid()) {
FXL_LOG(ERROR) << "Failed to find a Ledger process.";
return false;
}
return true;
}
bool LedgerMemoryEstimator::GetLedgerMemoryUsage(uint64_t* memory) {
FXL_CHECK(ledger_task_);
return GetMemoryUsageForTask(ledger_task_, memory);
}
} // namespace ledger