• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above
10  *    copyright notice, this list of conditions and the following
11  *    disclaimer in the documentation and/or other materials provided
12  *    with the distribution.
13  *  * Neither the name of The Linux Foundation nor the names of its
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <gralloc_priv.h>
31 
32 #include <core/buffer_allocator.h>
33 #include <utils/constants.h>
34 #include <utils/debug.h>
35 
36 #include "gr_utils.h"
37 #include "hwc_buffer_allocator.h"
38 #include "hwc_debugger.h"
39 
40 #define __CLASS__ "HWCBufferAllocator"
41 
42 using android::hardware::graphics::mapper::V2_0::Error;
43 using MapperV3Error = android::hardware::graphics::mapper::V3_0::Error;
44 using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
45 using MapperV3BufferDescriptor = android::hardware::graphics::mapper::V3_0::BufferDescriptor;
46 using android::hardware::hidl_handle;
47 using android::hardware::hidl_vec;
48 
49 namespace sdm {
50 
GetGrallocInstance()51 DisplayError HWCBufferAllocator::GetGrallocInstance() {
52   // Lazy initialization of gralloc HALs
53   if (mapper_V3_ != nullptr || mapper_V2_ != nullptr || allocator_V3_ != nullptr ||
54       allocator_V2_ != nullptr) {
55     return kErrorNone;
56   }
57 
58   allocator_V3_ = IAllocatorV3::getService();
59   if (allocator_V3_ == nullptr) {
60     allocator_V2_ = IAllocatorV2::getService();
61     if (allocator_V2_ == nullptr) {
62       DLOGE("Unable to get allocator");
63       return kErrorCriticalResource;
64     }
65   }
66 
67   mapper_V3_ = IMapperV3::getService();
68   if (mapper_V3_ == nullptr) {
69     mapper_V2_ = IMapperV2::getService();
70     if (mapper_V2_ == nullptr) {
71       DLOGE("Unable to get mapper");
72       return kErrorCriticalResource;
73     }
74   }
75 
76   return kErrorNone;
77 }
78 
AllocateBuffer(BufferInfo * buffer_info)79 DisplayError HWCBufferAllocator::AllocateBuffer(BufferInfo *buffer_info) {
80   auto err = GetGrallocInstance();
81   if (err != kErrorNone) {
82     return err;
83   }
84   const BufferConfig &buffer_config = buffer_info->buffer_config;
85   AllocatedBufferInfo *alloc_buffer_info = &buffer_info->alloc_buffer_info;
86   int format;
87   uint64_t alloc_flags = 0;
88   int error = SetBufferInfo(buffer_config.format, &format, &alloc_flags);
89   if (error != 0) {
90     return kErrorParameters;
91   }
92 
93   if (buffer_config.secure) {
94     alloc_flags |= BufferUsage::PROTECTED;
95   }
96 
97   if (buffer_config.secure_camera) {
98     alloc_flags |= BufferUsage::CAMERA_OUTPUT;
99   }
100 
101   if (!buffer_config.cache) {
102     // Allocate uncached buffers
103     alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
104   }
105 
106   if (buffer_config.gfx_client) {
107     alloc_flags |= BufferUsage::GPU_TEXTURE;
108   }
109 
110   alloc_flags |= BufferUsage::COMPOSER_OVERLAY;
111 
112   const native_handle_t *buf = nullptr;
113 
114   if (mapper_V3_ != nullptr) {
115     IMapperV3::BufferDescriptorInfo descriptor_info;
116     descriptor_info.width = buffer_config.width;
117     descriptor_info.height = buffer_config.height;
118     descriptor_info.layerCount = 1;
119     descriptor_info.format =
120         static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
121     descriptor_info.usage = alloc_flags;
122 
123     auto hidl_err = MapperV3Error::NONE;
124 
125     auto descriptor = BufferDescriptor();
126     mapper_V3_->createDescriptor(descriptor_info, [&](const auto &_error, const auto &_descriptor) {
127       hidl_err = _error;
128       if (hidl_err != MapperV3Error::NONE) {
129         return;
130       }
131       descriptor = _descriptor;
132     });
133 
134     if (hidl_err != MapperV3Error::NONE) {
135       DLOGE("Failed to create descriptor");
136       return kErrorMemory;
137     }
138 
139     hidl_handle raw_handle = nullptr;
140 
141     allocator_V3_->allocate(descriptor, 1,
142                             [&](const auto &_error, const auto &_stride, const auto &_buffers) {
143                               hidl_err = _error;
144                               if (hidl_err != MapperV3Error::NONE) {
145                                 return;
146                               }
147                               raw_handle = _buffers[0];
148                             });
149 
150     if (hidl_err != MapperV3Error::NONE) {
151       DLOGE("Failed to allocate buffer");
152       return kErrorMemory;
153     }
154 
155     mapper_V3_->importBuffer(raw_handle, [&](const auto &_error, const auto &_buffer) {
156       hidl_err = _error;
157       if (hidl_err != MapperV3Error::NONE) {
158         return;
159       }
160       buf = static_cast<const native_handle_t *>(_buffer);
161     });
162 
163     if (hidl_err != MapperV3Error::NONE) {
164       DLOGE("Failed to import buffer into HWC");
165       return kErrorMemory;
166     }
167   } else {
168     IMapperV2::BufferDescriptorInfo descriptor_info;
169     descriptor_info.width = buffer_config.width;
170     descriptor_info.height = buffer_config.height;
171     descriptor_info.layerCount = 1;
172     descriptor_info.format =
173         static_cast<android::hardware::graphics::common::V1_0::PixelFormat>(format);
174     descriptor_info.usage = alloc_flags;
175 
176     auto hidl_err = Error::NONE;
177 
178     auto descriptor = BufferDescriptor();
179     mapper_V2_->createDescriptor(descriptor_info, [&](const auto &_error, const auto &_descriptor) {
180       hidl_err = _error;
181       if (hidl_err != Error::NONE) {
182         return;
183       }
184       descriptor = _descriptor;
185     });
186 
187     if (hidl_err != Error::NONE) {
188       DLOGE("Failed to create descriptor");
189       return kErrorMemory;
190     }
191 
192     hidl_handle raw_handle = nullptr;
193 
194     allocator_V2_->allocate(descriptor, 1,
195                             [&](const auto &_error, const auto &_stride, const auto &_buffers) {
196                               hidl_err = _error;
197                               if (hidl_err != Error::NONE) {
198                                 return;
199                               }
200                               raw_handle = _buffers[0];
201                             });
202 
203     if (hidl_err != Error::NONE) {
204       DLOGE("Failed to allocate buffer");
205       return kErrorMemory;
206     }
207 
208     mapper_V2_->importBuffer(raw_handle, [&](const auto &_error, const auto &_buffer) {
209       hidl_err = _error;
210       if (hidl_err != Error::NONE) {
211         return;
212       }
213       buf = static_cast<const native_handle_t *>(_buffer);
214     });
215 
216     if (hidl_err != Error::NONE) {
217       DLOGE("Failed to import buffer into HWC");
218       return kErrorMemory;
219     }
220   }
221 
222   private_handle_t *hnd = nullptr;
223   hnd = (private_handle_t *)buf;  // NOLINT
224   alloc_buffer_info->fd = hnd->fd;
225   alloc_buffer_info->stride = UINT32(hnd->width);
226   alloc_buffer_info->aligned_width = UINT32(hnd->width);
227   alloc_buffer_info->aligned_height = UINT32(hnd->height);
228   alloc_buffer_info->size = hnd->size;
229   alloc_buffer_info->id = hnd->id;
230 
231   buffer_info->private_data = reinterpret_cast<void *>(hnd);
232   return kErrorNone;
233 }
234 
FreeBuffer(BufferInfo * buffer_info)235 DisplayError HWCBufferAllocator::FreeBuffer(BufferInfo *buffer_info) {
236   DisplayError err = kErrorNone;
237   auto hnd = reinterpret_cast<void *>(buffer_info->private_data);
238   if (mapper_V3_ != nullptr) {
239     mapper_V3_->freeBuffer(hnd);
240   } else {
241     mapper_V2_->freeBuffer(hnd);
242   }
243   AllocatedBufferInfo &alloc_buffer_info = buffer_info->alloc_buffer_info;
244 
245   alloc_buffer_info.fd = -1;
246   alloc_buffer_info.stride = 0;
247   alloc_buffer_info.size = 0;
248   buffer_info->private_data = NULL;
249   return err;
250 }
251 
GetCustomWidthAndHeight(const private_handle_t * handle,int * width,int * height)252 void HWCBufferAllocator::GetCustomWidthAndHeight(const private_handle_t *handle, int *width,
253                                                  int *height) {
254   *width = handle->width;
255   *height = handle->height;
256   gralloc::GetCustomDimensions(const_cast<private_handle_t *>(handle), width, height);
257 }
258 
GetAlignedWidthAndHeight(int width,int height,int format,uint32_t alloc_type,int * aligned_width,int * aligned_height)259 void HWCBufferAllocator::GetAlignedWidthAndHeight(int width, int height, int format,
260                                                   uint32_t alloc_type, int *aligned_width,
261                                                   int *aligned_height) {
262   uint64_t usage = 0;
263   if (alloc_type & GRALLOC_USAGE_HW_FB) {
264     usage |= BufferUsage::COMPOSER_CLIENT_TARGET;
265   }
266   if (alloc_type & GRALLOC_USAGE_PRIVATE_ALLOC_UBWC) {
267     usage |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
268   }
269   uint32_t aligned_w = UINT(width);
270   uint32_t aligned_h = UINT(height);
271   gralloc::BufferInfo info(width, height, format, usage);
272   gralloc::GetAlignedWidthAndHeight(info, &aligned_w, &aligned_h);
273   *aligned_width = INT(aligned_w);
274   *aligned_height = INT(aligned_h);
275 }
276 
GetBufferSize(BufferInfo * buffer_info)277 uint32_t HWCBufferAllocator::GetBufferSize(BufferInfo *buffer_info) {
278   const BufferConfig &buffer_config = buffer_info->buffer_config;
279   uint64_t alloc_flags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
280 
281   int width = INT(buffer_config.width);
282   int height = INT(buffer_config.height);
283   int format;
284 
285   if (buffer_config.secure) {
286     alloc_flags |= INT(GRALLOC_USAGE_PROTECTED);
287   }
288 
289   if (!buffer_config.cache) {
290     // Allocate uncached buffers
291     alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
292   }
293 
294   if (SetBufferInfo(buffer_config.format, &format, &alloc_flags) < 0) {
295     return 0;
296   }
297 
298   uint32_t aligned_width = 0, aligned_height = 0, buffer_size = 0;
299   gralloc::BufferInfo info(width, height, format, alloc_flags);
300   int ret = GetBufferSizeAndDimensions(info, &buffer_size, &aligned_width, &aligned_height);
301   if (ret < 0) {
302     return 0;
303   }
304   return buffer_size;
305 }
306 
SetBufferInfo(LayerBufferFormat format,int * target,uint64_t * flags)307 int HWCBufferAllocator::SetBufferInfo(LayerBufferFormat format, int *target, uint64_t *flags) {
308   switch (format) {
309     case kFormatRGBA8888:
310       *target = HAL_PIXEL_FORMAT_RGBA_8888;
311       break;
312     case kFormatRGBX8888:
313       *target = HAL_PIXEL_FORMAT_RGBX_8888;
314       break;
315     case kFormatRGB888:
316       *target = HAL_PIXEL_FORMAT_RGB_888;
317       break;
318     case kFormatRGB565:
319       *target = HAL_PIXEL_FORMAT_RGB_565;
320       break;
321     case kFormatBGR565:
322       *target = HAL_PIXEL_FORMAT_BGR_565;
323       break;
324     case kFormatBGR888:
325       *target = HAL_PIXEL_FORMAT_BGR_888;
326       break;
327     case kFormatBGRA8888:
328       *target = HAL_PIXEL_FORMAT_BGRA_8888;
329       break;
330     case kFormatYCrCb420PlanarStride16:
331       *target = HAL_PIXEL_FORMAT_YV12;
332       break;
333     case kFormatYCrCb420SemiPlanar:
334       *target = HAL_PIXEL_FORMAT_YCrCb_420_SP;
335       break;
336     case kFormatYCbCr420SemiPlanar:
337       *target = HAL_PIXEL_FORMAT_YCbCr_420_SP;
338       break;
339     case kFormatYCbCr422H2V1Packed:
340       *target = HAL_PIXEL_FORMAT_YCbCr_422_I;
341       break;
342     case kFormatCbYCrY422H2V1Packed:
343       *target = HAL_PIXEL_FORMAT_CbYCrY_422_I;
344       break;
345     case kFormatYCbCr422H2V1SemiPlanar:
346       *target = HAL_PIXEL_FORMAT_YCbCr_422_SP;
347       break;
348     case kFormatYCbCr420SemiPlanarVenus:
349       *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS;
350       break;
351     case kFormatYCrCb420SemiPlanarVenus:
352       *target = HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS;
353       break;
354     case kFormatYCbCr420SPVenusUbwc:
355     case kFormatYCbCr420SPVenusTile:
356       *target = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC;
357       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
358       break;
359     case kFormatRGBA5551:
360       *target = HAL_PIXEL_FORMAT_RGBA_5551;
361       break;
362     case kFormatRGBA4444:
363       *target = HAL_PIXEL_FORMAT_RGBA_4444;
364       break;
365     case kFormatRGBA1010102:
366       *target = HAL_PIXEL_FORMAT_RGBA_1010102;
367       break;
368     case kFormatARGB2101010:
369       *target = HAL_PIXEL_FORMAT_ARGB_2101010;
370       break;
371     case kFormatRGBX1010102:
372       *target = HAL_PIXEL_FORMAT_RGBX_1010102;
373       break;
374     case kFormatXRGB2101010:
375       *target = HAL_PIXEL_FORMAT_XRGB_2101010;
376       break;
377     case kFormatBGRA1010102:
378       *target = HAL_PIXEL_FORMAT_BGRA_1010102;
379       break;
380     case kFormatABGR2101010:
381       *target = HAL_PIXEL_FORMAT_ABGR_2101010;
382       break;
383     case kFormatBGRX1010102:
384       *target = HAL_PIXEL_FORMAT_BGRX_1010102;
385       break;
386     case kFormatXBGR2101010:
387       *target = HAL_PIXEL_FORMAT_XBGR_2101010;
388       break;
389     case kFormatYCbCr420P010:
390       *target = HAL_PIXEL_FORMAT_YCbCr_420_P010;
391       break;
392     case kFormatYCbCr420TP10Ubwc:
393     case kFormatYCbCr420TP10Tile:
394       *target = HAL_PIXEL_FORMAT_YCbCr_420_TP10_UBWC;
395       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
396       break;
397     case kFormatYCbCr420P010Ubwc:
398     case kFormatYCbCr420P010Tile:
399       *target = HAL_PIXEL_FORMAT_YCbCr_420_P010_UBWC;
400       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
401       break;
402     case kFormatYCbCr420P010Venus:
403       *target = HAL_PIXEL_FORMAT_YCbCr_420_P010_VENUS;
404       break;
405     case kFormatRGBA8888Ubwc:
406       *target = HAL_PIXEL_FORMAT_RGBA_8888;
407       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
408       break;
409     case kFormatRGBX8888Ubwc:
410       *target = HAL_PIXEL_FORMAT_RGBX_8888;
411       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
412       break;
413     case kFormatBGR565Ubwc:
414       *target = HAL_PIXEL_FORMAT_BGR_565;
415       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
416       break;
417     case kFormatRGBA1010102Ubwc:
418       *target = HAL_PIXEL_FORMAT_RGBA_1010102;
419       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
420       break;
421     case kFormatRGBX1010102Ubwc:
422       *target = HAL_PIXEL_FORMAT_RGBX_1010102;
423       *flags |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
424       break;
425     default:
426       DLOGE("Unsupported format = 0x%x", format);
427       return -EINVAL;
428   }
429   return 0;
430 }
431 
GetAllocatedBufferInfo(const BufferConfig & buffer_config,AllocatedBufferInfo * allocated_buffer_info)432 DisplayError HWCBufferAllocator::GetAllocatedBufferInfo(
433     const BufferConfig &buffer_config, AllocatedBufferInfo *allocated_buffer_info) {
434   // TODO(user): This API should pass the buffer_info of the already allocated buffer
435   // The private_data can then be typecast to the private_handle and used directly.
436   uint64_t alloc_flags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
437 
438   int width = INT(buffer_config.width);
439   int height = INT(buffer_config.height);
440   int format;
441 
442   if (buffer_config.secure) {
443     alloc_flags |= INT(GRALLOC_USAGE_PROTECTED);
444   }
445 
446   if (!buffer_config.cache) {
447     // Allocate uncached buffers
448     alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
449   }
450 
451   if (SetBufferInfo(buffer_config.format, &format, &alloc_flags) < 0) {
452     return kErrorParameters;
453   }
454 
455   uint32_t aligned_width = 0, aligned_height = 0, buffer_size = 0;
456   gralloc::BufferInfo info(width, height, format, alloc_flags);
457   int ret = GetBufferSizeAndDimensions(info, &buffer_size, &aligned_width, &aligned_height);
458   if (ret < 0) {
459     return kErrorParameters;
460   }
461   allocated_buffer_info->stride = UINT32(aligned_width);
462   allocated_buffer_info->aligned_width = UINT32(aligned_width);
463   allocated_buffer_info->aligned_height = UINT32(aligned_height);
464   allocated_buffer_info->size = UINT32(buffer_size);
465 
466   return kErrorNone;
467 }
468 
GetBufferLayout(const AllocatedBufferInfo & buf_info,uint32_t stride[4],uint32_t offset[4],uint32_t * num_planes)469 DisplayError HWCBufferAllocator::GetBufferLayout(const AllocatedBufferInfo &buf_info,
470                                                  uint32_t stride[4], uint32_t offset[4],
471                                                  uint32_t *num_planes) {
472   // TODO(user): Transition APIs to not need a private handle
473   private_handle_t hnd(-1, 0, 0, 0, 0, 0, 0);
474   int format = HAL_PIXEL_FORMAT_RGBA_8888;
475   uint64_t flags = 0;
476 
477   SetBufferInfo(buf_info.format, &format, &flags);
478   // Setup only the required stuff, skip rest
479   hnd.format = format;
480   hnd.width = INT32(buf_info.aligned_width);
481   hnd.height = INT32(buf_info.aligned_height);
482   if (flags & GRALLOC_USAGE_PRIVATE_ALLOC_UBWC) {
483     hnd.flags = private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
484   }
485 
486   int ret = gralloc::GetBufferLayout(&hnd, stride, offset, num_planes);
487   if (ret < 0) {
488     DLOGE("GetBufferLayout failed");
489     return kErrorParameters;
490   }
491 
492   return kErrorNone;
493 }
494 
MapBuffer(const private_handle_t * handle,int acquire_fence)495 DisplayError HWCBufferAllocator::MapBuffer(const private_handle_t *handle, int acquire_fence) {
496   auto err = GetGrallocInstance();
497   if (err != kErrorNone) {
498     return err;
499   }
500   NATIVE_HANDLE_DECLARE_STORAGE(acquire_fence_storage, 1, 0);
501   hidl_handle acquire_fence_handle;
502   if (acquire_fence >= 0) {
503     auto h = native_handle_init(acquire_fence_storage, 1, 0);
504     h->data[0] = acquire_fence;
505     acquire_fence_handle = h;
506   }
507 
508   auto hnd = const_cast<private_handle_t *>(handle);
509   void *buffer_ptr = NULL;
510   if (mapper_V3_ != nullptr) {
511     const IMapperV3::Rect access_region = {.left = 0, .top = 0, .width = 0, .height = 0};
512     mapper_V3_->lock(
513         reinterpret_cast<void *>(hnd), (uint64_t)BufferUsage::CPU_READ_OFTEN, access_region,
514         acquire_fence_handle,
515         [&](const auto &_error, const auto &_buffer, const auto &_bpp, const auto &_stride) {
516           if (_error == MapperV3Error::NONE) {
517             buffer_ptr = _buffer;
518           }
519         });
520   } else {
521     const IMapperV2::Rect access_region = {.left = 0, .top = 0, .width = 0, .height = 0};
522     mapper_V2_->lock(reinterpret_cast<void *>(hnd), (uint64_t)BufferUsage::CPU_READ_OFTEN,
523                      access_region, acquire_fence_handle,
524                      [&](const auto &_error, const auto &_buffer) {
525                        if (_error == Error::NONE) {
526                          buffer_ptr = _buffer;
527                        }
528                      });
529   }
530   if (!buffer_ptr) {
531     return kErrorUndefined;
532   }
533   return kErrorNone;
534 }
535 
UnmapBuffer(const private_handle_t * handle,int * release_fence)536 DisplayError HWCBufferAllocator::UnmapBuffer(const private_handle_t *handle, int *release_fence) {
537   DisplayError err = kErrorNone;
538   *release_fence = -1;
539   auto hnd = const_cast<private_handle_t *>(handle);
540   if (mapper_V3_ != nullptr) {
541     mapper_V3_->unlock(reinterpret_cast<void *>(hnd),
542                        [&](const auto &_error, const auto &_release_fence) {
543                          if (_error != MapperV3Error::NONE) {
544                            err = kErrorUndefined;
545                          }
546                        });
547   } else {
548     mapper_V2_->unlock(reinterpret_cast<void *>(hnd),
549                        [&](const auto &_error, const auto &_release_fence) {
550                          if (_error != Error::NONE) {
551                            err = kErrorUndefined;
552                          }
553                        });
554   }
555   return err;
556 }
557 
558 }  // namespace sdm
559