@ohos-graphics/stability-code-review 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -0
- package/SKILL.md +518 -0
- package/bin/install.js +165 -0
- package/config/rules.yaml +445 -0
- package/config/whitelist.yaml +52 -0
- package/package.json +40 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_001.md +275 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_002.md +273 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_003.md +305 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_004.md +350 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_005.md +301 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_006.md +320 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_007.md +432 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_008.md +394 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_009.md +425 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_010.md +472 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_011.md +204 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_012.md +210 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_013.md +226 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_014.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_015.md +256 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_016.md +269 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_017.md +222 -0
- package/references/BoundaryCondition/StabilityCodeReview_BoundaryCondition_018.md +336 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_001.md +414 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_002.md +335 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_003.md +284 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_004.md +313 -0
- package/references/ConcurrencyStability/StabilityCodeReview_ConcurrencyStability_005.md +364 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_001.md +142 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_002.md +222 -0
- package/references/ExceptionHandling/StabilityCodeReview_ExceptionHandling_003.md +383 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_001.md +258 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_002.md +131 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_003.md +220 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_004.md +224 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_005.md +250 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_006.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_007.md +169 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_008.md +153 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_009.md +144 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_010.md +152 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_011.md +221 -0
- package/references/GraphicsStability/StabilityCodeReview_GraphicsStability_012.md +318 -0
- package/references/InitializationOrder/StabilityCodeReview_InitializationOrder_001.md +411 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_001.md +255 -0
- package/references/Lifecycle/StabilityCodeReview_Lifecycle_002.md +177 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_001.md +332 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_002.md +261 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_003.md +428 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_004.md +400 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_005.md +364 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_006.md +359 -0
- package/references/MemoryStability/StabilityCodeReview_MemoryStability_007.md +279 -0
- package/references/PROBLEM_TEMPLATE.md +65 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_001.md +380 -0
- package/references/PerformanceStability/StabilityCodeReview_PerformanceStability_002.md +437 -0
- package/references/REPORT_TEMPLATE.csv +5 -0
- package/references/REPORT_TEMPLATE.md +132 -0
- package/references/RULE_DEVELOPMENT_GUIDE.md +711 -0
- package/references/RULE_INDEX.md +101 -0
- package/references/RULE_TEMPLATE.md +192 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_001.md +334 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_002.md +425 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_003.md +420 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_004.md +409 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_005.md +445 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_006.md +384 -0
- package/references/ResourceManagement/StabilityCodeReview_ResourceManagement_007.md +395 -0
- package/scripts/add-rule.py +423 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_GraphicsStability_002"
|
|
3
|
+
name: "VulkanCleanUpHelper与SharedContext引用计数混用"
|
|
4
|
+
category: "图形稳定性"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# VulkanCleanUpHelper与SharedContext引用计数混用
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
VulkanCleanUpHelper与SharedContext分属两套引用计数管理,不能混用。同一资源不能同时使用两种引用计数机制管理,否则会导致引用计数不一致,引发资源泄漏或提前释放。
|
|
15
|
+
|
|
16
|
+
## 检测示例
|
|
17
|
+
|
|
18
|
+
### 错误示例
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// 错误示例1:同一资源使用两种引用计数管理
|
|
22
|
+
class TextureManager {
|
|
23
|
+
public:
|
|
24
|
+
sk_sp<Surface> CreateSurface(
|
|
25
|
+
GrDirectContext* context,
|
|
26
|
+
const GrBackendTexture& backendTexture,
|
|
27
|
+
VulkanCleanUpHelper* cleanUpHelper,
|
|
28
|
+
SharedContext* sharedContext)
|
|
29
|
+
{
|
|
30
|
+
// 错误:同时使用VulkanCleanUpHelper和SharedContext
|
|
31
|
+
auto surface = Surface::MakeFromBackendTexture(
|
|
32
|
+
context, backendTexture, kTopLeft_GrSurfaceOrigin,
|
|
33
|
+
1, kRGBA_8888_SkColorType,
|
|
34
|
+
sharedContext->GetSurfaceProps(), // SharedContext引用计数
|
|
35
|
+
cleanUpHelper); // VulkanCleanUpHelper引用计数
|
|
36
|
+
return surface; // 错误:两套引用计数混用
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// 错误示例2:引用计数操作混用
|
|
41
|
+
class ImageResource {
|
|
42
|
+
public:
|
|
43
|
+
void AddRef() {
|
|
44
|
+
cleanUpHelper_->ref(); // VulkanCleanUpHelper引用
|
|
45
|
+
sharedContext_->AddRef(); // SharedContext引用 // 错误:混用
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void Release() {
|
|
49
|
+
cleanUpHelper_->unref(); // VulkanCleanUpHelper释放
|
|
50
|
+
sharedContext_->Release(); // SharedContext释放 // 错误:混用
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
VulkanCleanUpHelper* cleanUpHelper_;
|
|
55
|
+
SharedContext* sharedContext_;
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 正确示例
|
|
60
|
+
|
|
61
|
+
```cpp
|
|
62
|
+
// 正确示例1:仅使用VulkanCleanUpHelper管理
|
|
63
|
+
class TextureManager {
|
|
64
|
+
public:
|
|
65
|
+
sk_sp<Surface> CreateSurface(
|
|
66
|
+
GrDirectContext* context,
|
|
67
|
+
const GrBackendTexture& backendTexture,
|
|
68
|
+
VulkanCleanUpHelper* cleanUpHelper)
|
|
69
|
+
{
|
|
70
|
+
auto surface = Surface::MakeFromBackendTexture(
|
|
71
|
+
context, backendTexture, kTopLeft_GrSurfaceOrigin,
|
|
72
|
+
1, kRGBA_8888_SkColorType, nullptr, cleanUpHelper); // 正确:仅使用一套机制
|
|
73
|
+
return surface;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// 正确示例2:仅使用SharedContext管理
|
|
78
|
+
class ImageManager {
|
|
79
|
+
public:
|
|
80
|
+
sk_sp<Image> CreateImage(
|
|
81
|
+
SharedContext* sharedContext,
|
|
82
|
+
const GrBackendTexture& backendTexture)
|
|
83
|
+
{
|
|
84
|
+
auto image = sharedContext->CreateImageFromBackendTexture(backendTexture); // 正确
|
|
85
|
+
return image;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 风险流分析(RiskFlow)
|
|
91
|
+
|
|
92
|
+
- **RISK_SOURCE**: VulkanCleanUpHelper与SharedContext引用计数混用
|
|
93
|
+
- **RISK_TYPE**: 引用计数管理冲突
|
|
94
|
+
- **RISK_PATH**: 两套引用计数机制混用 -> 引用计数不一致 -> 资源泄漏或提前释放
|
|
95
|
+
- **IMPACT_POINT**: 内存泄漏、GPU崩溃
|
|
96
|
+
|
|
97
|
+
## 影响分析(ImpactAnalysis)
|
|
98
|
+
|
|
99
|
+
- **Trigger**: 同一资源使用两种引用计数管理
|
|
100
|
+
- **Propagation**: 引用计数机制冲突,计数不一致
|
|
101
|
+
- **Consequence**: 资源泄漏或提前释放、GPU崩溃、渲染异常
|
|
102
|
+
- **Mitigation**: 选择一种引用计数机制统一管理,不要混用
|
|
103
|
+
|
|
104
|
+
## 误报排除
|
|
105
|
+
|
|
106
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
107
|
+
|------|----------|----------|
|
|
108
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
109
|
+
| 仅使用一种机制 | 只存在一种引用计数 | 不报 |
|
|
110
|
+
## 测试用例
|
|
111
|
+
|
|
112
|
+
### 触发用例(应该报)
|
|
113
|
+
|
|
114
|
+
```cpp
|
|
115
|
+
// 错误:混用两套引用计数
|
|
116
|
+
void MixedRefCount()
|
|
117
|
+
{
|
|
118
|
+
cleanUpHelper->ref(); // VulkanCleanUpHelper
|
|
119
|
+
sharedContext->AddRef(); // SharedContext // 应该报
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 安全用例(不应该报)
|
|
124
|
+
|
|
125
|
+
```cpp
|
|
126
|
+
// 正确:仅使用一套引用计数
|
|
127
|
+
void SingleRefCount()
|
|
128
|
+
{
|
|
129
|
+
cleanUpHelper->ref(); // 仅VulkanCleanUpHelper // 不报
|
|
130
|
+
}
|
|
131
|
+
```
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_GraphicsStability_003"
|
|
3
|
+
name: "RS主线程禁止使用RenderNodeDrawable"
|
|
4
|
+
category: "图形稳定性"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# RS主线程禁止使用RenderNodeDrawable
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
RSMainThread类(RS主线程)不能使用RenderNodeDrawable,只能产生RenderNodeDrawable。**RSMainThread类负责渲染的Prepare及以前阶段**,包括处理事务数据、执行动画、计算遮挡、准备渲染数据等,而RenderNodeDrawable的实际绘制操作应在RSUniRenderThread类(Process及以后阶段)执行。如果在RSMainThread类中直接使用RenderNodeDrawable执行绘制,会破坏线程模型,引发渲染异常或崩溃。
|
|
15
|
+
|
|
16
|
+
**渲染流程说明**:
|
|
17
|
+
- RSMainThread类:负责Prepare及以前阶段(OnVsync → ProcessCommand → Animate → Prepare → CalcOcclusion → Sync)
|
|
18
|
+
- RSUniRenderThread类:负责Process及以后阶段(Render → OnDraw → GPU操作 → 资源管理)
|
|
19
|
+
|
|
20
|
+
## 检测示例
|
|
21
|
+
|
|
22
|
+
### 错误示例
|
|
23
|
+
|
|
24
|
+
```cpp
|
|
25
|
+
// 错误示例1:RS主线程直接使用RenderNodeDrawable绘制
|
|
26
|
+
void RSMainThread::OnRender()
|
|
27
|
+
{
|
|
28
|
+
auto drawable = GetRenderNodeDrawable(); // 错误:主线程获取Drawable
|
|
29
|
+
|
|
30
|
+
// 错误:主线程直接执行绘制操作
|
|
31
|
+
drawable->Draw(canvas); // 错误:主线程不应执行绘制
|
|
32
|
+
|
|
33
|
+
// 错误:主线程操作Drawable状态
|
|
34
|
+
drawable->SetVisible(true); // 错误:主线程不应操作Drawable
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 错误示例2:主线程回调中使用RenderNodeDrawable
|
|
38
|
+
class MainThreadHandler {
|
|
39
|
+
public:
|
|
40
|
+
void HandleRenderCommand()
|
|
41
|
+
{
|
|
42
|
+
if (IsMainThread()) {
|
|
43
|
+
auto drawable = node->GetDrawable(); // 错误:主线程获取
|
|
44
|
+
drawable->UpdateContent(); // 错误:主线程使用
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 正确示例
|
|
51
|
+
|
|
52
|
+
```cpp
|
|
53
|
+
// 正确示例1:RS主线程只产生RenderNodeDrawable
|
|
54
|
+
void RSMainThread::ProcessCommand()
|
|
55
|
+
{
|
|
56
|
+
auto node = CreateRenderNode();
|
|
57
|
+
auto drawable = RenderNodeDrawable::Create(node); // 正确:主线程创建
|
|
58
|
+
|
|
59
|
+
// 正确:提交到渲染线程执行
|
|
60
|
+
SubmitToRenderThread(drawable);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 正确示例2:渲染线程使用RenderNodeDrawable
|
|
64
|
+
void RenderThread::OnRender()
|
|
65
|
+
{
|
|
66
|
+
auto drawable = GetPendingDrawable(); // 正确:渲染线程获取
|
|
67
|
+
|
|
68
|
+
// 正确:渲染线程执行绘制
|
|
69
|
+
drawable->Draw(canvas); // 正确:渲染线程绘制
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 正确示例3:主线程通过命令传递
|
|
73
|
+
void RSMainThread::UpdateNode()
|
|
74
|
+
{
|
|
75
|
+
UpdateRenderNodeCommand cmd;
|
|
76
|
+
cmd.nodeId = node->GetId();
|
|
77
|
+
cmd.content = newContent;
|
|
78
|
+
|
|
79
|
+
SubmitCommand(cmd); // 正确:通过命令传递,不直接操作Drawable
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 风险流分析(RiskFlow)
|
|
84
|
+
|
|
85
|
+
- **RISK_SOURCE**: RSMainThread类使用RenderNodeDrawable
|
|
86
|
+
- **RISK_TYPE**: 线程职责越界
|
|
87
|
+
- **RISK_PATH**: RSMainThread类使用RenderNodeDrawable -> 线程安全风险 -> 渲染异常或崩溃
|
|
88
|
+
- **IMPACT_POINT**: 渲染异常、线程安全问题
|
|
89
|
+
|
|
90
|
+
## 影响分析(ImpactAnalysis)
|
|
91
|
+
|
|
92
|
+
- **Trigger**: RSMainThread类直接操作RenderNodeDrawable
|
|
93
|
+
- **Propagation**: 破坏渲染线程模型
|
|
94
|
+
- **Consequence**: 渲染异常、界面卡顿、崩溃
|
|
95
|
+
- **Mitigation**: RSMainThread类只产生RenderNodeDrawable,不直接使用
|
|
96
|
+
|
|
97
|
+
## 误报排除
|
|
98
|
+
|
|
99
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
100
|
+
|------|----------|----------|
|
|
101
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
102
|
+
| 创建操作 | RenderNodeDrawable::Create, OnGenerate | 不报(允许创建)|
|
|
103
|
+
| 渲染线程上下文 | RSUniRenderThread::, RenderThread:: | 不报 |
|
|
104
|
+
| 通过Drawable访问Node | drawable->GetRenderNode() | 不报(允许Get)|
|
|
105
|
+
|
|
106
|
+
### 创建vs使用的场景区分
|
|
107
|
+
|
|
108
|
+
RSMainThread允许**创建**RenderNodeDrawable,但禁止**使用**(绘制):
|
|
109
|
+
|
|
110
|
+
#### ✅ 允许场景(创建RenderNodeDrawable)
|
|
111
|
+
|
|
112
|
+
```cpp
|
|
113
|
+
// 正确场景1:创建RenderNodeDrawable
|
|
114
|
+
void RSMainThread::PrepareNode(RSRenderNode& node)
|
|
115
|
+
{
|
|
116
|
+
auto drawable = RenderNodeDrawable::OnGenerate(node); // ✅ 允许创建
|
|
117
|
+
node.SetDrawable(drawable); // ✅ 允许设置
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 正确场景2:获取Drawable但不执行绘制
|
|
121
|
+
void RSMainThread::ProcessNode(RSRenderNode& node)
|
|
122
|
+
{
|
|
123
|
+
auto drawable = node.GetDrawable(); // ✅ 允许获取
|
|
124
|
+
if (drawable) {
|
|
125
|
+
drawable->UpdateBounds(node.GetBounds()); // ✅ 允许Prepare阶段的状态更新
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 正确场景3:Prepare阶段的状态准备
|
|
130
|
+
void RSMainThread::PrepareRenderNode(RSRenderNode& node)
|
|
131
|
+
{
|
|
132
|
+
auto drawable = RenderNodeDrawable::Create(node); // ✅ 允许创建
|
|
133
|
+
drawable->SetPrepareData(data); // ✅ 允许Prepare数据设置
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### ❌ 禁止场景(使用RenderNodeDrawable执行绘制)
|
|
138
|
+
|
|
139
|
+
```cpp
|
|
140
|
+
// 错误场景1:主线程执行Draw绘制
|
|
141
|
+
void RSMainThread::RenderFrame()
|
|
142
|
+
{
|
|
143
|
+
auto drawable = GetDrawable();
|
|
144
|
+
drawable->Draw(canvas); // ❌ 禁止:主线程不应绘制
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 错误场景2:主线程执行OnDraw
|
|
148
|
+
void RSMainThread::OnRender()
|
|
149
|
+
{
|
|
150
|
+
auto drawable = GetDrawable();
|
|
151
|
+
drawable->OnDraw(canvas); // ❌ 禁止:主线程不应OnDraw
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 错误场景3:主线程执行GPU相关绘制命令
|
|
155
|
+
void RSMainThread::RenderNode()
|
|
156
|
+
{
|
|
157
|
+
auto drawable = GetDrawable();
|
|
158
|
+
drawable->RenderContent(); // ❌ 禁止:GPU绘制操作
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### RenderNodeDrawable生命周期
|
|
163
|
+
|
|
164
|
+
理解RenderNodeDrawable的两个阶段:
|
|
165
|
+
|
|
166
|
+
- **Prepare阶段(RSMainThread)**:
|
|
167
|
+
- 创建RenderNodeDrawable
|
|
168
|
+
- 设置Prepare数据(bounds、content等)
|
|
169
|
+
- 更新Drawable状态(可见性、脏区域等)
|
|
170
|
+
- 不执行实际的绘制操作
|
|
171
|
+
|
|
172
|
+
- **Process阶段(RSUniRenderThread)**:
|
|
173
|
+
- 获取已创建的Drawable
|
|
174
|
+
- 执行Draw/OnDraw绘制
|
|
175
|
+
- 执行GPU相关操作
|
|
176
|
+
- 资源管理和清理
|
|
177
|
+
|
|
178
|
+
### 检测规则细化
|
|
179
|
+
|
|
180
|
+
**应该报的情况**:
|
|
181
|
+
- RSMainThread中调用`drawable->Draw(canvas)`
|
|
182
|
+
- RSMainThread中调用`drawable->OnDraw(canvas)`
|
|
183
|
+
- RSMainThread中调用`drawable->RenderContent()`
|
|
184
|
+
- RSMainThread中执行GPU绘制命令
|
|
185
|
+
|
|
186
|
+
**不应该报的情况**:
|
|
187
|
+
- RSMainThread中调用`RenderNodeDrawable::Create(node)`
|
|
188
|
+
- RSMainThread中调用`RenderNodeDrawable::OnGenerate(node)`
|
|
189
|
+
- RSMainThread中调用`drawable->GetRenderNode()`
|
|
190
|
+
- RSMainThread中调用`drawable->UpdateBounds(bounds)`(Prepare数据)
|
|
191
|
+
- RSUniRenderThread中的任何Drawable操作
|
|
192
|
+
## 测试用例
|
|
193
|
+
|
|
194
|
+
### 触发用例(应该报)
|
|
195
|
+
|
|
196
|
+
```cpp
|
|
197
|
+
// RSMainThread上下文中使用RenderNodeDrawable
|
|
198
|
+
void RSMainThread::OnRender()
|
|
199
|
+
{
|
|
200
|
+
auto drawable = GetRenderNodeDrawable();
|
|
201
|
+
drawable->Draw(canvas); // 应该报:主线程不应绘制
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 安全用例(不应该报)
|
|
206
|
+
|
|
207
|
+
```cpp
|
|
208
|
+
// RSMainThread只创建RenderNodeDrawable
|
|
209
|
+
void RSMainThread::CreateDrawable()
|
|
210
|
+
{
|
|
211
|
+
auto drawable = RenderNodeDrawable::Create(node); // 不报:允许创建
|
|
212
|
+
SubmitToRenderThread(drawable);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// 渲染线程使用RenderNodeDrawable
|
|
216
|
+
void RenderThread::OnRender()
|
|
217
|
+
{
|
|
218
|
+
drawable->Draw(canvas); // 不报:渲染线程允许使用
|
|
219
|
+
}
|
|
220
|
+
```
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
rule_id: "StabilityCodeReview_GraphicsStability_004"
|
|
3
|
+
name: "RSUniRenderThread禁止访问RenderNode"
|
|
4
|
+
category: "图形稳定性"
|
|
5
|
+
severity: "HIGH"
|
|
6
|
+
language: ["cpp", "c++"]
|
|
7
|
+
author: "OH-Department7 Stability Team"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# RSUniRenderThread禁止访问RenderNode
|
|
11
|
+
|
|
12
|
+
## 问题描述
|
|
13
|
+
|
|
14
|
+
RSUniRenderThread类(统一渲染线程)不能访问RenderNode。**RSUniRenderThread类负责渲染的Process及以后阶段**,包括执行绘制命令、GPU操作、资源管理等。访问RenderNode应在RSMainThread类(Prepare阶段)进行,RSUniRenderThread类通过命令或Drawable间接获取渲染信息。
|
|
15
|
+
|
|
16
|
+
**渲染流程说明**:
|
|
17
|
+
- RSMainThread类:负责Prepare及以前阶段(OnVsync → ProcessCommand → Animate → Prepare → CalcOcclusion → Sync),可以直接访问RenderNode
|
|
18
|
+
- RSUniRenderThread类:负责Process及以后阶段(Render → OnDraw → GPU操作 → 资源管理),不应直接访问RenderNode
|
|
19
|
+
|
|
20
|
+
## 检测示例
|
|
21
|
+
|
|
22
|
+
### 错误示例
|
|
23
|
+
|
|
24
|
+
```cpp
|
|
25
|
+
// 错误示例1:RSUniRenderThread类直接访问RenderNode
|
|
26
|
+
void RSUniRenderThread::RenderFrame()
|
|
27
|
+
{
|
|
28
|
+
auto node = GetRenderNode(id); // 错误:RSUniRenderThread类获取RenderNode
|
|
29
|
+
|
|
30
|
+
// 错误:RSUniRenderThread类直接操作RenderNode
|
|
31
|
+
node->UpdateContent(); // 错误:不应在RSUniRenderThread类访问
|
|
32
|
+
|
|
33
|
+
// 错误:RSUniRenderThread类读取RenderNode状态
|
|
34
|
+
auto bounds = node->GetBounds(); // 错误:不应在RSUniRenderThread类访问
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 错误示例2:RSUniRenderThread类回调中访问RenderNode
|
|
38
|
+
class UniRenderCallback {
|
|
39
|
+
public:
|
|
40
|
+
void OnRenderComplete()
|
|
41
|
+
{
|
|
42
|
+
if (IsUniRenderThread()) {
|
|
43
|
+
RenderNode* node = nodeMap_->GetNode(surfaceId); // 错误
|
|
44
|
+
node->SetRenderComplete(); // 错误
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 正确示例
|
|
51
|
+
|
|
52
|
+
```cpp
|
|
53
|
+
// 正确示例1:RSUniRenderThread类通过Drawable获取信息
|
|
54
|
+
void RSUniRenderThread::RenderFrame()
|
|
55
|
+
{
|
|
56
|
+
auto drawable = GetDrawableForRender(); // 正确:通过Drawable
|
|
57
|
+
|
|
58
|
+
// 正确:从Drawable获取渲染信息
|
|
59
|
+
drawable->Draw(canvas); // 正确:不直接访问RenderNode
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 正确示例2:RSUniRenderThread类通过命令接收数据
|
|
63
|
+
void RSUniRenderThread::ProcessCommand(const RenderCommand& cmd)
|
|
64
|
+
{
|
|
65
|
+
// 正确:从命令中获取需要的信息
|
|
66
|
+
auto bounds = cmd.bounds;
|
|
67
|
+
auto content = cmd.content;
|
|
68
|
+
|
|
69
|
+
RenderInternal(bounds, content); // 正确:使用命令数据
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 正确示例3:RSMainThread类管理RenderNode
|
|
73
|
+
void RSMainThread::UpdateRenderNode(NodeId id, const Content& content)
|
|
74
|
+
{
|
|
75
|
+
auto node = GetRenderNode(id); // 正确:RSMainThread类访问
|
|
76
|
+
node->UpdateContent(content); // 正确:RSMainThread类操作
|
|
77
|
+
|
|
78
|
+
// 正确:通知RSUniRenderThread类
|
|
79
|
+
SubmitRenderCommand(id, node->GetBounds());
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 风险流分析(RiskFlow)
|
|
84
|
+
|
|
85
|
+
- **RISK_SOURCE**: RSUniRenderThread类访问RenderNode
|
|
86
|
+
- **RISK_TYPE**: 线程访问越界
|
|
87
|
+
- **RISK_PATH**: RSUniRenderThread类访问RenderNode -> 线程安全风险 -> 数据竞争
|
|
88
|
+
- **IMPACT_POINT**: 渲染数据不一致、崩溃
|
|
89
|
+
|
|
90
|
+
## 影响分析(ImpactAnalysis)
|
|
91
|
+
|
|
92
|
+
- **Trigger**: RSUniRenderThread类直接访问RenderNode
|
|
93
|
+
- **Propagation**: 破坏线程模型,引发数据竞争
|
|
94
|
+
- **Consequence**: 渲染异常、数据损坏、崩溃
|
|
95
|
+
- **Mitigation**: RSUniRenderThread类不应直接访问RenderNode
|
|
96
|
+
|
|
97
|
+
## 误报排除
|
|
98
|
+
|
|
99
|
+
| 场景 | 识别特征 | 处理方式 |
|
|
100
|
+
|------|----------|----------|
|
|
101
|
+
| NOPROTECT 标记 | 有 // NOPROTECT 注释 | 不报 |
|
|
102
|
+
| 主线程上下文 | RSMainThread:: | 不报 |
|
|
103
|
+
| 通过Drawable间接获取 | drawable->GetRenderNode().lock() | 不报(允许间接获取)|
|
|
104
|
+
| 只读访问 | drawable->GetNodeBounds() | 不报(从Drawable获取数据)|
|
|
105
|
+
|
|
106
|
+
### 间接获取vs直接访问的场景区分
|
|
107
|
+
|
|
108
|
+
RSUniRenderThread允许通过Drawable**间接获取**RenderNode信息,但禁止**直接访问**RenderNode对象:
|
|
109
|
+
|
|
110
|
+
#### ✅ 允许场景(通过Drawable间接获取)
|
|
111
|
+
|
|
112
|
+
```cpp
|
|
113
|
+
// 正确场景1:通过Drawable获取Node信息
|
|
114
|
+
void RSUniRenderThread::RenderDrawable(RSRenderNodeDrawable* drawable)
|
|
115
|
+
{
|
|
116
|
+
auto node = drawable->GetRenderNode().lock(); // ✅ 允许:通过Drawable间接获取
|
|
117
|
+
if (!node) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// 使用node的只读信息进行绘制准备
|
|
121
|
+
auto bounds = node->GetBounds(); // ✅ 允许:通过Drawable获取的只读访问
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 正确场景2:从Drawable获取渲染数据
|
|
125
|
+
void RSUniRenderThread::DrawContent(RSRenderNodeDrawable* drawable)
|
|
126
|
+
{
|
|
127
|
+
// Drawable已经缓存了必要的渲染数据
|
|
128
|
+
drawable->Draw(canvas); // ✅ 允许:使用Drawable绘制
|
|
129
|
+
|
|
130
|
+
// 不直接访问Node获取数据
|
|
131
|
+
// auto node = nodeMap_->GetNode(id); // ❌ 禁止
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 正确场景3:使用Drawable缓存的Prepare数据
|
|
135
|
+
void RSUniRenderThread::ProcessDrawable()
|
|
136
|
+
{
|
|
137
|
+
auto drawable = GetDrawable();
|
|
138
|
+
auto bounds = drawable->GetCachedBounds(); // ✅ 允许:使用Drawable缓存的数据
|
|
139
|
+
auto content = drawable->GetCachedContent(); // ✅ 允许
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### ❌ 禁止场景(直接访问RenderNode)
|
|
144
|
+
|
|
145
|
+
```cpp
|
|
146
|
+
// 错误场景1:通过NodeMap直接获取RenderNode
|
|
147
|
+
void RSUniRenderThread::RenderFrame()
|
|
148
|
+
{
|
|
149
|
+
auto node = nodeMap_->GetNode(nodeId); // ❌ 禁止:直接访问NodeMap
|
|
150
|
+
node->UpdateContent(); // ❌ 禁止:直接操作RenderNode
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 错误场景2:通过全局容器访问RenderNode
|
|
154
|
+
void RSUniRenderThread::ProcessNodes()
|
|
155
|
+
{
|
|
156
|
+
for (auto& node : globalNodeList) { // ❌ 禁止:直接遍历Node容器
|
|
157
|
+
node->Render(); // ❌ 禁止
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 错误场景3:通过id直接查询RenderNode
|
|
162
|
+
void RSUniRenderThread::OnRender(NodeId id)
|
|
163
|
+
{
|
|
164
|
+
RSRenderNode* node = RSBaseRenderNode::GetNodeById(id); // ❌ 禁止:直接查询
|
|
165
|
+
auto bounds = node->GetBounds(); // ❌ 禁止
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### RenderNode访问路径说明
|
|
170
|
+
|
|
171
|
+
理解RenderNode的两种访问路径:
|
|
172
|
+
|
|
173
|
+
- **RSMainThread路径**(允许直接访问):
|
|
174
|
+
- `GetRenderNode(id)` - 直接从NodeMap获取
|
|
175
|
+
- `RSRenderNode::GetNodeById(id)` - 直接查询
|
|
176
|
+
- 可以执行Update、Prepare等操作
|
|
177
|
+
|
|
178
|
+
- **RSUniRenderThread路径**(只能间接访问):
|
|
179
|
+
- `drawable->GetRenderNode().lock()` - 通过Drawable获取weak_ptr
|
|
180
|
+
- `drawable->GetCachedXXX()` - 使用Drawable缓存的数据
|
|
181
|
+
- 只能读取Prepare阶段缓存的数据,不能修改
|
|
182
|
+
|
|
183
|
+
### 检测规则细化
|
|
184
|
+
|
|
185
|
+
**应该报的情况**:
|
|
186
|
+
- RSUniRenderThread中调用`nodeMap_->GetNode(id)`
|
|
187
|
+
- RSUniRenderThread中调用`RSBaseRenderNode::GetNodeById(id)`
|
|
188
|
+
- RSUniRenderThread中直接操作`RSRenderNode*`指针
|
|
189
|
+
- RSUniRenderThread中遍历`globalNodeList`等Node容器
|
|
190
|
+
|
|
191
|
+
**不应该报的情况**:
|
|
192
|
+
- RSUniRenderThread中调用`drawable->GetRenderNode().lock()`(通过Drawable间接获取)
|
|
193
|
+
- RSUniRenderThread中调用`drawable->GetCachedXXX()`(使用Drawable缓存数据)
|
|
194
|
+
- RSMainThread中的任何RenderNode访问
|
|
195
|
+
- Prepare阶段的RenderNode操作(在RSMainThread中)
|
|
196
|
+
## 测试用例
|
|
197
|
+
|
|
198
|
+
### 触发用例(应该报)
|
|
199
|
+
|
|
200
|
+
```cpp
|
|
201
|
+
// RSUniRenderThread类访问RenderNode
|
|
202
|
+
void RSUniRenderThread::OnRender()
|
|
203
|
+
{
|
|
204
|
+
RenderNode* node = GetRenderNode(id); // 应该报
|
|
205
|
+
node->GetBounds(); // 应该报
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 安全用例(不应该报)
|
|
210
|
+
|
|
211
|
+
```cpp
|
|
212
|
+
// RSMainThread类访问RenderNode
|
|
213
|
+
void RSMainThread::UpdateNode()
|
|
214
|
+
{
|
|
215
|
+
RenderNode* node = GetRenderNode(id); // 不报:RSMainThread类允许
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// RSUniRenderThread类使用Drawable
|
|
219
|
+
void RSUniRenderThread::OnRender()
|
|
220
|
+
{
|
|
221
|
+
auto drawable = GetDrawable(); // 不报
|
|
222
|
+
drawable->Draw(canvas); // 不报
|
|
223
|
+
}
|
|
224
|
+
```
|