# !/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
说明:此文件是插件脚本的入口Py文件模板,任何其他插件脚本要加入Hubble,需以此模板为基础进行扩展开发
注意事项:
1. 插件文件命名和所在文件夹相同,例如DemoPlugin下面的DemoPlugin.py
2. 在HubblePlatform.py的trigger_plugin函数中,要更新配置变量plugin_property_dict(以后会放到线上去)
3. 新引入的Python3模块需要告知Hubble开发团队的后台部署人员 WX601464,pip3 install NewPackage.py后才能正常运行,否则会导致后台程序错误!
4. 任何问题请联系?WX601464/w30016103
"""
import os
import Hubble.utils.basic.HiviewLogger as HiviewLogger
import re
import datetime
from datetime import datetime, timedelta
import json
class PluginClass():
"""
Hubble程序会自动检测PluginClass名称的类,进行加工
1. self.logger: Hubble日志打印模块变量,可打印详细日志信息,便于后期调试,推荐使用self.logger.info("xxx"),本地调试时请注释self.logger相关命令。
2. self.plugin_result: Hubble能识别到的输出接口,最小填写量"conclusion""reason_info",具体解释请见变量定义处
3. plugin_preprocess: 预处理Hubble传入的info_dict,包含程序运行的基本信息
4. run_plugin_single: 单日志分析函数,插件脚本的分析能力体现于此
5. plugin_result_refinement: 对于批量处理多日志情况,run_plugin_single的单日志处理结果会汇总成一个结果列表,
基于此列表,用户可以进行二次精细化汇总,例如统计平均值等
"""
def __init__(self):
"""
初始化函数
"""
self.logger = HiviewLogger.HiviewLogger().get_logger()
self.plugin_result = { # 填好对应项,会在Hubble单任务分析报告里看见结果展示
"conclusion": { # 分析结论(定界结论)展示
"level_one": "", # 一级定界
"level_two": "", # 二级定界
"reason_info": "", # 根因信息
"solution": "",
"weight_level": "" # 脚本权重,界面展示时作为排序依据,有效值范围[5,10]
},
"analysis_process": { # 分析结论(定界过程)展示,列表中每一个dict元素代表定界过程中的一步
"show_order": [ # 展示顺序, 定义"1", "2", ...步骤
"1", "2"
],
"detailed_process": { # 按show_order的步骤取出过程
"1": {
"details": "", # 第一步详细信息(做了哪些处理总结下,例如在applogcat中找到Hubble关键字)
"CN": "" # 步骤名称(例如找到applogcat文件)
},
"2": {
"details": "", # 第二步详细信息
"CN": "" # 步骤名称
}
}
},
"feature_data": { # 调用相似问题识别能力,需先填好此变量,可能有多个识别到的故障及其特征
"": [] # key值代表发现的故障类型,value值是list of string,由识别到的特征字符串组成
}
}
# 将'05-12 14:51:55'的时间格式转换成时间2024-05-12 14:51:55
def log_str_to_datetime(self, time_str):
issue_time = datetime.strptime(time_str, '%m-%d %H:%M:%S')
current_year = datetime.now().year
issue_time_with_current_year = issue_time.replace(year=current_year)
return issue_time_with_current_year
def extract_datetime(self, string):
pattern = r"_(\d{8})_(\d{4})"
match = re.search(pattern, string)
if match:
return match.group(1) + "_" + match.group(2)
else:
return None
# 1低内存
def memAvailable(self, event_arr):
for line in event_arr:
monsc_re = re.compile('MemAvailable:(.*)kB Buffers').search(line)
if monsc_re:
monsc_tuples = monsc_re.groups()
memAvailable_vale = monsc_tuples[0]
if int(memAvailable_vale) < 1048576:
return 1
return 0
# 2杀后台
def am_kill(self, event_arr):
for line in event_arr:
if ('I am_kill' in line) or ('ActivityManager: Process' in line) or ('lowmemorykiller: Killing' in line):
return 1
return 0
# 3网络不佳
def rtt_rate(self, app_arr):
rtt_num = 0
for line in app_arr:
rtt_re = re.compile('PTcp RTT:(.*), rtt').search(line)
if rtt_re:
rtt_tuples = rtt_re.groups()
rtt_value = rtt_tuples[0]
if int(rtt_value) > 800:
rtt_num += 1
if rtt_num >= 2:
return 1
return 0
# 4前台应用丢帧
def choreographer(self, app_arr):
for line in app_arr:
if 'Choreographer: Skipped' in line:
return 1
return 0
# 5热限频
def temperature(self, app_arr):
target_frame = ''
for line in app_arr:
frame_re = re.compile('shell_frame] tempNew :(.*) tempOld').search(line)
if frame_re:
frame_tuples = frame_re.groups()
frame_value = frame_tuples[0]
if int(frame_value) > 43:
return 1
return 0
# 6低电限频
def cluster_freq(self, app_arr):
for line in app_arr:
if 'hisi_vbat_drop_cluster_freq_set' in line:
return 1
return 0
# 7编译优化
def compiler_optimization(self, app_arr):
for line in app_arr:
if 'Failed execv(/system/bin/dex2oat' in line:
return 1
return 0
# 8IO阻塞
def blockage(self, kernel_arr):
for line in kernel_arr:
if '[BLK-IO]io_latency' in line:
return 1
return 0
# 9整机碎片化过高
def free_sec(self, kernel_arr):
for line in kernel_arr:
free_sec_re = re.compile('free_sec=(.*),reserved_sec').search(line)
free_re = re.compile(',Free=(.*)MB,count=').search(line)
if free_sec_re and free_re:
free_sec_tuples = free_sec_re.groups()
free_sec_value = free_sec_tuples[0]
free_tuples = free_re.groups()
free_value = free_tuples[0]
res_value = 1 - (int(free_sec_value) * 2) / int(free_value)
if res_value > 0.8:
return 1
return 0
# 10应用卡死、无响应
def am_anr(self, event_arr):
for line in event_arr:
if 'am_anr' in line:
return 1
return 0
# 11冻屏\黑屏
def timeout_function(self, xcolie_arr):
for line in xcolie_arr:
if 'timeout function' in line:
return 1
return 0
# 12binder资源不足
def binder_loss(self, kernel_arr):
for line in kernel_arr:
if 'no async space left' in line:
return 1
return 0
# 13后台GC阻塞前台
def wait_for_gc(self, app_arr):
for line in app_arr:
if 'WaitForGcToComplete' in line:
return 1
return 0
# 14高温限帧
def over_heat_lcd_fps(self, app_arr):
for line in app_arr:
fps_re_mate = re.compile('overHeatLcdFps (.*), multiMaxLcdFreq').search(line)
if fps_re_mate:
fps_tuples_mate = fps_re_mate.groups()
fps_vale_mate = fps_tuples_mate[0]
if int(fps_vale_mate) != -1:
return 1
else:
fps_re = re.compile('overHeatLcdFps (.*), final refresh').search(line)
if fps_re:
self.logger.info('chenshuang:')
fps_tuples = fps_re.groups()
self.logger.info(fps_tuples)
fps_vale = fps_tuples[0]
if int(fps_vale) != -1:
return 1
return 0
# 17应用启动完成时延
def activity_task_manager(self, app_arr):
for line in app_arr:
display_re = re.compile('ActivityTaskManager: Displayed (.*)ms').search(line)
if display_re:
display_tuples = display_re.groups()
display_value = display_tuples[0]
display_time = display_value.split('+')[-1]
display_trans = display_time.split('s')
if len(display_trans) > 1:
display_res = int(display_trans[0]) * 1000 + int(display_trans[1])
print(display_res)
else:
display_res = int(display_trans[0])
if display_res > 1500:
return 1
return 0
# 19 input事件无响应
def inputDispatcher(self, app_arr):
for line in app_arr:
if 'InputDispatcher: Dropping' in line:
return 1
return 0
# 20 亮屏解锁慢
def unlock_slow(self, app_arr):
for line in app_arr:
if 'Keyguard drawn timeout' in line or 'Timeout waiting for drawn' in line:
return 1
return 0
# 21 音频播放卡顿
def audio_slow(self, app_arr):
for line in app_arr:
if 'E AudioFlinger: writing blocked, write to hal costs:' in line:
return 1
return 0
# 22 游戏卡顿
def game_slow(self, app_arr):
# 只检测游戏0和游戏4,为了不改动代码,所以直接降其他游戏检测项置零
res = [0, 0, 0, 0, 0, 0, 0, 0]
for line in app_arr:
game_re = re.compile('gamesdk update status: (.*)').search(line)
if game_re:
game_tuples = game_re.groups()
game_vale = game_tuples[0]
dict_game = json.loads(game_vale[1:-1])
if ("pkg" in dict_game) and ("4" in dict_game) and ("12" in dict_game):
if (dict_game["pkg"] == 'com.tencent.tmgp.sgame') and (dict_game["4"] == 7) and (
dict_game["12"] > 150):
res[0] = 1
if ("pkg" in dict_game) and ("4" in dict_game) and ("5" in dict_game) and ("7" in dict_game):
if (dict_game["pkg"] == 'com.tencent.tmgp.sgame') and (dict_game["4"] == 7) and (
dict_game["5"] < 75) and (
(dict_game["7"] == 90) or (dict_game["7"] == 120) or (dict_game["7"] == 144)):
res[1] = 0
if ("pkg" in dict_game) and ("4" in dict_game) and ("5" in dict_game) and ("7" in dict_game):
if (dict_game["pkg"] == 'com.tencent.tmgp.sgame') and (dict_game["4"] == 7) and (
dict_game["5"] < 50) and (
dict_game["7"] == 60):
res[2] = 0
if (dict_game["pkg"] == 'com.tencent.tmgp.sgame') and (dict_game["4"] == 7) and (
dict_game["5"] < 25) and (
dict_game["7"] == 30):
res[3] = 0
if ("pkg" in dict_game) and ("7" in dict_game):
if (dict_game["pkg"] == 'com.tencent.tmgp.sgame') and (dict_game["7"] > 150):
res[4] = 1
if ("pkg" in dict_game) and ("10" in dict_game) and ("3" in dict_game):
if (dict_game["pkg"] == 'com.tencent.tmgp.pubgmhd') and (dict_game["10"] == 30) and (
dict_game["3"] < 25):
res[5] = 0
if (dict_game["pkg"] == 'com.tencent.tmgp.pubgmhd') and (dict_game["10"] == 60) and (
dict_game["3"] < 50):
res[6] = 0
if (dict_game["pkg"] == 'com.tencent.tmgp.pubgmhd') and (
(dict_game["10"] == 90) or (dict_game["10"] == 120) or (dict_game["10"] == 144)) and (
dict_game["3"] < 75):
res[7] = 0
return res
# jank日志解析 --存储不足,整机lowait,限频,省电模式,高负载,低内存
def jank_log(self, jank_arr):
res = [0, 0, 0, 0, 0, 0]
for line in jank_arr:
freed_re = re.compile('FreeDisk":(.*),').search(line)
io_re = re.compile('Iowait":(.*),').search(line)
limit_re = re.compile('Limit_Freq":(.*),').search(line)
power_re = re.compile('bPowerSavingOn":(.*),').search(line)
cpu_re = re.compile('CpuLoad":(.*),').search(line)
available_re = re.compile('AvailableMem":(.*),').search(line)
if freed_re:
freed_tuples = freed_re.groups()
freed_value = freed_tuples[0]
if int(freed_value) < 15360:
res[0] = 1
if io_re:
io_tuples = io_re.groups()
io_value = io_tuples[0]
if int(io_value) > 80:
res[1] = 1
if limit_re:
limit_tuples = limit_re.groups()
limit_value = limit_tuples[0]
if int(limit_value) == 1:
res[2] = 0
if power_re:
power_tuples = power_re.groups()
power_value = power_tuples[0]
if (int(power_value) == 1) or (int(power_value) == 4):
res[3] = 1
if cpu_re:
cpu_tuples = cpu_re.groups()
cpu_value = cpu_tuples[0]
if int(cpu_value) > 6000:
res[4] = 1
if available_re:
available_tuples = available_re.groups()
available_value = available_tuples[0]
if int(available_value) < 819200:
res[5] = 1
return res
def plugin_preprocess(self, info_dict=None):
"""
预处理Hubble传入的info_dict,包含程序运行的基本信息
此函数的基础操作是获取下载日志列表地址,形成task_list任务分析列表,供Hubble调用
"""
self.logger.info("这是预处理函数?")
task_list = []
download_list = info_dict["common_info"]["log_download_list"]
max_analysis_num = 1 # 最多处理几个日志
if len(download_list) > max_analysis_num:
download_list = download_list[:max_analysis_num]
for download_item in download_list:
task_dict = {"download_addr": [], "task_params": {}}
task_dict["download_addr"] = download_item
task_list.append(task_dict)
return task_list
def run_plugin_single(self, uuid_log_path=None, log_path=None, param_dict=None):
"""
主脚本分析逻辑,分析单日志中存在的故障,存入self.plugin_result
1. uuid_log_path: Hubble单任务的顶级分析路径,包含生成的基本信息文件、结果文件和递归解压的日志文件夹
2. log_path: 递归解压的顶级日志文件夹,一般是uuid_log_path的子文件
3. param_dict: 脚本程序所需的参数信息,例如日志来源、领域等,
---------------------------------------------------
参数示例
BetaClub的param_dict示例:
param_dict = {"common_info":{'happen_time': '20230225182000', 'betano': '2103539765',
'version': 'FCO-AL00 3.1.0.115(SP2C00E110R2P3log)', 'product': 'FCO-AL00',
'logsource': 'BetaClub', 'beta_info': {'quesDetail': '图库退出卡顿。',
'faultNameLv1': '性能', 'faultNameLv2': '整机操作各种卡',
'activityName': '【旗舰手机PDU】【关键】FCO-AL00 Beta测试', 'faultCode': '1008_1002'},
'happen_time_unixtime': 1677320400000, 'label': '动效卡顿', 'l_pkgs': ['com.huawei.photos']}}
APR的param_dict示例:
param_dict = {'common_info': {'version': 'MNA-AL00 3.1.0.125(SP1DEMC735E126R2P2)',
'eventid': '901001002','errorcode2': '', 'errorcode4': '', 'logsource': 'AresOcean',
'errorcode3': '', 'product': 'MNA-AL00', 'datetime_str': '20230327112414'}}
建议通过字典的get方法进行取值,如可通过下述语句获取用户描述和产品名称:
brief = param_dict.get("common_info", {}).get("beta_info", {}).get("quesDetail", "")
product = param_dict.get("common_info", {}).get("product", "")
"""
self.logger.info("这是测试插件!uuid_log_path=[%s], log_path=[%s], param_dict=[%s]",
uuid_log_path, log_path, param_dict) # 此句为DemoPlugin.py独有,可删除
# 此代码块为文件路径的遍历方法,以hiapplogcat-log为例
app_path = []
screenshot = []
screenvideo = []
event_path = []
kernel_path = []
jankexec_path = []
for root, dirs, files in os.walk(uuid_log_path):
for file in files:
if "hiapplogcat-log" in file: # 可替换为其它日志类型
app_path.append(os.path.join(root, file))
if "Screenshot" in file:
screenshot.append(os.path.join(root, file))
if "SVID_" in file:
screenvideo.append(os.path.join(root, file))
if "eventslogcat-log" in file:
event_path.append(os.path.join(root, file))
if "kmsgcat-log" in file:
kernel_path.append(os.path.join(root, file))
if "jankexec.log" in file:
jankexec_path.append(os.path.join(root, file))
# 对app,event,kernel日志按照时间顺序进行排序
event_path = sorted(event_path, key=lambda f: f[-34:])
app_path = sorted(app_path, key=lambda g: g[-34:])
kernel_path = sorted(kernel_path, key=lambda g: g[-34:])
level_one = "稳定与流畅" # 临时二级定界字符串
conclusion = '详情请看根因分析'
# 打开app日志
app_list = []
for app in app_path:
with open(app, "r", encoding="utf-8", errors='ignore') as app_reader:
app_line = app_reader.readlines()
app_list += app_line
app_time_end = app_list[-1]
if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', app_time_end[:14]):
app_end = app_time_end[:14]
else:
app_time_end = app_list[-10]
app_end = app_time_end[:14]
app_arr = []
if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', app_end):
app_end_time = self.log_str_to_datetime(app_end)
for app_key in app_list:
if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', app_key[:14]):
app_key_time = self.log_str_to_datetime(app_key[:14])
if app_key_time > app_end_time - timedelta(minutes=10):
app_arr.append(app_key)
else:
app_arr = app_list
# 打开event日志
event_list = []
for event in event_path:
with open(event, "r", encoding="utf-8", errors='ignore') as event_reader:
event_line = event_reader.readlines()
event_list += event_line
event_time_end = event_list[-1]
if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', event_time_end[:14]):
event_end = event_time_end[:14]
else:
event_time_end = event_list[-2]
event_end = event_time_end[:14]
event_arr = []
event_end_time = self.log_str_to_datetime(event_end)
for event_key in event_list:
if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', event_key[:14]):
event_key_time = self.log_str_to_datetime(event_key[:14])
if event_key_time > event_end_time - timedelta(minutes=10):
event_arr.append(event_key)
# 打开kernel日志
kernel_list = []
for kernel in kernel_path:
with open(kernel, "r", encoding="utf-8", errors='ignore') as kernel_reader:
kernel_line = kernel_reader.readlines()
kernel_list += kernel_line
kernel_time_end = kernel_list[-1]
if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', kernel_time_end[:14]):
kernel_end = kernel_time_end[:14]
else:
kernel_time_end = kernel_list[-2]
kernel_end = kernel_time_end[:14]
kernel_arr = []
kernel_end_time = self.log_str_to_datetime(kernel_end)
for kernel_key in kernel_list:
if re.match(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}$', kernel_key[:14]):
kernel_key_time = self.log_str_to_datetime(kernel_key[:14])
if kernel_key_time > kernel_end_time - timedelta(minutes=10):
kernel_arr.append(kernel_key)
# 打开jankexec日志
jankexec_list = []
for jankexec in jankexec_path:
with open(jankexec, "r", encoding="utf-8", errors='ignore') as jankexec_reader:
jankexec_line = jankexec_reader.readlines()
jankexec_list += jankexec_line
first = self.memAvailable(event_arr) # 1低内存
second = self.am_kill(event_arr) # 2杀后台
third = self.rtt_rate(app_arr) # 3网络不佳
fourth = self.choreographer(app_arr) # 4前台应用丢帧
fifth = self.temperature(app_arr) # 5热限频
sixth = self.cluster_freq(app_arr) # 6低电限频
seventh = self.compiler_optimization(app_arr) # 7编译优化
eighth = self.blockage(kernel_arr) # 8IO阻塞
ninth = self.free_sec(kernel_arr) # 9整机碎片化过高
tenth = self.am_anr(event_arr) # 10应用卡死、无响应
twelfth = self.binder_loss(kernel_arr) # 12binder资源不足
thirteenth = self.wait_for_gc(app_arr) # 13后台GC阻塞前台
fourteenth = self.over_heat_lcd_fps(app_arr) # 14高温限帧
seventeenth = self.activity_task_manager(app_arr) # 17应用启动完成时延
nineteenth = self.inputDispatcher(app_arr) # 19 input事件无响应
twentieth = self.unlock_slow(app_arr) # 20 亮屏解锁慢
twen_one = self.audio_slow(app_arr) # 21 音频播放卡顿
twen_two = self.game_slow(app_arr) # 22 游戏卡顿
jank_res = self.jank_log(jankexec_list)
res = [first, second, third, fourth, 0, sixth, seventh, eighth, ninth, tenth, 0, twelfth, thirteenth,
fourteenth, 0, 0, 0, 0, nineteenth, 0, 0] + twen_two + jank_res
self.logger.info(res)
res_str = [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
[], [], [], [], [], [], [], [], [], []]
res_str[0] = ['整机低内存', '清除后台应用:桌面手势导航底部上划进入多任务中心,清理后台多任务应用卡片(三键导航点击导航键的方块图标可以进入多任务界面),定期(2-3天)关机重启设备。<br>进入手机管家进行深度清理存储空间,并在设置-应用管理中关闭不常用应用的自启应用、关联启动、后台活动']
res_str[1] = ['后台应用被清理查杀', '清除后台应用:桌面手势导航底部上划进入多任务中心,清理后台多任务应用卡片(三键导航点击导航键的方块图标可以进入多任务界面),定期(2-3天)关机重启设备。<br>进入手机管家进行深度清理存储空间,并在设置-应用管理中关闭不常用应用的自启应用、关联启动、后台活动']
res_str[2] = ['网络不佳', '调整到网络环境状态良好WIFI或移动数据下再体验']
res_str[3] = ['', '']
res_str[4] = ['高温限频', '建议尽量避免边充电边使用,适当降低屏幕亮度,关闭不使用或异常耗电的应用与功能开关(如:热点、“蓝牙”、NFC'
'等);游戏时适当降低画质,帧率和分辨率设置,可提升使用体验,减少发热;降低外放音量能降低扬声器功耗,或使用耳机播放声音可以有效减少发热;熄屏待设备降温后再查看使用。']
res_str[5] = ['低电欠压限频',
'手机/平板低电量(<20%)的时候,低电量模式,手机或平板会降低性能以节省电量,保障续航,建议将设备电量保持在20%以上下使用体验。']
res_str[6] = ['应用刚更新补丁或者大版本时需要一定周期内做代码的编译优化',
'建议将设备灭屏充电4小时以上(最好能灭屏充电一晚上),重启设备以保证系统及已安装的应用已进行优化,三天后可以再观察使用;']
res_str[7] = ['数据读写阻塞',
'建议引导用户进入手机管家针对存储空间进行清理优化,并在夜间保持充电习惯,建议将设备灭屏充电4小时以上(最好能灭屏充电一晚上),重启设备促进系统的碎片文件整理']
res_str[8] = ['整机碎片化过高',
'建议引导用户进入手机管家针对存储空间进行清理优化,并在夜间保持充电习惯,建议将设备灭屏充电4小时以上(最好能灭屏充电一晚上),重启设备促进系统的碎片文件整理']
res_str[9] = ['应用卡死、无响应', '建议重启应用或设备后再体验,同时前往应用市场检测更新应用版本']
res_str[10] = ['', '']
res_str[11] = ['binder资源不足(进程调用资源不足)',
'清除后台应用:桌面手势导航底部上划进入多任务中心,清理后台多任务应用卡片(三键导航点击导航键的方块图标可以进入多任务界面),定期(2-3天)关机重启设备。<br>进入手机管家进行深度清理存储空间,并在设置-应用管理中关闭不常用应用的自启应用、关联启动、后台活动']
res_str[12] = ['后台GC阻塞前台(应用自身运行时占用内存过高,自己触发垃圾回收,可能阻塞前台业务;整机负载高)',
'清理应用缓存并重启应用后尝试;建议备份数据卸载重装应用尝试;引导用户反馈三方渠道排查或等待应用版本更新']
res_str[13] = ['高温限帧',
'建议尽量避免边充电边使用,适当降低屏幕亮度,关闭不使用或异常耗电的应用与功能开关(如:热点、“蓝牙”、NFC等);游戏时适当降低画质,帧率和分辨率设置,可提升使用体验,减少发热;降低外放音量能降低扬声器功耗,或使用耳机播放声音可以有效减少发热;熄屏待设备降温后再查看使用。']
res_str[14] = ['', '']
res_str[15] = ['', '']
res_str[16] = ['', '']
res_str[17] = ['', '']
res_str[18] = ['应用响应超时(自身前台业务复杂或触控操作过于高频,导致应用自身响应触控操作不及时)', '建议重启应用或设备后再体验,同时前往应用市场检测更新应用版本']
res_str[19] = ['', '']
res_str[20] = ['', '']
res_str[21] = ['王者荣耀对局中网络差', '调整到网络环境状态良好WIFI或移动数据下再体验']
res_str[25] = ['和平精英游戏网络时延高(实时网络时高于150ms)', '调整到网络环境状态良好WIFI或移动数据下再体验']
res_str[29] = ['整机存储不足',
'建议引导清理设备存储空间,清理不常用的应用和文件,将手机存储空间预留20%及以上,保持充足的存储空间。']
res_str[30] = ['整机IO阻塞过多(数据读写阻塞)',
'建议引导用户进入手机管家针对存储空间进行清理优化,并在夜间保持充电习惯,建议将设备灭屏充电4小时以上(最好能灭屏充电一晚上),重启设备促进系统的碎片文件整理']
res_str[32] = ['处于省电模式',
'建议关闭(设置 > 电池 > 省电模式和 超级省电),并保持电量充足(20%以上)。省电模式和低电量情况下,设备会降低性能以节省电量。']
res_str[33] = ['整机高负载', '清除后台应用:桌面手势导航底部上划进入多任务中心,清理后台多任务应用卡片(三键导航点击导航键的方块图标可以进入多任务界面),定期(2-3天)关机重启设备。<br>进入手机管家进行深度清理存储空间,并在设置-应用管理中关闭不常用应用的自启应用、关联启动、后台活动']
res_str[34] = ['整机低内存', '清除后台应用:桌面手势导航底部上划进入多任务中心,清理后台多任务应用卡片(三键导航点击导航键的方块图标可以进入多任务界面),定期(2-3天)关机重启设备。<br>进入手机管家进行深度清理存储空间,并在设置-应用管理中关闭不常用应用的自启应用、关联启动、后台活动']
conclusion_res = []
solution_res = []
for i, key in enumerate(res):
if key:
conclusion_res.append(res_str[i][0])
solution_res.append(res_str[i][1])
if not conclusion_res:
self.plugin_result["conclusion"]['level_one'] = level_one # 一级定界,反映插件功能
self.plugin_result["conclusion"]['level_two'] = '整机卡顿' # 二级定界,根据插件得到的不同结论进行调整
self.plugin_result["conclusion"]['reason_info'] = '当前整机各项指标未诊断出异常' # 二级定界,根据插件得到的不同结论进行调整
self.plugin_result["conclusion"]['solution'] = '建议引导用户重新复现问题反馈日志' # 二级定界,根据插件得到的不同结论进行调整
return self.plugin_result # 如果想直接利用Hubble前端分析报告的展示项,请按定义填写好self.plugin_result变量
con_res = ''
solu_res = ''
for j, key_solution in enumerate(conclusion_res):
if key_solution in con_res:
continue
else:
con_res += '<br>' + '发现异常:' + key_solution + '<br>'
tmp = 0
for p, key in enumerate(solution_res):
if key in solu_res:
continue
else:
tmp += 1
solu_res += '<br>' + str(tmp) + ' : ' + key + '<br>'
# 此代码块用于结论赋值,未找到有效结论时不赋值即可
if conclusion:
self.plugin_result["conclusion"]['level_one'] = level_one # 一级定界,反映插件功能
self.plugin_result["conclusion"]['level_two'] = '整机卡顿' # 二级定界,根据插件得到的不同结论进行调整
self.plugin_result["conclusion"]['reason_info'] = con_res # 二级定界,根据插件得到的不同结论进行调整
self.plugin_result["conclusion"]['solution'] = solu_res # 二级定界,根据插件得到的不同结论进行调整
self.logger.info(self.plugin_result)
return self.plugin_result # 如果想直接利用Hubble前端分析报告的展示项,请按定义填写好self.plugin_result变量
def plugin_result_refinement(self, result_list=None):
"""
二次精细化加工产生的此脚本分析结果列表?
result_list中是self.plugin_result元素的列表集合
也即result_list = [self.plugin_result_1, self.plugin_result_2,...]
"""
self.logger.info("这是分析结果精加工函数")
return result_list # 如果是此分析脚本定制化的分析结果数据结构,需要和Hubble对齐前端取数逻辑才能将分析结论显示在分析报告内
这份脚本挺好的,内容不用怎么改,注释不要给我删了,帮我加一个判断,然后返回一份完整的代码给我:
是否开启免打扰
“DO_NOT_DISTURB、suppressed by DND、suppressed due to DND、isZenmodOn :true、zenmode_notification_tag” NotificationEntryMgr:
No peeking: suppressed by DND: 0|com.android.mms|54|null|10043
hilogs\hiapplogcat
关键字命中
开启了免打扰
建议关闭免打扰