1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include <android/log.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <string.h>
11 #include <sys/ioctl.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 
17 #include "base/process_util.h"
18 
19 #include "SharedMemoryBasic.h"
20 
21 //
22 // Temporarily go directly to the kernel interface until we can
23 // interact better with libcutils.
24 //
25 #include <linux/ashmem.h>
26 
27 namespace mozilla {
28 namespace ipc {
29 
30 static void
LogError(const char * what)31 LogError(const char* what)
32 {
33   __android_log_print(ANDROID_LOG_ERROR, "Gecko",
34                       "%s: %s (%d)", what, strerror(errno), errno);
35 }
36 
SharedMemoryBasic()37 SharedMemoryBasic::SharedMemoryBasic()
38   : mShmFd(-1)
39   , mMemory(nullptr)
40 { }
41 
~SharedMemoryBasic()42 SharedMemoryBasic::~SharedMemoryBasic()
43 {
44   Unmap();
45   CloseHandle();
46 }
47 
48 bool
SetHandle(const Handle & aHandle)49 SharedMemoryBasic::SetHandle(const Handle& aHandle)
50 {
51   MOZ_ASSERT(-1 == mShmFd, "Already Create()d");
52   mShmFd = aHandle.fd;
53   return true;
54 }
55 
56 bool
Create(size_t aNbytes)57 SharedMemoryBasic::Create(size_t aNbytes)
58 {
59   MOZ_ASSERT(-1 == mShmFd, "Already Create()d");
60 
61   // Carve a new instance off of /dev/ashmem
62   int shmfd = open("/" ASHMEM_NAME_DEF, O_RDWR, 0600);
63   if (-1 == shmfd) {
64     LogError("ShmemAndroid::Create():open");
65     return false;
66   }
67 
68   if (ioctl(shmfd, ASHMEM_SET_SIZE, aNbytes)) {
69     LogError("ShmemAndroid::Unmap():ioctl(SET_SIZE)");
70     close(shmfd);
71     return false;
72   }
73 
74   mShmFd = shmfd;
75   Created(aNbytes);
76   return true;
77 }
78 
79 bool
Map(size_t nBytes)80 SharedMemoryBasic::Map(size_t nBytes)
81 {
82   MOZ_ASSERT(nullptr == mMemory, "Already Map()d");
83 
84   mMemory = mmap(nullptr, nBytes,
85                  PROT_READ | PROT_WRITE,
86                  MAP_SHARED,
87                  mShmFd,
88                  0);
89   if (MAP_FAILED == mMemory) {
90     LogError("ShmemAndroid::Map()");
91     mMemory = nullptr;
92     return false;
93   }
94 
95   Mapped(nBytes);
96   return true;
97 }
98 
99 bool
ShareToProcess(base::ProcessId,Handle * aNewHandle)100 SharedMemoryBasic::ShareToProcess(base::ProcessId/*unused*/,
101                                   Handle* aNewHandle)
102 {
103   MOZ_ASSERT(mShmFd >= 0, "Should have been Create()d by now");
104 
105   int shmfdDup = dup(mShmFd);
106   if (-1 == shmfdDup) {
107     LogError("ShmemAndroid::ShareToProcess()");
108     return false;
109   }
110 
111   aNewHandle->fd = shmfdDup;
112   aNewHandle->auto_close = true;
113   return true;
114 }
115 
116 void
Unmap()117 SharedMemoryBasic::Unmap()
118 {
119   if (!mMemory) {
120     return;
121   }
122 
123   if (munmap(mMemory, Size())) {
124     LogError("ShmemAndroid::Unmap()");
125   }
126   mMemory = nullptr;
127 }
128 
129 void
CloseHandle()130 SharedMemoryBasic::CloseHandle()
131 {
132   if (mShmFd != -1) {
133     close(mShmFd);
134     mShmFd = -1;
135   }
136 }
137 
138 } // namespace ipc
139 } // namespace mozilla
140