• 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 #pragma once
18 
19 #include <limits>
20 #include <type_traits>
21 #include <utility>
22 
23 #include <binder/Enums.h>
24 #include <binder/Status.h>
25 #include <error/Result.h>
26 
27 namespace android {
28 
29 template <typename T>
30 using ConversionResult = error::Result<T>;
31 
32 /**
33  * A generic template to safely cast between integral types, respecting limits of the destination
34  * type.
35  */
36 template<typename To, typename From>
convertIntegral(From from)37 ConversionResult<To> convertIntegral(From from) {
38     // Special handling is required for signed / vs. unsigned comparisons, since otherwise we may
39     // have the signed converted to unsigned and produce wrong results.
40     if (std::is_signed_v<From> && !std::is_signed_v<To>) {
41         if (from < 0 || from > std::numeric_limits<To>::max()) {
42             return base::unexpected(BAD_VALUE);
43         }
44     } else if (std::is_signed_v<To> && !std::is_signed_v<From>) {
45         if (from > std::numeric_limits<To>::max()) {
46             return base::unexpected(BAD_VALUE);
47         }
48     } else {
49         if (from < std::numeric_limits<To>::min() || from > std::numeric_limits<To>::max()) {
50             return base::unexpected(BAD_VALUE);
51         }
52     }
53     return static_cast<To>(from);
54 }
55 
56 /**
57  * A generic template to safely cast between types, that are intended to be the same size, but
58  * interpreted differently.
59  */
60 template<typename To, typename From>
convertReinterpret(From from)61 ConversionResult<To> convertReinterpret(From from) {
62     static_assert(sizeof(From) == sizeof(To));
63     return static_cast<To>(from);
64 }
65 
66 /**
67  * A generic template that helps convert containers of convertible types, using iterators.
68  */
69 template<typename InputIterator, typename OutputIterator, typename Func>
convertRange(InputIterator start,InputIterator end,OutputIterator out,const Func & itemConversion)70 status_t convertRange(InputIterator start,
71                       InputIterator end,
72                       OutputIterator out,
73                       const Func& itemConversion) {
74     for (InputIterator iter = start; iter != end; ++iter, ++out) {
75         *out = VALUE_OR_RETURN_STATUS(itemConversion(*iter));
76     }
77     return OK;
78 }
79 
80 /**
81  * A generic template that helps convert containers of convertible types, using iterators.
82  * Uses a limit as maximum conversion items.
83  */
84 template<typename InputIterator, typename OutputIterator, typename Func>
convertRangeWithLimit(InputIterator start,InputIterator end,OutputIterator out,const Func & itemConversion,const size_t limit)85 status_t convertRangeWithLimit(InputIterator start,
86                       InputIterator end,
87                       OutputIterator out,
88                       const Func& itemConversion,
89                       const size_t limit) {
90     InputIterator last = end;
91     if (end - start > limit) {
92         last = start + limit;
93     }
94     for (InputIterator iter = start; (iter != last); ++iter, ++out) {
95         *out = VALUE_OR_RETURN_STATUS(itemConversion(*iter));
96     }
97     return OK;
98 }
99 
100 /**
101  * A generic template that helps convert containers of convertible types.
102  */
103 template<typename OutputContainer, typename InputContainer, typename Func>
104 ConversionResult<OutputContainer>
convertContainer(const InputContainer & input,const Func & itemConversion)105 convertContainer(const InputContainer& input, const Func& itemConversion) {
106     OutputContainer output;
107     auto ins = std::inserter(output, output.begin());
108     for (const auto& item : input) {
109         *ins = VALUE_OR_RETURN(itemConversion(item));
110     }
111     return output;
112 }
113 
114 /**
115  * A generic template that helps convert containers of convertible types
116  * using an item conversion function with an additional parameter.
117  */
118 template<typename OutputContainer, typename InputContainer, typename Func, typename Parameter>
119 ConversionResult<OutputContainer>
convertContainer(const InputContainer & input,const Func & itemConversion,const Parameter & param)120 convertContainer(const InputContainer& input, const Func& itemConversion, const Parameter& param) {
121     OutputContainer output;
122     auto ins = std::inserter(output, output.begin());
123     for (const auto& item : input) {
124         *ins = VALUE_OR_RETURN(itemConversion(item, param));
125     }
126     return output;
127 }
128 
129 /**
130  * A generic template that helps to "zip" two input containers of the same size
131  * into a single vector of converted types. The conversion function must
132  * thus accept two arguments.
133  */
134 template<typename OutputContainer, typename InputContainer1,
135         typename InputContainer2, typename Func>
136 ConversionResult<OutputContainer>
convertContainers(const InputContainer1 & input1,const InputContainer2 & input2,const Func & itemConversion)137 convertContainers(const InputContainer1& input1, const InputContainer2& input2,
138         const Func& itemConversion) {
139     auto iter2 = input2.begin();
140     OutputContainer output;
141     auto ins = std::inserter(output, output.begin());
142     for (const auto& item1 : input1) {
143         RETURN_IF_ERROR(iter2 != input2.end() ? OK : BAD_VALUE);
144         *ins = VALUE_OR_RETURN(itemConversion(item1, *iter2++));
145     }
146     return output;
147 }
148 
149 /**
150  * A generic template that helps to "unzip" a per-element conversion into
151  * a pair of elements into a pair of containers. The conversion function
152  * must emit a pair of elements.
153  */
154 template<typename OutputContainer1, typename OutputContainer2,
155         typename InputContainer, typename Func>
156 ConversionResult<std::pair<OutputContainer1, OutputContainer2>>
convertContainerSplit(const InputContainer & input,const Func & itemConversion)157 convertContainerSplit(const InputContainer& input, const Func& itemConversion) {
158     OutputContainer1 output1;
159     OutputContainer2 output2;
160     auto ins1 = std::inserter(output1, output1.begin());
161     auto ins2 = std::inserter(output2, output2.begin());
162     for (const auto& item : input) {
163         auto out_pair = VALUE_OR_RETURN(itemConversion(item));
164         *ins1 = out_pair.first;
165         *ins2 = out_pair.second;
166     }
167     return std::make_pair(output1, output2);
168 }
169 
170 ////////////////////////////////////////////////////////////////////////////////////////////////////
171 // The code below establishes:
172 // IntegralTypeOf<T>, which works for either integral types (in which case it evaluates to T), or
173 // enum types (in which case it evaluates to std::underlying_type_T<T>).
174 
175 template<typename T, typename = std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>
176 struct IntegralTypeOfStruct {
177     using Type = T;
178 };
179 
180 template<typename T>
181 struct IntegralTypeOfStruct<T, std::enable_if_t<std::is_enum_v<T>>> {
182     using Type = std::underlying_type_t<T>;
183 };
184 
185 template<typename T>
186 using IntegralTypeOf = typename IntegralTypeOfStruct<T>::Type;
187 
188 ////////////////////////////////////////////////////////////////////////////////////////////////////
189 // Utilities for handling bitmasks.
190 
191 template<typename Enum>
192 Enum indexToEnum_index(int index) {
193     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
194     return static_cast<Enum>(index);
195 }
196 
197 template<typename Enum>
198 Enum indexToEnum_bitmask(int index) {
199     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
200     return static_cast<Enum>(1 << index);
201 }
202 
203 template<typename Mask, typename Enum>
204 Mask enumToMask_bitmask(Enum e) {
205     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
206     static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
207     return static_cast<Mask>(e);
208 }
209 
210 template<typename Mask, typename Enum>
211 Mask enumToMask_index(Enum e) {
212     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
213     static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
214     return static_cast<Mask>(static_cast<std::make_unsigned_t<IntegralTypeOf<Mask>>>(1)
215             << static_cast<int>(e));
216 }
217 
218 template<typename DestMask, typename SrcMask, typename DestEnum, typename SrcEnum>
219 ConversionResult<DestMask> convertBitmask(
220         SrcMask src, const std::function<ConversionResult<DestEnum>(SrcEnum)>& enumConversion,
221         const std::function<SrcEnum(int)>& srcIndexToEnum,
222         const std::function<DestMask(DestEnum)>& destEnumToMask) {
223     using UnsignedDestMask = std::make_unsigned_t<IntegralTypeOf<DestMask>>;
224     using UnsignedSrcMask = std::make_unsigned_t<IntegralTypeOf<SrcMask>>;
225 
226     UnsignedDestMask dest = static_cast<UnsignedDestMask>(0);
227     UnsignedSrcMask usrc = static_cast<UnsignedSrcMask>(src);
228 
229     int srcBitIndex = 0;
230     while (usrc != 0) {
231         if (usrc & 1) {
232             SrcEnum srcEnum = srcIndexToEnum(srcBitIndex);
233             DestEnum destEnum = VALUE_OR_RETURN(enumConversion(srcEnum));
234             DestMask destMask = destEnumToMask(destEnum);
235             dest |= destMask;
236         }
237         ++srcBitIndex;
238         usrc >>= 1;
239     }
240     return static_cast<DestMask>(dest);
241 }
242 
243 template<typename Mask, typename Enum>
244 bool bitmaskIsSet(Mask mask, Enum index) {
245     return (mask & enumToMask_index<Mask, Enum>(index)) != 0;
246 }
247 
248 ////////////////////////////////////////////////////////////////////////////////////////////////////
249 // Utilities for working with AIDL unions.
250 // UNION_GET(obj, fieldname) returns a ConversionResult<T> containing either the strongly-typed
251 //   value of the respective field, or BAD_VALUE if the union is not set to the requested field.
252 // UNION_SET(obj, fieldname, value) sets the requested field to the given value.
253 
254 template<typename T, typename T::Tag tag>
255 using UnionFieldType = std::decay_t<decltype(std::declval<T>().template get<tag>())>;
256 
257 template<typename T, typename T::Tag tag>
258 ConversionResult<UnionFieldType<T, tag>> unionGetField(const T& u) {
259     if (u.getTag() != tag) {
260         return base::unexpected(BAD_VALUE);
261     }
262     return u.template get<tag>();
263 }
264 
265 #define UNION_GET(u, field) \
266     unionGetField<std::decay_t<decltype(u)>, std::decay_t<decltype(u)>::Tag::field>(u)
267 
268 #define UNION_SET(u, field, value) \
269     (u).set<std::decay_t<decltype(u)>::Tag::field>(value)
270 
271 namespace aidl_utils {
272 
273 /**
274  * Return true if the value is valid for the AIDL enumeration.
275  */
276 template <typename T>
277 bool isValidEnum(T value) {
278     constexpr android::enum_range<T> er{};
279     return std::find(er.begin(), er.end(), value) != er.end();
280 }
281 
282 // T is a "container" of enum binder types with a toString().
283 template <typename T>
284 std::string enumsToString(const T& t) {
285     std::string s;
286     for (const auto item : t) {
287         if (s.empty()) {
288             s = toString(item);
289         } else {
290             s.append("|").append(toString(item));
291         }
292     }
293     return s;
294 }
295 
296 /**
297  * Return the equivalent Android status_t from a binder exception code.
298  *
299  * Generally one should use statusTFromBinderStatus() instead.
300  *
301  * Exception codes can be generated from a remote Java service exception, translate
302  * them for use on the Native side.
303  *
304  * Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code
305  * can be found from transactionError() or serviceSpecificErrorCode().
306  */
307 static inline status_t statusTFromExceptionCode(int32_t exceptionCode) {
308     using namespace ::android::binder;
309     switch (exceptionCode) {
310         case Status::EX_NONE:
311             return OK;
312         case Status::EX_SECURITY: // Java SecurityException, rethrows locally in Java
313             return PERMISSION_DENIED;
314         case Status::EX_BAD_PARCELABLE: // Java BadParcelableException, rethrows in Java
315         case Status::EX_ILLEGAL_ARGUMENT: // Java IllegalArgumentException, rethrows in Java
316         case Status::EX_NULL_POINTER: // Java NullPointerException, rethrows in Java
317             return BAD_VALUE;
318         case Status::EX_ILLEGAL_STATE: // Java IllegalStateException, rethrows in Java
319         case Status::EX_UNSUPPORTED_OPERATION: // Java UnsupportedOperationException, rethrows
320             return INVALID_OPERATION;
321         case Status::EX_HAS_REPLY_HEADER: // Native strictmode violation
322         case Status::EX_PARCELABLE: // Java bootclass loader (not standard exception), rethrows
323         case Status::EX_NETWORK_MAIN_THREAD: // Java NetworkOnMainThreadException, rethrows
324         case Status::EX_TRANSACTION_FAILED: // Native - see error code
325         case Status::EX_SERVICE_SPECIFIC:  // Java ServiceSpecificException,
326                                            // rethrows in Java with integer error code
327             return UNKNOWN_ERROR;
328     }
329     return UNKNOWN_ERROR;
330 }
331 
332 /**
333  * Return the equivalent Android status_t from a binder status.
334  *
335  * Used to handle errors from a AIDL method declaration
336  *
337  * [oneway] void method(type0 param0, ...)
338  *
339  * or the following (where return_type is not a status_t)
340  *
341  * return_type method(type0 param0, ...)
342  */
343 static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) {
344     return status.isOk() ? OK // check OK,
345         : status.serviceSpecificErrorCode() // service-side error, not standard Java exception
346                                             // (fromServiceSpecificError)
347         ?: status.transactionError() // a native binder transaction error (fromStatusT)
348         ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a
349                                                     // standard Java exception (fromExceptionCode)
350 }
351 
352 /**
353  * Return a binder::Status from native service status.
354  *
355  * This is used for methods not returning an explicit status_t,
356  * where Java callers expect an exception, not an integer return value.
357  */
358 static inline ::android::binder::Status binderStatusFromStatusT(
359         status_t status, const char *optionalMessage = nullptr) {
360     const char * const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage;
361     // From binder::Status instructions:
362     //  Prefer a generic exception code when possible, then a service specific
363     //  code, and finally a status_t for low level failures or legacy support.
364     //  Exception codes and service specific errors map to nicer exceptions for
365     //  Java clients.
366 
367     using namespace ::android::binder;
368     switch (status) {
369         case OK:
370             return Status::ok();
371         case PERMISSION_DENIED: // throw SecurityException on Java side
372             return Status::fromExceptionCode(Status::EX_SECURITY, emptyIfNull);
373         case BAD_VALUE: // throw IllegalArgumentException on Java side
374             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, emptyIfNull);
375         case INVALID_OPERATION: // throw IllegalStateException on Java side
376             return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, emptyIfNull);
377     }
378 
379     // A service specific error will not show on status.transactionError() so
380     // be sure to use statusTFromBinderStatus() for reliable error handling.
381 
382     // throw a ServiceSpecificException.
383     return Status::fromServiceSpecificError(status, emptyIfNull);
384 }
385 
386 
387 } // namespace aidl_utils
388 
389 }  // namespace android
390