140681896Sopenharmony_ci#!/usr/bin/env python3
240681896Sopenharmony_ci# -*- coding: utf-8 -*-
340681896Sopenharmony_ci
440681896Sopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd.
540681896Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
640681896Sopenharmony_ci# you may not use this file except in compliance with the License.
740681896Sopenharmony_ci# You may obtain a copy of the License at
840681896Sopenharmony_ci#
940681896Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
1040681896Sopenharmony_ci#
1140681896Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
1240681896Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
1340681896Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1440681896Sopenharmony_ci# See the License for the specific language governing permissions and
1540681896Sopenharmony_ci# limitations under the License.
1640681896Sopenharmony_ci"""
1740681896Sopenharmony_ciDescription : Defining constants, common interface
1840681896Sopenharmony_ci"""
1940681896Sopenharmony_ciimport argparse
2040681896Sopenharmony_ciimport json
2140681896Sopenharmony_ciimport os
2240681896Sopenharmony_ciimport shutil
2340681896Sopenharmony_ciimport tempfile
2440681896Sopenharmony_cifrom collections import OrderedDict
2540681896Sopenharmony_ciimport xmltodict
2640681896Sopenharmony_ciimport zipfile
2740681896Sopenharmony_ci
2840681896Sopenharmony_cifrom cryptography.hazmat.primitives import hashes
2940681896Sopenharmony_cifrom log_exception import UPDATE_LOGGER
3040681896Sopenharmony_cifrom build_pkcs7 import sign_ota_package
3140681896Sopenharmony_cifrom copy import copy
3240681896Sopenharmony_cifrom ctypes import cdll
3340681896Sopenharmony_ci
3440681896Sopenharmony_cioperation_path = os.path.dirname(os.path.realpath(__file__))
3540681896Sopenharmony_ciPRODUCT = 'hi3516'
3640681896Sopenharmony_ciBUILD_TOOLS_FILE_NAME = 'build_tools.zip'
3740681896Sopenharmony_ciUPDATE_BIN_FILE_NAME = "update.bin"
3840681896Sopenharmony_ciUPDATE_EXE_FILE_NAME = "updater_binary"
3940681896Sopenharmony_ci
4040681896Sopenharmony_ciSCRIPT_KEY_LIST = ['prelude', 'verse', 'refrain', 'ending']
4140681896Sopenharmony_ciTOTAL_SCRIPT_FILE_NAME = "loadScript.us"
4240681896Sopenharmony_ciREGISTER_SCRIPT_FILE_NAME = "registerCmd.us"
4340681896Sopenharmony_ciSCRIPT_FILE_NAME = '-script.us'
4440681896Sopenharmony_ci
4540681896Sopenharmony_ciUPDATER_CONFIG = "updater_config"
4640681896Sopenharmony_ciXML_FILE_PATH = "updater_specified_config.xml"
4740681896Sopenharmony_ciSO_PATH = os.path.join(operation_path, 'lib/libpackage.so')
4840681896Sopenharmony_ciSO_PATH_L1 = os.path.join(operation_path, 'lib/libpackageL1.so')
4940681896Sopenharmony_ciDIFF_EXE_PATH = os.path.join(operation_path, 'lib/diff')
5040681896Sopenharmony_ciE2FSDROID_PATH = os.path.join(operation_path, 'lib/e2fsdroid')
5140681896Sopenharmony_ciMISC_INFO_PATH = "misc_info.txt"
5240681896Sopenharmony_ciVERSION_MBN_PATH = "VERSION.mbn"
5340681896Sopenharmony_ciBOARD_LIST_PATH = "BOARD.list"
5440681896Sopenharmony_ciEXTEND_COMPONENT_LIST = ["version_list", "board_list"]
5540681896Sopenharmony_ciEXTEND_OPTIONAL_COMPONENT_LIST = ["partitions_file"]
5640681896Sopenharmony_ciPARTITION_FILE = "partitions_file"
5740681896Sopenharmony_ciIGNORED_PARTITION_LIST = ['fastboot', 'boot', 'kernel', 'misc',
5840681896Sopenharmony_ci                          'updater', 'userdata']
5940681896Sopenharmony_ci
6040681896Sopenharmony_ciHASH_ALGORITHM_DICT = {'sha256': hashes.SHA256, 'sha384': hashes.SHA384}
6140681896Sopenharmony_ciLINUX_HASH_ALGORITHM_DICT = {'sha256': 'sha256sum', 'sha384': 'sha384sum'}
6240681896Sopenharmony_ciHASH_CONTENT_LEN_DICT = {'sha256': 64, 'sha384': 96}
6340681896Sopenharmony_ci
6440681896Sopenharmony_ciCOMPONENT_INFO_INNIT = ['', '000', '00', '0', '0o00']
6540681896Sopenharmony_ci
6640681896Sopenharmony_ciON_SERVER = "ON_SERVER"
6740681896Sopenharmony_ci
6840681896Sopenharmony_ciEXTEND_VALUE = 512
6940681896Sopenharmony_ci
7040681896Sopenharmony_ciFILE_MAP_ZERO_KEY = "__ZERO"
7140681896Sopenharmony_ciFILE_MAP_NONZERO_KEY = "__NONZERO"
7240681896Sopenharmony_ciFILE_MAP_COPY_KEY = "__COPY"
7340681896Sopenharmony_ci
7440681896Sopenharmony_ciMAX_BLOCKS_PER_GROUP = BLOCK_LIMIT = 1024
7540681896Sopenharmony_ciPER_BLOCK_SIZE = 4096
7640681896Sopenharmony_ci
7740681896Sopenharmony_ciVERSE_SCRIPT_EVENT = 0
7840681896Sopenharmony_ciINC_IMAGE_EVENT = 1
7940681896Sopenharmony_ciSIGN_PACKAGE_EVENT = 2
8040681896Sopenharmony_ciCHECK_BINARY_EVENT = 3
8140681896Sopenharmony_ciCONFIG_EVENT = 4
8240681896Sopenharmony_ciEXTEND_PATH_EVENT = 5
8340681896Sopenharmony_ciZIP_EVENT = 6
8440681896Sopenharmony_ciGENERATE_SIGNED_DATA_EVENT = 7 # sign build tools files to get hash_signed_data
8540681896Sopenharmony_ciPARTITION_CHANGE_EVENT = 8
8640681896Sopenharmony_ciDECOUPLED_EVENT = 9
8740681896Sopenharmony_ci
8840681896Sopenharmony_ci# Image file can not support update.
8940681896Sopenharmony_ciFORBIDEN_UPDATE_IMAGE_SET = {"ptable"}
9040681896Sopenharmony_ci
9140681896Sopenharmony_ci# 1000000: max number of function recursion depth
9240681896Sopenharmony_ciMAXIMUM_RECURSION_DEPTH = 1000000
9340681896Sopenharmony_ci
9440681896Sopenharmony_ci
9540681896Sopenharmony_cidef singleton(cls):
9640681896Sopenharmony_ci    _instance = {}
9740681896Sopenharmony_ci
9840681896Sopenharmony_ci    def _singleton(*args, **kargs):
9940681896Sopenharmony_ci        if cls not in _instance:
10040681896Sopenharmony_ci            _instance[cls] = cls(*args, **kargs)
10140681896Sopenharmony_ci        return _instance[cls]
10240681896Sopenharmony_ci
10340681896Sopenharmony_ci    return _singleton
10440681896Sopenharmony_ci
10540681896Sopenharmony_ci
10640681896Sopenharmony_ciclass ExtInit:
10740681896Sopenharmony_ci    """
10840681896Sopenharmony_ci    Init event for ext
10940681896Sopenharmony_ci    """
11040681896Sopenharmony_ci
11140681896Sopenharmony_ci    def __init__(self):
11240681896Sopenharmony_ci        self.funs = []
11340681896Sopenharmony_ci
11440681896Sopenharmony_ci    def reg_event(self, evevt_id, funs):
11540681896Sopenharmony_ci        self.funs.append([evevt_id, funs])
11640681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
11740681896Sopenharmony_ci            'register event %s: %s' % (evevt_id, funs.__name__))
11840681896Sopenharmony_ci
11940681896Sopenharmony_ci    def invoke_event(self, evevt_id):
12040681896Sopenharmony_ci        UPDATE_LOGGER.print_log(self.funs)
12140681896Sopenharmony_ci        for event in self.funs:
12240681896Sopenharmony_ci            funs = event[1]
12340681896Sopenharmony_ci            if event[0] == evevt_id and funs is not None:
12440681896Sopenharmony_ci                UPDATE_LOGGER.print_log(
12540681896Sopenharmony_ci                    'invoke event %s: %s' % (evevt_id, funs.__name__))
12640681896Sopenharmony_ci                return funs
12740681896Sopenharmony_ci        return False
12840681896Sopenharmony_ci
12940681896Sopenharmony_ci
13040681896Sopenharmony_ciclass BaseOptionsManager:
13140681896Sopenharmony_ci    def __init__(self):
13240681896Sopenharmony_ci        # Entry parameters
13340681896Sopenharmony_ci        self.source_package = None
13440681896Sopenharmony_ci        self.target_package = None
13540681896Sopenharmony_ci        self.update_package = None
13640681896Sopenharmony_ci        self.unpack_package_path = None
13740681896Sopenharmony_ci        self.no_zip = False
13840681896Sopenharmony_ci        self.partition_file = None
13940681896Sopenharmony_ci        self.signing_algorithm = None
14040681896Sopenharmony_ci        self.hash_algorithm = None
14140681896Sopenharmony_ci        self.private_key = None
14240681896Sopenharmony_ci        self.not_l2 = False
14340681896Sopenharmony_ci        self.signing_length = 256
14440681896Sopenharmony_ci        self.xml_path = None
14540681896Sopenharmony_ci        self.sd_card = False
14640681896Sopenharmony_ci
14740681896Sopenharmony_ci        self.make_dir_path = None
14840681896Sopenharmony_ci
14940681896Sopenharmony_ci
15040681896Sopenharmony_ci@singleton
15140681896Sopenharmony_ciclass OptionsManager(BaseOptionsManager):
15240681896Sopenharmony_ci    """
15340681896Sopenharmony_ci    Options management class
15440681896Sopenharmony_ci    """
15540681896Sopenharmony_ci
15640681896Sopenharmony_ci    def __init__(self):
15740681896Sopenharmony_ci        super().__init__()
15840681896Sopenharmony_ci
15940681896Sopenharmony_ci        self.init = ExtInit()
16040681896Sopenharmony_ci        self.parser = argparse.ArgumentParser()
16140681896Sopenharmony_ci
16240681896Sopenharmony_ci        # Own parameters
16340681896Sopenharmony_ci        self.product = None
16440681896Sopenharmony_ci
16540681896Sopenharmony_ci
16640681896Sopenharmony_ci        # Parsed package parameters
16740681896Sopenharmony_ci        self.target_package_dir = None
16840681896Sopenharmony_ci        self.target_package_config_dir = None
16940681896Sopenharmony_ci        self.target_package_temp_obj = None
17040681896Sopenharmony_ci        self.misc_info_dict = {}
17140681896Sopenharmony_ci        self.version_mbn_file_path = None
17240681896Sopenharmony_ci        self.version_mbn_content = None
17340681896Sopenharmony_ci        self.board_list_file_path = None
17440681896Sopenharmony_ci        self.board_list_content = None
17540681896Sopenharmony_ci
17640681896Sopenharmony_ci        self.source_package_dir = None
17740681896Sopenharmony_ci        self.source_package_temp_obj = None
17840681896Sopenharmony_ci
17940681896Sopenharmony_ci        # XML parsing parameters
18040681896Sopenharmony_ci        self.head_info_list = []
18140681896Sopenharmony_ci        self.component_info_dict = {}
18240681896Sopenharmony_ci        self.full_img_list = []
18340681896Sopenharmony_ci        self.full_img_name_list = []
18440681896Sopenharmony_ci        self.incremental_img_list = []
18540681896Sopenharmony_ci        self.incremental_img_name_list = []
18640681896Sopenharmony_ci        self.target_package_version = None
18740681896Sopenharmony_ci        self.source_package_version = None
18840681896Sopenharmony_ci        self.full_image_path_list = []
18940681896Sopenharmony_ci
19040681896Sopenharmony_ci        self.partition_file_obj = None
19140681896Sopenharmony_ci
19240681896Sopenharmony_ci        # Full processing parameters
19340681896Sopenharmony_ci        self.full_image_content_len_list = []
19440681896Sopenharmony_ci        self.full_image_file_obj_list = []
19540681896Sopenharmony_ci
19640681896Sopenharmony_ci        # Incremental processing parameters
19740681896Sopenharmony_ci        self.incremental_content_len_list = []
19840681896Sopenharmony_ci        self.incremental_image_file_obj_dict = {}
19940681896Sopenharmony_ci        self.incremental_block_file_obj_dict = {}
20040681896Sopenharmony_ci        self.incremental_temp_file_obj_list = []
20140681896Sopenharmony_ci        self.max_stash_size = 0
20240681896Sopenharmony_ci
20340681896Sopenharmony_ci        # Script parameters
20440681896Sopenharmony_ci        self.opera_script_file_name_dict = {}
20540681896Sopenharmony_ci        for each in SCRIPT_KEY_LIST:
20640681896Sopenharmony_ci            self.opera_script_file_name_dict[each] = []
20740681896Sopenharmony_ci        self.total_script_file_obj = None
20840681896Sopenharmony_ci
20940681896Sopenharmony_ci        self.register_script_file_obj = None
21040681896Sopenharmony_ci
21140681896Sopenharmony_ci        # Update package parameters
21240681896Sopenharmony_ci        self.update_bin_obj = None
21340681896Sopenharmony_ci        self.build_tools_zip_obj = None
21440681896Sopenharmony_ci        self.update_package_file_path = None
21540681896Sopenharmony_ci        self.signed_package = None
21640681896Sopenharmony_ci
21740681896Sopenharmony_ci
21840681896Sopenharmony_ciOPTIONS_MANAGER = OptionsManager()
21940681896Sopenharmony_ci
22040681896Sopenharmony_ci
22140681896Sopenharmony_cidef unzip_package(package_path, origin='target'):
22240681896Sopenharmony_ci    """
22340681896Sopenharmony_ci    Decompress the zip package.
22440681896Sopenharmony_ci    :param package_path: zip package path
22540681896Sopenharmony_ci    :param origin: package origin, which indicates
22640681896Sopenharmony_ci                whether the zip package is a source package or target package
22740681896Sopenharmony_ci    :return: Temporary directory (tmp_dir) and zip_data package;
22840681896Sopenharmony_ci            false if an exception occurs.
22940681896Sopenharmony_ci    """
23040681896Sopenharmony_ci    try:
23140681896Sopenharmony_ci        tmp_dir_obj = tempfile.TemporaryDirectory(prefix="%sfiles-" % origin)
23240681896Sopenharmony_ci        tmp_dir = tmp_dir_obj.name
23340681896Sopenharmony_ci
23440681896Sopenharmony_ci        zf_obj = zipfile.ZipFile(package_path)
23540681896Sopenharmony_ci        for name in zf_obj.namelist():
23640681896Sopenharmony_ci            if name.endswith('/'):
23740681896Sopenharmony_ci                os.mkdir(os.path.join(tmp_dir, name))
23840681896Sopenharmony_ci            else:
23940681896Sopenharmony_ci                ext_filename = os.path.join(
24040681896Sopenharmony_ci                    tmp_dir, name)
24140681896Sopenharmony_ci                fd = os.open(ext_filename, os.O_RDWR | os.O_CREAT, 0o755)
24240681896Sopenharmony_ci                with os.fdopen(fd, "wb") as f_w:
24340681896Sopenharmony_ci                    f_w.write(zf_obj.read(name))
24440681896Sopenharmony_ci    except OSError:
24540681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
24640681896Sopenharmony_ci            "Unzip package failed! path: %s" % package_path,
24740681896Sopenharmony_ci            log_type=UPDATE_LOGGER.ERROR_LOG)
24840681896Sopenharmony_ci        return False, False
24940681896Sopenharmony_ci    tmp_dir_list = os.listdir(tmp_dir)
25040681896Sopenharmony_ci    if len(tmp_dir_list) == 1:
25140681896Sopenharmony_ci        unzip_dir = os.path.join(tmp_dir, tmp_dir_list[0])
25240681896Sopenharmony_ci        if UPDATER_CONFIG not in \
25340681896Sopenharmony_ci                os.listdir(unzip_dir):
25440681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
25540681896Sopenharmony_ci                'Unsupported zip package structure!', UPDATE_LOGGER.ERROR_LOG)
25640681896Sopenharmony_ci            return False, False
25740681896Sopenharmony_ci    elif UPDATER_CONFIG in tmp_dir_list:
25840681896Sopenharmony_ci        unzip_dir = tmp_dir
25940681896Sopenharmony_ci    else:
26040681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
26140681896Sopenharmony_ci            'Unsupported zip package structure!', UPDATE_LOGGER.ERROR_LOG)
26240681896Sopenharmony_ci        return False, False
26340681896Sopenharmony_ci    UPDATE_LOGGER.print_log(
26440681896Sopenharmony_ci        '%s package unzip complete! path: %s' % (origin.title(), unzip_dir))
26540681896Sopenharmony_ci
26640681896Sopenharmony_ci    return tmp_dir_obj, unzip_dir
26740681896Sopenharmony_ci
26840681896Sopenharmony_ci
26940681896Sopenharmony_cidef split_img_name(image_path):
27040681896Sopenharmony_ci    """
27140681896Sopenharmony_ci    Split the image name by image path
27240681896Sopenharmony_ci    :return image name
27340681896Sopenharmony_ci    """
27440681896Sopenharmony_ci    tmp_path = image_path
27540681896Sopenharmony_ci    str_list = tmp_path.split("/")
27640681896Sopenharmony_ci
27740681896Sopenharmony_ci    return str_list[-1]
27840681896Sopenharmony_ci
27940681896Sopenharmony_ci
28040681896Sopenharmony_cidef get_update_config_softversion(mbn_dir, head_info_dict):
28140681896Sopenharmony_ci    soft_version_file = head_info_dict.get('softVersionFile')
28240681896Sopenharmony_ci    if soft_version_file is not None:
28340681896Sopenharmony_ci        mbn_path = os.path.join(mbn_dir, soft_version_file)
28440681896Sopenharmony_ci        if os.path.exists(mbn_path):
28540681896Sopenharmony_ci            with open(mbn_path, 'r') as mbn_file:
28640681896Sopenharmony_ci                head_info_dict['info']["@softVersion"] = mbn_file.read()
28740681896Sopenharmony_ci
28840681896Sopenharmony_ci
28940681896Sopenharmony_cidef parse_update_config(xml_path):
29040681896Sopenharmony_ci    """
29140681896Sopenharmony_ci    Parse the XML configuration file.
29240681896Sopenharmony_ci    :param xml_path: XML configuration file path
29340681896Sopenharmony_ci    :return head_info_dict: header information dict of the update package
29440681896Sopenharmony_ci            component_info_dict: component information dict
29540681896Sopenharmony_ci            full_img_list: full image list
29640681896Sopenharmony_ci            incremental_img_list: incremental image list
29740681896Sopenharmony_ci    """
29840681896Sopenharmony_ci    if os.path.exists(xml_path):
29940681896Sopenharmony_ci        with open(xml_path, 'r') as xml_file:
30040681896Sopenharmony_ci            xml_str = xml_file.read()
30140681896Sopenharmony_ci    else:
30240681896Sopenharmony_ci        UPDATE_LOGGER.print_log("XML file does not exist! xml path: %s" % xml_path, UPDATE_LOGGER.ERROR_LOG)
30340681896Sopenharmony_ci        ret_params = [False, False, False, False, False, False, False]
30440681896Sopenharmony_ci        return ret_params
30540681896Sopenharmony_ci    xml_content_dict = xmltodict.parse(xml_str, encoding='utf-8')
30640681896Sopenharmony_ci    package_dict = xml_content_dict.get('package', {})
30740681896Sopenharmony_ci    get_update_config_softversion(OPTIONS_MANAGER.target_package_dir, package_dict.get('head', {}))
30840681896Sopenharmony_ci    head_dict = package_dict.get('head', {}).get('info')
30940681896Sopenharmony_ci    package_version = head_dict.get("@softVersion")
31040681896Sopenharmony_ci    # component
31140681896Sopenharmony_ci    component_info = package_dict.get('group', {}).get('component')
31240681896Sopenharmony_ci    head_list = list(head_dict.values())
31340681896Sopenharmony_ci    head_list.pop()
31440681896Sopenharmony_ci    whole_list = []
31540681896Sopenharmony_ci    difference_list = []
31640681896Sopenharmony_ci    comp_dict = {}
31740681896Sopenharmony_ci    full_image_path_list = []
31840681896Sopenharmony_ci
31940681896Sopenharmony_ci    if not OPTIONS_MANAGER.not_l2:
32040681896Sopenharmony_ci        expand_component(comp_dict)
32140681896Sopenharmony_ci    if isinstance(component_info, OrderedDict) or isinstance(component_info, dict):
32240681896Sopenharmony_ci        component_info = [component_info]
32340681896Sopenharmony_ci    if component_info is None:
32440681896Sopenharmony_ci        ret_params = [[], {}, [], [], '', [], False]
32540681896Sopenharmony_ci        return ret_params
32640681896Sopenharmony_ci    for component in component_info:
32740681896Sopenharmony_ci        if component['@compAddr'] == 'userdata' and not OPTIONS_MANAGER.sd_card:
32840681896Sopenharmony_ci            continue
32940681896Sopenharmony_ci        component_list = list(component.values())
33040681896Sopenharmony_ci        component_list.pop()
33140681896Sopenharmony_ci        comp_dict[component['@compAddr']] = component_list
33240681896Sopenharmony_ci
33340681896Sopenharmony_ci        if component['@compAddr'] in (whole_list + difference_list):
33440681896Sopenharmony_ci            UPDATE_LOGGER.print_log("This component %s  repeats!" % component['@compAddr'], UPDATE_LOGGER.ERROR_LOG)
33540681896Sopenharmony_ci            ret_params = [False, False, False, False, False, False, False]
33640681896Sopenharmony_ci            return ret_params
33740681896Sopenharmony_ci
33840681896Sopenharmony_ci        if component['@compType'] == '0':
33940681896Sopenharmony_ci            whole_list.append(component['@compAddr'])
34040681896Sopenharmony_ci            OPTIONS_MANAGER.full_img_name_list.append(split_img_name(component['#text']))
34140681896Sopenharmony_ci            tem_path = os.path.join(OPTIONS_MANAGER.target_package_dir, component.get("#text", None))
34240681896Sopenharmony_ci            full_image_path_list.append(tem_path)
34340681896Sopenharmony_ci            comp_dict[component['@compAddr']] = component_list
34440681896Sopenharmony_ci        elif component['@compType'] == '1':
34540681896Sopenharmony_ci            difference_list.append(component['@compAddr'])
34640681896Sopenharmony_ci            OPTIONS_MANAGER.incremental_img_name_list.append(split_img_name(component['#text']))
34740681896Sopenharmony_ci
34840681896Sopenharmony_ci    ret_params = [head_list, comp_dict, whole_list, difference_list, package_version, full_image_path_list]
34940681896Sopenharmony_ci    return ret_params
35040681896Sopenharmony_ci
35140681896Sopenharmony_ci
35240681896Sopenharmony_cidef partitions_conversion(data):
35340681896Sopenharmony_ci    """
35440681896Sopenharmony_ci    Convert the start or length data in the partition table through
35540681896Sopenharmony_ci    multiply 1024 * 1024 and return the data.
35640681896Sopenharmony_ci    :param data: start or length data
35740681896Sopenharmony_ci    :return :
35840681896Sopenharmony_ci    """
35940681896Sopenharmony_ci    if data == '0':
36040681896Sopenharmony_ci        return 0
36140681896Sopenharmony_ci    elif data.endswith('M'):
36240681896Sopenharmony_ci        return int(data[0:-1]) * 1024 * 1024 // 512
36340681896Sopenharmony_ci    else:
36440681896Sopenharmony_ci        return False
36540681896Sopenharmony_ci
36640681896Sopenharmony_ci
36740681896Sopenharmony_cidef parse_partition_file_xml(xml_path):
36840681896Sopenharmony_ci    """
36940681896Sopenharmony_ci    Parse the XML configuration file.
37040681896Sopenharmony_ci    :param xml_path: XML configuration file path
37140681896Sopenharmony_ci    :return part_json: partition table information in JSON format
37240681896Sopenharmony_ci    """
37340681896Sopenharmony_ci    if os.path.exists(xml_path):
37440681896Sopenharmony_ci        with open(xml_path, 'r') as xml_file:
37540681896Sopenharmony_ci            xml_str = xml_file.read()
37640681896Sopenharmony_ci    else:
37740681896Sopenharmony_ci        UPDATE_LOGGER.print_log("XML file does not exist! xml path: %s" %
37840681896Sopenharmony_ci                                xml_path, UPDATE_LOGGER.ERROR_LOG)
37940681896Sopenharmony_ci        return False, False, False
38040681896Sopenharmony_ci    partitions_list = []
38140681896Sopenharmony_ci    partitions_file_path_list = []
38240681896Sopenharmony_ci    xml_content_dict = xmltodict.parse(xml_str, encoding='utf-8')
38340681896Sopenharmony_ci    part_list = xml_content_dict['Partition_Info']['Part']
38440681896Sopenharmony_ci    new_part_list = []
38540681896Sopenharmony_ci    for i, part in enumerate(part_list):
38640681896Sopenharmony_ci        start_value = partitions_conversion(part.get('@Start'))
38740681896Sopenharmony_ci        length_value = partitions_conversion(part.get('@Length'))
38840681896Sopenharmony_ci        if start_value is False or length_value is False:
38940681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
39040681896Sopenharmony_ci                "Partition file parsing failed! part_name: %s, xml_path: %s" %
39140681896Sopenharmony_ci                (part.get('@PartitionName'), xml_path),
39240681896Sopenharmony_ci                UPDATE_LOGGER.ERROR_LOG)
39340681896Sopenharmony_ci            return False, False, False
39440681896Sopenharmony_ci
39540681896Sopenharmony_ci        if part.get('@PartitionName') not in IGNORED_PARTITION_LIST:
39640681896Sopenharmony_ci            partitions_list.append(part.get('@PartitionName'))
39740681896Sopenharmony_ci            partitions_file_path_list.append(
39840681896Sopenharmony_ci                os.path.join(OPTIONS_MANAGER.target_package_dir,
39940681896Sopenharmony_ci                             "%s.img" % part.get('@PartitionName')))
40040681896Sopenharmony_ci        part_dict = {'start': start_value,
40140681896Sopenharmony_ci                     'length': length_value,
40240681896Sopenharmony_ci                     'partName': part.get('@PartitionName'),
40340681896Sopenharmony_ci                     'fsType': part.get('@FlashType')}
40440681896Sopenharmony_ci        new_part_list.append(part_dict)
40540681896Sopenharmony_ci    part_json = json.dumps(new_part_list)
40640681896Sopenharmony_ci    part_json = '{"Partition": %s}' % part_json
40740681896Sopenharmony_ci    file_obj = tempfile.NamedTemporaryFile(
40840681896Sopenharmony_ci        dir=OPTIONS_MANAGER.target_package_dir, prefix="partition_file-", mode='wb')
40940681896Sopenharmony_ci    file_obj.write(part_json.encode())
41040681896Sopenharmony_ci    file_obj.seek(0)
41140681896Sopenharmony_ci    return file_obj, partitions_list, partitions_file_path_list
41240681896Sopenharmony_ci
41340681896Sopenharmony_ci
41440681896Sopenharmony_cidef get_extend_path_list():
41540681896Sopenharmony_ci    get_config_list = OPTIONS_MANAGER.init.invoke_event(CONFIG_EVENT)
41640681896Sopenharmony_ci    if get_config_list:
41740681896Sopenharmony_ci        return get_config_list()
41840681896Sopenharmony_ci    else:
41940681896Sopenharmony_ci        return EXTEND_COMPONENT_LIST
42040681896Sopenharmony_ci
42140681896Sopenharmony_ci
42240681896Sopenharmony_cidef expand_component(component_dict):
42340681896Sopenharmony_ci    """
42440681896Sopenharmony_ci    Append components such as VERSION.mbn and board list.
42540681896Sopenharmony_ci    :param component_dict: component information dict
42640681896Sopenharmony_ci    :return:
42740681896Sopenharmony_ci    """
42840681896Sopenharmony_ci    extend_path_list = get_extend_path_list()
42940681896Sopenharmony_ci    if OPTIONS_MANAGER.partition_file is not None:
43040681896Sopenharmony_ci        extend_component_list = \
43140681896Sopenharmony_ci            extend_path_list + EXTEND_OPTIONAL_COMPONENT_LIST
43240681896Sopenharmony_ci    else:
43340681896Sopenharmony_ci        extend_component_list = extend_path_list
43440681896Sopenharmony_ci    for each in extend_component_list:
43540681896Sopenharmony_ci        tmp_info_list = copy(COMPONENT_INFO_INNIT)
43640681896Sopenharmony_ci        tmp_info_list[0] = each
43740681896Sopenharmony_ci        component_dict[each] = tmp_info_list
43840681896Sopenharmony_ci
43940681896Sopenharmony_ci
44040681896Sopenharmony_cidef clear_options():
44140681896Sopenharmony_ci    """
44240681896Sopenharmony_ci    Clear OPTIONS_MANAGER.
44340681896Sopenharmony_ci    """
44440681896Sopenharmony_ci    OPTIONS_MANAGER.product = None
44540681896Sopenharmony_ci
44640681896Sopenharmony_ci    # Entry parameters
44740681896Sopenharmony_ci    OPTIONS_MANAGER.source_package = None
44840681896Sopenharmony_ci    OPTIONS_MANAGER.target_package = None
44940681896Sopenharmony_ci    OPTIONS_MANAGER.update_package = None
45040681896Sopenharmony_ci    OPTIONS_MANAGER.no_zip = False
45140681896Sopenharmony_ci    OPTIONS_MANAGER.partition_file = None
45240681896Sopenharmony_ci    OPTIONS_MANAGER.signing_algorithm = None
45340681896Sopenharmony_ci    OPTIONS_MANAGER.hash_algorithm = None
45440681896Sopenharmony_ci    OPTIONS_MANAGER.private_key = None
45540681896Sopenharmony_ci    OPTIONS_MANAGER.not_l2 = False
45640681896Sopenharmony_ci    OPTIONS_MANAGER.signing_length = 256
45740681896Sopenharmony_ci    OPTIONS_MANAGER.xml_path = None
45840681896Sopenharmony_ci    OPTIONS_MANAGER.sd_card = False
45940681896Sopenharmony_ci
46040681896Sopenharmony_ci    OPTIONS_MANAGER.full_image_path_list = []
46140681896Sopenharmony_ci
46240681896Sopenharmony_ci    OPTIONS_MANAGER.make_dir_path = None
46340681896Sopenharmony_ci
46440681896Sopenharmony_ci    # Parsed package parameters
46540681896Sopenharmony_ci    OPTIONS_MANAGER.target_package_dir = None
46640681896Sopenharmony_ci    OPTIONS_MANAGER.target_package_config_dir = None
46740681896Sopenharmony_ci    OPTIONS_MANAGER.target_package_temp_obj = None
46840681896Sopenharmony_ci    OPTIONS_MANAGER.misc_info_dict = {}
46940681896Sopenharmony_ci    OPTIONS_MANAGER.version_mbn_file_path = None
47040681896Sopenharmony_ci    OPTIONS_MANAGER.version_mbn_content = None
47140681896Sopenharmony_ci    OPTIONS_MANAGER.board_list_file_path = None
47240681896Sopenharmony_ci    OPTIONS_MANAGER.board_list_content = None
47340681896Sopenharmony_ci
47440681896Sopenharmony_ci    OPTIONS_MANAGER.source_package_dir = None
47540681896Sopenharmony_ci    OPTIONS_MANAGER.source_package_temp_obj = None
47640681896Sopenharmony_ci
47740681896Sopenharmony_ci    # XML parsing parameters
47840681896Sopenharmony_ci    OPTIONS_MANAGER.head_info_list = []
47940681896Sopenharmony_ci    OPTIONS_MANAGER.component_info_dict = {}
48040681896Sopenharmony_ci    OPTIONS_MANAGER.full_img_list = []
48140681896Sopenharmony_ci    OPTIONS_MANAGER.incremental_img_list = []
48240681896Sopenharmony_ci    OPTIONS_MANAGER.target_package_version = None
48340681896Sopenharmony_ci    OPTIONS_MANAGER.source_package_version = None
48440681896Sopenharmony_ci    OPTIONS_MANAGER.partition_file_obj = None
48540681896Sopenharmony_ci
48640681896Sopenharmony_ci    # Global processing parameters
48740681896Sopenharmony_ci    OPTIONS_MANAGER.full_image_content_len_list = []
48840681896Sopenharmony_ci    OPTIONS_MANAGER.full_image_file_obj_list = []
48940681896Sopenharmony_ci
49040681896Sopenharmony_ci    # Incremental processing parameters
49140681896Sopenharmony_ci    OPTIONS_MANAGER.incremental_content_len_list = []
49240681896Sopenharmony_ci    OPTIONS_MANAGER.incremental_temp_file_obj_list = []
49340681896Sopenharmony_ci
49440681896Sopenharmony_ci    # Script parameters
49540681896Sopenharmony_ci    OPTIONS_MANAGER.opera_script_file_name_dict = {}
49640681896Sopenharmony_ci    for each in SCRIPT_KEY_LIST:
49740681896Sopenharmony_ci        OPTIONS_MANAGER.opera_script_file_name_dict[each] = []
49840681896Sopenharmony_ci    OPTIONS_MANAGER.total_script_file_obj = None
49940681896Sopenharmony_ci
50040681896Sopenharmony_ci    OPTIONS_MANAGER.register_script_file_obj = None
50140681896Sopenharmony_ci
50240681896Sopenharmony_ci    # Update package parameters
50340681896Sopenharmony_ci    OPTIONS_MANAGER.update_bin_obj = None
50440681896Sopenharmony_ci    OPTIONS_MANAGER.build_tools_zip_obj = None
50540681896Sopenharmony_ci    OPTIONS_MANAGER.update_package_file_path = None
50640681896Sopenharmony_ci
50740681896Sopenharmony_ci
50840681896Sopenharmony_cidef clear_resource(err_clear=False):
50940681896Sopenharmony_ci    """
51040681896Sopenharmony_ci    Clear resources, close temporary files, and clear temporary paths.
51140681896Sopenharmony_ci    :param err_clear: whether to clear errors
51240681896Sopenharmony_ci    :return:
51340681896Sopenharmony_ci    """
51440681896Sopenharmony_ci    target_package_temp_obj = OPTIONS_MANAGER.target_package_temp_obj
51540681896Sopenharmony_ci    if target_package_temp_obj is not None:
51640681896Sopenharmony_ci        target_package_temp_obj.cleanup()
51740681896Sopenharmony_ci    source_package_temp_obj = OPTIONS_MANAGER.source_package_temp_obj
51840681896Sopenharmony_ci    if source_package_temp_obj is not None:
51940681896Sopenharmony_ci        source_package_temp_obj.cleanup()
52040681896Sopenharmony_ci
52140681896Sopenharmony_ci    partition_file_obj = OPTIONS_MANAGER.partition_file_obj
52240681896Sopenharmony_ci    if partition_file_obj is not None:
52340681896Sopenharmony_ci        partition_file_obj.close()
52440681896Sopenharmony_ci
52540681896Sopenharmony_ci    build_tools_zip_obj = OPTIONS_MANAGER.build_tools_zip_obj
52640681896Sopenharmony_ci    if build_tools_zip_obj is not None:
52740681896Sopenharmony_ci        build_tools_zip_obj.close()
52840681896Sopenharmony_ci    update_bin_obj = OPTIONS_MANAGER.update_bin_obj
52940681896Sopenharmony_ci    if update_bin_obj is not None:
53040681896Sopenharmony_ci        update_bin_obj.close()
53140681896Sopenharmony_ci    total_script_file_obj = OPTIONS_MANAGER.total_script_file_obj
53240681896Sopenharmony_ci    if total_script_file_obj is not None:
53340681896Sopenharmony_ci        total_script_file_obj.close()
53440681896Sopenharmony_ci
53540681896Sopenharmony_ci    register_script_file_obj = OPTIONS_MANAGER.register_script_file_obj
53640681896Sopenharmony_ci    if register_script_file_obj is not None:
53740681896Sopenharmony_ci        register_script_file_obj.close()
53840681896Sopenharmony_ci
53940681896Sopenharmony_ci    full_image_file_obj_list = OPTIONS_MANAGER.full_image_file_obj_list
54040681896Sopenharmony_ci    if len(full_image_file_obj_list) != 0:
54140681896Sopenharmony_ci        for each_full_obj in full_image_file_obj_list:
54240681896Sopenharmony_ci            each_full_obj.close()
54340681896Sopenharmony_ci
54440681896Sopenharmony_ci    clear_file_obj(err_clear)
54540681896Sopenharmony_ci    clear_options()
54640681896Sopenharmony_ci
54740681896Sopenharmony_ci
54840681896Sopenharmony_cidef clear_file_obj(err_clear):
54940681896Sopenharmony_ci    """
55040681896Sopenharmony_ci    Clear resources and temporary file objects.
55140681896Sopenharmony_ci    :param err_clear: whether to clear errors
55240681896Sopenharmony_ci    :return:
55340681896Sopenharmony_ci    """
55440681896Sopenharmony_ci    incremental_temp_file_obj_list = \
55540681896Sopenharmony_ci        OPTIONS_MANAGER.incremental_temp_file_obj_list
55640681896Sopenharmony_ci    if len(incremental_temp_file_obj_list) != 0:
55740681896Sopenharmony_ci        for each_incremental_temp_obj in incremental_temp_file_obj_list:
55840681896Sopenharmony_ci            if each_incremental_temp_obj is not None:
55940681896Sopenharmony_ci                each_incremental_temp_obj.close()
56040681896Sopenharmony_ci    opera_script_file_name_dict = OPTIONS_MANAGER.opera_script_file_name_dict
56140681896Sopenharmony_ci    for each_value in opera_script_file_name_dict.values():
56240681896Sopenharmony_ci        for each in each_value:
56340681896Sopenharmony_ci            each[1].close()
56440681896Sopenharmony_ci    if err_clear:
56540681896Sopenharmony_ci        make_dir_path = OPTIONS_MANAGER.make_dir_path
56640681896Sopenharmony_ci        if make_dir_path is not None and os.path.exists(make_dir_path):
56740681896Sopenharmony_ci            shutil.rmtree(make_dir_path)
56840681896Sopenharmony_ci        update_package_file_path = OPTIONS_MANAGER.update_package_file_path
56940681896Sopenharmony_ci        if update_package_file_path is not None and \
57040681896Sopenharmony_ci                os.path.exists(update_package_file_path):
57140681896Sopenharmony_ci            os.remove(update_package_file_path)
57240681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
57340681896Sopenharmony_ci            'Exception occurred, Resource cleaning completed!')
57440681896Sopenharmony_ci    else:
57540681896Sopenharmony_ci        UPDATE_LOGGER.print_log('Resource cleaning completed!')
57640681896Sopenharmony_ci
57740681896Sopenharmony_ci
57840681896Sopenharmony_cidef get_file_content(file_path, file_name=None):
57940681896Sopenharmony_ci    """
58040681896Sopenharmony_ci    Read the file content.
58140681896Sopenharmony_ci    :param file_path: file path
58240681896Sopenharmony_ci    :param file_name: file name
58340681896Sopenharmony_ci    :return: file content
58440681896Sopenharmony_ci    """
58540681896Sopenharmony_ci    if not os.path.exists(file_path):
58640681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
58740681896Sopenharmony_ci            "%s is not exist! path: %s" % (file_name, file_path),
58840681896Sopenharmony_ci            log_type=UPDATE_LOGGER.ERROR_LOG)
58940681896Sopenharmony_ci        return False
59040681896Sopenharmony_ci    with open(file_path, 'r') as r_f:
59140681896Sopenharmony_ci        file_content = r_f.read()
59240681896Sopenharmony_ci    UPDATE_LOGGER.print_log(
59340681896Sopenharmony_ci        "%s file parsing complete! path: %s" % (file_name, file_path))
59440681896Sopenharmony_ci    return file_content
59540681896Sopenharmony_ci
59640681896Sopenharmony_ci
59740681896Sopenharmony_cidef get_update_info():
59840681896Sopenharmony_ci    """
59940681896Sopenharmony_ci    Parse the configuration file to obtain the update information.
60040681896Sopenharmony_ci    :return: update information if any; false otherwise.
60140681896Sopenharmony_ci    """
60240681896Sopenharmony_ci    if not OPTIONS_MANAGER.not_l2:
60340681896Sopenharmony_ci        decouple_res = OPTIONS_MANAGER.init.invoke_event(DECOUPLED_EVENT)
60440681896Sopenharmony_ci        OPTIONS_MANAGER.version_mbn_file_path = os.path.join(
60540681896Sopenharmony_ci            OPTIONS_MANAGER.target_package_config_dir, VERSION_MBN_PATH)
60640681896Sopenharmony_ci        version_mbn_content = \
60740681896Sopenharmony_ci            get_file_content(
60840681896Sopenharmony_ci                OPTIONS_MANAGER.version_mbn_file_path, os.path.basename(
60940681896Sopenharmony_ci                    os.path.join(OPTIONS_MANAGER.target_package_config_dir,
61040681896Sopenharmony_ci                                 VERSION_MBN_PATH)))
61140681896Sopenharmony_ci        if version_mbn_content is False and decouple_res is False:
61240681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
61340681896Sopenharmony_ci                "Get version mbn content failed!",
61440681896Sopenharmony_ci                log_type=UPDATE_LOGGER.ERROR_LOG)
61540681896Sopenharmony_ci            return False
61640681896Sopenharmony_ci        OPTIONS_MANAGER.version_mbn_content = version_mbn_content
61740681896Sopenharmony_ci        OPTIONS_MANAGER.board_list_file_path = os.path.join(
61840681896Sopenharmony_ci            OPTIONS_MANAGER.target_package_config_dir, BOARD_LIST_PATH)
61940681896Sopenharmony_ci        board_list_content = \
62040681896Sopenharmony_ci            get_file_content(
62140681896Sopenharmony_ci                OPTIONS_MANAGER.board_list_file_path, os.path.basename(
62240681896Sopenharmony_ci                    os.path.join(OPTIONS_MANAGER.target_package_config_dir,
62340681896Sopenharmony_ci                                 BOARD_LIST_PATH)))
62440681896Sopenharmony_ci        if board_list_content is False:
62540681896Sopenharmony_ci            UPDATE_LOGGER.print_log("Get board list content failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
62640681896Sopenharmony_ci            return False
62740681896Sopenharmony_ci        OPTIONS_MANAGER.board_list_content = board_list_content
62840681896Sopenharmony_ci
62940681896Sopenharmony_ci    if OPTIONS_MANAGER.xml_path is None:
63040681896Sopenharmony_ci        xml_file_path = os.path.join(
63140681896Sopenharmony_ci            OPTIONS_MANAGER.target_package_config_dir, XML_FILE_PATH)
63240681896Sopenharmony_ci    else:
63340681896Sopenharmony_ci        xml_file_path = OPTIONS_MANAGER.xml_path
63440681896Sopenharmony_ci
63540681896Sopenharmony_ci    # Parse the XML configuration file.
63640681896Sopenharmony_ci    head_info_list, component_info_dict, \
63740681896Sopenharmony_ci        full_img_list, incremental_img_list, \
63840681896Sopenharmony_ci        OPTIONS_MANAGER.target_package_version, \
63940681896Sopenharmony_ci        OPTIONS_MANAGER.full_image_path_list = \
64040681896Sopenharmony_ci        parse_update_config(xml_file_path)
64140681896Sopenharmony_ci    UPDATE_LOGGER.print_log("XML file parsing completed!")
64240681896Sopenharmony_ci    if head_info_list is False or component_info_dict is False or \
64340681896Sopenharmony_ci            full_img_list is False or incremental_img_list is False:
64440681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Get parse update config xml failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
64540681896Sopenharmony_ci        return False
64640681896Sopenharmony_ci    OPTIONS_MANAGER.head_info_list, OPTIONS_MANAGER.component_info_dict, \
64740681896Sopenharmony_ci        OPTIONS_MANAGER.full_img_list, OPTIONS_MANAGER.incremental_img_list = \
64840681896Sopenharmony_ci        head_info_list, component_info_dict, \
64940681896Sopenharmony_ci        full_img_list, incremental_img_list
65040681896Sopenharmony_ci    return True
65140681896Sopenharmony_ci
65240681896Sopenharmony_ci
65340681896Sopenharmony_cidef sign_package():
65440681896Sopenharmony_ci    return sign_ota_package(
65540681896Sopenharmony_ci        OPTIONS_MANAGER.update_package_file_path,
65640681896Sopenharmony_ci        OPTIONS_MANAGER.signed_package,
65740681896Sopenharmony_ci        OPTIONS_MANAGER.private_key)