diff --git a/tools/deps_guard/deps_guard.py b/tools/deps_guard/deps_guard.py
index fbd7e023394982ea40b9d713d0ed19bb376bb05f..5572aab0fd0a1712e7fa22fdae4ae8ce22f0b946 100755
--- a/tools/deps_guard/deps_guard.py
+++ b/tools/deps_guard/deps_guard.py
@@ -34,7 +34,7 @@ def __createArgParser():
return parser
-def deps_guard(out_path, args=None):
+def _deps_guard_module(out_path, args=None):
mgr = ElfFileMgr(out_path)
mgr.scan_all_files()
@@ -47,6 +47,23 @@ def deps_guard(out_path, args=None):
raise Exception("ERROR: deps_guard failed.")
+def _startup_guard_module(out_path, args):
+ import sys
+ import os
+ for path in sys.path:
+ if path.endswith("developtools/integration_verification/tools/deps_guard"):
+ sys.path.append(os.path.join(
+ path, "../startup_guard"))
+ break
+
+ from startup_guard import startup_guard
+
+ startup_guard(out_path, args)
+
+def deps_guard(out_path, args=None):
+ _deps_guard_module(out_path, args)
+ _startup_guard_module(out_path, args)
+
if __name__ == '__main__':
parser = __createArgParser()
diff --git a/tools/startup_guard/README.md b/tools/startup_guard/README.md
new file mode 100755
index 0000000000000000000000000000000000000000..68dae13364f5a5a084bbd718986981404c1fa6c3
--- /dev/null
+++ b/tools/startup_guard/README.md
@@ -0,0 +1,10 @@
+# 启动资源管控
+
+启动资源管控是对启动过程中配置文件(\*.cfg)和系统参数配置文件(\*.para", \*.para.dac)的管控, 约束各子模块的启动资源配置。通过对OpenHarmony镜像中的启动配置文件(\*.cfg)和系统参数配置文件(\*.para", \*.para.dac), 通过对白名单的检查, 完成对启动资源的管控。
+
+支持的拦截规则如下:
+
+| 规则名 | 规则说明 |
+| -------------------------------------------------------- | ------------------------------------------------------------ |
+| [NO-Config-Cmds-In-Init](rules/NO-Config-Cmds-In-Init/README.md) | 所有启动配置文件cmd管控 |
+| [NO-Config-SystemParameter-In-INIT](rules/NO-Config-SystemParameter-In-INIT/README.md) | 所有系统参数管控 |
diff --git a/tools/startup_guard/config_parser_mgr/__init__.py b/tools/startup_guard/config_parser_mgr/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..065104e03096d8111fb2144eae4e741edff79c04
--- /dev/null
+++ b/tools/startup_guard/config_parser_mgr/__init__.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from .config_parser_mgr import ConfigParserMgr
diff --git a/tools/startup_guard/config_parser_mgr/cfg/config_parser.py b/tools/startup_guard/config_parser_mgr/cfg/config_parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..299a805affc50e8259af4f8acb440d36684c141f
--- /dev/null
+++ b/tools/startup_guard/config_parser_mgr/cfg/config_parser.py
@@ -0,0 +1,519 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import json
+import pprint
+
+def _create_arg_parser():
+ import argparse
+ parser = argparse.ArgumentParser(description='Collect init config information from xxxx/etc/init dir.')
+ parser.add_argument('-i', '--input',
+ help='input init config files base directory example "out/rk3568/packages/phone/" ',
+ action='append', required=True)
+
+ parser.add_argument('-o', '--output',
+ help='output init config information database directory', required=False)
+ parser.add_argument('-b', '--bootevent',
+ help='input bootevent file from system ', required=False)
+ return parser
+
+class ItemParser(dict):
+ def __init__(self, config):
+ self._config_parser = config
+ self["name"] = ""
+ def create(self, json_node, parent = None, fileId = None):
+ return
+
+ def update(self, json_node, parent = None, fileId = None):
+ return
+
+ def get_name(self):
+ return self["name"]
+
+ def get(self, key):
+ if self.__contains__(key):
+ return self[key]
+ return None
+
+ # get value form json array
+ def get_strings_value(self, jsonStrArray):
+ if jsonStrArray == None or len(jsonStrArray) == 0:
+ return ""
+
+ string = jsonStrArray[0]
+ for i in range(1, len(jsonStrArray)):
+ string = string + "@" + jsonStrArray[i]
+ return string
+
+class CmdParser(ItemParser):
+ def __init__(self, config):
+ ItemParser.__init__(self, config)
+ self["content"] = ""
+ self["fileId"] = -1
+
+ def create(self, json_node, parent = None, fileId = None):
+ assert(isinstance(json_node, str))
+ assert(parent != None)
+ info = json_node.partition(" ") # 取第一个空格分割
+ self["name"] = info[0]
+ self["jobId"] = parent.get("jobId")
+ if fileId:
+ self["fileId"] = fileId
+ if len(info) > 2:
+ self["content"] = info[2]
+ #print("Create cmd %s %d" % (self["name"], self["fileId"]))
+ return
+
+ def __str__(self):
+ return "cmd \"%s\" content \"%s\" " % (self["name"], self["content"])
+
+class JobParser(ItemParser):
+ def __init__(self, config):
+ ItemParser.__init__(self, config)
+ self["condition"] = ""
+ self["serviceId"] = -1
+ self["fileId"] = -1
+ self["jobPriority"] = -1
+ self["jobPriority"] = -1
+ self["executionTime"] = 0
+
+ def _add_cmds(self, cmdList, fileId):
+ for cmd in cmdList:
+ self._config_parser.add_cmd(cmd, self, fileId)
+
+ def create(self, json_node, parent = None, fileId = None):
+ assert(isinstance(json_node, dict))
+ self["name"] = json_node["name"]
+ self["jobId"] = self._config_parser.get_job_id()
+ #print("JobParser %s %d" % (json_node["name"], fileId))
+ self["jobPriority"] = self._config_parser.get_job_priority(json_node["name"])
+
+ if fileId and self["fileId"] is None:
+ self["fileId"] = fileId
+ if parent != None:
+ self["serviceId"] = parent.get("serviceId")
+
+ if json_node.__contains__("condition"):
+ self["condition"] = json_node.get("condition")
+ if json_node.__contains__("cmds"):
+ self._add_cmds(json_node.get("cmds"), fileId)
+
+ return
+
+ def update(self, json_node, parent = None, fileId = None):
+ assert(isinstance(json_node, dict))
+ if parent != None:
+ self["serviceId"] = parent.get("serviceId")
+ if fileId and self["fileId"] is None:
+ self["fileId"] = fileId
+ if json_node.__contains__("cmds"):
+ self._add_cmds(json_node.get("cmds"), fileId)
+ return
+
+ def __str__(self):
+ return "jobs '%s' condition '%s' " % (self["name"], self["condition"])
+
+class ServiceParser(ItemParser):
+ def __init__(self, config):
+ ItemParser.__init__(self, config)
+ self["critical_enable"] = False
+ self["limit_time"] = 20
+ self["limit_count"] = 4
+ self["importance"] = 0
+ self["once"] = False
+ self["console"] = False
+ self["notify_state"] = True
+ self["on_demand"] = False
+ self["sandbox"] = False
+ self["disabled"] = False
+ self["start_mode"] = "normal"
+ self["secon"] = ""
+ self["boot_job"] = ""
+ self["start_job"] = ""
+ self["stop_job"] = ""
+ self["restart_job"] = ""
+ self["path"] = ""
+ self["apl"] = ""
+ self["d_caps"] = ""
+ self["permission"] = ""
+ self["permission_acls"] = ""
+ self["fileId"] = -1
+
+ def _handle_string_filed(self, json_node):
+ str_field_map = {
+ "uid" : "uid", "caps":"caps", "start_mode":"start-mode", "secon":"secon", "apl":"apl"
+ }
+ for key, name in str_field_map.items():
+ if json_node.__contains__(name):
+ self[key] = json_node.get(name)
+
+ def _handle_integer_filed(self, json_node):
+ str_field_map = {
+ "importance" : "importance"
+ }
+ for key, name in str_field_map.items():
+ if json_node.__contains__(name):
+ self[key] = json_node.get(name)
+
+ def _handle_Bool_filed(self, json_node):
+ bool_field_map = {
+ "once" : "once", "console" : "console", "notify_state" : "notify_state",
+ "on_demand" : "ondemand", "sandbox" : "sandbox", "disabled" : "disabled",
+ "critical_enable" : "critical_enable"
+ }
+ for key, name in bool_field_map.items():
+ if json_node.__contains__(name):
+ value = json_node.get(name)
+ if isinstance(value, bool):
+ self[key] = value
+ elif isinstance(value, int):
+ self[key] = value != 0
+
+ def _handle_array_filed(self, json_node):
+ array_field_map = {
+ "path" : "path", "gid" : "gid", "cpu_core" : "cpucore", "caps":"caps", "write_pid":"writepid",
+ "d_caps":"d-caps", "permission":"permission", "permission_acls":"permission_acls",
+ }
+ for key, name in array_field_map.items():
+ if json_node.__contains__(name) :
+ self[key] = self.get_strings_value(json_node.get(name))
+
+ def _handle_scope_jobs(self, json_node):
+ job_field_map = {
+ "boot_job" : "on_boot", "start_job" : "on-start", "stop_job":"on-stop", "restart_job":"on-restart"
+ }
+ for key, name in job_field_map.items():
+ if json_node.__contains__(name):
+ self[key] = json_node.get(name)
+ self._config_parser.add_job({"name" : json_node.get(name)}, self, self["fileId"])
+
+ def create(self, json_node, parent = None, fileId = None):
+ assert(isinstance(json_node, dict))
+ self["name"] = json_node["name"]
+ if not self.get("serviceId") :
+ self["serviceId"] = self._config_parser.get_service_id()
+ if fileId :
+ self["fileId"] = fileId
+ self._handle_string_filed(json_node)
+ self._handle_Bool_filed(json_node)
+ self._handle_array_filed(json_node)
+ self._handle_integer_filed(json_node)
+
+ #for file
+ if json_node.__contains__("file"):
+ for item in json_node.get("file"):
+ self._config_parser.add_service_file(item, self)
+
+ #for socket
+ if json_node.__contains__("socket"):
+ for item in json_node.get("socket"):
+ self._config_parser.add_service_socket(item, self)
+ #for jobs
+ if json_node.__contains__("jobs"):
+ self._handle_scope_jobs(json_node.get("jobs"))
+
+ #for critical
+ if json_node.__contains__("critical"):
+ critical = json_node.get("critical")
+ if isinstance(critical, list):
+ self["critical_enable"] = int(critical[0]) != 0
+ self["limit_time"] = int(critical[0])
+ self["limit_count"] = int(critical[0])
+ else:
+ self["critical_enable"] = int(critical) != 0
+ return
+
+ def update(self, json_node, parent = None, fileId = None):
+ self.create(json_node, parent, fileId)
+ return
+
+class ServiceSocketParser(ItemParser):
+ def __init__(self, config):
+ ItemParser.__init__(self, config)
+ self["family"] = ""
+ self["type"] = ""
+ self["protocol"] = ""
+ self["permissions"] = ""
+ self["uid"] = ""
+ self["gid"] = ""
+ self["serviceId"] = -1
+
+ def create(self, json_node, parent = None, file_id = None):
+ assert(isinstance(json_node, dict))
+ self["name"] = json_node["name"]
+ if parent != None:
+ self["serviceId"] = parent.get("serviceId")
+ fields = ["family", "type", "protocol", "permissions", "uid", "gid"]
+ for field in fields:
+ if json_node.get(field) :
+ self[field] = json_node.get(field)
+ if json_node.get("option") :
+ self["option"] = self.get_strings_value(json_node.get("option"))
+
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ return "socket '%s' serviceid = %d family %s" % (self["name"], self["serviceId"], self["family"])
+
+class ServiceFileParser(ItemParser):
+ def __init__(self, config):
+ ItemParser.__init__(self, config)
+ self["name"] = ""
+ self["content"] = ""
+ self["serviceId"] = -1
+
+ def create(self, json_node, parent = None, file_id = None):
+ assert(isinstance(json_node, str))
+ if parent != None:
+ self["serviceId"] = parent.get("serviceId")
+ info = json_node.partition(" ")
+ self["name"] = info[0]
+ if len(info) > 2:
+ self["content"] = info[2]
+ return
+
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ return "file '%s' serviceid = %d content '%s'" % (self["name"], self["serviceId"], self["content"])
+
+class ConfigParser():
+ def __init__(self, path):
+ self._path = path
+ self._jobs = {}
+ self._files = {}
+ self._cmds = []
+ self._services = {}
+ self._serviceSockets = {}
+ self._serviceFiles = {}
+ self._jobId = 0
+ self._file_id = 0
+ self._serviceId = 0
+ self._selinux = ""
+
+ def _load_services(self, json_node, file_id):
+ assert(isinstance(json_node, list))
+ for item in json_node:
+ self.add_service(item, file_id)
+ return
+
+ def _load_jobs(self, json_node, file_id):
+ assert(isinstance(json_node, list))
+ for item in json_node:
+ self.add_job(item, None, file_id)
+ return
+
+ def _load_import(self, import_node):
+ assert(isinstance(import_node, list))
+ start_with = [ "/system", "/chip_prod", "/sys_prod", "/vendor" ]
+ for file in import_node:
+ found = False
+ for start in start_with:
+ if file.startswith(start):
+ found = True
+ break
+ if found :
+ self.load_config(self._path + file)
+ else:
+ for start in start_with:
+ self.load_config(self._path + start + file, file)
+
+ def load_config(self, file_name):
+ path = self._path + file_name
+ if not os.path.exists(path):
+ print("Error, invalid config file %s" % path)
+ return
+ with open(path, encoding='utf-8') as content:
+ try:
+ root = json.load(content)
+ fileId = self.add_File(file_name)
+ # print("loadConfig %d file_name = %s" % (fileId, file_name))
+ assert(isinstance(root, dict))
+ if (root.__contains__("services")):
+ self._load_services(root["services"], fileId)
+ if (root.__contains__("jobs")):
+ self._load_jobs(root["jobs"], fileId)
+ if (root.__contains__("import")):
+ self._load_import(root["import"])
+ pass
+ except:
+ pass
+
+ def add_File(self, file_name):
+ if self._files.get(file_name):
+ return self._files.get(file_name).get("fileId")
+ self._file_id = self._file_id + 1
+ self._files[file_name] = {
+ "fileId" : self._file_id,
+ "file_name" : file_name
+ }
+ return self._files[file_name].get("fileId")
+
+ def add_job(self, item, service, file_id):
+ if self._jobs.get(item.get("name")):
+ self._jobs.get(item.get("name")).update(item, service, file_id)
+ return
+ parser = JobParser(self)
+ parser.create(item, service, file_id)
+ self._jobs[parser.get_name()] = parser
+
+ def add_cmd(self, item, job, file_id):
+ parser = CmdParser(self)
+ parser.create(item, job, file_id)
+ self._cmds.append(parser)
+
+ def add_service(self, item, file_id):
+ if self._services.get(item.get("name")):
+ self._services.get(item.get("name")).update(item)
+ return
+ parser = ServiceParser(self)
+ parser.create(item, None, file_id)
+ self._services[parser.get("name")] = parser
+
+ def add_service_socket(self, item, service):
+ parser = ServiceSocketParser(self)
+ parser.create(item, service)
+ self._serviceSockets[parser.get_name()] = parser
+
+ def add_service_file(self, item, service):
+ parser = ServiceFileParser(self)
+ parser.create(item, service)
+ self._serviceFiles[parser.get_name()] = parser
+
+ def get_job_id(self):
+ self._jobId = self._jobId + 1
+ return self._jobId
+
+ def get_service_id(self):
+ self._serviceId = self._serviceId + 1
+ return self._serviceId
+
+ def dump_config(self):
+ # print("Dump jobs: \n")
+ pp = pprint.PrettyPrinter(indent = 0, compact=True)
+ pp.pprint(self._jobs)
+ pass
+
+ def _is_valid_file(self, file):
+ valid_file_ext = [".cfg"]
+ if not file.is_file():
+ return False
+ for ext in valid_file_ext:
+ if file.name.endswith(ext):
+ return True
+ return False
+
+ def _scan_config_file(self, file_name):
+ dir = self._path + file_name
+ if not os.path.exists(dir):
+ return
+ try:
+ with os.scandir(dir) as files:
+ for file in files:
+ if self._is_valid_file(file):
+ name = file.path[len(self._path) :]
+ self.load_config(name)
+ except:
+ pass
+
+ def scan_config(self):
+ config_paths = [
+ "/system/etc/init",
+ "/chip_prod/etc/init",
+ "/sys_prod/etc/init",
+ "/vendor/etc/init",
+ ]
+ for file_name in config_paths:
+ self._scan_config_file(file_name)
+
+ def get_job_priority(self, job_name):
+ job_priority = {
+ "pre-init" : 0,
+ "init" : 1,
+ "post-init" : 2,
+ "early-fs" : 3,
+ "fs" : 4,
+ "post-fs" : 5,
+ "late-fs" : 6,
+ "post-fs-data" : 7,
+ "firmware_mounts_complete" : 8,
+ "early-boot" : 9,
+ "boot" : 10
+ }
+
+ if (job_priority.__contains__(job_name)):
+ # print("get_job_priority %s %d" % (job_name, job_priority.get(job_name)))
+ return job_priority.get(job_name)
+ return 100
+
+ def _load_boot_event(self, event):
+ if self._jobs.__contains__(event.get("name")):
+ print("loadBootEvent_ %s %f" % (event.get("name"), event.get("dur")))
+ self._jobs.get(event.get("name"))["executionTime"] = event.get("dur")
+
+ def load_boot_event_file(self, boot_event_file):
+ if not os.path.exists(boot_event_file):
+ print("Error, invalid config file %s" % boot_event_file)
+ return
+ #print("loadConfig file_name = %s" % file_name)
+ with open(boot_event_file, encoding='utf-8') as content:
+ try:
+ root = json.load(content)
+ for item in root:
+ self._load_boot_event(item)
+ except:
+ pass
+ pass
+
+ def load_selinux_config(self, file_name):
+ path = self._path + file_name
+ if not os.path.exists(path):
+ print("Error, invalid selinux config file %s" % path)
+ return
+ try:
+ with open(path, encoding='utf-8') as fp:
+ line = fp.readline()
+ while line :
+ if line.startswith("#") or len(line) < 3:
+ line = fp.readline()
+ continue
+ param_Info = line.partition("=")
+ if len(param_Info) != 3:
+ line = fp.readline()
+ continue
+ if param_Info[0].strip() == "SELINUX":
+ self._selinux = param_Info[2].strip()
+ line = fp.readline()
+ except:
+ print("Error, invalid parameter file ", file_name)
+ pass
+
+def startup_config_collect(base_path):
+ parser = ConfigParser(base_path + "/packages/phone")
+ parser.load_config("/system/etc/init.cfg")
+ parser.scan_config()
+ parser.load_selinux_config("/system/etc/selinux/config")
+ return parser
+
+if __name__ == '__main__':
+ args_parser = _create_arg_parser()
+ options = args_parser.parse_args()
+ startup_config_collect(options.input)
diff --git a/tools/startup_guard/config_parser_mgr/config_parser_mgr.py b/tools/startup_guard/config_parser_mgr/config_parser_mgr.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6e81542cb6c36ec4724b68f71cd65c9e6ce20e9
--- /dev/null
+++ b/tools/startup_guard/config_parser_mgr/config_parser_mgr.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import sys
+sys.path.append('.')
+
+from .param.system_parameter_parser import parameters_collect
+from .cfg.config_parser import startup_config_collect
+
+def __create_arg_parser():
+ import argparse
+ parser = argparse.ArgumentParser(description='Check startup architecture information from compiled output files.')
+ parser.add_argument('-i', '--input',
+ help='input config files base directory example "out/rk3568/packages/phone/" ', required=True)
+ return parser
+
+class ConfigParserMgr(object):
+ def __init__(self, path = None):
+ self._path = path
+ self._parser_list = {}
+
+ def load_all_parser(self, options):
+ cfg_parser = startup_config_collect(options)
+ param_parser = parameters_collect(options)
+ self._parser_list = {'cmd_whitelist':cfg_parser, 'system_parameter_whitelist':param_parser}
+
+ def get_parser_by_name(self, key):
+ if key:
+ return self._parser_list[key]
+
+if __name__ == '__main__':
+ args_parser = __create_arg_parser()
+ options = args_parser.parse_args()
+ mgr = ConfigParserMgr()
+ mgr.load_all_parser(options)
diff --git a/tools/startup_guard/config_parser_mgr/param/system_parameter_parser.py b/tools/startup_guard/config_parser_mgr/param/system_parameter_parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb07b6d0f304d977f81ef3e48e6ec3b4ba2092f9
--- /dev/null
+++ b/tools/startup_guard/config_parser_mgr/param/system_parameter_parser.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+
+class ParameterParser(dict):
+ def __init__(self, prefix, parameter = None):
+ self["prefix"] = prefix
+ if parameter == None:
+ self["type"] = "string"
+ self["dacUser"] = ""
+ self["dacGroup"] = ""
+ self["dacMode"] = 0
+ self["selinuxLabel"] = ""
+ self["value"] = ""
+ else:
+ self["type"] = parameter.get("type")
+ self["dacUser"] = parameter.get("dacUser")
+ self["dacGroup"] = parameter.get("dacGroup")
+ self["dacMode"] = parameter.get("dacMode")
+ self["selinuxLabel"] = parameter.get("selinuxLabel")
+ self["value"] = parameter.get("value")
+
+ def decode(self, info):
+ self["value"] = info.strip("\"").strip("\'")
+ #print("value '%s'" % self["value"])
+ return True
+
+ def __repr__(self):
+ return self.__str__()
+
+ def __str__(self):
+ return "%s= DAC[%s:%s:%s] selinux[%s] value=%s" % (self["prefix"], self["dacUser"], self["dacGroup"], self["dacMode"], self["selinuxLabel"], self["value"])
+
+class ParameterDacParser(ParameterParser):
+ def __init__(self, prefix, parameter=None):
+ ParameterParser.__init__(self, prefix, parameter)
+
+ def decode(self, info):
+ dacInfo = info.strip("\"").strip("\'").split(":")
+ if len(dacInfo) < 3:
+ print("Invalid dac %s" % info)
+ return False
+
+ self["dacUser"] = dacInfo[0]
+ self["dacGroup"] = dacInfo[1]
+ self["dacMode"] = dacInfo[2]
+ if len(dacInfo) > 3:
+ self["type"] = dacInfo[3]
+ return True
+
+class ParameterSelinuxParser(ParameterParser):
+ def __init__(self, prefix, parameter=None):
+ ParameterParser.__init__(self, prefix, parameter)
+
+ def decode(self, info):
+ self["selinuxLabel"] = info
+ #print("name %s selinux %s" % (self["prefix"], info))
+ return True
+
+class ParameterFileParser():
+ def __init__(self):
+ self._parameters = {}
+
+ def _handle_param_info(self, file_name, param_info):
+ param_name = param_info[0].strip()
+ old_param = self._parameters.get(param_name)
+ if file_name.endswith(".para.dac"):
+ param = ParameterDacParser(param_name, old_param)
+ if (param.decode(param_info[2].strip())):
+ self._parameters[param_name] = param
+ elif file_name.endswith(".para"):
+ param = ParameterParser(param_name, old_param)
+ if (param.decode(param_info[2].strip())):
+ self._parameters[param_name] = param
+ else:
+ param = ParameterSelinuxParser(param_name, old_param)
+ if (param.decode(param_info[2].strip())):
+ self._parameters[param_name] = param
+
+ def load_parameter_file(self, file_name, str = "="):
+ # print(" loadParameterFile %s" % fileName)
+ try:
+ with open(file_name, encoding='utf-8') as fp:
+ line = fp.readline()
+ while line :
+ #print("line %s" % (line))
+ if line.startswith("#") or len(line) < 3:
+ line = fp.readline()
+ continue
+ paramInfo = line.partition(str)
+ if len (paramInfo) != 3:
+ line = fp.readline()
+ continue
+ self._handle_param_info(file_name, paramInfo)
+ line = fp.readline()
+ except:
+ print("Error, invalid parameter file ", file_name)
+ pass
+
+ def dump_parameter(self):
+ for param in self._parameters.values():
+ print(str(param))
+
+ def _check_file(self, file):
+ valid_file_ext = [".para", ".para.dac"]
+ if not file.is_file():
+ return False
+ for ext in valid_file_ext:
+ if file.name.endswith(ext):
+ return True
+ return False
+
+ def _scan_parameter_file(self, dir):
+ if not os.path.exists(dir):
+ return
+ with os.scandir(dir) as files:
+ for file in files:
+ if self._check_file(file):
+ self.load_parameter_file(file.path)
+
+ def scan_parameter_file(self, dir):
+ parameter_paths = [
+ "/system/etc/param/ohos_const",
+ "/vendor/etc/param",
+ "/chip_prod/etc/param",
+ "/sys_prod/etc/param",
+ "/system/etc/param",
+ ]
+ for path in parameter_paths:
+ self._scan_parameter_file(dir + "/packages/phone" + path)
+
+def __create_arg_parser():
+ import argparse
+ parser = argparse.ArgumentParser(description='Collect parameter information from xxxx/etc/param dir.')
+ parser.add_argument('-i', '--input',
+ help='input parameter files base directory example "out/rk3568/packages/phone/" ', required=True)
+ return parser
+
+def parameters_collect(base_path):
+ parser = ParameterFileParser()
+ parser.scan_parameter_file(base_path)
+ parser.load_parameter_file(base_path + "/packages/phone/system/etc/selinux/targeted/contexts/parameter_contexts", " ")
+ # parser.dumpParameter()
+ return parser
+
+if __name__ == '__main__':
+ args_parser = __create_arg_parser()
+ options = args_parser.parse_args()
+ parameters_collect(options.input)
diff --git a/tools/startup_guard/rules/NO-Config-Cmds-In-Init/README.md b/tools/startup_guard/rules/NO-Config-Cmds-In-Init/README.md
new file mode 100755
index 0000000000000000000000000000000000000000..e58c53810fa0b1d19cf4b4c3beb9ad71e9a2a7ee
--- /dev/null
+++ b/tools/startup_guard/rules/NO-Config-Cmds-In-Init/README.md
@@ -0,0 +1,27 @@
+# 耗时命令白名单规则说明
+
+## 1. 耗时命令说明
+ 命令执行超过200ms的命令行。
+
+## 2. 规则解释
+
+ 1. **耗时命令约束**:**[白名单](whitelist.json)** 约束*.cfg文件中的耗时命令。
+ 2. **condition服务约束**:白名单中约束service启动方式是:"start-mode" : "condition" 且"ondemand" : false , 且服务通过start命令启动。
+ 3. **boot服务约束**:白名单约束service启动方式是:"start-mode" : "boot"。
+ 4. **selinux约束**:selinux未打开, 或服务的"secon"没有配置。
+
+编译时会提示如下类型的告警:
+
+ ```
+ [NOT ALLOWED]: 'mount_fstab' is invalid, in /system/etc/init.cfg
+ [NOT ALLOWED]: 'load_access_token_id' is invalid, in /system/etc/init/access_token.cfg
+ [NOT ALLOWED]: 'init_global_key' is invalid, in /system/etc/init.cfg
+ [NOT ALLOWED]: 'storage_daemon' cannot be started in boot mode
+ [NOT ALLOWED]: 'hilogd' cannot be started in conditional mode
+```
+
+## 3. 违规场景及处理方案建议
+
+ 1. 检查违规项是否是耗时命令,其次该命令存在文件路径是否包含白名单中, 如果不在,根据要求添加命令到白名单
+
+ 2. 检查服务启动类型, 根据 **[规则解释](README.md#2-规则解释)** 排查修改
diff --git a/tools/startup_guard/rules/NO-Config-Cmds-In-Init/whitelist.json b/tools/startup_guard/rules/NO-Config-Cmds-In-Init/whitelist.json
new file mode 100755
index 0000000000000000000000000000000000000000..80974265d644019de41ae09b3da7b4686fbd8825
--- /dev/null
+++ b/tools/startup_guard/rules/NO-Config-Cmds-In-Init/whitelist.json
@@ -0,0 +1,54 @@
+[
+ {
+ "cmds": [
+ {
+ "cmd":"mount_fstab",
+ "location":[
+ "/system/etc/init.cfg"
+ ]
+ }, {
+ "cmd":"load_access_token_id",
+ "location":[
+ "/system/etc/init/access_token.cfg"
+ ]
+ }, {
+ "cmd":"init_global_key",
+ "location":[
+ "/system/etc/init.cfg"
+ ]
+ }],
+ "start-modes": [
+ {
+ "start-mode":"condition",
+ "service":[
+ "hilogd",
+ "wifi_hal_service",
+ "hdcd",
+ "hiprofilerd",
+ "pulseaudio",
+ "huks_service",
+ "hiprofiler_plugins",
+ "watchdog_service",
+ "pinauth",
+ "hiprofiler_daemon",
+ "multimodalinput",
+ "udevd_service",
+ "mmi_uinput_service"
+ ]
+ }, {
+ "start-mode":"boot",
+ "service":[
+ "hiview",
+ "storage_daemon",
+ "samgr",
+ "thermal_protector",
+ "appspawn",
+ "param_watcher",
+ "device_manager",
+ "storage_manager",
+ "hdf_devmgr"
+ ]
+ }
+ ]
+ }
+]
diff --git a/tools/startup_guard/rules/NO-Config-SystemParameter-In-INIT/README.md b/tools/startup_guard/rules/NO-Config-SystemParameter-In-INIT/README.md
new file mode 100755
index 0000000000000000000000000000000000000000..20fdfbadc848de555b65ac21fc6d3ef259d2048f
--- /dev/null
+++ b/tools/startup_guard/rules/NO-Config-SystemParameter-In-INIT/README.md
@@ -0,0 +1,17 @@
+# 系统参数白名单规则说明
+
+## 1. 规则解释
+ 1. **[白名单](whitelist.json)** 约束系统参数配置文件(\*.para", \*.para.dac)中的名称。
+ 2. **[白名单](whitelist.json)** 约束系统参数命名合法性。系统参数命名由:字母、数字、下划线、'.'、 '-'、 '@'、 ':' 、 '_'。 例外:不允许出现".."
+ 3. 系统参数名未添加在 **[白名单](whitelist.json)**。
+
+编译时会提示如下类型的告警:
+
+ ```
+ [NOT ALLOWED]: Invalid param: distributedsched.continuationmanager..
+ [NOT ALLOWED]: persist.resourceschedule.memmgr.eswap.swapOutKBFromBirth is not found in the whitelist
+ ```
+
+## 2. 违规场景及处理方案建议
+
+ 1. 检查白名单和系统参数命名, 根据 **[规则解释](README.md#2-规则解释)** 排查修改
diff --git a/tools/startup_guard/rules/NO-Config-SystemParameter-In-INIT/whitelist.json b/tools/startup_guard/rules/NO-Config-SystemParameter-In-INIT/whitelist.json
new file mode 100755
index 0000000000000000000000000000000000000000..8733ef9be81dbecbd0daf23c01f1ffdcac6362b9
--- /dev/null
+++ b/tools/startup_guard/rules/NO-Config-SystemParameter-In-INIT/whitelist.json
@@ -0,0 +1,375 @@
+[
+ "const.ohos.version.security_patch",
+ "const.ohos.releasetype",
+ "const.ohos.apiversion",
+ "const.ohos.fullname",
+ "persist.thermal.log.enable",
+ "persist.thermal.log.interval",
+ "persist.thermal.log.width",
+ "persist.thermal.log.",
+ "sys.usb.config",
+ "const.product.hardwareversion",
+ "const.product.brand",
+ "const.build.product",
+ "accesstoken.permission.change",
+ "persist.resourceschedule.memmgr.eswap.permanently.closed",
+ "persist.resourceschedule.memmgr.eswap.minsToday",
+ "persist.resourceschedule.memmgr.eswap.swapOutKBToday",
+ "persist.resourceschedule.memmgr.eswap.minsFromBirth",
+ "persist.resourceschedule.memmgr.eswap.swapOutKBFromBirth",
+ "const.cust.",
+ "persist.darkmode",
+ "sys.usb.ffs.ready",
+ "persist.hdc.root",
+ "persist.hdc.mode",
+ "persist.hdc.port",
+ "persist.hdc.uv.threads",
+ "persist.hdc.control",
+ "persist.hdc.control.shell",
+ "persist.hdc.control.file",
+ "persist.hdc.control.fport",
+ "accessibility.config.ready",
+ "bootevent.appfwk.ready",
+ "component.startup.newRules",
+ "component.startup.newRules.except.LauncherSystemUI",
+ "component.startup.backgroundJudge.flag",
+ "component.startup.whitelist.associatedWakeUp",
+ "netmanager_base.",
+ "persist.netmanager_base.",
+ "const.distributed_file_property.enabled",
+ "const.distributed_file_only_for_same_account_test",
+ "const.telephony.slotCount",
+ "telephony.sim.opkey0",
+ "telephony.sim.opkey1",
+ "persist.sys.default_ime",
+ "ohos.servicectrl.",
+ "ohos.servicectrl.reboot.",
+ "ohos.boot.",
+ "bootevent.",
+ "startup.service.ctl.",
+ "startup.device.",
+ "const.debuggable",
+ "const.build.",
+ "const.SystemCapability.",
+ "const.product.",
+ "persist.init.",
+ "startup.appspawn.",
+ "startup.uevent.",
+ "persist.init.debug.",
+ "persist.init.bootevent.enable",
+ "persist.appspawn.",
+ "persist.xts.devattest.",
+ "ohos.boot.sn",
+ "const.product.udid",
+ "const.product.devUdid",
+ "const.actionable_compatible_property.enabled",
+ "const.postinstall.fstab.prefix",
+ "const.secure",
+ "security.perf_harden",
+ "const.allow.mock.location",
+ "persist.sys.usb.config",
+ "persist.window.boot.",
+ "debug.bytrace.",
+ "persist.distributed_hardware.device_manager.",
+ "persist.sys.hiview.",
+ "vendor.hifi.watchdog.come",
+ "bootevent.wms.fullscreen.ready",
+ "persist.pasteboard.",
+ "const.theme.screenlockWhiteApp",
+ "const.theme.screenlockApp",
+ "persist.global.language",
+ "persist.global.locale",
+ "persist.global.is24Hour",
+ "persist.sys.preferredLanguages",
+ "const.global.locale",
+ "const.global.language",
+ "const.global.region",
+ "bootevent.useriam.fwkready",
+ "hiviewdfx.hiperf.perf_event_max_sample_rate",
+ "hiviewdfx.hiperf.perf_cpu_time_max_percent",
+ "hiviewdfx.hiperf.perf_event_mlock_kb",
+ "persist.filemanagement.usb.readonly",
+ "debug.hitrace.tags.enableflags",
+ "hilog.",
+ "persist.sys.hilog.",
+ "bootevent.samgr.ready",
+ "persist.samgr.perf.ondemand",
+ "persist.sys.graphic.animationscale",
+ "debug.graphic.",
+ "musl.log.enable",
+ "musl.log.ld.all",
+ "const.display.brightness.",
+ "persist.sys.arkui.animationscale",
+ "const.build.characteristics",
+ "const.product.model",
+ "const.product.name",
+ "const.sandbox",
+ "const.product.devicetype",
+ "const.software.model",
+ "const.product.manufacturer",
+ "const.product.bootloader.version",
+ "const.product.cpu.abilist",
+ "const.product.software.version",
+ "const.product.incremental.version",
+ "const.product.firstapiversion",
+ "const.product.build.type",
+ "const.product.build.user",
+ "const.product.build.host",
+ "const.product.build.date",
+ "const.product.hardwareprofile",
+ "const.ohos.buildroothash",
+ "backup.debug.overrideExtensionConfig",
+ "persist.netmanager_base.http_proxy.host",
+ "persist.netmanager_base.http_proxy.port",
+ "persist.netmanager_base.http_proxy.exclusion_list",
+ "persist.distributed_hardware.device_manager.discover_status",
+ "input.pointer.device",
+ "hiviewdfx.hiprofiler.profilerd.start",
+ "hiviewdfx.hiprofiler.plugins.start",
+ "hiviewdfx.hiprofiler.native_memoryd.start",
+ "libc.hook_mode",
+ "persist.multimedia.audio.mediavolume",
+ "const.SystemCapability.ArkUI.UiAppearance",
+ "const.SystemCapability.ArkUI.ArkUI.Full",
+ "const.SystemCapability.ArkUI.ArkUI.Napi",
+ "const.SystemCapability.ArkUI.ArkUI.Libuv",
+ "const.SystemCapability.Account.AppAccount",
+ "const.SystemCapability.Account.OsAccount",
+ "const.SystemCapability.DistributedDataManager.KVStore.Core",
+ "const.SystemCapability.DistributedDataManager.KVStore.Lite",
+ "const.SystemCapability.DistributedDataManager.KVStore.DistributedKVStore",
+ "const.SystemCapability.DistributedDataManager.Preferences.Core",
+ "const.SystemCapability.DistributedDataManager.DataObject.DistributedObject",
+ "const.SystemCapability.DistributedDataManager.RelationalStore.Core",
+ "const.SystemCapability.DistributedDataManager.DataShare.Core",
+ "const.SystemCapability.DistributedDataManager.DataShare.Consumer",
+ "const.SystemCapability.DistributedDataManager.DataShare.Provider",
+ "const.SystemCapability.MiscServices.Pasteboard",
+ "const.SystemCapability.Security.AccessToken",
+ "const.SystemCapability.Security.DeviceSecurityLevel",
+ "const.SystemCapability.Security.DataTransitManager",
+ "const.SystemCapability.Security.DeviceAuth",
+ "const.SystemCapability.Security.AppVerify",
+ "const.SystemCapability.Security.CertificateManager",
+ "const.SystemCapability.Security.Huks",
+ "const.SystemCapability.Security.Cipher",
+ "const.SystemCapability.Security.CryptoFramework",
+ "const.SystemCapability.Security.Cert",
+ "const.SystemCapability.UserIAM.UserAuth.FaceAuth",
+ "const.SystemCapability.UserIAM.UserAuth.PinAuth",
+ "const.SystemCapability.UserIAM.UserAuth.Core",
+ "const.SystemCapability.UserIAM.UserAuth.FingerprintAuth",
+ "const.SystemCapability.Startup.SystemInfo",
+ "const.SystemCapability.HiviewDFX.HiLog",
+ "const.SystemCapability.HiviewDFX.HiTrace",
+ "const.SystemCapability.HiviewDFX.HiSysEvent",
+ "const.SystemCapability.HiviewDFX.HiAppEvent",
+ "const.SystemCapability.HiviewDFX.Hiview",
+ "const.SystemCapability.HiviewDFX.Hiview.FaultLogger",
+ "const.SystemCapability.HiviewDFX.HiChecker",
+ "const.SystemCapability.HiviewDFX.HiDumper",
+ "const.SystemCapability.Utils.Lang",
+ "const.SystemCapability.BundleManager.BundleTool",
+ "const.SystemCapability.BundleManager.DistributedBundleFramework",
+ "const.SystemCapability.BundleManager.BundleFramework",
+ "const.SystemCapability.BundleManager.Zlib",
+ "const.SystemCapability.BundleManager.BundleFramework.AppControl",
+ "const.SystemCapability.BundleManager.BundleFramework.Core",
+ "const.SystemCapability.BundleManager.BundleFramework.FreeInstall",
+ "const.SystemCapability.BundleManager.BundleFramework.Launcher",
+ "const.SystemCapability.BundleManager.BundleFramework.DefaultApp",
+ "const.SystemCapability.BundleManager.BundleFramework.Resource",
+ "const.SystemCapability.Ability.AbilityBase",
+ "const.SystemCapability.Ability.DistributedAbilityManager",
+ "const.SystemCapability.Ability.AbilityRuntime.Core",
+ "const.SystemCapability.Ability.AbilityRuntime.FAModel",
+ "const.SystemCapability.Ability.AbilityRuntime.AbilityCore",
+ "const.SystemCapability.Ability.AbilityRuntime.Mission",
+ "const.SystemCapability.Ability.AbilityRuntime.QuickFix",
+ "const.SystemCapability.Ability.AbilityTools.AbilityAssistant",
+ "const.SystemCapability.Ability.Form",
+ "const.SystemCapability.Notification.Emitter",
+ "const.SystemCapability.Notification.Notification",
+ "const.SystemCapability.Notification.ReminderAgent",
+ "const.SystemCapability.Notification.CommonEvent",
+ "const.SystemCapability.Communication.SoftBus.Core",
+ "const.SystemCapability.Communication.NetManager.Core",
+ "const.SystemCapability.Communication.Bluetooth.Core",
+ "const.SystemCapability.Communication.Bluetooth.Lite",
+ "const.SystemCapability.Communication.NetStack",
+ "const.SystemCapability.Communication.WiFi.STA",
+ "const.SystemCapability.Communication.WiFi.AP.Core",
+ "const.SystemCapability.Communication.WiFi.P2P",
+ "const.SystemCapability.Communication.WiFi.Core",
+ "const.SystemCapability.Communication.IPC.Core",
+ "const.SystemCapability.Communication.NetManager.Ethernet",
+ "const.SystemCapability.Communication.NetManager.NetSharing",
+ "const.SystemCapability.Communication.NetManager.MDNS",
+ "const.SystemCapability.Communication.NetManager.Vpn",
+ "const.SystemCapability.Location.Location.Core",
+ "const.SystemCapability.Location.Location.Gnss",
+ "const.SystemCapability.Location.Location.Geofence",
+ "const.SystemCapability.Location.Location.Geocoder",
+ "const.SystemCapability.Location.Location.Lite",
+ "const.SystemCapability.Update.UpdateService",
+ "const.SystemCapability.HiviewDFX.HiProfiler.HiDebug",
+ "const.SystemCapability.Developtools.Syscap",
+ "const.SystemCapability.Sensors.Sensor",
+ "const.SystemCapability.Sensors.MiscDevice",
+ "const.SystemCapability.Graphic.Graphic2D.ColorManager.Core",
+ "const.SystemCapability.Graphic.Graphic2D.EGL",
+ "const.SystemCapability.Graphic.Graphic2D.GLES3",
+ "const.SystemCapability.Graphic.Graphic2D.NativeWindow",
+ "const.SystemCapability.Graphic.Graphic2D.NativeDrawing",
+ "const.SystemCapability.Graphic.Graphic2D.WebGL",
+ "const.SystemCapability.Graphic.Graphic2D.WebGL2",
+ "const.SystemCapability.WindowManager.WindowManager.Core",
+ "const.SystemCapability.MiscServices.Time",
+ "const.SystemCapability.MiscServices.InputMethodFramework",
+ "const.SystemCapability.MiscServices.Download",
+ "const.SystemCapability.MiscServices.Upload",
+ "const.SystemCapability.Print.PrintFramework",
+ "const.SystemCapability.MiscServices.ScreenLock",
+ "const.SystemCapability.MiscServices.Wallpaper",
+ "const.SystemCapability.Multimedia.Audio.Core",
+ "const.SystemCapability.Multimedia.Audio.Renderer",
+ "const.SystemCapability.Multimedia.Audio.Capturer",
+ "const.SystemCapability.Multimedia.Audio.Device",
+ "const.SystemCapability.Multimedia.Audio.Volume",
+ "const.SystemCapability.Multimedia.Audio.Communication",
+ "const.SystemCapability.Multimedia.Audio.Tone",
+ "const.SystemCapability.Multimedia.Audio.Interrupt",
+ "const.SystemCapability.Multimedia.Image.Core",
+ "const.SystemCapability.Multimedia.Image.ImageSource",
+ "const.SystemCapability.Multimedia.Image.ImagePacker",
+ "const.SystemCapability.Multimedia.Image.ImageReceiver",
+ "const.SystemCapability.Multimedia.Image.ImageCreator",
+ "const.SystemCapability.Multimedia.Camera.Core",
+ "const.SystemCapability.Multimedia.MediaLibrary.Core",
+ "const.SystemCapability.Multimedia.MediaLibrary.DistributedCore",
+ "const.SystemCapability.FileManagement.UserFileManager.Core",
+ "const.SystemCapability.FileManagement.UserFileManager.DistributedCore",
+ "const.SystemCapability.Multimedia.Media.Core",
+ "const.SystemCapability.Multimedia.Media.AudioPlayer",
+ "const.SystemCapability.Multimedia.Media.VideoPlayer",
+ "const.SystemCapability.Multimedia.Media.AudioRecorder",
+ "const.SystemCapability.Multimedia.Media.VideoRecorder",
+ "const.SystemCapability.Multimedia.Media.AudioDecoder",
+ "const.SystemCapability.Multimedia.Media.AudioEncoder",
+ "const.SystemCapability.Multimedia.Media.VideoDecoder",
+ "const.SystemCapability.Multimedia.Media.VideoEncoder",
+ "const.SystemCapability.Multimedia.Media.CodecBase",
+ "const.SystemCapability.Multimedia.Media.AVPlayer",
+ "const.SystemCapability.Multimedia.Media.AVRecorder",
+ "const.SystemCapability.Multimedia.SystemSound.Core",
+ "const.SystemCapability.Multimedia.AVSession",
+ "const.SystemCapability.Multimedia.AVSession.Core",
+ "const.SystemCapability.Multimedia.AVSession.Manager",
+ "const.SystemCapability.MultimodalInput.Input.InputConsumer",
+ "const.SystemCapability.MultimodalInput.Input.InputDevice",
+ "const.SystemCapability.MultimodalInput.Input.Core",
+ "const.SystemCapability.MultimodalInput.Input.InputSimulator",
+ "const.SystemCapability.MultimodalInput.Input.InputMonitor",
+ "const.SystemCapability.MultimodalInput.Input.Pointer",
+ "const.SystemCapability.MultimodalInput.Input.ShortKey",
+ "const.SystemCapability.Telephony.DataStorage",
+ "const.SystemCapability.Telephony.CellularCall",
+ "const.SystemCapability.Telephony.CellularData",
+ "const.SystemCapability.Telephony.SmsMms",
+ "const.SystemCapability.Telephony.StateRegistry",
+ "const.SystemCapability.Telephony.CallManager",
+ "const.SystemCapability.Telephony.CoreService",
+ "const.SystemCapability.Global.I18n",
+ "const.SystemCapability.Global.ResourceManager",
+ "const.SystemCapability.PowerManager.BatteryStatistics",
+ "const.SystemCapability.PowerManager.ThermalManager",
+ "const.SystemCapability.PowerManager.PowerManager.Core",
+ "const.SystemCapability.PowerManager.PowerManager.Extension",
+ "const.SystemCapability.PowerManager.DisplayPowerManager",
+ "const.SystemCapability.PowerManager.BatteryManager.Core",
+ "const.SystemCapability.PowerManager.BatteryManager.Extension",
+ "const.SystemCapability.USB.USBManager",
+ "const.SystemCapability.Applications.settings.Core",
+ "const.SystemCapability.Applications.ContactsData",
+ "const.SystemCapability.XTS.DeviceAttest",
+ "const.SystemCapability.Test.WuKong",
+ "const.SystemCapability.Test.UiTest",
+ "const.SystemCapability.DistributedHardware.DistributedAudio",
+ "const.SystemCapability.DistributedHardware.DistributedCamera",
+ "const.SystemCapability.DistributedHardware.DistributedScreen",
+ "const.SystemCapability.DistributedHardware.DistributedInput",
+ "const.SystemCapability.DistributedHardware.DistributedHardwareFWK",
+ "const.SystemCapability.DistributedHardware.DeviceManager",
+ "const.SystemCapability.Msdp.DeviceStatus.Stationary",
+ "const.SystemCapability.FileManagement.File.FileIO",
+ "const.SystemCapability.FileManagement.File.Environment",
+ "const.SystemCapability.FileManagement.File.DistributedFile",
+ "const.SystemCapability.FileManagement.DistributedFileService.CloudSyncManager",
+ "const.SystemCapability.FileManagement.UserFileService",
+ "const.SystemCapability.FileManagement.AppFileService",
+ "const.SystemCapability.FileManagement.StorageService.Backup",
+ "const.SystemCapability.FileManagement.StorageService.SpatialStatistics",
+ "const.SystemCapability.FileManagement.StorageService.Volume",
+ "const.SystemCapability.FileManagement.StorageService.Encryption",
+ "const.SystemCapability.ResourceSchedule.WorkScheduler",
+ "const.SystemCapability.ResourceSchedule.BackgroundTaskManager.ContinuousTask",
+ "const.SystemCapability.ResourceSchedule.BackgroundTaskManager.TransientTask",
+ "const.SystemCapability.ResourceSchedule.BackgroundTaskManager.EfficiencyResourcesApply",
+ "const.SystemCapability.ResourceSchedule.UsageStatistics.AppGroup",
+ "const.SystemCapability.ResourceSchedule.UsageStatistics.App",
+ "const.SystemCapability.BarrierFree.Accessibility.Core",
+ "const.SystemCapability.BarrierFree.Accessibility.Hearing",
+ "const.SystemCapability.BarrierFree.Accessibility.Vision",
+ "const.SystemCapability.Customization.ConfigPolicy",
+ "const.SystemCapability.Customization.EnterpriseDeviceManager",
+ "const.SystemCapability.Web.Webview.Core",
+ "const.SystemCapability.Ai.MindSpore",
+ "persist.time.timezone",
+ "hiviewdfx.hiprofiler.",
+ "libc.hook_mode.",
+ "hilog.private.on",
+ "hilog.debug.on",
+ "persist.sys.hilog.kmsg.on",
+ "persist.sys.hilog.debug.on",
+ "hilog.flowctrl.proc.on",
+ "hilog.flowctrl.domain.on",
+ "hilog.loggable.global",
+ "hilog.buffersize.global",
+ "persist.time.",
+ "const.ark.minVersion",
+ "const.ark.version",
+ "const.display.brightness.min",
+ "const.display.brightness.default",
+ "const.display.brightness.max",
+ "persist.telephony.",
+ "telephony.",
+ "sys.",
+ "sys.usb",
+ "net.",
+ "net.tcp.",
+ "const.postinstall.",
+ "const.postinstall.fstab.",
+ "const.allow.",
+ "const.allow.mock.",
+ "security.",
+ "persist.",
+ "persist.sys.",
+ "debug.",
+ "musl.",
+ "bootevent.wms.",
+ "ffrt.",
+ "hiviewdfx.hiperf.",
+ "persist.multimedia.audio.",
+ "persist.ark.",
+ "persist.ace.",
+ "accesstoken.permission.",
+ "persist.bms.",
+ "distributedsched.continuationmanager.",
+ "updater.hdc.configfs",
+ "updater.flashd.configfs",
+ "updater.data.configs",
+ "persist.xts.devattest.authresult",
+ "llvm.debug.service.",
+ "persist.edm.edm_enable",
+ "persist.edm."
+]
diff --git a/tools/startup_guard/startup_checker/__init__.py b/tools/startup_guard/startup_checker/__init__.py
new file mode 100755
index 0000000000000000000000000000000000000000..73a52affd3e6a31256bd957f449bb2a589a46a79
--- /dev/null
+++ b/tools/startup_guard/startup_checker/__init__.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from .cmds_rule import cmdRule
+from .system_parameter_rules import SystemParameterRule
+
+def check_all_rules(mgr, args):
+ rules = [
+ cmdRule,
+ SystemParameterRule,
+ ]
+
+ passed = True
+ for rule in rules:
+ r = rule(mgr, args)
+ r.log("Do %s rule checking now:" % rule.RULE_NAME)
+ if not r.__check__():
+ passed = False
+ else:
+ passed = True
+
+ if not passed:
+ r.log(" Please refer to: \033[91m%s\x1b[0m" % r.get_help_url())
+ pass
+
+ if args and args.no_fail:
+ return True
+
+ return passed
diff --git a/tools/startup_guard/startup_checker/base_rule.py b/tools/startup_guard/startup_checker/base_rule.py
new file mode 100755
index 0000000000000000000000000000000000000000..082ca1286a9f15694b71c99ed5583d89c117f546
--- /dev/null
+++ b/tools/startup_guard/startup_checker/base_rule.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import json
+
+class BaseRule(object):
+ RULE_NAME = ""
+
+ def __init__(self, mgr, args):
+ self._args = args
+ self._mgr = mgr
+ self._white_lists = self.__load_files__("whitelist.json")
+
+ def __load_files__(self, name):
+ rules_dir = []
+ rules_dir.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../rules"))
+ if self._args and self._args.rules:
+ rules_dir = rules_dir + self._args.rules
+
+ res = []
+ for d in rules_dir:
+ rules_file = os.path.join(d, self.__class__.RULE_NAME, name)
+ try:
+ with open(rules_file, "r") as f:
+ jsonstr = "".join([ line.strip() for line in f if not line.strip().startswith("//") ])
+ res = res + json.loads(jsonstr)
+ except:
+ pass
+
+ return res
+
+ def get_mgr(self):
+ return self._mgr
+
+ def get_white_lists(self):
+ return self._white_lists
+
+ def log(self, info):
+ print(info)
+
+ def warn(self, info):
+ print("\033[35m[WARNING]\x1b[0m: %s" % info)
+
+ def error(self, info):
+ print("\033[91m[NOT ALLOWED]\x1b[0m: %s" % info)
+
+ def get_help_url(self):
+ return "https://gitee.com/openharmony/developtools_integration_verification/tree/master/tools/startup_guard/rules/%s/README.md" % self.__class__.RULE_NAME
+
+ # To be override
+ def __check__(self):
+ # Default pass
+ return True
diff --git a/tools/startup_guard/startup_checker/cmds_rule.py b/tools/startup_guard/startup_checker/cmds_rule.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0c28b76e114acb6984420fc8904d78a5a8eca9c
--- /dev/null
+++ b/tools/startup_guard/startup_checker/cmds_rule.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import json
+
+from .base_rule import BaseRule
+
+class cmdRule(BaseRule):
+ RULE_NAME = "NO-Config-Cmds-In-Init"
+
+ def __init__(self, mgr, args):
+ super().__init__(mgr, args)
+ self._cmds = {}
+ self._start_modes = {}
+ self._boot_list = {}
+ self._condition_list = {}
+
+ def _get_json_service(self):
+ for i in range(len(self._start_modes)):
+ if self._start_modes[i]["start-mode"] == "boot":
+ self._boot_list = self._start_modes[i]["service"]
+ elif self._start_modes[i]["start-mode"] == "condition":
+ self._condition_list = self._start_modes[i]["service"]
+ pass
+
+ def _get_start_cmds(self, parser):
+ list = []
+ for cmd in parser._cmds:
+ if cmd["name"] == "start":
+ list.append(cmd["content"])
+ pass
+ return list
+
+ def _parse_while_list(self):
+ white_lists =self.get_white_lists()[0]
+ for key, item in white_lists.items():
+ if key == "cmds":
+ self._cmds = item
+ if key == "start-modes":
+ self._start_modes = item
+
+ def _check_condition_start_mode(self, cmd_list, service_name, passed):
+ # print(cmd_list)
+ if service_name in self._condition_list and service_name in cmd_list:
+ pass
+ else:
+ self.error("\'%s\' cannot be started in conditional mode" % service_name)
+ passed = False
+ return passed
+
+
+ def _check_service(self, parser):
+ boot_passed = True
+ condition_passed = True
+ start_cmd_list = self._get_start_cmds(parser)
+ for key, item in parser._services.items():
+ if item.get("start_mode") == "boot":
+ if key not in self._boot_list:
+ self.error("\'%s\' cannot be started in boot mode" % key)
+ boot_passed = False
+ elif item.get("on_demand") is not True and item.get("start_mode") == "condition":
+ condition_passed = self._check_condition_start_mode(start_cmd_list, key, condition_passed)
+ return boot_passed and condition_passed
+
+ def _check_file_id_in_cmds(self, cmdlist, cmdline):
+ file_id_list = set()
+ # print(cmdlist)
+ for i in range(len(cmdlist)):
+ if cmdline == cmdlist[i]["name"]:
+ file_id_list.add(cmdlist[i]["fileId"])
+ pass
+ return file_id_list
+
+ def _check_cmdline_in_parser(self, parser):
+ passed = True
+ cmdline = []
+ file_id_list = set()
+ parser_cmds = parser._cmds
+
+ for cmd in self._cmds:
+ cmdline = cmd["cmd"]
+ file_id_list = self._check_file_id_in_cmds(parser_cmds, cmdline)
+ file_lists = cmd["location"]
+ for key, item in parser._files.items():
+ if item["fileId"] in file_id_list and key not in file_lists:
+ output = "\'" + cmd["cmd"] + "\' is invalid, in "+ key
+ self.error("%s" % str(output))
+ passed = False
+ file_id_list.clear()
+ return passed
+
+ def _check_selinux(self, parser):
+ if parser._selinux != 'enforcing':
+ self.warn("selinux status is %s" %parser._selinux)
+ return False
+
+ passed = True
+ for key, item in parser._services.items():
+ if item.get("secon") is None:
+ output_str = "%s \'secon\' is empty" % key
+ self.warn("%s" % str(output_str))
+ passed = False
+ return passed
+
+ def check_config_cmd(self):
+ self._parse_while_list()
+ cfg_parser = self.get_mgr().get_parser_by_name('cmd_whitelist')
+ self._get_json_service()
+ self._get_start_cmds(cfg_parser)
+
+ secon_passed = self._check_selinux(cfg_parser)
+ cmd_passed = self._check_cmdline_in_parser(cfg_parser)
+ start_mode_passed = self._check_service(cfg_parser)
+ return secon_passed and cmd_passed and start_mode_passed
+
+ def __check__(self):
+ return self.check_config_cmd()
diff --git a/tools/startup_guard/startup_checker/system_parameter_rules.py b/tools/startup_guard/startup_checker/system_parameter_rules.py
new file mode 100644
index 0000000000000000000000000000000000000000..b91d118c34bf111489f6192e81d37b17d019e3b2
--- /dev/null
+++ b/tools/startup_guard/startup_checker/system_parameter_rules.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from .base_rule import BaseRule
+
+class SystemParameterRule(BaseRule):
+ RULE_NAME = "NO-Config-SystemParameter-In-INIT"
+
+ def _check_param_name(self, param_name, empty_flag):
+ # len: (0, 96]
+ # Only allow alphanumeric, plus '.', '-', '@', ':', or '_'/
+ # Don't allow ".." to appear in a param name
+ if len(param_name) > 96 or len(param_name) < 1 or param_name[0] == '.' or '..' in param_name:
+ return False
+
+ if empty_flag is False:
+ if param_name[-1] == '.':
+ return False
+
+ if param_name == "#":
+ return True
+
+ for char_value in param_name:
+ if char_value in '._-@:':
+ continue
+
+ if char_value.isalnum():
+ continue
+ return False
+ return True
+
+ def _check_Param_in_init(self):
+ passed = True
+ value_empty_flag = True
+ white_list =self.get_white_lists()
+ parser = self.get_mgr().get_parser_by_name('system_parameter_whitelist')
+ for key, item in parser._parameters.items():
+ if str(item)[-1] == "=":
+ value_empty_flag = True
+ else:
+ value_empty_flag = False
+
+ if not self._check_param_name(key, value_empty_flag):
+ self.error("Invalid param: %s" % key)
+ continue
+ if key in white_list:
+ continue
+ self.error("%s is not found in the whitelist" % key)
+ passed = False
+ return passed
+
+ def __check__(self):
+ return self._check_Param_in_init()
diff --git a/tools/startup_guard/startup_guard.py b/tools/startup_guard/startup_guard.py
new file mode 100755
index 0000000000000000000000000000000000000000..875763d6851d64c48cff2228243ba13e9391ca1e
--- /dev/null
+++ b/tools/startup_guard/startup_guard.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+#
+# Copyright (c) 2023 Huawei Device Co., Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from config_parser_mgr import ConfigParserMgr
+
+def __create_arg_parser():
+ import argparse
+ parser = argparse.ArgumentParser(description='Check startup architecture information from compiled output files.')
+ parser.add_argument('-i', '--input',
+ help='input config files base directory example "out/rk3568" ', required=True)
+ parser.add_argument('-r', '--rules', action='append',
+ help='rules directory', required=False)
+ parser.add_argument('-n', '--no_fail',
+ help='force to pass all rules', required=False)
+ return parser
+
+def startup_guard(out_path, args=None):
+ mgr = ConfigParserMgr()
+ mgr.load_all_parser(out_path)
+
+ from startup_checker import check_all_rules
+ passed = check_all_rules(mgr, args)
+ passed = True
+ if passed:
+ print("All rules passed")
+ return
+
+ raise Exception("ERROR: config_guard failed.")
+
+if __name__ == '__main__':
+ parser = __create_arg_parser()
+ args = parser.parse_args()
+ startup_guard(args.input, args)