1 /*
2  * Copyright (C) 2018 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_parcel_utils.h
24  * @brief A collection of helper wrappers for AParcel.
25  */
26 
27 #pragma once
28 
29 #include <android/binder_auto_utils.h>
30 #include <android/binder_interface_utils.h>
31 #include <android/binder_internal_logging.h>
32 #include <android/binder_parcel.h>
33 
34 #include <array>
35 #include <optional>
36 #include <string>
37 #include <type_traits>
38 #include <vector>
39 
40 namespace ndk {
41 
42 namespace {
43 template <typename Test, template <typename...> class Ref>
44 struct is_specialization : std::false_type {};
45 
46 template <template <typename...> class Ref, typename... Args>
47 struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
48 
49 template <typename Test, template <typename...> class Ref>
50 static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
51 
52 // Get the first template type from a container, the T from MyClass<T, ...>.
53 template <typename T>
54 struct first_template_type {
55     using type = void;
56 };
57 
58 template <template <typename...> class V, typename T, typename... Args>
59 struct first_template_type<V<T, Args...>> {
60     using type = T;
61 };
62 
63 template <typename T>
64 using first_template_type_t = typename first_template_type<T>::type;
65 
66 // Tells if T represents NDK interface (shared_ptr<ICInterface-derived>)
67 template <typename T>
68 static inline constexpr bool is_interface_v = is_specialization_v<T, std::shared_ptr>&&
69         std::is_base_of_v<::ndk::ICInterface, first_template_type_t<T>>;
70 
71 // Tells if T represents NDK parcelable with readFromParcel/writeToParcel methods defined
72 template <typename T, typename = void>
73 struct is_parcelable : std::false_type {};
74 
75 template <typename T>
76 struct is_parcelable<
77         T, std::void_t<decltype(std::declval<T>().readFromParcel(std::declval<const AParcel*>())),
78                        decltype(std::declval<T>().writeToParcel(std::declval<AParcel*>()))>>
79     : std::true_type {};
80 
81 template <typename T>
82 static inline constexpr bool is_parcelable_v = is_parcelable<T>::value;
83 
84 // Tells if T represents nullable NDK parcelable (optional<parcelable> or unique_ptr<parcelable>)
85 template <typename T>
86 static inline constexpr bool is_nullable_parcelable_v = is_parcelable_v<first_template_type_t<T>> &&
87                                                         (is_specialization_v<T, std::optional> ||
88                                                          is_specialization_v<T, std::unique_ptr>);
89 
90 // Tells if T is a fixed-size array.
91 template <typename T>
92 struct is_fixed_array : std::false_type {};
93 
94 template <typename T, size_t N>
95 struct is_fixed_array<std::array<T, N>> : std::true_type {};
96 
97 template <typename T>
98 static inline constexpr bool is_fixed_array_v = is_fixed_array<T>::value;
99 
100 template <typename T>
101 static inline constexpr bool dependent_false_v = false;
102 }  // namespace
103 
104 /**
105  * This checks the length against the array size and retrieves the buffer. No allocation required.
106  */
107 template <typename T, size_t N>
108 static inline bool AParcel_stdArrayAllocator(void* arrayData, int32_t length, T** outBuffer) {
109     if (length < 0) return false;
110 
111     if (length != static_cast<int32_t>(N)) {
112         return false;
113     }
114 
115     std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
116     *outBuffer = arr->data();
117     return true;
118 }
119 
120 /**
121  * This checks the length against the array size and retrieves the buffer. No allocation required.
122  */
123 template <typename T, size_t N>
124 static inline bool AParcel_nullableStdArrayAllocator(void* arrayData, int32_t length,
125                                                      T** outBuffer) {
126     std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
127     if (length < 0) {
128         *arr = std::nullopt;
129         return true;
130     }
131 
132     if (length != static_cast<int32_t>(N)) {
133         return false;
134     }
135 
136     arr->emplace();
137     *outBuffer = (*arr)->data();
138     return true;
139 }
140 
141 /**
142  * This checks the length against the array size. No allocation required.
143  */
144 template <size_t N>
145 static inline bool AParcel_stdArrayExternalAllocator(void* arrayData, int32_t length) {
146     (void)arrayData;
147     return length == static_cast<int32_t>(N);
148 }
149 
150 /**
151  * This checks the length against the array size. No allocation required.
152  */
153 template <typename T, size_t N>
154 static inline bool AParcel_nullableStdArrayExternalAllocator(void* arrayData, int32_t length) {
155     std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
156 
157     if (length < 0) {
158         *arr = std::nullopt;
159         return true;
160     }
161 
162     if (length != static_cast<int32_t>(N)) {
163         return false;
164     }
165 
166     arr->emplace();
167     return true;
168 }
169 
170 /**
171  * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
172  */
173 template <typename T>
174 static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) {
175     if (length < 0) return false;
176 
177     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
178     if (static_cast<size_t>(length) > vec->max_size()) return false;
179 
180     vec->resize(static_cast<size_t>(length));
181     *outBuffer = vec->data();
182     return true;
183 }
184 
185 /**
186  * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
187  */
188 template <typename T>
189 static inline bool AParcel_nullableStdVectorAllocator(void* vectorData, int32_t length,
190                                                       T** outBuffer) {
191     std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
192 
193     if (length < 0) {
194         *vec = std::nullopt;
195         return true;
196     }
197 
198     *vec = std::optional<std::vector<T>>(std::vector<T>{});
199 
200     if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
201     (*vec)->resize(static_cast<size_t>(length));
202 
203     *outBuffer = (*vec)->data();
204     return true;
205 }
206 
207 /**
208  * This allocates a vector to size 'length' and returns whether the allocation is successful.
209  *
210  * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
211  * externally with respect to the NDK, and that size information is not passed into the NDK.
212  * Instead, it is used in cases where callbacks are used. Note that when this allocator is used,
213  * null arrays are not supported.
214  *
215  * See AParcel_readVector(const AParcel* parcel, std::vector<bool>)
216  * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>)
217  */
218 template <typename T>
219 static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, int32_t length) {
220     if (length < 0) return false;
221 
222     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
223     if (static_cast<size_t>(length) > vec->max_size()) return false;
224 
225     vec->resize(static_cast<size_t>(length));
226     return true;
227 }
228 
229 /**
230  * This allocates a vector to size 'length' and returns whether the allocation is successful.
231  *
232  * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
233  * externally with respect to the NDK, and that size information is not passed into the NDK.
234  * Instead, it is used in cases where callbacks are used. Note, when this allocator is used,
235  * the vector itself can be nullable.
236  *
237  * See AParcel_readVector(const AParcel* parcel,
238  * std::optional<std::vector<std::optional<std::string>>>)
239  */
240 template <typename T>
241 static inline bool AParcel_nullableStdVectorExternalAllocator(void* vectorData, int32_t length) {
242     std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
243 
244     if (length < 0) {
245         *vec = std::nullopt;
246         return true;
247     }
248 
249     *vec = std::optional<std::vector<T>>(std::vector<T>{});
250 
251     if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
252     (*vec)->resize(static_cast<size_t>(length));
253 
254     return true;
255 }
256 
257 /**
258  * This retrieves the underlying value in a vector which may not be contiguous at index from a
259  * corresponding vectorData.
260  */
261 template <typename T>
262 static inline T AParcel_stdVectorGetter(const void* vectorData, size_t index) {
263     const std::vector<T>* vec = static_cast<const std::vector<T>*>(vectorData);
264     return (*vec)[index];
265 }
266 
267 /**
268  * This sets the underlying value in a corresponding vectorData which may not be contiguous at
269  * index.
270  */
271 template <typename T>
272 static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T value) {
273     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
274     (*vec)[index] = value;
275 }
276 
277 /**
278  * This sets the underlying value in a corresponding vectorData which may not be contiguous at
279  * index.
280  */
281 template <typename T>
282 static inline void AParcel_nullableStdVectorSetter(void* vectorData, size_t index, T value) {
283     std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
284     vec->value()[index] = value;
285 }
286 
287 /**
288  * Convenience method to write a nullable strong binder.
289  */
290 static inline binder_status_t AParcel_writeNullableStrongBinder(AParcel* parcel,
291                                                                 const SpAIBinder& binder) {
292     return AParcel_writeStrongBinder(parcel, binder.get());
293 }
294 
295 /**
296  * Convenience method to read a nullable strong binder.
297  */
298 static inline binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel,
299                                                                SpAIBinder* binder) {
300     AIBinder* readBinder;
301     binder_status_t status = AParcel_readStrongBinder(parcel, &readBinder);
302     if (status == STATUS_OK) {
303         binder->set(readBinder);
304     }
305     return status;
306 }
307 
308 /**
309  * Convenience method to write a strong binder but return an error if it is null.
310  */
311 static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel,
312                                                                 const SpAIBinder& binder) {
313     if (binder.get() == nullptr) {
314         syslog(LOG_ERR, "Passing null binder object as non-@nullable AIDL IBinder");
315         return STATUS_UNEXPECTED_NULL;
316     }
317     return AParcel_writeStrongBinder(parcel, binder.get());
318 }
319 
320 /**
321  * Convenience method to read a strong binder but return an error if it is null.
322  */
323 static inline binder_status_t AParcel_readRequiredStrongBinder(const AParcel* parcel,
324                                                                SpAIBinder* binder) {
325     AIBinder* readBinder;
326     binder_status_t ret = AParcel_readStrongBinder(parcel, &readBinder);
327     if (ret == STATUS_OK) {
328         if (readBinder == nullptr) {
329             return STATUS_UNEXPECTED_NULL;
330         }
331 
332         binder->set(readBinder);
333     }
334     return ret;
335 }
336 
337 /**
338  * Convenience method to write a ParcelFileDescriptor where -1 represents a null value.
339  */
340 static inline binder_status_t AParcel_writeNullableParcelFileDescriptor(
341         AParcel* parcel, const ScopedFileDescriptor& fd) {
342     return AParcel_writeParcelFileDescriptor(parcel, fd.get());
343 }
344 
345 /**
346  * Convenience method to read a ParcelFileDescriptor where -1 represents a null value.
347  */
348 static inline binder_status_t AParcel_readNullableParcelFileDescriptor(const AParcel* parcel,
349                                                                        ScopedFileDescriptor* fd) {
350     int readFd;
351     binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
352     if (status == STATUS_OK) {
353         fd->set(readFd);
354     }
355     return status;
356 }
357 
358 /**
359  * Convenience method to write a valid ParcelFileDescriptor.
360  */
361 static inline binder_status_t AParcel_writeRequiredParcelFileDescriptor(
362         AParcel* parcel, const ScopedFileDescriptor& fd) {
363     if (fd.get() < 0) {
364         syslog(LOG_ERR, "Passing -1 file descriptor as non-@nullable AIDL ParcelFileDescriptor");
365         return STATUS_UNEXPECTED_NULL;
366     }
367     return AParcel_writeParcelFileDescriptor(parcel, fd.get());
368 }
369 
370 /**
371  * Convenience method to read a valid ParcelFileDescriptor.
372  */
373 static inline binder_status_t AParcel_readRequiredParcelFileDescriptor(const AParcel* parcel,
374                                                                        ScopedFileDescriptor* fd) {
375     int readFd;
376     binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
377     if (status == STATUS_OK) {
378         if (readFd < 0) {
379             return STATUS_UNEXPECTED_NULL;
380         }
381         fd->set(readFd);
382     }
383     return status;
384 }
385 
386 /**
387  * Allocates a std::string to length and returns the underlying buffer. For use with
388  * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*).
389  */
390 static inline bool AParcel_stdStringAllocator(void* stringData, int32_t length, char** buffer) {
391     if (length <= 0) return false;
392 
393     std::string* str = static_cast<std::string*>(stringData);
394     str->resize(static_cast<size_t>(length) - 1);
395     *buffer = &(*str)[0];
396     return true;
397 }
398 
399 /**
400  * Allocates a string in a std::optional<std::string> to size 'length' (or to std::nullopt when
401  * length is -1) and returns the underlying buffer. For use with AParcel_readString. See use below
402  * in AParcel_readString(const AParcel*, std::optional<std::string>*).
403  */
404 static inline bool AParcel_nullableStdStringAllocator(void* stringData, int32_t length,
405                                                       char** buffer) {
406     if (length == 0) return false;
407 
408     std::optional<std::string>* str = static_cast<std::optional<std::string>*>(stringData);
409 
410     if (length < 0) {
411         *str = std::nullopt;
412         return true;
413     }
414 
415     *str = std::optional<std::string>(std::string{});
416     (*str)->resize(static_cast<size_t>(length) - 1);
417     *buffer = &(**str)[0];
418     return true;
419 }
420 
421 /**
422  * Allocates a std::string inside of a std::vector<std::string> at index 'index' to size 'length'.
423  */
424 static inline bool AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
425                                                            int32_t length, char** buffer) {
426     std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
427     std::string& element = vec->at(index);
428     return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
429 }
430 
431 /**
432  * This gets the length and buffer of a std::string inside of a std::vector<std::string> at index
433  * index.
434  */
435 static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index,
436                                                                int32_t* outLength) {
437     const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
438     const std::string& element = vec->at(index);
439 
440     *outLength = static_cast<int32_t>(element.size());
441     return element.c_str();
442 }
443 
444 /**
445  * Allocates a string in a std::optional<std::string> inside of a
446  * std::optional<std::vector<std::optional<std::string>>> at index 'index' to size 'length' (or to
447  * std::nullopt when length is -1).
448  */
449 static inline bool AParcel_nullableStdVectorStringElementAllocator(void* vectorData, size_t index,
450                                                                    int32_t length, char** buffer) {
451     std::optional<std::vector<std::optional<std::string>>>* vec =
452             static_cast<std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
453     std::optional<std::string>& element = vec->value().at(index);
454     return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
455 }
456 
457 /**
458  * This gets the length and buffer of a std::optional<std::string> inside of a
459  * std::vector<std::string> at index index. If the string is null, then it returns null and a length
460  * of -1.
461  */
462 static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData,
463                                                                        size_t index,
464                                                                        int32_t* outLength) {
465     const std::optional<std::vector<std::optional<std::string>>>* vec =
466             static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
467     const std::optional<std::string>& element = vec->value().at(index);
468 
469     if (!element) {
470         *outLength = -1;
471         return nullptr;
472     }
473 
474     *outLength = static_cast<int32_t>(element->size());
475     return element->c_str();
476 }
477 
478 /**
479  * This retrieves the underlying value in a std::array which may not be contiguous at index from a
480  * corresponding arrData.
481  */
482 template <typename T, size_t N>
483 static inline T AParcel_stdArrayGetter(const void* arrData, size_t index) {
484     const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrData);
485     return (*arr)[index];
486 }
487 
488 /**
489  * This sets the underlying value in a corresponding arrData which may not be contiguous at
490  * index.
491  */
492 template <typename T, size_t N>
493 static inline void AParcel_stdArraySetter(void* arrData, size_t index, T value) {
494     std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrData);
495     (*arr)[index] = value;
496 }
497 
498 /**
499  * This retrieves the underlying value in a std::array which may not be contiguous at index from a
500  * corresponding arrData.
501  */
502 template <typename T, size_t N>
503 static inline T AParcel_nullableStdArrayGetter(const void* arrData, size_t index) {
504     const std::optional<std::array<T, N>>* arr =
505             static_cast<const std::optional<std::array<T, N>>*>(arrData);
506     return (*arr)[index];
507 }
508 
509 /**
510  * This sets the underlying value in a corresponding arrData which may not be contiguous at
511  * index.
512  */
513 template <typename T, size_t N>
514 static inline void AParcel_nullableStdArraySetter(void* arrData, size_t index, T value) {
515     std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrData);
516     (*arr)->at(index) = value;
517 }
518 
519 /**
520  * Allocates a std::string inside of std::array<std::string, N> at index 'index' to size 'length'.
521  */
522 template <size_t N>
523 static inline bool AParcel_stdArrayStringElementAllocator(void* arrData, size_t index,
524                                                           int32_t length, char** buffer) {
525     std::array<std::string, N>* arr = static_cast<std::array<std::string, N>*>(arrData);
526     std::string& element = arr->at(index);
527     return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
528 }
529 
530 /**
531  * This gets the length and buffer of a std::string inside of a std::array<std::string, N> at index
532  * 'index'.
533  */
534 template <size_t N>
535 static const char* AParcel_stdArrayStringElementGetter(const void* arrData, size_t index,
536                                                        int32_t* outLength) {
537     const std::array<std::string, N>* arr = static_cast<const std::array<std::string, N>*>(arrData);
538     const std::string& element = arr->at(index);
539 
540     *outLength = static_cast<int32_t>(element.size());
541     return element.c_str();
542 }
543 
544 /**
545  * Allocates a std::string inside of std::array<std::optional<std::string>, N> at index 'index' to
546  * size 'length'.
547  */
548 template <size_t N>
549 static inline bool AParcel_stdArrayNullableStringElementAllocator(void* arrData, size_t index,
550                                                                   int32_t length, char** buffer) {
551     std::array<std::optional<std::string>, N>* arr =
552             static_cast<std::array<std::optional<std::string>, N>*>(arrData);
553     std::optional<std::string>& element = arr->at(index);
554     return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
555 }
556 
557 /**
558  * This gets the length and buffer of a std::string inside of a
559  * std::array<std::optional<std::string>, N> at index 'index'.
560  */
561 template <size_t N>
562 static const char* AParcel_stdArrayNullableStringElementGetter(const void* arrData, size_t index,
563                                                                int32_t* outLength) {
564     const std::array<std::optional<std::string>, N>* arr =
565             static_cast<const std::array<std::optional<std::string>, N>*>(arrData);
566     const std::optional<std::string>& element = arr->at(index);
567 
568     if (!element) {
569         *outLength = -1;
570         return nullptr;
571     }
572 
573     *outLength = static_cast<int32_t>(element->size());
574     return element->c_str();
575 }
576 
577 /**
578  * Allocates a std::string inside of std::optional<std::array<std::optional<std::string>, N>> at
579  * index 'index' to size 'length'.
580  */
581 template <size_t N>
582 static inline bool AParcel_nullableStdArrayStringElementAllocator(void* arrData, size_t index,
583                                                                   int32_t length, char** buffer) {
584     std::optional<std::array<std::optional<std::string>, N>>* arr =
585             static_cast<std::optional<std::array<std::optional<std::string>, N>>*>(arrData);
586     std::optional<std::string>& element = (*arr)->at(index);
587     return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
588 }
589 
590 /**
591  * Convenience API for writing a std::string.
592  */
593 static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
594     return AParcel_writeString(parcel, str.c_str(), static_cast<int32_t>(str.size()));
595 }
596 
597 /**
598  * Convenience API for reading a std::string.
599  */
600 static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
601     void* stringData = static_cast<void*>(str);
602     return AParcel_readString(parcel, stringData, AParcel_stdStringAllocator);
603 }
604 
605 /**
606  * Convenience API for writing a std::optional<std::string>.
607  */
608 static inline binder_status_t AParcel_writeString(AParcel* parcel,
609                                                   const std::optional<std::string>& str) {
610     if (!str) {
611         return AParcel_writeString(parcel, nullptr, -1);
612     }
613 
614     return AParcel_writeString(parcel, str->c_str(), static_cast<int32_t>(str->size()));
615 }
616 
617 /**
618  * Convenience API for reading a std::optional<std::string>.
619  */
620 static inline binder_status_t AParcel_readString(const AParcel* parcel,
621                                                  std::optional<std::string>* str) {
622     void* stringData = static_cast<void*>(str);
623     return AParcel_readString(parcel, stringData, AParcel_nullableStdStringAllocator);
624 }
625 
626 /**
627  * Convenience API for writing a std::vector<std::string>
628  */
629 static inline binder_status_t AParcel_writeVector(AParcel* parcel,
630                                                   const std::vector<std::string>& vec) {
631     const void* vectorData = static_cast<const void*>(&vec);
632     return AParcel_writeStringArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
633                                     AParcel_stdVectorStringElementGetter);
634 }
635 
636 /**
637  * Convenience API for reading a std::vector<std::string>
638  */
639 static inline binder_status_t AParcel_readVector(const AParcel* parcel,
640                                                  std::vector<std::string>* vec) {
641     void* vectorData = static_cast<void*>(vec);
642     return AParcel_readStringArray(parcel, vectorData,
643                                    AParcel_stdVectorExternalAllocator<std::string>,
644                                    AParcel_stdVectorStringElementAllocator);
645 }
646 
647 /**
648  * Convenience API for writing a std::optional<std::vector<std::optional<std::string>>>
649  */
650 static inline binder_status_t AParcel_writeVector(
651         AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) {
652     const void* vectorData = static_cast<const void*>(&vec);
653     return AParcel_writeStringArray(parcel, vectorData,
654                                     (vec ? static_cast<int32_t>(vec->size()) : -1),
655                                     AParcel_nullableStdVectorStringElementGetter);
656 }
657 
658 /**
659  * Convenience API for reading a std::optional<std::vector<std::optional<std::string>>>
660  */
661 static inline binder_status_t AParcel_readVector(
662         const AParcel* parcel, std::optional<std::vector<std::optional<std::string>>>* vec) {
663     void* vectorData = static_cast<void*>(vec);
664     return AParcel_readStringArray(
665             parcel, vectorData,
666             AParcel_nullableStdVectorExternalAllocator<std::optional<std::string>>,
667             AParcel_nullableStdVectorStringElementAllocator);
668 }
669 
670 /**
671  * Convenience API for writing a non-null parcelable.
672  */
673 template <typename P>
674 static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) {
675     if constexpr (is_interface_v<P>) {
676         // Legacy behavior: allow null
677         return first_template_type_t<P>::writeToParcel(parcel, p);
678     } else {
679         static_assert(is_parcelable_v<P>);
680         binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
681         if (status != STATUS_OK) {
682             return status;
683         }
684         return p.writeToParcel(parcel);
685     }
686 }
687 
688 /**
689  * Convenience API for reading a non-null parcelable.
690  */
691 template <typename P>
692 static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) {
693     if constexpr (is_interface_v<P>) {
694         // Legacy behavior: allow null
695         return first_template_type_t<P>::readFromParcel(parcel, p);
696     } else {
697         static_assert(is_parcelable_v<P>);
698         int32_t null;
699         binder_status_t status = AParcel_readInt32(parcel, &null);
700         if (status != STATUS_OK) {
701             return status;
702         }
703         if (null == 0) {
704             return STATUS_UNEXPECTED_NULL;
705         }
706         return p->readFromParcel(parcel);
707     }
708 }
709 
710 /**
711  * Convenience API for writing a nullable parcelable.
712  */
713 template <typename P>
714 static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel, const P& p) {
715     if constexpr (is_interface_v<P>) {
716         return first_template_type_t<P>::writeToParcel(parcel, p);
717     } else {
718         static_assert(is_nullable_parcelable_v<P>);
719         if (!p) {
720             return AParcel_writeInt32(parcel, 0);  // null
721         }
722         binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
723         if (status != STATUS_OK) {
724             return status;
725         }
726         return p->writeToParcel(parcel);
727     }
728 }
729 
730 /**
731  * Convenience API for reading a nullable parcelable.
732  */
733 template <typename P>
734 static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel, P* p) {
735     if constexpr (is_interface_v<P>) {
736         return first_template_type_t<P>::readFromParcel(parcel, p);
737     } else if constexpr (is_specialization_v<P, std::optional>) {
738         int32_t null;
739         binder_status_t status = AParcel_readInt32(parcel, &null);
740         if (status != STATUS_OK) {
741             return status;
742         }
743         if (null == 0) {
744             *p = std::nullopt;
745             return STATUS_OK;
746         }
747         p->emplace(first_template_type_t<P>());
748         return (*p)->readFromParcel(parcel);
749     } else {
750         static_assert(is_specialization_v<P, std::unique_ptr>);
751         int32_t null;
752         binder_status_t status = AParcel_readInt32(parcel, &null);
753         if (status != STATUS_OK) {
754             return status;
755         }
756         if (null == 0) {
757             p->reset();
758             return STATUS_OK;
759         }
760         *p = std::make_unique<first_template_type_t<P>>();
761         return (*p)->readFromParcel(parcel);
762     }
763 }
764 
765 // Forward decls
766 template <typename T>
767 static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value);
768 template <typename T>
769 static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value);
770 template <typename T>
771 static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value);
772 template <typename T>
773 static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value);
774 
775 /**
776  * Reads an object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
777  */
778 template <typename T, size_t N>
779 binder_status_t AParcel_readStdArrayData(const AParcel* parcel, void* arrayData, size_t index) {
780     std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
781     return AParcel_readData(parcel, &arr->at(index));
782 }
783 
784 /**
785  * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
786  */
787 template <typename T, size_t N>
788 binder_status_t AParcel_readStdArrayNullableData(const AParcel* parcel, void* arrayData,
789                                                  size_t index) {
790     std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData);
791     return AParcel_readNullableData(parcel, &arr->at(index));
792 }
793 
794 /**
795  * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'.
796  */
797 template <typename T, size_t N>
798 binder_status_t AParcel_readNullableStdArrayNullableData(const AParcel* parcel, void* arrayData,
799                                                          size_t index) {
800     std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData);
801     return AParcel_readNullableData(parcel, &(*arr)->at(index));
802 }
803 
804 /**
805  * Writes an object of type T inside a std::array<T, N> at index 'index' to 'parcel'.
806  */
807 template <typename T, size_t N>
808 binder_status_t AParcel_writeStdArrayData(AParcel* parcel, const void* arrayData, size_t index) {
809     const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData);
810     return AParcel_writeData(parcel, arr->at(index));
811 }
812 
813 /**
814  * Writes a nullable object of type T inside a std::array<T, N> at index 'index' to 'parcel'.
815  */
816 template <typename T, size_t N>
817 binder_status_t AParcel_writeStdArrayNullableData(AParcel* parcel, const void* arrayData,
818                                                   size_t index) {
819     const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData);
820     return AParcel_writeNullableData(parcel, arr->at(index));
821 }
822 
823 /**
824  * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
825  */
826 template <typename P>
827 binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData,
828                                                         size_t index) {
829     const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData);
830     return AParcel_writeParcelable(parcel, vector->at(index));
831 }
832 
833 /**
834  * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
835  */
836 template <typename P>
837 binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData,
838                                                        size_t index) {
839     std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData);
840     return AParcel_readParcelable(parcel, &vector->at(index));
841 }
842 
843 /**
844  * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
845  */
846 template <typename P>
847 binder_status_t AParcel_writeNullableStdVectorParcelableElement(AParcel* parcel,
848                                                                 const void* vectorData,
849                                                                 size_t index) {
850     const std::optional<std::vector<P>>* vector =
851             static_cast<const std::optional<std::vector<P>>*>(vectorData);
852     return AParcel_writeNullableParcelable(parcel, (*vector)->at(index));
853 }
854 
855 /**
856  * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
857  */
858 template <typename P>
859 binder_status_t AParcel_readNullableStdVectorParcelableElement(const AParcel* parcel,
860                                                                void* vectorData, size_t index) {
861     std::optional<std::vector<P>>* vector = static_cast<std::optional<std::vector<P>>*>(vectorData);
862     return AParcel_readNullableParcelable(parcel, &(*vector)->at(index));
863 }
864 
865 /**
866  * Writes a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index'
867  * to 'parcel'.
868  */
869 template <>
870 inline binder_status_t AParcel_writeStdVectorParcelableElement<ScopedFileDescriptor>(
871         AParcel* parcel, const void* vectorData, size_t index) {
872     const std::vector<ScopedFileDescriptor>* vector =
873             static_cast<const std::vector<ScopedFileDescriptor>*>(vectorData);
874     return AParcel_writeRequiredParcelFileDescriptor(parcel, vector->at(index));
875 }
876 
877 /**
878  * Reads a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index'
879  * from 'parcel'.
880  */
881 template <>
882 inline binder_status_t AParcel_readStdVectorParcelableElement<ScopedFileDescriptor>(
883         const AParcel* parcel, void* vectorData, size_t index) {
884     std::vector<ScopedFileDescriptor>* vector =
885             static_cast<std::vector<ScopedFileDescriptor>*>(vectorData);
886     return AParcel_readRequiredParcelFileDescriptor(parcel, &vector->at(index));
887 }
888 
889 /**
890  * Writes a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
891  * index 'index' to 'parcel'.
892  */
893 template <>
894 inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<ScopedFileDescriptor>(
895         AParcel* parcel, const void* vectorData, size_t index) {
896     const std::optional<std::vector<ScopedFileDescriptor>>* vector =
897             static_cast<const std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
898     return AParcel_writeNullableParcelFileDescriptor(parcel, (*vector)->at(index));
899 }
900 
901 /**
902  * Reads a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
903  * index 'index' from 'parcel'.
904  */
905 template <>
906 inline binder_status_t AParcel_readNullableStdVectorParcelableElement<ScopedFileDescriptor>(
907         const AParcel* parcel, void* vectorData, size_t index) {
908     std::optional<std::vector<ScopedFileDescriptor>>* vector =
909             static_cast<std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
910     return AParcel_readNullableParcelFileDescriptor(parcel, &(*vector)->at(index));
911 }
912 
913 /**
914  * Writes an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
915  * to 'parcel'.
916  */
917 template <>
918 inline binder_status_t AParcel_writeStdVectorParcelableElement<SpAIBinder>(AParcel* parcel,
919                                                                            const void* vectorData,
920                                                                            size_t index) {
921     const std::vector<SpAIBinder>* vector = static_cast<const std::vector<SpAIBinder>*>(vectorData);
922     return AParcel_writeRequiredStrongBinder(parcel, vector->at(index));
923 }
924 
925 /**
926  * Reads an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
927  * from 'parcel'.
928  */
929 template <>
930 inline binder_status_t AParcel_readStdVectorParcelableElement<SpAIBinder>(const AParcel* parcel,
931                                                                           void* vectorData,
932                                                                           size_t index) {
933     std::vector<SpAIBinder>* vector = static_cast<std::vector<SpAIBinder>*>(vectorData);
934     return AParcel_readRequiredStrongBinder(parcel, &vector->at(index));
935 }
936 
937 /**
938  * Writes an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
939  * to 'parcel'.
940  */
941 template <>
942 inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<SpAIBinder>(
943         AParcel* parcel, const void* vectorData, size_t index) {
944     const std::optional<std::vector<SpAIBinder>>* vector =
945             static_cast<const std::optional<std::vector<SpAIBinder>>*>(vectorData);
946     return AParcel_writeNullableStrongBinder(parcel, (*vector)->at(index));
947 }
948 
949 /**
950  * Reads an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
951  * from 'parcel'.
952  */
953 template <>
954 inline binder_status_t AParcel_readNullableStdVectorParcelableElement<SpAIBinder>(
955         const AParcel* parcel, void* vectorData, size_t index) {
956     std::optional<std::vector<SpAIBinder>>* vector =
957             static_cast<std::optional<std::vector<SpAIBinder>>*>(vectorData);
958     return AParcel_readNullableStrongBinder(parcel, &(*vector)->at(index));
959 }
960 
961 /**
962  * Convenience API for writing a std::vector<P>
963  */
964 template <typename P>
965 static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
966     if constexpr (std::is_enum_v<P>) {
967         if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
968             return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()),
969                                           static_cast<int32_t>(vec.size()));
970         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
971             return AParcel_writeInt32Array(parcel, reinterpret_cast<const int32_t*>(vec.data()),
972                                            static_cast<int32_t>(vec.size()));
973         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
974             return AParcel_writeInt64Array(parcel, reinterpret_cast<const int64_t*>(vec.data()),
975                                            static_cast<int32_t>(vec.size()));
976         } else {
977             static_assert(dependent_false_v<P>, "unrecognized type");
978         }
979     } else {
980         static_assert(!std::is_same_v<P, std::string>, "specialization should be used");
981         const void* vectorData = static_cast<const void*>(&vec);
982         return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
983                                             AParcel_writeStdVectorParcelableElement<P>);
984     }
985 }
986 
987 /**
988  * Convenience API for reading a std::vector<P>
989  */
990 template <typename P>
991 static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) {
992     if constexpr (std::is_enum_v<P>) {
993         void* vectorData = static_cast<void*>(vec);
994         if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
995             return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
996         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
997             return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
998         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
999             return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
1000         } else {
1001             static_assert(dependent_false_v<P>, "unrecognized type");
1002         }
1003     } else {
1004         static_assert(!std::is_same_v<P, std::string>, "specialization should be used");
1005         void* vectorData = static_cast<void*>(vec);
1006         return AParcel_readParcelableArray(parcel, vectorData,
1007                                            AParcel_stdVectorExternalAllocator<P>,
1008                                            AParcel_readStdVectorParcelableElement<P>);
1009     }
1010 }
1011 
1012 /**
1013  * Convenience API for writing a std::optional<std::vector<P>>
1014  */
1015 template <typename P>
1016 static inline binder_status_t AParcel_writeVector(AParcel* parcel,
1017                                                   const std::optional<std::vector<P>>& vec) {
1018     if constexpr (std::is_enum_v<P>) {
1019         if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
1020             return AParcel_writeByteArray(
1021                     parcel, vec ? reinterpret_cast<const int8_t*>(vec->data()) : nullptr,
1022                     vec ? static_cast<int32_t>(vec->size()) : -1);
1023         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
1024             return AParcel_writeInt32Array(
1025                     parcel, vec ? reinterpret_cast<const int32_t*>(vec->data()) : nullptr,
1026                     vec ? static_cast<int32_t>(vec->size()) : -1);
1027         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
1028             return AParcel_writeInt64Array(
1029                     parcel, vec ? reinterpret_cast<const int64_t*>(vec->data()) : nullptr,
1030                     vec ? static_cast<int32_t>(vec->size()) : -1);
1031         } else {
1032             static_assert(dependent_false_v<P>, "unrecognized type");
1033         }
1034     } else {
1035         static_assert(!std::is_same_v<P, std::optional<std::string>>,
1036                       "specialization should be used");
1037         if (!vec) return AParcel_writeInt32(parcel, -1);
1038         const void* vectorData = static_cast<const void*>(&vec);
1039         return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec->size()),
1040                                             AParcel_writeNullableStdVectorParcelableElement<P>);
1041     }
1042 }
1043 
1044 /**
1045  * Convenience API for reading a std::optional<std::vector<P>>
1046  */
1047 template <typename P>
1048 static inline binder_status_t AParcel_readVector(const AParcel* parcel,
1049                                                  std::optional<std::vector<P>>* vec) {
1050     if constexpr (std::is_enum_v<P>) {
1051         void* vectorData = static_cast<void*>(vec);
1052         if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) {
1053             return AParcel_readByteArray(parcel, vectorData,
1054                                          AParcel_nullableStdVectorAllocator<int8_t>);
1055         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) {
1056             return AParcel_readInt32Array(parcel, vectorData,
1057                                           AParcel_nullableStdVectorAllocator<int32_t>);
1058         } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) {
1059             return AParcel_readInt64Array(parcel, vectorData,
1060                                           AParcel_nullableStdVectorAllocator<int64_t>);
1061         } else {
1062             static_assert(dependent_false_v<P>, "unrecognized type");
1063         }
1064     } else {
1065         static_assert(!std::is_same_v<P, std::optional<std::string>>,
1066                       "specialization should be used");
1067         void* vectorData = static_cast<void*>(vec);
1068         return AParcel_readParcelableArray(parcel, vectorData,
1069                                            AParcel_nullableStdVectorExternalAllocator<P>,
1070                                            AParcel_readNullableStdVectorParcelableElement<P>);
1071     }
1072 }
1073 
1074 // @START
1075 /**
1076  * Writes a vector of int32_t to the next location in a non-null parcel.
1077  */
1078 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
1079     return AParcel_writeInt32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
1080 }
1081 
1082 /**
1083  * Writes an optional vector of int32_t to the next location in a non-null parcel.
1084  */
1085 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1086                                            const std::optional<std::vector<int32_t>>& vec) {
1087     if (!vec) return AParcel_writeInt32Array(parcel, nullptr, -1);
1088     return AParcel_writeVector(parcel, *vec);
1089 }
1090 
1091 /**
1092  * Reads a vector of int32_t from the next location in a non-null parcel.
1093  */
1094 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
1095     void* vectorData = static_cast<void*>(vec);
1096     return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
1097 }
1098 
1099 /**
1100  * Reads an optional vector of int32_t from the next location in a non-null parcel.
1101  */
1102 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1103                                           std::optional<std::vector<int32_t>>* vec) {
1104     void* vectorData = static_cast<void*>(vec);
1105     return AParcel_readInt32Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int32_t>);
1106 }
1107 
1108 /**
1109  * Writes a vector of uint32_t to the next location in a non-null parcel.
1110  */
1111 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
1112     return AParcel_writeUint32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
1113 }
1114 
1115 /**
1116  * Writes an optional vector of uint32_t to the next location in a non-null parcel.
1117  */
1118 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1119                                            const std::optional<std::vector<uint32_t>>& vec) {
1120     if (!vec) return AParcel_writeUint32Array(parcel, nullptr, -1);
1121     return AParcel_writeVector(parcel, *vec);
1122 }
1123 
1124 /**
1125  * Reads a vector of uint32_t from the next location in a non-null parcel.
1126  */
1127 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
1128     void* vectorData = static_cast<void*>(vec);
1129     return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>);
1130 }
1131 
1132 /**
1133  * Reads an optional vector of uint32_t from the next location in a non-null parcel.
1134  */
1135 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1136                                           std::optional<std::vector<uint32_t>>* vec) {
1137     void* vectorData = static_cast<void*>(vec);
1138     return AParcel_readUint32Array(parcel, vectorData,
1139                                    AParcel_nullableStdVectorAllocator<uint32_t>);
1140 }
1141 
1142 /**
1143  * Writes a vector of int64_t to the next location in a non-null parcel.
1144  */
1145 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
1146     return AParcel_writeInt64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
1147 }
1148 
1149 /**
1150  * Writes an optional vector of int64_t to the next location in a non-null parcel.
1151  */
1152 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1153                                            const std::optional<std::vector<int64_t>>& vec) {
1154     if (!vec) return AParcel_writeInt64Array(parcel, nullptr, -1);
1155     return AParcel_writeVector(parcel, *vec);
1156 }
1157 
1158 /**
1159  * Reads a vector of int64_t from the next location in a non-null parcel.
1160  */
1161 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
1162     void* vectorData = static_cast<void*>(vec);
1163     return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
1164 }
1165 
1166 /**
1167  * Reads an optional vector of int64_t from the next location in a non-null parcel.
1168  */
1169 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1170                                           std::optional<std::vector<int64_t>>* vec) {
1171     void* vectorData = static_cast<void*>(vec);
1172     return AParcel_readInt64Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int64_t>);
1173 }
1174 
1175 /**
1176  * Writes a vector of uint64_t to the next location in a non-null parcel.
1177  */
1178 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
1179     return AParcel_writeUint64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
1180 }
1181 
1182 /**
1183  * Writes an optional vector of uint64_t to the next location in a non-null parcel.
1184  */
1185 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1186                                            const std::optional<std::vector<uint64_t>>& vec) {
1187     if (!vec) return AParcel_writeUint64Array(parcel, nullptr, -1);
1188     return AParcel_writeVector(parcel, *vec);
1189 }
1190 
1191 /**
1192  * Reads a vector of uint64_t from the next location in a non-null parcel.
1193  */
1194 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
1195     void* vectorData = static_cast<void*>(vec);
1196     return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>);
1197 }
1198 
1199 /**
1200  * Reads an optional vector of uint64_t from the next location in a non-null parcel.
1201  */
1202 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1203                                           std::optional<std::vector<uint64_t>>* vec) {
1204     void* vectorData = static_cast<void*>(vec);
1205     return AParcel_readUint64Array(parcel, vectorData,
1206                                    AParcel_nullableStdVectorAllocator<uint64_t>);
1207 }
1208 
1209 /**
1210  * Writes a vector of float to the next location in a non-null parcel.
1211  */
1212 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
1213     return AParcel_writeFloatArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
1214 }
1215 
1216 /**
1217  * Writes an optional vector of float to the next location in a non-null parcel.
1218  */
1219 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1220                                            const std::optional<std::vector<float>>& vec) {
1221     if (!vec) return AParcel_writeFloatArray(parcel, nullptr, -1);
1222     return AParcel_writeVector(parcel, *vec);
1223 }
1224 
1225 /**
1226  * Reads a vector of float from the next location in a non-null parcel.
1227  */
1228 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
1229     void* vectorData = static_cast<void*>(vec);
1230     return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>);
1231 }
1232 
1233 /**
1234  * Reads an optional vector of float from the next location in a non-null parcel.
1235  */
1236 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1237                                           std::optional<std::vector<float>>* vec) {
1238     void* vectorData = static_cast<void*>(vec);
1239     return AParcel_readFloatArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<float>);
1240 }
1241 
1242 /**
1243  * Writes a vector of double to the next location in a non-null parcel.
1244  */
1245 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
1246     return AParcel_writeDoubleArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
1247 }
1248 
1249 /**
1250  * Writes an optional vector of double to the next location in a non-null parcel.
1251  */
1252 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1253                                            const std::optional<std::vector<double>>& vec) {
1254     if (!vec) return AParcel_writeDoubleArray(parcel, nullptr, -1);
1255     return AParcel_writeVector(parcel, *vec);
1256 }
1257 
1258 /**
1259  * Reads a vector of double from the next location in a non-null parcel.
1260  */
1261 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
1262     void* vectorData = static_cast<void*>(vec);
1263     return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>);
1264 }
1265 
1266 /**
1267  * Reads an optional vector of double from the next location in a non-null parcel.
1268  */
1269 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1270                                           std::optional<std::vector<double>>* vec) {
1271     void* vectorData = static_cast<void*>(vec);
1272     return AParcel_readDoubleArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<double>);
1273 }
1274 
1275 /**
1276  * Writes a vector of bool to the next location in a non-null parcel.
1277  */
1278 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
1279     return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
1280                                   static_cast<int32_t>(vec.size()), AParcel_stdVectorGetter<bool>);
1281 }
1282 
1283 /**
1284  * Writes an optional vector of bool to the next location in a non-null parcel.
1285  */
1286 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1287                                            const std::optional<std::vector<bool>>& vec) {
1288     if (!vec) return AParcel_writeBoolArray(parcel, nullptr, -1, AParcel_stdVectorGetter<bool>);
1289     return AParcel_writeVector(parcel, *vec);
1290 }
1291 
1292 /**
1293  * Reads a vector of bool from the next location in a non-null parcel.
1294  */
1295 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
1296     void* vectorData = static_cast<void*>(vec);
1297     return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>,
1298                                  AParcel_stdVectorSetter<bool>);
1299 }
1300 
1301 /**
1302  * Reads an optional vector of bool from the next location in a non-null parcel.
1303  */
1304 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1305                                           std::optional<std::vector<bool>>* vec) {
1306     void* vectorData = static_cast<void*>(vec);
1307     return AParcel_readBoolArray(parcel, vectorData,
1308                                  AParcel_nullableStdVectorExternalAllocator<bool>,
1309                                  AParcel_nullableStdVectorSetter<bool>);
1310 }
1311 
1312 /**
1313  * Writes a vector of char16_t to the next location in a non-null parcel.
1314  */
1315 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
1316     return AParcel_writeCharArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
1317 }
1318 
1319 /**
1320  * Writes an optional vector of char16_t to the next location in a non-null parcel.
1321  */
1322 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1323                                            const std::optional<std::vector<char16_t>>& vec) {
1324     if (!vec) return AParcel_writeCharArray(parcel, nullptr, -1);
1325     return AParcel_writeVector(parcel, *vec);
1326 }
1327 
1328 /**
1329  * Reads a vector of char16_t from the next location in a non-null parcel.
1330  */
1331 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
1332     void* vectorData = static_cast<void*>(vec);
1333     return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>);
1334 }
1335 
1336 /**
1337  * Reads an optional vector of char16_t from the next location in a non-null parcel.
1338  */
1339 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1340                                           std::optional<std::vector<char16_t>>* vec) {
1341     void* vectorData = static_cast<void*>(vec);
1342     return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>);
1343 }
1344 
1345 /**
1346  * Writes a vector of uint8_t to the next location in a non-null parcel.
1347  */
1348 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint8_t>& vec) {
1349     return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()),
1350                                   static_cast<int32_t>(vec.size()));
1351 }
1352 
1353 /**
1354  * Writes an optional vector of uint8_t to the next location in a non-null parcel.
1355  */
1356 inline binder_status_t AParcel_writeVector(AParcel* parcel,
1357                                            const std::optional<std::vector<uint8_t>>& vec) {
1358     if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1);
1359     return AParcel_writeVector(parcel, *vec);
1360 }
1361 
1362 /**
1363  * Reads a vector of uint8_t from the next location in a non-null parcel.
1364  */
1365 inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint8_t>* vec) {
1366     void* vectorData = static_cast<void*>(vec);
1367     return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
1368 }
1369 
1370 /**
1371  * Reads an optional vector of uint8_t from the next location in a non-null parcel.
1372  */
1373 inline binder_status_t AParcel_readVector(const AParcel* parcel,
1374                                           std::optional<std::vector<uint8_t>>* vec) {
1375     void* vectorData = static_cast<void*>(vec);
1376     return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>);
1377 }
1378 
1379 // @END
1380 
1381 /**
1382  * Convenience API for writing the size of a vector.
1383  */
1384 template <typename T>
1385 static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) {
1386     if (vec.size() > INT32_MAX) {
1387         return STATUS_BAD_VALUE;
1388     }
1389 
1390     return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size()));
1391 }
1392 
1393 /**
1394  * Convenience API for writing the size of a vector.
1395  */
1396 template <typename T>
1397 static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel,
1398                                                       const std::optional<std::vector<T>>& vec) {
1399     if (!vec) {
1400         return AParcel_writeInt32(parcel, -1);
1401     }
1402 
1403     if (vec->size() > INT32_MAX) {
1404         return STATUS_BAD_VALUE;
1405     }
1406 
1407     return AParcel_writeInt32(parcel, static_cast<int32_t>(vec->size()));
1408 }
1409 
1410 /**
1411  * Convenience API for resizing a vector.
1412  */
1413 template <typename T>
1414 static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) {
1415     int32_t size;
1416     binder_status_t err = AParcel_readInt32(parcel, &size);
1417 
1418     if (err != STATUS_OK) return err;
1419     if (size < 0) return STATUS_UNEXPECTED_NULL;
1420 
1421     // TODO(b/188215728): delegate to libbinder_ndk
1422     if (size > 1000000) return STATUS_NO_MEMORY;
1423 
1424     vec->resize(static_cast<size_t>(size));
1425     return STATUS_OK;
1426 }
1427 
1428 /**
1429  * Convenience API for resizing a vector.
1430  */
1431 template <typename T>
1432 static inline binder_status_t AParcel_resizeVector(const AParcel* parcel,
1433                                                    std::optional<std::vector<T>>* vec) {
1434     int32_t size;
1435     binder_status_t err = AParcel_readInt32(parcel, &size);
1436 
1437     if (err != STATUS_OK) return err;
1438     if (size < -1) return STATUS_UNEXPECTED_NULL;
1439 
1440     if (size == -1) {
1441         *vec = std::nullopt;
1442         return STATUS_OK;
1443     }
1444 
1445     // TODO(b/188215728): delegate to libbinder_ndk
1446     if (size > 1000000) return STATUS_NO_MEMORY;
1447 
1448     *vec = std::optional<std::vector<T>>(std::vector<T>{});
1449     (*vec)->resize(static_cast<size_t>(size));
1450     return STATUS_OK;
1451 }
1452 
1453 /**
1454  * Writes a fixed-size array of T.
1455  */
1456 template <typename T, size_t N>
1457 static inline binder_status_t AParcel_writeFixedArray(AParcel* parcel,
1458                                                       const std::array<T, N>& arr) {
1459     if constexpr (std::is_same_v<T, bool>) {
1460         const void* arrayData = static_cast<const void*>(&arr);
1461         return AParcel_writeBoolArray(parcel, arrayData, static_cast<int32_t>(N),
1462                                       &AParcel_stdArrayGetter<T, N>);
1463     } else if constexpr (std::is_same_v<T, uint8_t>) {
1464         return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(arr.data()),
1465                                       static_cast<int32_t>(arr.size()));
1466     } else if constexpr (std::is_same_v<T, char16_t>) {
1467         return AParcel_writeCharArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
1468     } else if constexpr (std::is_same_v<T, int32_t>) {
1469         return AParcel_writeInt32Array(parcel, arr.data(), static_cast<int32_t>(arr.size()));
1470     } else if constexpr (std::is_same_v<T, int64_t>) {
1471         return AParcel_writeInt64Array(parcel, arr.data(), static_cast<int32_t>(arr.size()));
1472     } else if constexpr (std::is_same_v<T, float>) {
1473         return AParcel_writeFloatArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
1474     } else if constexpr (std::is_same_v<T, double>) {
1475         return AParcel_writeDoubleArray(parcel, arr.data(), static_cast<int32_t>(arr.size()));
1476     } else if constexpr (std::is_same_v<T, std::string>) {
1477         const void* arrayData = static_cast<const void*>(&arr);
1478         return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N),
1479                                         &AParcel_stdArrayStringElementGetter<N>);
1480     } else {
1481         const void* arrayData = static_cast<const void*>(&arr);
1482         return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N),
1483                                             &AParcel_writeStdArrayData<T, N>);
1484     }
1485 }
1486 
1487 /**
1488  * Writes a fixed-size array of T.
1489  */
1490 template <typename T, size_t N>
1491 static inline binder_status_t AParcel_writeFixedArrayWithNullableData(AParcel* parcel,
1492                                                                       const std::array<T, N>& arr) {
1493     if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> ||
1494                   std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> ||
1495                   std::is_same_v<T, int64_t> || std::is_same_v<T, float> ||
1496                   std::is_same_v<T, double> || std::is_same_v<T, std::string>) {
1497         return AParcel_writeFixedArray(parcel, arr);
1498     } else if constexpr (std::is_same_v<T, std::optional<std::string>>) {
1499         const void* arrayData = static_cast<const void*>(&arr);
1500         return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N),
1501                                         &AParcel_stdArrayNullableStringElementGetter<N>);
1502     } else {
1503         const void* arrayData = static_cast<const void*>(&arr);
1504         return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N),
1505                                             &AParcel_writeStdArrayNullableData<T, N>);
1506     }
1507 }
1508 
1509 /**
1510  * Writes a fixed-size array of T.
1511  */
1512 template <typename T, size_t N>
1513 static inline binder_status_t AParcel_writeNullableFixedArrayWithNullableData(
1514         AParcel* parcel, const std::optional<std::array<T, N>>& arr) {
1515     if (!arr) return AParcel_writeInt32(parcel, -1);
1516     return AParcel_writeFixedArrayWithNullableData(parcel, arr.value());
1517 }
1518 
1519 /**
1520  * Reads a fixed-size array of T.
1521  */
1522 template <typename T, size_t N>
1523 static inline binder_status_t AParcel_readFixedArray(const AParcel* parcel, std::array<T, N>* arr) {
1524     void* arrayData = static_cast<void*>(arr);
1525     if constexpr (std::is_same_v<T, bool>) {
1526         return AParcel_readBoolArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
1527                                      &AParcel_stdArraySetter<T, N>);
1528     } else if constexpr (std::is_same_v<T, uint8_t>) {
1529         return AParcel_readByteArray(parcel, arrayData, &AParcel_stdArrayAllocator<int8_t, N>);
1530     } else if constexpr (std::is_same_v<T, char16_t>) {
1531         return AParcel_readCharArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
1532     } else if constexpr (std::is_same_v<T, int32_t>) {
1533         return AParcel_readInt32Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
1534     } else if constexpr (std::is_same_v<T, int64_t>) {
1535         return AParcel_readInt64Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
1536     } else if constexpr (std::is_same_v<T, float>) {
1537         return AParcel_readFloatArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
1538     } else if constexpr (std::is_same_v<T, double>) {
1539         return AParcel_readDoubleArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>);
1540     } else if constexpr (std::is_same_v<T, std::string>) {
1541         return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
1542                                        &AParcel_stdArrayStringElementAllocator<N>);
1543     } else {
1544         return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
1545                                            &AParcel_readStdArrayData<T, N>);
1546     }
1547 }
1548 
1549 /**
1550  * Reads a fixed-size array of T.
1551  */
1552 template <typename T, size_t N>
1553 static inline binder_status_t AParcel_readFixedArrayWithNullableData(const AParcel* parcel,
1554                                                                      std::array<T, N>* arr) {
1555     void* arrayData = static_cast<void*>(arr);
1556     if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> ||
1557                   std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> ||
1558                   std::is_same_v<T, int64_t> || std::is_same_v<T, float> ||
1559                   std::is_same_v<T, double> || std::is_same_v<T, std::string>) {
1560         return AParcel_readFixedArray(parcel, arr);
1561     } else if constexpr (std::is_same_v<T, std::optional<std::string>>) {
1562         return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
1563                                        &AParcel_stdArrayNullableStringElementAllocator<N>);
1564     } else {
1565         return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>,
1566                                            &AParcel_readStdArrayNullableData<T, N>);
1567     }
1568 }
1569 
1570 /**
1571  * Reads a fixed-size array of T.
1572  */
1573 template <typename T, size_t N>
1574 static inline binder_status_t AParcel_readNullableFixedArrayWithNullableData(
1575         const AParcel* parcel, std::optional<std::array<T, N>>* arr) {
1576     void* arrayData = static_cast<void*>(arr);
1577     if constexpr (std::is_same_v<T, bool>) {
1578         return AParcel_readBoolArray(parcel, arrayData,
1579                                      &AParcel_nullableStdArrayExternalAllocator<T, N>,
1580                                      &AParcel_nullableStdArraySetter<T, N>);
1581     } else if constexpr (std::is_same_v<T, uint8_t>) {
1582         return AParcel_readByteArray(parcel, arrayData,
1583                                      &AParcel_nullableStdArrayAllocator<int8_t, N>);
1584     } else if constexpr (std::is_same_v<T, char16_t>) {
1585         return AParcel_readCharArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
1586     } else if constexpr (std::is_same_v<T, int32_t>) {
1587         return AParcel_readInt32Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
1588     } else if constexpr (std::is_same_v<T, int64_t>) {
1589         return AParcel_readInt64Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
1590     } else if constexpr (std::is_same_v<T, float>) {
1591         return AParcel_readFloatArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
1592     } else if constexpr (std::is_same_v<T, double>) {
1593         return AParcel_readDoubleArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>);
1594     } else if constexpr (std::is_same_v<T, std::string>) {
1595         return AParcel_readStringArray(parcel, arrayData,
1596                                        &AParcel_nullableStdArrayExternalAllocator<N>,
1597                                        &AParcel_nullableStdArrayStringElementAllocator<N>);
1598     } else {
1599         return AParcel_readParcelableArray(parcel, arrayData,
1600                                            &AParcel_nullableStdArrayExternalAllocator<T, N>,
1601                                            &AParcel_readStdArrayNullableData<T, N>);
1602     }
1603 }
1604 
1605 /**
1606  * Convenience API for writing a value of any type.
1607  */
1608 template <typename T>
1609 static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value) {
1610     if constexpr (is_specialization_v<T, std::vector>) {
1611         return AParcel_writeVector(parcel, value);
1612     } else if constexpr (is_fixed_array_v<T>) {
1613         return AParcel_writeFixedArray(parcel, value);
1614     } else if constexpr (std::is_same_v<std::string, T>) {
1615         return AParcel_writeString(parcel, value);
1616     } else if constexpr (std::is_same_v<bool, T>) {
1617         return AParcel_writeBool(parcel, value);
1618     } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) {
1619         return AParcel_writeByte(parcel, value);
1620     } else if constexpr (std::is_same_v<char16_t, T>) {
1621         return AParcel_writeChar(parcel, value);
1622     } else if constexpr (std::is_same_v<int32_t, T>) {
1623         return AParcel_writeInt32(parcel, value);
1624     } else if constexpr (std::is_same_v<int64_t, T>) {
1625         return AParcel_writeInt64(parcel, value);
1626     } else if constexpr (std::is_same_v<float, T>) {
1627         return AParcel_writeFloat(parcel, value);
1628     } else if constexpr (std::is_same_v<double, T>) {
1629         return AParcel_writeDouble(parcel, value);
1630     } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
1631         return AParcel_writeRequiredParcelFileDescriptor(parcel, value);
1632     } else if constexpr (std::is_same_v<SpAIBinder, T>) {
1633         return AParcel_writeRequiredStrongBinder(parcel, value);
1634     } else if constexpr (std::is_enum_v<T>) {
1635         return AParcel_writeData(parcel, static_cast<std::underlying_type_t<T>>(value));
1636     } else if constexpr (is_interface_v<T>) {
1637         return AParcel_writeParcelable(parcel, value);
1638     } else if constexpr (is_parcelable_v<T>) {
1639         return AParcel_writeParcelable(parcel, value);
1640     } else {
1641         static_assert(dependent_false_v<T>, "unrecognized type");
1642     }
1643 }
1644 
1645 /**
1646  * Convenience API for writing a nullable value of any type.
1647  */
1648 template <typename T>
1649 static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value) {
1650     if constexpr (is_specialization_v<T, std::optional> &&
1651                   is_specialization_v<first_template_type_t<T>, std::vector>) {
1652         return AParcel_writeVector(parcel, value);
1653     } else if constexpr (is_specialization_v<T, std::optional> &&
1654                          is_fixed_array_v<first_template_type_t<T>>) {
1655         return AParcel_writeNullableFixedArrayWithNullableData(parcel, value);
1656     } else if constexpr (is_fixed_array_v<T>) {  // happens with a nullable multi-dimensional array.
1657         return AParcel_writeFixedArrayWithNullableData(parcel, value);
1658     } else if constexpr (is_specialization_v<T, std::optional> &&
1659                          std::is_same_v<first_template_type_t<T>, std::string>) {
1660         return AParcel_writeString(parcel, value);
1661     } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) {
1662         return AParcel_writeNullableParcelable(parcel, value);
1663     } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
1664         return AParcel_writeNullableParcelFileDescriptor(parcel, value);
1665     } else if constexpr (std::is_same_v<SpAIBinder, T>) {
1666         return AParcel_writeNullableStrongBinder(parcel, value);
1667     } else {
1668         return AParcel_writeData(parcel, value);
1669     }
1670 }
1671 
1672 /**
1673  * Convenience API for reading a value of any type.
1674  */
1675 template <typename T>
1676 static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value) {
1677     if constexpr (is_specialization_v<T, std::vector>) {
1678         return AParcel_readVector(parcel, value);
1679     } else if constexpr (is_fixed_array_v<T>) {
1680         return AParcel_readFixedArray(parcel, value);
1681     } else if constexpr (std::is_same_v<std::string, T>) {
1682         return AParcel_readString(parcel, value);
1683     } else if constexpr (std::is_same_v<bool, T>) {
1684         return AParcel_readBool(parcel, value);
1685     } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) {
1686         return AParcel_readByte(parcel, value);
1687     } else if constexpr (std::is_same_v<char16_t, T>) {
1688         return AParcel_readChar(parcel, value);
1689     } else if constexpr (std::is_same_v<int32_t, T>) {
1690         return AParcel_readInt32(parcel, value);
1691     } else if constexpr (std::is_same_v<int64_t, T>) {
1692         return AParcel_readInt64(parcel, value);
1693     } else if constexpr (std::is_same_v<float, T>) {
1694         return AParcel_readFloat(parcel, value);
1695     } else if constexpr (std::is_same_v<double, T>) {
1696         return AParcel_readDouble(parcel, value);
1697     } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
1698         return AParcel_readRequiredParcelFileDescriptor(parcel, value);
1699     } else if constexpr (std::is_same_v<SpAIBinder, T>) {
1700         return AParcel_readRequiredStrongBinder(parcel, value);
1701     } else if constexpr (std::is_enum_v<T>) {
1702         return AParcel_readData(parcel, reinterpret_cast<std::underlying_type_t<T>*>(value));
1703     } else if constexpr (is_interface_v<T>) {
1704         return AParcel_readParcelable(parcel, value);
1705     } else if constexpr (is_parcelable_v<T>) {
1706         return AParcel_readParcelable(parcel, value);
1707     } else {
1708         static_assert(dependent_false_v<T>, "unrecognized type");
1709     }
1710 }
1711 
1712 /**
1713  * Convenience API for reading a nullable value of any type.
1714  */
1715 template <typename T>
1716 static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value) {
1717     if constexpr (is_specialization_v<T, std::optional> &&
1718                   is_specialization_v<first_template_type_t<T>, std::vector>) {
1719         return AParcel_readVector(parcel, value);
1720     } else if constexpr (is_specialization_v<T, std::optional> &&
1721                          is_fixed_array_v<first_template_type_t<T>>) {
1722         return AParcel_readNullableFixedArrayWithNullableData(parcel, value);
1723     } else if constexpr (is_fixed_array_v<T>) {  // happens with a nullable multi-dimensional array.
1724         return AParcel_readFixedArrayWithNullableData(parcel, value);
1725     } else if constexpr (is_specialization_v<T, std::optional> &&
1726                          std::is_same_v<first_template_type_t<T>, std::string>) {
1727         return AParcel_readString(parcel, value);
1728     } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) {
1729         return AParcel_readNullableParcelable(parcel, value);
1730     } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) {
1731         return AParcel_readNullableParcelFileDescriptor(parcel, value);
1732     } else if constexpr (std::is_same_v<SpAIBinder, T>) {
1733         return AParcel_readNullableStrongBinder(parcel, value);
1734     } else {
1735         return AParcel_readData(parcel, value);
1736     }
1737 }
1738 
1739 }  // namespace ndk
1740 
1741 /** @} */
1742