diff --git a/aidl/memtrack/core/Android.bp b/aidl/memtrack/core/Android.bp new file mode 100644 index 00000000..cfce23ec --- /dev/null +++ b/aidl/memtrack/core/Android.bp @@ -0,0 +1,34 @@ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_shared { + name: "libmemtrack-pixel", + vendor: true, + srcs: [ + "Memtrack.cpp", + "GpuSysfsReader.cpp", + "filesystem.cpp", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "android.hardware.memtrack-V1-ndk", + "libbase", + "libbinder_ndk", + "liblog", + ], + cppflags: [ + "-Wall", + "-Werror", + "-Wformat", + "-Wthread-safety", + "-Wunused", + "-Wunreachable-code", + ], + visibility: [ + "//hardware/google/graphics/common/memtrack-pixel/service:__pkg__" + ], +} diff --git a/aidl/memtrack/core/GpuSysfsReader.cpp b/aidl/memtrack/core/GpuSysfsReader.cpp new file mode 100644 index 00000000..48e09a2d --- /dev/null +++ b/aidl/memtrack/core/GpuSysfsReader.cpp @@ -0,0 +1,59 @@ +#include "GpuSysfsReader.h" + +#include + +#include +#include + +#include "filesystem.h" + +#undef LOG_TAG +#define LOG_TAG "memtrack-gpusysfsreader" + +using namespace GpuSysfsReader; + +namespace { +uint64_t readNode(const std::string node, pid_t pid) { + std::stringstream ss; + if (pid) + ss << kSysfsDevicePath << "/" << kProcessDir << "/" << pid << "/" << node; + else + ss << kSysfsDevicePath << "/" << node; + const std::string path = ss.str(); + + if (!filesystem::exists(filesystem::path(path))) { + ALOGV("File not found: %s", path.c_str()); + return 0; + } + + std::ifstream file(path.c_str()); + if (!file.is_open()) { + ALOGW("Failed to open %s path", path.c_str()); + return 0; + } + + uint64_t out; + file >> out; + file.close(); + + return out; +} +} // namespace + +uint64_t GpuSysfsReader::getDmaBufGpuMem(pid_t pid) { return readNode(kDmaBufGpuMemNode, pid); } + +uint64_t GpuSysfsReader::getGpuMemTotal(pid_t pid) { return readNode(kTotalGpuMemNode, pid); } + +uint64_t GpuSysfsReader::getPrivateGpuMem(pid_t pid) { + auto dma_buf_size = getDmaBufGpuMem(pid); + auto gpu_total_size = getGpuMemTotal(pid); + + if (dma_buf_size > gpu_total_size) { + ALOGE("Bug in reader, dma-buf size (%" PRIu64 ") is higher than total gpu size (%" PRIu64 + ")", + dma_buf_size, gpu_total_size); + return 0; + } + + return gpu_total_size - dma_buf_size; +} diff --git a/aidl/memtrack/core/GpuSysfsReader.h b/aidl/memtrack/core/GpuSysfsReader.h new file mode 100644 index 00000000..df622d11 --- /dev/null +++ b/aidl/memtrack/core/GpuSysfsReader.h @@ -0,0 +1,17 @@ + +#pragma once + +#include +#include + +namespace GpuSysfsReader { +uint64_t getDmaBufGpuMem(pid_t pid = 0); +uint64_t getGpuMemTotal(pid_t pid = 0); +uint64_t getPrivateGpuMem(pid_t pid = 0); + +constexpr char kSysfsDevicePath[] = "/sys/class/misc/mali0/device"; +constexpr char kProcessDir[] = "kprcs"; +constexpr char kMappedDmaBufsDir[] = "dma_bufs"; +constexpr char kTotalGpuMemNode[] = "total_gpu_mem"; +constexpr char kDmaBufGpuMemNode[] = "dma_buf_gpu_mem"; +} // namespace GpuSysfsReader diff --git a/aidl/memtrack/core/Memtrack.cpp b/aidl/memtrack/core/Memtrack.cpp new file mode 100644 index 00000000..48d4fa7b --- /dev/null +++ b/aidl/memtrack/core/Memtrack.cpp @@ -0,0 +1,79 @@ +#include +#include + +#include +#include +#include + +#include "GpuSysfsReader.h" +#include "filesystem.h" + +#undef LOG_TAG +#define LOG_TAG "memtrack-core" + +namespace aidl { +namespace android { +namespace hardware { +namespace memtrack { + +ndk::ScopedAStatus Memtrack::getMemory(int pid, MemtrackType type, + std::vector* _aidl_return) { + if (pid < 0) + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); + + if (type != MemtrackType::OTHER && type != MemtrackType::GL && type != MemtrackType::GRAPHICS && + type != MemtrackType::MULTIMEDIA && type != MemtrackType::CAMERA) + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + + _aidl_return->clear(); + + // Other types are retained only for backward compatibility + if (type != MemtrackType::GL && type != MemtrackType::GRAPHICS) + return ndk::ScopedAStatus::ok(); + + // pid 0 is only supported for GL type to report total private memory + if (pid == 0 && type != MemtrackType::GL) + return ndk::ScopedAStatus::ok(); + + uint64_t size = 0; + switch (type) { + case MemtrackType::GL: + size = GpuSysfsReader::getPrivateGpuMem(pid); + break; + case MemtrackType::GRAPHICS: + // TODO(b/194483693): This is not PSS as required by memtrack HAL + // but complete dmabuf allocations. Reporting PSS requires reading + // procfs. This HAL does not have that permission yet. + size = GpuSysfsReader::getDmaBufGpuMem(pid); + break; + default: + break; + } + + MemtrackRecord record = { + .flags = MemtrackRecord::FLAG_SMAPS_UNACCOUNTED, + .sizeInBytes = static_cast(size), + }; + _aidl_return->emplace_back(record); + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Memtrack::getGpuDeviceInfo(std::vector* _aidl_return) { + auto devPath = filesystem::path(GpuSysfsReader::kSysfsDevicePath); + std::string devName = "default-gpu"; + if (filesystem::exists(devPath) && filesystem::is_symlink(devPath)) { + devName = filesystem::read_symlink(devPath).filename().string(); + } + + DeviceInfo dev_info = {.id = 0, .name = devName}; + + _aidl_return->clear(); + _aidl_return->emplace_back(dev_info); + return ndk::ScopedAStatus::ok(); +} + +} // namespace memtrack +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/aidl/memtrack/core/filesystem.cpp b/aidl/memtrack/core/filesystem.cpp new file mode 100644 index 00000000..fa25fdcf --- /dev/null +++ b/aidl/memtrack/core/filesystem.cpp @@ -0,0 +1,70 @@ +#include "filesystem.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace filesystem { + +bool exists(const path& p) { + struct stat s; + return stat(p.string().c_str(), &s) == 0; +} + +bool is_directory(const path& p) { + struct stat s; + if (stat(p.string().c_str(), &s)) + return false; + + return S_ISDIR(s.st_mode); +} + +bool is_symlink(const path& p) { + struct stat s; + if (lstat(p.string().c_str(), &s)) + return false; + + return S_ISLNK(s.st_mode); +} + +path read_symlink(const path& p) { + char* actualPath = realpath(p.string().c_str(), NULL); + if (!actualPath) { + return path(p.string()); + } + + path out(actualPath); + free(actualPath); + return out; +} + +std::vector directory_iterator(const path& p) { + if (!exists(p) || !is_directory(p)) + return {}; + + std::unique_ptr dir(opendir(p.string().c_str()), &closedir); + if (!dir) { + ALOGE("Failed to open %s directory", p.string().c_str()); + } + + std::vector out; + struct dirent* dent; + while ((dent = readdir(dir.get()))) { + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) + continue; + + std::stringstream ss(p.string()); + ss << "/" << dent->d_name; + out.emplace_back(ss.str()); + } + + return out; +} + +} // namespace filesystem diff --git a/aidl/memtrack/core/filesystem.h b/aidl/memtrack/core/filesystem.h new file mode 100644 index 00000000..46032231 --- /dev/null +++ b/aidl/memtrack/core/filesystem.h @@ -0,0 +1,60 @@ +// TODO(b/147469372): filesystem library in Android's libcxx is not available +// for vendors. It had an unstable ABI and libcxx isn't updated ever since. + +// This simply implements some of the required functions in not-so-safe fashion. + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace filesystem { +class path { +public: + path(const std::string _path) : strPath(_path) {} + + path filename() const { + auto pos = strPath.rfind('/'); + if (pos == std::string::npos) + return path(strPath); + + pos++; + auto l = strPath.size(); + return path(strPath.substr(pos, l - pos)); + } + + std::string string() const { return strPath; } + +private: + std::string strPath; +}; + +class directory_entry { +public: + directory_entry(const std::string _path) : p(_path) {} + + class path path() { + return p; + } + +private: + class path p; +}; + +bool exists(const path& p); + +bool is_directory(const path& p); + +bool is_symlink(const path& p); + +path read_symlink(const path& p); + +// Vector is easier to create than an iterator and serves our purposes well +std::vector directory_iterator(const path& p); +} // namespace filesystem diff --git a/aidl/memtrack/core/include/Memtrack.h b/aidl/memtrack/core/include/Memtrack.h new file mode 100644 index 00000000..afd06605 --- /dev/null +++ b/aidl/memtrack/core/include/Memtrack.h @@ -0,0 +1,25 @@ + +#pragma once + +#include +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace memtrack { + +class Memtrack : public BnMemtrack { +public: + ndk::ScopedAStatus getMemory(int pid, MemtrackType type, + std::vector* _aidl_return) override; + + ndk::ScopedAStatus getGpuDeviceInfo(std::vector* _aidl_return) override; +}; + +} // namespace memtrack +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/aidl/memtrack/service/Android.bp b/aidl/memtrack/service/Android.bp new file mode 100644 index 00000000..f4084961 --- /dev/null +++ b/aidl/memtrack/service/Android.bp @@ -0,0 +1,20 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_binary { + name: "android.hardware.memtrack-service.pixel", + relative_install_path: "hw", + init_rc: ["memtrack.rc"], + vintf_fragments: ["memtrack.xml"], + vendor: true, + shared_libs: [ + "android.hardware.memtrack-V1-ndk", + "libbase", + "libbinder_ndk", + "libmemtrack-pixel", + ], + srcs: [ + "main.cpp", + ], +} diff --git a/aidl/memtrack/service/main.cpp b/aidl/memtrack/service/main.cpp new file mode 100644 index 00000000..facc4c19 --- /dev/null +++ b/aidl/memtrack/service/main.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +#undef LOG_TAG +#define LOG_TAG "memtrack-service" + +using aidl::android::hardware::memtrack::Memtrack; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + std::shared_ptr memtrack = ndk::SharedRefBase::make(); + + const std::string instance = std::string() + Memtrack::descriptor + "/default"; + binder_status_t status = + AServiceManager_addService(memtrack->asBinder().get(), instance.c_str()); + CHECK(status == STATUS_OK); + + ABinderProcess_joinThreadPool(); + return EXIT_FAILURE; // Unreachable +} diff --git a/aidl/memtrack/service/memtrack.rc b/aidl/memtrack/service/memtrack.rc new file mode 100644 index 00000000..02f5a692 --- /dev/null +++ b/aidl/memtrack/service/memtrack.rc @@ -0,0 +1,4 @@ +service vendor.memtrack-default /vendor/bin/hw/android.hardware.memtrack-service.pixel + class hal + user graphics + group system diff --git a/aidl/memtrack/service/memtrack.xml b/aidl/memtrack/service/memtrack.xml new file mode 100644 index 00000000..3e3e0f6c --- /dev/null +++ b/aidl/memtrack/service/memtrack.xml @@ -0,0 +1,7 @@ + + + android.hardware.memtrack + IMemtrack/default + + +