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