• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2021 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16"""
17Description : Defining constants, common interface
18"""
19import argparse
20import json
21import os
22import shutil
23import tempfile
24from collections import OrderedDict
25import xmltodict
26import zipfile
27
28from cryptography.hazmat.primitives import hashes
29from log_exception import UPDATE_LOGGER
30from build_pkcs7 import sign_ota_package
31from copy import copy
32from ctypes import cdll
33
34operation_path = os.path.dirname(os.path.realpath(__file__))
35PRODUCT = 'hi3516'
36BUILD_TOOLS_FILE_NAME = 'build_tools.zip'
37UPDATE_BIN_FILE_NAME = "update.bin"
38UPDATE_EXE_FILE_NAME = "updater_binary"
39
40SCRIPT_KEY_LIST = ['prelude', 'verse', 'refrain', 'ending']
41TOTAL_SCRIPT_FILE_NAME = "loadScript.us"
42REGISTER_SCRIPT_FILE_NAME = "registerCmd.us"
43SCRIPT_FILE_NAME = '-script.us'
44
45UPDATER_CONFIG = "updater_config"
46XML_FILE_PATH = "updater_specified_config.xml"
47SO_PATH = os.path.join(operation_path, 'lib/libpackage.so')
48SO_PATH_L1 = os.path.join(operation_path, 'lib/libpackageL1.so')
49DIFF_EXE_PATH = os.path.join(operation_path, 'lib/diff')
50E2FSDROID_PATH = os.path.join(operation_path, 'lib/e2fsdroid')
51MISC_INFO_PATH = "misc_info.txt"
52VERSION_MBN_PATH = "VERSION.mbn"
53BOARD_LIST_PATH = "BOARD.list"
54EXTEND_COMPONENT_LIST = ["version_list", "board_list"]
55EXTEND_OPTIONAL_COMPONENT_LIST = ["partitions_file"]
56PARTITION_FILE = "partitions_file"
57IGNORED_PARTITION_LIST = ['fastboot', 'boot', 'kernel', 'misc',
58                          'updater', 'userdata']
59
60HASH_ALGORITHM_DICT = {'sha256': hashes.SHA256, 'sha384': hashes.SHA384}
61LINUX_HASH_ALGORITHM_DICT = {'sha256': 'sha256sum', 'sha384': 'sha384sum'}
62HASH_CONTENT_LEN_DICT = {'sha256': 64, 'sha384': 96}
63
64COMPONENT_INFO_INNIT = ['', '000', '00', '0', '0o00']
65
66ON_SERVER = "ON_SERVER"
67
68EXTEND_VALUE = 512
69
70FILE_MAP_ZERO_KEY = "__ZERO"
71FILE_MAP_NONZERO_KEY = "__NONZERO"
72FILE_MAP_COPY_KEY = "__COPY"
73
74MAX_BLOCKS_PER_GROUP = BLOCK_LIMIT = 1024
75PER_BLOCK_SIZE = 4096
76
77VERSE_SCRIPT_EVENT = 0
78INC_IMAGE_EVENT = 1
79SIGN_PACKAGE_EVENT = 2
80CHECK_BINARY_EVENT = 3
81CONFIG_EVENT = 4
82EXTEND_PATH_EVENT = 5
83ZIP_EVENT = 6
84GENERATE_SIGNED_DATA_EVENT = 7 # sign build tools files to get hash_signed_data
85PARTITION_CHANGE_EVENT = 8
86DECOUPLED_EVENT = 9
87
88# Image file can not support update.
89FORBIDEN_UPDATE_IMAGE_SET = {"ptable"}
90
91# 1000000: max number of function recursion depth
92MAXIMUM_RECURSION_DEPTH = 1000000
93
94
95def singleton(cls):
96    _instance = {}
97
98    def _singleton(*args, **kargs):
99        if cls not in _instance:
100            _instance[cls] = cls(*args, **kargs)
101        return _instance[cls]
102
103    return _singleton
104
105
106class ExtInit:
107    """
108    Init event for ext
109    """
110
111    def __init__(self):
112        self.funs = []
113
114    def reg_event(self, evevt_id, funs):
115        self.funs.append([evevt_id, funs])
116        UPDATE_LOGGER.print_log(
117            'register event %s: %s' % (evevt_id, funs.__name__))
118
119    def invoke_event(self, evevt_id):
120        UPDATE_LOGGER.print_log(self.funs)
121        for event in self.funs:
122            funs = event[1]
123            if event[0] == evevt_id and funs is not None:
124                UPDATE_LOGGER.print_log(
125                    'invoke event %s: %s' % (evevt_id, funs.__name__))
126                return funs
127        return False
128
129
130class BaseOptionsManager:
131    def __init__(self):
132        # Entry parameters
133        self.source_package = None
134        self.target_package = None
135        self.update_package = None
136        self.unpack_package_path = None
137        self.no_zip = False
138        self.partition_file = None
139        self.signing_algorithm = None
140        self.hash_algorithm = None
141        self.private_key = None
142        self.not_l2 = False
143        self.signing_length = 256
144        self.xml_path = None
145        self.sd_card = False
146        self.stream_update = False
147        self.chunk_limit = 11       # chunk size 11 * 4096 = 44KB
148        self.ab_partition_update = False
149
150        self.make_dir_path = None
151
152
153@singleton
154class OptionsManager(BaseOptionsManager):
155    """
156    Options management class
157    """
158
159    def __init__(self):
160        super().__init__()
161
162        self.init = ExtInit()
163        self.parser = argparse.ArgumentParser()
164
165        # Own parameters
166        self.product = None
167
168
169        # Parsed package parameters
170        self.target_package_dir = None
171        self.target_package_config_dir = None
172        self.target_package_temp_obj = None
173        self.misc_info_dict = {}
174        self.version_mbn_file_path = None
175        self.version_mbn_content = None
176        self.board_list_file_path = None
177        self.board_list_content = None
178
179        self.source_package_dir = None
180        self.source_package_temp_obj = None
181
182        # XML parsing parameters
183        self.head_info_list = []
184        self.component_info_dict = {}
185        self.full_img_list = []
186        self.full_img_name_list = []
187        self.incremental_img_list = []
188        self.incremental_img_name_list = []
189        self.target_package_version = None
190        self.source_package_version = None
191        self.full_image_path_list = []
192
193        self.partition_file_obj = None
194
195        # Full processing parameters
196        self.full_image_content_len_list = []
197        self.full_image_file_obj_list = []
198        # 全量流式升级
199        self.full_image_new_data = {}
200        self.full_chunk = {}
201        self.full_block_sets = {}
202        # 存放所有chunk
203        self.full_image_chunk_list = []
204
205        # Incremental processing parameters
206        self.incremental_content_len_list = []
207        self.incremental_image_file_obj_dict = {}
208        self.incremental_block_file_obj_dict = {}
209        self.incremental_temp_file_obj_list = []
210        self.max_stash_size = 0
211
212        # 差分流式升级
213        # 定义一个transfer_list来存放image.transfer.list内容
214        self.image_transfer_dict_contents = {}
215        self.image_patch_dic = {}
216        self.image_new_dic = {}
217        self.diff_image_new_data = {}
218        # 差分流式本地升级
219        self.zip_offset = 0
220
221        # 存放镜像所有数据,以blcok为单位
222        self.all_blocks_data = {}
223        self.len_block = 0
224
225        # no map 文件
226        self.image_chunk = {}
227        self.image_block_sets = {}
228        self.no_map_file_list = []
229        self.no_map_image_exist = False
230
231        # Script parameters
232        self.opera_script_file_name_dict = {}
233        for each in SCRIPT_KEY_LIST:
234            self.opera_script_file_name_dict[each] = []
235        self.total_script_file_obj = None
236
237        self.register_script_file_obj = None
238
239        # Update package parameters
240        self.update_bin_obj = None
241        self.build_tools_zip_obj = None
242        self.update_package_file_path = None
243        self.signed_package = None
244
245OPTIONS_MANAGER = OptionsManager()
246
247
248def unzip_package(package_path, origin='target'):
249    """
250    Decompress the zip package.
251    :param package_path: zip package path
252    :param origin: package origin, which indicates
253                whether the zip package is a source package or target package
254    :return: Temporary directory (tmp_dir) and zip_data package;
255            false if an exception occurs.
256    """
257    try:
258        tmp_dir_obj = tempfile.TemporaryDirectory(prefix="%sfiles-" % origin)
259        tmp_dir = tmp_dir_obj.name
260
261        zf_obj = zipfile.ZipFile(package_path)
262        for name in zf_obj.namelist():
263            if name.endswith('/'):
264                os.mkdir(os.path.join(tmp_dir, name))
265            else:
266                ext_filename = os.path.join(
267                    tmp_dir, name)
268                fd = os.open(ext_filename, os.O_RDWR | os.O_CREAT, 0o755)
269                with os.fdopen(fd, "wb") as f_w:
270                    f_w.write(zf_obj.read(name))
271    except OSError:
272        UPDATE_LOGGER.print_log(
273            "Unzip package failed! path: %s" % package_path,
274            log_type=UPDATE_LOGGER.ERROR_LOG)
275        return False, False
276    tmp_dir_list = os.listdir(tmp_dir)
277    if len(tmp_dir_list) == 1:
278        unzip_dir = os.path.join(tmp_dir, tmp_dir_list[0])
279        if UPDATER_CONFIG not in \
280                os.listdir(unzip_dir):
281            UPDATE_LOGGER.print_log(
282                'Unsupported zip package structure!', UPDATE_LOGGER.ERROR_LOG)
283            return False, False
284    elif UPDATER_CONFIG in tmp_dir_list:
285        unzip_dir = tmp_dir
286    else:
287        UPDATE_LOGGER.print_log(
288            'Unsupported zip package structure!', UPDATE_LOGGER.ERROR_LOG)
289        return False, False
290    UPDATE_LOGGER.print_log(
291        '%s package unzip complete! path: %s' % (origin.title(), unzip_dir))
292
293    return tmp_dir_obj, unzip_dir
294
295
296def split_img_name(image_path):
297    """
298    Split the image name by image path
299    :return image name
300    """
301    tmp_path = image_path
302    str_list = tmp_path.split("/")
303
304    return str_list[-1]
305
306
307def get_update_config_softversion(mbn_dir, head_info_dict):
308    soft_version_file = head_info_dict.get('softVersionFile')
309    if soft_version_file is not None:
310        mbn_path = os.path.join(mbn_dir, soft_version_file)
311        if os.path.exists(mbn_path):
312            with open(mbn_path, 'r') as mbn_file:
313                head_info_dict['info']["@softVersion"] = mbn_file.read()
314
315
316def parse_update_config(xml_path):
317    """
318    Parse the XML configuration file.
319    :param xml_path: XML configuration file path
320    :return head_info_dict: header information dict of the update package
321            component_info_dict: component information dict
322            full_img_list: full image list
323            incremental_img_list: incremental image list
324    """
325    if os.path.exists(xml_path):
326        with open(xml_path, 'r') as xml_file:
327            xml_str = xml_file.read()
328    else:
329        UPDATE_LOGGER.print_log("XML file does not exist! xml path: %s" % xml_path, UPDATE_LOGGER.ERROR_LOG)
330        ret_params = [False, False, False, False, False, False, False]
331        return ret_params
332    xml_content_dict = xmltodict.parse(xml_str, encoding='utf-8')
333    package_dict = xml_content_dict.get('package', {})
334    get_update_config_softversion(OPTIONS_MANAGER.target_package_dir, package_dict.get('head', {}))
335    head_dict = package_dict.get('head', {}).get('info')
336    package_version = head_dict.get("@softVersion")
337    # component
338    component_info = package_dict.get('group', {}).get('component')
339    head_list = list(head_dict.values())
340    head_list.pop()
341    whole_list = []
342    difference_list = []
343    comp_dict = {}
344    full_image_path_list = []
345
346    if not OPTIONS_MANAGER.not_l2:
347        expand_component(comp_dict)
348    if isinstance(component_info, OrderedDict) or isinstance(component_info, dict):
349        component_info = [component_info]
350    if component_info is None:
351        ret_params = [[], {}, [], [], '', [], False]
352        return ret_params
353    for component in component_info:
354        if component['@compAddr'] == 'userdata' and not OPTIONS_MANAGER.sd_card:
355            continue
356        component_list = list(component.values())
357        component_list.pop()
358        comp_dict[component['@compAddr']] = component_list
359
360        if component['@compAddr'] in (whole_list + difference_list):
361            UPDATE_LOGGER.print_log("This component %s  repeats!" % component['@compAddr'], UPDATE_LOGGER.ERROR_LOG)
362            ret_params = [False, False, False, False, False, False, False]
363            return ret_params
364
365        if component['@compType'] == '0':
366            whole_list.append(component['@compAddr'])
367            OPTIONS_MANAGER.full_img_name_list.append(split_img_name(component['#text']))
368            tem_path = os.path.join(OPTIONS_MANAGER.target_package_dir, component.get("#text", None))
369            full_image_path_list.append(tem_path)
370            comp_dict[component['@compAddr']] = component_list
371        elif component['@compType'] == '1':
372            difference_list.append(component['@compAddr'])
373            OPTIONS_MANAGER.incremental_img_name_list.append(split_img_name(component['#text']))
374
375    ret_params = [head_list, comp_dict, whole_list, difference_list, package_version, full_image_path_list]
376    return ret_params
377
378
379def partitions_conversion(data):
380    """
381    Convert the start or length data in the partition table through
382    multiply 1024 * 1024 and return the data.
383    :param data: start or length data
384    :return :
385    """
386    if data == '0':
387        return 0
388    elif data.endswith('M'):
389        return int(data[0:-1]) * 1024 * 1024 // 512
390    else:
391        return False
392
393
394def parse_partition_file_xml(xml_path):
395    """
396    Parse the XML configuration file.
397    :param xml_path: XML configuration file path
398    :return part_json: partition table information in JSON format
399    """
400    if os.path.exists(xml_path):
401        with open(xml_path, 'r') as xml_file:
402            xml_str = xml_file.read()
403    else:
404        UPDATE_LOGGER.print_log("XML file does not exist! xml path: %s" %
405                                xml_path, UPDATE_LOGGER.ERROR_LOG)
406        return False, False, False
407    partitions_list = []
408    partitions_file_path_list = []
409    xml_content_dict = xmltodict.parse(xml_str, encoding='utf-8')
410    part_list = xml_content_dict['Partition_Info']['Part']
411    new_part_list = []
412    for i, part in enumerate(part_list):
413        start_value = partitions_conversion(part.get('@Start'))
414        length_value = partitions_conversion(part.get('@Length'))
415        if start_value is False or length_value is False:
416            UPDATE_LOGGER.print_log(
417                "Partition file parsing failed! part_name: %s, xml_path: %s" %
418                (part.get('@PartitionName'), xml_path),
419                UPDATE_LOGGER.ERROR_LOG)
420            return False, False, False
421
422        if part.get('@PartitionName') not in IGNORED_PARTITION_LIST:
423            partitions_list.append(part.get('@PartitionName'))
424            partitions_file_path_list.append(
425                os.path.join(OPTIONS_MANAGER.target_package_dir,
426                             "%s.img" % part.get('@PartitionName')))
427        part_dict = {'start': start_value,
428                     'length': length_value,
429                     'partName': part.get('@PartitionName'),
430                     'fsType': part.get('@FlashType')}
431        new_part_list.append(part_dict)
432    part_json = json.dumps(new_part_list)
433    part_json = '{"Partition": %s}' % part_json
434    file_obj = tempfile.NamedTemporaryFile(
435        dir=OPTIONS_MANAGER.target_package_dir, prefix="partition_file-", mode='wb')
436    file_obj.write(part_json.encode())
437    file_obj.seek(0)
438    return file_obj, partitions_list, partitions_file_path_list
439
440
441def get_extend_path_list():
442    get_config_list = OPTIONS_MANAGER.init.invoke_event(CONFIG_EVENT)
443    if get_config_list:
444        return get_config_list()
445    else:
446        return EXTEND_COMPONENT_LIST
447
448
449def expand_component(component_dict):
450    """
451    Append components such as VERSION.mbn and board list.
452    :param component_dict: component information dict
453    :return:
454    """
455    extend_path_list = get_extend_path_list()
456    if OPTIONS_MANAGER.partition_file is not None:
457        extend_component_list = \
458            extend_path_list + EXTEND_OPTIONAL_COMPONENT_LIST
459    else:
460        extend_component_list = extend_path_list
461    for each in extend_component_list:
462        tmp_info_list = copy(COMPONENT_INFO_INNIT)
463        tmp_info_list[0] = each
464        component_dict[each] = tmp_info_list
465
466
467def clear_options():
468    """
469    Clear OPTIONS_MANAGER.
470    """
471    OPTIONS_MANAGER.product = None
472
473    # Entry parameters
474    OPTIONS_MANAGER.source_package = None
475    OPTIONS_MANAGER.target_package = None
476    OPTIONS_MANAGER.update_package = None
477    OPTIONS_MANAGER.no_zip = False
478    OPTIONS_MANAGER.partition_file = None
479    OPTIONS_MANAGER.signing_algorithm = None
480    OPTIONS_MANAGER.hash_algorithm = None
481    OPTIONS_MANAGER.private_key = None
482    OPTIONS_MANAGER.not_l2 = False
483    OPTIONS_MANAGER.signing_length = 256
484    OPTIONS_MANAGER.xml_path = None
485    OPTIONS_MANAGER.sd_card = False
486
487    OPTIONS_MANAGER.stream_update = False
488    OPTIONS_MANAGER.chunk_limit = 11
489
490    OPTIONS_MANAGER.full_image_path_list = []
491
492    OPTIONS_MANAGER.make_dir_path = None
493
494    # Parsed package parameters
495    OPTIONS_MANAGER.target_package_dir = None
496    OPTIONS_MANAGER.target_package_config_dir = None
497    OPTIONS_MANAGER.target_package_temp_obj = None
498    OPTIONS_MANAGER.misc_info_dict = {}
499    OPTIONS_MANAGER.version_mbn_file_path = None
500    OPTIONS_MANAGER.version_mbn_content = None
501    OPTIONS_MANAGER.board_list_file_path = None
502    OPTIONS_MANAGER.board_list_content = None
503
504    OPTIONS_MANAGER.source_package_dir = None
505    OPTIONS_MANAGER.source_package_temp_obj = None
506
507    # XML parsing parameters
508    OPTIONS_MANAGER.head_info_list = []
509    OPTIONS_MANAGER.component_info_dict = {}
510    OPTIONS_MANAGER.full_img_list = []
511    OPTIONS_MANAGER.incremental_img_list = []
512    OPTIONS_MANAGER.target_package_version = None
513    OPTIONS_MANAGER.source_package_version = None
514    OPTIONS_MANAGER.partition_file_obj = None
515
516    # Global processing parameters
517    OPTIONS_MANAGER.full_image_content_len_list = []
518    OPTIONS_MANAGER.full_image_file_obj_list = []
519
520    # Incremental processing parameters
521    OPTIONS_MANAGER.incremental_content_len_list = []
522    OPTIONS_MANAGER.incremental_temp_file_obj_list = []
523
524    # Script parameters
525    OPTIONS_MANAGER.opera_script_file_name_dict = {}
526    for each in SCRIPT_KEY_LIST:
527        OPTIONS_MANAGER.opera_script_file_name_dict[each] = []
528    OPTIONS_MANAGER.total_script_file_obj = None
529
530    OPTIONS_MANAGER.register_script_file_obj = None
531
532    # Update package parameters
533    OPTIONS_MANAGER.update_bin_obj = None
534    OPTIONS_MANAGER.build_tools_zip_obj = None
535    OPTIONS_MANAGER.update_package_file_path = None
536
537
538def clear_resource(err_clear=False):
539    """
540    Clear resources, close temporary files, and clear temporary paths.
541    :param err_clear: whether to clear errors
542    :return:
543    """
544    target_package_temp_obj = OPTIONS_MANAGER.target_package_temp_obj
545    if target_package_temp_obj is not None:
546        target_package_temp_obj.cleanup()
547    source_package_temp_obj = OPTIONS_MANAGER.source_package_temp_obj
548    if source_package_temp_obj is not None:
549        source_package_temp_obj.cleanup()
550
551    partition_file_obj = OPTIONS_MANAGER.partition_file_obj
552    if partition_file_obj is not None:
553        partition_file_obj.close()
554
555    build_tools_zip_obj = OPTIONS_MANAGER.build_tools_zip_obj
556    if build_tools_zip_obj is not None:
557        build_tools_zip_obj.close()
558    update_bin_obj = OPTIONS_MANAGER.update_bin_obj
559    if update_bin_obj is not None:
560        update_bin_obj.close()
561    total_script_file_obj = OPTIONS_MANAGER.total_script_file_obj
562    if total_script_file_obj is not None:
563        total_script_file_obj.close()
564
565    register_script_file_obj = OPTIONS_MANAGER.register_script_file_obj
566    if register_script_file_obj is not None:
567        register_script_file_obj.close()
568
569    full_image_file_obj_list = OPTIONS_MANAGER.full_image_file_obj_list
570    if len(full_image_file_obj_list) != 0:
571        for each_full_obj in full_image_file_obj_list:
572            each_full_obj.close()
573
574    clear_file_obj(err_clear)
575    clear_options()
576
577
578def clear_file_obj(err_clear):
579    """
580    Clear resources and temporary file objects.
581    :param err_clear: whether to clear errors
582    :return:
583    """
584    incremental_temp_file_obj_list = \
585        OPTIONS_MANAGER.incremental_temp_file_obj_list
586    if len(incremental_temp_file_obj_list) != 0:
587        for each_incremental_temp_obj in incremental_temp_file_obj_list:
588            if each_incremental_temp_obj is not None:
589                each_incremental_temp_obj.close()
590    opera_script_file_name_dict = OPTIONS_MANAGER.opera_script_file_name_dict
591    for each_value in opera_script_file_name_dict.values():
592        for each in each_value:
593            each[1].close()
594    if err_clear:
595        make_dir_path = OPTIONS_MANAGER.make_dir_path
596        if make_dir_path is not None and os.path.exists(make_dir_path):
597            shutil.rmtree(make_dir_path)
598        update_package_file_path = OPTIONS_MANAGER.update_package_file_path
599        if update_package_file_path is not None and \
600                os.path.exists(update_package_file_path):
601            os.remove(update_package_file_path)
602        UPDATE_LOGGER.print_log(
603            'Exception occurred, Resource cleaning completed!')
604    else:
605        UPDATE_LOGGER.print_log('Resource cleaning completed!')
606
607
608def get_file_content(file_path, file_name=None):
609    """
610    Read the file content.
611    :param file_path: file path
612    :param file_name: file name
613    :return: file content
614    """
615    if not os.path.exists(file_path):
616        UPDATE_LOGGER.print_log(
617            "%s is not exist! path: %s" % (file_name, file_path),
618            log_type=UPDATE_LOGGER.ERROR_LOG)
619        return False
620    with open(file_path, 'r') as r_f:
621        file_content = r_f.read()
622    UPDATE_LOGGER.print_log(
623        "%s file parsing complete! path: %s" % (file_name, file_path))
624    return file_content
625
626
627def get_update_info():
628    """
629    Parse the configuration file to obtain the update information.
630    :return: update information if any; false otherwise.
631    """
632    if not OPTIONS_MANAGER.not_l2:
633        decouple_res = OPTIONS_MANAGER.init.invoke_event(DECOUPLED_EVENT)
634        OPTIONS_MANAGER.version_mbn_file_path = os.path.join(
635            OPTIONS_MANAGER.target_package_config_dir, VERSION_MBN_PATH)
636        version_mbn_content = \
637            get_file_content(
638                OPTIONS_MANAGER.version_mbn_file_path, os.path.basename(
639                    os.path.join(OPTIONS_MANAGER.target_package_config_dir,
640                                 VERSION_MBN_PATH)))
641        if version_mbn_content is False and decouple_res is False:
642            UPDATE_LOGGER.print_log(
643                "Get version mbn content failed!",
644                log_type=UPDATE_LOGGER.ERROR_LOG)
645            return False
646        OPTIONS_MANAGER.version_mbn_content = version_mbn_content
647        OPTIONS_MANAGER.board_list_file_path = os.path.join(
648            OPTIONS_MANAGER.target_package_config_dir, BOARD_LIST_PATH)
649        board_list_content = \
650            get_file_content(
651                OPTIONS_MANAGER.board_list_file_path, os.path.basename(
652                    os.path.join(OPTIONS_MANAGER.target_package_config_dir,
653                                 BOARD_LIST_PATH)))
654        if board_list_content is False:
655            UPDATE_LOGGER.print_log("Get board list content failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
656            return False
657        OPTIONS_MANAGER.board_list_content = board_list_content
658
659    if OPTIONS_MANAGER.xml_path is None:
660        xml_file_path = os.path.join(
661            OPTIONS_MANAGER.target_package_config_dir, XML_FILE_PATH)
662    else:
663        xml_file_path = OPTIONS_MANAGER.xml_path
664
665    # Parse the XML configuration file.
666    head_info_list, component_info_dict, \
667        full_img_list, incremental_img_list, \
668        OPTIONS_MANAGER.target_package_version, \
669        OPTIONS_MANAGER.full_image_path_list = \
670        parse_update_config(xml_file_path)
671    UPDATE_LOGGER.print_log("XML file parsing completed!")
672    if head_info_list is False or component_info_dict is False or \
673            full_img_list is False or incremental_img_list is False:
674        UPDATE_LOGGER.print_log("Get parse update config xml failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
675        return False
676    OPTIONS_MANAGER.head_info_list, OPTIONS_MANAGER.component_info_dict, \
677        OPTIONS_MANAGER.full_img_list, OPTIONS_MANAGER.incremental_img_list = \
678        head_info_list, component_info_dict, \
679        full_img_list, incremental_img_list
680    return True
681
682
683def sign_package():
684    return sign_ota_package(
685        OPTIONS_MANAGER.update_package_file_path,
686        OPTIONS_MANAGER.signed_package,
687        OPTIONS_MANAGER.private_key)