• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 // WARNING: This file is intended for multiple inclusion, one time
18 // with BACKEND_NDK_IMPL defined, one time without it.
19 // Do not include directly, use 'AidlConversionUtil.h'.
20 #if (defined(BACKEND_NDK_IMPL) && !defined(AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_NDK)) || \
21     (!defined(BACKEND_NDK_IMPL) && !defined(AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_CPP))
22 #if defined(BACKEND_NDK_IMPL)
23 #define AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_NDK
24 #else
25 #define AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_CPP
26 #endif  // BACKEND_NDK_IMPL
27 
28 #include <functional>
29 #include <limits>
30 #include <type_traits>
31 #include <utility>
32 
33 #include <android-base/expected.h>
34 
35 #if defined(BACKEND_NDK_IMPL)
36 #include <android/binder_auto_utils.h>
37 #include <android/binder_enums.h>
38 #include <android/binder_status.h>
39 
40 namespace aidl {
41 #else
42 #include <binder/Enums.h>
43 #include <binder/Status.h>
44 #endif  // BACKEND_NDK_IMPL
45 namespace android {
46 
47 #if defined(BACKEND_NDK_IMPL)
48 // This adds `::aidl::android::ConversionResult` for convenience.
49 // Otherwise, it would be required to write `::android::ConversionResult` everywhere.
50 template <typename T>
51 using ConversionResult = ::android::ConversionResult<T>;
52 #endif  // BACKEND_NDK_IMPL
53 
54 /**
55  * A generic template to safely cast between integral types, respecting limits of the destination
56  * type.
57  */
58 template<typename To, typename From>
convertIntegral(From from)59 ConversionResult<To> convertIntegral(From from) {
60     // Special handling is required for signed / vs. unsigned comparisons, since otherwise we may
61     // have the signed converted to unsigned and produce wrong results.
62     if constexpr (std::is_signed_v<From> && !std::is_signed_v<To>) {
63         if (from < 0 || from > std::numeric_limits<To>::max()) {
64             return ::android::base::unexpected(::android::BAD_VALUE);
65         }
66     } else if constexpr (std::is_signed_v<To> && !std::is_signed_v<From>) {
67         if (from > std::numeric_limits<To>::max()) {
68             return ::android::base::unexpected(::android::BAD_VALUE);
69         }
70     } else /* constexpr */ {
71         if (from < std::numeric_limits<To>::min() || from > std::numeric_limits<To>::max()) {
72             return ::android::base::unexpected(::android::BAD_VALUE);
73         }
74     }
75     return static_cast<To>(from);
76 }
77 
78 /**
79  * A generic template to safely cast between types, that are intended to be the same size, but
80  * interpreted differently.
81  */
82 template<typename To, typename From>
convertReinterpret(From from)83 ConversionResult<To> convertReinterpret(From from) {
84     static_assert(sizeof(From) == sizeof(To));
85     return static_cast<To>(from);
86 }
87 
88 /**
89  * A generic template that helps convert containers of convertible types, using iterators.
90  */
91 template<typename InputIterator, typename OutputIterator, typename Func>
convertRange(InputIterator start,InputIterator end,OutputIterator out,const Func & itemConversion)92 ::android::status_t convertRange(InputIterator start,
93                       InputIterator end,
94                       OutputIterator out,
95                       const Func& itemConversion) {
96     for (InputIterator iter = start; iter != end; ++iter, ++out) {
97         *out = VALUE_OR_RETURN_STATUS(itemConversion(*iter));
98     }
99     return ::android::OK;
100 }
101 
102 /**
103  * A generic template that helps convert containers of convertible types, using iterators.
104  * Uses a limit as maximum conversion items.
105  */
106 template<typename InputIterator, typename OutputIterator, typename Func>
convertRangeWithLimit(InputIterator start,InputIterator end,OutputIterator out,const Func & itemConversion,const size_t limit)107 ::android::status_t convertRangeWithLimit(InputIterator start,
108                       InputIterator end,
109                       OutputIterator out,
110                       const Func& itemConversion,
111                       const size_t limit) {
112     InputIterator last = end;
113     if (end - start > limit) {
114         last = start + limit;
115     }
116     for (InputIterator iter = start; (iter != last); ++iter, ++out) {
117         *out = VALUE_OR_RETURN_STATUS(itemConversion(*iter));
118     }
119     return ::android::OK;
120 }
121 
122 /**
123  * A generic template that helps convert containers of convertible types without
124  * using an intermediate container.
125  */
126 template<typename InputContainer, typename OutputContainer, typename Func>
convertContainer(const InputContainer & input,OutputContainer * output,const Func & itemConversion)127 ::android::status_t convertContainer(const InputContainer& input, OutputContainer* output,
128         const Func& itemConversion) {
129     auto ins = std::inserter(*output, output->begin());
130     for (const auto& item : input) {
131         *ins = VALUE_OR_RETURN_STATUS(itemConversion(item));
132     }
133     return ::android::OK;
134 }
135 
136 /**
137  * A generic template that helps convert containers of convertible types.
138  */
139 template<typename OutputContainer, typename InputContainer, typename Func>
140 ConversionResult<OutputContainer>
convertContainer(const InputContainer & input,const Func & itemConversion)141 convertContainer(const InputContainer& input, const Func& itemConversion) {
142     OutputContainer output;
143     auto ins = std::inserter(output, output.begin());
144     for (const auto& item : input) {
145         *ins = VALUE_OR_RETURN(itemConversion(item));
146     }
147     return output;
148 }
149 
150 /**
151  * A generic template that helps convert containers of convertible types
152  * using an item conversion function with an additional parameter.
153  */
154 template<typename OutputContainer, typename InputContainer, typename Func, typename Parameter>
155 ConversionResult<OutputContainer>
convertContainer(const InputContainer & input,const Func & itemConversion,const Parameter & param)156 convertContainer(const InputContainer& input, const Func& itemConversion, const Parameter& param) {
157     OutputContainer output;
158     auto ins = std::inserter(output, output.begin());
159     for (const auto& item : input) {
160         *ins = VALUE_OR_RETURN(itemConversion(item, param));
161     }
162     return output;
163 }
164 
165 /**
166  * A generic template that helps to "zip" two input containers of the same size
167  * into a single vector of converted types. The conversion function must
168  * thus accept two arguments.
169  */
170 template<typename OutputContainer, typename InputContainer1,
171         typename InputContainer2, typename Func>
172 ConversionResult<OutputContainer>
convertContainers(const InputContainer1 & input1,const InputContainer2 & input2,const Func & itemConversion)173 convertContainers(const InputContainer1& input1, const InputContainer2& input2,
174         const Func& itemConversion) {
175     auto iter2 = input2.begin();
176     OutputContainer output;
177     auto ins = std::inserter(output, output.begin());
178     for (const auto& item1 : input1) {
179         RETURN_IF_ERROR(iter2 != input2.end() ? ::android::OK : ::android::BAD_VALUE);
180         *ins = VALUE_OR_RETURN(itemConversion(item1, *iter2++));
181     }
182     return output;
183 }
184 
185 /**
186  * A generic template that helps to "unzip" a per-element conversion into
187  * a pair of elements into a pair of containers. The conversion function
188  * must emit a pair of elements.
189  */
190 template<typename OutputContainer1, typename OutputContainer2,
191         typename InputContainer, typename Func>
192 ConversionResult<std::pair<OutputContainer1, OutputContainer2>>
convertContainerSplit(const InputContainer & input,const Func & itemConversion)193 convertContainerSplit(const InputContainer& input, const Func& itemConversion) {
194     OutputContainer1 output1;
195     OutputContainer2 output2;
196     auto ins1 = std::inserter(output1, output1.begin());
197     auto ins2 = std::inserter(output2, output2.begin());
198     for (const auto& item : input) {
199         auto out_pair = VALUE_OR_RETURN(itemConversion(item));
200         *ins1 = out_pair.first;
201         *ins2 = out_pair.second;
202     }
203     return std::make_pair(output1, output2);
204 }
205 
206 ////////////////////////////////////////////////////////////////////////////////////////////////////
207 // The code below establishes:
208 // IntegralTypeOf<T>, which works for either integral types (in which case it evaluates to T), or
209 // enum types (in which case it evaluates to std::underlying_type_T<T>).
210 
211 template<typename T, typename = std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>
212 struct IntegralTypeOfStruct {
213     using Type = T;
214 };
215 
216 template<typename T>
217 struct IntegralTypeOfStruct<T, std::enable_if_t<std::is_enum_v<T>>> {
218     using Type = std::underlying_type_t<T>;
219 };
220 
221 template<typename T>
222 using IntegralTypeOf = typename IntegralTypeOfStruct<T>::Type;
223 
224 ////////////////////////////////////////////////////////////////////////////////////////////////////
225 // Utilities for handling bitmasks.
226 // Some AIDL enums are specified using bit indices, for example:
227 //   `AidlEnum { FOO = 0, BAR = 1, BAZ = 2' }`
228 // while corresponding legacy types universally uses actual bitmasks, for example:
229 //   `enum legacy_enum_t { LEGACY_FOO = 1 << 0, LEGACY_BAR = 1 << 1, LEGACY_BAZ = 1 << 2 }`
230 // There is also the third type used to store the resulting mask, which is combined
231 // from individual bits. In AIDL this is typically an int (`int32_t`), in legacy types this
232 // is often the enum type itself (although, strictly this is not correct since masks are not
233 // declared as part of the enum type). The bit index value always has an integer type.
234 //
235 // `indexToEnum_index` constructs an instance of the enum from an index,
236 // for example `AidlEnum::BAR` from `1`.
237 // `indexToEnum_bitmask` produces a corresponding legacy bitmask enum instance,
238 // for example, `LEGACY_BAR` (`2`) from `1`.
239 // `enumToMask_bitmask` simply casts an enum type to a bitmask type.
240 // `enumToMask_index` creates a mask from an enum type which specifies an index.
241 //
242 // All these functions can be plugged into `convertBitmask`. For example, to implement
243 // conversion from `AidlEnum` to `legacy_enum_t`, with a mask stored in `int32_t`,
244 // the following call needs to be made:
245 //   convertBitmask<legacy_enum_t /*DestMask*/, int32_t /*SrcMask*/,
246 //                  legacy_enum_t /*DestEnum*/, AidlEnum /*SrcEnum*/>(
247 //     maskField /*int32_t*/, aidl2legacy_AidlEnum_legacy_enum_t /*enumConversion*/,
248 //     indexToEnum_index<AidlEnum> /*srcIndexToEnum*/,
249 //     enumToMask_bitmask<legacy_enum_t, legacy_enum_t> /*destEnumToMask*/)
250 //
251 // The only extra function needed is for mapping between corresponding enum values
252 // of the AidlEnum and the legacy_enum_t. Note that the mapping is between values
253 // of enums, for example, `AidlEnum::BAZ` maps to `LEGACY_BAZ` and vice versa.
254 
255 template<typename Enum>
256 Enum indexToEnum_index(int index) {
257     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
258     return static_cast<Enum>(index);
259 }
260 
261 template<typename Enum>
262 Enum indexToEnum_bitmask(int index) {
263     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
264     return static_cast<Enum>(1 << index);
265 }
266 
267 template<typename Mask, typename Enum>
268 Mask enumToMask_bitmask(Enum e) {
269     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
270     static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
271     return static_cast<Mask>(e);
272 }
273 
274 template<typename Mask, typename Enum>
275 Mask enumToMask_index(Enum e) {
276     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
277     static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
278     return static_cast<Mask>(static_cast<std::make_unsigned_t<IntegralTypeOf<Mask>>>(1)
279             << static_cast<int>(e));
280 }
281 
282 template<typename DestMask, typename SrcMask, typename DestEnum, typename SrcEnum>
283 ConversionResult<DestMask> convertBitmask(
284         SrcMask src, const std::function<ConversionResult<DestEnum>(SrcEnum)>& enumConversion,
285         const std::function<SrcEnum(int)>& srcIndexToEnum,
286         const std::function<DestMask(DestEnum)>& destEnumToMask) {
287     using UnsignedDestMask = std::make_unsigned_t<IntegralTypeOf<DestMask>>;
288     using UnsignedSrcMask = std::make_unsigned_t<IntegralTypeOf<SrcMask>>;
289 
290     UnsignedDestMask dest = static_cast<UnsignedDestMask>(0);
291     UnsignedSrcMask usrc = static_cast<UnsignedSrcMask>(src);
292 
293     int srcBitIndex = 0;
294     while (usrc != 0) {
295         if (usrc & 1) {
296             SrcEnum srcEnum = srcIndexToEnum(srcBitIndex);
297             DestEnum destEnum = VALUE_OR_RETURN(enumConversion(srcEnum));
298             DestMask destMask = destEnumToMask(destEnum);
299             dest |= destMask;
300         }
301         ++srcBitIndex;
302         usrc >>= 1;
303     }
304     return static_cast<DestMask>(dest);
305 }
306 
307 template<typename Mask, typename Enum>
308 bool bitmaskIsSet(Mask mask, Enum index) {
309     return (mask & enumToMask_index<Mask, Enum>(index)) != 0;
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////////////////////////
313 // Utilities for working with AIDL unions.
314 // UNION_GET(obj, fieldname) returns a ConversionResult<T> containing either the strongly-typed
315 //   value of the respective field, or ::android::BAD_VALUE if the union is not set to the requested
316 //   field.
317 // UNION_SET(obj, fieldname, value) sets the requested field to the given value.
318 
319 template<typename T, typename T::Tag tag>
320 using UnionFieldType = std::decay_t<decltype(std::declval<T>().template get<tag>())>;
321 
322 template<typename T, typename T::Tag tag>
323 ConversionResult<UnionFieldType<T, tag>> unionGetField(const T& u) {
324     if (u.getTag() != tag) {
325         return ::android::base::unexpected(::android::BAD_VALUE);
326     }
327     return u.template get<tag>();
328 }
329 
330 #define UNION_GET(u, field) \
331     unionGetField<std::decay_t<decltype(u)>, std::decay_t<decltype(u)>::Tag::field>(u)
332 
333 #define UNION_SET(u, field, value) \
334     (u).set<std::decay_t<decltype(u)>::Tag::field>(value)
335 
336 #define UNION_MAKE(u, field, value) u::make<u::Tag::field>(value)
337 
338 namespace aidl_utils {
339 
340 /**
341  * Return true if the value is valid for the AIDL enumeration.
342  */
343 template <typename T>
344 bool isValidEnum(T value) {
345 #if defined(BACKEND_NDK_IMPL)
346     constexpr ndk::enum_range<T> er{};
347 #else
348     constexpr ::android::enum_range<T> er{};
349 #endif
350     return std::find(er.begin(), er.end(), value) != er.end();
351 }
352 
353 // T is a "container" of enum binder types with a toString().
354 template <typename T>
355 std::string enumsToString(const T& t) {
356     std::string s;
357     for (const auto item : t) {
358         if (s.empty()) {
359             s = toString(item);
360         } else {
361             s.append("|").append(toString(item));
362         }
363     }
364     return s;
365 }
366 
367 /**
368  * Return the equivalent Android ::android::status_t from a binder exception code.
369  *
370  * Generally one should use statusTFromBinderStatus() instead.
371  *
372  * Exception codes can be generated from a remote Java service exception, translate
373  * them for use on the Native side.
374  *
375  * Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code
376  * can be found from transactionError() or serviceSpecificErrorCode().
377  */
378 #if defined(BACKEND_NDK_IMPL)
379 static inline ::android::status_t statusTFromExceptionCode(binder_exception_t exception) {
380     switch (exception) {
381         case EX_NONE:
382             return ::android::OK;
383         case EX_SECURITY:  // Java SecurityException, rethrows locally in Java
384             return ::android::PERMISSION_DENIED;
385         case EX_BAD_PARCELABLE:  // Java BadParcelableException, rethrows in Java
386         case EX_ILLEGAL_ARGUMENT:  // Java IllegalArgumentException, rethrows in Java
387         case EX_NULL_POINTER:  // Java NullPointerException, rethrows in Java
388             return ::android::BAD_VALUE;
389         case EX_ILLEGAL_STATE:  // Java IllegalStateException, rethrows in Java
390         case EX_UNSUPPORTED_OPERATION:  // Java UnsupportedOperationException, rethrows
391             return ::android::INVALID_OPERATION;
392         case EX_PARCELABLE:  // Java bootclass loader (not standard exception), rethrows
393         case EX_NETWORK_MAIN_THREAD:  // Java NetworkOnMainThreadException, rethrows
394         case EX_TRANSACTION_FAILED: // Native - see error code
395         case EX_SERVICE_SPECIFIC:   // Java ServiceSpecificException,
396                                             // rethrows in Java with integer error code
397             return ::android::UNKNOWN_ERROR;
398     }
399     return ::android::UNKNOWN_ERROR;
400 }
401 #else
402 static inline ::android::status_t statusTFromExceptionCode(int32_t exceptionCode) {
403     using namespace ::android::binder;
404     switch (exceptionCode) {
405         case Status::EX_NONE:
406             return ::android::OK;
407         case Status::EX_SECURITY:  // Java SecurityException, rethrows locally in Java
408             return ::android::PERMISSION_DENIED;
409         case Status::EX_BAD_PARCELABLE:  // Java BadParcelableException, rethrows in Java
410         case Status::EX_ILLEGAL_ARGUMENT:  // Java IllegalArgumentException, rethrows in Java
411         case Status::EX_NULL_POINTER:  // Java NullPointerException, rethrows in Java
412             return ::android::BAD_VALUE;
413         case Status::EX_ILLEGAL_STATE:  // Java IllegalStateException, rethrows in Java
414         case Status::EX_UNSUPPORTED_OPERATION:  // Java UnsupportedOperationException, rethrows
415             return ::android::INVALID_OPERATION;
416         case Status::EX_HAS_REPLY_HEADER: // Native strictmode violation
417         case Status::EX_PARCELABLE:  // Java bootclass loader (not standard exception), rethrows
418         case Status::EX_NETWORK_MAIN_THREAD:  // Java NetworkOnMainThreadException, rethrows
419         case Status::EX_TRANSACTION_FAILED: // Native - see error code
420         case Status::EX_SERVICE_SPECIFIC:   // Java ServiceSpecificException,
421                                             // rethrows in Java with integer error code
422             return ::android::UNKNOWN_ERROR;
423     }
424     return ::android::UNKNOWN_ERROR;
425 }
426 #endif  // BACKEND_NDK_IMPL
427 
428 /**
429  * Return the equivalent Android ::android::status_t from a binder status.
430  *
431  * Used to handle errors from a AIDL method declaration
432  *
433  * [oneway] void method(type0 param0, ...)
434  *
435  * or the following (where return_type is not a status_t)
436  *
437  * return_type method(type0 param0, ...)
438  */
439 #if !defined(BACKEND_NDK_IMPL)
440 static inline ::android::status_t statusTFromBinderStatus(const ::android::binder::Status &status) {
441     return status.isOk() ? ::android::OK // check ::android::OK,
442         : status.serviceSpecificErrorCode() // service-side error, not standard Java exception
443                                             // (fromServiceSpecificError)
444         ?: status.transactionError() // a native binder transaction error (fromStatusT)
445         ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a
446                                                     // standard Java exception (fromExceptionCode)
447 }
448 #endif
449 
450 #if defined(BACKEND_NDK_IMPL)
451 static inline ::android::status_t statusTFromBinderStatus(const ::ndk::ScopedAStatus &status) {
452     // What we want to do is to 'return statusTFromBinderStatus(status.get()->get())'
453     // However, since the definition of AStatus is not exposed, we have to do the same
454     // via methods of ScopedAStatus:
455     return status.isOk() ? ::android::OK // check ::android::OK,
456         : status.getServiceSpecificError() // service-side error, not standard Java exception
457                                            // (fromServiceSpecificError)
458         ?: status.getStatus() // a native binder transaction error (fromStatusT)
459         ?: statusTFromExceptionCode(status.getExceptionCode()); // a service-side error with a
460                                                      // standard Java exception (fromExceptionCode)
461 }
462 
463 static inline ::android::status_t statusTFromBinderStatusT(binder_status_t status) {
464     return statusTFromBinderStatus(::ndk::ScopedAStatus::fromStatus(status));
465 }
466 #endif
467 
468 /**
469  * Return a binder::Status from native service status.
470  *
471  * This is used for methods not returning an explicit status_t,
472  * where Java callers expect an exception, not an integer return value.
473  */
474 #if !defined(BACKEND_NDK_IMPL)
475 static inline ::android::binder::Status binderStatusFromStatusT(
476         ::android::status_t status, const char *optionalMessage = nullptr) {
477     const char * const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage;
478     // From binder::Status instructions:
479     //  Prefer a generic exception code when possible, then a service specific
480     //  code, and finally a ::android::status_t for low level failures or legacy support.
481     //  Exception codes and service specific errors map to nicer exceptions for
482     //  Java clients.
483 
484     using namespace ::android::binder;
485     switch (status) {
486         case ::android::OK:
487             return Status::ok();
488         case ::android::PERMISSION_DENIED: // throw SecurityException on Java side
489             return Status::fromExceptionCode(Status::EX_SECURITY, emptyIfNull);
490         case ::android::BAD_VALUE: // throw IllegalArgumentException on Java side
491             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, emptyIfNull);
492         case ::android::INVALID_OPERATION: // throw IllegalStateException on Java side
493             return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, emptyIfNull);
494     }
495 
496     // A service specific error will not show on status.transactionError() so
497     // be sure to use statusTFromBinderStatus() for reliable error handling.
498 
499     // throw a ServiceSpecificException.
500     return Status::fromServiceSpecificError(status, emptyIfNull);
501 }
502 #endif
503 
504 } // namespace aidl_utils
505 
506 }  // namespace android
507 
508 #if defined(BACKEND_NDK_IMPL)
509 }  // namespace aidl
510 #endif
511 
512 // (defined(BACKEND_NDK_IMPL) && !defined(AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_NDK)) || \
513 // (!defined(BACKEND_NDK_IMPL) && !defined(AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_CPP))
514 #endif
515