編輯:關於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()
實現的效果,是一個滾動的公告欄,是這樣的:可以看到這個公告欄一方面是滾動,另外一方面是可點擊。實現的思路:1.textView放在ViewFlipper中實現滑動效果(可
谷歌在推出Android5.0的同時推出了全新的設計Material Design,谷歌為了給我們提供更加規范的MD設計風格的控件,在2015年IO大會上推出了Desig
Android App開發完了,自然希望錄個gif做個展示。視頻也可以做展示,但是需要上傳到優酷、土豆等等,而且本來就十幾秒的App演示操作過程,視頻網站的廣告就要一分鐘
頂部指示器?這是什麼?好吧,我承認這是我自己想出來的詞,因為我不知道它有什麼學名,究竟是什麼呢?看下這個圖就知道了。這是我們的美工MM畫的,偶的神吶,這雖然很漂亮