1 /* 2 * Copyright (C) 2017 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 "src/tracing/ipc/posix_shared_memory.h" 18 19 #include <fcntl.h> 20 #include <stdint.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <sys/mman.h> 24 #include <sys/stat.h> 25 #include <unistd.h> 26 27 #include <memory> 28 #include <utility> 29 30 #include "perfetto/base/build_config.h" 31 #include "perfetto/base/logging.h" 32 #include "perfetto/base/temp_file.h" 33 34 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) 35 #include <linux/memfd.h> 36 #include <sys/syscall.h> 37 #endif 38 39 namespace perfetto { 40 41 // static 42 std::unique_ptr<PosixSharedMemory> PosixSharedMemory::Create(size_t size) { 43 base::ScopedFile fd; 44 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) 45 bool is_memfd = false; 46 fd.reset(static_cast<int>(syscall(__NR_memfd_create, "perfetto_shmem", 47 MFD_CLOEXEC | MFD_ALLOW_SEALING))); 48 is_memfd = !!fd; 49 50 if (!fd) { 51 // TODO: if this fails on Android we should fall back on ashmem. 52 PERFETTO_DPLOG("memfd_create() failed"); 53 } 54 #endif 55 56 if (!fd) 57 fd = base::TempFile::CreateUnlinked().ReleaseFD(); 58 59 PERFETTO_CHECK(fd); 60 int res = ftruncate(fd.get(), static_cast<off_t>(size)); 61 PERFETTO_CHECK(res == 0); 62 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) 63 if (is_memfd) { 64 res = fcntl(*fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL); 65 PERFETTO_DCHECK(res == 0); 66 } 67 #endif 68 return MapFD(std::move(fd), size); 69 } 70 71 // static 72 std::unique_ptr<PosixSharedMemory> PosixSharedMemory::AttachToFd( 73 base::ScopedFile fd) { 74 struct stat stat_buf = {}; 75 int res = fstat(fd.get(), &stat_buf); 76 PERFETTO_CHECK(res == 0 && stat_buf.st_size > 0); 77 return MapFD(std::move(fd), static_cast<size_t>(stat_buf.st_size)); 78 } 79 80 // static 81 std::unique_ptr<PosixSharedMemory> PosixSharedMemory::MapFD(base::ScopedFile fd, 82 size_t size) { 83 PERFETTO_DCHECK(fd); 84 PERFETTO_DCHECK(size > 0); 85 void* start = 86 mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0); 87 PERFETTO_CHECK(start != MAP_FAILED); 88 return std::unique_ptr<PosixSharedMemory>( 89 new PosixSharedMemory(start, size, std::move(fd))); 90 } 91 92 PosixSharedMemory::PosixSharedMemory(void* start, 93 size_t size, 94 base::ScopedFile fd) 95 : start_(start), size_(size), fd_(std::move(fd)) {} 96 97 PosixSharedMemory::~PosixSharedMemory() { 98 munmap(start(), size()); 99 } 100 101 PosixSharedMemory::Factory::~Factory() {} 102 103 std::unique_ptr<SharedMemory> PosixSharedMemory::Factory::CreateSharedMemory( 104 size_t size) { 105 return PosixSharedMemory::Create(size); 106 } 107 108 } // namespace perfetto 109