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 17""" 18The tool for making updater package. 19 20positional arguments: 21 target_package Target package file path. 22 update_package Update package file path. 23 24optional arguments: 25 -h, --help show this help message and exit 26 -s SOURCE_PACKAGE, --source_package SOURCE_PACKAGE 27 Source package file path. 28 -nz, --no_zip No zip mode, 29 which means to output the update package without zip. 30 -pf PARTITION_FILE, --partition_file PARTITION_FILE 31 Variable partition mode, Partition list file path. 32 -sa {ECC,RSA}, --signing_algorithm {ECC,RSA} 33 The signing algorithms 34 supported by the tool include ['ECC', 'RSA']. 35 -ha {sha256,sha384}, --hash_algorithm {sha256,sha384} 36 The hash algorithms 37 supported by the tool include ['sha256', 'sha384']. 38 -pk PRIVATE_KEY, --private_key PRIVATE_KEY 39 Private key file path. 40 -nl2, --not_l2 Not L2 mode, Distinguish between L1 and L2. 41 -sl {256,384}, --signing_length {256,384} 42 The signing content length 43 supported by the tool include ['256', '384']. 44 -xp, --xml_path XML file path. 45 -sc, --sd_card SD Card mode, Create update package for SD Card. 46""" 47import filecmp 48import os 49import sys 50import argparse 51import subprocess 52import tempfile 53import hashlib 54import xmltodict 55import patch_package_process 56 57from gigraph_process import GigraphProcess 58from image_class import FullUpdateImage 59from image_class import IncUpdateImage 60from transfers_manager import TransfersManager 61from log_exception import UPDATE_LOGGER 62from script_generator import PreludeScript 63from script_generator import VerseScript 64from script_generator import RefrainScript 65from script_generator import EndingScript 66from update_package import build_update_package 67from unpack_updater_package import UnpackPackage 68from utils import OPTIONS_MANAGER 69from utils import UPDATER_CONFIG 70from utils import parse_partition_file_xml 71from utils import unzip_package 72from utils import clear_resource 73from utils import PRODUCT 74from utils import XML_FILE_PATH 75from utils import get_update_info 76from utils import SCRIPT_KEY_LIST 77from utils import PER_BLOCK_SIZE 78from utils import E2FSDROID_PATH 79from utils import MAXIMUM_RECURSION_DEPTH 80from utils import VERSE_SCRIPT_EVENT 81from utils import INC_IMAGE_EVENT 82from utils import DIFF_EXE_PATH 83from utils import get_update_config_softversion 84from vendor_script import create_vendor_script_class 85 86sys.setrecursionlimit(MAXIMUM_RECURSION_DEPTH) 87 88 89def type_check(arg): 90 """ 91 Argument check, which is used to check whether the specified arg is a file. 92 :param arg: the arg to check 93 :return: Check result, which is False if the arg is invalid. 94 """ 95 if arg is not None and not os.path.exists(arg): 96 UPDATE_LOGGER.print_log( 97 "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 98 return False 99 return arg 100 101 102def private_key_check(arg): 103 """ 104 Argument check, which is used to check whether 105 the specified arg is a private_key. 106 :param arg: The arg to check. 107 :return: Check result, which is False if the arg is invalid. 108 """ 109 if arg != "ON_SERVER" and not os.path.isfile(arg): 110 UPDATE_LOGGER.print_log( 111 "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 112 return False 113 return arg 114 115 116def check_update_package(arg): 117 """ 118 Argument check, which is used to check whether 119 the update package path exists. 120 :param arg: The arg to check. 121 :return: Check result 122 """ 123 make_dir_path = None 124 if os.path.exists(arg): 125 if os.path.isfile(arg): 126 UPDATE_LOGGER.print_log( 127 "Update package must be a dir path, not a file path. " 128 "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 129 return False 130 else: 131 try: 132 UPDATE_LOGGER.print_log( 133 "Update package path does not exist. The dir will be created!" 134 "path: %s" % arg, UPDATE_LOGGER.WARNING_LOG) 135 os.makedirs(arg) 136 make_dir_path = arg 137 except OSError: 138 UPDATE_LOGGER.print_log( 139 "Make update package path dir failed! " 140 "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 141 return False 142 if make_dir_path is not None: 143 OPTIONS_MANAGER.make_dir_path = make_dir_path 144 OPTIONS_MANAGER.update_package = arg 145 return arg 146 147 148def unpack_check(arg): 149 """ 150 Argument check, which is used to check whether 151 the update package path exists. 152 :param arg: The arg to check. 153 :return: Check result 154 """ 155 unpack_package = os.path.join(OPTIONS_MANAGER.update_package, arg) 156 if not os.path.isfile(unpack_package): 157 UPDATE_LOGGER.print_log( 158 "FileNotFoundError, path: %s" % unpack_package, UPDATE_LOGGER.ERROR_LOG) 159 OPTIONS_MANAGER.unpack_package_path = None 160 return False 161 OPTIONS_MANAGER.unpack_package_path = unpack_package 162 return arg 163 164 165def create_entrance_args(): 166 """ 167 Arguments for the tool to create an update package 168 :return source_package : source version package 169 target_package : target version package 170 update_package : update package output path 171 no_zip : whether to enable the update package zip function. 172 partition_file : partition table XML file 173 signing_algorithm : signature algorithm (ECC and RSA (default)) 174 private_key : path of the private key file 175 """ 176 parser = OPTIONS_MANAGER.parser 177 parser.description = "Tool for creating update package." 178 parser.add_argument("-unpack", "--unpack_package", type=unpack_check, 179 default=None, help="Unpack updater package.") 180 parser.add_argument("-s", "--source_package", type=type_check, 181 default=None, help="Source package file path.") 182 parser.add_argument("target_package", type=type_check, 183 help="Target package file path.") 184 parser.add_argument("update_package", type=check_update_package, 185 help="Update package file path.") 186 parser.add_argument("-nz", "--no_zip", action='store_true', 187 help="No zip mode, Output update package without zip.") 188 parser.add_argument("-pf", "--partition_file", default=None, 189 help="Variable partition mode, " 190 "Partition list file path.") 191 parser.add_argument("-sa", "--signing_algorithm", default='RSA', 192 choices=['ECC', 'RSA'], 193 help="The signing algorithm " 194 "supported by the tool include ['ECC', 'RSA'].") 195 parser.add_argument("-ha", "--hash_algorithm", default='sha256', 196 choices=['sha256', 'sha384'], 197 help="The hash algorithm " 198 "supported by the tool include " 199 "['sha256', 'sha384'].") 200 parser.add_argument("-pk", "--private_key", type=private_key_check, 201 default=None, help="Private key file path.") 202 parser.add_argument("-nl2", "--not_l2", action='store_true', 203 help="Not L2 mode, Distinguish between L1 and L2.") 204 parser.add_argument("-sl", "--signing_length", default='256', 205 choices=['256', '384'], 206 help="The signing content length " 207 "supported by the tool include " 208 "['256', '384'].") 209 parser.add_argument("-xp", "--xml_path", type=private_key_check, 210 default=None, help="XML file path.") 211 parser.add_argument("-sc", "--sd_card", action='store_true', 212 help="SD Card mode, " 213 "Create update package for SD Card.") 214 215 216def parse_args(): 217 args = OPTIONS_MANAGER.parser.parse_args() 218 OPTIONS_MANAGER.source_package = args.source_package 219 OPTIONS_MANAGER.target_package = args.target_package 220 OPTIONS_MANAGER.update_package = args.update_package 221 OPTIONS_MANAGER.no_zip = args.no_zip 222 OPTIONS_MANAGER.partition_file = args.partition_file 223 OPTIONS_MANAGER.signing_algorithm = args.signing_algorithm 224 OPTIONS_MANAGER.hash_algorithm = args.hash_algorithm 225 OPTIONS_MANAGER.private_key = args.private_key 226 OPTIONS_MANAGER.not_l2 = args.not_l2 227 OPTIONS_MANAGER.signing_length = int(args.signing_length) 228 OPTIONS_MANAGER.xml_path = args.xml_path 229 OPTIONS_MANAGER.sd_card = args.sd_card 230 231 232def get_args(): 233 ret_args = \ 234 [OPTIONS_MANAGER.source_package, 235 OPTIONS_MANAGER.target_package, 236 OPTIONS_MANAGER.update_package, 237 OPTIONS_MANAGER.no_zip, 238 OPTIONS_MANAGER.not_l2, 239 OPTIONS_MANAGER.partition_file, 240 OPTIONS_MANAGER.signing_algorithm, 241 OPTIONS_MANAGER.hash_algorithm, 242 OPTIONS_MANAGER.private_key] 243 return ret_args 244 245 246def get_script_obj(): 247 """ 248 Obtain Opera script object 249 :return: 250 """ 251 script_obj_list = create_vendor_script_class() 252 if script_obj_list == [None] * len(SCRIPT_KEY_LIST): 253 prelude_script = PreludeScript() 254 verse_script = VerseScript() 255 refrain_script = RefrainScript() 256 ending_script = EndingScript() 257 258 generate_verse_script = \ 259 OPTIONS_MANAGER.init.invoke_event(VERSE_SCRIPT_EVENT) 260 if generate_verse_script: 261 verse_script = generate_verse_script() 262 else: 263 UPDATE_LOGGER.print_log( 264 "Get vendor extension object completed!" 265 "The vendor extension script will be generated.") 266 prelude_script = script_obj_list[0] 267 verse_script = script_obj_list[1] 268 refrain_script = script_obj_list[2] 269 ending_script = script_obj_list[3] 270 return prelude_script, verse_script, refrain_script, ending_script 271 272 273def get_source_package_path(source_package): 274 """ 275 get_source_package_path. 276 :param source_package: source package path 277 :return: 278 """ 279 if os.path.isdir(source_package): 280 OPTIONS_MANAGER.source_package_dir = source_package 281 elif source_package.endswith('.zip'): 282 # Decompress the source package. 283 tmp_dir_obj, unzip_dir = unzip_package(source_package) 284 if tmp_dir_obj is False or unzip_dir is False: 285 clear_resource(err_clear=True) 286 return False 287 OPTIONS_MANAGER.source_package_dir = unzip_dir 288 OPTIONS_MANAGER.source_package_temp_obj = tmp_dir_obj 289 else: 290 UPDATE_LOGGER.print_log("Input Update Package type exception!" 291 "path: %s" % source_package, UPDATE_LOGGER.ERROR_LOG) 292 clear_resource(err_clear=True) 293 return False 294 return True 295 296 297def check_incremental_args(no_zip, partition_file, source_package, 298 incremental_img_list): 299 """ 300 When the incremental list is not empty, incremental processing is required. 301 In this case, check related arguments. 302 :param no_zip: no zip mode 303 :param partition_file: 304 :param source_package: 305 :param incremental_img_list: 306 :return: 307 """ 308 if "boot" in incremental_img_list: 309 UPDATE_LOGGER.print_log( 310 "boot cannot be incrementally processed!", 311 UPDATE_LOGGER.ERROR_LOG) 312 clear_resource(err_clear=True) 313 return False 314 if source_package is None: 315 UPDATE_LOGGER.print_log( 316 "The source package is missing, " 317 "cannot be incrementally processed!", 318 UPDATE_LOGGER.ERROR_LOG) 319 clear_resource(err_clear=True) 320 return False 321 if no_zip: 322 UPDATE_LOGGER.print_log( 323 "No ZIP mode, cannot be incrementally processed!", 324 UPDATE_LOGGER.ERROR_LOG) 325 clear_resource(err_clear=True) 326 return False 327 if partition_file is not None: 328 UPDATE_LOGGER.print_log( 329 "Partition file is not None, " 330 "cannot be incrementally processed!", 331 UPDATE_LOGGER.ERROR_LOG) 332 clear_resource(err_clear=True) 333 return False 334 335 if not get_source_package_path(source_package): 336 return False 337 xml_path = '' 338 if OPTIONS_MANAGER.source_package_dir is not False: 339 xml_path = os.path.join(OPTIONS_MANAGER.source_package_dir, 340 UPDATER_CONFIG, XML_FILE_PATH) 341 if OPTIONS_MANAGER.source_package_dir is False: 342 OPTIONS_MANAGER.source_package_temp_obj = None 343 OPTIONS_MANAGER.source_package_dir = None 344 if os.path.exists(xml_path): 345 with open(xml_path, 'r') as xml_file: 346 xml_str = xml_file.read() 347 else: 348 UPDATE_LOGGER.print_log("XML file does not exist! xml path: %s" % 349 xml_path, UPDATE_LOGGER.ERROR_LOG) 350 return False 351 xml_content_dict = xmltodict.parse(xml_str, encoding='utf-8') 352 package_dict = xml_content_dict.get('package', {}) 353 get_update_config_softversion(OPTIONS_MANAGER.source_package_dir, package_dict.get('head', {})) 354 head_dict = package_dict.get('head', {}).get('info') 355 OPTIONS_MANAGER.source_package_version = head_dict.get("@softVersion") 356 if check_package_version(OPTIONS_MANAGER.target_package_version, 357 OPTIONS_MANAGER.source_package_version) is False: 358 clear_resource(err_clear=True) 359 return False 360 return True 361 362 363def check_userdata_image(): 364 """ 365 Check the userdata image. Updating this image is prohibited. 366 :return: 367 """ 368 if 'userdata' in OPTIONS_MANAGER.full_img_list or \ 369 'userdata' in OPTIONS_MANAGER.incremental_img_list: 370 UPDATE_LOGGER.print_log( 371 "userdata image does not participate in update!" 372 "Please check xml config, path: %s!" % 373 os.path.join(OPTIONS_MANAGER.target_package_config_dir, 374 XML_FILE_PATH), 375 UPDATE_LOGGER.ERROR_LOG) 376 clear_resource(err_clear=True) 377 return False 378 return True 379 380 381def check_images_list(): 382 """ 383 Check full_img_list and incremental_img_list. 384 If their lengths are 0, an error will be logged. 385 :return: 386 """ 387 if len(OPTIONS_MANAGER.full_img_list) == 0 and \ 388 len(OPTIONS_MANAGER.incremental_img_list) == 0: 389 UPDATE_LOGGER.print_log( 390 "The image list is empty!" 391 "Please check xml config, path: %s!" % 392 os.path.join(OPTIONS_MANAGER.target_package_config_dir, 393 XML_FILE_PATH), 394 UPDATE_LOGGER.ERROR_LOG) 395 clear_resource(err_clear=True) 396 return False 397 return True 398 399 400def check_target_package_path(target_package): 401 """ 402 Check the target_package path. 403 :param target_package: target package path 404 :return: 405 """ 406 if os.path.isdir(target_package): 407 OPTIONS_MANAGER.target_package_dir = target_package 408 temp_dir_list = os.listdir(target_package) 409 if UPDATER_CONFIG in temp_dir_list: 410 OPTIONS_MANAGER.target_package_config_dir = \ 411 os.path.join(target_package, UPDATER_CONFIG) 412 else: 413 UPDATE_LOGGER.print_log( 414 "Exception's target package path! path: %s" % 415 target_package, UPDATE_LOGGER.ERROR_LOG) 416 return False 417 elif target_package.endswith('.zip'): 418 # Decompress the target package. 419 tmp_dir_obj, unzip_dir = unzip_package(target_package) 420 if tmp_dir_obj is False or unzip_dir is False: 421 clear_resource(err_clear=True) 422 return False 423 OPTIONS_MANAGER.target_package_dir = unzip_dir 424 OPTIONS_MANAGER.target_package_temp_obj = tmp_dir_obj 425 OPTIONS_MANAGER.target_package_config_dir = \ 426 os.path.join(unzip_dir, UPDATER_CONFIG) 427 else: 428 UPDATE_LOGGER.print_log( 429 "Input Update Package type exception! path: %s" % 430 target_package, UPDATE_LOGGER.ERROR_LOG) 431 clear_resource(err_clear=True) 432 return False 433 return True 434 435 436def check_miss_private_key(private_key): 437 """ 438 Check private key. 439 :param private_key: 440 :return: 441 """ 442 if private_key is None: 443 UPDATE_LOGGER.print_log( 444 "Private key is None, update package cannot be signed! " 445 "Please specify the signature private key by -pk.", 446 UPDATE_LOGGER.ERROR_LOG) 447 clear_resource(err_clear=True) 448 return False 449 return True 450 451 452def check_package_version(target_ver, source_ver): 453 """ 454 target_ver: target version 455 source_ver: source version 456 return: 457 """ 458 try: 459 target_num = ''.join(target_ver.split(' ')[-1].replace('.', '')) 460 source_num = ''.join(source_ver.split(' ')[-1].replace('.', '')) 461 if int(target_num) <= int(source_num): 462 UPDATE_LOGGER.print_log( 463 'Target package version %s <= Source package version!' 464 'Unable to make updater package!', 465 UPDATE_LOGGER.ERROR_LOG) 466 return False 467 except ValueError: 468 UPDATE_LOGGER.print_log('your package version number is not compliant.' 469 'Please check your package version number!', 470 UPDATE_LOGGER.ERROR_LOG) 471 return False 472 return True 473 474 475def generate_image_map_file(image_path, map_path, image_name): 476 """ 477 :param image_path: image path 478 :param map_path: image map file path 479 :param image_name: image name 480 :return: 481 """ 482 if not os.path.exists(image_path): 483 UPDATE_LOGGER.print_log("The source %s.img file is missing from the" 484 "source package, cannot be incrementally processed. ", 485 image_name, UPDATE_LOGGER.ERROR_LOG) 486 return False 487 488 cmd = \ 489 [E2FSDROID_PATH, "-B", map_path, "-a", "/%s" % image_name, image_path, "-e"] 490 491 sub_p = subprocess.Popen( 492 cmd, shell=False, stdout=subprocess.PIPE, 493 stderr=subprocess.STDOUT) 494 sub_p.wait() 495 496 if not os.path.exists(map_path): 497 UPDATE_LOGGER.print_log("%s generate image map file failed." 498 % image_path) 499 return False 500 return True 501 502 503def get_file_sha256(update_package): 504 sha256obj = hashlib.sha256() 505 maxbuf = 8192 506 with open(update_package, 'rb') as package_file: 507 while True: 508 buf = package_file.read(maxbuf) 509 if not buf: 510 break 511 sha256obj.update(buf) 512 hash_value = sha256obj.hexdigest() 513 return str(hash_value).upper() 514 515 516def write_image_patch_script(partition, src_image_path, tgt_image_path, 517 script_check_cmd_list, script_write_cmd_list, verse_script): 518 """ 519 Add command content to the script. 520 :param partition: image name 521 :param script_check_cmd_list: incremental check command list 522 :param script_write_cmd_list: incremental write command list 523 :param verse_script: verse script object 524 :return: 525 """ 526 src_sha = get_file_sha256(src_image_path) 527 src_size = os.path.getsize(src_image_path) 528 tgt_sha = get_file_sha256(tgt_image_path) 529 tgt_size = os.path.getsize(tgt_image_path) 530 531 sha_check_cmd = verse_script.image_sha_check(partition, 532 src_size, src_sha, tgt_size, tgt_sha) 533 534 first_block_check_cmd = verse_script.first_block_check(partition) 535 536 abort_cmd = verse_script.abort(partition) 537 538 cmd = 'if ({sha_check_cmd} != 0)' \ 539 '{{\n {abort_cmd}}}\n'.format( 540 sha_check_cmd=sha_check_cmd, 541 abort_cmd=abort_cmd) 542 543 script_check_cmd_list.append(cmd) 544 545 image_patch_cmd = verse_script.image_patch(partition, os.path.getsize(src_image_path), 546 get_file_sha256(src_image_path), os.path.getsize(tgt_image_path), 547 get_file_sha256(tgt_image_path)) 548 549 cmd = '%s_WRITE_FLAG%s' % (partition, image_patch_cmd) 550 script_write_cmd_list.append(cmd) 551 return True 552 553 554def increment_image_diff_processing( 555 partition, src_image_path, tgt_image_path, 556 script_check_cmd_list, script_write_cmd_list, verse_script): 557 """ 558 Incremental image processing 559 :param verse_script: verse script 560 :param incremental_img_list: incremental image list 561 :param source_package_dir: source package path 562 :param target_package_dir: target package path 563 :return: 564 """ 565 patch_file_obj = tempfile.NamedTemporaryFile( 566 prefix="%s_patch.dat-" % partition, mode='wb') 567 OPTIONS_MANAGER.incremental_image_file_obj_dict[partition] = patch_file_obj 568 cmd = [DIFF_EXE_PATH] 569 570 cmd.extend(['-s', src_image_path, '-d', tgt_image_path, 571 '-p', patch_file_obj.name, '-l', '4096']) 572 sub_p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 573 stderr=subprocess.STDOUT) 574 output, _ = sub_p.communicate() 575 sub_p.wait() 576 if sub_p.returncode != 0: 577 raise ValueError(output) 578 return write_image_patch_script(partition, src_image_path, tgt_image_path, 579 script_check_cmd_list, script_write_cmd_list, verse_script) 580 581 582def increment_image_processing( 583 verse_script, incremental_img_list, source_package_dir, 584 target_package_dir): 585 """ 586 Incremental image processing 587 :param verse_script: verse script 588 :param incremental_img_list: incremental image list 589 :param source_package_dir: source package path 590 :param target_package_dir: target package path 591 :return: 592 """ 593 script_check_cmd_list = [] 594 script_write_cmd_list = [] 595 patch_process = None 596 block_diff = 0 597 for each_img_name in OPTIONS_MANAGER.incremental_img_name_list: 598 each_img = each_img_name[:-4] 599 each_src_image_path = \ 600 os.path.join(source_package_dir, 601 '%s.img' % each_img) 602 each_src_map_path = \ 603 os.path.join(source_package_dir, 604 '%s.map' % each_img) 605 each_tgt_image_path = \ 606 os.path.join(target_package_dir, 607 '%s.img' % each_img) 608 each_tgt_map_path = \ 609 os.path.join(target_package_dir, 610 '%s.map' % each_img) 611 612 check_make_map_path(each_img) 613 614 if filecmp.cmp(each_src_image_path, each_tgt_image_path): 615 UPDATE_LOGGER.print_log( 616 "Source Image is the same as Target Image!" 617 "src image path: %s, tgt image path: %s" % 618 (each_src_image_path, each_tgt_image_path), 619 UPDATE_LOGGER.INFO_LOG) 620 OPTIONS_MANAGER.incremental_img_list.remove(each_img) 621 first_block_check_cmd = verse_script.first_block_check(each_img) 622 abort_cmd = verse_script.abort(each_img) 623 cmd = 'if ({first_block_check_cmd} != 0)' '{{\n {abort_cmd}}}\n'.format( 624 first_block_check_cmd=first_block_check_cmd, abort_cmd=abort_cmd) 625 script_check_cmd_list.append(cmd) 626 continue 627 628 src_generate_map = True 629 tgt_generate_map = True 630 if not os.path.exists(each_src_map_path): 631 src_generate_map = generate_image_map_file(each_src_image_path, 632 each_src_map_path, each_img) 633 if not src_generate_map: 634 UPDATE_LOGGER.print_log("The source %s.img file" 635 "generate map file failed. " % each_img) 636 637 if not os.path.exists(each_tgt_map_path): 638 tgt_generate_map = generate_image_map_file(each_tgt_image_path, 639 each_tgt_map_path, each_img) 640 if not tgt_generate_map: 641 UPDATE_LOGGER.print_log("The target %s.img file" 642 "generate map file failed. " % each_img) 643 644 if not src_generate_map or not tgt_generate_map: 645 if increment_image_diff_processing(each_img, each_src_image_path, each_tgt_image_path, 646 script_check_cmd_list, script_write_cmd_list, verse_script) is True: 647 continue 648 UPDATE_LOGGER.print_log("increment_image_diff_processing %s failed" % each_img) 649 clear_resource(err_clear=True) 650 return False 651 652 block_diff += 1 653 src_image_class = \ 654 IncUpdateImage(each_src_image_path, each_src_map_path) 655 tgt_image_class = \ 656 IncUpdateImage(each_tgt_image_path, each_tgt_map_path) 657 OPTIONS_MANAGER.src_image = src_image_class 658 OPTIONS_MANAGER.tgt_image = tgt_image_class 659 660 inc_image = OPTIONS_MANAGER.init.invoke_event(INC_IMAGE_EVENT) 661 if inc_image: 662 src_image_class, tgt_image_class = inc_image() 663 664 transfers_manager = TransfersManager( 665 each_img, tgt_image_class, src_image_class) 666 transfers_manager.find_process_needs() 667 actions_list = transfers_manager.get_action_list() 668 669 graph_process = GigraphProcess(actions_list, src_image_class, 670 tgt_image_class) 671 actions_list = graph_process.actions_list 672 patch_process = \ 673 patch_package_process.PatchProcess( 674 each_img, tgt_image_class, src_image_class, actions_list) 675 patch_process.patch_process() 676 patch_process.write_script(each_img, script_check_cmd_list, 677 script_write_cmd_list, verse_script) 678 OPTIONS_MANAGER.incremental_block_file_obj_dict[each_img] = patch_process.package_patch_zip 679 680 if not check_patch_file(patch_process): 681 UPDATE_LOGGER.print_log( 682 'Verify the incremental result failed!', 683 UPDATE_LOGGER.ERROR_LOG) 684 raise RuntimeError 685 686 verse_script.add_command( 687 "\n# ---- start incremental check here ----\n") 688 for each_check_cmd in script_check_cmd_list: 689 verse_script.add_command(each_check_cmd) 690 verse_script.add_command( 691 "\n# ---- start incremental write here ----\n") 692 for each_write_cmd in script_write_cmd_list: 693 verse_script.add_command(each_write_cmd) 694 return True 695 696 697def check_patch_file(patch_process): 698 new_dat_file_obj, patch_dat_file_obj, transfer_list_file_obj = \ 699 patch_process.package_patch_zip.get_file_obj() 700 with open(transfer_list_file_obj.name) as f_t: 701 num = 0 702 diff_str = None 703 diff_num = 0 704 for line in f_t: 705 if line.startswith('new '): 706 each_line_list = \ 707 line.strip().replace("new ", "").split(",")[1:] 708 for idx in range(0, len(each_line_list), 2): 709 num += \ 710 int(each_line_list[idx + 1]) - int(each_line_list[idx]) 711 continue 712 if line.startswith('bsdiff ') or line.startswith('pkgdiff '): 713 diff_str = line 714 if diff_str: 715 diff_list = diff_str.split('\n')[0].split(' ') 716 diff_num = int(diff_list[1]) + int(diff_list[2]) 717 check_flag = \ 718 (os.path.getsize(new_dat_file_obj.name) == num * PER_BLOCK_SIZE) and \ 719 (os.path.getsize(patch_dat_file_obj.name) == diff_num) 720 return check_flag 721 722 723def check_make_map_path(each_img): 724 """ 725 If env does not exist, the command for map generation does not exist 726 in the environment variable, and False will be returned. 727 """ 728 try: 729 cmd = [E2FSDROID_PATH, " -h"] 730 subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, 731 stderr=subprocess.STDOUT) 732 except FileNotFoundError: 733 UPDATE_LOGGER.print_log( 734 "Command not found, need check the env! " 735 "Make %s.map failed!" % each_img, 736 UPDATE_LOGGER.ERROR_LOG) 737 clear_resource(err_clear=True) 738 raise RuntimeError 739 return True 740 741 742def incremental_processing(no_zip, partition_file, source_package, 743 verse_script): 744 """ 745 Incremental processing. 746 :param no_zip: no zip mode 747 :param partition_file: partition xml file path 748 :param source_package: source package path 749 :param verse_script: verse script obj 750 :return : processing result 751 """ 752 if len(OPTIONS_MANAGER.incremental_img_list) != 0: 753 if check_incremental_args(no_zip, partition_file, source_package, 754 OPTIONS_MANAGER.incremental_img_list) \ 755 is False: 756 return False 757 if increment_image_processing( 758 verse_script, OPTIONS_MANAGER.incremental_img_list, 759 OPTIONS_MANAGER.source_package_dir, 760 OPTIONS_MANAGER.target_package_dir) is False: 761 return False 762 else: 763 if source_package is not None: 764 UPDATE_LOGGER.print_log( 765 "There is no incremental image, " 766 "the - S parameter is not required!", 767 UPDATE_LOGGER.ERROR_LOG) 768 raise RuntimeError 769 770 771def check_args(private_key, source_package, target_package, update_package): 772 """ 773 Input args check. 774 :param private_key: private key path 775 :param source_package: source package path 776 :param target_package: target package path 777 :param update_package: output package path 778 :return : Judgment result 779 """ 780 if source_package is False or private_key is False or \ 781 target_package is False or update_package is False: 782 return False 783 if check_miss_private_key(private_key) is False: 784 return False 785 if check_target_package_path(target_package) is False: 786 return False 787 if get_update_info() is False: 788 return False 789 if check_images_list() is False: 790 return False 791 return True 792 793 794create_entrance_args() 795 796 797def main(): 798 """ 799 Entry function. 800 """ 801 parse_args() 802 803 OPTIONS_MANAGER.product = PRODUCT 804 805 source_package, target_package, update_package, no_zip, not_l2, \ 806 partition_file, signing_algorithm, hash_algorithm, private_key = \ 807 get_args() 808 if not_l2: 809 no_zip = True 810 811 # Unpack updater package 812 if OPTIONS_MANAGER.unpack_package_path: 813 package = UnpackPackage() 814 if not package.unpack_package(): 815 UPDATE_LOGGER.print_log( 816 "Unpack update package .bin failed!", UPDATE_LOGGER.ERROR_LOG) 817 clear_resource(err_clear=True) 818 return 819 UPDATE_LOGGER.print_log("Unpack update package .bin success!") 820 clear_resource() 821 return 822 823 if OPTIONS_MANAGER.sd_card: 824 if source_package is not None or \ 825 OPTIONS_MANAGER.xml_path is not None or \ 826 partition_file is not None: 827 UPDATE_LOGGER.print_log( 828 "SD Card updater, " 829 "the -S/-xp/-pf parameter is not required!", 830 UPDATE_LOGGER.ERROR_LOG) 831 raise RuntimeError 832 if check_args(private_key, source_package, 833 target_package, update_package) is False: 834 clear_resource(err_clear=True) 835 return 836 837 if not OPTIONS_MANAGER.sd_card: 838 if check_userdata_image() is False: 839 clear_resource(err_clear=True) 840 return 841 842 # Create a Script object. 843 prelude_script, verse_script, refrain_script, ending_script = \ 844 get_script_obj() 845 846 # Create partition. 847 if partition_file is not None: 848 verse_script.add_command("\n# ---- do updater partitions ----\n") 849 updater_partitions_cmd = verse_script.updater_partitions() 850 verse_script.add_command(updater_partitions_cmd) 851 852 partition_file_obj, partitions_list, partitions_file_path_list = \ 853 parse_partition_file_xml(partition_file) 854 if partition_file_obj is False: 855 clear_resource(err_clear=True) 856 return False 857 OPTIONS_MANAGER.partition_file_obj = partition_file_obj 858 OPTIONS_MANAGER.full_img_list = partitions_list 859 OPTIONS_MANAGER.full_image_path_list = partitions_file_path_list 860 861 if incremental_processing( 862 no_zip, partition_file, source_package, verse_script) is False: 863 clear_resource(err_clear=True) 864 return 865 866 # Full processing 867 if len(OPTIONS_MANAGER.full_img_list) != 0: 868 verse_script.add_command("\n# ---- full image ----\n") 869 full_update_image = \ 870 FullUpdateImage(OPTIONS_MANAGER.target_package_dir, 871 OPTIONS_MANAGER.full_img_list, 872 OPTIONS_MANAGER.full_img_name_list, 873 verse_script, OPTIONS_MANAGER.full_image_path_list, 874 no_zip=OPTIONS_MANAGER.no_zip) 875 full_image_content_len_list, full_image_file_obj_list = \ 876 full_update_image.update_full_image() 877 if full_image_content_len_list is False or \ 878 full_image_file_obj_list is False: 879 clear_resource(err_clear=True) 880 return 881 OPTIONS_MANAGER.full_image_content_len_list, \ 882 OPTIONS_MANAGER.full_image_file_obj_list = \ 883 full_image_content_len_list, full_image_file_obj_list 884 885 # Generate the update package. 886 build_re = build_update_package(no_zip, update_package, 887 prelude_script, verse_script, 888 refrain_script, ending_script) 889 if build_re is False: 890 clear_resource(err_clear=True) 891 return 892 # Clear resources. 893 clear_resource() 894 895 896if __name__ == '__main__': 897 main() 898