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,unsigned int * val)33 static bool ReadUintFromFile(const std::string& path, unsigned int* 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
GetDmabufSysfsStats(DmabufSysfsStats * stats,const std::string & dmabuf_sysfs_stats_path)55 bool GetDmabufSysfsStats(DmabufSysfsStats* stats, const std::string& dmabuf_sysfs_stats_path) {
56 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(dmabuf_sysfs_stats_path.c_str()), closedir);
57
58 if (!dir) {
59 PLOG(ERROR) << "Unable to access: " << dmabuf_sysfs_stats_path;
60 return false;
61 }
62
63 // clear stats
64 *stats = {};
65
66 // Iterate over all the buffer directories to save exporter name, and size.
67 struct dirent* dent;
68 while ((dent = readdir(dir.get()))) {
69 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue;
70
71 std::string buf_entry_path = ::android::base::StringPrintf(
72 "%s/%s", dmabuf_sysfs_stats_path.c_str(), dent->d_name);
73
74 struct DmabufInfo info = {};
75
76 // Save inode number from dir name
77 if (!android::base::ParseUint(dent->d_name, &info.inode)) {
78 LOG(ERROR) << "Unable to parse value from " << dent->d_name;
79 return false;
80 }
81
82 // Read exporter name for the buffer
83 std::string exp_name_path = buf_entry_path + "/exporter_name";
84 std::string exporter_name;
85 if (!android::base::ReadFileToString(exp_name_path, &exporter_name)) {
86 PLOG(ERROR) << "Unable to access " << exp_name_path;
87 return false;
88 }
89
90 info.exp_name = android::base::Trim(exporter_name);
91
92 // Read size of the buffer
93 std::string size_path = buf_entry_path + "/size";
94 if (!ReadUintFromFile(size_path, &info.size)) return false;
95
96 // Update totals
97 stats->total_.size += info.size;
98 stats->total_.buffer_count++;
99
100 stats->buffer_stats_.emplace_back(info);
101
102 // update exporter_info_ map.
103 auto exp_stats = stats->exporter_info_.find(info.exp_name);
104 if (exp_stats != stats->exporter_info_.end()) {
105 exp_stats->second.size += info.size;
106 exp_stats->second.buffer_count++;
107 } else {
108 struct DmabufTotal total = {.size = info.size, .buffer_count = 1};
109 stats->exporter_info_[info.exp_name] = total;
110 }
111 }
112
113 return true;
114 }
115
GetDmabufTotalExportedKb(uint64_t * total_exported,const std::string & dmabuf_sysfs_stats_path)116 bool GetDmabufTotalExportedKb(uint64_t* total_exported,
117 const std::string& dmabuf_sysfs_stats_path) {
118 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(dmabuf_sysfs_stats_path.c_str()), closedir);
119 if (!dir) {
120 PLOG(ERROR) << "Unable to access: " << dmabuf_sysfs_stats_path;
121 return false;
122 }
123
124 *total_exported = 0;
125 struct dirent* dent;
126 while ((dent = readdir(dir.get()))) {
127 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue;
128
129 std::string buf_entry_path = ::android::base::StringPrintf(
130 "%s/%s", dmabuf_sysfs_stats_path.c_str(), dent->d_name);
131
132 // Read size of the buffer
133 unsigned int buf_size = 0;
134 std::string size_path = buf_entry_path + "/size";
135 if (!ReadUintFromFile(size_path, &buf_size)) return false;
136 *total_exported += buf_size;
137 }
138
139 *total_exported = *total_exported / 1024;
140
141 return true;
142 }
143 } // namespace dmabufinfo
144 } // namespace android
145