已合并
补充arkts1.2剪贴板权限弹窗 #77867
SprucEovo创建于 2025年12月16日
补充arkts1.2剪贴板权限弹窗 #77867
已合并
SprucEovo创建于 2025年12月16日
9 个文件变更+115-3
@@ -62,7 +62,7 @@ static void GetCommonFunc(ani_vm* vm, ani_ref savePtr,
62 webviewControllerPeer->releaseRefFunc = std::move(releaseRefFunc);62 webviewControllerPeer->releaseRefFunc = std::move(releaseRefFunc);
63}63}
64 64 
65-static bool GetFileSelectorObject(ani_env* env, const char* classDesc, ani_object* obj, void* args)65+static bool GetObjectFromPtr(ani_env* env, const char* classDesc, ani_object* obj, void* args)
66{66{
67 ani_class cls;67 ani_class cls;
68 if (env->FindClass(classDesc, &cls) != ANI_OK) {68 if (env->FindClass(classDesc, &cls) != ANI_OK) {
@@ -92,13 +92,13 @@ static void DefaultOnShowFileSelector(ani_vm* vm, void* paramPeer, void* resultP
92 return;92 return;
93 }93 }
94 ani_object paramObj;94 ani_object paramObj;
95- if (!GetFileSelectorObject(env, "arkui.component.web.FileSelectorParam", &paramObj, paramPeer)) {95+ if (!GetObjectFromPtr(env, "arkui.component.web.FileSelectorParam", &paramObj, paramPeer)) {
96 release(paramPeer);96 release(paramPeer);
97 release(resultPeer);97 release(resultPeer);
98 return;98 return;
99 }99 }
100 ani_object resultObj;100 ani_object resultObj;
101- if (!GetFileSelectorObject(env, "arkui.component.web.FileSelectorResult", &resultObj, resultPeer)) {101+ if (!GetObjectFromPtr(env, "arkui.component.web.FileSelectorResult", &resultObj, resultPeer)) {
102 release(resultPeer);102 release(resultPeer);
103 return;103 return;
104 }104 }
@@ -130,6 +130,39 @@ static void DefaultOnShowFileSelector(ani_vm* vm, void* paramPeer, void* resultP
130 HILOGI("Call defaultOnShowFileSelector done");130 HILOGI("Call defaultOnShowFileSelector done");
131}131}
132 132 
133+static void DefaultPermissionClipboard(ani_vm* vm, void* peer, std::function<void()> release)
arkui-feature-manager
arkui-feature-managerarkui-feature-manager2025年12月16日

🤖 AI 代码检视意见(回复本评论可解决检视意见,点击被检视代码行左侧的小头像可收起检视意见)


🟠 资源泄漏:错误路径未调用release函数

位置: L133-L164 | 严重程度: High

❓ 问题描述

DefaultPermissionClipboard函数在第148和153行的FindClass和Class_FindStaticMethod失败时,直接return而没有调用之前传入的release函数,这可能导致资源泄漏。与DefaultOnShowFileSelector函数的错误处理不一致(后者在所有错误路径都调用了release)。

💡 修复建议

在所有错误路径中添加release()调用:

static void DefaultPermissionClipboard(ani_vm* vm, void* peer, std::function<void()> release)
{
    HILOGI("Call defaultPermissionClipboard start");
    ani_env* env = GetAniEnv(vm);
    if (!env) {
        HILOGE("DefaultPermissionClipboard callback env is nullptr");
        release();
        return;
    }
    ani_object obj;
    if (!GetObjectFromPtr(env, "arkui.component.web.PermissionRequest", &obj, peer)) {
        release();
        return;
    }
    ani_class cls;
    if (env->FindClass("@ohos.web.permissionRequest.PermissionClipboard", &cls) != ANI_OK) {
        HILOGE("FindClass fail: PermissionClipboard");
        release(); // 添加此行
        return;
    }
    ani_static_method method;
    if (env->Class_FindStaticMethod(cls, "defaultPermissionClipboard",
                                    "C{arkui.component.web.PermissionRequest}:",
                                    &method) != ANI_OK) {
        HILOGE("Class_FindStaticMethod fail, defaultPermissionClipboard");
        release(); // 添加此行
        return;
    }
    if (env->Class_CallStaticMethod_Void(cls, method, obj) != ANI_OK) {
        HILOGE("Call defaultPermissionClipboard fail");
        release(); // 添加此行
        return;
    }
    HILOGI("Call defaultPermissionClipboard done");
}

likedislike
134+{
135+ HILOGI("Call defaultPermissionClipboard start");
136+ ani_env* env = GetAniEnv(vm);
137+ if (!env) {
138+ HILOGE("DefaultPermissionClipboard callback env is nullptr");
139+ release();
140+ return;
141+ }
142+ ani_object obj;
143+ if (!GetObjectFromPtr(env, "arkui.component.web.PermissionRequest", &obj, peer)) {
144+ release();
145+ return;
146+ }
147+ ani_class cls;
148+ if (env->FindClass("@ohos.web.permissionRequest.PermissionClipboard", &cls) != ANI_OK) {
149+ HILOGE("FindClass fail: PermissionClipboard");
150+ return;
151+ }
152+ ani_static_method method;
153+ if (env->Class_FindStaticMethod(cls, "defaultPermissionClipboard",
154+ "C{arkui.component.web.PermissionRequest}:",
155+ &method) != ANI_OK) {
156+ HILOGE("Class_FindStaticMethod fail, defaultPermissionClipboard");
157+ return;
158+ }
159+ if (env->Class_CallStaticMethod_Void(cls, method, obj) != ANI_OK) {
160+ HILOGE("Call defaultPermissionClipboard fail");
161+ return;
162+ }
163+ HILOGI("Call defaultPermissionClipboard done");
164+}
165+ 
133static void GetWebOptionsFunc(ani_vm* vm, ani_ref savePtr,166static void GetWebOptionsFunc(ani_vm* vm, ani_ref savePtr,
134 WebviewControllerPeer* webviewControllerPeer)167 WebviewControllerPeer* webviewControllerPeer)
135{168{
@@ -167,10 +200,14 @@ static void GetWebOptionsFunc(ani_vm* vm, ani_ref savePtr,
167 auto defaultOnShowFileSelectorFunc = [vm](void* paramPeer, void* resultPeer, std::function<void(void*)> release) {200 auto defaultOnShowFileSelectorFunc = [vm](void* paramPeer, void* resultPeer, std::function<void(void*)> release) {
168 DefaultOnShowFileSelector(vm, paramPeer, resultPeer, std::move(release));201 DefaultOnShowFileSelector(vm, paramPeer, resultPeer, std::move(release));
169 };202 };
203+ auto defaultPermissionClipboardFunc = [vm](void* peer, std::function<void()> release) {
arkui-feature-manager
arkui-feature-managerarkui-feature-manager2025年12月16日

🤖 AI 代码检视意见(回复本评论可解决检视意见,点击被检视代码行左侧的小头像可收起检视意见)


🟡 潜在空指针解引用:未检查回调有效性

位置: L203-L205 | 严重程度: Medium

❓ 问题描述

在GetWebOptionsFunc中创建defaultPermissionClipboardFunc时,没有检查controller->defaultPermissionClipboardFunc是否为null,如果为null则后续调用会导致未定义行为。

💡 修复建议

添加null检查:

if (controller->defaultPermissionClipboardFunc) {
    auto defaultPermissionClipboardFunc = [vm](void* peer, std::function<void()> release) {
        DefaultPermissionClipboard(vm, peer, std::move(release));
    };
    webviewControllerPeer->defaultPermissionClipboardFunc = std::move(defaultPermissionClipboardFunc);
} else {
    webviewControllerPeer->defaultPermissionClipboardFunc = nullptr;
}

likedislike
204+ DefaultPermissionClipboard(vm, peer, std::move(release));
205+ };
170 webviewControllerPeer->setWebIdFunc = std::move(setWebIdFunc);206 webviewControllerPeer->setWebIdFunc = std::move(setWebIdFunc);
171 webviewControllerPeer->setHapPathFunc = std::move(setHapPathFunc);207 webviewControllerPeer->setHapPathFunc = std::move(setHapPathFunc);
172 webviewControllerPeer->setWebDetachFunc = std::move(setWebDetachFunc);208 webviewControllerPeer->setWebDetachFunc = std::move(setWebDetachFunc);
173 webviewControllerPeer->defaultOnShowFileSelectorFunc = std::move(defaultOnShowFileSelectorFunc);209 webviewControllerPeer->defaultOnShowFileSelectorFunc = std::move(defaultOnShowFileSelectorFunc);
210+ webviewControllerPeer->defaultPermissionClipboardFunc = std::move(defaultPermissionClipboardFunc);
174}211}
175 212 
176static void GetWebviewControllerHandlerFunc(ani_vm* vm, ani_ref savePtr,213static void GetWebviewControllerHandlerFunc(ani_vm* vm, ani_ref savePtr,
@@ -1034,6 +1034,16 @@ void WebModelStatic::SetPermissionRequestEventId(
1034 webEventHub->SetOnPermissionRequestEvent(std::move(uiCallback));1034 webEventHub->SetOnPermissionRequestEvent(std::move(uiCallback));
1035}1035}
1036 1036 
1037+void WebModelStatic::SetPermissionClipboard(
1038+ FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback)
1039+{
1040+ CHECK_NULL_VOID(frameNode);
1041+ auto uiCallback = [func = callback](const std::shared_ptr<BaseEventInfo>& info) { func(info.get()); };
1042+ auto webPatternStatic = AceType::DynamicCast<WebPatternStatic>(frameNode->GetPattern());
1043+ CHECK_NULL_VOID(webPatternStatic);
1044+ webPatternStatic->SetPermissionClipboardCallback(std::move(uiCallback));
1045+}
1046+ 
1037void WebModelStatic::SetScreenCaptureRequestEventId(1047void WebModelStatic::SetScreenCaptureRequestEventId(
1038 FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback)1048 FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback)
1039{1049{
@@ -149,6 +149,8 @@ public:
149 FrameNode* frameNode, std::function<std::string(const BaseEventInfo* info)>&& callback);149 FrameNode* frameNode, std::function<std::string(const BaseEventInfo* info)>&& callback);
150 static void SetPermissionRequestEventId(150 static void SetPermissionRequestEventId(
151 FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback);151 FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback);
152+ static void SetPermissionClipboard(
153+ FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback);
152 static void SetScreenCaptureRequestEventId(154 static void SetScreenCaptureRequestEventId(
153 FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback);155 FrameNode* frameNode, std::function<void(const BaseEventInfo* info)>&& callback);
154 static void SetOnContextMenuShow(156 static void SetOnContextMenuShow(
@@ -88,6 +88,7 @@ typedef struct webview_WebviewControllerPeer {
88 std::function<void(const std::string&)> setHapPathFunc = nullptr;88 std::function<void(const std::string&)> setHapPathFunc = nullptr;
89 std::function<void(int32_t)> setWebDetachFunc = nullptr;89 std::function<void(int32_t)> setWebDetachFunc = nullptr;
90 std::function<void(void*, void*, std::function<void(void*)>)> defaultOnShowFileSelectorFunc = nullptr;90 std::function<void(void*, void*, std::function<void(void*)>)> defaultOnShowFileSelectorFunc = nullptr;
91+ std::function<void(void*, std::function<void()>)> defaultPermissionClipboardFunc = nullptr;
91} WebviewControllerPeer;92} WebviewControllerPeer;
92 93 
93typedef struct NodeAdapterInfo {94typedef struct NodeAdapterInfo {
@@ -270,6 +270,12 @@ void SetWebOptionsImpl(Ark_NativePointer node,
270 WebAttributeModifier::DefaultOnShowFileSelector(std::move(callback), weakNode, instanceId, info);270 WebAttributeModifier::DefaultOnShowFileSelector(std::move(callback), weakNode, instanceId, info);
271 };271 };
272 WebModelStatic::SetDefaultFileSelectorShow(frameNode, std::move(fileSelectorShowFromUserCallback));272 WebModelStatic::SetDefaultFileSelectorShow(frameNode, std::move(fileSelectorShowFromUserCallback));
273+ auto requestPermissionsFromUserCallback = [callback = std::move(controller->defaultPermissionClipboardFunc),
274+ weakNode = AceType::WeakClaim(frameNode),
275+ instanceId = Container::CurrentId()](const BaseEventInfo* info) {
276+ WebAttributeModifier::DefaultPermissionClipboard(std::move(callback), weakNode, instanceId, info);
277+ };
278+ WebModelStatic::SetPermissionClipboard(frameNode, std::move(requestPermissionsFromUserCallback));
273 /* This controller is only used to pass the hook function for initializing the webviewController.279 /* This controller is only used to pass the hook function for initializing the webviewController.
274 * After passing, the corresponding memory needs to be released.280 * After passing, the corresponding memory needs to be released.
275 */281 */
@@ -401,8 +401,14 @@ void DefaultOnShowFileSelector(const std::function<void(void*, void*, std::funct
401 auto* eventInfo = TypeInfoHelper::DynamicCast<FileSelectorEvent>(info);401 auto* eventInfo = TypeInfoHelper::DynamicCast<FileSelectorEvent>(info);
402 CHECK_NULL_VOID(eventInfo);402 CHECK_NULL_VOID(eventInfo);
403 auto paramPeer = new FileSelectorParamPeer();403 auto paramPeer = new FileSelectorParamPeer();
404+ CHECK_NULL_VOID(paramPeer);
404 paramPeer->handler = eventInfo->GetParam();405 paramPeer->handler = eventInfo->GetParam();
405 auto resultPeer = new FileSelectorResultPeer();406 auto resultPeer = new FileSelectorResultPeer();
407+ if (!resultPeer) {
408+ delete paramPeer;
409+ paramPeer = nullptr;
410+ return;
411+ }
406 resultPeer->handler = eventInfo->GetFileSelectorResult();412 resultPeer->handler = eventInfo->GetFileSelectorResult();
407 auto releaseFunc = [&paramPeer, &resultPeer](void* peer) {413 auto releaseFunc = [&paramPeer, &resultPeer](void* peer) {
408 if (paramPeer == peer) {414 if (paramPeer == peer) {
@@ -595,6 +601,26 @@ void OnPermissionRequest(const CallbackHelper<Callback_OnPermissionRequestEvent_
595 arkCallback.InvokeSync(parameter);601 arkCallback.InvokeSync(parameter);
596}602}
597 603 
604+void DefaultPermissionClipboard(const std::function<void(void*, std::function<void()>)>& callback,
arkui-feature-manager
arkui-feature-managerarkui-feature-manager2025年12月16日

🤖 AI 代码检视意见(回复本评论可解决检视意见,点击被检视代码行左侧的小头像可收起检视意见)


🟠 内存泄漏风险:异常情况下未释放分配的对象

位置: L604-L622 | 严重程度: High

❓ 问题描述

DefaultPermissionClipboard函数在第614行使用new分配了PermissionRequestPeer对象,但在第621行调用callback时,如果callback抛出异常,会导致第614行分配的对象未被释放,造成内存泄漏。虽然代码中有CHECK_NULL_VOID检查,但这并不能防止callback抛出异常。

💡 修复建议

使用RAII模式或try-catch块确保异常安全。建议修改为:

void DefaultPermissionClipboard(const std::function<void(void*, std::function<void()>)>& callback,
    WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info)
{
    CHECK_NULL_VOID(callback);
    ContainerScope scope(instanceId);
    auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
    CHECK_NULL_VOID(pipelineContext);
    pipelineContext->UpdateCurrentActiveNode(weakNode);
    auto* eventInfo = TypeInfoHelper::DynamicCast<WebPermissionRequestEvent>(info);
    CHECK_NULL_VOID(eventInfo);
    
    auto peer = std::make_unique<PermissionRequestPeer>();
    peer->handler = eventInfo->GetWebPermissionRequest();
    
    auto releaseFunc = [peerPtr = peer.get()]() {
        delete peerPtr;
    };
    
    // 使用try-catch确保异常安全
    try {
        callback(peer.release(), std::move(releaseFunc));
    } catch (...) {
        // 如果callback抛出异常,确保peer被释放
        delete peer.release();
        throw;
    }
}

likedislike
605+ WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info)
606+{
607+ CHECK_NULL_VOID(callback);
608+ ContainerScope scope(instanceId);
609+ auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
610+ CHECK_NULL_VOID(pipelineContext);
611+ pipelineContext->UpdateCurrentActiveNode(weakNode);
612+ auto* eventInfo = TypeInfoHelper::DynamicCast<WebPermissionRequestEvent>(info);
613+ CHECK_NULL_VOID(eventInfo);
614+ auto peer = new PermissionRequestPeer();
615+ CHECK_NULL_VOID(peer);
616+ peer->handler = eventInfo->GetWebPermissionRequest();
617+ auto releaseFunc = [&peer]() {
arkui-feature-manager
arkui-feature-managerarkui-feature-manager2025年12月16日

🤖 AI 代码检视意见(回复本评论可解决检视意见,点击被检视代码行左侧的小头像可收起检视意见)


🟢 无效代码:releaseFunc中的多余赋值

位置: L617-L620 | 严重程度: Low

❓ 问题描述

在releaseFunc lambda中,第619行的peer = nullptr;是无效代码。peer是按值捕获的,修改它不会影响lambda外部的变量,这行代码没有任何效果。

💡 修复建议

删除多余的赋值语句:

auto releaseFunc = [&peer]() {
    delete peer;
    // 删除此行: peer = nullptr;
};

likedislike
618+ delete peer;
619+ peer = nullptr;
620+ };
621+ callback(peer, std::move(releaseFunc));
622+}
623+ 
598void OnScreenCaptureRequest(const CallbackHelper<Callback_OnScreenCaptureRequestEvent_Void>& arkCallback,624void OnScreenCaptureRequest(const CallbackHelper<Callback_OnScreenCaptureRequestEvent_Void>& arkCallback,
599 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info)625 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info)
600{626{
@@ -87,6 +87,8 @@ std::string OnOverrideErrorPage(
87 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info);87 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info);
88void OnPermissionRequest(const CallbackHelper<Callback_OnPermissionRequestEvent_Void>& arkCallback,88void OnPermissionRequest(const CallbackHelper<Callback_OnPermissionRequestEvent_Void>& arkCallback,
89 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info);89 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info);
90+void DefaultPermissionClipboard(const std::function<void(void*, std::function<void()>)>& callback,
91+ WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info);
90void OnScreenCaptureRequest(const CallbackHelper<Callback_OnScreenCaptureRequestEvent_Void>& arkCallback,92void OnScreenCaptureRequest(const CallbackHelper<Callback_OnScreenCaptureRequestEvent_Void>& arkCallback,
91 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info);93 WeakPtr<FrameNode> weakNode, int32_t instanceId, const BaseEventInfo* info);
92bool OnContextMenuShow(const CallbackHelper<Callback_OnContextMenuShowEvent_Boolean>& arkCallback,94bool OnContextMenuShow(const CallbackHelper<Callback_OnContextMenuShowEvent_Boolean>& arkCallback,
@@ -32,6 +32,7 @@ public:
32 using SetWebDetachCallback = std::function<void(int32_t)>;32 using SetWebDetachCallback = std::function<void(int32_t)>;
33 using OnControllerAttachedCallback = std::function<void()>;33 using OnControllerAttachedCallback = std::function<void()>;
34 using DefaultFileSelectorShowCallback = std::function<void(const std::shared_ptr<BaseEventInfo>&)>;34 using DefaultFileSelectorShowCallback = std::function<void(const std::shared_ptr<BaseEventInfo>&)>;
35+ using PermissionClipboardCallback = std::function<void(const std::shared_ptr<BaseEventInfo>&)>;
35 WebPattern();36 WebPattern();
36 ~WebPattern() override;37 ~WebPattern() override;
37 38 
@@ -160,6 +161,7 @@ public:
160 }161 }
161 162 
162 void SetSetWebDetachCallback(SetWebDetachCallback&& callback) {}163 void SetSetWebDetachCallback(SetWebDetachCallback&& callback) {}
164+ void SetPermissionClipboardCallback(PermissionClipboardCallback&& Callback) {}
163 void SetEmulateTouchFromMouseEvent(bool emulateTouchFromMouseEvent) {}165 void SetEmulateTouchFromMouseEvent(bool emulateTouchFromMouseEvent) {}
164 void UpdateDataDetectorConfig(const TextDetectConfig& config) {}166 void UpdateDataDetectorConfig(const TextDetectConfig& config) {}
165 void SetJsProxyCallback(JsProxyCallback&& jsProxyCallback) {}167 void SetJsProxyCallback(JsProxyCallback&& jsProxyCallback) {}
@@ -1671,6 +1671,32 @@ HWTEST_F(WebModelStaticTest, SetPermissionRequestEventId028, TestSize.Level1)
1671#endif1671#endif
1672}1672}
1673 1673 
1674+/**
1675+ * @tc.name: SetPermissionClipboard001
1676+ * @tc.desc: Test web_model_static.cpp
1677+ * @tc.type: FUNC
1678+ */
1679+HWTEST_F(WebModelStaticTest, SetPermissionClipboard001, TestSize.Level1)
1680+{
1681+#ifdef OHOS_STANDARD_SYSTEM
1682+ auto* stack = ViewStackProcessor::GetInstance();
1683+ auto nodeId = stack->ClaimNodeId();
1684+ auto frameNode = WebModelStatic::CreateFrameNode(nodeId);
1685+ ASSERT_NE(frameNode, nullptr);
1686+ stack->Push(frameNode);
1687+ bool callbackCalled = false;
1688+ WebModelStatic::SetPermissionClipboard(AccessibilityManager::RawPtr(frameNode),
1689+ [&callbackCalled](const BaseEventInfo* info) { callbackCalled = true; });
1690+ 
1691+ auto webPatternStatic = ViewStackProcessor::GetInstance()->GetMainFrameNodePattern<WebPatternStatic>();
1692+ ASSERT_NE(webPatternStatic, nullptr);
1693+ 
1694+ auto mockEventInfo = std::make_shared<MockBaseEventInfo>();
1695+ webPatternStatic->GetPermissionClipboardCallback()(mockEventInfo);
1696+ EXPECT_TRUE(callbackCalled);
1697+#endif
1698+}
1699+ 
1674/**1700/**
1675 * @tc.name: SetScreenCaptureRequestEventId0091701 * @tc.name: SetScreenCaptureRequestEventId009
1676 * @tc.desc: Test web_model_static.cpp1702 * @tc.desc: Test web_model_static.cpp