• 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.
16import binascii
17import copy
18import os
19import subprocess
20import tempfile
21import time
22import collections as collect
23import enum
24import ctypes
25import zipfile
26
27from log_exception import UPDATE_LOGGER
28from script_generator import create_script
29from utils import sign_package
30from utils import HASH_CONTENT_LEN_DICT
31from utils import OPTIONS_MANAGER
32from utils import REGISTER_SCRIPT_FILE_NAME
33from utils import ON_SERVER
34from utils import SCRIPT_KEY_LIST
35from utils import EXTEND_OPTIONAL_COMPONENT_LIST
36from utils import COMPONENT_INFO_INNIT
37from utils import UPDATE_EXE_FILE_NAME
38from utils import TOTAL_SCRIPT_FILE_NAME
39from utils import EXTEND_PATH_EVENT
40from utils import LINUX_HASH_ALGORITHM_DICT
41from utils import UPDATE_BIN_FILE_NAME
42from utils import BUILD_TOOLS_FILE_NAME
43from utils import SIGN_PACKAGE_EVENT
44from utils import CHECK_BINARY_EVENT
45from utils import ZIP_EVENT
46from utils import GENERATE_SIGNED_DATA_EVENT
47from utils import DECOUPLED_EVENT
48from utils import get_extend_path_list
49from create_update_package import CreatePackage
50from create_update_package import SIGN_ALGO_RSA
51from create_update_package import SIGN_ALGO_PSS
52from create_signed_data import generate_signed_data_default
53
54IS_DEL = 0
55SIGNING_LENGTH_256 = 256
56DIGEST_LEN = 32
57HASH_VALUE_MAX_LEN = 128
58
59
60class SignMethod(enum.Enum):
61    RSA = 1
62    ECC = 2
63
64
65class PkgHeader(ctypes.Structure):
66    _fields_ = [("digest_method", ctypes.c_ubyte),
67                ("sign_method", ctypes.c_ubyte),
68                ("pkg_type", ctypes.c_ubyte),
69                ("pkg_flags", ctypes.c_ubyte),
70                ("entry_count", ctypes.c_int),
71                ("update_file_version", ctypes.c_int),
72                ("product_update_id", ctypes.c_char_p),
73                ("software_version", ctypes.c_char_p),
74                ("date", ctypes.c_char_p),
75                ("time", ctypes.c_char_p),
76                ("describe_package_id", ctypes.c_char_p)]
77
78
79class PkgComponent(ctypes.Structure):
80    _fields_ = [("digest", ctypes.c_ubyte * DIGEST_LEN),
81                ("file_path", ctypes.c_char_p),
82                ("component_addr", ctypes.c_char_p),
83                ("version", ctypes.c_char_p),
84                ("size", ctypes.c_int),
85                ("id", ctypes.c_int),
86                ("original_size", ctypes.c_int),
87                ("res_type", ctypes.c_ubyte),
88                ("type", ctypes.c_ubyte),
89                ("flags", ctypes.c_ubyte)]
90
91
92class SignInfo(ctypes.Structure):
93    _fields_ = [("sign_offset", ctypes.c_int),
94                ("hash_len", ctypes.c_int),
95                ("hash_code", ctypes.c_ubyte * (HASH_VALUE_MAX_LEN + 1))]
96
97
98def create_update_bin():
99    """
100    Call the interface to generate the update.bin file.
101    :return update_bin_obj: Update file object.
102                            If exception occurs, return False.
103    """
104    update_bin_obj = tempfile.NamedTemporaryFile(dir=OPTIONS_MANAGER.update_package, prefix="update_bin-")
105
106    head_value_list = OPTIONS_MANAGER.head_info_list
107    component_dict = OPTIONS_MANAGER.component_info_dict
108    full_image_file_obj_list = OPTIONS_MANAGER.full_image_file_obj_list
109    if OPTIONS_MANAGER.stream_update:
110        # List of chunks stored in full streaming update
111        full_img_list = OPTIONS_MANAGER.full_image_chunk_list
112    else:
113        full_img_list = OPTIONS_MANAGER.full_img_list
114
115    extend_component_list = get_extend_path_list()
116    if not OPTIONS_MANAGER.not_l2:
117        if OPTIONS_MANAGER.partition_file_obj is not None:
118            all_image_name = \
119                extend_component_list + EXTEND_OPTIONAL_COMPONENT_LIST + full_img_list
120        else:
121            all_image_name = extend_component_list + full_img_list
122    else:
123        all_image_name = full_img_list
124    sort_component_dict = collect.OrderedDict()
125    for each_image_name in all_image_name:
126        sort_component_dict[each_image_name] = component_dict.get(each_image_name)
127    component_dict = copy.deepcopy(sort_component_dict)
128    head_list = get_head_list(len(component_dict), head_value_list)
129
130    component_list = get_component_list(
131        full_image_file_obj_list, component_dict)
132
133    save_patch = update_bin_obj.name.encode("utf-8")
134
135    if OPTIONS_MANAGER.private_key == ON_SERVER:
136        private_key = "./update_package.py"
137    else:
138        private_key = OPTIONS_MANAGER.private_key.encode("utf-8")
139
140    if OPTIONS_MANAGER.not_l2:
141        sign_algo = SIGN_ALGO_PSS
142    else:
143        sign_algo = SIGN_ALGO_RSA
144
145    # create bin
146    package = CreatePackage(head_list, component_list, save_patch, OPTIONS_MANAGER.private_key)
147    if not package.create_package():
148        UPDATE_LOGGER.print_log("Create update package .bin failed!", UPDATE_LOGGER.ERROR_LOG)
149        return False
150
151    UPDATE_LOGGER.print_log("Create update package .bin complete! path: %s" % update_bin_obj.name)
152    return update_bin_obj
153
154
155def get_component_list(all_image_file_obj_list, component_dict):
156    """
157    Get the list of component information according to
158    the component information structure.
159    :param all_image_file_obj_list: all image object file list
160    :param component_dict: Component information content dict
161    :return component_list: List of component information.
162                            If exception occurs, return False.
163    """
164    pkg_components = PkgComponent * len(component_dict)
165    component_list = pkg_components()
166    extend_list = get_extend_path_list()
167    if not OPTIONS_MANAGER.not_l2:
168        if OPTIONS_MANAGER.partition_file_obj is not None:
169            extend_component_list = extend_list + EXTEND_OPTIONAL_COMPONENT_LIST
170            extend_path_list = [OPTIONS_MANAGER.version_mbn_file_path,
171                                OPTIONS_MANAGER.board_list_file_path,
172                                OPTIONS_MANAGER.partition_file_obj.name]
173        else:
174            extend_component_list = extend_list
175            extend_path_list = [OPTIONS_MANAGER.version_mbn_file_path,
176                                OPTIONS_MANAGER.board_list_file_path]
177    else:
178        extend_component_list = []
179        extend_path_list = []
180    get_path_list = OPTIONS_MANAGER.init.invoke_event(EXTEND_PATH_EVENT)
181    if get_path_list:
182        extend_path_list = get_path_list()
183    idx = 0
184    for key, component in component_dict.items():
185        if idx < len(extend_component_list):
186            file_path = extend_path_list[idx]
187        else:
188            file_path = all_image_file_obj_list[idx - len(extend_component_list)].name
189        digest = get_hash_content(file_path, OPTIONS_MANAGER.hash_algorithm)
190        if not digest:
191            return
192        if component is None:
193            component = copy.copy(COMPONENT_INFO_INNIT)
194            component[0] = key
195        component_list[idx].digest = (ctypes.c_ubyte * 32).from_buffer_copy(
196            binascii.a2b_hex(digest.encode('utf-8')))
197        component_list[idx].file_path = file_path.encode("utf-8")
198        if not OPTIONS_MANAGER.not_l2:
199            component_list[idx].component_addr = ('/%s' % component[0]).encode("utf-8")
200        else:
201            component_list[idx].component_addr = ('%s' % component[0]).encode("utf-8")
202        component_list[idx].version = component[4].encode("utf-8")
203        component_list[idx].size = os.path.getsize(file_path)
204        component_list[idx].id = int(component[1])
205        if component[3] == 1:
206            component_list[idx].original_size = os.path.getsize(file_path)
207        else:
208            component_list[idx].original_size = 0
209        component_list[idx].res_type = int(component[2])
210        component_list[idx].type = int(component[3])
211        component_list[idx].flags = IS_DEL
212
213        idx += 1
214    return component_list
215
216
217def get_head_list(component_count, head_value_list):
218    """
219    According to the header structure, get the list of HEAD headers.
220    :param component_count: number of components
221    :param head_value_list: list of header values
222    :return head_list: header list
223    """
224    head_list = PkgHeader()
225    if OPTIONS_MANAGER.signing_length != SIGNING_LENGTH_256:
226        # PKG_DIGEST_TYPE_SHA384   3,use sha384
227        head_list.digest_method = 3
228    else:
229        # PKG_DIGEST_TYPE_SHA256   2,use sha256
230        head_list.digest_method = 2
231    if OPTIONS_MANAGER.private_key == ON_SERVER:
232        head_list.sign_method = 0
233    else:
234        if OPTIONS_MANAGER.signing_algorithm == "ECC":
235            # signing algorithm use ECC
236            head_list.sign_method = SignMethod.ECC.value
237        else:
238            # signing algorithm use RSA
239            head_list.sign_method = SignMethod.RSA.value
240    head_list.pkg_type = 1
241    if OPTIONS_MANAGER.not_l2:
242        head_list.pkg_flags = 1
243    else:
244        head_list.pkg_flags = 0
245    head_list.entry_count = component_count
246    head_list.update_file_version = int(head_value_list[0])
247    head_list.product_update_id = head_value_list[1].encode("utf-8")
248    head_list.software_version = head_value_list[2].encode("utf-8")
249    head_list.date = head_value_list[3].encode("utf-8")
250    head_list.time = head_value_list[4].encode("utf-8")
251    head_list.describe_package_id = ctypes.c_char_p("update/info.bin".encode())
252    return head_list
253
254
255def get_tools_component_list(count, opera_script_dict):
256    """
257    Get the list of component information according to
258    the component information structure.
259    :param count: number of components
260    :param opera_script_dict: script file name and path dict
261    :return component_list: list of component information.
262                            If exception occurs, return False.
263    """
264    pkg_components = PkgComponent * count
265    component_list = pkg_components()
266    component_value_list = list(opera_script_dict.keys())
267    component_num = 0
268    for i, component in enumerate(component_value_list):
269        component_list[i].file_path = component.encode("utf-8")
270        component_list[i].component_addr = \
271            (opera_script_dict[component]).encode("utf-8")
272        component_num += 1
273    return component_list, component_num
274
275
276def get_tools_head_list(component_count):
277    """
278    According to the header structure, get the list of HEAD headers.
279    :param component_count: number of components
280    :return head_list: header list
281    """
282    head_list = PkgHeader()
283    head_list.digest_method = 0
284    head_list.sign_method = 0
285    head_list.pkg_type = 2
286    head_list.pkg_flags = 0
287    head_list.entry_count = component_count
288    return head_list
289
290
291def get_signing_from_server(package_path, hash_algorithm, hash_code=None):
292    """
293    Server update package signature requires the vendor to
294    implement its own service signature interface, as shown below:
295    ip = ""
296    user_name = ""
297    pass_word = ""
298    signe_jar = ""
299    signing_config = [signe_jar, ip, user_name, pass_word,
300                      hash_code, hash_algorithm]
301    cmd = ' '.join(signing_config)
302    subprocess.Popen(
303        cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
304    :param package_path: update package file path
305    :param hash_algorithm: hash algorithm
306    :param hash_code: hash code
307    :return:
308    """
309    UPDATE_LOGGER.print_log("Signing %s, hash algorithm is: %s, "
310                            "Signing hash code: %s" %
311                            (package_path, hash_algorithm, hash_code))
312    signing_content = ""
313    return signing_content.encode()
314
315
316def create_build_tools_zip():
317    """
318    Create the update package file.
319    :param lib: lib object
320    :return:
321    """
322    opera_script_file_name_dict = OPTIONS_MANAGER.opera_script_file_name_dict
323    tmp_dict = {}
324    for each in SCRIPT_KEY_LIST:
325        tmp_dict[each] = []
326    if opera_script_file_name_dict == tmp_dict:
327        UPDATE_LOGGER.print_log(
328            "Script dict is null!",
329            log_type=UPDATE_LOGGER.ERROR_LOG)
330        return False
331    count = 0
332    opera_script_dict = {}
333    for each_value in opera_script_file_name_dict.values():
334        for each in each_value:
335            opera_script_dict[each[1].name] = each[0]
336            count += 1
337    # other_file_count --> 1(updater_binary) + 1(loadScript.us)
338    other_file_count = 2
339    count += other_file_count
340    if OPTIONS_MANAGER.register_script_file_obj is not None:
341        count += 1
342    head_list = get_tools_head_list(count)
343    component_list, num = get_tools_component_list(count, opera_script_dict)
344    total_script_file_obj = OPTIONS_MANAGER.total_script_file_obj
345    register_script_file_obj = OPTIONS_MANAGER.register_script_file_obj
346    update_exe_path = os.path.join(OPTIONS_MANAGER.target_package_dir, UPDATE_EXE_FILE_NAME)
347
348    file_obj = tempfile.NamedTemporaryFile(dir=OPTIONS_MANAGER.update_package, prefix="build_tools-")
349    files_to_sign = []
350    zip_file = zipfile.ZipFile(file_obj.name, 'w', zipfile.ZIP_DEFLATED)
351    # file name will be prefixed by build_tools in hash signed data
352    name_format_str = "build_tools/{}"
353    # add opera_script to build_tools.zip
354    for key, value in opera_script_dict.items():
355        zip_file.write(key, value)
356        files_to_sign += [(key, name_format_str.format(value))]
357    binary_check = OPTIONS_MANAGER.init.invoke_event(CHECK_BINARY_EVENT)
358    if callable(binary_check) is False or (callable(binary_check) and binary_check() is False):
359        if not os.path.exists(update_exe_path):
360            UPDATE_LOGGER.print_log("updater_binary file does not exist!path: %s" % update_exe_path,
361                log_type=UPDATE_LOGGER.ERROR_LOG)
362            return False
363        # add update_binary to build_tools.zip
364        zip_file.write(update_exe_path, UPDATE_EXE_FILE_NAME)
365        files_to_sign += [(update_exe_path, name_format_str.format(UPDATE_EXE_FILE_NAME))]
366
367    # add loadScript to build_tools.zip
368    zip_file.write(total_script_file_obj.name, TOTAL_SCRIPT_FILE_NAME)
369    files_to_sign += [(total_script_file_obj.name, name_format_str.format(TOTAL_SCRIPT_FILE_NAME))]
370    if OPTIONS_MANAGER.register_script_file_obj is not None:
371        zip_file.write(register_script_file_obj.name, REGISTER_SCRIPT_FILE_NAME)
372        files_to_sign += [(register_script_file_obj.name, name_format_str.format(REGISTER_SCRIPT_FILE_NAME))]
373
374    if create_hsd_for_build_tools(zip_file, files_to_sign) is False:
375        zip_file.close()
376        return False
377    zip_file.close()
378    return file_obj
379
380
381def do_sign_package(update_package, update_file_name):
382    signed_package = os.path.join(
383            update_package, "%s.zip" % update_file_name)
384    OPTIONS_MANAGER.signed_package = signed_package
385    if os.path.exists(signed_package):
386        os.remove(signed_package)
387
388    sign_ota_package = \
389        OPTIONS_MANAGER.init.invoke_event(SIGN_PACKAGE_EVENT)
390    if sign_ota_package:
391        return sign_ota_package()
392    else:
393        return sign_package()
394
395
396def get_update_file_name():
397    if OPTIONS_MANAGER.sd_card :
398        package_type = "sd"
399    elif OPTIONS_MANAGER.source_package :
400        package_type = "diff"
401    else :
402        package_type = "full"
403    if OPTIONS_MANAGER.not_l2:
404        update_file_name = ''.join(
405            ["updater_", OPTIONS_MANAGER.target_package_version.replace(" ", "_")])
406    else :
407        update_file_name = ''.join(
408            ["updater_", package_type])
409    return update_file_name
410
411
412def do_zip_update_package():
413    zip_file = zipfile.ZipFile(OPTIONS_MANAGER.update_package_file_path,
414                               'w', zipfile.ZIP_DEFLATED, allowZip64=True)
415    # add files to update package
416    do_add_files = OPTIONS_MANAGER.init.invoke_event(ZIP_EVENT)
417    if callable(do_add_files) and do_add_files(zip_file) is False:
418        UPDATE_LOGGER.print_log("add files fail", UPDATE_LOGGER.ERROR_LOG)
419        zip_file.close()
420        return False
421    # add update.bin to update package
422    if not OPTIONS_MANAGER.stream_update:
423        zip_file.write(OPTIONS_MANAGER.update_bin_obj.name, "update.bin")
424    # add build_tools.zip to update package
425    zip_file.write(OPTIONS_MANAGER.build_tools_zip_obj.name, BUILD_TOOLS_FILE_NAME)
426
427    zip_file.write(OPTIONS_MANAGER.board_list_file_path, "board_list")
428    decouple_res = OPTIONS_MANAGER.init.invoke_event(DECOUPLED_EVENT)
429    if decouple_res is False:
430        zip_file.write(OPTIONS_MANAGER.version_mbn_file_path, "version_list")
431
432    if OPTIONS_MANAGER.max_stash_size != 0:
433        max_stash_file_obj = tempfile.NamedTemporaryFile(mode="w+")
434        max_stash_file_obj.write(str(OPTIONS_MANAGER.max_stash_size))
435        max_stash_file_obj.flush()
436        zip_file.write(max_stash_file_obj.name, "all_max_stash")
437
438    for package_patch_zip in OPTIONS_MANAGER.incremental_block_file_obj_dict.values():
439        package_patch_zip.package_block_patch(zip_file)
440
441    for partition, patch_obj in OPTIONS_MANAGER.incremental_image_file_obj_dict.items():
442        zip_file.write(patch_obj.name, "%s.patch.dat" % partition)
443
444    zip_file.close()
445    return True
446
447
448def do_zip_update_bin_package():
449    zip_file = zipfile.ZipFile(OPTIONS_MANAGER.update_package_file_path,
450                               'w', zipfile.ZIP_DEFLATED, allowZip64=True)
451    # add files to update package
452    do_add_files = OPTIONS_MANAGER.init.invoke_event(ZIP_EVENT)
453    if callable(do_add_files) and do_add_files(zip_file) is False:
454        UPDATE_LOGGER.print_log("add files fail", UPDATE_LOGGER.ERROR_LOG)
455        zip_file.close()
456        return False
457    # add update.bin to update package
458    zip_file.write(OPTIONS_MANAGER.update_bin_obj.name, "update.bin")
459    # add build_tools.zip to update package
460    zip_file.write(OPTIONS_MANAGER.build_tools_zip_obj.name, BUILD_TOOLS_FILE_NAME)
461
462    zip_file.write(OPTIONS_MANAGER.board_list_file_path, "board_list")
463    decouple_res = OPTIONS_MANAGER.init.invoke_event(DECOUPLED_EVENT)
464    if decouple_res is False:
465        zip_file.write(OPTIONS_MANAGER.version_mbn_file_path, "version_list")
466
467    if OPTIONS_MANAGER.max_stash_size != 0:
468        max_stash_file_obj = tempfile.NamedTemporaryFile(mode="w+")
469        max_stash_file_obj.write(str(OPTIONS_MANAGER.max_stash_size))
470        max_stash_file_obj.flush()
471        zip_file.write(max_stash_file_obj.name, "all_max_stash")
472
473    for package_patch_zip in OPTIONS_MANAGER.incremental_block_file_obj_dict.values():
474        package_patch_zip.package_block_patch(zip_file)
475
476    for partition, patch_obj in OPTIONS_MANAGER.incremental_image_file_obj_dict.items():
477        zip_file.write(patch_obj.name, "%s.patch.dat" % partition)
478
479    zip_file.close()
480    return True
481
482
483def create_hsd_for_build_tools(zip_file, files_to_sign):
484    """
485    generate hash signed data for build_tools.zip
486    """
487    generate_signed_data_ext = OPTIONS_MANAGER.init.invoke_event(GENERATE_SIGNED_DATA_EVENT)
488    signed_data = ""
489    # add hash signed data to build_tools.zip
490    if generate_signed_data_ext is False:
491        signed_data = generate_signed_data_default(files_to_sign)
492    else:
493        signed_data = generate_signed_data_ext(files_to_sign)
494    if signed_data == "":
495        UPDATE_LOGGER.print_log("generate_signed_data failed", log_type=UPDATE_LOGGER.ERROR_LOG)
496        zip_file.close()
497        return False
498    zip_file.writestr("hash_signed_data", signed_data)
499    return True
500
501
502def build_update_package(no_zip, update_package, prelude_script,
503                         verse_script, refrain_script, ending_script):
504    """
505    Create the update package file.
506    :param no_zip: no zip
507    :param update_package: update package path
508    :param prelude_script: prelude object
509    :param verse_script: verse object
510    :param refrain_script: refrain object
511    :param ending_script: ending object
512    :return: If exception occurs, return False.
513    """
514    if not OPTIONS_MANAGER.stream_update:
515        update_bin_obj = create_update_bin()
516        if update_bin_obj:
517            OPTIONS_MANAGER.update_bin_obj = update_bin_obj
518        else:
519            return False
520
521    update_file_name = get_update_file_name()
522
523    if not no_zip:
524        update_package_path = os.path.join(
525            update_package, '%s_unsigned.zip' % update_file_name)
526        OPTIONS_MANAGER.update_package_file_path = update_package_path
527
528        create_script(prelude_script, verse_script,
529                      refrain_script, ending_script)
530
531        build_tools_zip_obj = create_build_tools_zip()
532        if build_tools_zip_obj is False:
533            UPDATE_LOGGER.print_log(
534                "Create build tools zip failed!",
535                log_type=UPDATE_LOGGER.ERROR_LOG)
536            return False
537        OPTIONS_MANAGER.build_tools_zip_obj = build_tools_zip_obj
538
539        if not do_zip_update_package():
540            UPDATE_LOGGER.print_log("Zip update package fail", UPDATE_LOGGER.ERROR_LOG)
541            return False
542
543        sign_result = do_sign_package(update_package, update_file_name)
544        if not sign_result:
545            UPDATE_LOGGER.print_log("Sign ota package fail", UPDATE_LOGGER.ERROR_LOG)
546            return False
547
548        # 生成update_bin文件,流式本地升级
549        if OPTIONS_MANAGER.stream_update:
550            update_bin_obj = create_update_bin()
551            if update_bin_obj:
552                OPTIONS_MANAGER.update_bin_obj = update_bin_obj
553            else:
554                return False
555
556            if not do_zip_update_bin_package():
557                UPDATE_LOGGER.print_log("Zip update package fail", UPDATE_LOGGER.ERROR_LOG)
558                return False
559
560            sign_result = do_sign_package(update_package, update_file_name)
561            if not sign_result:
562                UPDATE_LOGGER.print_log("Sign ota package fail", UPDATE_LOGGER.ERROR_LOG)
563                return False
564            UPDATE_LOGGER.print_log("create_update_bin successful %s" % update_package_path, UPDATE_LOGGER.INFO_LOG)
565
566        if os.path.exists(update_package_path):
567            os.remove(update_package_path)
568
569    else:
570        update_package_path = os.path.join(
571            update_package, '%s.bin' % update_file_name)
572        if os.path.exists(update_package_path):
573            os.remove(update_package_path)
574        OPTIONS_MANAGER.update_package_file_path = update_package_path
575        with open(OPTIONS_MANAGER.update_bin_obj.name, 'rb') as r_f:
576            content = r_f.read()
577        with open(update_package_path, 'wb') as w_f:
578            w_f.write(content)
579    return True
580
581
582def get_hash_content(file_path, hash_algorithm):
583    """
584    Use SHA256SUM to get the hash value of the file.
585    :param file_path : file path
586    :param hash_algorithm: hash algorithm
587    :return hash_content: hash value
588    """
589    try:
590        cmd = [LINUX_HASH_ALGORITHM_DICT[hash_algorithm], file_path]
591    except KeyError:
592        UPDATE_LOGGER.print_log(
593            "Unsupported hash algorithm! %s" % hash_algorithm,
594            log_type=UPDATE_LOGGER.ERROR_LOG)
595        return False
596    if not os.path.exists(file_path):
597        UPDATE_LOGGER.print_log(
598            "%s failed!" % LINUX_HASH_ALGORITHM_DICT[hash_algorithm],
599            UPDATE_LOGGER.ERROR_LOG)
600        raise RuntimeError
601    process_obj = subprocess.Popen(
602        cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
603    process_obj.wait()
604    hash_content = \
605        process_obj.stdout.read().decode(encoding='gbk').split(' ')[0]
606    if len(hash_content) != HASH_CONTENT_LEN_DICT.get(hash_algorithm):
607        UPDATE_LOGGER.print_log(
608            "Get hash content failed! The length of the hash_content is 0!",
609            UPDATE_LOGGER.ERROR_LOG)
610        raise RuntimeError
611    if process_obj.returncode == 0:
612        UPDATE_LOGGER.print_log(
613            "Get hash content success! path: %s" % file_path)
614    return hash_content
615