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 #ifndef CPP_CAR_BINDER_LIB_LARGEPARCELABLE_INCLUDE_LARGEPARCELABLEVECTOR_H_
18 #define CPP_CAR_BINDER_LIB_LARGEPARCELABLE_INCLUDE_LARGEPARCELABLEVECTOR_H_
19
20 #include "LargeParcelableBase.h"
21 #include "SharedMemory.h"
22
23 #include <android/binder_parcel.h>
24 #include <android/binder_parcel_utils.h>
25 #include <android/binder_status.h>
26
27 #include <memory>
28 #include <optional>
29
30 namespace android {
31 namespace automotive {
32 namespace car_binder_lib {
33
34 // This class allows a list of stable AIDL parcelables to be marshalled to a shared memory file if
35 // their serialized parcel exceeds binder limitation.
36 template <class T>
37 class LargeParcelableVector : public LargeParcelableBase {
38 public:
LargeParcelableVector()39 LargeParcelableVector() {}
40
41 // Use a list of stable AIDL parcelables to initiate this large parcelable.
42 //
43 // T must be a Parcelable.
LargeParcelableVector(std::vector<T> parcelable)44 explicit LargeParcelableVector(std::vector<T> parcelable) :
45 mParcelable(std::move(parcelable)) {}
46
47 // Get the list of stable AIDL parcelable object. Caller is supposed to use
48 // 'LargeParcelableVector' class to parse data from 'Parcel' and then use 'getParcelables' to
49 // get the underlying parsed regular parcelable objects.
getParcelables()50 inline const std::optional<const std::vector<T>*> getParcelables() const {
51 if (!hasDeserializedParcelable()) {
52 return std::nullopt;
53 }
54 return &mParcelable;
55 }
56
57 protected:
58 // Serialize this parcelable to 'dest'.
59 binder_status_t serialize(AParcel* dest) const override;
60
61 // Serialize a NULL parcelable for 'this' class to 'dest'.
62 binder_status_t serializeNullPayload(AParcel* dest) const override;
63
64 // Read a 'Parcelable' from the given Parcel. The src might be parsed to a NULL parcelable.
65 binder_status_t deserialize(const AParcel& src) override;
66
67 private:
68 std::vector<T> mParcelable;
69
70 // Serialize a nullable Parcelabel 'payload' to 'dest'.
71 static binder_status_t serializePayload(const std::vector<T>* payload, AParcel* dest);
72 };
73
74 template <class T>
serializePayload(const std::vector<T> * payload,AParcel * dest)75 binder_status_t LargeParcelableVector<T>::serializePayload(const std::vector<T>* payload,
76 AParcel* dest) {
77 int32_t startPosition;
78 if (DBG_PAYLOAD) {
79 startPosition = AParcel_getDataPosition(dest);
80 }
81 if (binder_status_t status = ::ndk::AParcel_writeVector(dest, *payload); status != STATUS_OK) {
82 ALOGE("failed to write parcelable vector to parcel, status: %d", status);
83 return status;
84 }
85 if (DBG_PAYLOAD) {
86 ALOGD("serialize-payload, start:%d size: %d", startPosition,
87 (AParcel_getDataPosition(dest) - startPosition));
88 }
89 return STATUS_OK;
90 }
91
92 template <class T>
serialize(AParcel * dest)93 binder_status_t LargeParcelableVector<T>::serialize(AParcel* dest) const {
94 return serializePayload(&mParcelable, dest);
95 }
96
97 template <class T>
serializeNullPayload(AParcel * dest)98 binder_status_t LargeParcelableVector<T>::serializeNullPayload(AParcel* dest) const {
99 std::vector<T> empty;
100 return serializePayload(&empty, dest);
101 }
102
103 template <class T>
deserialize(const AParcel & src)104 binder_status_t LargeParcelableVector<T>::deserialize(const AParcel& src) {
105 int32_t startPosition;
106 if (DBG_PAYLOAD) {
107 startPosition = AParcel_getDataPosition(&src);
108 ALOGD("start position: %d", startPosition);
109 }
110 if (binder_status_t status = ::ndk::AParcel_readVector(&src, &mParcelable);
111 status != STATUS_OK) {
112 ALOGE("failed to read parcelable vector from parcel, status: %d", status);
113 return status;
114 }
115 if (DBG_PAYLOAD) {
116 ALOGD("deserialize-payload, start:%d size: %d", startPosition,
117 (AParcel_getDataPosition(&src) - startPosition));
118 }
119 return STATUS_OK;
120 }
121
122 } // namespace car_binder_lib
123 } // namespace automotive
124 } // namespace android
125
126 #endif // CPP_CAR_BINDER_LIB_LARGEPARCELABLE_INCLUDE_LARGEPARCELABLEVECTOR_H_
127