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