• 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 <android-base/expected.h>
24 #include <binder/Status.h>
25 
26 namespace android {
27 
28 template <typename T>
29 using ConversionResult = base::expected<T, status_t>;
30 
31 // Convenience macros for working with ConversionResult, useful for writing converted for aggregate
32 // types.
33 
34 #define VALUE_OR_RETURN(result)                                \
35     ({                                                         \
36         auto _tmp = (result);                                  \
37         if (!_tmp.ok()) return base::unexpected(_tmp.error()); \
38         std::move(_tmp.value());                               \
39     })
40 
41 #define RETURN_IF_ERROR(result) \
42     if (status_t _tmp = (result); _tmp != OK) return base::unexpected(_tmp);
43 
44 #define VALUE_OR_RETURN_STATUS(x)           \
45     ({                                      \
46        auto _tmp = (x);                     \
47        if (!_tmp.ok()) return _tmp.error(); \
48        std::move(_tmp.value());             \
49      })
50 
51 #define VALUE_OR_FATAL(result)                                        \
52     ({                                                                \
53        auto _tmp = (result);                                          \
54        LOG_ALWAYS_FATAL_IF(!_tmp.ok(),                                \
55                            "Function: %s Line: %d Failed result (%d)",\
56                            __FUNCTION__, __LINE__, _tmp.error());     \
57        std::move(_tmp.value());                                       \
58      })
59 
60 /**
61  * A generic template to safely cast between integral types, respecting limits of the destination
62  * type.
63  */
64 template<typename To, typename From>
convertIntegral(From from)65 ConversionResult<To> convertIntegral(From from) {
66     // Special handling is required for signed / vs. unsigned comparisons, since otherwise we may
67     // have the signed converted to unsigned and produce wrong results.
68     if (std::is_signed_v<From> && !std::is_signed_v<To>) {
69         if (from < 0 || from > std::numeric_limits<To>::max()) {
70             return base::unexpected(BAD_VALUE);
71         }
72     } else if (std::is_signed_v<To> && !std::is_signed_v<From>) {
73         if (from > std::numeric_limits<To>::max()) {
74             return base::unexpected(BAD_VALUE);
75         }
76     } else {
77         if (from < std::numeric_limits<To>::min() || from > std::numeric_limits<To>::max()) {
78             return base::unexpected(BAD_VALUE);
79         }
80     }
81     return static_cast<To>(from);
82 }
83 
84 /**
85  * A generic template to safely cast between types, that are intended to be the same size, but
86  * interpreted differently.
87  */
88 template<typename To, typename From>
convertReinterpret(From from)89 ConversionResult<To> convertReinterpret(From from) {
90     static_assert(sizeof(From) == sizeof(To));
91     return static_cast<To>(from);
92 }
93 
94 /**
95  * A generic template that helps convert containers of convertible types, using iterators.
96  */
97 template<typename InputIterator, typename OutputIterator, typename Func>
convertRange(InputIterator start,InputIterator end,OutputIterator out,const Func & itemConversion)98 status_t convertRange(InputIterator start,
99                       InputIterator end,
100                       OutputIterator out,
101                       const Func& itemConversion) {
102     for (InputIterator iter = start; iter != end; ++iter, ++out) {
103         *out = VALUE_OR_RETURN_STATUS(itemConversion(*iter));
104     }
105     return OK;
106 }
107 
108 /**
109  * A generic template that helps convert containers of convertible types.
110  */
111 template<typename OutputContainer, typename InputContainer, typename Func>
112 ConversionResult<OutputContainer>
convertContainer(const InputContainer & input,const Func & itemConversion)113 convertContainer(const InputContainer& input, const Func& itemConversion) {
114     OutputContainer output;
115     auto ins = std::inserter(output, output.begin());
116     for (const auto& item : input) {
117         *ins = VALUE_OR_RETURN(itemConversion(item));
118     }
119     return output;
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////////////////////////
123 // The code below establishes:
124 // IntegralTypeOf<T>, which works for either integral types (in which case it evaluates to T), or
125 // enum types (in which case it evaluates to std::underlying_type_T<T>).
126 
127 template<typename T, typename = std::enable_if_t<std::is_integral_v<T> || std::is_enum_v<T>>>
128 struct IntegralTypeOfStruct {
129     using Type = T;
130 };
131 
132 template<typename T>
133 struct IntegralTypeOfStruct<T, std::enable_if_t<std::is_enum_v<T>>> {
134     using Type = std::underlying_type_t<T>;
135 };
136 
137 template<typename T>
138 using IntegralTypeOf = typename IntegralTypeOfStruct<T>::Type;
139 
140 ////////////////////////////////////////////////////////////////////////////////////////////////////
141 // Utilities for handling bitmasks.
142 
143 template<typename Enum>
144 Enum indexToEnum_index(int index) {
145     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
146     return static_cast<Enum>(index);
147 }
148 
149 template<typename Enum>
150 Enum indexToEnum_bitmask(int index) {
151     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
152     return static_cast<Enum>(1 << index);
153 }
154 
155 template<typename Mask, typename Enum>
156 Mask enumToMask_bitmask(Enum e) {
157     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
158     static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
159     return static_cast<Mask>(e);
160 }
161 
162 template<typename Mask, typename Enum>
163 Mask enumToMask_index(Enum e) {
164     static_assert(std::is_enum_v<Enum> || std::is_integral_v<Enum>);
165     static_assert(std::is_enum_v<Mask> || std::is_integral_v<Mask>);
166     return static_cast<Mask>(static_cast<std::make_unsigned_t<IntegralTypeOf<Mask>>>(1)
167             << static_cast<int>(e));
168 }
169 
170 template<typename DestMask, typename SrcMask, typename DestEnum, typename SrcEnum>
171 ConversionResult<DestMask> convertBitmask(
172         SrcMask src, const std::function<ConversionResult<DestEnum>(SrcEnum)>& enumConversion,
173         const std::function<SrcEnum(int)>& srcIndexToEnum,
174         const std::function<DestMask(DestEnum)>& destEnumToMask) {
175     using UnsignedDestMask = std::make_unsigned_t<IntegralTypeOf<DestMask>>;
176     using UnsignedSrcMask = std::make_unsigned_t<IntegralTypeOf<SrcMask>>;
177 
178     UnsignedDestMask dest = static_cast<UnsignedDestMask>(0);
179     UnsignedSrcMask usrc = static_cast<UnsignedSrcMask>(src);
180 
181     int srcBitIndex = 0;
182     while (usrc != 0) {
183         if (usrc & 1) {
184             SrcEnum srcEnum = srcIndexToEnum(srcBitIndex);
185             DestEnum destEnum = VALUE_OR_RETURN(enumConversion(srcEnum));
186             DestMask destMask = destEnumToMask(destEnum);
187             dest |= destMask;
188         }
189         ++srcBitIndex;
190         usrc >>= 1;
191     }
192     return static_cast<DestMask>(dest);
193 }
194 
195 template<typename Mask, typename Enum>
196 bool bitmaskIsSet(Mask mask, Enum index) {
197     return (mask & enumToMask_index<Mask, Enum>(index)) != 0;
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////////////////////////////
201 // Utilities for working with AIDL unions.
202 // UNION_GET(obj, fieldname) returns a ConversionResult<T> containing either the strongly-typed
203 //   value of the respective field, or BAD_VALUE if the union is not set to the requested field.
204 // UNION_SET(obj, fieldname, value) sets the requested field to the given value.
205 
206 template<typename T, typename T::Tag tag>
207 using UnionFieldType = std::decay_t<decltype(std::declval<T>().template get<tag>())>;
208 
209 template<typename T, typename T::Tag tag>
210 ConversionResult<UnionFieldType<T, tag>> unionGetField(const T& u) {
211     if (u.getTag() != tag) {
212         return base::unexpected(BAD_VALUE);
213     }
214     return u.template get<tag>();
215 }
216 
217 #define UNION_GET(u, field) \
218     unionGetField<std::decay_t<decltype(u)>, std::decay_t<decltype(u)>::Tag::field>(u)
219 
220 #define UNION_SET(u, field, value) \
221     (u).set<std::decay_t<decltype(u)>::Tag::field>(value)
222 
223 namespace aidl_utils {
224 
225 /**
226  * Return the equivalent Android status_t from a binder exception code.
227  *
228  * Generally one should use statusTFromBinderStatus() instead.
229  *
230  * Exception codes can be generated from a remote Java service exception, translate
231  * them for use on the Native side.
232  *
233  * Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code
234  * can be found from transactionError() or serviceSpecificErrorCode().
235  */
236 static inline status_t statusTFromExceptionCode(int32_t exceptionCode) {
237     using namespace ::android::binder;
238     switch (exceptionCode) {
239         case Status::EX_NONE:
240             return OK;
241         case Status::EX_SECURITY: // Java SecurityException, rethrows locally in Java
242             return PERMISSION_DENIED;
243         case Status::EX_BAD_PARCELABLE: // Java BadParcelableException, rethrows in Java
244         case Status::EX_ILLEGAL_ARGUMENT: // Java IllegalArgumentException, rethrows in Java
245         case Status::EX_NULL_POINTER: // Java NullPointerException, rethrows in Java
246             return BAD_VALUE;
247         case Status::EX_ILLEGAL_STATE: // Java IllegalStateException, rethrows in Java
248         case Status::EX_UNSUPPORTED_OPERATION: // Java UnsupportedOperationException, rethrows
249             return INVALID_OPERATION;
250         case Status::EX_HAS_REPLY_HEADER: // Native strictmode violation
251         case Status::EX_PARCELABLE: // Java bootclass loader (not standard exception), rethrows
252         case Status::EX_NETWORK_MAIN_THREAD: // Java NetworkOnMainThreadException, rethrows
253         case Status::EX_TRANSACTION_FAILED: // Native - see error code
254         case Status::EX_SERVICE_SPECIFIC:  // Java ServiceSpecificException,
255                                            // rethrows in Java with integer error code
256             return UNKNOWN_ERROR;
257     }
258     return UNKNOWN_ERROR;
259 }
260 
261 /**
262  * Return the equivalent Android status_t from a binder status.
263  *
264  * Used to handle errors from a AIDL method declaration
265  *
266  * [oneway] void method(type0 param0, ...)
267  *
268  * or the following (where return_type is not a status_t)
269  *
270  * return_type method(type0 param0, ...)
271  */
272 static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) {
273     return status.isOk() ? OK // check OK,
274         : status.serviceSpecificErrorCode() // service-side error, not standard Java exception
275                                             // (fromServiceSpecificError)
276         ?: status.transactionError() // a native binder transaction error (fromStatusT)
277         ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a
278                                                     // standard Java exception (fromExceptionCode)
279 }
280 
281 /**
282  * Return a binder::Status from native service status.
283  *
284  * This is used for methods not returning an explicit status_t,
285  * where Java callers expect an exception, not an integer return value.
286  */
287 static inline ::android::binder::Status binderStatusFromStatusT(
288         status_t status, const char *optionalMessage = nullptr) {
289     const char * const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage;
290     // From binder::Status instructions:
291     //  Prefer a generic exception code when possible, then a service specific
292     //  code, and finally a status_t for low level failures or legacy support.
293     //  Exception codes and service specific errors map to nicer exceptions for
294     //  Java clients.
295 
296     using namespace ::android::binder;
297     switch (status) {
298         case OK:
299             return Status::ok();
300         case PERMISSION_DENIED: // throw SecurityException on Java side
301             return Status::fromExceptionCode(Status::EX_SECURITY, emptyIfNull);
302         case BAD_VALUE: // throw IllegalArgumentException on Java side
303             return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, emptyIfNull);
304         case INVALID_OPERATION: // throw IllegalStateException on Java side
305             return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, emptyIfNull);
306     }
307 
308     // A service specific error will not show on status.transactionError() so
309     // be sure to use statusTFromBinderStatus() for reliable error handling.
310 
311     // throw a ServiceSpecificException.
312     return Status::fromServiceSpecificError(status, emptyIfNull);
313 }
314 
315 
316 } // namespace aidl_utils
317 
318 }  // namespace android
319