編輯:關於Android編程
寫在前面:
“build/tools/releasetools/ota_from_target_files -u lk.bin -n target.zip update.zip”這是制作整包的命令,很顯然這裡支持lk升級。本系列博文主要對該命令的執行流程及原理進行一個系統的分析,涉及到/build/tools/releasetools/目錄下多個模塊如ota_from_target_files、common等。由於本人對python了解粗淺,文中所涉及到的python語法大都做了注釋,以便幫助部分對python有興趣的同學能夠讀懂相應的語句。
整個流程看起來有些繁瑣冗雜,希望有興趣的同學能夠耐心的去看,已經比較熟悉python語法的同學可以挑選感興趣的部分作為參考。
一,執行腳本
那麼首先,我們從命令中可以看到整包的制作流程是從ota_from_target_files模塊開始的。而ota_from_target_files模塊最先執行的方法是從下面這段語句開始的,如下:
#__name__作為模塊的內置屬性,指.py文件的調用方式;.py文件有兩種使用方式:作為模塊被調用和直接使用。如果它等於__main__就表示是直接執行。也就是說在if __name__ == __main__:之後的語句作為模塊被調用的時候不執行;直接使用的時候,語句之後的代碼執行。而這裡很顯然是直接使用。
if __name__ == '__main__':
try:
common.CloseInheritedPipes()MAC系統中卻是一些描述文件(PIPE),這裡在開始之前關閉fds;這裡主要是根據當前所使用的操作系統做的一些調整
main(sys.argv[1:])這是編譯腳本主要的方法
except common.ExternalError, e:
print
print ERROR: %s % (e,)
print
sys.exit(1)
下面是腳本的入口函數main(arg)
def main(argv):
將用戶設定的 Option 存入 OPTIONS 變量中。OPTIONS是一個Python Class, 我們將其理解為一個C Struct或者一個java的封裝即可
def option_handler(o, a):
if o in (-b, --board_config):#in是一個布爾操作符,用來測試左邊的操作數是否包含於右邊的元祖,這裡用來判斷參數o所傳入的值是否包含在(-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
#解析參數
args = common.ParseOptions(argv, __doc__,
extra_opts=b:k:i:d:wfgne:r:l:u:t:z:d:a:s:2,
extra_long_opts=[board_config=,
package_key=,
incremental_from=,
wipe_user_data,
special_factory_reset,
ubifs,
no_prereq,
extra_script=,
preloader=,
logo=,
uboot=,
tee=,
trustonic=,
dsp=,
worker_threads=,
aslr_mode=,
two_step,
],
extra_option_handler=option_handler)
上面解析參數的操作實際上是封裝在了common.py模塊來進行,這裡我們對extra_option_handler=option_handler簡單的解釋一下,在Python中函數是可以直接復制給一個變量的,option_handler是上面定義的一個方法,而這裡並沒有執行,而是直接賦值給了extra_option_handler,而且我們需要注意的是賦值並不會執行option_handler中內容,而是在實際調用的時候才會執行。那麼既然變量可以指向函數,所以一個函數可以接收另外一個函數作為參數。
那麼我們接著來了解函數解析的流程,首先看代碼:
#在python中,getopt模塊是專門用來處理命令行參數的,這裡args是個列表,包含那些沒有-或--的參數,格式如下['target.zip','update.zip'],而opts是個包含元祖的列表,每個元祖是分析出來的格式信息,如[('-u', 'lk.bin'),('-n', ''),('-i', 'base.zip')] ;如果想了解getopt具體的邏輯請參考這篇博文python中getopt的使用。
#解析參數
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=, public_key_suffix=, private_key_suffix=,
device_specific=, extra=] +
list(extra_long_opts))
#那麼我們可以在這裡添加log來查看opts、args中的值
print(begin)
for i in range(len(opts)):
print(opts[i])
print(************)
for i in range(len(args)):
print(args[i])
print(end)
except 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 = 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,)
#環境變量
os.environ[PATH] = (os.path.join(OPTIONS.search_path, bin) +
os.pathsep + os.environ[PATH])
return args
下面是具體log打印的信息:
begin
('-u', 'lk.bin')
('-n', '')
('-i', 'base.zip')
******
target.zip
update.zip
end
那麼參數解析完畢之後,執行流程繼續回到ota_from_target_files中的main函數。我們順著流程接著看。
下面是對完成參數解析的返回值的長度進行一個過濾,這裡固定是2,無論是整包或者差分包的制作。
if len(args) != 2:
common.Usage(__doc__)
sys.exit(1)
#這裡沒有額外的腳本,因此OPTIONS.extra_script的值為None。
if OPTIONS.extra_script is not None:
OPTIONS.extra_script = open(OPTIONS.extra_script).read()
簡單實現Android滾動公告欄
實現的效果,是一個滾動的公告欄,是這樣的:可以看到這個公告欄一方面是滾動,另外一方面是可點擊。實現的思路:1.textView放在ViewFlipper中實現滑動效果(可
Android Design新控件之TextInputLayout(文本輸入布局)
谷歌在推出Android5.0的同時推出了全新的設計Material Design,谷歌為了給我們提供更加規范的MD設計風格的控件,在2015年IO大會上推出了Desig
Android下錄制App操作生成Gif動態圖的全過程
Android App開發完了,自然希望錄個gif做個展示。視頻也可以做展示,但是需要上傳到優酷、土豆等等,而且本來就十幾秒的App演示操作過程,視頻網站的廣告就要一分鐘
ListView實現頂部和底部內容指示器的方法
頂部指示器?這是什麼?好吧,我承認這是我自己想出來的詞,因為我不知道它有什麼學名,究竟是什麼呢?看下這個圖就知道了。這是我們的美工MM畫的,偶的神吶,這雖然很漂亮