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_list.append( 568 patch_file_obj) 569 cmd = [DIFF_EXE_PATH] 570 571 cmd.extend(['-s', src_image_path, '-d', tgt_image_path, 572 '-p', patch_file_obj.name, '-l', '4096']) 573 sub_p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 574 stderr=subprocess.STDOUT) 575 try: 576 output, _ = sub_p.communicate(timeout=5) 577 except subprocess.TimeoutExpired: 578 sub_p.kill() 579 580 sub_p.wait() 581 if sub_p.returncode != 0: 582 raise ValueError(output) 583 return write_image_patch_script(partition, src_image_path, tgt_image_path, 584 script_check_cmd_list, script_write_cmd_list, verse_script) 585 586 587def increment_image_processing( 588 verse_script, incremental_img_list, source_package_dir, 589 target_package_dir): 590 """ 591 Incremental image processing 592 :param verse_script: verse script 593 :param incremental_img_list: incremental image list 594 :param source_package_dir: source package path 595 :param target_package_dir: target package path 596 :return: 597 """ 598 script_check_cmd_list = [] 599 script_write_cmd_list = [] 600 patch_process = None 601 block_diff = 0 602 for each_img_name in OPTIONS_MANAGER.incremental_img_name_list: 603 each_img = each_img_name[:-4] 604 each_src_image_path = \ 605 os.path.join(source_package_dir, 606 '%s.img' % each_img) 607 each_src_map_path = \ 608 os.path.join(source_package_dir, 609 '%s.map' % each_img) 610 each_tgt_image_path = \ 611 os.path.join(target_package_dir, 612 '%s.img' % each_img) 613 each_tgt_map_path = \ 614 os.path.join(target_package_dir, 615 '%s.map' % each_img) 616 617 check_make_map_path(each_img) 618 619 if filecmp.cmp(each_src_image_path, each_tgt_image_path): 620 UPDATE_LOGGER.print_log( 621 "Source Image is the same as Target Image!" 622 "src image path: %s, tgt image path: %s" % 623 (each_src_image_path, each_tgt_image_path), 624 UPDATE_LOGGER.INFO_LOG) 625 626 src_generate_map = True 627 tgt_generate_map = True 628 if not os.path.exists(each_src_map_path): 629 src_generate_map = generate_image_map_file(each_src_image_path, 630 each_src_map_path, each_img) 631 if not src_generate_map: 632 UPDATE_LOGGER.print_log("The source %s.img file" 633 "generate map file failed. " % each_img) 634 635 if not os.path.exists(each_tgt_map_path): 636 tgt_generate_map = generate_image_map_file(each_tgt_image_path, 637 each_tgt_map_path, each_img) 638 if not tgt_generate_map: 639 UPDATE_LOGGER.print_log("The target %s.img file" 640 "generate map file failed. " % each_img) 641 642 if not src_generate_map or not tgt_generate_map: 643 if increment_image_diff_processing(each_img, each_src_image_path, each_tgt_image_path, 644 script_check_cmd_list, script_write_cmd_list, verse_script) is True: 645 continue 646 UPDATE_LOGGER.print_log("increment_image_diff_processing %s failed" % each_img) 647 clear_resource(err_clear=True) 648 return False 649 650 block_diff += 1 651 src_image_class = \ 652 IncUpdateImage(each_src_image_path, each_src_map_path) 653 tgt_image_class = \ 654 IncUpdateImage(each_tgt_image_path, each_tgt_map_path) 655 OPTIONS_MANAGER.src_image = src_image_class 656 OPTIONS_MANAGER.tgt_image = tgt_image_class 657 658 inc_image = OPTIONS_MANAGER.init.invoke_event(INC_IMAGE_EVENT) 659 if inc_image: 660 src_image_class, tgt_image_class = inc_image() 661 662 transfers_manager = TransfersManager( 663 each_img, tgt_image_class, src_image_class) 664 transfers_manager.find_process_needs() 665 actions_list = transfers_manager.get_action_list() 666 667 graph_process = GigraphProcess(actions_list, src_image_class, 668 tgt_image_class) 669 actions_list = graph_process.actions_list 670 patch_process = \ 671 patch_package_process.PatchProcess( 672 each_img, tgt_image_class, src_image_class, actions_list) 673 patch_process.patch_process() 674 patch_process.package_patch_zip.package_patch_zip() 675 patch_process.write_script(each_img, script_check_cmd_list, 676 script_write_cmd_list, verse_script) 677 if block_diff > 0: 678 if not check_patch_file(patch_process): 679 UPDATE_LOGGER.print_log( 680 'Verify the incremental result failed!', 681 UPDATE_LOGGER.ERROR_LOG) 682 raise RuntimeError 683 UPDATE_LOGGER.print_log( 684 'Verify the incremental result successfully!', 685 UPDATE_LOGGER.INFO_LOG) 686 687 verse_script.add_command( 688 "\n# ---- start incremental check here ----\n") 689 for each_check_cmd in script_check_cmd_list: 690 verse_script.add_command(each_check_cmd) 691 verse_script.add_command( 692 "\n# ---- start incremental write here ----\n") 693 for each_write_cmd in script_write_cmd_list: 694 verse_script.add_command(each_write_cmd) 695 return True 696 697 698def check_patch_file(patch_process): 699 new_dat_file_obj, patch_dat_file_obj, transfer_list_file_obj = \ 700 patch_process.package_patch_zip.get_file_obj() 701 with open(transfer_list_file_obj.name) as f_t: 702 num = 0 703 diff_str = None 704 diff_num = 0 705 for line in f_t: 706 if line.startswith('new '): 707 each_line_list = \ 708 line.strip().replace("new ", "").split(",")[1:] 709 for idx in range(0, len(each_line_list), 2): 710 num += \ 711 int(each_line_list[idx + 1]) - int(each_line_list[idx]) 712 continue 713 if line.startswith('bsdiff ') or line.startswith('pkgdiff '): 714 diff_str = line 715 if diff_str: 716 diff_list = diff_str.split('\n')[0].split(' ') 717 diff_num = int(diff_list[1]) + int(diff_list[2]) 718 check_flag = \ 719 (os.path.getsize(new_dat_file_obj.name) == num * PER_BLOCK_SIZE) and \ 720 (os.path.getsize(patch_dat_file_obj.name) == diff_num) 721 return check_flag 722 723 724def check_make_map_path(each_img): 725 """ 726 If env does not exist, the command for map generation does not exist 727 in the environment variable, and False will be returned. 728 """ 729 try: 730 cmd = [E2FSDROID_PATH, " -h"] 731 subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, 732 stderr=subprocess.STDOUT) 733 except FileNotFoundError: 734 UPDATE_LOGGER.print_log( 735 "Command not found, need check the env! " 736 "Make %s.map failed!" % each_img, 737 UPDATE_LOGGER.ERROR_LOG) 738 clear_resource(err_clear=True) 739 raise RuntimeError 740 return True 741 742 743def incremental_processing(no_zip, partition_file, source_package, 744 verse_script): 745 """ 746 Incremental processing. 747 :param no_zip: no zip mode 748 :param partition_file: partition xml file path 749 :param source_package: source package path 750 :param verse_script: verse script obj 751 :return : processing result 752 """ 753 if len(OPTIONS_MANAGER.incremental_img_list) != 0: 754 if check_incremental_args(no_zip, partition_file, source_package, 755 OPTIONS_MANAGER.incremental_img_list) \ 756 is False: 757 return False 758 if increment_image_processing( 759 verse_script, OPTIONS_MANAGER.incremental_img_list, 760 OPTIONS_MANAGER.source_package_dir, 761 OPTIONS_MANAGER.target_package_dir) is False: 762 return False 763 else: 764 if source_package is not None: 765 UPDATE_LOGGER.print_log( 766 "There is no incremental image, " 767 "the - S parameter is not required!", 768 UPDATE_LOGGER.ERROR_LOG) 769 raise RuntimeError 770 771 772def check_args(private_key, source_package, target_package, update_package): 773 """ 774 Input args check. 775 :param private_key: private key path 776 :param source_package: source package path 777 :param target_package: target package path 778 :param update_package: output package path 779 :return : Judgment result 780 """ 781 if source_package is False or private_key is False or \ 782 target_package is False or update_package is False: 783 return False 784 if check_miss_private_key(private_key) is False: 785 return False 786 if check_target_package_path(target_package) is False: 787 return False 788 if get_update_info() is False: 789 return False 790 if check_images_list() is False: 791 return False 792 return True 793 794 795create_entrance_args() 796 797 798def main(): 799 """ 800 Entry function. 801 """ 802 parse_args() 803 804 OPTIONS_MANAGER.product = PRODUCT 805 806 source_package, target_package, update_package, no_zip, not_l2, \ 807 partition_file, signing_algorithm, hash_algorithm, private_key = \ 808 get_args() 809 if not_l2: 810 no_zip = True 811 812 # Unpack updater package 813 if OPTIONS_MANAGER.unpack_package_path: 814 package = UnpackPackage() 815 if not package.unpack_package(): 816 UPDATE_LOGGER.print_log( 817 "Unpack update package .bin failed!", UPDATE_LOGGER.ERROR_LOG) 818 clear_resource(err_clear=True) 819 return 820 UPDATE_LOGGER.print_log("Unpack update package .bin success!") 821 clear_resource(err_clear=True) 822 return 823 824 if OPTIONS_MANAGER.sd_card: 825 if source_package is not None or \ 826 OPTIONS_MANAGER.xml_path is not None or \ 827 partition_file is not None: 828 UPDATE_LOGGER.print_log( 829 "SD Card updater, " 830 "the -S/-xp/-pf parameter is not required!", 831 UPDATE_LOGGER.ERROR_LOG) 832 raise RuntimeError 833 if check_args(private_key, source_package, 834 target_package, update_package) is False: 835 clear_resource(err_clear=True) 836 return 837 838 if not OPTIONS_MANAGER.sd_card: 839 if check_userdata_image() is False: 840 clear_resource(err_clear=True) 841 return 842 843 # Create a Script object. 844 prelude_script, verse_script, refrain_script, ending_script = \ 845 get_script_obj() 846 847 # Create partition. 848 if partition_file is not None: 849 verse_script.add_command("\n# ---- do updater partitions ----\n") 850 updater_partitions_cmd = verse_script.updater_partitions() 851 verse_script.add_command(updater_partitions_cmd) 852 853 partition_file_obj, partitions_list, partitions_file_path_list = \ 854 parse_partition_file_xml(partition_file) 855 if partition_file_obj is False: 856 clear_resource(err_clear=True) 857 return False 858 OPTIONS_MANAGER.partition_file_obj = partition_file_obj 859 OPTIONS_MANAGER.full_img_list = partitions_list 860 OPTIONS_MANAGER.full_image_path_list = partitions_file_path_list 861 OPTIONS_MANAGER.two_step = False 862 863 # Upgrade the updater image. 864 if OPTIONS_MANAGER.two_step: 865 get_status_cmd = verse_script.get_status() 866 set_status_0_cmd = verse_script.set_status('0') 867 set_status_1_cmd = verse_script.set_status('1') 868 reboot_now_cmd = verse_script.reboot_now() 869 create_updater_script_command = \ 870 '\n# ---- do updater partitions ----\n\n' \ 871 'if ({get_status_cmd} == 0){{\nUPDATER_WRITE_FLAG\n' \ 872 ' {set_status_1_cmd} {reboot_now_cmd}}}\n' \ 873 'else{{ \nALL_WRITE_FLAG\n {set_status_0_cmd}}}'.format( 874 get_status_cmd=get_status_cmd, 875 set_status_1_cmd=set_status_1_cmd, 876 set_status_0_cmd=set_status_0_cmd, 877 reboot_now_cmd=reboot_now_cmd) 878 verse_script.add_command(create_updater_script_command) 879 880 if incremental_processing( 881 no_zip, partition_file, source_package, verse_script) is False: 882 clear_resource(err_clear=True) 883 return 884 885 # Full processing 886 if len(OPTIONS_MANAGER.full_img_list) != 0: 887 verse_script.add_command("\n# ---- full image ----\n") 888 full_update_image = \ 889 FullUpdateImage(OPTIONS_MANAGER.target_package_dir, 890 OPTIONS_MANAGER.full_img_list, 891 OPTIONS_MANAGER.full_img_name_list, 892 verse_script, OPTIONS_MANAGER.full_image_path_list, 893 no_zip=OPTIONS_MANAGER.no_zip) 894 full_image_content_len_list, full_image_file_obj_list = \ 895 full_update_image.update_full_image() 896 if full_image_content_len_list is False or \ 897 full_image_file_obj_list is False: 898 clear_resource(err_clear=True) 899 return 900 OPTIONS_MANAGER.full_image_content_len_list, \ 901 OPTIONS_MANAGER.full_image_file_obj_list = \ 902 full_image_content_len_list, full_image_file_obj_list 903 904 # Generate the update package. 905 build_re = build_update_package(no_zip, update_package, 906 prelude_script, verse_script, 907 refrain_script, ending_script) 908 if build_re is False: 909 clear_resource(err_clear=True) 910 return 911 # Clear resources. 912 clear_resource() 913 914 915if __name__ == '__main__': 916 main() 917