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