1#!/usr/bin/env python3 2# coding=utf-8 3 4# 5# Copyright (c) 2020-2023 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import os 20import shutil 21import subprocess 22import json 23import sys 24import time 25import xml.etree.ElementTree as ET 26from public_method import get_server_dict, get_config_ip, get_sn_list 27import stat 28 29FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL 30MODES = stat.S_IWUSR | stat.S_IRUSR 31 32 33def _init_sys_config(): 34 sys.localcoverage_path = os.path.join(current_path, "..") 35 sys.path.insert(0, sys.localcoverage_path) 36 37 38def modify_init_file(developer_path, hdc_str): 39 """ 40 /etc/init.cfg文件添加cmds 41 """ 42 recv_path = os.path.join(developer_path, "local_coverage/resident_service/resources") 43 print("%s file recv /etc/init.cfg %s" % (hdc_str, recv_path)) 44 coverage_command("%s file recv /etc/init.cfg %s" % (hdc_str, recv_path)) 45 recv_restores_path = os.path.join(recv_path, "restores_environment") 46 if not os.path.exists(recv_restores_path): 47 os.mkdir(recv_restores_path) 48 recv_restores_name = os.path.join(recv_restores_path, "init.cfg") 49 if not os.path.exists(recv_restores_name): 50 coverage_command("%s file recv /etc/init.cfg %s" % (hdc_str, recv_restores_path)) 51 else: 52 print("INFO: file exit", recv_restores_name) 53 54 cfg_file_path = os.path.join(recv_path, "init.cfg") 55 if os.path.exists(cfg_file_path): 56 with open(cfg_file_path, "r") as fp: 57 json_data = json.load(fp) 58 59 for jobs_list in json_data["jobs"]: 60 if jobs_list["name"] == "init": 61 if jobs_list["cmds"][-1] != "export GCOV_FETCH_METHOD FM_SIGNA": 62 jobs_list["cmds"].append("mkdir /data/gcov 0777 system system") 63 jobs_list["cmds"].append("export GCOV_PREFIX /data/gcov") 64 jobs_list["cmds"].append("export GCOV_FETCH_METHOD FM_SIGNA") 65 else: 66 return 67 json_str = json.dumps(json_data, indent=2) 68 if os.path.exists(cfg_file_path): 69 os.remove(cfg_file_path) 70 with os.fdopen(os.open(cfg_file_path, FLAGS, MODES), 'w') as json_file: 71 json_file.write(json_str) 72 else: 73 print("init.cfg file not exists") 74 return 75 print("%s shell mount -o rw,remount / > /dev/null 2>&1" % hdc_str) 76 coverage_command("%s shell mount -o rw,remount / > /dev/null 2>&1" % hdc_str) 77 print("%s target mount" % hdc_str) 78 coverage_command("%s target mount" % hdc_str) 79 print("%s file send %s %s" % (hdc_str, cfg_file_path, "/etc/")) 80 coverage_command("%s file send %s %s" % (hdc_str, cfg_file_path, "/etc/")) 81 coverage_command("%s shell param set persist.appspawn.client.timeout 120 > /dev/null 2>&1" % hdc_str) 82 return 83 84 85def modify_faultloggerd_file(developer_path, hdc_str): 86 _, enforce = subprocess.getstatusoutput("%s shell getenforce" % hdc_str) 87 coverage_command("%s shell mount -o rw,remount /" % hdc_str) 88 print("%s shell mount -o rw,remount /" % hdc_str) 89 coverage_command("%s target mount" % hdc_str) 90 if enforce != "Permissive": 91 coverage_command("%s shell sed -i 's/enforcing/permissive/g' /system/etc/selinux/config" % hdc_str) 92 93 recv_path = os.path.join(developer_path, "local_coverage/resident_service/resources") 94 print("%s file recv /system/etc/init/faultloggerd.cfg %s" % (hdc_str, recv_path)) 95 coverage_command("%s file recv /system/etc/init/faultloggerd.cfg %s" % (hdc_str, recv_path)) 96 97 cfg_file_path = os.path.join(recv_path, "faultloggerd.cfg") 98 if os.path.exists(cfg_file_path): 99 with open(cfg_file_path, "r") as fp: 100 json_data = json.load(fp) 101 if json_data.get("jobs") and json_data["jobs"][0]["name"] != "pre-init": 102 json_data["jobs"].insert(0, { 103 "name": "pre-init", 104 "cmds": [ 105 "export LD_PRELOAD libcoverage_signal_handler.z.so" 106 ] 107 }) 108 json_str = json.dumps(json_data, indent=4) 109 if os.path.exists(cfg_file_path): 110 os.remove(cfg_file_path) 111 with os.fdopen(os.open(cfg_file_path, FLAGS, MODES), 'w') as json_file: 112 json_file.write(json_str) 113 print("%s file send %s %s" % (hdc_str, cfg_file_path, "/system/etc/init/")) 114 coverage_command("%s file send %s %s" % (hdc_str, cfg_file_path, "/system/etc/init/")) 115 else: 116 print("faultloggerd.cfg file not exists.") 117 118 return 119 120 121def modify_foundation_xml(serv, config_path, origin_xml) -> str: 122 """ 123 修改foundation.xml文件,删去拆分的进程相关 124 :param serv: 拆分进程 125 :param config_path: 配置文件路径 126 :param origin_xml: 原foundation.xml 127 :return: 修改后foundation.xml路径 128 """ 129 lib_list = FoundationServer.lib_dict.get(serv) 130 131 tree = ET.parse(origin_xml) 132 root = tree.getroot() 133 loadlibs = root.find("loadlibs") 134 135 for lib in lib_list: 136 for sa in root.findall('systemability'): 137 if lib in sa.find('libpath').text: 138 root.remove(sa) 139 for ll in loadlibs.findall('libpath'): 140 if lib in ll.text: 141 loadlibs.remove(ll) 142 143 tree.write(os.path.join(config_path, 'foundation.xml'), encoding='utf-8', xml_declaration=True) 144 return os.path.join(config_path, 'foundation.xml') 145 146 147def modify_foundation_json(serv, config_path, origin_json) -> str: 148 """ 149 修改foundation.json文件,删去拆分的进程相关 150 :param serv: 拆分进程 151 :param config_path: 配置文件路径 152 :param origin_json: 原foundation.json 153 :return: 修改后foundation.json路径 154 """ 155 lib_list = FoundationServer.lib_dict.get(serv) 156 157 with open(origin_json, "r", encoding="UTF-8") as f: 158 f_dict = json.load(f) 159 160 tmp_list = list() 161 for i in range(len(f_dict["systemability"])): 162 if f_dict["systemability"][i]["libpath"] not in lib_list: 163 tmp_list.append(f_dict["systemability"][i]) 164 f_dict["systemability"] = tmp_list 165 166 new_json = os.path.join(config_path, 'foundation.json') 167 if os.path.exists(new_json): 168 os.remove(new_json) 169 with os.fdopen(os.open(new_json, FLAGS, MODES), 'w') as f: 170 json.dump(f_dict, f, indent=4) 171 172 return new_json 173 174 175def create_service_json(serv, config_path, origin_json) -> str: 176 """ 177 创建进程json 178 :param serv: 进程名 179 :param config_path:配置文件所在目录 180 :param origin_json: 原foundation.json 181 :return: json文件路径 182 """ 183 lib_list = FoundationServer.lib_dict.get(serv) 184 with open(origin_json, "r", encoding="UTF-8") as f: 185 f_dict = json.load(f) 186 187 tmp_list = list() 188 for lib in lib_list: 189 for i in range(len(f_dict["systemability"])): 190 if f_dict["systemability"][i]["libpath"] == lib: 191 tmp_list.append(f_dict["systemability"][i]) 192 f_dict["systemability"] = tmp_list 193 f_dict["process"] = "{}".format(serv) 194 195 new_json = os.path.join(config_path, '{}.json'.format(serv)) 196 if os.path.exists(new_json): 197 os.remove(new_json) 198 with os.fdopen(os.open(new_json, FLAGS, MODES), 'w') as f: 199 json.dump(f_dict, f, indent=4) 200 201 return new_json 202 203 204def create_service_xml(serv, config_path, origin_xml) -> str: 205 """ 206 创建进程xml 207 :param serv: 进程名 208 :param config_path:配置文件所在目录 209 :param origin_xml: 原foundation.xml 210 :return: xml文件路径 211 """ 212 lib_list = FoundationServer.lib_dict.get(serv) 213 214 tree = ET.parse(origin_xml) 215 root = tree.getroot() 216 loadlibs = root.find("loadlibs") 217 218 for lib in lib_list: 219 for sa in root.findall('systemability'): 220 if lib not in sa.find('libpath').text: 221 root.remove(sa) 222 for lp in loadlibs.findall('libpath'): 223 if lib not in lp.text: 224 loadlibs.remove(lp) 225 226 tree.write(os.path.join(config_path, '{}.xml'.format(serv)), encoding='utf-8', xml_declaration=True) 227 return os.path.join(config_path, '{}.xml'.format(serv)) 228 229 230def create_service_cfg(serv, config_path, origin_cfg) -> str: 231 """ 232 创建进程cfg文件 233 :param serv: 进程名 234 :param config_path:配置文件所在目录 235 :param origin_cfg: 原foundation.cfg 236 :return: cfg文件路径 237 """ 238 with open(origin_cfg, "r") as jf: 239 json_obj = json.load(jf) 240 json_obj["jobs"][0]["name"] = "services:{}".format(serv) 241 242 json_obj["services"][0]["name"] = "{}".format(serv) 243 244 path_list = json_obj["services"][0]["path"] 245 path_list.remove("/system/profile/foundation.json") 246 path_list.append("/system/profile/{}.json".format(serv)) 247 json_obj["services"][0]["path"] = path_list 248 249 json_obj["services"][0]["jobs"]["on-start"] = "services:{}".format(serv) 250 251 cfg_path = os.path.join(config_path, "{}.cfg".format(serv)) 252 if os.path.exists(cfg_path): 253 os.remove(cfg_path) 254 with os.fdopen(os.open(cfg_path, FLAGS, MODES), 'w') as r: 255 json.dump(json_obj, r, indent=4) 256 return cfg_path 257 258 259def remove_configs(config_path): 260 """ 261 清理配置文件目录下的xml和cfg文件 262 :param config_path: 配置文件目录 263 :return: 264 """ 265 logger("Clear config path...", "INFO") 266 shutil.rmtree(config_path) 267 os.mkdir(config_path) 268 269 270def split_foundation_services(developer_path, system_info_dict, home_path, hdc_dict): 271 """ 272 foundation.xml、XXX.xml文件推送到 /system/profile 273 XXX.cfg文件推送到/etc/init/ 274 reboot设备,可以将服务从foundation中拆分出来,成为一个独立服务进程 275 """ 276 config_path = os.path.join(developer_path, "local_coverage", "resident_service", "config") 277 remove_configs(config_path) 278 279 device_ip = hdc_dict["device_ip"] 280 hdc_port = hdc_dict["device_port"] 281 device_sn = hdc_dict["device_sn_str"] 282 283 hdc_command(device_ip, hdc_port, device_sn, "file recv /system/profile/foundation.json {}".format(config_path)) 284 hdc_command(device_ip, hdc_port, device_sn, "file recv /etc/init/foundation.cfg {}".format(config_path)) 285 286 if os.path.exists(os.path.join(config_path, "foundation.json")): 287 origin_json = os.path.join(config_path, "foundation_origin.json") 288 os.rename(os.path.join(config_path, "foundation.json"), origin_json) 289 else: 290 logger("{} not exist, Cannot modify.".format(os.path.join(config_path, "foundation.json")), "ERROR") 291 return 292 293 if os.path.exists(os.path.join(config_path, "foundation.cfg")): 294 origin_cfg = os.path.join(config_path, "foundation_origin.cfg") 295 os.rename(os.path.join(config_path, "foundation.cfg"), origin_cfg) 296 else: 297 logger("{} not exist, Cannot modify.".format(os.path.join(config_path, "foundation.cfg")), "ERROR") 298 return 299 300 foundation_process_list = FoundationServer.lib_dict.keys() 301 302 # 推送配置文件 303 for _, value_list in system_info_dict.items(): 304 for process_str in value_list: 305 if process_str in foundation_process_list: 306 foundation_json = modify_foundation_json(process_str, config_path, origin_json) 307 service_json = create_service_json(process_str, config_path, origin_json) 308 service_cfg = create_service_cfg(process_str, config_path, origin_cfg) 309 310 hdc_command(device_ip, hdc_port, device_sn, "shell rm -rf {}".format(home_path)) 311 hdc_command(device_ip, hdc_port, device_sn, "file send {} /system/profile/".format(foundation_json)) 312 hdc_command(device_ip, hdc_port, device_sn, "file send {} /system/profile/".format(service_json)) 313 hdc_command(device_ip, hdc_port, device_sn, "file send {} /etc/init/".format(service_cfg)) 314 315 return 316 317 318def modify_cfg_xml_file(developer_path, device_ip, device_sn_list, 319 system_info_dict, home_path, device_port): 320 if device_ip and len(device_sn_list) >= 1: 321 for device_sn_str in device_sn_list: 322 hdc_str = "hdc -s %s:%s -t %s" % (device_ip, device_port, device_sn_str) 323 hdc_dict = {"device_ip": device_ip, "device_port": device_port, "device_sn_str": device_sn_str} 324 modify_init_file(developer_path, hdc_str) 325 modify_faultloggerd_file( 326 developer_path, hdc_str) 327 # 推送服务对应的配置文件 328 split_foundation_services(developer_path, system_info_dict, home_path, hdc_dict) 329 logger("{} shell reboot".format(hdc_str), "INFO") 330 coverage_command("%s shell reboot > /dev/null 2>&1" % hdc_str) 331 while True: 332 after_sn_list = get_sn_list("hdc -s %s:%s list targets" % (device_ip, device_port)) 333 time.sleep(10) 334 if device_sn_str in after_sn_list: 335 break 336 coverage_command("%s shell getenforce" % hdc_str) 337 else: 338 logger("user_config.xml device ip not config", "ERROR") 339 340 341if __name__ == '__main__': 342 command_args = sys.argv[1] 343 command_str = command_args.split("command_str=")[1].replace(",", " ") 344 current_path = os.getcwd() 345 _init_sys_config() 346 from local_coverage.utils import coverage_command, \ 347 logger, hdc_command, FoundationServer 348 349 root_path = current_path.split("/test/testfwk/developer_test")[0] 350 developer_test_path = os.path.join(root_path, "test/testfwk/developer_test") 351 home_paths = '/'.join(root_path.split("/")[:3]) 352 353 # 获取user_config中的device ip 354 ip, port, sn = get_config_ip(os.path.join(developer_test_path, "config/user_config.xml")) 355 if not port: 356 port = "8710" 357 sn_list = [] 358 if sn: 359 sn_list.extend(sn.replace(" ", "").split(";")) 360 else: 361 sn_list = get_sn_list("hdc -s %s:%s list targets" % (ip, port)) 362 363 # 获取子系统部件与服务的关系 364 system_dict, _, _ = get_server_dict(command_str) 365 366 # 修改设备init.cfg, faultloggerd.cfg等文件 367 modify_cfg_xml_file(developer_test_path, ip, sn_list, 368 system_dict, home_paths, port) 369