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