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 "AAudio"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <stdint.h>
22 #include <stdio.h>
23
24 #include <sys/mman.h>
25 #include <aaudio/AAudio.h>
26
27 #include <binder/Parcelable.h>
28 #include <utility/AAudioUtilities.h>
29
30 #include "binding/SharedMemoryParcelable.h"
31
32 using android::NO_ERROR;
33 using android::status_t;
34 using android::Parcel;
35 using android::Parcelable;
36
37 using namespace aaudio;
38
SharedMemoryParcelable()39 SharedMemoryParcelable::SharedMemoryParcelable() {}
~SharedMemoryParcelable()40 SharedMemoryParcelable::~SharedMemoryParcelable() {};
41
setup(int fd,int32_t sizeInBytes)42 void SharedMemoryParcelable::setup(int fd, int32_t sizeInBytes) {
43 mFd = fd;
44 mSizeInBytes = sizeInBytes;
45
46 }
47
writeToParcel(Parcel * parcel) const48 status_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
49 status_t status = parcel->writeInt32(mSizeInBytes);
50 if (status != NO_ERROR) return status;
51 if (mSizeInBytes > 0) {
52 status = parcel->writeDupFileDescriptor(mFd);
53 ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d",
54 status);
55 }
56 return status;
57 }
58
readFromParcel(const Parcel * parcel)59 status_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) {
60 status_t status = parcel->readInt32(&mSizeInBytes);
61 if (status != NO_ERROR) {
62 return status;
63 }
64 if (mSizeInBytes > 0) {
65 // Keep the original FD until you are done with the mFd.
66 // If you close it in here then it will prevent mFd from working.
67 mOriginalFd = parcel->readFileDescriptor();
68 ALOGV("SharedMemoryParcelable::readFromParcel() LEAK? mOriginalFd = %d\n", mOriginalFd);
69 mFd = fcntl(mOriginalFd, F_DUPFD_CLOEXEC, 0);
70 ALOGV("SharedMemoryParcelable::readFromParcel() LEAK? mFd = %d\n", mFd);
71 if (mFd == -1) {
72 status = -errno;
73 ALOGE("SharedMemoryParcelable readFromParcel fcntl() failed : %d", status);
74 }
75 }
76 return status;
77 }
78
close()79 aaudio_result_t SharedMemoryParcelable::close() {
80 if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
81 int err = munmap(mResolvedAddress, mSizeInBytes);
82 if (err < 0) {
83 ALOGE("SharedMemoryParcelable::close() munmap() failed %d", err);
84 return AAudioConvert_androidToAAudioResult(err);
85 }
86 mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
87 }
88 if (mFd != -1) {
89 ALOGV("SharedMemoryParcelable::close() LEAK? mFd = %d\n", mFd);
90 ::close(mFd);
91 mFd = -1;
92 }
93 if (mOriginalFd != -1) {
94 ALOGV("SharedMemoryParcelable::close() LEAK? mOriginalFd = %d\n", mOriginalFd);
95 ::close(mOriginalFd);
96 mOriginalFd = -1;
97 }
98 return AAUDIO_OK;
99 }
100
resolve(int32_t offsetInBytes,int32_t sizeInBytes,void ** regionAddressPtr)101 aaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
102 void **regionAddressPtr) {
103
104 if (offsetInBytes < 0) {
105 ALOGE("SharedMemoryParcelable illegal offsetInBytes = %d", offsetInBytes);
106 return AAUDIO_ERROR_OUT_OF_RANGE;
107 } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
108 ALOGE("SharedMemoryParcelable out of range, offsetInBytes = %d, "
109 "sizeInBytes = %d, mSizeInBytes = %d",
110 offsetInBytes, sizeInBytes, mSizeInBytes);
111 return AAUDIO_ERROR_OUT_OF_RANGE;
112 }
113 if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
114 mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ|PROT_WRITE,
115 MAP_SHARED, mFd, 0);
116 if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
117 ALOGE("SharedMemoryParcelable mmap failed for fd = %d, errno = %s",
118 mFd, strerror(errno));
119 return AAUDIO_ERROR_INTERNAL;
120 }
121 }
122 *regionAddressPtr = mResolvedAddress + offsetInBytes;
123 ALOGV("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
124 ALOGV("SharedMemoryParcelable offset by %d, *regionAddressPtr = %p",
125 offsetInBytes, *regionAddressPtr);
126 return AAUDIO_OK;
127 }
128
getSizeInBytes()129 int32_t SharedMemoryParcelable::getSizeInBytes() {
130 return mSizeInBytes;
131 }
132
validate()133 aaudio_result_t SharedMemoryParcelable::validate() {
134 if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
135 ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes);
136 return AAUDIO_ERROR_OUT_OF_RANGE;
137 }
138 if (mSizeInBytes > 0) {
139 if (mFd == -1) {
140 ALOGE("SharedMemoryParcelable uninitialized mFd = %d", mFd);
141 return AAUDIO_ERROR_INTERNAL;
142 }
143 }
144 return AAUDIO_OK;
145 }
146
dump()147 void SharedMemoryParcelable::dump() {
148 ALOGD("SharedMemoryParcelable mFd = %d", mFd);
149 ALOGD("SharedMemoryParcelable mSizeInBytes = %d", mSizeInBytes);
150 ALOGD("SharedMemoryParcelable mResolvedAddress = %p", mResolvedAddress);
151 }
152