Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
636d84c
Merge branch 'dev' of https://gitcode.com/SMAT/ArkAnalyzer-HapRay
huhanGitHub Nov 17, 2025
aa0dc0d
Merge branch 'dev' of https://gitcode.com/SMAT/ArkAnalyzer-HapRay
huhanGitHub Nov 24, 2025
019624b
Merge remote-tracking branch 'origin/main'
huhanGitHub Dec 3, 2025
b8650d9
Merge branch 'dev' of https://gitcode.com/SMAT/ArkAnalyzer-HapRay
huhanGitHub Dec 3, 2025
5699d63
Merge remote-tracking branch 'origin/main'
huhanGitHub Dec 10, 2025
c425f25
Merge branch 'dev' of https://gitcode.com/SMAT/ArkAnalyzer-HapRay
huhanGitHub Dec 10, 2025
8e72f88
Bugfix: 修复 symbol_recovery 查找trace stramer位置失败
code-sunbo Dec 16, 2025
15a1e2e
更新 opt READMe
code-sunbo Dec 16, 2025
b3a2cdc
Bugfix: 打包增加 run_macos.sh脚本
code-sunbo Dec 16, 2025
66cd5fd
!348 merge dev into dev
code-sunbo Dec 16, 2025
6ba6348
Bugfix: 修复windows GUI编译告警
code-sunbo Dec 16, 2025
d20ca00
!349 merge dev into dev
code-sunbo Dec 16, 2025
cb03ccd
bugfix:给设备留足够时间采集信息。
Dec 16, 2025
152a494
!350 merge dev into dev
Dec 16, 2025
2607d51
add test_release.js
code-sunbo Dec 16, 2025
29b6732
!351 merge dev into dev
code-sunbo Dec 16, 2025
b57c30d
Merge remote-tracking branch 'origin/main'
huhanGitHub Dec 17, 2025
a4c2cb8
增加部分 ohpm 库
code-sunbo Dec 17, 2025
8900f49
!352 merge dev into dev
code-sunbo Dec 17, 2025
2a959fa
界面输入控件修复。
Dec 18, 2025
b6445e1
!353 merge dev into dev
Dec 18, 2025
3a90a51
Merge branch 'dev' of https://gitcode.com/SMAT/ArkAnalyzer-HapRay
huhanGitHub Dec 18, 2025
7f69ab5
static_analye skip armeabi-v7a and x86_64 folders
code-sunbo Dec 18, 2025
284ee2d
!355 merge dev into dev
code-sunbo Dec 18, 2025
5da9e4b
Merge branch 'dev' of https://gitcode.com/SMAT/ArkAnalyzer-HapRay
huhanGitHub Dec 19, 2025
eb745fe
空刷完善四阶段算法,增加假阳性,增加进程级别的冗余cpu指令计算
huhanGitHub Dec 19, 2025
a4c9b06
!356 merge dev into dev
Dec 19, 2025
e44cd5e
一级内存html报告展示
Dec 19, 2025
6b18d8c
!357 merge dev into dev
Dec 19, 2025
1c4f7e8
生成报告时不强制依赖perf.data
code-sunbo Dec 19, 2025
37b60b5
!359 merge dev into dev
code-sunbo Dec 19, 2025
7837ae5
支持无perf data时报告查看
code-sunbo Dec 19, 2025
3aacc22
!360 merge dev into dev
code-sunbo Dec 19, 2025
b666de6
增加RS阶段skip帧检测,增加反向回溯空刷帧算法,增加线程唤醒链算法
huhanGitHub Dec 19, 2025
e8a81a3
!361 merge dev into dev
Dec 19, 2025
be998f7
空刷调用栈火焰图。
Dec 20, 2025
3a580b1
处理冲突
Dec 20, 2025
70016e2
!365 merge dev into dev
Dec 20, 2025
4707f5a
更新快手测试用例。
Dec 20, 2025
f0d549e
!366 merge dev into dev
Dec 20, 2025
7fcec9c
1.页面对比初版。2.执行结果历史记录显示二级菜单并排序。
Dec 22, 2025
68c00b1
Merge branch 'dev' of https://gitcode.com/B1A2/ArkAnalyzer-HapRay int…
Dec 22, 2025
ba2643b
!368 merge dev into dev
Dec 22, 2025
3c33d14
控件参数顺序修改,ui对比结果调整。
Dec 22, 2025
a6a295f
!369 merge dev into dev
Dec 22, 2025
e88c192
统计导出符号数量
code-sunbo Dec 23, 2025
e804ff0
!370 merge dev into dev
code-sunbo Dec 23, 2025
e121216
增加特定第三方框架检测;优化执行效率;增加结果json字段,方便后续debug
huhanGitHub Dec 23, 2025
df59b98
!371 merge dev into dev
Dec 23, 2025
9f505c0
为每个调用链添加对应的thread id
huhanGitHub Dec 23, 2025
8e2bd7c
!372 merge dev into dev
Dec 23, 2025
304622c
为每个调用链添加对应的thread id和 thread name
huhanGitHub Dec 23, 2025
d4b0776
修复opt指令:跳过chunk数量小于10的so文件,so太小预测不准。通过elf检测so文件而不只是so后缀。excel中输出检测fail原因
huhanGitHub Dec 23, 2025
f6bb96a
!373 merge dev into dev
Dec 24, 2025
239b1b1
lto预测使用统一svm模型
huhanGitHub Dec 24, 2025
ddc78f5
!374 merge dev into dev
Dec 24, 2025
59fc2ab
Bugfix: fix compile error TS6196: 'FormatOptions' is declared but nev…
code-sunbo Dec 24, 2025
c04d29f
!375 merge dev into dev
code-sunbo Dec 24, 2025
29ca4a6
Bugfix: 修复用例加载失败/显示不全
code-sunbo Dec 24, 2025
070e945
!376 merge dev into dev
code-sunbo Dec 24, 2025
beafdae
bugfix:不显示nativeMemory
Dec 24, 2025
79f4406
!377 merge dev into dev
Dec 24, 2025
6825a65
bugfix:只从trace中获取信息,不依赖perf
Dec 24, 2025
df7e60f
!378 merge dev into dev
Dec 24, 2025
f2cadb1
bugfix:缺少匹配tid字段。
Dec 24, 2025
6dcd67a
!379 merge dev into dev
Dec 24, 2025
efe05d2
fix lint error
code-sunbo Dec 24, 2025
8fc6ac7
!380 merge dev into dev
code-sunbo Dec 24, 2025
f6e5349
Bugfix: Error reading ELF file seek of closed file
code-sunbo Dec 24, 2025
e757a31
!381 merge dev into dev
code-sunbo Dec 24, 2025
5de60fa
Bugfix: 修复循环依赖
code-sunbo Dec 24, 2025
287223a
!382 merge dev into dev
code-sunbo Dec 24, 2025
5c6648f
Bugfix: 修复循环依赖
code-sunbo Dec 24, 2025
827bbfa
!383 merge dev into dev
code-sunbo Dec 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions hapray-gui/core/file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import logging
import subprocess
import sys
from pathlib import Path
from typing import Optional

