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