OTA制作

OTA的制作流程是從ota_from_target_files開(kāi)始的熙揍,ota_from_target_files模塊最先執(zhí)行的方法如下:

if __name__ == '__main__':
  try:
    common.CloseInheritedPipes()     //MAC系統(tǒng)gmake會(huì)存在文件描述符泄露饲梭,因此在開(kāi)始其他工作的時(shí)候?qū)⑦@些描述符關(guān)閉
    main(sys.argv[1:])                         //開(kāi)始制作OTA包
  except common.ExternalError as e:
    print
    print "   ERROR: %s" % (e,)
    print
    sys.exit(1)
  finally:
    common.Cleanup()

腳本入口函數(shù)main

def main(argv):

  def option_handler(o, a):   \\將用戶設(shè)定的option存入到一個(gè)OPTIONS類中
    if o == "--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 == "--full_radio":
      OPTIONS.full_radio = True
    elif o == "--full_bootloader":
      OPTIONS.full_bootloader = True
    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 ("-o", "--oem_settings"):
      OPTIONS.oem_source = a
    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 ("-t", "--worker_threads"):
      if a.isdigit():
        OPTIONS.worker_threads = int(a)
      else:
        raise ValueError("Cannot parse value %r for option %r - only "
                         "integers are allowed." % (a, o))
    elif o in ("-2", "--two_step"):
      OPTIONS.two_step = True
    elif o == "--no_signing":
      OPTIONS.no_signing = True
    elif o == "--verify":
      OPTIONS.verify = True
    elif o == "--block":
      OPTIONS.block_based = True
    elif o in ("-b", "--binary"):
      OPTIONS.updater_binary = a
    elif o in ("--no_fallback_to_full",):
      OPTIONS.fallback_to_full = False
    elif o == "--stash_threshold":
      try:
        OPTIONS.stash_threshold = float(a)
      except ValueError:
        raise ValueError("Cannot parse value %r for option %r - expecting "
                         "a float" % (a, o))
    else:
      return False
    return True

解析參數(shù),將得到的參數(shù)和參數(shù)值傳回給args蹭越,args是個(gè)列表,保存了沒(méi)有加-或者--的參數(shù)

  args = common.ParseOptions(argv, __doc__,
                             extra_opts="b:k:i:d:wne:t:a:2o:",
                             extra_long_opts=[
                                 "board_config=",
                                 "package_key=",
                                 "incremental_from=",
                                 "full_radio",
                                 "full_bootloader",
                                 "wipe_user_data",
                                 "no_prereq",
                                 "extra_script=",
                                 "worker_threads=",
                                 "aslr_mode=",
                                 "two_step",
                                 "no_signing",
                                 "block",
                                 "binary=",
                                 "oem_settings=",
                                 "verify",
                                 "no_fallback_to_full",
                                 "stash_threshold=",
                             ], extra_option_handler=option_handler)

common.py中的ParseOptions,主要是調(diào)用python中的getopt模塊中的getopt函數(shù)來(lái)解析參數(shù)

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=", "java_args=", "public_key_suffix=",
         "private_key_suffix=", "boot_signer_path=", "boot_signer_args=",
         "verity_signer_path=", "verity_signer_args=", "device_specific=",
         "extra="] +
        list(extra_long_opts))
  except getopt.GetoptError as err:
    Usage(docstring)
    print "**", str(err), "**"
    sys.exit(2)

  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 ("--java_args",):
      OPTIONS.java_args = 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 ("--boot_signer_path",):
      OPTIONS.boot_signer_path = a
    elif o in ("--boot_signer_args",):
      OPTIONS.boot_signer_args = shlex.split(a)
    elif o in ("--verity_signer_path",):
      OPTIONS.verity_signer_path = a
    elif o in ("--verity_signer_args",):
      OPTIONS.verity_signer_args = shlex.split(a)
    elif o in ("-s", "--device_specific"):
      OPTIONS.device_specific = a
    elif o in ("-x", "--extra"):
      key, value = a.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,)

  if OPTIONS.search_path:
    os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") +
                          os.pathsep + os.environ["PATH"])

  return args
  if len(args) != 2:
    common.Usage(__doc__)
    sys.exit(1)

  if OPTIONS.extra_script is not None:
    OPTIONS.extra_script = open(OPTIONS.extra_script).read()

解壓目標(biāo)文件包

  print "unzipping target target-files..."
  OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])

common.py中的UnzipTemp函數(shù)妇斤,主要是對(duì)目標(biāo)文件包進(jìn)行解壓,返回值是tmp臨時(shí)路徑和zipfile.ZipFile目標(biāo)文件包的內(nèi)容丹拯。

