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