1 /*
2 * Copyright 2016 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 #define LOG_TAG "SharedMemoryParcelable"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <inttypes.h>
22 #include <stdint.h>
23 #include <stdio.h>
24
25 #include <sys/mman.h>
26 #include <aaudio/AAudio.h>
27
28 #include <android-base/unique_fd.h>
29 #include <binder/Parcelable.h>
30 #include <utility/AAudioUtilities.h>
31
32 #include "binding/SharedMemoryParcelable.h"
33
34 using android::base::unique_fd;
35 using android::NO_ERROR;
36 using android::status_t;
37 using android::media::SharedFileRegion;
38
39 using namespace aaudio;
40
SharedMemoryParcelable(SharedFileRegion && parcelable)41 SharedMemoryParcelable::SharedMemoryParcelable(SharedFileRegion&& parcelable) {
42 mFd = parcelable.fd.release();
43 mSizeInBytes = parcelable.size;
44 mOffsetInBytes = parcelable.offset;
45 }
46
parcelable()47 SharedFileRegion SharedMemoryParcelable::parcelable() && {
48 SharedFileRegion result;
49 result.fd.reset(std::move(mFd));
50 result.size = mSizeInBytes;
51 result.offset = mOffsetInBytes;
52 return result;
53 }
54
dup() const55 SharedMemoryParcelable SharedMemoryParcelable::dup() const {
56 SharedMemoryParcelable result;
57 result.setup(mFd, static_cast<int32_t>(mSizeInBytes));
58 return result;
59 }
60
setup(const unique_fd & fd,int32_t sizeInBytes)61 void SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
62 constexpr int minFd = 3; // skip over stdout, stdin and stderr
63 mFd.reset(fcntl(fd.get(), F_DUPFD_CLOEXEC, minFd)); // store a duplicate FD
64 ALOGV("setup(fd = %d -> %d, size = %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
65 mSizeInBytes = sizeInBytes;
66 }
67
close()68 aaudio_result_t SharedMemoryParcelable::close() {
69 if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
70 int err = munmap(mResolvedAddress, mSizeInBytes);
71 if (err < 0) {
72 ALOGE("close() munmap() failed %d", err);
73 return AAudioConvert_androidToAAudioResult(err);
74 }
75 mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
76 }
77 return AAUDIO_OK;
78 }
79
resolveSharedMemory(const unique_fd & fd)80 aaudio_result_t SharedMemoryParcelable::resolveSharedMemory(const unique_fd& fd) {
81 mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
82 MAP_SHARED, fd.get(), 0);
83 if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
84 ALOGE("mmap() failed for fd = %d, nBytes = %" PRId64 ", errno = %s",
85 fd.get(), mSizeInBytes, strerror(errno));
86 return AAUDIO_ERROR_INTERNAL;
87 }
88 return AAUDIO_OK;
89 }
90
resolve(int32_t offsetInBytes,int32_t sizeInBytes,void ** regionAddressPtr)91 aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
92 void **regionAddressPtr) {
93 if (offsetInBytes < 0) {
94 ALOGE("illegal offsetInBytes = %d", offsetInBytes);
95 return AAUDIO_ERROR_OUT_OF_RANGE;
96 } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
97 ALOGE("out of range, offsetInBytes = %d, "
98 "sizeInBytes = %d, mSizeInBytes = %" PRId64,
99 offsetInBytes, sizeInBytes, mSizeInBytes);
100 return AAUDIO_ERROR_OUT_OF_RANGE;
101 }
102
103 aaudio_result_t result = AAUDIO_OK;
104
105 if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
106 if (mFd.get() != -1) {
107 result = resolveSharedMemory(mFd);
108 } else {
109 ALOGE("has no file descriptor for shared memory.");
110 result = AAUDIO_ERROR_INTERNAL;
111 }
112 }
113
114 if (result == AAUDIO_OK && mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
115 *regionAddressPtr = mResolvedAddress + offsetInBytes;
116 ALOGV("mResolvedAddress = %p", mResolvedAddress);
117 ALOGV("offset by %d, *regionAddressPtr = %p", offsetInBytes, *regionAddressPtr);
118 }
119 return result;
120 }
121
getSizeInBytes()122 int32_t SharedMemoryParcelable::getSizeInBytes() {
123 return mSizeInBytes;
124 }
125
validate() const126 aaudio_result_t SharedMemoryParcelable::validate() const {
127 if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
128 ALOGE("invalid mSizeInBytes = %" PRId64, mSizeInBytes);
129 return AAUDIO_ERROR_OUT_OF_RANGE;
130 }
131 if (mOffsetInBytes != 0) {
132 ALOGE("invalid mOffsetInBytes = %" PRId64, mOffsetInBytes);
133 return AAUDIO_ERROR_OUT_OF_RANGE;
134 }
135 return AAUDIO_OK;
136 }
137
dump()138 void SharedMemoryParcelable::dump() {
139 ALOGD("mFd = %d", mFd.get());
140 ALOGD("mSizeInBytes = %" PRId64, mSizeInBytes);
141 }
142