def UnzipTemp(filename, pattern=None):
  """Unzip the given archive into a temporary directory and return the name.

  If filename is of the form "foo.zip+bar.zip", unzip foo.zip into a
  temp dir, then unzip bar.zip into that_dir/BOOTABLE_IMAGES.

  Returns (tempdir, zipobj) where zipobj is a zipfile.ZipFile (of the
  main file), open for reading.
  """

  tmp = tempfile.mkdtemp(prefix="targetfiles-")
  OPTIONS.tempfiles.append(tmp)

  def unzip_to_dir(filename, dirname):
    cmd = ["unzip", "-o", "-q", filename, "-d", dirname]
    if pattern is not None:
      cmd.append(pattern)
    p = Run(cmd, stdout=subprocess.PIPE)  //開(kāi)啟一個(gè)進(jìn)程來(lái)解壓目標(biāo)文件包
    p.communicate()
    if p.returncode != 0:
      raise ExternalError("failed to unzip input target-files \"%s\"" %
                          (filename,))

  m = re.match(r"^(.*[.]zip)\+(.*[.]zip)$", filename, re.IGNORECASE)
  if m:
    unzip_to_dir(m.group(1), tmp)
    unzip_to_dir(m.group(2), os.path.join(tmp, "BOOTABLE_IMAGES"))
    filename = m.group(1)
  else:
    unzip_to_dir(filename, tmp)

  return tmp, zipfile.ZipFile(filename, "r")
  OPTIONS.target_tmp = OPTIONS.input_tmp
  OPTIONS.info_dict = common.LoadInfoDict(input_zip)

將目標(biāo)文件包中META/misc_info.txt的信息進(jìn)行解析保存

def LoadInfoDict(input_file):
  """Read and parse the META/misc_info.txt key/value pairs from the
  input target files and return a dict."""

  def read_helper(fn):
    if isinstance(input_file, zipfile.ZipFile):
      return input_file.read(fn)
    else:
      path = os.path.join(input_file, *fn.split("/"))
      try:
        with open(path) as f:
          return f.read()
      except IOError as e:
        if e.errno == errno.ENOENT:
          raise KeyError(fn)
  d = {}
  try:
    d = LoadDictionaryFromLines(read_helper("META/misc_info.txt").split("\n"))
  except KeyError:
    # ok if misc_info.txt doesn't exist
    pass

  # backwards compatibility: These values used to be in their own
  # files.  Look for them, in case we're processing an old
  # target_files zip.

  if "mkyaffs2_extra_flags" not in d:
    try:
      d["mkyaffs2_extra_flags"] = read_helper(
          "META/mkyaffs2-extra-flags.txt").strip()
    except KeyError:
      # ok if flags don't exist
      pass

  if "recovery_api_version" not in d:
    try:
      d["recovery_api_version"] = read_helper(
          "META/recovery-api-version.txt").strip()
    except KeyError:
      raise ValueError("can't find recovery API version in input target-files")

if "tool_extensions" not in d:
    try:
      d["tool_extensions"] = read_helper("META/tool-extensions.txt").strip()
    except KeyError:
      # ok if extensions don't exist
      pass

  if "fstab_version" not in d:
    d["fstab_version"] = "1"

  try:
    data = read_helper("META/imagesizes.txt")
    for line in data.split("\n"):
      if not line:
        continue
      name, value = line.split(" ", 1)
      if not value:
        continue
      if name == "blocksize":
        d[name] = value
      else:
        d[name + "_size"] = value
  except KeyError:
    pass

  def makeint(key):
    if key in d:
      d[key] = int(d[key], 0)

  makeint("recovery_api_version")
  makeint("blocksize")
  makeint("system_size")
  makeint("vendor_size")
  makeint("userdata_size")
  makeint("cache_size")
  makeint("recovery_size")
  makeint("boot_size")
  makeint("fstab_version")

  d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"])
  d["build.prop"] = LoadBuildProp(read_helper)
  return d
