• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #define LOG_TAG "Gralloc5"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 
20 #include <ui/Gralloc5.h>
21 
22 #include <aidl/android/hardware/graphics/allocator/AllocationError.h>
23 #include <aidlcommonsupport/NativeHandle.h>
24 #include <android/binder_manager.h>
25 #include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
26 #include <android/llndk-versioning.h>
27 #include <binder/IPCThreadState.h>
28 #include <dlfcn.h>
29 #include <ui/FatVector.h>
30 #include <vndksupport/linker.h>
31 
32 using namespace aidl::android::hardware::graphics::allocator;
33 using namespace aidl::android::hardware::graphics::common;
34 using namespace ::android::hardware::graphics::mapper;
35 
36 using ADataspace = aidl::android::hardware::graphics::common::Dataspace;
37 using APixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
38 
39 namespace android {
40 
41 static const auto kIAllocatorServiceName = IAllocator::descriptor + std::string("/default");
42 static const auto kIAllocatorMinimumVersion = 2;
43 constexpr const char* kStandardMetadataName =
44         "android.hardware.graphics.common.StandardMetadataType";
45 
46 // TODO(b/72323293, b/72703005): Remove these invalid bits from callers
47 static constexpr uint64_t kRemovedUsageBits = static_cast<uint64_t>((1 << 10) | (1 << 13));
48 
49 typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper *_Nullable *_Nonnull outImplementation);
50 
51 struct Gralloc5 {
52     std::shared_ptr<IAllocator> allocator;
53     AIMapper *mapper = nullptr;
54 };
55 
waitForAllocator()56 static std::shared_ptr<IAllocator> waitForAllocator() {
57     if (__builtin_available(android 31, *)) {
58         if (!AServiceManager_isDeclared(kIAllocatorServiceName.c_str())) {
59             return nullptr;
60         }
61         auto allocator = IAllocator::fromBinder(
62                 ndk::SpAIBinder(AServiceManager_waitForService(kIAllocatorServiceName.c_str())));
63         if (!allocator) {
64             ALOGE("AIDL IAllocator declared but failed to get service");
65             return nullptr;
66         }
67 
68         int32_t version = 0;
69         if (!allocator->getInterfaceVersion(&version).isOk()) {
70             ALOGE("Failed to query interface version");
71             return nullptr;
72         }
73         if (version < kIAllocatorMinimumVersion) {
74             return nullptr;
75         }
76         return allocator;
77     } else {
78         // TODO: LOG_ALWAYS_FATAL("libui is not backwards compatible");
79         return nullptr;
80     }
81 }
82 
loadIMapperLibrary()83 static void *loadIMapperLibrary() {
84     static void *imapperLibrary = []() -> void * {
85         auto allocator = waitForAllocator();
86         std::string mapperSuffix;
87         auto status = allocator->getIMapperLibrarySuffix(&mapperSuffix);
88         if (!status.isOk()) {
89             ALOGE("Failed to get IMapper library suffix");
90             return nullptr;
91         }
92 
93         void* so = nullptr;
94         // TODO(b/322384429) switch this to __ANDROID_API_V__ when V is finalized
95         if API_LEVEL_AT_LEAST(__ANDROID_API_FUTURE__, 202404) {
96             so = AServiceManager_openDeclaredPassthroughHal("mapper", mapperSuffix.c_str(),
97                                                             RTLD_LOCAL | RTLD_NOW);
98         } else {
99             std::string lib_name = "mapper." + mapperSuffix + ".so";
100             so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
101         }
102         if (!so) {
103             ALOGE("Failed to load mapper.%s.so", mapperSuffix.c_str());
104         }
105         return so;
106     }();
107     return imapperLibrary;
108 }
109 
getInstance()110 static const Gralloc5 &getInstance() {
111     static Gralloc5 instance = []() {
112         auto allocator = waitForAllocator();
113         if (!allocator) {
114             return Gralloc5{};
115         }
116         void *so = loadIMapperLibrary();
117         if (!so) {
118             return Gralloc5{};
119         }
120         auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
121         AIMapper *mapper = nullptr;
122         AIMapper_Error error = loadIMapper(&mapper);
123         if (error != AIMAPPER_ERROR_NONE) {
124             ALOGE("AIMapper_loadIMapper failed %d", error);
125             return Gralloc5{};
126         }
127         return Gralloc5{std::move(allocator), mapper};
128     }();
129     return instance;
130 }
131 
132 template <StandardMetadataType T>
getStandardMetadata(AIMapper * mapper,buffer_handle_t bufferHandle)133 static auto getStandardMetadata(AIMapper *mapper, buffer_handle_t bufferHandle)
134         -> decltype(StandardMetadata<T>::value::decode(nullptr, 0)) {
135     using Value = typename StandardMetadata<T>::value;
136     // TODO: Tune for common-case better
137     FatVector<uint8_t, 128> buffer;
138     int32_t sizeRequired = mapper->v5.getStandardMetadata(bufferHandle, static_cast<int64_t>(T),
139                                                           buffer.data(), buffer.size());
140     if (sizeRequired < 0) {
141         ALOGW_IF(-AIMAPPER_ERROR_UNSUPPORTED != sizeRequired,
142                  "Unexpected error %d from valid getStandardMetadata call", -sizeRequired);
143         return std::nullopt;
144     }
145     if ((size_t)sizeRequired > buffer.size()) {
146         buffer.resize(sizeRequired);
147         sizeRequired = mapper->v5.getStandardMetadata(bufferHandle, static_cast<int64_t>(T),
148                                                       buffer.data(), buffer.size());
149     }
150     if (sizeRequired < 0 || (size_t)sizeRequired > buffer.size()) {
151         ALOGW("getStandardMetadata failed, received %d with buffer size %zd", sizeRequired,
152               buffer.size());
153         // Generate a fail type
154         return std::nullopt;
155     }
156     return Value::decode(buffer.data(), sizeRequired);
157 }
158 
159 template <StandardMetadataType T>
setStandardMetadata(AIMapper * mapper,buffer_handle_t bufferHandle,const typename StandardMetadata<T>::value_type & value)160 static AIMapper_Error setStandardMetadata(AIMapper *mapper, buffer_handle_t bufferHandle,
161                                           const typename StandardMetadata<T>::value_type &value) {
162     using Value = typename StandardMetadata<T>::value;
163     int32_t sizeRequired = Value::encode(value, nullptr, 0);
164     if (sizeRequired < 0) {
165         ALOGW("Failed to calculate required size");
166         return static_cast<AIMapper_Error>(-sizeRequired);
167     }
168     FatVector<uint8_t, 128> buffer;
169     buffer.resize(sizeRequired);
170     sizeRequired = Value::encode(value, buffer.data(), buffer.size());
171     if (sizeRequired < 0 || (size_t)sizeRequired > buffer.size()) {
172         ALOGW("Failed to encode with calculated size %d; buffer size %zd", sizeRequired,
173               buffer.size());
174         return static_cast<AIMapper_Error>(-sizeRequired);
175     }
176     return mapper->v5.setStandardMetadata(bufferHandle, static_cast<int64_t>(T), buffer.data(),
177                                           sizeRequired);
178 }
179 
Gralloc5Allocator(const Gralloc5Mapper & mapper)180 Gralloc5Allocator::Gralloc5Allocator(const Gralloc5Mapper &mapper) : mMapper(mapper) {
181     mAllocator = getInstance().allocator;
182 }
183 
isLoaded() const184 bool Gralloc5Allocator::isLoaded() const {
185     return mAllocator != nullptr;
186 }
187 
getValidUsageBits()188 static uint64_t getValidUsageBits() {
189     static const uint64_t validUsageBits = []() -> uint64_t {
190         uint64_t bits = 0;
191         for (const auto bit : ndk::enum_range<BufferUsage>{}) {
192             bits |= static_cast<int64_t>(bit);
193         }
194         return bits;
195     }();
196     return validUsageBits | kRemovedUsageBits;
197 }
198 
makeDescriptor(std::string requestorName,uint32_t width,uint32_t height,PixelFormat format,uint32_t layerCount,uint64_t usage)199 static std::optional<BufferDescriptorInfo> makeDescriptor(std::string requestorName, uint32_t width,
200                                                           uint32_t height, PixelFormat format,
201                                                           uint32_t layerCount, uint64_t usage) {
202     uint64_t validUsageBits = getValidUsageBits();
203     if (usage & ~validUsageBits) {
204         ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64, usage & ~validUsageBits);
205         return std::nullopt;
206     }
207 
208     BufferDescriptorInfo descriptorInfo{
209             .width = static_cast<int32_t>(width),
210             .height = static_cast<int32_t>(height),
211             .layerCount = static_cast<int32_t>(layerCount),
212             .format = static_cast<::aidl::android::hardware::graphics::common::PixelFormat>(format),
213             .usage = static_cast<BufferUsage>(usage),
214     };
215     auto nameLength = std::min(requestorName.length(), descriptorInfo.name.size() - 1);
216     memcpy(descriptorInfo.name.data(), requestorName.data(), nameLength);
217     requestorName.data()[nameLength] = 0;
218     return descriptorInfo;
219 }
220 
dumpDebugInfo(bool less) const221 std::string Gralloc5Allocator::dumpDebugInfo(bool less) const {
222     return mMapper.dumpBuffers(less);
223 }
224 
allocate(std::string requestorName,uint32_t width,uint32_t height,android::PixelFormat format,uint32_t layerCount,uint64_t usage,uint32_t * outStride,buffer_handle_t * outBufferHandles,bool importBuffers) const225 status_t Gralloc5Allocator::allocate(std::string requestorName, uint32_t width, uint32_t height,
226                                      android::PixelFormat format, uint32_t layerCount,
227                                      uint64_t usage, uint32_t* outStride,
228                                      buffer_handle_t* outBufferHandles, bool importBuffers) const {
229     auto result = allocate(GraphicBufferAllocator::AllocationRequest{
230             .importBuffer = importBuffers,
231             .width = width,
232             .height = height,
233             .format = format,
234             .layerCount = layerCount,
235             .usage = usage,
236             .requestorName = requestorName,
237     });
238 
239     *outStride = result.stride;
240     outBufferHandles[0] = result.handle;
241     return result.status;
242 }
243 
allocate(const GraphicBufferAllocator::AllocationRequest & request) const244 GraphicBufferAllocator::AllocationResult Gralloc5Allocator::allocate(
245         const GraphicBufferAllocator::AllocationRequest& request) const {
246     auto descriptorInfo = makeDescriptor(request.requestorName, request.width, request.height,
247                                          request.format, request.layerCount, request.usage);
248     if (!descriptorInfo) {
249         return GraphicBufferAllocator::AllocationResult{BAD_VALUE};
250     }
251 
252     descriptorInfo->additionalOptions.reserve(request.extras.size());
253     for (const auto& option : request.extras) {
254         ExtendableType type;
255         type.name = option.name;
256         type.value = option.value;
257         descriptorInfo->additionalOptions.push_back(std::move(type));
258     }
259 
260     AllocationResult result;
261     auto status = mAllocator->allocate2(*descriptorInfo, 1, &result);
262     if (!status.isOk()) {
263         auto error = status.getExceptionCode();
264         if (error == EX_SERVICE_SPECIFIC) {
265             switch (static_cast<AllocationError>(status.getServiceSpecificError())) {
266                 case AllocationError::BAD_DESCRIPTOR:
267                     error = BAD_VALUE;
268                     break;
269                 case AllocationError::NO_RESOURCES:
270                     error = NO_MEMORY;
271                     break;
272                 default:
273                     error = UNKNOWN_ERROR;
274                     break;
275             }
276         }
277         return GraphicBufferAllocator::AllocationResult{error};
278     }
279 
280     GraphicBufferAllocator::AllocationResult ret{OK};
281     if (request.importBuffer) {
282         auto handle = makeFromAidl(result.buffers[0]);
283         auto error = mMapper.importBuffer(handle, &ret.handle);
284         native_handle_delete(handle);
285         if (error != NO_ERROR) {
286             return GraphicBufferAllocator::AllocationResult{error};
287         }
288     } else {
289         ret.handle = dupFromAidl(result.buffers[0]);
290         if (!ret.handle) {
291             return GraphicBufferAllocator::AllocationResult{NO_MEMORY};
292         }
293     }
294 
295     ret.stride = result.stride;
296 
297     // Release all the resources held by AllocationResult (specifically any remaining FDs)
298     result = {};
299     // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
300     // TODO: Re-enable this at some point if it's necessary. We can't do it now because libui
301     // is marked apex_available (b/214400477) and libbinder isn't (which of course is correct)
302     // IPCThreadState::self()->flushCommands();
303 
304     return ret;
305 }
306 
preload()307 void Gralloc5Mapper::preload() {
308     // TODO(b/261858155): Implement. We can't bounce off of IAllocator for this because zygote can't
309     // use binder. So when an alternate strategy of retrieving the library prefix is available,
310     // use that here.
311 }
312 
Gralloc5Mapper()313 Gralloc5Mapper::Gralloc5Mapper() {
314     mMapper = getInstance().mapper;
315 }
316 
isLoaded() const317 bool Gralloc5Mapper::isLoaded() const {
318     return mMapper != nullptr && mMapper->version >= AIMAPPER_VERSION_5;
319 }
320 
isStandardMetadata(AIMapper_MetadataType metadataType)321 static bool isStandardMetadata(AIMapper_MetadataType metadataType) {
322     return strcmp(kStandardMetadataName, metadataType.name) == 0;
323 }
324 
325 struct DumpBufferResult {
326     uint64_t bufferId;
327     std::string name;
328     uint64_t width;
329     uint64_t height;
330     uint64_t layerCount;
331     APixelFormat pixelFormatRequested;
332     uint32_t pixelFormatFourCC;
333     uint64_t pixelFormatModifier;
334     BufferUsage usage;
335     ADataspace dataspace;
336     uint64_t allocationSize;
337     uint64_t protectedContent;
338     ExtendableType compression;
339     ExtendableType interlaced;
340     ExtendableType chromaSiting;
341     std::vector<ui::PlaneLayout> planeLayouts;
342 };
343 
344 #define DECODE_TO(name, output)                                                                 \
345     case StandardMetadataType::name:                                                            \
346         output = StandardMetadata<StandardMetadataType::name>::value ::decode(value, valueSize) \
347                          .value();                                                              \
348         break
349 
dumpBufferCommon(DumpBufferResult * outResult,AIMapper_MetadataType metadataType,const void * value,size_t valueSize)350 static void dumpBufferCommon(DumpBufferResult* outResult, AIMapper_MetadataType metadataType,
351                              const void* value, size_t valueSize) {
352     if (!isStandardMetadata(metadataType)) {
353         return;
354     }
355     StandardMetadataType type = (StandardMetadataType)metadataType.value;
356     switch (type) {
357         DECODE_TO(BUFFER_ID, outResult->bufferId);
358         DECODE_TO(NAME, outResult->name);
359         DECODE_TO(WIDTH, outResult->width);
360         DECODE_TO(HEIGHT, outResult->height);
361         DECODE_TO(LAYER_COUNT, outResult->layerCount);
362         DECODE_TO(PIXEL_FORMAT_REQUESTED, outResult->pixelFormatRequested);
363         DECODE_TO(PIXEL_FORMAT_FOURCC, outResult->pixelFormatFourCC);
364         DECODE_TO(PIXEL_FORMAT_MODIFIER, outResult->pixelFormatModifier);
365         DECODE_TO(USAGE, outResult->usage);
366         DECODE_TO(DATASPACE, outResult->dataspace);
367         DECODE_TO(ALLOCATION_SIZE, outResult->allocationSize);
368         DECODE_TO(PROTECTED_CONTENT, outResult->protectedContent);
369         DECODE_TO(COMPRESSION, outResult->compression);
370         DECODE_TO(INTERLACED, outResult->interlaced);
371         DECODE_TO(CHROMA_SITING, outResult->chromaSiting);
372         DECODE_TO(PLANE_LAYOUTS, outResult->planeLayouts);
373         default:
374             break;
375     }
376 }
377 
378 #undef DECODE_TO
379 
380 template <typename EnumT, typename = std::enable_if_t<std::is_enum<EnumT>{}>>
to_underlying(EnumT e)381 constexpr std::underlying_type_t<EnumT> to_underlying(EnumT e) noexcept {
382     return static_cast<std::underlying_type_t<EnumT>>(e);
383 }
384 
writeDumpToStream(const DumpBufferResult & bufferDump,std::ostream & outDump,bool less)385 static void writeDumpToStream(const DumpBufferResult& bufferDump, std::ostream& outDump,
386                               bool less) {
387     double allocationSizeKiB = static_cast<double>(bufferDump.allocationSize) / 1024;
388 
389     outDump << "+ name:" << bufferDump.name << ", id:" << bufferDump.bufferId
390             << ", size:" << std::fixed << allocationSizeKiB << "KiB, w/h:" << bufferDump.width
391             << "x" << bufferDump.height << ", usage: 0x" << std::hex
392             << to_underlying(bufferDump.usage) << std::dec
393             << ", req fmt:" << to_underlying(bufferDump.pixelFormatRequested)
394             << ", fourcc/mod:" << bufferDump.pixelFormatFourCC << "/"
395             << bufferDump.pixelFormatModifier << ", dataspace: 0x" << std::hex
396             << to_underlying(bufferDump.dataspace) << std::dec << ", compressed: ";
397 
398     if (less) {
399         bool isCompressed = !gralloc4::isStandardCompression(bufferDump.compression) ||
400                 (gralloc4::getStandardCompressionValue(bufferDump.compression) !=
401                  ui::Compression::NONE);
402         outDump << std::boolalpha << isCompressed << "\n";
403     } else {
404         outDump << gralloc4::getCompressionName(bufferDump.compression) << "\n";
405     }
406 
407     if (!less) {
408         bool firstPlane = true;
409         for (const auto& planeLayout : bufferDump.planeLayouts) {
410             if (firstPlane) {
411                 firstPlane = false;
412                 outDump << "\tplanes: ";
413             } else {
414                 outDump << "\t        ";
415             }
416 
417             for (size_t i = 0; i < planeLayout.components.size(); i++) {
418                 const auto& planeLayoutComponent = planeLayout.components[i];
419                 outDump << gralloc4::getPlaneLayoutComponentTypeName(planeLayoutComponent.type);
420                 if (i < planeLayout.components.size() - 1) {
421                     outDump << "/";
422                 } else {
423                     outDump << ":\t";
424                 }
425             }
426             outDump << " w/h:" << planeLayout.widthInSamples << "x" << planeLayout.heightInSamples
427                     << ", stride:" << planeLayout.strideInBytes
428                     << " bytes, size:" << planeLayout.totalSizeInBytes;
429             outDump << ", inc:" << planeLayout.sampleIncrementInBits
430                     << " bits, subsampling w/h:" << planeLayout.horizontalSubsampling << "x"
431                     << planeLayout.verticalSubsampling;
432             outDump << "\n";
433         }
434 
435         outDump << "\tlayer cnt: " << bufferDump.layerCount
436                 << ", protected content: " << bufferDump.protectedContent
437                 << ", interlaced: " << gralloc4::getInterlacedName(bufferDump.interlaced)
438                 << ", chroma siting:" << gralloc4::getChromaSitingName(bufferDump.chromaSiting)
439                 << "\n";
440     }
441 }
442 
dumpBuffer(buffer_handle_t bufferHandle,bool less) const443 std::string Gralloc5Mapper::dumpBuffer(buffer_handle_t bufferHandle, bool less) const {
444     DumpBufferResult bufferInfo;
445     AIMapper_DumpBufferCallback dumpBuffer = [](void* contextPtr,
446                                                 AIMapper_MetadataType metadataType,
447                                                 const void* _Nonnull value, size_t valueSize) {
448         DumpBufferResult* context = reinterpret_cast<DumpBufferResult*>(contextPtr);
449         dumpBufferCommon(context, metadataType, value, valueSize);
450     };
451     AIMapper_Error error = mMapper->v5.dumpBuffer(bufferHandle, dumpBuffer, &bufferInfo);
452     if (error != AIMAPPER_ERROR_NONE) {
453         ALOGE("Error dumping buffer: %d", error);
454         return std::string{};
455     }
456     std::ostringstream stream;
457     stream.precision(2);
458     writeDumpToStream(bufferInfo, stream, less);
459     return stream.str();
460 }
461 
dumpBuffers(bool less) const462 std::string Gralloc5Mapper::dumpBuffers(bool less) const {
463     class DumpAllBuffersContext {
464     private:
465         bool mHasPending = false;
466         DumpBufferResult mPending;
467         std::vector<DumpBufferResult> mResults;
468 
469     public:
470         DumpAllBuffersContext() { mResults.reserve(10); }
471 
472         void commit() {
473             if (mHasPending) {
474                 mResults.push_back(mPending);
475                 mHasPending = false;
476             }
477         }
478 
479         DumpBufferResult* write() {
480             mHasPending = true;
481             return &mPending;
482         }
483 
484         const std::vector<DumpBufferResult>& results() {
485             commit();
486             return mResults;
487         }
488     } context;
489 
490     AIMapper_BeginDumpBufferCallback beginCallback = [](void* contextPtr) {
491         DumpAllBuffersContext* context = reinterpret_cast<DumpAllBuffersContext*>(contextPtr);
492         context->commit();
493     };
494 
495     AIMapper_DumpBufferCallback dumpBuffer = [](void* contextPtr,
496                                                 AIMapper_MetadataType metadataType,
497                                                 const void* _Nonnull value, size_t valueSize) {
498         DumpAllBuffersContext* context = reinterpret_cast<DumpAllBuffersContext*>(contextPtr);
499         dumpBufferCommon(context->write(), metadataType, value, valueSize);
500     };
501 
502     AIMapper_Error error = mMapper->v5.dumpAllBuffers(beginCallback, dumpBuffer, &context);
503     if (error != AIMAPPER_ERROR_NONE) {
504         ALOGE("Error dumping buffers: %d", error);
505         return std::string{};
506     }
507     uint64_t totalAllocationSize = 0;
508     std::ostringstream stream;
509     stream.precision(2);
510     stream << "Imported gralloc buffers:\n";
511 
512     for (const auto& bufferDump : context.results()) {
513         writeDumpToStream(bufferDump, stream, less);
514         totalAllocationSize += bufferDump.allocationSize;
515     }
516 
517     double totalAllocationSizeKiB = static_cast<double>(totalAllocationSize) / 1024;
518     stream << "Total imported by gralloc: " << totalAllocationSizeKiB << "KiB\n";
519     return stream.str();
520 }
521 
importBuffer(const native_handle_t * rawHandle,buffer_handle_t * outBufferHandle) const522 status_t Gralloc5Mapper::importBuffer(const native_handle_t *rawHandle,
523                                       buffer_handle_t *outBufferHandle) const {
524     return mMapper->v5.importBuffer(rawHandle, outBufferHandle);
525 }
526 
freeBuffer(buffer_handle_t bufferHandle) const527 void Gralloc5Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
528     mMapper->v5.freeBuffer(bufferHandle);
529 }
530 
validateBufferSize(buffer_handle_t bufferHandle,uint32_t width,uint32_t height,PixelFormat format,uint32_t layerCount,uint64_t usage,uint32_t stride) const531 status_t Gralloc5Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
532                                             uint32_t height, PixelFormat format,
533                                             uint32_t layerCount, uint64_t usage,
534                                             uint32_t stride) const {
535     {
536         auto value = getStandardMetadata<StandardMetadataType::WIDTH>(mMapper, bufferHandle);
537         if (width != value) {
538             ALOGW("Width didn't match, expected %d got %" PRId64, width, value.value_or(-1));
539             return BAD_VALUE;
540         }
541     }
542     {
543         auto value = getStandardMetadata<StandardMetadataType::HEIGHT>(mMapper, bufferHandle);
544         if (height != value) {
545             ALOGW("Height didn't match, expected %d got %" PRId64, height, value.value_or(-1));
546             return BAD_VALUE;
547         }
548     }
549     {
550         auto expected = static_cast<APixelFormat>(format);
551         if (expected != APixelFormat::IMPLEMENTATION_DEFINED) {
552             auto value =
553                     getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(mMapper,
554                                                                                       bufferHandle);
555             if (expected != value) {
556                 ALOGW("Format didn't match, expected %d got %s", format,
557                       value.has_value() ? toString(*value).c_str() : "<null>");
558                 return BAD_VALUE;
559             }
560         }
561     }
562     {
563         auto value = getStandardMetadata<StandardMetadataType::LAYER_COUNT>(mMapper, bufferHandle);
564         if (layerCount != value) {
565             ALOGW("Layer count didn't match, expected %d got %" PRId64, layerCount,
566                   value.value_or(-1));
567             return BAD_VALUE;
568         }
569     }
570     // TODO: This can false-positive fail if the allocator adjusted the USAGE bits internally
571     //       Investigate further & re-enable or remove, but for now ignoring usage should be OK
572     (void)usage;
573     // {
574     //     auto value = getStandardMetadata<StandardMetadataType::USAGE>(mMapper, bufferHandle);
575     //     if (static_cast<BufferUsage>(usage) != value) {
576     //         ALOGW("Usage didn't match, expected %" PRIu64 " got %" PRId64, usage,
577     //               static_cast<int64_t>(value.value_or(BufferUsage::CPU_READ_NEVER)));
578     //         return BAD_VALUE;
579     //     }
580     // }
581     {
582         auto value = getStandardMetadata<StandardMetadataType::STRIDE>(mMapper, bufferHandle);
583         if (stride != value) {
584             ALOGW("Stride didn't match, expected %" PRIu32 " got %" PRId32, stride,
585                   value.value_or(-1));
586             return BAD_VALUE;
587         }
588     }
589     return OK;
590 }
591 
getTransportSize(buffer_handle_t bufferHandle,uint32_t * outNumFds,uint32_t * outNumInts) const592 void Gralloc5Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t *outNumFds,
593                                       uint32_t *outNumInts) const {
594     mMapper->v5.getTransportSize(bufferHandle, outNumFds, outNumInts);
595 }
596 
lock(buffer_handle_t bufferHandle,uint64_t usage,const Rect & bounds,int acquireFence,void ** outData,int32_t * outBytesPerPixel,int32_t * outBytesPerStride) const597 status_t Gralloc5Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect &bounds,
598                               int acquireFence, void **outData, int32_t *outBytesPerPixel,
599                               int32_t *outBytesPerStride) const {
600     if (outBytesPerPixel) *outBytesPerPixel = -1;
601     if (outBytesPerStride) *outBytesPerStride = -1;
602 
603     auto status = mMapper->v5.lock(bufferHandle, usage, bounds, acquireFence, outData);
604 
605     ALOGW_IF(status != AIMAPPER_ERROR_NONE, "lock(%p, ...) failed: %d", bufferHandle, status);
606     return static_cast<status_t>(status);
607 }
608 
lock(buffer_handle_t bufferHandle,uint64_t usage,const Rect & bounds,int acquireFence,android_ycbcr * outYcbcr) const609 status_t Gralloc5Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect &bounds,
610                               int acquireFence, android_ycbcr *outYcbcr) const {
611     if (!outYcbcr) {
612         return BAD_VALUE;
613     }
614 
615     // TODO(b/262279301): Change the return type of ::unlock to unique_fd instead of int so that
616     //  ignoring the return value "just works" instead
617     auto unlock = [this](buffer_handle_t bufferHandle) {
618         int fence = this->unlock(bufferHandle);
619         if (fence != -1) {
620             ::close(fence);
621         }
622     };
623 
624     std::vector<ui::PlaneLayout> planeLayouts;
625     status_t error = getPlaneLayouts(bufferHandle, &planeLayouts);
626     if (error != NO_ERROR) {
627         return error;
628     }
629 
630     void *data = nullptr;
631     error = lock(bufferHandle, usage, bounds, acquireFence, &data, nullptr, nullptr);
632     if (error != NO_ERROR) {
633         return error;
634     }
635 
636     android_ycbcr ycbcr;
637 
638     ycbcr.y = nullptr;
639     ycbcr.cb = nullptr;
640     ycbcr.cr = nullptr;
641     ycbcr.ystride = 0;
642     ycbcr.cstride = 0;
643     ycbcr.chroma_step = 0;
644 
645     for (const auto &planeLayout : planeLayouts) {
646         for (const auto &planeLayoutComponent : planeLayout.components) {
647             if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
648                 continue;
649             }
650 
651             uint8_t *tmpData = static_cast<uint8_t *>(data) + planeLayout.offsetInBytes;
652 
653             // Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
654             // but we still want to point to the start of the first byte.
655             tmpData += (planeLayoutComponent.offsetInBits / 8);
656 
657             uint64_t sampleIncrementInBytes;
658 
659             auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
660             switch (type) {
661                 case PlaneLayoutComponentType::Y:
662                     if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
663                         unlock(bufferHandle);
664                         return BAD_VALUE;
665                     }
666                     ycbcr.y = tmpData;
667                     ycbcr.ystride = planeLayout.strideInBytes;
668                     break;
669 
670                 case PlaneLayoutComponentType::CB:
671                 case PlaneLayoutComponentType::CR:
672                     if (planeLayout.sampleIncrementInBits % 8 != 0) {
673                         unlock(bufferHandle);
674                         return BAD_VALUE;
675                     }
676 
677                     sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
678                     if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
679                         (sampleIncrementInBytes != 4)) {
680                         unlock(bufferHandle);
681                         return BAD_VALUE;
682                     }
683 
684                     if (ycbcr.cstride == 0 && ycbcr.chroma_step == 0) {
685                         ycbcr.cstride = planeLayout.strideInBytes;
686                         ycbcr.chroma_step = sampleIncrementInBytes;
687                     } else {
688                         if ((static_cast<int64_t>(ycbcr.cstride) != planeLayout.strideInBytes) ||
689                             (ycbcr.chroma_step != sampleIncrementInBytes)) {
690                             unlock(bufferHandle);
691                             return BAD_VALUE;
692                         }
693                     }
694 
695                     if (type == PlaneLayoutComponentType::CB) {
696                         if (ycbcr.cb != nullptr) {
697                             unlock(bufferHandle);
698                             return BAD_VALUE;
699                         }
700                         ycbcr.cb = tmpData;
701                     } else {
702                         if (ycbcr.cr != nullptr) {
703                             unlock(bufferHandle);
704                             return BAD_VALUE;
705                         }
706                         ycbcr.cr = tmpData;
707                     }
708                     break;
709                 default:
710                     break;
711             };
712         }
713     }
714 
715     *outYcbcr = ycbcr;
716     return OK;
717 }
718 
unlock(buffer_handle_t bufferHandle) const719 int Gralloc5Mapper::unlock(buffer_handle_t bufferHandle) const {
720     int fence = -1;
721     AIMapper_Error error = mMapper->v5.unlock(bufferHandle, &fence);
722     if (error != AIMAPPER_ERROR_NONE) {
723         ALOGW("unlock failed with error %d", error);
724     }
725     return fence;
726 }
727 
isSupported(uint32_t width,uint32_t height,PixelFormat format,uint32_t layerCount,uint64_t usage,bool * outSupported) const728 status_t Gralloc5Mapper::isSupported(uint32_t width, uint32_t height, PixelFormat format,
729                                      uint32_t layerCount, uint64_t usage,
730                                      bool *outSupported) const {
731     auto descriptorInfo = makeDescriptor("", width, height, format, layerCount, usage);
732     if (!descriptorInfo) {
733         *outSupported = false;
734         return OK;
735     }
736     auto status = getInstance().allocator->isSupported(*descriptorInfo, outSupported);
737     if (!status.isOk()) {
738         ALOGW("IAllocator::isSupported error %d (%s)", status.getStatus(), status.getMessage());
739         *outSupported = false;
740     }
741     return OK;
742 }
743 
getBufferId(buffer_handle_t bufferHandle,uint64_t * outBufferId) const744 status_t Gralloc5Mapper::getBufferId(buffer_handle_t bufferHandle, uint64_t *outBufferId) const {
745     auto value = getStandardMetadata<StandardMetadataType::BUFFER_ID>(mMapper, bufferHandle);
746     if (value.has_value()) {
747         *outBufferId = *value;
748         return OK;
749     }
750     return UNKNOWN_TRANSACTION;
751 }
752 
getName(buffer_handle_t bufferHandle,std::string * outName) const753 status_t Gralloc5Mapper::getName(buffer_handle_t bufferHandle, std::string *outName) const {
754     auto value = getStandardMetadata<StandardMetadataType::NAME>(mMapper, bufferHandle);
755     if (value.has_value()) {
756         *outName = *value;
757         return OK;
758     }
759     return UNKNOWN_TRANSACTION;
760 }
761 
getWidth(buffer_handle_t bufferHandle,uint64_t * outWidth) const762 status_t Gralloc5Mapper::getWidth(buffer_handle_t bufferHandle, uint64_t *outWidth) const {
763     auto value = getStandardMetadata<StandardMetadataType::WIDTH>(mMapper, bufferHandle);
764     if (value.has_value()) {
765         *outWidth = *value;
766         return OK;
767     }
768     return UNKNOWN_TRANSACTION;
769 }
770 
getHeight(buffer_handle_t bufferHandle,uint64_t * outHeight) const771 status_t Gralloc5Mapper::getHeight(buffer_handle_t bufferHandle, uint64_t *outHeight) const {
772     auto value = getStandardMetadata<StandardMetadataType::HEIGHT>(mMapper, bufferHandle);
773     if (value.has_value()) {
774         *outHeight = *value;
775         return OK;
776     }
777     return UNKNOWN_TRANSACTION;
778 }
779 
getLayerCount(buffer_handle_t bufferHandle,uint64_t * outLayerCount) const780 status_t Gralloc5Mapper::getLayerCount(buffer_handle_t bufferHandle,
781                                        uint64_t *outLayerCount) const {
782     auto value = getStandardMetadata<StandardMetadataType::LAYER_COUNT>(mMapper, bufferHandle);
783     if (value.has_value()) {
784         *outLayerCount = *value;
785         return OK;
786     }
787     return UNKNOWN_TRANSACTION;
788 }
789 
getPixelFormatRequested(buffer_handle_t bufferHandle,ui::PixelFormat * outPixelFormatRequested) const790 status_t Gralloc5Mapper::getPixelFormatRequested(buffer_handle_t bufferHandle,
791                                                  ui::PixelFormat *outPixelFormatRequested) const {
792     auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(mMapper,
793                                                                                    bufferHandle);
794     if (value.has_value()) {
795         *outPixelFormatRequested = static_cast<ui::PixelFormat>(*value);
796         return OK;
797     }
798     return UNKNOWN_TRANSACTION;
799 }
800 
getPixelFormatFourCC(buffer_handle_t bufferHandle,uint32_t * outPixelFormatFourCC) const801 status_t Gralloc5Mapper::getPixelFormatFourCC(buffer_handle_t bufferHandle,
802                                               uint32_t *outPixelFormatFourCC) const {
803     auto value =
804             getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>(mMapper, bufferHandle);
805     if (value.has_value()) {
806         *outPixelFormatFourCC = *value;
807         return OK;
808     }
809     return UNKNOWN_TRANSACTION;
810 }
811 
getPixelFormatModifier(buffer_handle_t bufferHandle,uint64_t * outPixelFormatModifier) const812 status_t Gralloc5Mapper::getPixelFormatModifier(buffer_handle_t bufferHandle,
813                                                 uint64_t *outPixelFormatModifier) const {
814     auto value =
815             getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_MODIFIER>(mMapper, bufferHandle);
816     if (value.has_value()) {
817         *outPixelFormatModifier = *value;
818         return OK;
819     }
820     return UNKNOWN_TRANSACTION;
821 }
822 
getUsage(buffer_handle_t bufferHandle,uint64_t * outUsage) const823 status_t Gralloc5Mapper::getUsage(buffer_handle_t bufferHandle, uint64_t *outUsage) const {
824     auto value = getStandardMetadata<StandardMetadataType::USAGE>(mMapper, bufferHandle);
825     if (value.has_value()) {
826         *outUsage = static_cast<uint64_t>(*value);
827         return OK;
828     }
829     return UNKNOWN_TRANSACTION;
830 }
831 
getAllocationSize(buffer_handle_t bufferHandle,uint64_t * outAllocationSize) const832 status_t Gralloc5Mapper::getAllocationSize(buffer_handle_t bufferHandle,
833                                            uint64_t *outAllocationSize) const {
834     auto value = getStandardMetadata<StandardMetadataType::ALLOCATION_SIZE>(mMapper, bufferHandle);
835     if (value.has_value()) {
836         *outAllocationSize = *value;
837         return OK;
838     }
839     return UNKNOWN_TRANSACTION;
840 }
841 
getProtectedContent(buffer_handle_t bufferHandle,uint64_t * outProtectedContent) const842 status_t Gralloc5Mapper::getProtectedContent(buffer_handle_t bufferHandle,
843                                              uint64_t *outProtectedContent) const {
844     auto value =
845             getStandardMetadata<StandardMetadataType::PROTECTED_CONTENT>(mMapper, bufferHandle);
846     if (value.has_value()) {
847         *outProtectedContent = *value;
848         return OK;
849     }
850     return UNKNOWN_TRANSACTION;
851 }
852 
getCompression(buffer_handle_t bufferHandle,aidl::android::hardware::graphics::common::ExtendableType * outCompression) const853 status_t Gralloc5Mapper::getCompression(
854         buffer_handle_t bufferHandle,
855         aidl::android::hardware::graphics::common::ExtendableType *outCompression) const {
856     auto value = getStandardMetadata<StandardMetadataType::COMPRESSION>(mMapper, bufferHandle);
857     if (value.has_value()) {
858         *outCompression = *value;
859         return OK;
860     }
861     return UNKNOWN_TRANSACTION;
862 }
863 
getCompression(buffer_handle_t bufferHandle,ui::Compression * outCompression) const864 status_t Gralloc5Mapper::getCompression(buffer_handle_t bufferHandle,
865                                         ui::Compression *outCompression) const {
866     auto value = getStandardMetadata<StandardMetadataType::COMPRESSION>(mMapper, bufferHandle);
867     if (!value.has_value()) {
868         return UNKNOWN_TRANSACTION;
869     }
870     if (!gralloc4::isStandardCompression(*value)) {
871         return BAD_TYPE;
872     }
873     *outCompression = gralloc4::getStandardCompressionValue(*value);
874     return OK;
875 }
876 
getInterlaced(buffer_handle_t bufferHandle,aidl::android::hardware::graphics::common::ExtendableType * outInterlaced) const877 status_t Gralloc5Mapper::getInterlaced(
878         buffer_handle_t bufferHandle,
879         aidl::android::hardware::graphics::common::ExtendableType *outInterlaced) const {
880     auto value = getStandardMetadata<StandardMetadataType::INTERLACED>(mMapper, bufferHandle);
881     if (value.has_value()) {
882         *outInterlaced = *value;
883         return OK;
884     }
885     return UNKNOWN_TRANSACTION;
886 }
887 
getInterlaced(buffer_handle_t bufferHandle,ui::Interlaced * outInterlaced) const888 status_t Gralloc5Mapper::getInterlaced(buffer_handle_t bufferHandle,
889                                        ui::Interlaced *outInterlaced) const {
890     if (!outInterlaced) {
891         return BAD_VALUE;
892     }
893     ExtendableType interlaced;
894     status_t error = getInterlaced(bufferHandle, &interlaced);
895     if (error) {
896         return error;
897     }
898     if (!gralloc4::isStandardInterlaced(interlaced)) {
899         return BAD_TYPE;
900     }
901     *outInterlaced = gralloc4::getStandardInterlacedValue(interlaced);
902     return NO_ERROR;
903 }
904 
getChromaSiting(buffer_handle_t bufferHandle,aidl::android::hardware::graphics::common::ExtendableType * outChromaSiting) const905 status_t Gralloc5Mapper::getChromaSiting(
906         buffer_handle_t bufferHandle,
907         aidl::android::hardware::graphics::common::ExtendableType *outChromaSiting) const {
908     auto value = getStandardMetadata<StandardMetadataType::CHROMA_SITING>(mMapper, bufferHandle);
909     if (value.has_value()) {
910         *outChromaSiting = *value;
911         return OK;
912     }
913     return UNKNOWN_TRANSACTION;
914 }
915 
getChromaSiting(buffer_handle_t bufferHandle,ui::ChromaSiting * outChromaSiting) const916 status_t Gralloc5Mapper::getChromaSiting(buffer_handle_t bufferHandle,
917                                          ui::ChromaSiting *outChromaSiting) const {
918     if (!outChromaSiting) {
919         return BAD_VALUE;
920     }
921     ExtendableType chromaSiting;
922     status_t error = getChromaSiting(bufferHandle, &chromaSiting);
923     if (error) {
924         return error;
925     }
926     if (!gralloc4::isStandardChromaSiting(chromaSiting)) {
927         return BAD_TYPE;
928     }
929     *outChromaSiting = gralloc4::getStandardChromaSitingValue(chromaSiting);
930     return NO_ERROR;
931 }
932 
getPlaneLayouts(buffer_handle_t bufferHandle,std::vector<ui::PlaneLayout> * outPlaneLayouts) const933 status_t Gralloc5Mapper::getPlaneLayouts(buffer_handle_t bufferHandle,
934                                          std::vector<ui::PlaneLayout> *outPlaneLayouts) const {
935     auto value = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(mMapper, bufferHandle);
936     if (value.has_value()) {
937         *outPlaneLayouts = *value;
938         return OK;
939     }
940     return UNKNOWN_TRANSACTION;
941 }
942 
getDataspace(buffer_handle_t bufferHandle,ui::Dataspace * outDataspace) const943 status_t Gralloc5Mapper::getDataspace(buffer_handle_t bufferHandle,
944                                       ui::Dataspace *outDataspace) const {
945     auto value = getStandardMetadata<StandardMetadataType::DATASPACE>(mMapper, bufferHandle);
946     if (value.has_value()) {
947         *outDataspace = static_cast<ui::Dataspace>(*value);
948         return OK;
949     }
950     return UNKNOWN_TRANSACTION;
951 }
952 
setDataspace(buffer_handle_t bufferHandle,ui::Dataspace dataspace) const953 status_t Gralloc5Mapper::setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) const {
954     return setStandardMetadata<StandardMetadataType::DATASPACE>(mMapper, bufferHandle,
955                                                                 static_cast<Dataspace>(dataspace));
956 }
957 
getBlendMode(buffer_handle_t bufferHandle,ui::BlendMode * outBlendMode) const958 status_t Gralloc5Mapper::getBlendMode(buffer_handle_t bufferHandle,
959                                       ui::BlendMode *outBlendMode) const {
960     auto value = getStandardMetadata<StandardMetadataType::BLEND_MODE>(mMapper, bufferHandle);
961     if (value.has_value()) {
962         *outBlendMode = static_cast<ui::BlendMode>(*value);
963         return OK;
964     }
965     return UNKNOWN_TRANSACTION;
966 }
967 
getSmpte2086(buffer_handle_t bufferHandle,std::optional<ui::Smpte2086> * outSmpte2086) const968 status_t Gralloc5Mapper::getSmpte2086(buffer_handle_t bufferHandle,
969                                       std::optional<ui::Smpte2086> *outSmpte2086) const {
970     auto value = getStandardMetadata<StandardMetadataType::SMPTE2086>(mMapper, bufferHandle);
971     if (value.has_value()) {
972         *outSmpte2086 = *value;
973         return OK;
974     }
975     return UNKNOWN_TRANSACTION;
976 }
977 
setSmpte2086(buffer_handle_t bufferHandle,std::optional<ui::Smpte2086> smpte2086) const978 status_t Gralloc5Mapper::setSmpte2086(buffer_handle_t bufferHandle,
979                                       std::optional<ui::Smpte2086> smpte2086) const {
980     return setStandardMetadata<StandardMetadataType::SMPTE2086>(mMapper, bufferHandle, smpte2086);
981 }
982 
getCta861_3(buffer_handle_t bufferHandle,std::optional<ui::Cta861_3> * outCta861_3) const983 status_t Gralloc5Mapper::getCta861_3(buffer_handle_t bufferHandle,
984                                      std::optional<ui::Cta861_3> *outCta861_3) const {
985     auto value = getStandardMetadata<StandardMetadataType::CTA861_3>(mMapper, bufferHandle);
986     if (value.has_value()) {
987         *outCta861_3 = *value;
988         return OK;
989     }
990     return UNKNOWN_TRANSACTION;
991 }
992 
setCta861_3(buffer_handle_t bufferHandle,std::optional<ui::Cta861_3> cta861_3) const993 status_t Gralloc5Mapper::setCta861_3(buffer_handle_t bufferHandle,
994                                      std::optional<ui::Cta861_3> cta861_3) const {
995     return setStandardMetadata<StandardMetadataType::CTA861_3>(mMapper, bufferHandle, cta861_3);
996 }
997 
getSmpte2094_40(buffer_handle_t bufferHandle,std::optional<std::vector<uint8_t>> * outSmpte2094_40) const998 status_t Gralloc5Mapper::getSmpte2094_40(
999         buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>> *outSmpte2094_40) const {
1000     auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_40>(mMapper, bufferHandle);
1001     if (value.has_value()) {
1002         *outSmpte2094_40 = std::move(*value);
1003         return OK;
1004     }
1005     return UNKNOWN_TRANSACTION;
1006 }
1007 
setSmpte2094_40(buffer_handle_t bufferHandle,std::optional<std::vector<uint8_t>> smpte2094_40) const1008 status_t Gralloc5Mapper::setSmpte2094_40(buffer_handle_t bufferHandle,
1009                                          std::optional<std::vector<uint8_t>> smpte2094_40) const {
1010     return setStandardMetadata<StandardMetadataType::SMPTE2094_40>(mMapper, bufferHandle,
1011                                                                    smpte2094_40);
1012 }
1013 
getSmpte2094_10(buffer_handle_t bufferHandle,std::optional<std::vector<uint8_t>> * outSmpte2094_10) const1014 status_t Gralloc5Mapper::getSmpte2094_10(
1015         buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>> *outSmpte2094_10) const {
1016     auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_10>(mMapper, bufferHandle);
1017     if (value.has_value()) {
1018         *outSmpte2094_10 = std::move(*value);
1019         return OK;
1020     }
1021     return UNKNOWN_TRANSACTION;
1022 }
1023 
setSmpte2094_10(buffer_handle_t bufferHandle,std::optional<std::vector<uint8_t>> smpte2094_10) const1024 status_t Gralloc5Mapper::setSmpte2094_10(buffer_handle_t bufferHandle,
1025                                          std::optional<std::vector<uint8_t>> smpte2094_10) const {
1026     return setStandardMetadata<StandardMetadataType::SMPTE2094_10>(mMapper, bufferHandle,
1027                                                                    smpte2094_10);
1028 }
1029 
1030 } // namespace android