• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.xmlXXX.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