1 /*
2 * Copyright (C) 2021 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 "LargeParcelable"
18
19 #include "LargeParcelableBase.h"
20
21 #include "MappedFile.h"
22 #include "SharedMemory.h"
23
24 #include <android-base/unique_fd.h>
25 #include <android/binder_auto_utils.h>
26 #include <android/binder_parcel.h>
27 #include <android/binder_parcel_utils.h>
28 #include <android/binder_status.h>
29 #include <utils/Errors.h>
30 #include <utils/Log.h>
31
32 #include <stdint.h>
33
34 #include <cstring>
35 #include <iostream>
36 #include <memory>
37 #include <optional>
38 #include <sstream>
39 #include <string>
40
41 namespace android {
42 namespace automotive {
43 namespace car_binder_lib {
44
45 using ::android::base::borrowed_fd;
46 using ::android::base::unique_fd;
47 using ::ndk::ScopedAParcel;
48 using ::ndk::ScopedFileDescriptor;
49
scopedFdToBorrowedFd(const ScopedFileDescriptor & fd)50 borrowed_fd LargeParcelableBase::scopedFdToBorrowedFd(const ScopedFileDescriptor& fd) {
51 borrowed_fd memoryFd(fd.get());
52 return memoryFd;
53 }
54
scopeFdToUniqueFd(ScopedFileDescriptor && fd)55 unique_fd LargeParcelableBase::scopeFdToUniqueFd(ScopedFileDescriptor&& fd) {
56 // ScopedFileDescriptor does not have release function, so we have to directly modify its
57 // underlying fd pointer to remove ownership.
58 unique_fd memoryFd(fd.get());
59 *(fd.getR()) = INVALID_MEMORY_FD;
60 return memoryFd;
61 }
62
readFromParcel(const AParcel * in)63 binder_status_t LargeParcelableBase::readFromParcel(const AParcel* in) {
64 mHasDeserializedParcelable = false;
65
66 // Make this compatible with stable AIDL
67 // payloadSize + Nullable Parcelable + Nullable ParcelFileDescriptor
68 int32_t startPosition = AParcel_getDataPosition(in);
69 int32_t totalPayloadSize;
70 if (binder_status_t status = AParcel_readInt32(in, &totalPayloadSize); status != STATUS_OK) {
71 ALOGE("failed to read Int32: %d", status);
72 return status;
73 }
74 if (binder_status_t status = deserialize(*in); status != STATUS_OK) {
75 ALOGE("failed to deserialize: %d", status);
76 return status;
77 }
78 int32_t sharedMemoryPosition = AParcel_getDataPosition(in);
79 ScopedFileDescriptor descriptor;
80 if (binder_status_t status = AParcel_readNullableParcelFileDescriptor(in, &descriptor);
81 status != STATUS_OK) {
82 ALOGE("invalid data, failed to read file descirptor: %d", status);
83 return status;
84 }
85 bool hasSharedMemory = (descriptor.get() != INVALID_MEMORY_FD);
86 if (hasSharedMemory) {
87 // Release descriptor to memoryFd.
88 unique_fd memoryFd = scopeFdToUniqueFd(std::move(descriptor));
89 if (binder_status_t status = deserializeSharedMemoryAndClose(std::move(memoryFd));
90 status != STATUS_OK) {
91 return status;
92 }
93 }
94 if (DBG_PAYLOAD) {
95 ALOGD("Read, start:%d totalPayloadSize:%d sharedMemoryPosition:%d hasSharedMemory:%d",
96 startPosition, totalPayloadSize, sharedMemoryPosition, hasSharedMemory);
97 }
98 mHasDeserializedParcelable = true;
99 return STATUS_OK;
100 }
101
prepareSharedMemory(AParcel * parcel) const102 binder_status_t LargeParcelableBase::prepareSharedMemory(AParcel* parcel) const {
103 int32_t startPosition = AParcel_getDataPosition(parcel);
104 if (binder_status_t status = serializeMemoryFdOrPayload(parcel, nullptr); status != STATUS_OK) {
105 ALOGE("failed to serialize: %d", status);
106 return status;
107 }
108 int32_t payloadSize = AParcel_getDataPosition(parcel) - startPosition;
109 bool noSharedMemory = (payloadSize <= MAX_DIRECT_PAYLOAD_SIZE);
110 if (noSharedMemory) {
111 // Do nothing.
112 mNeedSharedMemory = false;
113 return STATUS_OK;
114 }
115 binder_status_t status;
116 std::unique_ptr<SharedMemory> sharedMemory =
117 serializeParcelToSharedMemory(*parcel, startPosition, payloadSize, &status);
118 if (status != STATUS_OK) {
119 ALOGE("failed to serialize parcel to shared memory: %d", status);
120 return status;
121 }
122 mNeedSharedMemory = true;
123 mSharedMemory = std::move(sharedMemory);
124 return STATUS_OK;
125 }
126
writeToParcel(AParcel * dest) const127 binder_status_t LargeParcelableBase::writeToParcel(AParcel* dest) const {
128 // Make this compatible with stable AIDL
129 // payloadSize + Nullable Parcelable + Nullable ParcelFileDescriptor
130 int startPosition = AParcel_getDataPosition(dest);
131 if (!mNeedSharedMemory.has_value()) {
132 if (binder_status_t status = prepareSharedMemory(dest); status != STATUS_OK) {
133 ALOGE("failed to serialize payload to parcel: %d", status);
134 return status;
135 }
136 }
137 bool needSharedMemory = mNeedSharedMemory.value();
138 if (needSharedMemory) {
139 const SharedMemory* sharedMemory = mSharedMemory.get();
140 AParcel_setDataPosition(dest, startPosition);
141 if (binder_status_t status = serializeMemoryFdOrPayload(dest, sharedMemory);
142 status != STATUS_OK) {
143 ALOGE("failed to serialize shared memory fd to parcel: %d", status);
144 return status;
145 }
146 }
147
148 int32_t totalPayloadSize = AParcel_getDataPosition(dest) - startPosition;
149 if (DBG_PAYLOAD) {
150 ALOGD("Write, start:%d totalPayloadSize:%d hasSharedMemory:%d", startPosition,
151 totalPayloadSize, needSharedMemory);
152 }
153 return OK;
154 }
155
deserializeSharedMemoryAndClose(unique_fd memoryFd)156 binder_status_t LargeParcelableBase::deserializeSharedMemoryAndClose(unique_fd memoryFd) {
157 ScopedAParcel parcel(AParcel_create());
158 // This would close memoryFd after destruction.
159 SharedMemory sharedMemory(std::move(memoryFd));
160 if (!sharedMemory.isValid()) {
161 ALOGE("invalid shared memory fd, status: %d", sharedMemory.getErr());
162 return STATUS_FDS_NOT_ALLOWED;
163 }
164 if (binder_status_t status = copyFromSharedMemory(sharedMemory, parcel.get());
165 status != STATUS_OK) {
166 return status;
167 }
168 int32_t payloadSize;
169 if (binder_status_t status = AParcel_readInt32(parcel.get(), &payloadSize);
170 status != STATUS_OK) {
171 ALOGE("failed to read Int32: %d", status);
172 if (DBG_PAYLOAD) {
173 ALOGD("parse shared memory file, payload size: %d", payloadSize);
174 }
175 return status;
176 }
177 if (binder_status_t status = deserialize(*(parcel.get())); status != STATUS_OK) {
178 return status;
179 }
180 // There is an additional 0 for null file descriptor in the parcel we would ignore.
181 return STATUS_OK;
182 }
183
copyFromSharedMemory(const SharedMemory & sharedMemory,AParcel * parcel)184 binder_status_t LargeParcelableBase::copyFromSharedMemory(const SharedMemory& sharedMemory,
185 AParcel* parcel) {
186 std::unique_ptr<MappedFile> mappedFile = sharedMemory.mapReadOnly();
187 size_t mappedFileSize = mappedFile->getSize();
188 if (!mappedFile->isValid()) {
189 ALOGE("failed to map file for size: %zu, error: %d", sharedMemory.getSize(),
190 mappedFile->getErr());
191 return STATUS_FDS_NOT_ALLOWED;
192 }
193 if (binder_status_t status =
194 AParcel_unmarshal(parcel, static_cast<const uint8_t*>(mappedFile->getAddr()),
195 mappedFileSize);
196 status != STATUS_OK) {
197 return status;
198 }
199 AParcel_setDataPosition(parcel, 0);
200 if (DBG_PAYLOAD) {
201 size_t dumpSize = std::min(DBG_DUMP_LENGTH, mappedFileSize);
202 bool truncated = (dumpSize < mappedFileSize);
203 std::stringbuf buffer;
204 std::ostream bd(&buffer);
205 if (truncated) {
206 bd << "unmarshalled(truncated):";
207 } else {
208 bd << "unmarshalled:";
209 }
210 bd << std::hex;
211 size_t parcelStartPosition = AParcel_getDataPosition(parcel);
212 std::unique_ptr<uint8_t[]> fromParcel(new uint8_t[mappedFileSize]);
213 if (binder_status_t status = AParcel_marshal(parcel, fromParcel.get(), 0, dumpSize);
214 status != STATUS_OK) {
215 ALOGE("failed to marshal parcel: %d", status);
216 return status;
217 }
218 for (size_t i = 0; i < dumpSize; i++) {
219 bd << static_cast<int>(fromParcel[i]);
220 if (i != dumpSize - 1) {
221 bd << ",";
222 }
223 }
224 bd << "=startPosition:" << parcelStartPosition;
225 bd.flush();
226 ALOGD("%s", buffer.str().c_str());
227 AParcel_setDataPosition(parcel, parcelStartPosition);
228 }
229 return STATUS_OK;
230 }
231
writeSharedMemoryCompatibleToParcel(const SharedMemory * sharedMemory,AParcel * dest)232 binder_status_t LargeParcelableBase::writeSharedMemoryCompatibleToParcel(
233 const SharedMemory* sharedMemory, AParcel* dest) {
234 ScopedFileDescriptor descriptor;
235 if (sharedMemory == nullptr) {
236 return ::ndk::AParcel_writeNullableParcelFileDescriptor(dest, descriptor);
237 }
238 // non-null case
239 unique_fd fd = sharedMemory->getDupFd();
240 descriptor.set(fd.release());
241 return ::ndk::AParcel_writeNullableParcelFileDescriptor(dest, descriptor);
242 }
243
serializeParcelToSharedMemory(const AParcel & p,int32_t start,int32_t size,binder_status_t * outStatus)244 std::unique_ptr<SharedMemory> LargeParcelableBase::serializeParcelToSharedMemory(
245 const AParcel& p, int32_t start, int32_t size, binder_status_t* outStatus) {
246 std::unique_ptr<SharedMemory> memory(new SharedMemory(size));
247 if (!memory->isValid()) {
248 ALOGE("failed to create memfile for size: %d, status: %d", size, memory->getErr());
249 *outStatus = STATUS_UNKNOWN_ERROR;
250 return std::unique_ptr<SharedMemory>(nullptr);
251 }
252 // This would be unmapped after function returns.
253 std::unique_ptr<MappedFile> buffer = memory->mapReadWrite();
254 if (!buffer->isValid()) {
255 ALOGE("failed to map shared memory as read write for size: %d, status: %d", size,
256 buffer->getErr());
257 *outStatus = STATUS_UNKNOWN_ERROR;
258 return std::unique_ptr<SharedMemory>(nullptr);
259 }
260 if (binder_status_t status =
261 AParcel_marshal(&p, static_cast<uint8_t*>(buffer->getWriteAddr()), start, size);
262 status != STATUS_OK) {
263 ALOGE("failed to marshal parcel: %d", status);
264 *outStatus = status;
265 return std::unique_ptr<SharedMemory>(nullptr);
266 }
267 buffer->sync();
268
269 if (status_t astatus = memory->lock() != OK) {
270 ALOGE("Failed to set read-only protection on shared memory: %d", astatus);
271 *outStatus = STATUS_UNKNOWN_ERROR;
272 return std::unique_ptr<SharedMemory>(nullptr);
273 }
274
275 if (DBG_PAYLOAD) {
276 size_t dumpSize = std::min(DBG_DUMP_LENGTH, static_cast<size_t>(size));
277 std::stringbuf log;
278 std::ostream bd(&log);
279 const uint8_t* addr = static_cast<uint8_t*>(buffer->getWriteAddr());
280 bd << "unmarshalled:" << std::hex;
281 for (size_t i = 0; i < dumpSize; i++) {
282 bd << static_cast<int>(addr[i]);
283 if (i != dumpSize - 1) {
284 bd << ",";
285 }
286 }
287 bd.flush();
288 ALOGD("%s", log.str().c_str());
289 }
290 *outStatus = STATUS_OK;
291 return memory;
292 }
293
updatePayloadSize(AParcel * dest,int32_t startPosition)294 int32_t LargeParcelableBase::updatePayloadSize(AParcel* dest, int32_t startPosition) {
295 int32_t lastPosition = AParcel_getDataPosition(dest);
296 int32_t totalPayloadSize = lastPosition - startPosition;
297 AParcel_setDataPosition(dest, startPosition);
298 AParcel_writeInt32(dest, totalPayloadSize);
299 AParcel_setDataPosition(dest, lastPosition);
300 return totalPayloadSize;
301 }
302
hasDeserializedParcelable() const303 bool LargeParcelableBase::hasDeserializedParcelable() const {
304 return mHasDeserializedParcelable;
305 }
306
getParcelFromMemoryFile(const ScopedFileDescriptor & fd,AParcel * parcel)307 binder_status_t LargeParcelableBase::getParcelFromMemoryFile(const ScopedFileDescriptor& fd,
308 AParcel* parcel) {
309 borrowed_fd memoryFd = scopedFdToBorrowedFd(fd);
310 SharedMemory sharedMemory(memoryFd);
311 if (!sharedMemory.isValid()) {
312 ALOGE("invalid shared memory fd, status: %d", sharedMemory.getErr());
313 return STATUS_FDS_NOT_ALLOWED;
314 }
315 if (binder_status_t status = copyFromSharedMemory(sharedMemory, parcel); status != STATUS_OK) {
316 ALOGE("failed to copy from shared memory: %d", status);
317 return status;
318 }
319 return STATUS_OK;
320 }
321
parcelToMemoryFile(const AParcel & parcel,ScopedFileDescriptor * sharedMemoryFd)322 binder_status_t LargeParcelableBase::parcelToMemoryFile(const AParcel& parcel,
323 ScopedFileDescriptor* sharedMemoryFd) {
324 int32_t payloadSize = AParcel_getDataPosition(&parcel);
325 binder_status_t status = STATUS_OK;
326 std::unique_ptr<SharedMemory> sharedMemory =
327 serializeParcelToSharedMemory(parcel, /*start=*/0, payloadSize, &status);
328 if (status != STATUS_OK) {
329 ALOGE("failed to serialize parcel to shared memory: %d", status);
330 return status;
331 }
332
333 unique_fd fd(sharedMemory->getDupFd());
334 sharedMemoryFd->set(fd.release());
335 return STATUS_OK;
336 }
337
serializeMemoryFdOrPayload(AParcel * dest,const SharedMemory * sharedMemory) const338 binder_status_t LargeParcelableBase::serializeMemoryFdOrPayload(
339 AParcel* dest, const SharedMemory* sharedMemory) const {
340 // This is compatible with stable AIDL serialization:
341 // payload size + payload + nullable fd
342 // The shared Memory file might contain a serialized parcel created from this function.
343 int32_t startPosition = AParcel_getDataPosition(dest);
344 AParcel_writeInt32(dest, 0);
345 if (sharedMemory == nullptr) {
346 if (binder_status_t status = serialize(dest); status != STATUS_OK) {
347 ALOGE("failed to serialize: %d", status);
348 return status;
349 }
350 } else {
351 serializeNullPayload(dest);
352 }
353
354 if (DBG_PAYLOAD) {
355 int sharedMemoryPosition = AParcel_getDataPosition(dest) - startPosition;
356 ALOGD("Serialize shared memory fd: sharedMemoryPosition:%d hasSharedMemory:%d",
357 sharedMemoryPosition, sharedMemory != nullptr);
358 }
359 if (binder_status_t status = writeSharedMemoryCompatibleToParcel(sharedMemory, dest);
360 status != STATUS_OK) {
361 ALOGE("failed to write file descriptor to parcel: %d", status);
362 return status;
363 }
364 updatePayloadSize(dest, startPosition);
365 return STATUS_OK;
366 }
367
368 } // namespace car_binder_lib
369 } // namespace automotive
370 } // namespace android
371