1204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk/*
2204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * Copyright 2016 The Android Open Source Project
3204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk *
4204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * Licensed under the Apache License, Version 2.0 (the "License");
5204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * you may not use this file except in compliance with the License.
6204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * You may obtain a copy of the License at
7204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk *
8204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk *      http://www.apache.org/licenses/LICENSE-2.0
9204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk *
10204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * Unless required by applicable law or agreed to in writing, software
11204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * distributed under the License is distributed on an "AS IS" BASIS,
12204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * See the License for the specific language governing permissions and
14204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * limitations under the License.
15204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk */
16204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
17fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk#define LOG_TAG "SharedMemoryParcelable"
18c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk//#define LOG_NDEBUG 0
19c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <utils/Log.h>
20c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk
21204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <stdint.h>
22c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <stdio.h>
23204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
24204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <sys/mman.h>
25a4eb0d86a29be2763be5fac51727858d5095794bPhil Burk#include <aaudio/AAudio.h>
26204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
27e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk#include <android-base/unique_fd.h>
28204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <binder/Parcelable.h>
29c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <utility/AAudioUtilities.h>
30204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
31204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include "binding/SharedMemoryParcelable.h"
32204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
33e72481c5c16d401c776e0ba49b84b80223769b91Phil Burkusing android::base::unique_fd;
34204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::NO_ERROR;
35204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::status_t;
36204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::Parcel;
37204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::Parcelable;
38204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
395ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkusing namespace aaudio;
40204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
41204a163c86f357a878873fe7d4c4164f3d55c9b6Phil BurkSharedMemoryParcelable::SharedMemoryParcelable() {}
42204a163c86f357a878873fe7d4c4164f3d55c9b6Phil BurkSharedMemoryParcelable::~SharedMemoryParcelable() {};
43204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
44e72481c5c16d401c776e0ba49b84b80223769b91Phil Burkvoid SharedMemoryParcelable::setup(const unique_fd& fd, int32_t sizeInBytes) {
45e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    mFd.reset(dup(fd.get())); // store a duplicate fd
46fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk    ALOGV("setup(%d -> %d, %d) this = %p\n", fd.get(), mFd.get(), sizeInBytes, this);
47204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    mSizeInBytes = sizeInBytes;
48204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk}
49204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
50204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkstatus_t SharedMemoryParcelable::writeToParcel(Parcel* parcel) const {
51a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk    status_t status = AAudioConvert_aaudioToAndroidStatus(validate());
52a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk    if (status != NO_ERROR) return status;
53a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk
54a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk    status = parcel->writeInt32(mSizeInBytes);
55c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    if (status != NO_ERROR) return status;
56204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    if (mSizeInBytes > 0) {
57fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk        ALOGV("writeToParcel() mFd = %d, this = %p\n", mFd.get(), this);
58e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        status = parcel->writeUniqueFileDescriptor(mFd);
59942bdc0aebc88dc8b12c0e7742ec0003bbb8b80fPhil Burk        ALOGE_IF(status != NO_ERROR, "SharedMemoryParcelable writeDupFileDescriptor failed : %d",
60942bdc0aebc88dc8b12c0e7742ec0003bbb8b80fPhil Burk                 status);
61204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    }
62c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return status;
63204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk}
64204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
65204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkstatus_t SharedMemoryParcelable::readFromParcel(const Parcel* parcel) {
66c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    status_t status = parcel->readInt32(&mSizeInBytes);
67a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk    if (status != NO_ERROR) goto error;
68a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk
69204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    if (mSizeInBytes > 0) {
70e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        // The Parcel owns the file descriptor and will close it later.
71e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        unique_fd mmapFd;
72e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        status = parcel->readUniqueFileDescriptor(&mmapFd);
73e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        if (status != NO_ERROR) {
74fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk            ALOGE("readFromParcel() readUniqueFileDescriptor() failed : %d", status);
75a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk            goto error;
76c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        }
77a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk
78a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk        // Resolve the memory now while we still have the FD from the Parcel.
79a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk        // Closing the FD will not affect the shared memory once mmap() has been called.
80a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk        aaudio_result_t result = resolveSharedMemory(mmapFd);
81a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk        status = AAudioConvert_aaudioToAndroidStatus(result);
82a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk        if (status != NO_ERROR) goto error;
83204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    }
84a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk
85a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk    return AAudioConvert_aaudioToAndroidStatus(validate());
86a5891f427bbd57914090f3260430b82f6879ec8dPhil Burk
87a5891f427bbd57914090f3260430b82f6879ec8dPhil Burkerror:
88c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return status;
89204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk}
90204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
91c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t SharedMemoryParcelable::close() {
92478d5df3a0e1693669f5809176d5c7f6e8c9aa88Phil Burk    if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
93c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        int err = munmap(mResolvedAddress, mSizeInBytes);
94c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        if (err < 0) {
95fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk            ALOGE("close() munmap() failed %d", err);
96c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk            return AAudioConvert_androidToAAudioResult(err);
97c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk        }
98478d5df3a0e1693669f5809176d5c7f6e8c9aa88Phil Burk        mResolvedAddress = MMAP_UNRESOLVED_ADDRESS;
99c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    }
100e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    return AAUDIO_OK;
101e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk}
102e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk
103e72481c5c16d401c776e0ba49b84b80223769b91Phil Burkaaudio_result_t SharedMemoryParcelable::resolveSharedMemory(const unique_fd& fd) {
104e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    mResolvedAddress = (uint8_t *) mmap(0, mSizeInBytes, PROT_READ | PROT_WRITE,
105e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk                                        MAP_SHARED, fd.get(), 0);
106e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
107fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk        ALOGE("mmap() failed for fd = %d, errno = %s", fd.get(), strerror(errno));
108e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        return AAUDIO_ERROR_INTERNAL;
109c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    }
110c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk    return AAUDIO_OK;
111c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk}
112204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
1135ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t SharedMemoryParcelable::resolve(int32_t offsetInBytes, int32_t sizeInBytes,
114204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk                                              void **regionAddressPtr) {
115204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    if (offsetInBytes < 0) {
116fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk        ALOGE("illegal offsetInBytes = %d", offsetInBytes);
1175ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk        return AAUDIO_ERROR_OUT_OF_RANGE;
118204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    } else if ((offsetInBytes + sizeInBytes) > mSizeInBytes) {
119fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk        ALOGE("out of range, offsetInBytes = %d, "
120e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk                      "sizeInBytes = %d, mSizeInBytes = %d",
121204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk              offsetInBytes, sizeInBytes, mSizeInBytes);
1225ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk        return AAUDIO_ERROR_OUT_OF_RANGE;
123204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    }
124e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk
125e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    aaudio_result_t result = AAUDIO_OK;
126e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk
127478d5df3a0e1693669f5809176d5c7f6e8c9aa88Phil Burk    if (mResolvedAddress == MMAP_UNRESOLVED_ADDRESS) {
128e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        if (mFd.get() != -1) {
129e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk            result = resolveSharedMemory(mFd);
130e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        } else {
131fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk            ALOGE("has no file descriptor for shared memory.");
132e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk            result = AAUDIO_ERROR_INTERNAL;
133204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk        }
134204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    }
135e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk
136e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    if (result == AAUDIO_OK && mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
137e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk        *regionAddressPtr = mResolvedAddress + offsetInBytes;
138fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk        ALOGV("mResolvedAddress = %p", mResolvedAddress);
139fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk        ALOGV("offset by %d, *regionAddressPtr = %p", offsetInBytes, *regionAddressPtr);
140e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    }
141e72481c5c16d401c776e0ba49b84b80223769b91Phil Burk    return result;
142204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk}
143204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
144204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkint32_t SharedMemoryParcelable::getSizeInBytes() {
145204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    return mSizeInBytes;
146204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk}
147204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
148a5891f427bbd57914090f3260430b82f6879ec8dPhil Burkaaudio_result_t SharedMemoryParcelable::validate() const {
1493df348fbaca567ca891503213ff8c344a1ea2e05Phil Burk    if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
150fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk        ALOGE("invalid mSizeInBytes = %d", mSizeInBytes);
1513df348fbaca567ca891503213ff8c344a1ea2e05Phil Burk        return AAUDIO_ERROR_OUT_OF_RANGE;
152204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk    }
1535ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk    return AAUDIO_OK;
154204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk}
155204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk
156204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkvoid SharedMemoryParcelable::dump() {
157fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk    ALOGD("mFd = %d", mFd.get());
158fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk    ALOGD("mSizeInBytes = %d", mSizeInBytes);
159fbf031e8f197c916ae9c399f42926494ebdeb497Phil Burk    ALOGD("mResolvedAddress = %p", mResolvedAddress);
160204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk}
161