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 PARTITION_CHANGE_EVENT 84from utils import DECOUPLED_EVENT 85from utils import get_update_config_softversion 86from vendor_script import create_vendor_script_class 87 88sys.setrecursionlimit(MAXIMUM_RECURSION_DEPTH) 89 90 91def type_check(arg): 92 """ 93 Argument check, which is used to check whether the specified arg is a file. 94 :param arg: the arg to check 95 :return: Check result, which is False if the arg is invalid. 96 """ 97 if arg is not None and not os.path.exists(arg): 98 UPDATE_LOGGER.print_log( 99 "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 100 return False 101 return arg 102 103 104def private_key_check(arg): 105 """ 106 Argument check, which is used to check whether 107 the specified arg is a private_key. 108 :param arg: The arg to check. 109 :return: Check result, which is False if the arg is invalid. 110 """ 111 if arg != "ON_SERVER" and not os.path.isfile(arg): 112 UPDATE_LOGGER.print_log( 113 "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 114 return False 115 return arg 116 117 118def check_update_package(arg): 119 """ 120 Argument check, which is used to check whether 121 the update package path exists. 122 :param arg: The arg to check. 123 :return: Check result 124 """ 125 make_dir_path = None 126 if os.path.exists(arg): 127 if os.path.isfile(arg): 128 UPDATE_LOGGER.print_log( 129 "Update package must be a dir path, not a file path. " 130 "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 131 return False 132 else: 133 try: 134 UPDATE_LOGGER.print_log( 135 "Update package path does not exist. The dir will be created!" 136 "path: %s" % arg, UPDATE_LOGGER.WARNING_LOG) 137 os.makedirs(arg) 138 make_dir_path = arg 139 except OSError: 140 UPDATE_LOGGER.print_log( 141 "Make update package path dir failed! " 142 "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG) 143 return False 144 if make_dir_path is not None: 145 OPTIONS_MANAGER.make_dir_path = make_dir_path 146 OPTIONS_MANAGER.update_package = arg 147 return arg 148 149 150def unpack_check(arg): 151 """ 152 Argument check, which is used to check whether 153 the update package path exists. 154 :param arg: The arg to check. 155 :return: Check result 156 """ 157 unpack_package = os.path.join(OPTIONS_MANAGER.update_package, arg) 158 if not os.path.isfile(unpack_package): 159 UPDATE_LOGGER.print_log( 160 "FileNotFoundError, path: %s" % unpack_package, UPDATE_LOGGER.ERROR_LOG) 161 OPTIONS_MANAGER.unpack_package_path = None 162 return False 163 OPTIONS_MANAGER.unpack_package_path = unpack_package 164 return arg 165 166 167def create_entrance_args(): 168 """ 169 Arguments for the tool to create an update package 170 :return source_package : source version package 171 target_package : target version package 172 update_package : update package output path 173 no_zip : whether to enable the update package zip function. 174 partition_file : partition table XML file 175 signing_algorithm : signature algorithm (ECC and RSA (default)) 176 private_key : path of the private key file 177 """ 178 parser = OPTIONS_MANAGER.parser 179 parser.description = "Tool for creating update package." 180 parser.add_argument("-unpack", "--unpack_package", type=unpack_check, 181 default=None, help="Unpack updater package.") 182 parser.add_argument("-s", "--source_package", type=type_check, 183 default=None, help="Source package file path.") 184 parser.add_argument("target_package", type=type_check, 185 help="Target package file path.") 186 parser.add_argument("update_package", type=check_update_package, 187 help="Update package file path.") 188 parser.add_argument("-nz", "--no_zip", action='store_true', 189 help="No zip mode, Output update package without zip.") 190 parser.add_argument("-pf", "--partition_file", default=None, 191 help="Variable partition mode, " 192 "Partition list file path.") 193 parser.add_argument("-sa", "--signing_algorithm", default='RSA', 194 choices=['ECC', 'RSA'], 195 help="The signing algorithm " 196 "supported by the tool include ['ECC', 'RSA'].") 197 parser.add_argument("-ha", "--hash_algorithm", default='sha256', 198 choices=['sha256', 'sha384'], 199 help="The hash algorithm " 200 "supported by the tool include " 201 "['sha256', 'sha384'].") 202 parser.add_argument("-pk", "--private_key", type=private_key_check, 203 default=None, help="Private key file path.") 204 parser.add_argument("-nl2", "--not_l2", action='store_true', 205 help="Not L2 mode, Distinguish between L1 and L2.") 206 parser.add_argument("-sl", "--signing_length", default='256', 207 choices=['256', '384'], 208 help="The signing content length " 209 "supported by the tool include " 210 "['256', '384'].") 211 parser.add_argument("-xp", "--xml_path", type=private_key_check, 212 default=None, help="XML file path.") 213 parser.add_argument("-sc", "--sd_card", action='store_true', 214 help="SD Card mode, " 215 "Create update package for SD Card.") 216 217 218def parse_args(): 219 args = OPTIONS_MANAGER.parser.parse_args() 220 OPTIONS_MANAGER.source_package = args.source_package 221 OPTIONS_MANAGER.target_package = args.target_package 222 OPTIONS_MANAGER.update_package = args.update_package 223 OPTIONS_MANAGER.no_zip = args.no_zip 224 OPTIONS_MANAGER.partition_file = args.partition_file 225 OPTIONS_MANAGER.signing_algorithm = args.signing_algorithm 226 OPTIONS_MANAGER.hash_algorithm = args.hash_algorithm 227 OPTIONS_MANAGER.private_key = args.private_key 228 OPTIONS_MANAGER.not_l2 = args.not_l2 229 OPTIONS_MANAGER.signing_length = int(args.signing_length) 230 OPTIONS_MANAGER.xml_path = args.xml_path 231 OPTIONS_MANAGER.sd_card = args.sd_card 232 233 234def get_args(): 235 ret_args = \ 236 [OPTIONS_MANAGER.source_package, 237 OPTIONS_MANAGER.target_package, 238 OPTIONS_MANAGER.update_package, 239 OPTIONS_MANAGER.no_zip, 240 OPTIONS_MANAGER.not_l2, 241 OPTIONS_MANAGER.partition_file, 242 OPTIONS_MANAGER.signing_algorithm, 243 OPTIONS_MANAGER.hash_algorithm, 244 OPTIONS_MANAGER.private_key] 245 return ret_args 246 247 248def get_script_obj(): 249 """ 250 Obtain Opera script object 251 :return: 252 """ 253 script_obj_list = create_vendor_script_class() 254 if script_obj_list == [None] * len(SCRIPT_KEY_LIST): 255 prelude_script = PreludeScript() 256 verse_script = VerseScript() 257 refrain_script = RefrainScript() 258 ending_script = EndingScript() 259 260 generate_verse_script = \ 261 OPTIONS_MANAGER.init.invoke_event(VERSE_SCRIPT_EVENT) 262 if generate_verse_script: 263 verse_script = generate_verse_script() 264 else: 265 UPDATE_LOGGER.print_log( 266 "Get vendor extension object completed!" 267 "The vendor extension script will be generated.") 268 prelude_script = script_obj_list[0] 269 verse_script = script_obj_list[1] 270 refrain_script = script_obj_list[2] 271 ending_script = script_obj_list[3] 272 return prelude_script, verse_script, refrain_script, ending_script 273 274 275def get_source_package_path(source_package): 276 """ 277 get_source_package_path. 278 :param source_package: source package path 279 :return: 280 """ 281 if os.path.isdir(source_package): 282 OPTIONS_MANAGER.source_package_dir = source_package 283 elif source_package.endswith('.zip'): 284 # Decompress the source package. 285 tmp_dir_obj, unzip_dir = unzip_package(source_package) 286 if tmp_dir_obj is False or unzip_dir is False: 287 clear_resource(err_clear=True) 288 return False 289 OPTIONS_MANAGER.source_package_dir = unzip_dir 290 OPTIONS_MANAGER.source_package_temp_obj = tmp_dir_obj 291 else: 292 UPDATE_LOGGER.print_log("Input Update Package type exception!" 293 "path: %s" % source_package, UPDATE_LOGGER.ERROR_LOG) 294 clear_resource(err_clear=True) 295 return False 296 return True 297 298 299def check_incremental_args(no_zip, partition_file, source_package, 300 incremental_img_list): 301 """ 302 When the incremental list is not empty, incremental processing is required. 303 In this case, check related arguments. 304 :param no_zip: no zip mode 305 :param partition_file: 306 :param source_package: 307 :param incremental_img_list: 308 :return: 309 """ 310 if "boot" in incremental_img_list: 311 UPDATE_LOGGER.print_log("boot cannot be incrementally processed!", UPDATE_LOGGER.ERROR_LOG) 312 clear_resource(err_clear=True) 313 return False 314 if source_package is None: 315 UPDATE_LOGGER.print_log("The source package is missing, " 316 "cannot be incrementally processed!", UPDATE_LOGGER.ERROR_LOG) 317 clear_resource(err_clear=True) 318 return False 319 if no_zip: 320 UPDATE_LOGGER.print_log("No ZIP mode, cannot be incrementally processed!", UPDATE_LOGGER.ERROR_LOG) 321 clear_resource(err_clear=True) 322 return False 323 if partition_file is not None: 324 UPDATE_LOGGER.print_log("Partition file is not None, " 325 "cannot be incrementally processed!", UPDATE_LOGGER.ERROR_LOG) 326 clear_resource(err_clear=True) 327 return False 328 329 if not get_source_package_path(source_package): 330 return False 331 partition_change = OPTIONS_MANAGER.init.invoke_event(PARTITION_CHANGE_EVENT) 332 if callable(partition_change) and partition_change() is False: 333 return False 334 UPDATE_LOGGER.print_log("Partition interception check finish.", UPDATE_LOGGER.INFO_LOG) 335 xml_path = '' 336 if OPTIONS_MANAGER.source_package_dir is not False: 337 xml_path = os.path.join(OPTIONS_MANAGER.source_package_dir, UPDATER_CONFIG, XML_FILE_PATH) 338 if OPTIONS_MANAGER.source_package_dir is False: 339 OPTIONS_MANAGER.source_package_temp_obj = None 340 OPTIONS_MANAGER.source_package_dir = None 341 if os.path.exists(xml_path): 342 with open(xml_path, 'r') as xml_file: 343 xml_str = xml_file.read() 344 else: 345 UPDATE_LOGGER.print_log("XML file does not exist! xml path: %s" % 346 xml_path, UPDATE_LOGGER.ERROR_LOG) 347 return False 348 349 xml_content_dict = xmltodict.parse(xml_str, encoding='utf-8') 350 package_dict = xml_content_dict.get('package', {}) 351 get_update_config_softversion(OPTIONS_MANAGER.source_package_dir, package_dict.get('head', {})) 352 head_dict = package_dict.get('head', {}).get('info') 353 OPTIONS_MANAGER.source_package_version = head_dict.get("@softVersion") 354 no_need_version_check_res = OPTIONS_MANAGER.init.invoke_event(DECOUPLED_EVENT) 355 if no_need_version_check_res is False: 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 = [E2FSDROID_PATH, "-B", map_path, "-a", "/%s" % image_name, image_path, "-e"] 489 res = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 490 _, err = res.communicate(timeout=300) 491 if res.returncode != 0: 492 UPDATE_LOGGER.print_log("%s.map generate failed, reason:%s" % 493 (image_name, err.decode()), UPDATE_LOGGER.ERROR_LOG) 494 return False 495 UPDATE_LOGGER.print_log("%s.map generate success" % image_name, UPDATE_LOGGER.INFO_LOG) 496 return True 497 498 499def get_file_sha256(update_package): 500 sha256obj = hashlib.sha256() 501 maxbuf = 8192 502 with open(update_package, 'rb') as package_file: 503 while True: 504 buf = package_file.read(maxbuf) 505 if not buf: 506 break 507 sha256obj.update(buf) 508 hash_value = sha256obj.hexdigest() 509 return str(hash_value).upper() 510 511 512def write_image_patch_script(partition, src_image_path, tgt_image_path, 513 script_check_cmd_list, script_write_cmd_list, verse_script): 514 """ 515 Add command content to the script. 516 :param partition: image name 517 :param script_check_cmd_list: incremental check command list 518 :param script_write_cmd_list: incremental write command list 519 :param verse_script: verse script object 520 :return: 521 """ 522 src_sha = get_file_sha256(src_image_path) 523 src_size = os.path.getsize(src_image_path) 524 tgt_sha = get_file_sha256(tgt_image_path) 525 tgt_size = os.path.getsize(tgt_image_path) 526 527 sha_check_cmd = verse_script.image_sha_check(partition, 528 src_size, src_sha, tgt_size, tgt_sha) 529 530 first_block_check_cmd = verse_script.first_block_check(partition) 531 532 abort_cmd = verse_script.abort(partition) 533 534 cmd = 'if ({sha_check_cmd} != 0)' \ 535 '{{\n {abort_cmd}}}\n'.format( 536 sha_check_cmd=sha_check_cmd, 537 abort_cmd=abort_cmd) 538 539 script_check_cmd_list.append(cmd) 540 541 image_patch_cmd = verse_script.image_patch(partition, os.path.getsize(src_image_path), 542 get_file_sha256(src_image_path), os.path.getsize(tgt_image_path), 543 get_file_sha256(tgt_image_path)) 544 545 cmd = '%s_WRITE_FLAG%s' % (partition, image_patch_cmd) 546 script_write_cmd_list.append(cmd) 547 return True 548 549 550def increment_image_diff_processing( 551 partition, src_image_path, tgt_image_path, 552 script_check_cmd_list, script_write_cmd_list, verse_script): 553 """ 554 Incremental image processing 555 :param verse_script: verse script 556 :param incremental_img_list: incremental image list 557 :param source_package_dir: source package path 558 :param target_package_dir: target package path 559 :return: 560 """ 561 patch_file_obj = tempfile.NamedTemporaryFile( 562 prefix="%s_patch.dat-" % partition, mode='wb') 563 OPTIONS_MANAGER.incremental_image_file_obj_dict[partition] = patch_file_obj 564 cmd = [DIFF_EXE_PATH] 565 566 cmd.extend(['-s', src_image_path, '-d', tgt_image_path, 567 '-p', patch_file_obj.name, '-l', '4096']) 568 sub_p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 569 stderr=subprocess.STDOUT) 570 try: 571 output, _ = sub_p.communicate(timeout=1800) 572 except subprocess.TimeoutExpired: 573 sub_p.kill() 574 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 add_incremental_command(verse_script, script_check_cmd_list, script_write_cmd_list): 583 """ 584 add command for increment_image_progressing to verse_script 585 :param verse_script: verse script 586 :param script_check_cmd_list: verse_script check command list 587 :param script_write_cmd_list: verse_script write command list 588 :return: 589 """ 590 verse_script.add_command("\n# ---- start incremental check here ----\n") 591 for each_check_cmd in script_check_cmd_list: 592 verse_script.add_command(each_check_cmd) 593 verse_script.add_command("\n# ---- start incremental write here ----\n") 594 for each_write_cmd in script_write_cmd_list: 595 verse_script.add_command(each_write_cmd) 596 597 598def increment_image_processing( 599 verse_script, incremental_img_list, source_package_dir, 600 target_package_dir): 601 """ 602 Incremental image processing 603 :param verse_script: verse script 604 :param incremental_img_list: incremental image list 605 :param source_package_dir: source package path 606 :param target_package_dir: target package path 607 :return: 608 """ 609 script_check_cmd_list = [] 610 script_write_cmd_list = [] 611 patch_process = None 612 for each_img_name in OPTIONS_MANAGER.incremental_img_name_list: 613 each_img = each_img_name[:-4] 614 each_src_image_path = os.path.join(source_package_dir, '%s.img' % each_img) 615 each_src_map_path = os.path.join(source_package_dir, '%s.map' % each_img) 616 each_tgt_image_path = os.path.join(target_package_dir, '%s.img' % each_img) 617 each_tgt_map_path = os.path.join(target_package_dir, '%s.map' % each_img) 618 619 check_make_map_path(each_img) 620 621 if filecmp.cmp(each_src_image_path, each_tgt_image_path): 622 UPDATE_LOGGER.print_log("Source Image is the same as Target Image! src image path: %s, tgt image path: %s" 623 % (each_src_image_path, each_tgt_image_path), UPDATE_LOGGER.INFO_LOG) 624 OPTIONS_MANAGER.incremental_img_list.remove(each_img) 625 continue 626 627 src_generate_map = True 628 tgt_generate_map = True 629 if not os.path.exists(each_src_map_path): 630 src_generate_map = generate_image_map_file(each_src_image_path, each_src_map_path, each_img) 631 632 if not os.path.exists(each_tgt_map_path): 633 tgt_generate_map = generate_image_map_file(each_tgt_image_path, each_tgt_map_path, each_img) 634 635 if not src_generate_map or not tgt_generate_map: 636 if increment_image_diff_processing(each_img, each_src_image_path, each_tgt_image_path, 637 script_check_cmd_list, script_write_cmd_list, verse_script) is True: 638 continue 639 UPDATE_LOGGER.print_log("increment_image_diff_processing %s failed" % each_img) 640 clear_resource(err_clear=True) 641 return False 642 643 inc_image = OPTIONS_MANAGER.init.invoke_event(INC_IMAGE_EVENT) 644 if inc_image: 645 src_image_class, tgt_image_class = inc_image(each_src_image_path, each_src_map_path, 646 each_tgt_image_path, each_tgt_map_path) 647 else: 648 src_image_class = IncUpdateImage(each_src_image_path, each_src_map_path) 649 tgt_image_class = IncUpdateImage(each_tgt_image_path, each_tgt_map_path) 650 651 transfers_manager = TransfersManager(each_img, tgt_image_class, src_image_class) 652 transfers_manager.find_process_needs() 653 actions_list = transfers_manager.get_action_list() 654 655 graph_process = GigraphProcess(actions_list, src_image_class, tgt_image_class) 656 actions_list = graph_process.actions_list 657 patch_process = patch_package_process.PatchProcess(each_img, tgt_image_class, src_image_class, actions_list) 658 patch_process.patch_process() 659 patch_process.write_script(each_img, script_check_cmd_list, script_write_cmd_list, verse_script) 660 OPTIONS_MANAGER.incremental_block_file_obj_dict[each_img] = patch_process.package_patch_zip 661 662 if not check_patch_file(patch_process): 663 UPDATE_LOGGER.print_log('Verify the incremental result failed!', UPDATE_LOGGER.ERROR_LOG) 664 raise RuntimeError 665 666 add_incremental_command(verse_script, script_check_cmd_list, script_write_cmd_list) 667 return True 668 669 670def check_patch_file(patch_process): 671 new_dat_file_obj, patch_dat_file_obj, transfer_list_file_obj = \ 672 patch_process.package_patch_zip.get_file_obj() 673 with open(transfer_list_file_obj.name) as f_t: 674 num = 0 675 diff_str = None 676 diff_num = 0 677 for line in f_t: 678 if line.startswith('new '): 679 each_line_list = \ 680 line.strip().replace("new ", "").split(",")[1:] 681 for idx in range(0, len(each_line_list), 2): 682 num += \ 683 int(each_line_list[idx + 1]) - int(each_line_list[idx]) 684 continue 685 if line.startswith('bsdiff ') or line.startswith('pkgdiff '): 686 diff_str = line 687 if diff_str: 688 diff_list = diff_str.split('\n')[0].split(' ') 689 diff_num = int(diff_list[1]) + int(diff_list[2]) 690 check_flag = \ 691 (os.path.getsize(new_dat_file_obj.name) == num * PER_BLOCK_SIZE) and \ 692 (os.path.getsize(patch_dat_file_obj.name) == diff_num) 693 return check_flag 694 695 696def check_make_map_path(each_img): 697 """ 698 If env does not exist, the command for map generation does not exist 699 in the environment variable, and False will be returned. 700 """ 701 try: 702 cmd = [E2FSDROID_PATH, " -h"] 703 subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, 704 stderr=subprocess.STDOUT) 705 except FileNotFoundError: 706 UPDATE_LOGGER.print_log( 707 "Command not found, need check the env! " 708 "Make %s.map failed!" % each_img, 709 UPDATE_LOGGER.ERROR_LOG) 710 clear_resource(err_clear=True) 711 raise RuntimeError 712 return True 713 714 715def incremental_processing(no_zip, partition_file, source_package, 716 verse_script): 717 """ 718 Incremental processing. 719 :param no_zip: no zip mode 720 :param partition_file: partition xml file path 721 :param source_package: source package path 722 :param verse_script: verse script obj 723 :return : processing result 724 """ 725 if len(OPTIONS_MANAGER.incremental_img_list) != 0: 726 if check_incremental_args(no_zip, partition_file, source_package, 727 OPTIONS_MANAGER.incremental_img_list) \ 728 is False: 729 return False 730 if increment_image_processing( 731 verse_script, OPTIONS_MANAGER.incremental_img_list, 732 OPTIONS_MANAGER.source_package_dir, 733 OPTIONS_MANAGER.target_package_dir) is False: 734 return False 735 else: 736 if source_package is not None: 737 UPDATE_LOGGER.print_log( 738 "There is no incremental image, " 739 "the - S parameter is not required!", 740 UPDATE_LOGGER.ERROR_LOG) 741 raise RuntimeError 742 743 744def check_args(private_key, source_package, target_package, update_package): 745 """ 746 Input args check. 747 :param private_key: private key path 748 :param source_package: source package path 749 :param target_package: target package path 750 :param update_package: output package path 751 :return : Judgment result 752 """ 753 if source_package is False or private_key is False or \ 754 target_package is False or update_package is False: 755 return False 756 if check_miss_private_key(private_key) is False: 757 return False 758 if check_target_package_path(target_package) is False: 759 return False 760 if get_update_info() is False: 761 return False 762 if check_images_list() is False: 763 return False 764 return True 765 766 767def unpack_package_processing(): 768 if OPTIONS_MANAGER.unpack_package_path: 769 package = UnpackPackage() 770 if not package.unpack_package(): 771 UPDATE_LOGGER.print_log("Unpack update package.bin failed!", UPDATE_LOGGER.ERROR_LOG) 772 clear_resource(err_clear=True) 773 sys.exit(1) 774 UPDATE_LOGGER.print_log("Unpack update package.bin success!") 775 clear_resource() 776 sys.exit(0) 777 778 779create_entrance_args() 780 781 782def main(): 783 """ 784 Entry function. 785 """ 786 parse_args() 787 788 OPTIONS_MANAGER.product = PRODUCT 789 790 source_package, target_package, update_package, no_zip, not_l2, \ 791 partition_file, signing_algorithm, hash_algorithm, private_key = get_args() 792 if not_l2: 793 no_zip = True 794 795 # Unpack updater package 796 unpack_package_processing() 797 798 if OPTIONS_MANAGER.sd_card: 799 if source_package is not None or OPTIONS_MANAGER.xml_path is not None or partition_file is not None: 800 UPDATE_LOGGER.print_log("SDCard updater:-S/-xp/-pf parameter is not required!", UPDATE_LOGGER.ERROR_LOG) 801 raise RuntimeError 802 if check_args(private_key, source_package, target_package, update_package) is False: 803 clear_resource(err_clear=True) 804 return 805 806 if not OPTIONS_MANAGER.sd_card: 807 if check_userdata_image() is False: 808 clear_resource(err_clear=True) 809 return 810 811 # Create a Script object. 812 prelude_script, verse_script, refrain_script, ending_script = get_script_obj() 813 814 # Create partition. 815 if partition_file is not None: 816 verse_script.add_command("\n# ---- do updater partitions ----\n") 817 updater_partitions_cmd = verse_script.updater_partitions() 818 verse_script.add_command(updater_partitions_cmd) 819 820 partition_file_obj, partitions_list, partitions_file_path_list = parse_partition_file_xml(partition_file) 821 if partition_file_obj is False: 822 clear_resource(err_clear=True) 823 return False 824 OPTIONS_MANAGER.partition_file_obj = partition_file_obj 825 OPTIONS_MANAGER.full_img_list = partitions_list 826 OPTIONS_MANAGER.full_image_path_list = partitions_file_path_list 827 828 if incremental_processing(no_zip, partition_file, source_package, verse_script) is False: 829 clear_resource(err_clear=True) 830 return 831 832 # Full processing 833 if len(OPTIONS_MANAGER.full_img_list) != 0: 834 verse_script.add_command("\n# ---- full image ----\n") 835 full_update_image = FullUpdateImage(OPTIONS_MANAGER.target_package_dir, 836 OPTIONS_MANAGER.full_img_list, OPTIONS_MANAGER.full_img_name_list, verse_script, 837 OPTIONS_MANAGER.full_image_path_list, no_zip=OPTIONS_MANAGER.no_zip) 838 full_image_content_len_list, full_image_file_obj_list = full_update_image.update_full_image() 839 if full_image_content_len_list is False or full_image_file_obj_list is False: 840 clear_resource(err_clear=True) 841 return 842 OPTIONS_MANAGER.full_image_content_len_list, OPTIONS_MANAGER.full_image_file_obj_list = \ 843 full_image_content_len_list, full_image_file_obj_list 844 845 # Generate the update package. 846 if build_update_package( 847 no_zip, update_package, prelude_script, verse_script, refrain_script, ending_script) is False: 848 clear_resource(err_clear=True) 849 return 850 # Clear resources. 851 clear_resource() 852 853 854if __name__ == '__main__': 855 main() 856