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