• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 /**
18  * @addtogroup NdkBinder
19  * @{
20  */
21 
22 /**
23  * @file binder_parcelable_utils.h
24  * @brief Helper for parcelable.
25  */
26 
27 #pragma once
28 #include <android/binder_parcel_utils.h>
29 #include <optional>
30 
31 namespace ndk {
32 // Also see Parcelable.h in libbinder.
33 typedef int32_t parcelable_stability_t;
34 enum {
35     STABILITY_LOCAL,
36     STABILITY_VINTF,  // corresponds to @VintfStability
37 };
38 #define RETURN_ON_FAILURE(expr)                   \
39     do {                                          \
40         binder_status_t _status = (expr);         \
41         if (_status != STATUS_OK) return _status; \
42     } while (false)
43 
44 class AParcelableHolder {
45    public:
46     AParcelableHolder() = delete;
AParcelableHolder(parcelable_stability_t stability)47     explicit AParcelableHolder(parcelable_stability_t stability)
48         : mParcel(AParcel_create()), mStability(stability) {}
49 
50     virtual ~AParcelableHolder() = default;
51 
writeToParcel(AParcel * parcel)52     binder_status_t writeToParcel(AParcel* parcel) const {
53         RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
54         if (__builtin_available(android 31, *)) {
55             int32_t size = AParcel_getDataSize(this->mParcel.get());
56             RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
57         } else {
58             return STATUS_INVALID_OPERATION;
59         }
60         if (__builtin_available(android 31, *)) {
61             int32_t size = AParcel_getDataSize(this->mParcel.get());
62             RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
63         } else {
64             return STATUS_INVALID_OPERATION;
65         }
66         return STATUS_OK;
67     }
68 
readFromParcel(const AParcel * parcel)69     binder_status_t readFromParcel(const AParcel* parcel) {
70         if (__builtin_available(android 31, *)) {
71             AParcel_reset(mParcel.get());
72         } else {
73             return STATUS_INVALID_OPERATION;
74         }
75 
76         RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
77         int32_t dataSize;
78         binder_status_t status = AParcel_readInt32(parcel, &dataSize);
79 
80         if (status != STATUS_OK || dataSize < 0) {
81             return status != STATUS_OK ? status : STATUS_BAD_VALUE;
82         }
83 
84         int32_t dataStartPos = AParcel_getDataPosition(parcel);
85 
86         if (dataStartPos > INT32_MAX - dataSize) {
87             return STATUS_BAD_VALUE;
88         }
89 
90         if (__builtin_available(android 31, *)) {
91             status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
92         } else {
93             status = STATUS_INVALID_OPERATION;
94         }
95         if (status != STATUS_OK) {
96             return status;
97         }
98         return AParcel_setDataPosition(parcel, dataStartPos + dataSize);
99     }
100 
101     template <typename T>
setParcelable(const T & p)102     binder_status_t setParcelable(const T& p) {
103         if (this->mStability > T::_aidl_stability) {
104             return STATUS_BAD_VALUE;
105         }
106         if (__builtin_available(android 31, *)) {
107             AParcel_reset(mParcel.get());
108         } else {
109             return STATUS_INVALID_OPERATION;
110         }
111         AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
112         p.writeToParcel(mParcel.get());
113         return STATUS_OK;
114     }
115 
116     template <typename T>
getParcelable(std::optional<T> * ret)117     binder_status_t getParcelable(std::optional<T>* ret) const {
118         const std::string parcelableDesc(T::descriptor);
119         AParcel_setDataPosition(mParcel.get(), 0);
120         if (__builtin_available(android 31, *)) {
121             if (AParcel_getDataSize(mParcel.get()) == 0) {
122                 *ret = std::nullopt;
123                 return STATUS_OK;
124             }
125         } else {
126             return STATUS_INVALID_OPERATION;
127         }
128         std::string parcelableDescInParcel;
129         binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
130         if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
131             *ret = std::nullopt;
132             return status;
133         }
134         *ret = std::make_optional<T>();
135         status = (*ret)->readFromParcel(this->mParcel.get());
136         if (status != STATUS_OK) {
137             *ret = std::nullopt;
138             return status;
139         }
140         return STATUS_OK;
141     }
142 
reset()143     void reset() {
144         if (__builtin_available(android 31, *)) {
145             AParcel_reset(mParcel.get());
146         }
147     }
148 
149     inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
150     inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
151     inline bool operator<=(const AParcelableHolder& rhs) const { return this <= &rhs; }
152     inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
153     inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
154     inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
155 
156    private:
157     mutable ndk::ScopedAParcel mParcel;
158     parcelable_stability_t mStability;
159 };
160 
161 #undef RETURN_ON_FAILURE
162 }  // namespace ndk
163 
164 /** @} */
165