Expand Down Expand Up @@ -72,11 +73,20 @@ def list_directories(directory: str) -> list[str]:
def get_project_root() -> Path:
"""获取项目根目录"""
# 从当前文件向上查找,直到找到包含特定标记文件的目录
current = Path(__file__).resolve()
# 打包后默认路径:_internal/core
logger.info('当前文件路径:%s', __file__)
current = Path(__file__).resolve().parent
if hasattr(sys, 'frozen') and hasattr(sys, '_MEIPASS'):
return current.parent.parent

# 向上遍历直到文件系统根目录(当到达根目录时,parent 等于 current)
while current != current.parent:
if (current / 'hapray-gui').exists() or (current / 'perf_testing').exists():
return current
if (current / 'tools').exists() or (current / 'perf_testing').exists():
return current / 'dist'
current = current.parent

# 如果找不到,记录警告并返回当前工作目录
logger.warning('未找到项目根目录,返回当前工作目录 :%s', Path.cwd())
return Path.cwd()

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion hapray-gui/core/plugin_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(self, plugins_dir: Optional[Path] = None):
plugins_dir = exe_dir.parent
else:
# 开发环境
plugins_dir = Path(__file__).parent.parent.parent / 'tools'
plugins_dir = Path(__file__).parent.parent.parent / 'dist' / 'tools'
self.plugins_dir = Path(plugins_dir).resolve()
self.plugins: dict[str, BaseTool] = {}
self.plugin_metadata: dict[str, dict[str, Any]] = {}
Expand Down
18 changes: 17 additions & 1 deletion hapray-gui/core/result_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,24 @@ def __init__(self, output_dir: Optional[str] = None):
else:
self.output_dir = Path(self.config.get_output_dir())

