mirror of
https://github.com/openharmony/developtools_integration_verification.git
synced 2026-07-21 22:55:28 -04:00
@@ -65,6 +65,8 @@ Note:If the text contains special characters, please escape them according to th
|
||||
<filefilter name="defaultFilter" desc="Files not to check">
|
||||
<filteritem type="filename" name="*.png|*.jpeg|*.json" desc="Test files"/>
|
||||
<filteritem type="filename" name="*.bin|*.exe|ReadMe|oeminfo_nvm_test" desc="There are the upgrade tool files"/>
|
||||
<filteritem type="filepath" name="DeployDevice/.*" desc="There are the smoketest tool files"/>
|
||||
<filteritem type="filepath" name="tools/.*" desc="There are tools files"/>
|
||||
</filefilter>
|
||||
<filefilter name="defaultPolicyFilter" desc="Filters for compatibility, license header policies">
|
||||
<filteritem type="filename" name="*.png|*.jpeg|*.json|*.hap|*.csv|dhcpc.sh" desc="NoLicenseHeader"/>
|
||||
|
||||
@@ -2,74 +2,65 @@
|
||||
|
||||
## 功能介绍
|
||||
|
||||
基于config.json、编译产物out/{product_name}/build_configs/parts_info/parts_deps.json,分析各必选部件和可选部件间的依赖关系。
|
||||
基于vendor下的config.json、xml文件中的开源部件集、BUILD.gn文件,分析是否存在对闭源部件的依赖以及是否存在对非必选部件的无条件依赖。
|
||||
|
||||
结果以json格式进行存储。
|
||||
|
||||
## 支持产品
|
||||
|
||||
主要是rk3568系列,已测试产品包括rk3568、rk3568_mini_system、pc_mini_system、tablet_mini_system、phone_mini_system
|
||||
|
||||
## 实现思路
|
||||
|
||||
利用产品部件定义文件config.json和编译构建自动生成的out/{product_name}/build_configs/parts_info/parts_deps.json中已有的信息重新组织,查找相关BUILD.gn文件路径。
|
||||
config.json文件主要是关于rk3568系列,已测试产品包括rk3568、rk3568_mini_system、pc_mini_system、tablet_mini_system、phone_mini_system的config.json文件
|
||||
|
||||
## 使用说明
|
||||
|
||||
前置条件:
|
||||
|
||||
1. 获取整个components_deps目录
|
||||
1. 对系统进行编译
|
||||
1. 获取BUILD.gn文件
|
||||
1. 获取包含开源部件集的xml文件
|
||||
1. 获取包含部件集定义的config.json文件
|
||||
1. python3及以后
|
||||
|
||||
命令介绍:
|
||||
|
||||
1. `-h`或`--help`命令查看帮助
|
||||
```shell
|
||||
> python3 components_deps_analyzer.py -h
|
||||
usage: components_deps_analyzer.py [-h] -c CONFIG_JSON -d PARTS_DEPS_JSON [-s SINGLE_COMPONENT_NAME] [-o OUTPUT_FILE]
|
||||
> python components_deps_analyzer.py --help
|
||||
usage: components_deps_analyzer.py [-h] -p COMPONENTS_GN_PATH_LIST -c CONFIG_PATH -o OPEN_COMPONENT_XML_PATH [-r RESULT_JSON_NAME]
|
||||
|
||||
-s SINGLE_COMPONENT_NAME, --single_component_name SINGLE_COMPONENT_NAME
|
||||
single component name
|
||||
-o OUTPUT_FILE, --output_file OUTPUT_FILE
|
||||
eg: demo/components_deps
|
||||
analyze components deps.
|
||||
|
||||
optional arguments:
|
||||
-p COMPONENTS_GN_PATH_LIST, --components_gn_path_list COMPONENTS_GN_PATH_LIST
|
||||
path of pr BUILD.gn
|
||||
-g GN_COMPONENT, --gn_component GN_COMPONENT
|
||||
gn file corresponding component
|
||||
-c CONFIG_PATH, --config_path CONFIG_PATH
|
||||
path of config_file
|
||||
-o OPEN_COMPONENT_XML_PATH, --open_component_xml_path OPEN_COMPONENT_XML_PATH
|
||||
open component name set
|
||||
-r RESULT_JSON_NAME, --result_json_name RESULT_JSON_NAME
|
||||
name of output_json
|
||||
|
||||
```
|
||||
1. 使用示例
|
||||
```shell
|
||||
python components_deps_analyzer.py -c vendor/hihope/rk3568/config.json -d out/rk3568/build_configs/parts_info/parts_deps.json -o components_dep -s ability_runtime
|
||||
python components_deps_analyzer.py -p BUILD.gn,pkgs/BUILD.gn -g ace_engine,cef -c config_path -o .\gn_xml\ohos.xml
|
||||
```
|
||||
|
||||
## 输出格式介绍(components_dep.json)
|
||||
## 输出格式介绍(result.json)
|
||||
|
||||
```
|
||||
{
|
||||
必选部件名: {
|
||||
无条件依赖的可选部件名1:
|
||||
[BUILD.gn文件路径1,
|
||||
BUILD.gn文件路径2,
|
||||
...],
|
||||
无条件依赖的可选部件名2:
|
||||
[BUILD.gn文件路径1,
|
||||
BUILD.gn文件路径2,
|
||||
...],
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 单部件输出格式介绍(ability_runtime.json)
|
||||
|
||||
```
|
||||
{
|
||||
无条件依赖的可选部件名1:
|
||||
[BUILD.gn文件路径1,
|
||||
BUILD.gn文件路径2,
|
||||
...],
|
||||
无条件依赖的可选部件名2:
|
||||
[BUILD.gn文件路径1,
|
||||
BUILD.gn文件路径2,
|
||||
...],
|
||||
[
|
||||
{
|
||||
"file_path": BUILD.gn文件路径,
|
||||
"error": [
|
||||
{
|
||||
"line": 行号,
|
||||
"rule": 触发规则,
|
||||
"detail": 详细说明
|
||||
},
|
||||
...
|
||||
]
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
]
|
||||
```
|
||||
@@ -13,7 +13,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This file contains the comparison between mandatory components and the actual compiled components.
|
||||
# This file provide the detection tool for unconditional dependence of required components on optional components.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
@@ -23,111 +23,131 @@ import re
|
||||
|
||||
class Analyzer:
|
||||
@classmethod
|
||||
def __get_components(cls, config: str):
|
||||
mandatory_components = list()
|
||||
optional_components = list()
|
||||
with open(config, 'r', encoding='utf-8') as r:
|
||||
config_json = json.load(r)
|
||||
inherit = config_json['inherit']
|
||||
for json_name in inherit:
|
||||
with open(json_name, 'r', encoding='utf-8') as r:
|
||||
inherit_file = json.load(r)
|
||||
for subsystem in inherit_file['subsystems']:
|
||||
for component in subsystem['components']:
|
||||
mandatory_components.append(component['component'])
|
||||
def __get_open_components(cls, xml_path):
|
||||
open_components = list()
|
||||
with open(xml_path, 'r', encoding='utf-8') as r:
|
||||
xml_info = r.readlines()
|
||||
for line in xml_info:
|
||||
if "path=" in line:
|
||||
tmp = re.findall('path="(.*?)"', line)[0]
|
||||
open_components.append(tmp.split('/')[-1])
|
||||
return open_components
|
||||
|
||||
@classmethod
|
||||
def __deal_config_json(cls, config_json):
|
||||
components = list()
|
||||
for subsystem in config_json['subsystems']:
|
||||
for component in subsystem['components']:
|
||||
if component not in mandatory_components:
|
||||
optional_components.append(component['component'])
|
||||
return mandatory_components, optional_components
|
||||
if component not in components:
|
||||
components.append(component['component'])
|
||||
return components
|
||||
|
||||
@classmethod
|
||||
def __get_gn_path(cls, parts_deps: str, mandatory: list):
|
||||
mandatory_gn_path = dict()
|
||||
with open(parts_deps, 'r', encoding='utf-8') as r:
|
||||
parts_deps_json = json.load(r)
|
||||
for component in parts_deps_json:
|
||||
if component in mandatory and parts_deps_json[component]:
|
||||
mandatory_gn_path[component] = '/'.join(
|
||||
parts_deps_json[component]['build_config_file'].split('/')[:-1])
|
||||
return mandatory_gn_path
|
||||
def __get_required_components(cls, config_path: str):
|
||||
required_components = list()
|
||||
files = os.listdir(config_path)
|
||||
for file in files:
|
||||
if file.endswith(".json"):
|
||||
with open(os.path.join(config_path, file), 'r', encoding='utf-8') as r:
|
||||
config_json = json.load(r)
|
||||
required_components += cls.__deal_config_json(config_json)
|
||||
return required_components
|
||||
|
||||
@classmethod
|
||||
def __judge_deps(cls, gn_path: str, optional_components):
|
||||
def __get_line(cls, txt_list, key_words: str):
|
||||
for i in range(len(txt_list)):
|
||||
if key_words in txt_list[i]:
|
||||
return i + 1
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
def __judge_deps(cls, gn_path: str, open_components_list, optional_components):
|
||||
error = list()
|
||||
deps = list()
|
||||
dependent_close = True
|
||||
with open(gn_path, 'r', encoding='utf-8') as r:
|
||||
gn = r.readlines()
|
||||
txt = ''
|
||||
for line in gn:
|
||||
txt += line.strip()
|
||||
for optional_component in optional_components:
|
||||
dep_txt = re.findall('deps = \[(.*?)\]', txt) + re.findall('deps += \[(.*?)\]', txt)
|
||||
txt += line
|
||||
key_txt = ' '.join(re.findall('if \(.+?\{(.*?)\}', txt))
|
||||
for component in open_components_list:
|
||||
if dependent_close == True:
|
||||
if component in txt:
|
||||
dependent_close = False
|
||||
for i in range(len(gn)):
|
||||
dep_txt = re.findall('deps = \[(.*?)\]', gn[i]) + re.findall('deps += \[(.*?)\]', gn[i])
|
||||
dep_info = list()
|
||||
for info in dep_txt:
|
||||
if '/' in info:
|
||||
dep_info += re.findall('/(.*?):', info)
|
||||
else:
|
||||
dep_info += re.findall('"(.*?):', info)
|
||||
if optional_component in dep_info:
|
||||
key_txt = ' '.join(re.findall('if \(.+?\{(.*?)\}', txt))
|
||||
if optional_component not in key_txt:
|
||||
deps.append({'component': optional_component, 'gn_path': gn_path})
|
||||
return deps
|
||||
for component in optional_components:
|
||||
if component in dep_info and component not in key_txt:
|
||||
deps.append((component, i + 1))
|
||||
if dependent_close == True and re.findall('deps =', txt):
|
||||
line = cls.__get_line(gn, 'deps =')
|
||||
error.append(
|
||||
{"line": line, "rule": "depend close component", "detail": "可能依赖闭源部件,请检查deps中的内容"})
|
||||
for one_dep in deps:
|
||||
error.append({"line": one_dep[1], "rule": "depend optional component",
|
||||
"detail": "依赖开源部件中的非必选部件{},请检查deps中的内容".format(one_dep[0])})
|
||||
return gn_path, error
|
||||
|
||||
@classmethod
|
||||
def __get_deps(cls, mandatory_gn: dict, optional_components_list: list):
|
||||
all_deps = dict()
|
||||
for component in mandatory_gn.keys():
|
||||
component_deps = list()
|
||||
total_deps = dict()
|
||||
for root, _, files in os.walk(mandatory_gn[component]):
|
||||
if 'BUILD.gn' in files:
|
||||
component_deps += cls.__judge_deps(os.path.join(root, 'BUILD.gn'), optional_components_list)
|
||||
for one_dep in component_deps:
|
||||
if one_dep['component'] not in total_deps.keys():
|
||||
total_deps[one_dep['component']] = [one_dep['gn_path']]
|
||||
else:
|
||||
total_deps[one_dep['component']].append(one_dep['gn_path'])
|
||||
all_deps[component] = total_deps
|
||||
return all_deps
|
||||
|
||||
@classmethod
|
||||
def analysis(cls, config_path: str, parts_deps_path: str, output_file: str, single_component: str):
|
||||
def analysis(cls, gn_path_list, gn_component, config_path: str, open_components_path, result_json_name: str):
|
||||
if not os.path.exists(config_path):
|
||||
print("error: {} is inaccessible or not found".format(config_path))
|
||||
return
|
||||
if not os.path.exists(parts_deps_path):
|
||||
print("error: {} is inaccessible or not found".format(parts_deps_path))
|
||||
if not os.path.exists(open_components_path):
|
||||
print("error: {} is inaccessible or not found".format(open_components_path))
|
||||
return
|
||||
mandatory_components, optional_components = cls.__get_components(config_path)
|
||||
mandatory_components_gn_path = cls.__get_gn_path(parts_deps_path, mandatory_components)
|
||||
deps = cls.__get_deps(mandatory_components_gn_path, optional_components)
|
||||
with os.fdopen(os.open(output_file + ".json", os.O_WRONLY | os.O_CREAT, mode=0o640), "w") as fd:
|
||||
json.dump(deps, fd, indent=4)
|
||||
if single_component != 'false' and single_component in deps.keys():
|
||||
with os.fdopen(os.open(single_component + ".json", os.O_WRONLY | os.O_CREAT, mode=0o640), "w") as fd:
|
||||
json.dump(deps[single_component], fd, indent=4)
|
||||
if len(gn_path_list) != len(gn_component):
|
||||
print(
|
||||
"error: The component corresponding to the gn file and the gn file path are not in one-to-one correspondence.")
|
||||
return
|
||||
required_components = cls.__get_required_components(config_path)
|
||||
open_components = cls.__get_open_components(open_components_path)
|
||||
optional_components = list()
|
||||
for components in open_components:
|
||||
if components not in required_components:
|
||||
optional_components.append(components)
|
||||
result = list()
|
||||
for i in range(len(gn_path_list)):
|
||||
one_result = dict()
|
||||
if gn_component[i] in required_components:
|
||||
one_result["file_path"], one_result["error"] = cls.__judge_deps(gn_path_list[i], open_components,
|
||||
optional_components)
|
||||
else:
|
||||
one_result["file_path"], one_result["error"] = gn_path_list[i], []
|
||||
result.append(one_result)
|
||||
with os.fdopen(os.open(result_json_name + ".json", os.O_WRONLY | os.O_CREAT, mode=0o640), "w",
|
||||
encoding='utf-8') as fd:
|
||||
json.dump(result, fd, indent=4, ensure_ascii=False)
|
||||
|
||||
|
||||
def get_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=f"analyze components deps.\n")
|
||||
parser.add_argument("-c", "--config_json", required=True, type=str,
|
||||
help="path of root path of openharmony/vendor/hihope/{product_name}/config.json")
|
||||
parser.add_argument("-d", "--parts_deps_json", required=True, type=str,
|
||||
help="path of out/{product_name}/build_configs/parts_info/parts_deps.json")
|
||||
parser.add_argument("-s", "--single_component_name", type=str, default="false",
|
||||
help="single component name")
|
||||
parser.add_argument("-o", "--output_file", type=str, default="components_deps",
|
||||
help="eg: demo/components_deps")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
parser.add_argument("-p", "--components_gn_path_list", required=True, type=str,
|
||||
help="path of pr BUILD.gn")
|
||||
parser.add_argument("-g", "--gn_component", required=True, type=str,
|
||||
help="gn file corresponding component")
|
||||
parser.add_argument("-c", "--config_path", required=True, type=str,
|
||||
help="path of config_file")
|
||||
parser.add_argument("-o", "--open_component_xml_path", required=True, type=str,
|
||||
help="open component name set")
|
||||
parser.add_argument("-r", "--result_json_name", type=str, default="result",
|
||||
help="name of output_json")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = get_args()
|
||||
config_json_path = args.config_json
|
||||
parts_deps_json_path = args.parts_deps_json
|
||||
output_file_name = args.output_file
|
||||
single_component = args.single_component_name
|
||||
Analyzer.analysis(config_json_path, parts_deps_json_path, output_file_name, single_component)
|
||||
gn_path_list = args.components_gn_path_list.split(',')
|
||||
gn_component = args.gn_component.split(',')
|
||||
config_path = args.config_path
|
||||
open_components_xml_path = args.open_component_xml_path
|
||||
result_json_name = args.result_json_name
|
||||
Analyzer.analysis(gn_path_list, gn_component, config_path, open_components_xml_path, result_json_name)
|
||||
@@ -20,62 +20,73 @@ import json
|
||||
|
||||
from .base_rule import BaseRule
|
||||
|
||||
|
||||
class HdiRule(BaseRule):
|
||||
RULE_NAME = "NO-Depends-On-HDI"
|
||||
RULE_NAME = "NO-Depends-On-HDI"
|
||||
|
||||
def __check_depends_on_hdi(self):
|
||||
lists = self.get_white_lists()
|
||||
def __check_depends_on_hdi(self):
|
||||
lists = self.get_white_lists()
|
||||
|
||||
passed = True
|
||||
passed = True
|
||||
|
||||
hdi_without_shlib_type = []
|
||||
non_hdi_with_hdi_shlib_type = []
|
||||
hdi_without_shlib_type = []
|
||||
non_hdi_with_hdi_shlib_type = []
|
||||
|
||||
# Check if any napi modules has dependedBy
|
||||
for mod in self.get_mgr().get_all():
|
||||
is_hdi = False
|
||||
if "hdiType" in mod and mod["hdiType"] == "hdi_service":
|
||||
is_hdi = True
|
||||
# Collect non HDI modules with shlib_type of value "hdi"
|
||||
if not is_hdi and ("shlib_type" in mod and mod["shlib_type"] == "hdi"):
|
||||
non_hdi_with_hdi_shlib_type.append(mod)
|
||||
# Check if any napi modules has dependedBy
|
||||
for mod in self.get_mgr().get_all():
|
||||
is_hdi = False
|
||||
if "hdiType" in mod and mod["hdiType"] == "hdi_service":
|
||||
is_hdi = True
|
||||
# Collect non HDI modules with shlib_type of value "hdi"
|
||||
if not is_hdi and ("shlib_type" in mod and mod["shlib_type"] == "hdi"):
|
||||
non_hdi_with_hdi_shlib_type.append(mod)
|
||||
|
||||
# Collect HDI modules without shlib_type with value of "hdi"
|
||||
if is_hdi and ("shlib_type" not in mod or mod["shlib_type"] != "hdi"):
|
||||
if mod["name"] not in lists:
|
||||
hdi_without_shlib_type.append(mod)
|
||||
# Collect HDI modules without shlib_type with value of "hdi"
|
||||
if is_hdi and ("shlib_type" not in mod or mod["shlib_type"] != "hdi"):
|
||||
if mod["name"] not in lists:
|
||||
hdi_without_shlib_type.append(mod)
|
||||
|
||||
if not is_hdi:
|
||||
continue
|
||||
if self.__ignore_mod(mod, is_hdi, lists):
|
||||
continue
|
||||
|
||||
if len(mod["dependedBy"]) == 0:
|
||||
continue
|
||||
# Check if HDI modules is depended by other modules
|
||||
self.error("hdi module %s depended by:" % mod["name"])
|
||||
for dep in mod["dependedBy"]:
|
||||
caller = dep["caller"]
|
||||
self.log(" module [%s] defined in [%s]" % (caller["name"], caller["labelPath"]))
|
||||
passed = False
|
||||
|
||||
if mod["name"] in lists:
|
||||
continue
|
||||
if len(hdi_without_shlib_type) > 0:
|
||||
for mod in hdi_without_shlib_type:
|
||||
if mod["name"] not in lists:
|
||||
passed = False
|
||||
self.error('hdi module %s has no shlib_type="hdi", add it in %s' % (mod["name"], mod["labelPath"]))
|
||||
|
||||
# If hdi module has version_script to specify exported symbols, it can be depended by others
|
||||
if "version_script" in mod:
|
||||
continue
|
||||
if len(non_hdi_with_hdi_shlib_type) > 0:
|
||||
for mod in non_hdi_with_hdi_shlib_type:
|
||||
self.warn('non hdi module %s with shlib_type="hdi", %s' % (mod["name"], mod["labelPath"]))
|
||||
|
||||
# Check if HDI modules is depended by other modules
|
||||
self.error("hdi module %s depended by:" % mod["name"])
|
||||
for dep in mod["dependedBy"]:
|
||||
caller = dep["caller"]
|
||||
self.log(" module [%s] defined in [%s]" % (caller["name"], caller["labelPath"]))
|
||||
passed = False
|
||||
return passed
|
||||
|
||||
if len(hdi_without_shlib_type) > 0:
|
||||
for mod in hdi_without_shlib_type:
|
||||
if mod["name"] not in lists:
|
||||
passed = False
|
||||
self.error('hdi module %s has no shlib_type="hdi", add it in %s' % (mod["name"], mod["labelPath"]))
|
||||
def check(self):
|
||||
return self.__check_depends_on_hdi()
|
||||
|
||||
def __ignore_mod(self, mod, is_hdi, lists):
|
||||
ignore_flag = False
|
||||
if not is_hdi:
|
||||
ignore_flag = True
|
||||
return ignore_flag
|
||||
|
||||
if len(non_hdi_with_hdi_shlib_type) > 0:
|
||||
for mod in non_hdi_with_hdi_shlib_type:
|
||||
self.warn('non hdi module %s with shlib_type="hdi", %s' % (mod["name"], mod["labelPath"]))
|
||||
if len(mod["dependedBy"]) == 0:
|
||||
ignore_flag = True
|
||||
return ignore_flag
|
||||
|
||||
return passed
|
||||
if mod["name"] in lists:
|
||||
ignore_flag = True
|
||||
return ignore_flag
|
||||
|
||||
def check(self):
|
||||
return self.__check_depends_on_hdi()
|
||||
# If hdi module has version_script to specify exported symbols, it can be depended by others
|
||||
if "version_script" in mod:
|
||||
ignore_flag = True
|
||||
|
||||
return ignore_flag
|
||||
|
||||
@@ -6,6 +6,7 @@ import re
|
||||
from pathlib import Path
|
||||
from typing import *
|
||||
|
||||
|
||||
def unit_adaptive(size: int) -> str:
|
||||
unit_list = ["Byte", "KB", "MB", "GB"]
|
||||
index = 0
|
||||
@@ -13,9 +14,10 @@ def unit_adaptive(size: int) -> str:
|
||||
size /= 1024
|
||||
index += 1
|
||||
if index == len(unit_list):
|
||||
index = len(unit_list)-1
|
||||
index = len(unit_list) - 1
|
||||
size *= 1024
|
||||
return str(round(size,2))+unit_list[index]
|
||||
return str(round(size, 2)) + unit_list[index]
|
||||
|
||||
|
||||
class BasicTool:
|
||||
@classmethod
|
||||
@@ -34,7 +36,7 @@ class BasicTool:
|
||||
ptrn = re.compile(ptrn, re.M | re.S)
|
||||
result = re.finditer(ptrn, content)
|
||||
return result
|
||||
|
||||
|
||||
@classmethod
|
||||
def find_all_files(cls, folder: str, real_path: bool = True, apply_abs: bool = True, de_duplicate: bool = True,
|
||||
p_filter: typing.Callable = lambda x: True) -> list:
|
||||
@@ -53,7 +55,7 @@ class BasicTool:
|
||||
@classmethod
|
||||
def get_abs_path(cls, path: str) -> str:
|
||||
return os.path.abspath(os.path.expanduser(path))
|
||||
|
||||
|
||||
@classmethod
|
||||
def re_group_1(cls, content: str, pattern: str, **kwargs) -> str:
|
||||
"""
|
||||
@@ -69,9 +71,9 @@ class BasicTool:
|
||||
if result:
|
||||
return result.group(1)
|
||||
return str()
|
||||
|
||||
|
||||
@classmethod
|
||||
def execute(cls, cmd: str, post_processor: Callable[[Text], Text] = lambda x:x) -> Any:
|
||||
def execute(cls, cmd: str, post_processor: Callable[[Text], Text] = lambda x: x) -> Any:
|
||||
"""
|
||||
封装popen,返回标准输出的列表
|
||||
:param post_processor: 对执行结果进行处理
|
||||
@@ -86,4 +88,4 @@ class BasicTool:
|
||||
|
||||
if __name__ == '__main__':
|
||||
for i in BasicTool.find_all_files(".", apply_abs=False):
|
||||
print(i)
|
||||
print(i)
|
||||
|
||||
@@ -105,7 +105,8 @@ class GnCommonTool:
|
||||
return part_name, subsystem_name
|
||||
|
||||
@classmethod
|
||||
def _parse_part_subsystem(cls, part_var_flag: bool, subsystem_var_flag: bool, var_list: List[str], part_cmd: str, subsystem_cmd: str, gn_file: str, project_path: str) -> Tuple[str, str]:
|
||||
def _parse_part_subsystem(cls, part_var_flag: bool, subsystem_var_flag: bool, var_list: List[str], part_cmd: str,
|
||||
subsystem_cmd: str, gn_file: str, project_path: str) -> Tuple[str, str]:
|
||||
part_name = subsystem_name = None
|
||||
part = os.popen(part_cmd).read().strip()
|
||||
if len(part) != 0:
|
||||
@@ -169,6 +170,7 @@ class GnCommonTool:
|
||||
subsystem_name = t_subsystem_name
|
||||
return part_name, subsystem_name
|
||||
|
||||
|
||||
class GnVariableParser:
|
||||
@classmethod
|
||||
def string_parser(cls, var: str, content: str) -> str:
|
||||
|
||||
@@ -28,8 +28,10 @@ import logging
|
||||
class RomRamBaselineCollector:
|
||||
"""collect baseline of rom and ram from bundle.json
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _put(cls, result_dict: Dict, subsystem_name: str, component_name: str, rom_size: str, ram_size: str, bundle_path: str) -> None:
|
||||
def _put(cls, result_dict: Dict, subsystem_name: str, component_name: str, rom_size: str, ram_size: str,
|
||||
bundle_path: str) -> None:
|
||||
if not result_dict.get(subsystem_name):
|
||||
result_dict[subsystem_name] = dict()
|
||||
result_dict[subsystem_name][component_name] = dict()
|
||||
@@ -43,6 +45,7 @@ class RomRamBaselineCollector:
|
||||
x = x.split("\n")
|
||||
y = [item for item in x if item]
|
||||
return y
|
||||
|
||||
bundle_list = BasicTool.execute(
|
||||
cmd=f"find {oh_path} -name bundle.json", post_processor=post_handler)
|
||||
rom_ram_baseline_dict: Dict[str, Dict] = dict()
|
||||
|
||||
@@ -99,7 +99,7 @@ class RamAnalyzer:
|
||||
|
||||
@classmethod
|
||||
def __parse_hidumper_mem(cls, content: typing.Text, device_num: str, ss: str = "Pss") -> typing.Dict[
|
||||
typing.Text, int]:
|
||||
typing.Text, int]:
|
||||
"""
|
||||
解析:hidumper --meme的结果
|
||||
返回{process_name: pss}形式的字典
|
||||
@@ -141,7 +141,7 @@ class RamAnalyzer:
|
||||
continue
|
||||
name = processed[1] # 否则的话就取名字,和对应的size
|
||||
size = int(processed[cls.__ss_dict.get(ss)]) * \
|
||||
1024 # kilo byte to byte
|
||||
1024 # kilo byte to byte
|
||||
full_process_name = find_full_process_name(name)
|
||||
if not full_process_name:
|
||||
print(
|
||||
@@ -213,7 +213,7 @@ class RamAnalyzer:
|
||||
component_val_dict: typing.Dict[str, str] = sub_val_dict.get(
|
||||
component_name)
|
||||
delete_values_from_dict(component_val_dict, [
|
||||
"size", "file_count"])
|
||||
"size", "file_count"])
|
||||
for file_name, size in component_val_dict.items():
|
||||
file_basename: str = os.path.split(file_name)[-1]
|
||||
elf_info_dict[file_basename] = {
|
||||
@@ -251,12 +251,11 @@ class RamAnalyzer:
|
||||
|
||||
@classmethod
|
||||
def get_process_so_relationship(cls, cfg_path: str, profile_path: str) -> typing.Dict[
|
||||
str, typing.List[str]]:
|
||||
str, typing.List[str]]:
|
||||
"""
|
||||
parse the relationship between process and elf file
|
||||
"""
|
||||
# 从merged_sa里面收集
|
||||
# json_list = glob.glob(json_path + os.sep + "*[.]json", recursive=True)
|
||||
process_elf_dict: typing.Dict[str, typing.List[str]] = dict()
|
||||
cfg_list = glob.glob(cfg_path + os.sep + "*.cfg", recursive=True)
|
||||
for cfg in cfg_list:
|
||||
@@ -289,16 +288,17 @@ class RamAnalyzer:
|
||||
}
|
||||
}
|
||||
"""
|
||||
#print('data_dict',data_dict)
|
||||
tmp_dict = copy.deepcopy(data_dict)
|
||||
writer = SimpleExcelWriter("ram_info")
|
||||
header_unit = "" if unit_adapt else ", Byte"
|
||||
header = header = [
|
||||
"subsystem_name", "component_name", f"component_size(ram{header_unit})", "process_name", f"process_size({ss}{header_unit})", "elf", f"elf_size{'' if unit_adapt else '(Byte)'}"
|
||||
header = [
|
||||
"subsystem_name", "component_name", f"component_size(ram{header_unit})", "process_name",
|
||||
f"process_size({ss}{header_unit})", "elf", f"elf_size{'' if unit_adapt else '(Byte)'}"
|
||||
]
|
||||
if baseline_file:
|
||||
header = [
|
||||
"subsystem_name", "component_name", f"component_size(ram{header_unit})", "baseline", "process_name", f"process_size({ss}{header_unit})", "elf", f"elf_size{'' if unit_adapt else '(Byte)'}"
|
||||
"subsystem_name", "component_name", f"component_size(ram{header_unit})", "baseline", "process_name",
|
||||
f"process_size({ss}{header_unit})", "elf", f"elf_size{'' if unit_adapt else '(Byte)'}"
|
||||
]
|
||||
writer.set_sheet_header(header)
|
||||
subsystem_c = 0
|
||||
@@ -347,7 +347,7 @@ class RamAnalyzer:
|
||||
process_start_r, process_c, process_end_r, process_c, process_name)
|
||||
writer.write_merge(
|
||||
process_start_r, process_size_c, process_end_r, process_size_c, process_size)
|
||||
process_start_r = process_end_r+1
|
||||
process_start_r = process_end_r + 1
|
||||
writer.write_merge(component_start_r, component_c,
|
||||
component_end_r, component_c, component_name)
|
||||
writer.write_merge(component_start_r, component_size_c,
|
||||
@@ -358,7 +358,7 @@ class RamAnalyzer:
|
||||
component_start_r = component_end_r + 1
|
||||
writer.write_merge(subsystem_start_r, subsystem_c,
|
||||
subsystem_end_r, subsystem_c, subsystem_name)
|
||||
subsystem_start_r = subsystem_end_r+1
|
||||
subsystem_start_r = subsystem_end_r + 1
|
||||
writer.save(filename)
|
||||
|
||||
@classmethod
|
||||
@@ -382,7 +382,7 @@ class RamAnalyzer:
|
||||
if cn == "size" or cn == "file_count":
|
||||
continue
|
||||
component_val_dict: typing.Dict[str,
|
||||
int] = sub_val_dict.get(cn)
|
||||
int] = sub_val_dict.get(cn)
|
||||
for k, v in component_val_dict.items():
|
||||
if k == "size" or k == "file_count":
|
||||
continue
|
||||
@@ -406,6 +406,12 @@ class RamAnalyzer:
|
||||
component_info["baseline"] = baseline_dict[subsystem_name][component_name].get(
|
||||
"ram")
|
||||
|
||||
@classmethod
|
||||
def inside_refactored_result_unit_adaptive(cls, process_info):
|
||||
for elf_name, elf_size in process_info["elf"].items():
|
||||
process_info["elf"][elf_name] = unit_adaptive(elf_size)
|
||||
return process_info
|
||||
|
||||
@classmethod
|
||||
def refactored_result_unit_adaptive(cls, result_dict: Dict[str, Dict]) -> None:
|
||||
for subsystem_name, subsystem_info in result_dict.items():
|
||||
@@ -417,14 +423,13 @@ class RamAnalyzer:
|
||||
for process_name, process_info in component_info.items():
|
||||
pro_size = unit_adaptive(process_info["size"])
|
||||
del process_info["size"]
|
||||
for elf_name, elf_size in process_info["elf"].items():
|
||||
process_info["elf"][elf_name] = unit_adaptive(elf_size)
|
||||
process_info = cls.inside_refactored_result_unit_adaptive(process_info)
|
||||
process_info["size"] = pro_size
|
||||
component_info["size"] = com_size
|
||||
subsystem_info["size"] = sub_size
|
||||
|
||||
@classmethod
|
||||
def result_process1(cls,result_dict,process_name,process_size,elf,size):
|
||||
def result_process1(cls, result_dict, process_name, process_size, elf, size):
|
||||
result_dict[process_name] = dict()
|
||||
result_dict[process_name]["size"] = process_size
|
||||
result_dict[process_name]["startup"] = dict()
|
||||
@@ -434,7 +439,7 @@ class RamAnalyzer:
|
||||
return result_dict
|
||||
|
||||
@classmethod
|
||||
def result_process2(cls, result_dict, process_name, subsystem_name, process_size,component_name,hap_name, size):
|
||||
def result_process2(cls, result_dict, process_name, subsystem_name, process_size, component_name, hap_name, size):
|
||||
result_dict[process_name] = dict()
|
||||
result_dict[process_name]["size"] = process_size
|
||||
result_dict[process_name][subsystem_name] = dict()
|
||||
@@ -453,7 +458,7 @@ class RamAnalyzer:
|
||||
return result_dict
|
||||
|
||||
@classmethod
|
||||
def result_process4(cls, result_dict, process_size_dict, rom_result_dict, process_elf_dict,so_info_dict):
|
||||
def result_process4(cls, result_dict, process_size_dict, rom_result_dict, process_elf_dict, so_info_dict):
|
||||
def get(key: typing.Any, dt: typing.Dict[str, typing.Any]):
|
||||
for k, v in dt.items():
|
||||
if k.startswith(key) or (len(v) > 0 and key == v[0]):
|
||||
@@ -468,26 +473,29 @@ class RamAnalyzer:
|
||||
if process_name == "init":
|
||||
_, elf, _, _, size = cls.find_elf_size_from_rom_result(process_name, "startup", "init",
|
||||
lambda x, y: os.path.split(y)[
|
||||
-1].lower() == x.lower(),
|
||||
-1].lower() == x.lower(),
|
||||
rom_result_dict)
|
||||
result_dict=cls.result_process1(result_dict,process_name,process_size,elf,size)
|
||||
result_dict = cls.result_process1(result_dict, process_name, process_size, elf, size)
|
||||
continue
|
||||
# 如果是hap,特殊处理
|
||||
if (process_name.startswith("com.") or process_name.startswith("ohos.")):
|
||||
_, hap_name, subsystem_name, component_name, size = cls.find_elf_size_from_rom_result(process_name, "*", "*",
|
||||
_, hap_name, subsystem_name, component_name, size = cls.find_elf_size_from_rom_result(process_name, "*",
|
||||
"*",
|
||||
lambda x, y: len(
|
||||
y.split(
|
||||
'/')) >= 3 and x.lower().startswith(
|
||||
y.split('/')[2].lower()),
|
||||
y.split('/')[
|
||||
2].lower()),
|
||||
rom_result_dict)
|
||||
result_dict=cls.result_process2(result_dict, process_name, subsystem_name, process_size,component_name,hap_name, size)
|
||||
result_dict = cls.result_process2(result_dict, process_name, subsystem_name, process_size,
|
||||
component_name, hap_name, size)
|
||||
continue
|
||||
# 得到进程相关的elf文件list
|
||||
so_list: list = get(process_name, process_elf_dict)
|
||||
if so_list is None:
|
||||
print("warning: process '{}' not found in .json or .cfg".format(
|
||||
process_name))
|
||||
result_dict=cls.result_process3(result_dict, process_name, process_size)
|
||||
result_dict = cls.result_process3(result_dict, process_name, process_size)
|
||||
continue
|
||||
result_dict[process_name] = dict()
|
||||
result_dict[process_name]["size"] = process_size
|
||||
@@ -509,6 +517,7 @@ class RamAnalyzer:
|
||||
result_dict[process_name][subsystem_name][component_name] = dict()
|
||||
result_dict[process_name][subsystem_name][component_name][so] = so_size
|
||||
return result_dict
|
||||
|
||||
@classmethod
|
||||
def analysis(cls, cfg_path: str, json_path: str, rom_result_json: str, device_num: str,
|
||||
output_file: str, ss: str, output_excel: bool, baseline_file: str, unit_adapt: bool):
|
||||
@@ -532,7 +541,8 @@ class RamAnalyzer:
|
||||
process_size_dict: typing.Dict[str, int] = cls.process_hidumper_info(
|
||||
device_num, ss)
|
||||
result_dict: typing.Dict[str, typing.Dict[str, typing.Any]] = dict()
|
||||
result_dict = cls.result_process4(result_dict, process_size_dict, rom_result_dict, process_elf_dict,so_info_dict)
|
||||
result_dict = cls.result_process4(result_dict, process_size_dict, rom_result_dict, process_elf_dict,
|
||||
so_info_dict)
|
||||
base_dir, _ = os.path.split(output_file)
|
||||
if len(base_dir) != 0 and not os.path.isdir(base_dir):
|
||||
os.makedirs(base_dir, exist_ok=True)
|
||||
@@ -550,6 +560,27 @@ class RamAnalyzer:
|
||||
refactored_result, output_file + ".xls", ss, baseline_file, unit_adapt)
|
||||
|
||||
|
||||
def inside_refacotr_result(component_info, refactored_ram_dict, subsystem_name, component_name, process_name,
|
||||
process_size):
|
||||
for elf_name, elf_size in component_info.items():
|
||||
if not refactored_ram_dict.get(subsystem_name):
|
||||
refactored_ram_dict[subsystem_name] = dict()
|
||||
refactored_ram_dict[subsystem_name]["size"] = 0
|
||||
if not refactored_ram_dict[subsystem_name].get(component_name):
|
||||
refactored_ram_dict[subsystem_name][component_name] = dict(
|
||||
)
|
||||
refactored_ram_dict[subsystem_name][component_name]["size"] = 0
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name] = dict(
|
||||
)
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name]["size"] = process_size
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name]["elf"] = dict(
|
||||
)
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name]["elf"][elf_name] = elf_size
|
||||
refactored_ram_dict[subsystem_name]["size"] += process_size
|
||||
refactored_ram_dict[subsystem_name][component_name]["size"] += process_size
|
||||
return refactored_ram_dict
|
||||
|
||||
|
||||
def refacotr_result(ram_result: Dict[str, Dict]) -> Dict[str, Dict]:
|
||||
refactored_ram_dict: Dict[str, Dict] = dict()
|
||||
for process_name, process_info in ram_result.items():
|
||||
@@ -557,22 +588,8 @@ def refacotr_result(ram_result: Dict[str, Dict]) -> Dict[str, Dict]:
|
||||
del process_info["size"]
|
||||
for subsystem_name, subsystem_info in process_info.items():
|
||||
for component_name, component_info in subsystem_info.items():
|
||||
for elf_name, elf_size in component_info.items():
|
||||
if not refactored_ram_dict.get(subsystem_name):
|
||||
refactored_ram_dict[subsystem_name] = dict()
|
||||
refactored_ram_dict[subsystem_name]["size"] = 0
|
||||
if not refactored_ram_dict[subsystem_name].get(component_name):
|
||||
refactored_ram_dict[subsystem_name][component_name] = dict(
|
||||
)
|
||||
refactored_ram_dict[subsystem_name][component_name]["size"] = 0
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name] = dict(
|
||||
)
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name]["size"] = process_size
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name]["elf"] = dict(
|
||||
)
|
||||
refactored_ram_dict[subsystem_name][component_name][process_name]["elf"][elf_name] = elf_size
|
||||
refactored_ram_dict[subsystem_name]["size"] += process_size
|
||||
refactored_ram_dict[subsystem_name][component_name]["size"] += process_size
|
||||
refactored_ram_dict = inside_refacotr_result(component_info, refactored_ram_dict, subsystem_name,
|
||||
component_name, process_name, process_size)
|
||||
return refactored_ram_dict
|
||||
|
||||
|
||||
@@ -615,8 +632,9 @@ if __name__ == '__main__':
|
||||
rom_result = args.rom_result
|
||||
device_num = args.device_num
|
||||
output_filename = args.output_filename
|
||||
baseline_file = args.baseline_file
|
||||
output_excel = args.excel
|
||||
unit_adapt = args.unit_adaptive
|
||||
baseline = args.baseline_file
|
||||
output_excel_path = args.excel
|
||||
unit_adaptiv = args.unit_adaptive
|
||||
RamAnalyzer.analysis(cfg_path, profile_path, rom_result,
|
||||
device_num=device_num, output_file=output_filename, ss="Pss", output_excel=output_excel, baseline_file=baseline_file, unit_adapt=unit_adapt)
|
||||
device_num=device_num, output_file=output_filename, ss="Pss", output_excel=output_excel_path,
|
||||
baseline_file=baseline, unit_adapt=unit_adaptiv)
|
||||
@@ -109,14 +109,17 @@ class RomAnalyzer:
|
||||
if label:
|
||||
cs_flag = True
|
||||
gn_path = os.path.join(project_path, label.split(':')[
|
||||
0].lstrip('/'), "BUILD.gn")
|
||||
0].lstrip('/'), "BUILD.gn")
|
||||
component_name = unit.get("part_name")
|
||||
subsystem_name = unit.get("subsystem_name")
|
||||
if (not component_name) or (not subsystem_name):
|
||||
if not component_name:
|
||||
cn, sn = GnCommonTool.find_part_subsystem(
|
||||
gn_path, project_path)
|
||||
component_name = cn if not component_name else component_name
|
||||
subsystem_name = sn if not subsystem_name else subsystem_name
|
||||
component_name = cn
|
||||
if not subsystem_name:
|
||||
cn, sn = GnCommonTool.find_part_subsystem(
|
||||
gn_path, project_path)
|
||||
subsystem_name = sn
|
||||
else:
|
||||
print("warning: keyword 'label' not found in {}".format(unit))
|
||||
for target in dest:
|
||||
@@ -126,14 +129,24 @@ class RomAnalyzer:
|
||||
"subsystem_name": subsystem_name,
|
||||
"gn_path": gn_path,
|
||||
}
|
||||
continue
|
||||
tmp = target.split('/')[-1]
|
||||
pre_info = extra_info.get(tmp)
|
||||
if not pre_info:
|
||||
continue
|
||||
else:
|
||||
tmp = target.split('/')[-1]
|
||||
pre_info = extra_info.get(tmp)
|
||||
if not pre_info:
|
||||
continue
|
||||
product_info_dict[target] = pre_info
|
||||
return product_info_dict
|
||||
|
||||
@classmethod
|
||||
def __inside_save_result_as_excel(cls, add_baseline, subsystem_name, component_name,
|
||||
baseline, file_name, size):
|
||||
if add_baseline:
|
||||
return [subsystem_name, component_name,
|
||||
baseline, file_name, size]
|
||||
else:
|
||||
return [subsystem_name, component_name, file_name, size]
|
||||
|
||||
@classmethod
|
||||
def __save_result_as_excel(cls, result_dict: dict, output_name: str, add_baseline: bool):
|
||||
header = ["subsystem_name", "component_name",
|
||||
@@ -173,10 +186,8 @@ class RomAnalyzer:
|
||||
component_end_row += component_file_count
|
||||
|
||||
for file_name, size in component_dict.items():
|
||||
line = [subsystem_name, component_name, file_name, size]
|
||||
if add_baseline:
|
||||
line = [subsystem_name, component_name,
|
||||
baseline, file_name, size]
|
||||
line = cls.__inside_save_result_as_excel(add_baseline, subsystem_name, component_name,
|
||||
baseline, file_name, size)
|
||||
excel_writer.append_line(line)
|
||||
excel_writer.write_merge(component_start_row, component_col, component_end_row, component_col,
|
||||
component_name)
|
||||
@@ -190,7 +201,8 @@ class RomAnalyzer:
|
||||
excel_writer.save(output_name + ".xls")
|
||||
|
||||
@classmethod
|
||||
def __put(cls, unit: typing.Dict[Text, Any], result_dict: typing.Dict[Text, Dict], baseline_dict: Dict[str, Any], add_baseline: bool):
|
||||
def __put(cls, unit: typing.Dict[Text, Any], result_dict: typing.Dict[Text, Dict], baseline_dict: Dict[str, Any],
|
||||
baseline: bool):
|
||||
|
||||
component_name = NOTFOUND if unit.get(
|
||||
"component_name") is None else unit.get("component_name")
|
||||
@@ -201,6 +213,7 @@ class RomAnalyzer:
|
||||
if (not baseline_dict.get(subsystem_name)) or (not baseline_dict.get(subsystem_name).get(component_name)):
|
||||
return str()
|
||||
return baseline_dict.get(subsystem_name).get(component_name).get("rom")
|
||||
|
||||
size = unit.get("size")
|
||||
relative_filepath = unit.get("relative_filepath")
|
||||
if result_dict.get(subsystem_name) is None: # 子系统
|
||||
@@ -212,7 +225,7 @@ class RomAnalyzer:
|
||||
result_dict[subsystem_name][component_name] = dict()
|
||||
result_dict[subsystem_name][component_name]["size"] = 0
|
||||
result_dict[subsystem_name][component_name]["file_count"] = 0
|
||||
if add_baseline:
|
||||
if baseline:
|
||||
result_dict[subsystem_name][component_name]["baseline"] = get_rom_baseline(
|
||||
)
|
||||
|
||||
@@ -238,7 +251,8 @@ class RomAnalyzer:
|
||||
|
||||
@classmethod
|
||||
def analysis(cls, system_module_info_json: Text, product_dirs: List[str],
|
||||
project_path: Text, product_name: Text, output_file: Text, output_execel: bool, add_baseline: bool, unit_adapt: bool):
|
||||
project_path: Text, product_name: Text, output_file: Text, output_execel: bool, add_baseline: bool,
|
||||
unit_adapt: bool):
|
||||
"""
|
||||
system_module_info_json: json文件
|
||||
product_dirs:要处理的产物的路径列表如["vendor", "system/"]
|
||||
@@ -258,7 +272,8 @@ class RomAnalyzer:
|
||||
pre_collector.collect_sa_profile()
|
||||
extra_product_info_dict: Dict[str, Dict] = pre_collector.result_dict
|
||||
product_info_dict = cls.__collect_product_info(
|
||||
system_module_info_json, project_path, extra_info=extra_product_info_dict) # collect product info from json file
|
||||
system_module_info_json, project_path,
|
||||
extra_info=extra_product_info_dict) # collect product info from json file
|
||||
result_dict: Dict[Text:Dict] = dict()
|
||||
for d in product_dirs:
|
||||
file_list: List[Text] = BasicTool.find_all_files(d)
|
||||
@@ -316,12 +331,12 @@ def get_args():
|
||||
if __name__ == '__main__':
|
||||
args = get_args()
|
||||
module_info_json = args.module_info_json
|
||||
project_path = args.project_path
|
||||
project_origin_path = args.project_path
|
||||
product_name = args.product_name
|
||||
product_dirs = args.product_dir
|
||||
output_file = args.output_file
|
||||
output_excel = args.excel
|
||||
add_baseline = args.baseline
|
||||
unit_adapt = args.unit_adaptive
|
||||
baseline_path = args.baseline
|
||||
unit_adaptiv = args.unit_adaptive
|
||||
RomAnalyzer.analysis(module_info_json, product_dirs,
|
||||
project_path, product_name, output_file, output_excel, add_baseline, unit_adapt)
|
||||
project_origin_path, product_name, output_file, output_excel, baseline_path, unit_adaptiv)
|
||||
|
||||
Reference in New Issue
Block a user