• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/parseint.h>
20 #include <android-base/stringprintf.h>
21 #include <android-base/strings.h>
22 #include <inttypes.h>
23 
24 #include <dmabufinfo/dmabuf_sysfs_stats.h>
25 
26 #include <filesystem>
27 #include <string>
28 #include <unordered_map>
29 
30 namespace android {
31 namespace dmabufinfo {
32 
ReadUintFromFile(const std::string & path,uint64_t * val)33 static bool ReadUintFromFile(const std::string& path, uint64_t* val) {
34     std::string temp;
35 
36     if (!android::base::ReadFileToString(path, &temp)) {
37         PLOG(ERROR) << "Unable to access " << path;
38         return false;
39     }
40 
41     if (!android::base::ParseUint(android::base::Trim(temp), val)) {
42         LOG(ERROR) << "Unable to parse value from " << path;
43         return false;
44     }
45     return true;
46 }
47 
ReadBufferExporter(unsigned int inode,std::string * exporter,const std::string & dmabuf_sysfs_path)48 bool ReadBufferExporter(unsigned int inode, std::string* exporter,
49                         const std::string& dmabuf_sysfs_path) {
50     std::string exporter_path =
51             ::android::base::StringPrintf("%s/%u/exporter_name", dmabuf_sysfs_path.c_str(), inode);
52     return android::base::ReadFileToString(exporter_path, exporter);
53 }
54 
ReadBufferSize(unsigned int inode,uint64_t * size,const std::string & dmabuf_sysfs_path)55 bool ReadBufferSize(unsigned int inode, uint64_t* size, const std::string& dmabuf_sysfs_path) {
56     std::string size_path =
57             ::android::base::StringPrintf("%s/%u/size", dmabuf_sysfs_path.c_str(), inode);
58     return ReadUintFromFile(size_path, size);
59 }
60 
GetDmabufSysfsStats(DmabufSysfsStats * stats,const std::string & dmabuf_sysfs_stats_path)61 bool GetDmabufSysfsStats(DmabufSysfsStats* stats, const std::string& dmabuf_sysfs_stats_path) {
62     std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(dmabuf_sysfs_stats_path.c_str()), closedir);
63 
64     if (!dir) {
65         PLOG(ERROR) << "Unable to access: " << dmabuf_sysfs_stats_path;
66         return false;
67     }
68 
69     // clear stats
70     *stats = {};
71 
72     // Iterate over all the buffer directories to save exporter name, and size.
73     struct dirent* dent;
74     while ((dent = readdir(dir.get()))) {
75         if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue;
76 
77         std::string buf_entry_path = ::android::base::StringPrintf(
78                 "%s/%s", dmabuf_sysfs_stats_path.c_str(), dent->d_name);
79 
80         struct DmabufInfo info = {};
81 
82         // Save inode number from dir name
83         if (!android::base::ParseUint(dent->d_name, &info.inode)) {
84             LOG(ERROR) << "Unable to parse value from " << dent->d_name;
85             return false;
86         }
87 
88         // Read exporter name for the buffer
89         std::string exp_name_path = buf_entry_path + "/exporter_name";
90         std::string exporter_name;
91         if (!android::base::ReadFileToString(exp_name_path, &exporter_name)) {
92             PLOG(ERROR) << "Unable to access " << exp_name_path;
93             return false;
94         }
95 
96         info.exp_name = android::base::Trim(exporter_name);
97 
98         // Read size of the buffer
99         std::string size_path = buf_entry_path + "/size";
100         if (!ReadUintFromFile(size_path, &info.size)) return false;
101 
102         // Update totals
103         stats->total_.size += info.size;
104         stats->total_.buffer_count++;
105 
106         stats->buffer_stats_.emplace_back(info);
107 
108         // update exporter_info_ map.
109         auto exp_stats = stats->exporter_info_.find(info.exp_name);
110         if (exp_stats != stats->exporter_info_.end()) {
111             exp_stats->second.size += info.size;
112             exp_stats->second.buffer_count++;
113         } else {
114             struct DmabufTotal total = {.size = info.size, .buffer_count = 1};
115             stats->exporter_info_[info.exp_name] = total;
116         }
117     }
118 
119     return true;
120 }
121 
GetDmabufTotalExportedKb(uint64_t * total_exported,const std::string & dmabuf_sysfs_stats_path)122 bool GetDmabufTotalExportedKb(uint64_t* total_exported,
123                               const std::string& dmabuf_sysfs_stats_path) {
124     std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(dmabuf_sysfs_stats_path.c_str()), closedir);
125     if (!dir) {
126         PLOG(ERROR) << "Unable to access: " << dmabuf_sysfs_stats_path;
127         return false;
128     }
129 
130     *total_exported = 0;
131     struct dirent* dent;
132     while ((dent = readdir(dir.get()))) {
133         if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue;
134 
135         std::string buf_entry_path = ::android::base::StringPrintf(
136                 "%s/%s", dmabuf_sysfs_stats_path.c_str(), dent->d_name);
137 
138         // Read size of the buffer
139         uint64_t buf_size = 0;
140         std::string size_path = buf_entry_path + "/size";
141         if (!ReadUintFromFile(size_path, &buf_size)) return false;
142         *total_exported += buf_size;
143     }
144 
145     *total_exported = *total_exported / 1024;
146 
147     return true;
148 }
149 }  // namespace dmabufinfo
150 }  // namespace android
151