def LoadDictionaryFromLines(lines):
  d = {}
  for line in lines:
    line = line.strip()
    if not line or line.startswith("#"):
      continue
    if "=" in line:
      name, value = line.split("=", 1)
      d[name] = value
  return d
  # If this image was originally labelled with SELinux contexts, make sure we
  # also apply the labels in our new image. During building, the "file_contexts"
  # is in the out/ directory tree, but for repacking from target-files.zip it's
  # in the root directory of the ramdisk.
  if "selinux_fc" in OPTIONS.info_dict:
    OPTIONS.info_dict["selinux_fc"] = os.path.join(
        OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")

  if OPTIONS.verbose:
    print "--- target info ---"
    common.DumpInfoDict(OPTIONS.info_dict)    //打印從目標(biāo)文件包中的/META/misc_info.txt讀取的信息

  # If the caller explicitly specified the device-specific extensions
  # path via -s/--device_specific, use that.  Otherwise, use
  # META/releasetools.py if it is present in the target target_files.
  # Otherwise, take the path of the file from 'tool_extensions' in the
  # info dict and look for that in the local filesystem, relative to
  # the current directory.

  if OPTIONS.device_specific is None:
    from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py")
    if os.path.exists(from_input):
      print "(using device-specific extensions from target_files)"
      OPTIONS.device_specific = from_input
    else:
      OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None)

  if OPTIONS.device_specific is not None:
    OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific)

  while True:

    if OPTIONS.no_signing:
      if os.path.exists(args[1]):
        os.unlink(args[1])
      output_zip = zipfile.ZipFile(args[1], "w",
                                   compression=zipfile.ZIP_DEFLATED)
    else:
      temp_zip_file = tempfile.NamedTemporaryFile()
      output_zip = zipfile.ZipFile(temp_zip_file, "w",
                                   compression=zipfile.ZIP_DEFLATED)

    cache_size = OPTIONS.info_dict.get("cache_size", None)
    if cache_size is None:
      raise RuntimeError("can't determine the cache partition size")
    OPTIONS.cache_size = cache_size

    if OPTIONS.incremental_source is None:
      WriteFullOTAPackage(input_zip, output_zip)
      if OPTIONS.package_key is None:
        OPTIONS.package_key = OPTIONS.info_dict.get(
            "default_system_dev_certificate",
            "build/target/product/security/testkey")
      common.ZipClose(output_zip)
      break

    else:
      print "unzipping source target-files..."     //解析和保存源文件包的相關(guān)信息
      OPTIONS.source_tmp, source_zip = common.UnzipTemp(
          OPTIONS.incremental_source)
      OPTIONS.target_info_dict = OPTIONS.info_dict
      OPTIONS.source_info_dict = common.LoadInfoDict(source_zip)
      if "selinux_fc" in OPTIONS.source_info_dict:
        OPTIONS.source_info_dict["selinux_fc"] = os.path.join(
            OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts")
      if OPTIONS.package_key is None:
        OPTIONS.package_key = OPTIONS.source_info_dict.get(
            "default_system_dev_certificate",
            "build/target/product/security/testkey")
      if OPTIONS.verbose:
        print "--- source info ---"
        common.DumpInfoDict(OPTIONS.source_info_dict)

      try:
        WriteIncrementalOTAPackage(input_zip, source_zip, output_zip)  //構(gòu)建OTA包
        common.ZipClose(output_zip)
        break
      except ValueError:
        if not OPTIONS.fallback_to_full:
          raise
        print "--- failed to build incremental; falling back to full ---"
        OPTIONS.incremental_source = None
        common.ZipClose(output_zip)

  if not OPTIONS.no_signing:
    SignOutput(temp_zip_file.name, args[1])
    temp_zip_file.close()

  print "done."
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末站超,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乖酬,更是在濱河造成了極大的恐慌死相,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咬像,死亡現(xiàn)場(chǎng)離奇詭異算撮,居然都是意外死亡生宛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)肮柜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)陷舅,“玉大人,你說(shuō)我怎么就攤上這事审洞±痴觯” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵芒澜,是天一觀的道長(zhǎng)仰剿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)撰糠,這世上最難降的妖魔是什么酥馍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮阅酪,結(jié)果婚禮上旨袒,老公的妹妹穿的比我還像新娘。我一直安慰自己术辐,他們只是感情好砚尽,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著辉词,像睡著了一般必孤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瑞躺,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天敷搪,我揣著相機(jī)與錄音,去河邊找鬼幢哨。 笑死赡勘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捞镰。 我是一名探鬼主播闸与,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼岸售!你這毒婦竟也來(lái)了践樱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凸丸,失蹤者是張志新(化名)和其女友劉穎拷邢,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體甲雅,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡解孙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年坑填,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抛人。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弛姜。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妖枚,靈堂內(nèi)的尸體忽然破棺而出廷臼,到底是詐尸還是另有隱情,我是刑警寧澤绝页,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布荠商,位于F島的核電站,受9級(jí)特大地震影響续誉,放射性物質(zhì)發(fā)生泄漏莱没。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一酷鸦、第九天 我趴在偏房一處隱蔽的房頂上張望饰躲。 院中可真熱鬧,春花似錦臼隔、人聲如沸嘹裂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寄狼。三九已至,卻和暖如春氨淌,著一層夾襖步出監(jiān)牢的瞬間泊愧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工盛正, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留删咱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓蛮艰,卻偏偏與公主長(zhǎng)得像腋腮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壤蚜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容