def save_result(self, tool_name: str, result: ToolResult, params: dict[str, Any]) -> str:
def save_result(
self,
tool_name: str,
result: ToolResult,
params: dict[str, Any],
action_name: str = None,
menu_category: str = None,
) -> str:
"""
保存执行结果

Args:
tool_name: 工具名称
result: 执行结果
params: 参数
action_name: 动作名称(可选)
menu_category: 菜单分类(可选)

Returns:
保存的文件路径
"""
Expand All @@ -38,6 +52,8 @@ def save_result(self, tool_name: str, result: ToolResult, params: dict[str, Any]
result_file = result_dir / 'result.json'
result_data = {
'tool_name': tool_name,
'action_name': action_name,
'menu_category': menu_category,
'timestamp': timestamp,
'success': result.success,
'message': result.message,
Expand Down
20 changes: 16 additions & 4 deletions hapray-gui/gui/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ def build_function_tree(self):
'opt': '⚡', # SO编译优化
'static': '📱', # 应用技术栈分析
'symbol-recovery': '🔧', # 符号恢复
'ui-compare': '📌', # UI组件树对比
}

# 定义菜单结构映射:plugin_id -> {action_key -> display_name}
Expand All @@ -232,6 +233,7 @@ def build_function_tree(self):
'ui-tech-stack': '页面技术栈动态识别',
'update': '更新测试报告',
'compare': '对比报告',
'ui-compare': 'UI组件树对比',
}
}
},
Expand Down Expand Up @@ -280,7 +282,15 @@ def build_function_tree(self):
icon = action_icons.get(action_key, '⚙️')
action_item.setText(0, f'{icon} {display_name}')
action_item.setData(
0, Qt.UserRole, {'type': 'action', 'plugin_id': plugin_id, 'action': action_key}
0,
Qt.UserRole,
{
'type': 'action',
'plugin_id': plugin_id,
'action': action_key,
'action_name': display_name,
'menu_category': menu_name,
},
)

# 如果一级菜单下没有子项,隐藏该菜单
Expand Down Expand Up @@ -308,16 +318,18 @@ def on_function_selected(self, item, column):
elif function_type in ['plugin', 'action']:
plugin_id = data.get('plugin_id')
action = data.get('action')
self.show_tool_config(plugin_id, action)
action_name = data.get('action_name')
menu_category = data.get('menu_category')
self.show_tool_config(plugin_id, action, action_name, menu_category)

def show_tool_config(self, plugin_id, action=None):
def show_tool_config(self, plugin_id, action=None, action_name=None, menu_category=None):
"""显示工具配置界面"""
tool = self.plugin_loader.get_plugin(plugin_id)
if not tool:
return

