• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "memory/rs_tag_tracker.h"
17 #include "native_buffer_utils.h"
18 #include "platform/common/rs_log.h"
19 #include "render_context/render_context.h"
20 #include "pipeline/sk_resource_manager.h"
21 
22 namespace OHOS::Rosen {
23 namespace NativeBufferUtils {
DeleteVkImage(void * context)24 void DeleteVkImage(void* context)
25 {
26     VulkanCleanupHelper* cleanupHelper = static_cast<VulkanCleanupHelper*>(context);
27     if (cleanupHelper != nullptr) {
28         cleanupHelper->UnRef();
29     }
30 }
31 
GetNativeBufferFormatProperties(RsVulkanContext & vkContext,VkDevice device,OH_NativeBuffer * nativeBuffer,VkNativeBufferFormatPropertiesOHOS * nbFormatProps,VkNativeBufferPropertiesOHOS * nbProps)32 bool GetNativeBufferFormatProperties(RsVulkanContext& vkContext, VkDevice device, OH_NativeBuffer* nativeBuffer,
33                                      VkNativeBufferFormatPropertiesOHOS* nbFormatProps,
34                                      VkNativeBufferPropertiesOHOS* nbProps)
35 {
36     if (!nbFormatProps || !nbProps) {
37         RS_LOGE("GetNativeBufferFormatProperties failed!");
38         return false;
39     }
40     nbFormatProps->sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_FORMAT_PROPERTIES_OHOS;
41     nbFormatProps->pNext = nullptr;
42 
43     nbProps->sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_PROPERTIES_OHOS;
44     nbProps->pNext = nbFormatProps;
45 
46     VkResult err = vkContext.GetRsVulkanInterface().vkGetNativeBufferPropertiesOHOS(device, nativeBuffer, nbProps);
47     if (VK_SUCCESS != err) {
48         ROSEN_LOGE("NativeBufferUtils: vkGetNativeBufferPropertiesOHOS Failed ! %{public}d", err);
49         return false;
50     }
51     return true;
52 }
53 
CreateVkImage(RsVulkanContext & vkContext,VkImage * image,const VkNativeBufferFormatPropertiesOHOS & nbFormatProps,const VkExtent3D & imageSize,VkImageUsageFlags usageFlags=0,bool isProtected=false)54 bool CreateVkImage(RsVulkanContext& vkContext, VkImage* image,
55     const VkNativeBufferFormatPropertiesOHOS& nbFormatProps, const VkExtent3D& imageSize,
56     VkImageUsageFlags usageFlags = 0, bool isProtected = false)
57 {
58     VkExternalFormatOHOS externalFormat;
59     externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_OHOS;
60     externalFormat.pNext = nullptr;
61     externalFormat.externalFormat = 0;
62 
63     if (nbFormatProps.format == VK_FORMAT_UNDEFINED) {
64         externalFormat.externalFormat = nbFormatProps.externalFormat;
65     }
66 
67     const VkExternalMemoryImageCreateInfo externalMemoryImageInfo {
68         VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, // sType
69         &externalFormat, // pNext
70         VK_EXTERNAL_MEMORY_HANDLE_TYPE_OHOS_NATIVE_BUFFER_BIT_OHOS, // handleTypes
71     };
72 
73     VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
74 
75     VkImageCreateFlags flags = isProtected ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
76 
77     const VkImageCreateInfo imageCreateInfo = {
78         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
79         &externalMemoryImageInfo,
80         flags,
81         VK_IMAGE_TYPE_2D,
82         nbFormatProps.format,
83         imageSize,
84         1,
85         1,
86         VK_SAMPLE_COUNT_1_BIT,
87         tiling,
88         usageFlags,
89         VK_SHARING_MODE_EXCLUSIVE,
90         0,
91         0,
92         VK_IMAGE_LAYOUT_UNDEFINED,
93     };
94 
95     if (imageSize.width != 0 && imageSize.height != 0 &&
96         imageSize.depth > VKIMAGE_LIMIT_SIZE / imageSize.width / imageSize.height) {
97         ROSEN_LOGE("NativeBufferUtils: vkCreateImag failed, image is too large, width:%{public}u, height::%{public}u,"
98                    "depth::%{public}u",
99             imageSize.width, imageSize.height, imageSize.depth);
100         return false;
101     }
102 
103     VkResult err = vkContext.GetRsVulkanInterface().vkCreateImage(vkContext.GetDevice(),
104         &imageCreateInfo, nullptr, image);
105     if (err != VK_SUCCESS) {
106         ROSEN_LOGE("NativeBufferUtils: vkCreateImage failed");
107         return false;
108     }
109     return true;
110 }
111 
AllocateDeviceMemory(RsVulkanContext & vkContext,VkDeviceMemory * memory,VkImage & image,OH_NativeBuffer * nativeBuffer,VkNativeBufferPropertiesOHOS & nbProps,bool isProtected)112 bool AllocateDeviceMemory(RsVulkanContext& vkContext, VkDeviceMemory* memory, VkImage& image,
113     OH_NativeBuffer* nativeBuffer, VkNativeBufferPropertiesOHOS& nbProps, bool isProtected)
114 {
115     VkPhysicalDeviceMemoryProperties2 physicalDeviceMemProps;
116     physicalDeviceMemProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
117     physicalDeviceMemProps.pNext = nullptr;
118     auto& vkInterface = vkContext.GetRsVulkanInterface();
119 
120     uint32_t foundTypeIndex = 0;
121     VkDevice device = vkInterface.GetDevice();
122     VkPhysicalDevice physicalDevice = vkInterface.GetPhysicalDevice();
123     vkInterface.vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &physicalDeviceMemProps);
124     uint32_t memTypeCnt = physicalDeviceMemProps.memoryProperties.memoryTypeCount;
125     bool found = false;
126     for (uint32_t i = 0; i < memTypeCnt; ++i) {
127         if (nbProps.memoryTypeBits & (1 << i)) {
128             const VkPhysicalDeviceMemoryProperties& pdmp = physicalDeviceMemProps.memoryProperties;
129             uint32_t supportedFlags = pdmp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
130             if (supportedFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
131                 foundTypeIndex = i;
132                 found = true;
133                 break;
134             }
135         }
136     }
137     if (!found) {
138         ROSEN_LOGE("NativeBufferUtils: no fit memory type, memoryTypeBits is %{public}u", nbProps.memoryTypeBits);
139         vkInterface.vkDestroyImage(device, image, nullptr);
140         return false;
141     }
142 
143     VkImportNativeBufferInfoOHOS nbImportInfo;
144     nbImportInfo.sType = VK_STRUCTURE_TYPE_IMPORT_NATIVE_BUFFER_INFO_OHOS;
145     nbImportInfo.pNext = nullptr;
146     nbImportInfo.buffer = nativeBuffer;
147 
148     VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
149     dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
150     dedicatedAllocInfo.pNext = &nbImportInfo;
151     dedicatedAllocInfo.image = image;
152     dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
153 
154     VkMemoryAllocateInfo allocInfo = {
155         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, &dedicatedAllocInfo, nbProps.allocationSize, foundTypeIndex,
156     };
157 
158     VkResult err = vkInterface.vkAllocateMemory(device, &allocInfo, nullptr, memory);
159     if (err != VK_SUCCESS) {
160         vkInterface.vkDestroyImage(device, image, nullptr);
161         ROSEN_LOGE("NativeBufferUtils: vkAllocateMemory Fail");
162         return false;
163     }
164     return true;
165 }
166 
BindImageMemory(VkDevice device,RsVulkanContext & vkContext,VkImage & image,VkDeviceMemory & memory)167 bool BindImageMemory(VkDevice device, RsVulkanContext& vkContext, VkImage& image, VkDeviceMemory& memory)
168 {
169     auto& vkInterface = vkContext.GetRsVulkanInterface();
170     VkBindImageMemoryInfo bindImageInfo;
171     bindImageInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
172     bindImageInfo.pNext = nullptr;
173     bindImageInfo.image = image;
174     bindImageInfo.memory = memory;
175     bindImageInfo.memoryOffset = 0;
176 
177     VkResult err = vkInterface.vkBindImageMemory2(device, 1, &bindImageInfo);
178     if (err != VK_SUCCESS) {
179         ROSEN_LOGE("NativeBufferUtils: vkBindImageMemory2 failed");
180         vkInterface.vkDestroyImage(device, image, nullptr);
181         vkInterface.vkFreeMemory(device, memory, nullptr);
182         return false;
183     }
184     return true;
185 }
186 
MakeFromNativeWindowBuffer(std::shared_ptr<Drawing::GPUContext> skContext,NativeWindowBuffer * nativeWindowBuffer,NativeSurfaceInfo & nativeSurface,int width,int height,bool isProtected)187 bool MakeFromNativeWindowBuffer(std::shared_ptr<Drawing::GPUContext> skContext, NativeWindowBuffer* nativeWindowBuffer,
188     NativeSurfaceInfo& nativeSurface, int width, int height, bool isProtected)
189 {
190     OH_NativeBuffer* nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(nativeWindowBuffer);
191     if (nativeBuffer == nullptr) {
192         ROSEN_LOGE("MakeFromNativeWindowBuffer: OH_NativeBufferFromNativeWindowBuffer failed");
193         return false;
194     }
195 
196     auto& vkContext = RsVulkanContext::GetSingleton();
197 
198     VkDevice device = vkContext.GetDevice();
199 
200     VkNativeBufferFormatPropertiesOHOS nbFormatProps;
201     VkNativeBufferPropertiesOHOS nbProps;
202     if (!GetNativeBufferFormatProperties(vkContext, device, nativeBuffer, &nbFormatProps, &nbProps)) {
203         return false;
204     }
205 
206     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
207     if (nbFormatProps.format != VK_FORMAT_UNDEFINED) {
208         usageFlags = usageFlags | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT
209             | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
210     }
211 
212     VkImage image;
213     if (!CreateVkImage(vkContext, &image, nbFormatProps, {width, height, 1}, usageFlags, isProtected)) {
214         return false;
215     }
216 
217     VkDeviceMemory memory;
218     if (!AllocateDeviceMemory(vkContext, &memory, image, nativeBuffer, nbProps, isProtected)) {
219         return false;
220     }
221 
222     if (!BindImageMemory(device, vkContext, image, memory)) {
223         return false;
224     }
225 
226     auto colorSpace = RenderContext::ConvertColorGamutToColorSpace(nativeSurface.graphicColorGamut);
227     Drawing::TextureInfo texture_info;
228     texture_info.SetWidth(width);
229     texture_info.SetHeight(height);
230     std::shared_ptr<Drawing::VKTextureInfo> vkTextureInfo = std::make_shared<Drawing::VKTextureInfo>();
231     vkTextureInfo->vkImage = image;
232     vkTextureInfo->vkAlloc.memory = memory;
233     vkTextureInfo->vkAlloc.size = npProps.allocationSize;
234     vkTextureInfo->vkAlloc.source = Drawing::VKMemSource::EXTERNAL;
235     vkTextureInfo->imageTiling = VK_IMAGE_TILING_OPTIMAL;
236     vkTextureInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
237     vkTextureInfo->format = nbFormatProps.format;
238     vkTextureInfo->imageUsageFlags = usageFlags;
239     vkTextureInfo->sampleCount = 1;
240     vkTextureInfo->levelCount = 1;
241     vkTextureInfo->vkProtected = isProtected;
242     texture_info.SetVKTextureInfo(vkTextureInfo);
243 
244     Drawing::ColorType colorType = Drawing::ColorType::COLORTYPE_RGBA_8888;
245     if (nbFormatProps.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32) {
246         colorType = Drawing::ColorType::COLORTYPE_RGBA_1010102;
247     }
248 
249     nativeSurface.drawingSurface = Drawing::Surface::MakeFromBackendTexture(
250         skContext.get(),
251         texture_info,
252         Drawing::TextureOrigin::TOP_LEFT,
253         1,
254         colorType,
255         colorSpace,
256         DeleteVkImage,
257         new VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
258             image, memory));
259     if (nativeSurface.drawingSurface) {
260         SKResourceManager::Instance().HoldResource(nativeSurface.drawingSurface);
261     }
262 
263     nativeSurface.image = image;
264     if (nativeSurface.nativeWindowBuffer != nullptr) {
265         NativeObjectUnreference(nativeSurface.nativeWindowBuffer);
266     }
267     NativeObjectReference(nativeWindowBuffer);
268     nativeSurface.nativeWindowBuffer = nativeWindowBuffer;
269 
270     return true;
271 }
272 
GetYcbcrInfo(VkNativeBufferFormatPropertiesOHOS & nbFormatProps)273 GrVkYcbcrConversionInfo GetYcbcrInfo(VkNativeBufferFormatPropertiesOHOS& nbFormatProps)
274 {
275     GrVkYcbcrConversionInfo ycbcrInfo = {
276         .fFormat = nbFormatProps.format,
277         .fExternalFormat = nbFormatProps.externalFormat,
278         .fYcbcrModel = nbFormatProps.suggestedYcbcrModel,
279         .fYcbcrRange = nbFormatProps.suggestedYcbcrRange,
280         .fXChromaOffset = nbFormatProps.suggestedXChromaOffset,
281         .fYChromaOffset = nbFormatProps.suggestedYChromaOffset,
282         .fChromaFilter = VK_FILTER_NEAREST,
283         .fForceExplicitReconstruction = VK_FALSE,
284         .fFormatFeatures = nbFormatProps.formatFeatures
285     };
286 
287     if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT & nbFormatProps.formatFeatures) {
288         ycbcrInfo.fChromaFilter = VK_FILTER_LINEAR;
289     }
290     return ycbcrInfo;
291 }
292 
MakeBackendTextureFromNativeBuffer(NativeWindowBuffer * nativeWindowBuffer,int width,int height,bool isProtected)293 Drawing::BackendTexture MakeBackendTextureFromNativeBuffer(NativeWindowBuffer* nativeWindowBuffer,
294     int width, int height, bool isProtected)
295 {
296     OH_NativeBuffer* nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(nativeWindowBuffer);
297     if (!nativeBuffer) {
298         ROSEN_LOGE("MakeBackendTextureFromNativeBuffer: OH_NativeBufferFromNativeWindowBuffer failed");
299         return {};
300     }
301 
302     auto& vkContext = RsVulkanContext::GetSingleton();
303     VkDevice device = vkContext.GetDevice();
304 
305     VkNativeBufferFormatPropertiesOHOS nbFormatProps;
306     VkNativeBufferPropertiesOHOS nbProps;
307     if (!GetNativeBufferFormatProperties(vkContext, device, nativeBuffer, &nbFormatProps, &nbProps)) {
308         return {};
309     }
310 
311     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
312     if (nbFormatProps.format != VK_FORMAT_UNDEFINED) {
313         usageFlags = usageFlags | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
314     }
315 
316     VkImage image;
317     if (!CreateVkImage(vkContext, &image, nbFormatProps, {width, height, 1}, usageFlags, isProtected)) {
318         return {};
319     }
320 
321     VkDeviceMemory memory;
322     if (!AllocateDeviceMemory(vkContext, &memory, image, nativeBuffer, nbProps, isProtected)) {
323         return {};
324     }
325 
326     if (!BindImageMemory(device, vkContext, image, memory)) {
327         return {};
328     }
329 
330     Drawing::BackendTexture backendTexture(true);
331     Drawing::TextureInfo textureInfo;
332     textureInfo.SetWidth(width);
333     textureInfo.SetHeight(height);
334 
335     std::shared_ptr<Drawing::VKTextureInfo> imageInfo = std::make_shared<Drawing::VKTextureInfo>();
336     imageInfo->vkImage = image;
337     imageInfo->vkAlloc.memory = memory;
338     imageInfo->vkAlloc.size = npProps.allocationSize;
339     imageInfo->vkAlloc.source = Drawing::VKMemSource::EXTERNAL;
340     imageInfo->vkProtected = isProtected ? true : false;
341     imageInfo->imageTiling = VK_IMAGE_TILING_OPTIMAL;
342     imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
343     imageInfo->format = nbFormatProps.format;
344     imageInfo->imageUsageFlags = usageFlags;
345     imageInfo->levelCount = 1;
346     imageInfo->currentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
347     imageInfo->ycbcrConversionInfo.format = nbFormatProps.format;
348     imageInfo->ycbcrConversionInfo.externalFormat = nbFormatProps.externalFormat;
349     imageInfo->ycbcrConversionInfo.ycbcrModel = nbFormatProps.suggestedYcbcrModel;
350     imageInfo->ycbcrConversionInfo.ycbcrRange = nbFormatProps.suggestedYcbcrRange;
351     imageInfo->ycbcrConversionInfo.xChromaOffset = nbFormatProps.suggestedXChromaOffset;
352     imageInfo->ycbcrConversionInfo.yChromaOffset = nbFormatProps.suggestedYChromaOffset;
353     imageInfo->ycbcrConversionInfo.chromaFilter = VK_FILTER_NEAREST;
354     imageInfo->ycbcrConversionInfo.forceExplicitReconstruction = VK_FALSE;
355     imageInfo->ycbcrConversionInfo.formatFeatures = nbFormatProps.formatFeatures;
356     if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT & nbFormatProps.formatFeatures) {
357         imageInfo->ycbcrConversionInfo.chromaFilter = VK_FILTER_LINEAR;
358     }
359     imageInfo->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
360 
361     textureInfo.SetVKTextureInfo(imageInfo);
362     backendTexture.SetTextureInfo(textureInfo);
363     return backendTexture;
364 }
365 
CreateFromNativeWindowBuffer(Drawing::GPUContext * gpuContext,const Drawing::ImageInfo & imageInfo,NativeSurfaceInfo & nativeSurface)366 std::shared_ptr<Drawing::Surface> CreateFromNativeWindowBuffer(Drawing::GPUContext* gpuContext,
367     const Drawing::ImageInfo& imageInfo, NativeSurfaceInfo& nativeSurface)
368 {
369     OH_NativeBuffer* nativeBuffer = OH_NativeBufferFromNativeWindowBuffer(nativeSurface.nativeWindowBuffer);
370     if (nativeBuffer == nullptr) {
371         ROSEN_LOGE("CreateFromNativeWindowBuffer: OH_NativeBufferFromNativeWindowBuffer failed");
372         return nullptr;
373     }
374 
375     auto& vkContext = RsVulkanContext::GetSingleton();
376 
377     VkDevice device = vkContext.GetDevice();
378 
379     VkNativeBufferFormatPropertiesOHOS nbFormatProps;
380     VkNativeBufferPropertiesOHOS nbProps;
381     if (!GetNativeBufferFormatProperties(vkContext, device, nativeBuffer, &nbFormatProps, &nbProps)) {
382         return nullptr;
383     }
384 
385     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
386     if (nbFormatProps.format != VK_FORMAT_UNDEFINED) {
387         usageFlags = usageFlags | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT
388             | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
389     }
390 
391     VkImage image;
392     if (!CreateVkImage(vkContext, &image, nbFormatProps, {imageInfo.GetWidth(), imageInfo.GetHeight(), 1},
393         usageFlags, false)) {
394         return nullptr;
395     }
396 
397     VkDeviceMemory memory;
398     if (!AllocateDeviceMemory(vkContext, &memory, image, nativeBuffer, nbProps, false)) {
399         return nullptr;
400     }
401 
402     if (!BindImageMemory(device, vkContext, image, memory)) {
403         return nullptr;
404     }
405 
406     Drawing::TextureInfo texture_info;
407     texture_info.SetWidth(imageInfo.GetWidth());
408     texture_info.SetHeight(imageInfo.GetHeight());
409     std::shared_ptr<Drawing::VKTextureInfo> vkTextureInfo = std::make_shared<Drawing::VKTextureInfo>();
410     vkTextureInfo->vkImage = image;
411     vkTextureInfo->vkAlloc.memory = memory;
412     vkTextureInfo->vkAlloc.size = npProps.allocationSize;
413     vkTextureInfo->vkAlloc.source = Drawing::VKMemSource::EXTERNAL;
414     vkTextureInfo->imageTiling = VK_IMAGE_TILING_OPTIMAL;
415     vkTextureInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
416     vkTextureInfo->format = nbFormatProps.format;
417     vkTextureInfo->imageUsageFlags = usageFlags;
418     vkTextureInfo->sampleCount = 1;
419     vkTextureInfo->levelCount = 1;
420     vkTextureInfo->vkProtected = false;
421     texture_info.SetVKTextureInfo(vkTextureInfo);
422 
423     std::shared_ptr<Drawing::Surface> surface = Drawing::Surface::MakeFromBackendTexture(
424         gpuContext,
425         texture_info,
426         Drawing::TextureOrigin::TOP_LEFT,
427         1,
428         imageInfo.GetColorType(),
429         Drawing::ColorSpace::CreateSRGB(),
430         DeleteVkImage,
431         new VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
432             image, memory));
433 
434     nativeSurface.image = image;
435     return surface;
436 }
437 } // namespace NativeBufferUtils
438 } // namespace OHOS::Rosen
439