1 /* Copyright (C) 2019 The Android Open Source Project
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <gtest/gtest.h>
17 #include <inttypes.h>
18 #include <linux/dma-buf.h>
19 #include <poll.h>
20 #include <string.h>
21 #include <sys/mman.h>
22 #include <sys/types.h>
23 
24 #include <fstream>
25 #include <string>
26 #include <unordered_map>
27 #include <vector>
28 
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/stringprintf.h>
32 #include <android-base/strings.h>
33 #include <android-base/unique_fd.h>
34 #include <ion/ion.h>
35 #include <unistd.h>
36 
37 #include <dmabufinfo/dmabuf_sysfs_stats.h>
38 #include <dmabufinfo/dmabufinfo.h>
39 
40 using namespace ::android::dmabufinfo;
41 using namespace ::android::base;
42 
43 namespace fs = std::filesystem;
44 
45 #define MAX_HEAP_NAME 32
46 #define ION_HEAP_ANY_MASK (0x7fffffff)
47 
48 struct ion_heap_data {
49     char name[MAX_HEAP_NAME];
50     __u32 type;
51     __u32 heap_id;
52     __u32 reserved0;
53     __u32 reserved1;
54     __u32 reserved2;
55 };
56 
57 #ifndef DMA_BUF_SET_NAME
58 #define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 5, const char*)
59 #endif
60 
61 class fd_sharer {
62   public:
63     fd_sharer();
~fd_sharer()64     ~fd_sharer() { kill(); }
65 
ok() const66     bool ok() const { return child_pid > 0; }
67     bool sendfd(int fd);
68     bool kill();
pid() const69     pid_t pid() const { return child_pid; }
70 
71   private:
72     unique_fd parent_fd, child_fd;
73     pid_t child_pid;
74 
75     void run();
76 };
77 
fd_sharer()78 fd_sharer::fd_sharer() : parent_fd{}, child_fd{}, child_pid{-1} {
79     bool sp_ok = android::base::Socketpair(SOCK_STREAM, &parent_fd, &child_fd);
80     if (!sp_ok) return;
81 
82     child_pid = fork();
83     if (child_pid < 0) return;
84 
85     if (child_pid == 0) run();
86 }
87 
kill()88 bool fd_sharer::kill() {
89     int err = ::kill(child_pid, SIGKILL);
90     if (err < 0) return false;
91 
92     return ::waitpid(child_pid, nullptr, 0) == child_pid;
93 }
94 
run()95 void fd_sharer::run() {
96     while (true) {
97         int fd;
98         char unused = 0;
99 
100         iovec iov{};
101         iov.iov_base = &unused;
102         iov.iov_len = sizeof(unused);
103 
104         msghdr msg{};
105         msg.msg_iov = &iov;
106         msg.msg_iovlen = 1;
107 
108         char cmsg_buf[CMSG_SPACE(sizeof(fd))];
109         msg.msg_control = cmsg_buf;
110         msg.msg_controllen = sizeof(cmsg_buf);
111 
112         cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
113         cmsg->cmsg_level = SOL_SOCKET;
114         cmsg->cmsg_type = SCM_RIGHTS;
115         cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
116 
117         ssize_t s = TEMP_FAILURE_RETRY(recvmsg(child_fd, &msg, 0));
118         if (s == -1) break;
119 
120         s = TEMP_FAILURE_RETRY(write(child_fd, &unused, sizeof(unused)));
121         if (s == -1) break;
122     }
123 }
124 
sendfd(int fd)125 bool fd_sharer::sendfd(int fd) {
126     char unused = 0;
127 
128     iovec iov{};
129     iov.iov_base = &unused;
130     iov.iov_len = sizeof(unused);
131 
132     msghdr msg{};
133     msg.msg_iov = &iov;
134     msg.msg_iovlen = 1;
135 
136     char cmsg_buf[CMSG_SPACE(sizeof(fd))];
137     msg.msg_control = cmsg_buf;
138     msg.msg_controllen = sizeof(cmsg_buf);
139 
140     cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
141     cmsg->cmsg_level = SOL_SOCKET;
142     cmsg->cmsg_type = SCM_RIGHTS;
143     cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
144 
145     int* fd_buf = reinterpret_cast<int*>(CMSG_DATA(cmsg));
146     *fd_buf = fd;
147 
148     ssize_t s = TEMP_FAILURE_RETRY(sendmsg(parent_fd, &msg, 0));
149     if (s == -1) return false;
150 
151     // The target process installs the fd into its fd table during recvmsg().
152     // So if we return now, there's a brief window between sendfd() finishing
153     // and libmemoryinfo actually seeing that the buffer has been shared.  This
154     // window is just large enough to break tests.
155     //
156     // To work around this, wait for the target process to respond with a dummy
157     // byte, with a timeout of 1 s.
158     pollfd p{};
159     p.fd = parent_fd;
160     p.events = POLL_IN;
161     int ready = poll(&p, 1, 1000);
162     if (ready != 1) return false;
163 
164     s = TEMP_FAILURE_RETRY(read(parent_fd, &unused, sizeof(unused)));
165     if (s == -1) return false;
166 
167     return true;
168 }
169 
170 #define EXPECT_ONE_BUF_EQ(_bufptr, _name, _fdrefs, _maprefs, _expname, _count, _size) \
171     do {                                                                              \
172         EXPECT_EQ(_bufptr->name(), _name);                                            \
173         EXPECT_EQ(_bufptr->fdrefs().size(), _fdrefs);                                 \
174         EXPECT_EQ(_bufptr->maprefs().size(), _maprefs);                               \
175         EXPECT_EQ(_bufptr->exporter(), _expname);                                     \
176         EXPECT_EQ(_bufptr->count(), _count);                                          \
177         EXPECT_EQ(_bufptr->size(), _size);                                            \
178     } while (0)
179 
180 #define EXPECT_PID_IN_FDREFS(_bufptr, _pid, _expect)                         \
181     do {                                                                     \
182         const std::unordered_map<pid_t, int>& _fdrefs = _bufptr->fdrefs();   \
183         auto _ref = _fdrefs.find(_pid);                                      \
184         EXPECT_EQ((_ref != _fdrefs.end()), _expect);                         \
185     } while (0)
186 
187 #define EXPECT_PID_IN_MAPREFS(_bufptr, _pid, _expect)                        \
188     do {                                                                     \
189         const std::unordered_map<pid_t, int>& _maprefs = _bufptr->maprefs(); \
190         auto _ref = _maprefs.find(_pid);                                     \
191         EXPECT_EQ((_ref != _maprefs.end()), _expect);                        \
192     } while (0)
193 
TEST(DmaBufInfoParser,TestReadDmaBufInfo)194 TEST(DmaBufInfoParser, TestReadDmaBufInfo) {
195     std::string bufinfo = R"bufinfo(00045056    00000002    00000007    00000002    ion 00022069
196 	Attached Devices:
197 Total 0 devices attached
198 01048576    00000002    00000007    00000001    ion 00019834    CAMERA
199 	Attached Devices:
200 	soc:qcom,cam_smmu:msm_cam_smmu_icp
201 Total 1 devices attached)bufinfo";
202 
203     TemporaryFile tf;
204     ASSERT_TRUE(tf.fd != -1);
205     ASSERT_TRUE(::android::base::WriteStringToFd(bufinfo, tf.fd));
206     std::string path = std::string(tf.path);
207 
208     std::vector<DmaBuffer> dmabufs;
209     EXPECT_TRUE(ReadDmaBufInfo(&dmabufs, path));
210 
211     EXPECT_EQ(dmabufs.size(), 2UL);
212 
213     EXPECT_EQ(dmabufs[0].size(), 45056UL);
214     EXPECT_EQ(dmabufs[0].inode(), 22069UL);
215     EXPECT_EQ(dmabufs[0].count(), 2UL);
216     EXPECT_EQ(dmabufs[0].exporter(), "ion");
217     EXPECT_TRUE(dmabufs[0].name().empty());
218     EXPECT_EQ(dmabufs[0].total_refs(), 0ULL);
219     EXPECT_TRUE(dmabufs[0].fdrefs().empty());
220     EXPECT_TRUE(dmabufs[0].maprefs().empty());
221 
222     EXPECT_EQ(dmabufs[1].size(), 1048576UL);
223     EXPECT_EQ(dmabufs[1].inode(), 19834UL);
224     EXPECT_EQ(dmabufs[1].count(), 1UL);
225     EXPECT_EQ(dmabufs[1].exporter(), "ion");
226     EXPECT_FALSE(dmabufs[1].name().empty());
227     EXPECT_EQ(dmabufs[1].name(), "CAMERA");
228     EXPECT_EQ(dmabufs[1].total_refs(), 0ULL);
229     EXPECT_TRUE(dmabufs[1].fdrefs().empty());
230     EXPECT_TRUE(dmabufs[1].maprefs().empty());
231 }
232 
233 class DmaBufSysfsStatsParser : public ::testing::Test {
234   public:
SetUp()235     virtual void SetUp() {
236         fs::current_path(fs::temp_directory_path());
237         buffer_stats_path = fs::current_path() / "buffers";
238         ASSERT_TRUE(fs::create_directory(buffer_stats_path));
239     }
TearDown()240     virtual void TearDown() { fs::remove_all(buffer_stats_path); }
241 
242     std::filesystem::path buffer_stats_path;
243 };
244 
TEST_F(DmaBufSysfsStatsParser,TestReadDmaBufSysfsStats)245 TEST_F(DmaBufSysfsStatsParser, TestReadDmaBufSysfsStats) {
246     using android::base::StringPrintf;
247 
248     for (unsigned int inode_number = 74831; inode_number < 74841; inode_number++) {
249         auto buffer_path = buffer_stats_path / StringPrintf("%u", inode_number);
250         ASSERT_TRUE(fs::create_directories(buffer_path));
251 
252         auto buffer_size_path = buffer_path / "size";
253         const std::string buffer_size = "4096";
254         ASSERT_TRUE(android::base::WriteStringToFile(buffer_size, buffer_size_path));
255 
256         auto exp_name_path = buffer_path / "exporter_name";
257         const std::string exp_name = "system";
258         ASSERT_TRUE(android::base::WriteStringToFile(exp_name, exp_name_path));
259     }
260 
261     DmabufSysfsStats stats;
262     ASSERT_TRUE(GetDmabufSysfsStats(&stats, buffer_stats_path.c_str()));
263 
264     auto buffer_stats = stats.buffer_stats();
265     ASSERT_EQ(buffer_stats.size(), 10UL);
266 
267     auto buf_info = buffer_stats[0];
268     EXPECT_EQ(buf_info.inode, 74831UL);
269     EXPECT_EQ(buf_info.exp_name, "system");
270     EXPECT_EQ(buf_info.size, 4096UL);
271 
272     auto exporter_stats = stats.exporter_info();
273     ASSERT_EQ(exporter_stats.size(), 1UL);
274     auto exp_info = exporter_stats.find("system");
275     ASSERT_TRUE(exp_info != exporter_stats.end());
276     EXPECT_EQ(exp_info->second.size, 40960UL);
277     EXPECT_EQ(exp_info->second.buffer_count, 10UL);
278 
279     auto total_size = stats.total_size();
280     EXPECT_EQ(total_size, 40960UL);
281 
282     auto total_count = stats.total_count();
283     EXPECT_EQ(total_count, 10UL);
284 
285     uint64_t total_exported;
286     EXPECT_TRUE(GetDmabufTotalExportedKb(&total_exported, buffer_stats_path.c_str()));
287     EXPECT_EQ(total_exported, 40UL);
288 }
289 
290 class DmaBufProcessStatsTest : public ::testing::Test {
291   public:
SetUp()292     virtual void SetUp() {
293         fs::current_path(fs::temp_directory_path());
294         dmabuf_sysfs_path = fs::current_path() / "buffers";
295         procfs_path = fs::current_path() / "proc";
296         ASSERT_TRUE(fs::create_directory(dmabuf_sysfs_path));
297         ASSERT_TRUE(fs::create_directory(procfs_path));
298         pid_path = procfs_path / android::base::StringPrintf("%d", pid);
299         ASSERT_TRUE(fs::create_directories(pid_path));
300         pid_fdinfo_path = pid_path / "fdinfo";
301         ASSERT_TRUE(fs::create_directories(pid_fdinfo_path));
302     }
TearDown()303     virtual void TearDown() {
304         fs::remove_all(dmabuf_sysfs_path);
305         fs::remove_all(procfs_path);
306     }
307 
AddFdInfo(unsigned int inode,unsigned int size,bool is_dmabuf)308     void AddFdInfo(unsigned int inode, unsigned int size, bool is_dmabuf) {
309         std::string dmabuf_fdinfo = android::base::StringPrintf(
310                 "size:\t%u\ncount:\t1\nexp_name:\t%s\n", size, exporter.c_str());
311         std::string fdinfo =
312                 android::base::StringPrintf("pos:\t21\nflags:\t0032\nmnt_id:\t02\nino:\t%u\n%s",
313                                             inode, (is_dmabuf) ? dmabuf_fdinfo.c_str() : "");
314 
315         auto fdinfo_file_path = pid_fdinfo_path / android::base::StringPrintf("%d", fd++);
316         ASSERT_TRUE(android::base::WriteStringToFile(fdinfo, fdinfo_file_path));
317     }
318 
AddSysfsDmaBufStats(unsigned int inode,unsigned int size,unsigned int mmap_count)319     void AddSysfsDmaBufStats(unsigned int inode, unsigned int size, unsigned int mmap_count) {
320         auto buffer_path = dmabuf_sysfs_path / android::base::StringPrintf("%u", inode);
321         ASSERT_TRUE(fs::create_directory(buffer_path));
322 
323         auto size_path = buffer_path / "size";
324         ASSERT_TRUE(android::base::WriteStringToFile(android::base::StringPrintf("%u", size),
325                                                      size_path));
326 
327         auto mmap_count_path = buffer_path / "mmap_count";
328         ASSERT_TRUE(android::base::WriteStringToFile(
329                 android::base::StringPrintf("%u", mmap_count), mmap_count_path));
330 
331         auto exporter_path = buffer_path / "exporter_name";
332         ASSERT_TRUE(android::base::WriteStringToFile(exporter, exporter_path));
333     }
334 
CreateMapEntry(unsigned int inode,unsigned int size,bool is_dmabuf)335     std::string CreateMapEntry(unsigned int inode, unsigned int size, bool is_dmabuf) {
336         return android::base::StringPrintf("0000000000-%010x rw-s 00000000 00:08 %u %s", size,
337                                            inode, (is_dmabuf) ? "/dmabuf:" : "/not/dmabuf/");
338     }
339 
AddMapEntries(std::vector<std::string> entries)340     void AddMapEntries(std::vector<std::string> entries) {
341         std::string maps_content = android::base::Join(entries, '\n');
342 
343         auto maps_file_path = pid_path / "maps";
344         ASSERT_TRUE(android::base::WriteStringToFile(maps_content, maps_file_path));
345     }
346 
347     std::filesystem::path dmabuf_sysfs_path;
348     std::filesystem::path procfs_path;
349     std::filesystem::path pid_path;
350     std::filesystem::path pid_fdinfo_path;
351     std::string exporter = "system_heap";
352     int pid = 10;
353     int fd = 0;
354 };
355 
TEST_F(DmaBufProcessStatsTest,TestReadDmaBufInfo)356 TEST_F(DmaBufProcessStatsTest, TestReadDmaBufInfo) {
357     AddFdInfo(1, 1024, false);
358     AddFdInfo(2, 2048, true);  // Dmabuf 1
359 
360     std::vector<std::string> map_entries;
361     map_entries.emplace_back(CreateMapEntry(3, 1024, false));
362     map_entries.emplace_back(CreateMapEntry(4, 1024, true));  // Dmabuf 2
363     AddMapEntries(map_entries);
364 
365     AddSysfsDmaBufStats(2, 2048, 4);  // Dmabuf 1
366     AddSysfsDmaBufStats(4, 1024, 1);  // Dmabuf 2
367 
368     std::vector<DmaBuffer> dmabufs;
369     ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs, true, procfs_path, dmabuf_sysfs_path));
370 
371     ASSERT_EQ(dmabufs.size(), 2u);
372 
373     auto dmabuf1 = std::find_if(dmabufs.begin(), dmabufs.end(),
374                                 [](const DmaBuffer& dmabuf) { return dmabuf.inode() == 2; });
375     ASSERT_NE(dmabuf1, dmabufs.end());
376     ASSERT_EQ(dmabuf1->size(), 2048u);
377     ASSERT_EQ(dmabuf1->fdrefs().size(), 1u);
378     ASSERT_EQ(dmabuf1->maprefs().size(), 0u);
379     ASSERT_EQ(dmabuf1->total_refs(), 1u);
380     ASSERT_EQ(dmabuf1->exporter(), exporter);
381 
382     auto dmabuf2 = std::find_if(dmabufs.begin(), dmabufs.end(),
383                                 [](const DmaBuffer& dmabuf) { return dmabuf.inode() == 4; });
384     ASSERT_NE(dmabuf2, dmabufs.end());
385     ASSERT_EQ(dmabuf2->size(), 1024u);
386     ASSERT_EQ(dmabuf2->fdrefs().size(), 0u);
387     ASSERT_EQ(dmabuf2->maprefs().size(), 1u);
388     ASSERT_EQ(dmabuf2->total_refs(), 1u);
389     ASSERT_EQ(dmabuf2->exporter(), exporter);
390 }
391 
TEST_F(DmaBufProcessStatsTest,TestReadDmaBufFdRefs)392 TEST_F(DmaBufProcessStatsTest, TestReadDmaBufFdRefs) {
393     AddFdInfo(1, 1024, false);
394     AddFdInfo(2, 2048, true);  // Dmabuf 1
395     AddFdInfo(2, 2048, true);  // Dmabuf 1
396     AddFdInfo(3, 1024, true);  // Dmabuf 2
397 
398     std::vector<DmaBuffer> dmabufs;
399     ASSERT_TRUE(ReadDmaBufFdRefs(pid, &dmabufs, procfs_path));
400     ASSERT_EQ(dmabufs.size(), 2u);
401 
402     const auto& dmabuf1 = std::find_if(dmabufs.begin(), dmabufs.end(),
403                                        [](const DmaBuffer& dmabuf) { return dmabuf.inode() == 2; });
404 
405     ASSERT_EQ(dmabuf1->size(), 2048u);
406     ASSERT_EQ(dmabuf1->fdrefs().size(), 1u);  // Only one process has FDs to this buffer
407     ASSERT_EQ(dmabuf1->maprefs().size(), 0u);
408     ASSERT_EQ(dmabuf1->total_refs(), 2u);
409     ASSERT_EQ(dmabuf1->exporter(), exporter);
410 
411     // Verify process has 2 FDs to this buffer
412     ASSERT_NE(dmabuf1, dmabufs.end());
413     const auto& fdrefs1 = dmabuf1->fdrefs();
414     const auto& pid_fdrefs1 = fdrefs1.find(pid);
415     ASSERT_NE(pid_fdrefs1, fdrefs1.end());
416     ASSERT_EQ(pid_fdrefs1->second, 2);
417 
418     const auto& dmabuf2 = std::find_if(dmabufs.begin(), dmabufs.end(),
419                                        [](const DmaBuffer& dmabuf) { return dmabuf.inode() == 3; });
420     ASSERT_EQ(dmabuf2->size(), 1024u);
421     ASSERT_EQ(dmabuf2->fdrefs().size(), 1u);  // Only one process has FDs to this buffer
422     ASSERT_EQ(dmabuf2->maprefs().size(), 0u);
423     ASSERT_EQ(dmabuf2->total_refs(), 1u);
424     ASSERT_EQ(dmabuf2->exporter(), exporter);
425 
426     // Verify process only has 1 FD to this buffer
427     ASSERT_NE(dmabuf2, dmabufs.end());
428     const auto& fdrefs2 = dmabuf2->fdrefs();
429     const auto& pid_fdrefs2 = fdrefs2.find(pid);
430     ASSERT_NE(pid_fdrefs2, fdrefs2.end());
431     ASSERT_EQ(pid_fdrefs2->second, 1);
432 }
433 
TEST_F(DmaBufProcessStatsTest,TestReadDmaBufMapRefs)434 TEST_F(DmaBufProcessStatsTest, TestReadDmaBufMapRefs) {
435     std::vector<std::string> map_entries;
436     map_entries.emplace_back(CreateMapEntry(1, 1024, false));
437     map_entries.emplace_back(CreateMapEntry(2, 1024, true));  // Dmabuf 1
438     map_entries.emplace_back(CreateMapEntry(2, 1024, true));  // Dmabuf 1
439     map_entries.emplace_back(CreateMapEntry(3, 2048, true));  // Dmabuf 2
440     AddMapEntries(map_entries);
441 
442     AddSysfsDmaBufStats(2, 1024, 2);  // Dmabuf 1
443     AddSysfsDmaBufStats(3, 1024, 1);  // Dmabuf 2
444 
445     std::vector<DmaBuffer> dmabufs;
446     ASSERT_TRUE(ReadDmaBufMapRefs(pid, &dmabufs, procfs_path, dmabuf_sysfs_path));
447     ASSERT_EQ(dmabufs.size(), 2u);
448 
449     const auto& dmabuf1 = std::find_if(dmabufs.begin(), dmabufs.end(),
450                                        [](const DmaBuffer& dmabuf) { return dmabuf.inode() == 2; });
451 
452     ASSERT_EQ(dmabuf1->size(), 1024u);
453     ASSERT_EQ(dmabuf1->fdrefs().size(), 0u);
454     ASSERT_EQ(dmabuf1->maprefs().size(), 1u);  // Only one process mapped this buffer
455     ASSERT_EQ(dmabuf1->total_refs(), 2u);
456     ASSERT_EQ(dmabuf1->exporter(), exporter);
457 
458     // Verify process mapped this buffer twice
459     ASSERT_NE(dmabuf1, dmabufs.end());
460     const auto& maprefs1 = dmabuf1->maprefs();
461     const auto& pid_maprefs1 = maprefs1.find(pid);
462     ASSERT_NE(pid_maprefs1, maprefs1.end());
463     ASSERT_EQ(pid_maprefs1->second, 2);
464 
465     const auto& dmabuf2 = std::find_if(dmabufs.begin(), dmabufs.end(),
466                                        [](const DmaBuffer& dmabuf) { return dmabuf.inode() == 3; });
467     ASSERT_EQ(dmabuf2->size(), 2048u);
468     ASSERT_EQ(dmabuf2->fdrefs().size(), 0u);
469     ASSERT_EQ(dmabuf2->maprefs().size(), 1u);  // Only one process mapped this buffer
470     ASSERT_EQ(dmabuf2->total_refs(), 1u);
471     ASSERT_EQ(dmabuf2->exporter(), exporter);
472 
473     // Verify process mapped this buffer only once
474     ASSERT_NE(dmabuf2, dmabufs.end());
475     const auto& maprefs2 = dmabuf2->maprefs();
476     const auto& pid_maprefs2 = maprefs2.find(pid);
477     ASSERT_NE(pid_maprefs2, maprefs2.end());
478     ASSERT_EQ(pid_maprefs2->second, 1);
479 }
480 
481 class DmaBufTester : public ::testing::Test {
482   public:
DmaBufTester()483     DmaBufTester() : ion_fd(ion_open()), ion_heap_mask(get_ion_heap_mask()) {}
484 
~DmaBufTester()485     ~DmaBufTester() {
486         if (ion_fd >= 0) {
487             ion_close(ion_fd);
488         }
489     }
490 
is_valid()491     bool is_valid() { return (ion_fd >= 0 && ion_heap_mask > 0); }
492 
allocate(uint64_t size,const std::string & name)493     unique_fd allocate(uint64_t size, const std::string& name) {
494         int fd;
495         int err = ion_alloc_fd(ion_fd, size, 0, ion_heap_mask, 0, &fd);
496         if (err < 0) {
497             printf("Failed ion_alloc_fd, return value: %d\n", err);
498             return unique_fd{};
499         }
500 
501         if (!name.empty()) {
502             if (ioctl(fd, DMA_BUF_SET_NAME, name.c_str()) == -1) {
503                 printf("Failed ioctl(DMA_BUF_SET_NAME): %s\n", strerror(errno));
504                 close(fd);
505                 return unique_fd{};
506             }
507         }
508 
509         return unique_fd{fd};
510     }
511 
readAndCheckDmaBuffer(std::vector<DmaBuffer> * dmabufs,pid_t pid,const std::string name,size_t fdrefs_size,size_t maprefs_size,const std::string exporter,size_t refcount,uint64_t buf_size,bool expectFdrefs,bool expectMapRefs)512     void readAndCheckDmaBuffer(std::vector<DmaBuffer>* dmabufs, pid_t pid, const std::string name,
513                                size_t fdrefs_size, size_t maprefs_size, const std::string exporter,
514                                size_t refcount, uint64_t buf_size, bool expectFdrefs,
515                                bool expectMapRefs) {
516         EXPECT_TRUE(ReadDmaBufInfo(pid, dmabufs));
517         EXPECT_EQ(dmabufs->size(), 1UL);
518         EXPECT_ONE_BUF_EQ(dmabufs->begin(), name, fdrefs_size, maprefs_size, exporter, refcount,
519                           buf_size);
520         // Make sure the buffer has the right pid too.
521         EXPECT_PID_IN_FDREFS(dmabufs->begin(), pid, expectFdrefs);
522         EXPECT_PID_IN_MAPREFS(dmabufs->begin(), pid, expectMapRefs);
523     }
524 
checkPidRef(DmaBuffer & dmabuf,pid_t pid,int expectFdrefs)525     bool checkPidRef(DmaBuffer& dmabuf, pid_t pid, int expectFdrefs) {
526         int fdrefs = dmabuf.fdrefs().find(pid)->second;
527         return fdrefs == expectFdrefs;
528     }
529 
530   private:
get_ion_heap_mask()531     int get_ion_heap_mask() {
532         if (ion_fd < 0) {
533             return 0;
534         }
535 
536         if (ion_is_legacy(ion_fd)) {
537             // Since ION is still in staging, we've seen that the heap mask ids are also
538             // changed across kernels for some reason. So, here we basically ask for a buffer
539             // from _any_ heap.
540             return ION_HEAP_ANY_MASK;
541         }
542 
543         int cnt;
544         int err = ion_query_heap_cnt(ion_fd, &cnt);
545         if (err < 0) {
546             return err;
547         }
548 
549         std::vector<ion_heap_data> heaps;
550         heaps.resize(cnt);
551         err = ion_query_get_heaps(ion_fd, cnt, &heaps[0]);
552         if (err < 0) {
553             return err;
554         }
555 
556         unsigned int ret = 0;
557         for (auto& it : heaps) {
558             if (!strcmp(it.name, "ion_system_heap")) {
559                 ret |= (1 << it.heap_id);
560             }
561         }
562 
563         return ret;
564     }
565 
566     int ion_fd;
567     const int ion_heap_mask;
568 };
569 
TEST_F(DmaBufTester,TestFdRef)570 TEST_F(DmaBufTester, TestFdRef) {
571     // Test if a dma buffer is found while the corresponding file descriptor
572     // is open
573     ASSERT_TRUE(is_valid());
574     pid_t pid = getpid();
575     std::vector<DmaBuffer> dmabufs;
576     {
577         // Allocate one buffer and make sure the library can see it
578         unique_fd buf = allocate(4096, "dmabuftester-4k");
579         ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
580         ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
581 
582         EXPECT_EQ(dmabufs.size(), 1UL);
583         EXPECT_ONE_BUF_EQ(dmabufs.begin(), "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL);
584 
585         // Make sure the buffer has the right pid too.
586         EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, true);
587     }
588 
589     // Now make sure the buffer has disappeared
590     ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
591     EXPECT_TRUE(dmabufs.empty());
592 }
593 
TEST_F(DmaBufTester,TestMapRef)594 TEST_F(DmaBufTester, TestMapRef) {
595     // Test to make sure we can find a buffer if the fd is closed but the buffer
596     // is mapped
597     ASSERT_TRUE(is_valid());
598     pid_t pid = getpid();
599     std::vector<DmaBuffer> dmabufs;
600     {
601         // Allocate one buffer and make sure the library can see it
602         unique_fd buf = allocate(4096, "dmabuftester-4k");
603         ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
604         auto ptr = mmap(0, 4096, PROT_READ, MAP_SHARED, buf, 0);
605         ASSERT_NE(ptr, MAP_FAILED);
606         ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
607 
608         EXPECT_EQ(dmabufs.size(), 1UL);
609         EXPECT_ONE_BUF_EQ(dmabufs.begin(), "dmabuftester-4k", 1UL, 1UL, "ion", 2UL, 4096ULL);
610 
611         // Make sure the buffer has the right pid too.
612         EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, true);
613         EXPECT_PID_IN_MAPREFS(dmabufs.begin(), pid, true);
614 
615         // close the file descriptor and re-read the stats
616         buf.reset(-1);
617         ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
618 
619         EXPECT_EQ(dmabufs.size(), 1UL);
620         EXPECT_ONE_BUF_EQ(dmabufs.begin(), "<unknown>", 0UL, 1UL, "<unknown>", 0UL, 4096ULL);
621 
622         EXPECT_PID_IN_FDREFS(dmabufs.begin(), pid, false);
623         EXPECT_PID_IN_MAPREFS(dmabufs.begin(), pid, true);
624 
625         // unmap the bufer and lose all references
626         munmap(ptr, 4096);
627     }
628 
629     // Now make sure the buffer has disappeared
630     ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
631     EXPECT_TRUE(dmabufs.empty());
632 }
633 
TEST_F(DmaBufTester,TestSharedfd)634 TEST_F(DmaBufTester, TestSharedfd) {
635     // Each time a shared buffer is received over a socket, the remote process
636     // will take an extra reference on it.
637 
638     ASSERT_TRUE(is_valid());
639 
640     pid_t pid = getpid();
641     std::vector<DmaBuffer> dmabufs;
642     {
643         fd_sharer sharer{};
644         ASSERT_TRUE(sharer.ok());
645         // Allocate one buffer and make sure the library can see it
646         unique_fd buf = allocate(4096, "dmabuftester-4k");
647         ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
648         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
649                               false);
650 
651         ASSERT_TRUE(sharer.sendfd(buf));
652         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 2UL, 4096ULL, true,
653                               false);
654         EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 1));
655         readAndCheckDmaBuffer(&dmabufs, sharer.pid(), "dmabuftester-4k", 1UL, 0UL, "ion", 2UL,
656                               4096ULL, true, false);
657         EXPECT_TRUE(checkPidRef(dmabufs[0], sharer.pid(), 1));
658 
659         ASSERT_TRUE(sharer.sendfd(buf));
660         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 3UL, 4096ULL, true,
661                               false);
662         EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 1));
663         readAndCheckDmaBuffer(&dmabufs, sharer.pid(), "dmabuftester-4k", 1UL, 0UL, "ion", 3UL,
664                               4096ULL, true, false);
665         EXPECT_TRUE(checkPidRef(dmabufs[0], sharer.pid(), 2));
666 
667         ASSERT_TRUE(sharer.kill());
668         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
669                               false);
670     }
671 
672     // Now make sure the buffer has disappeared
673     ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
674     EXPECT_TRUE(dmabufs.empty());
675 }
676 
TEST_F(DmaBufTester,DupFdTest)677 TEST_F(DmaBufTester, DupFdTest) {
678     // dup()ing an fd will make this process take an extra reference on the
679     // shared buffer.
680 
681     ASSERT_TRUE(is_valid());
682 
683     pid_t pid = getpid();
684     std::vector<DmaBuffer> dmabufs;
685     {
686         // Allocate one buffer and make sure the library can see it
687         unique_fd buf = allocate(4096, "dmabuftester-4k");
688         ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
689         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
690                               false);
691 
692         unique_fd buf2{dup(buf)};
693         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 2UL, 4096ULL, true,
694                               false);
695         EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 2));
696 
697         close(buf2.release());
698         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
699                               false);
700         EXPECT_TRUE(checkPidRef(dmabufs[0], pid, 1));
701     }
702 
703     // Now make sure the buffer has disappeared
704     ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
705     EXPECT_TRUE(dmabufs.empty());
706 }
707 
TEST_F(DmaBufTester,ForkTest)708 TEST_F(DmaBufTester, ForkTest) {
709     // fork()ing a child will cause the child to automatically take a reference
710     // on any existing shared buffers.
711     ASSERT_TRUE(is_valid());
712 
713     pid_t pid = getpid();
714     std::vector<DmaBuffer> dmabufs;
715     {
716         // Allocate one buffer and make sure the library can see it
717         unique_fd buf = allocate(4096, "dmabuftester-4k");
718         ASSERT_GT(buf, 0) << "Allocated buffer is invalid";
719         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
720                               false);
721         fd_sharer sharer{};
722         ASSERT_TRUE(sharer.ok());
723         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 2UL, 4096ULL, true,
724                               false);
725         readAndCheckDmaBuffer(&dmabufs, sharer.pid(), "dmabuftester-4k", 1UL, 0UL, "ion", 2UL,
726                               4096ULL, true, false);
727         ASSERT_TRUE(sharer.kill());
728         readAndCheckDmaBuffer(&dmabufs, pid, "dmabuftester-4k", 1UL, 0UL, "ion", 1UL, 4096ULL, true,
729                               false);
730     }
731 
732     // Now make sure the buffer has disappeared
733     ASSERT_TRUE(ReadDmaBufInfo(pid, &dmabufs));
734     EXPECT_TRUE(dmabufs.empty());
735 }
736 
main(int argc,char ** argv)737 int main(int argc, char** argv) {
738     ::testing::InitGoogleTest(&argc, argv);
739     ::android::base::InitLogging(argv, android::base::StderrLogger);
740     return RUN_ALL_TESTS();
741 }
742