# 创建工具页面
tool_page = ToolPage(tool)
tool_page = ToolPage(tool, action_name=action_name, menu_category=menu_category)
if action and hasattr(tool_page, 'current_action') and hasattr(tool_page, 'rebuild_param_form'):
tool_page.current_action = action
tool_page.rebuild_param_form()
Expand Down
107 changes: 92 additions & 15 deletions hapray-gui/gui/multi_select_combobox.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
"""

from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import QComboBox, QListView, QStyledItemDelegate
from PySide6.QtGui import QMouseEvent
from PySide6.QtWidgets import QComboBox, QListView, QSizePolicy, QStyledItemDelegate

from core.logger import get_logger

logger = get_logger(__name__)


class CheckableComboBox(QComboBox):
Expand Down Expand Up @@ -112,9 +117,19 @@ class MultiSelectComboBox(QComboBox):
def __init__(self, parent=None):
super().__init__(parent)

logger.debug('MultiSelectComboBox 初始化开始')

# 设置为可编辑,但不允许用户输入
self.setEditable(True)
self.lineEdit().setReadOnly(True)
line_edit = self.lineEdit()
line_edit.setReadOnly(True)
line_edit.setMinimumWidth(500) # 设置内部 lineEdit 的最小宽度
# 安装事件过滤器到 lineEdit,以便处理点击事件
line_edit.installEventFilter(self)

# 设置控件本身的最小宽度和大小策略
self.setMinimumWidth(500)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

# 创建列表视图
list_view = QListView()
Expand All @@ -128,34 +143,52 @@ def __init__(self, parent=None):
# 初始化
self.update_text()

logger.debug(f'MultiSelectComboBox 初始化完成,当前项目数量: {self.count()}')

def handle_item_pressed(self, index):
"""处理项目点击"""
item = self.model().itemFromIndex(index)
if item.checkState() == Qt.Checked:
item.setCheckState(Qt.Unchecked)
else:
item.setCheckState(Qt.Checked)
return False # 阻止关闭下拉框
if item:
if item.checkState() == Qt.Checked:
item.setCheckState(Qt.Unchecked)
else:
item.setCheckState(Qt.Checked)
# 对于多选下拉框,点击选项后不自动关闭,让用户可以继续选择
# 用户点击外部区域时会自动关闭

def update_text(self):
"""更新显示文本"""
row_count = self.model().rowCount()
logger.debug(f'MultiSelectComboBox.update_text 被调用,模型行数: {row_count},控件 count: {self.count()}')
checked_items = self.get_checked_items()
if not checked_items:
self.lineEdit().setText('请选择测试用例...')
display_text = '请选择测试用例...'
self.lineEdit().setText(display_text)
logger.debug(f'更新显示文本为: "{display_text}"')
elif len(checked_items) == 1:
self.lineEdit().setText(checked_items[0])
display_text = checked_items[0]
self.lineEdit().setText(display_text)
logger.debug(f'更新显示文本为: "{display_text}"')
else:
self.lineEdit().setText(f'已选择 {len(checked_items)} 个测试用例')
display_text = f'已选择 {len(checked_items)} 个测试用例'
self.lineEdit().setText(display_text)
logger.debug(f'更新显示文本为: "{display_text}"')

self.selection_changed.emit(checked_items)

def get_checked_items(self) -> list[str]:
"""获取所有选中的项目"""
row_count = self.model().rowCount()
logger.debug(f'MultiSelectComboBox.get_checked_items 被调用,模型行数: {row_count}')
checked_items = []
for i in range(self.model().rowCount()):
for i in range(row_count):
item = self.model().item(i)
if item and item.checkState() == Qt.Checked:
checked_items.append(item.text())
if item:
if item.checkState() == Qt.Checked:
checked_items.append(item.text())
else:
logger.warning(f'第 {i} 行的模型项为 None')
logger.debug(f'选中的项目: {checked_items},共 {len(checked_items)} 个')
return checked_items

def set_checked_items(self, items: list[str]):
Expand All @@ -171,17 +204,61 @@ def set_checked_items(self, items: list[str]):

def addItem(self, text, userData=None):
"""添加项目"""
logger.debug(f'MultiSelectComboBox.addItem 被调用,添加项目: {text}')
super().addItem(text, userData)
item = self.model().item(self.count() - 1, 0)
item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
item.setCheckState(Qt.Unchecked)
if item:
item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
item.setCheckState(Qt.Unchecked)
logger.debug(f'项目 "{text}" 添加成功,当前总数: {self.count()}')
else:
logger.error(f'项目 "{text}" 添加失败,无法获取模型项')

def addItems(self, texts):
"""添加多个项目"""
logger.info(f'MultiSelectComboBox.addItems 被调用,准备添加 {len(texts)} 个项目')
logger.debug(f'项目列表: {texts}')
if not texts:
logger.warning('MultiSelectComboBox.addItems 接收到空列表')
for text in texts:
self.addItem(text)
logger.info(f'MultiSelectComboBox.addItems 完成,当前项目总数: {self.count()}')

def clear(self):
"""清空所有项目"""
old_count = self.count()
logger.info(f'MultiSelectComboBox.clear 被调用,清空前项目数: {old_count}')
super().clear()
new_count = self.count()
logger.info(f'MultiSelectComboBox.clear 完成,清空后项目数: {new_count}')
self.update_text()

def showPopup(self):
"""显示下拉框"""
logger.debug('MultiSelectComboBox.showPopup 被调用')
super().showPopup()

def hidePopup(self):
"""隐藏下拉框"""
logger.debug('MultiSelectComboBox.hidePopup 被调用')
# 允许正常关闭下拉框(点击外部或按下 ESC 时)
super().hidePopup()

def eventFilter(self, obj, event):
"""事件过滤器,处理 lineEdit 的点击事件"""
if (
obj == self.lineEdit()
and isinstance(event, QMouseEvent)
and event.type() == QMouseEvent.Type.MouseButtonPress
and event.button() == Qt.LeftButton
):
# 点击 lineEdit 时显示下拉框(因为 lineEdit 是只读的,无法输入)
try:
view = self.view()
if not view.isVisible():
logger.debug('点击 lineEdit,显示下拉框')
self.showPopup()
return True # 阻止默认行为
except Exception as e:
logger.error(f'处理 lineEdit 点击事件时出错: {e}')
return super().eventFilter(obj, event)
Loading
Loading