Android OTA update package creation script (1. Parameter Parsing)
Preface:
"Build/tools/releasetools/ota_from_target_files-u lk. bin-n target.zip update.zip" is the command for creating the entire package. Obviously, lk upgrade is supported here. This series of blog posts mainly analyzes the execution process and principle of this command in a system, involving multiple modules in the/build/tools/releasetools/directory, such as ota_from_target_files and common. As I have a rough understanding of python, most of the python syntaxes involved in this article are annotated to help some students interested in python understand the corresponding statements.
The entire process looks complicated and complex. I hope that interested users can patiently look at it. Those who are familiar with the python syntax can select the part they are interested in as a reference.
1. Execute the script
First, we can see from the command that the entire package creation process starts from the ota_from_target_files module. The ota_from_target_files module first executes the following statements:
#__ Name _ is the built-in attribute of the module, which refers to the call method of the. py file. The. py file can be called as a module or used directly. If it is equal to _ main _, it indicates direct execution. That is to say, when the statement after if _ name _ = _ main __: is called as a module, it is not executed; when it is directly used, the code after the statement is executed. It is obviously used directly here.
If _ name _ = '_ main _': try: common. closeInheritedPipes () is a description file (PIPE) in the MAC system. Here, fds is disabled before the start. Here, the main (sys) is adjusted based on the current operating system. argv [1:]) This is the main method used to compile the script. externalError, e: print ERROR: % s % (e,) print sys. exit (1)
The following is the script entry function main (arg)
Def main (argv): saves the Option set by the user to the OPTIONS variable. OPTIONS is a Python Class. We can understand it as a C Struct or a java encapsulation. def option_handler (o, a): if o in (-B, -- board_config ): # in is a boolean operator used to test whether the left operand is contained in the ancestor on the right. Here, it is used to determine whether the input value of parameter o is included in (-B, -- board_config; pass # deprecated elif o in (-k, -- package_key): OPTIONS. package_key = a elif o in (-I, -- incremental_from): OPTIONS. incremental_source = a elif o in (-w, -- wipe_user_data): OPTIONS. wipe_user_data = True elif o in (-n, -- no_prereq): OPTIONS. omit_prereq = True elif o in (-e, -- extra_script): OPTIONS. extra_script = a elif o in (-a, -- aslr_mode): if a in (on, On, true, True, yes, Yes): OPTIONS. aslr_mode = True else: OPTIONS. aslr_mode = False elif o in (-- worker_threads): OPTIONS. worker_threads = int (a) elif o in (-2, -- two_step): OPTIONS. two_step = True elif o in (-r, -- preloader): OPTIONS. preloader = a elif o in (-l, -- logo): OPTIONS. logo = a elif o in (-u, -- uboot): OPTIONS. uboot = a elif o in (-d, -- dsp): OPTIONS. dsp = a elif o in (-f, -- special_factory_reset): OPTIONS. special_factory_reset = True elif o in (-g, -- ubifs): OPTIONS. ubifs = True elif o in (-t, -- tee): OPTIONS. tee = a elif o in (-z, -- trustonic): OPTIONS. trustonic = a else: return False return True
2. parsing Parameters
# Parsing parameter args = common. parseOptions (argv, _ doc __, extra_opts = B: k: I: d: wfgne: r: l: u: t: z: d: a: s: 2, response = [board_config =, package_key =, incremental_from =, wipe_user_data, response, ubifs, no_prereq, extra_script =, preloader =, logo =, uboot =, tee =, trustonic =, dsp =, worker_threads =, aslr_mode =, two_step,], extra_option_handler = option_handler)
The above Parameter Parsing operations are actually encapsulated in common. here we will explain the extra_option_handler = option_handler. in Python, functions can be directly copied to a variable. option_handler is a method defined above, the assignment is not executed here, but directly assigned to extra_option_handler. Note that the assignment will not execute the content in option_handler, but will be executed during actual calls. Since variables can point to functions, one function can receive another function as a parameter.
Then let's take a look at the function parsing process. First, let's look at the Code:
Opts is a list containing the ancestor, and each ancestor is the analyzed format information, such as [('-U', 'lk. bin'), ('-n', ''), ('-I ', 'base.zip')]; for details about the getopt logic, refer to the use of getopt in python.
# Parsing parameter def ParseOptions (argv, docstring, extra_opts =, extra_long_opts = (), extra_option_handler = None): Parse the options in argv and return any arguments that aren't flags. docstring is the calling module's docstring, to be displayed for errors and-h. extra_opts and extra_long_opts are for flags defined by the caller, which are processed by passing them to extra_option_handler. try: opts, args = getopt. getopt (argv, hvp: s: x: + extra_opts, [help, verbose, path =, signapk_path =, extra_signapk_args =, java_path =, Signature =, private_key_suffix =, device_specpacific =, extra =] + list (extra_long_opts) # Here we can add a log to view the value of print (begin) for I in range (len (opts) in opts and args )): print (opts [I]) print (*************) for I in range (len (args): print (args [I]) print (end) Counter t getopt. getoptError, err: Usage (docstring) print **, str (err), ** sys. exit (2) path_specified = False for o, a in opts: if o in (-h, -- help): Usage (docstring) sys. exit () elif o in (-v, -- verbose): OPTIONS. verbose = True elif o in (-p, -- path): OPTIONS. search_path = a elif o in (-- signapk_path,): OPTIONS. signapk_path = a elif o in (-- extra_signapk_args,): OPTIONS. extra_signapk_args = shlex. split (a) elif o in (-- java_path,): OPTIONS. java_path = a elif o in (-- public_key_suffix,): OPTIONS. public_key_suffix = a elif o in (-- private_key_suffix,): OPTIONS. private_key_suffix = a elif o in (-s, -- device_specific): OPTIONS. device_specific = a elif o in (-x, -- extra): key, value =. split (=, 1) OPTIONS. extras [key] = value else: if extra_option_handler is None or not extra_option_handler (o, a): assert False, unknown option % s % (o,) # environment variable OS. environ [PATH] = (OS. path. join (OPTIONS. search_path, bin) + OS. pathsep + OS. environ [PATH]) return args
The following information is printed by log:
begin('-u', 'lk.bin')('-n', '')('-i', 'base.zip')******target.zipupdate.zipend
After the parameters are parsed, the execution process continues to return to the main function in ota_from_target_files. Let's proceed with the process.
The following is a filter of the length of the returned value after parameter resolution. Here it is fixed to 2, whether it is the whole package or the creation of the differential package.
if len(args) != 2: common.Usage(__doc__) sys.exit(1)
# There is no additional script here, so the value of OPTIONS. extra_script is None.
if OPTIONS.extra_script is not None: OPTIONS.extra_script = open(OPTIONS.extra_script).read()