像極客同樣提取Android的Root權限

本文將深刻揭示提取Android ROOT權限的完整過程。這一過程與網上的方法有很大的差別。不少網上提取ROOT權限的方式都是使用別人作好的程序,有的甚至點擊一下按鈕就會自動完成全部的工做。這樣作儘管能夠成功提取ROOT權限,但讀者並不能瞭解其中的原理,並且因爲Android設備的千差萬別,可能並非每一種Android設備均可以很容易找到提取ROOT權限的工具。因此最通用的方法就是儘量利用現成的工具來完成提取ROOT權限的工做。那麼現成的工具備什麼呢?其實主要就是Android源代碼以及Linux內核源代碼。也就是說,大多數工做均可以經過這些源代碼來解決。當了解了這一過程的原理後,若是並無找到合適的提取ROOT權限的工具,就能夠經過本文介紹的方法很容易獲取Android設備的ROOT權限。
本文介紹的提取ROOT權限的方法主要針對Nexus 7,對於其餘Android設備也可使用相似的方法。但必須知足以下兩個條件。

  • Android設備容許進入bootloader模式。有少數的Android設備關閉了bootloader模式,因此沒法刷機。根據筆者的經驗,Google的幾個親兒子(Nexus系列),HTC、三星的Android設備基本都沒問題,其餘廠商的設備就須要具體問題具體分析了。css

  • 能夠找到合適的Recovery。有的Android設備自帶的Recovery因爲功能有限,在刷機上也有一些問題,因此不得不使用第三方的Recovery。一般大廠商生產的Android設備都能找到合適的第三方Recovery。但刷Recovery一般也必須知足第1個條件。android

1.  提取ROOT權限的步驟
資深Android 玩家和喜歡玩「酷」的Android 用戶在Android 手機到手後的第一件事就是提取ROOT 權限,由於Android 設備有了ROOT 權限,就徹底在本身的控制之下了,儘管這樣作會帶來必定的安全隱患,但在他們看來,自由比任何東西都重要。
可能不少人是經過從網上下載的工具提取ROOT 權限的。那麼提取ROOT 權限真的很複雜嗎?No ,其實提取ROOT 權限遠沒有編寫Android 應用複雜,只須要一些簡單的步驟就能夠搞定,固然,若是有編程的基礎,那就會更以爲提取ROOT 權限的過程簡直太「酷」了。那麼在本文先看一下提取ROOT 權限的基本步驟。
1 :刷一個合適的Recovery
對於一部沒有ROOT 權限的Android 設備,將文件複製到系統目錄的方法有以下兩個。
  • 在bootloader模式下複製整個的文件系統。nginx

  • 在recovery模式下將文件複製到Android設備中的指定目錄。程序員


一般複製完整的系統目錄結構會使用第1 種方法,例如,複製整個system 文件系統(system.img )。而要將少許的文件複製到某些文件系統,通常會使用第2 種方法。由於這種方法能夠經過腳本命令複製指定的文件到系統目錄(如/system/xbin ),並且不會影響其餘無關的數據。
讀者可使用官方的Recovery ,也能夠下載第三方的Recovery 。通常第三方的Recovery 會更強大一些。在下一節會詳細介紹如何使用第三方的Recovery
2 :破解su 命令
提取ROOT 權限的關鍵就是執行su 命令。不過Android 系統帶的su 命令在默認狀況下只能由root 用戶調用,因此使用su 命令以前須要先破解su 命令,也就是修改su 源代碼,將檢測調用權限的代碼去掉,若是有必要,再加入知足本身需求的代碼。也就是所,提取ROOT 權限實際上使用的是已經破解了的su 命令。在後面的內容 會詳細介紹如何修改su 源代碼,並從新生成su 命令文件。
3 :製做Recovery 刷機文件(update.zip
要想將破解後的su 命令放到Android 的系統目錄(如/system/bin )目錄中,須要製做Recovery 刷機包,也就是一個普通的zip 壓縮文件。一般文件名爲update.zip 。不過不少高級的Recovery 容許選擇其餘的zip 文件。因此通常Recovery 刷機包能夠起任何文件名。
Recovery 刷機包的內部結構有必定的規則,主要的工做就是編寫updater-script 腳本文件,該腳本文件的詳細編寫過程會在後面的內容 節介紹。
 
4 :執行su 命令提取ROOT 權限
到這一步就水到渠成了,直接執行su 命令,當前的Shell 就擁有root 權限了(Shell 標識符由$ 變成了# )。如今能夠在Shell 中瀏覽只有root 權限才能看到的內容,例如,經過ls /data/data 命令查看/data/data 目錄中的文件和目錄列表。
 
5 :使ROOT 權限更完美
其實第4 步已經成功使當前的Shell 擁有了root 權限,不過還有一點缺陷,就是當進入Android 設備的Shell 時每次都須要執行su 命令才能獲取root 權限,這樣有些麻煩。所以還須要修改配置文件,使得一進入Shell 就能夠馬上擁有root 權限。在後面的內容 會詳細介紹如何修改,以及修改哪些配置文件。

2.  須要一個很酷的recovery
任何一個在Android 設備上成功運行的ROM 都會自帶一個Recovery ,經過Recovery ,能夠將一個zip 格式刷機包中的內容複製到指定的系統目錄。Nexus 7 官方ROM 也帶了一個Recovery 。不過這個Recovery 功能有限,並且zip 文件還須要簽名才能刷機,很麻煩。固然,讀者能夠定製本身的Recovery ,不過定製Recovery 的工做量是很是大的,一般不可能在短期內完成,因此本文暫不作深究,在後續的文章中會專門探討與定製Recovery 相關的問題。既然官方自帶的ROM 不給力,而定製Recovery 又很費勁,那麼最節省時間的方法就是使用第三方的Recovery
如今有不少第三方的Recovery,其中比較著名的是Clockwork Recovery。目前大多數流行的Android設備都有對應的Clockwork RecoveryClockwork Recovery不只功能強大,並且zip格式的刷機包不須要簽名就能夠正常使用。
刷機以前首先應執行下面的命令進入bootloader模式。
adb reboot-bootloader
大概35秒時間,Nexus 7就會自動重啓,並進入bootloader模式。要注意的是,在bootloader模式下adb命令再也不起做用,取而代之的是fastboot命令,要想知道當前PC有多少Android設備處於bootloader模式,可使用下面的命令。固然,若是Android設備處於正常模式下,可使用adb devices顯示當前鏈接到PCAndroid設備列表。
fastboot devices
進入到bootloader模式後就能夠爲所欲爲地刷機了。在本文只介紹如何刷Recovery,後續的文章會深刻講解如何刷各類鏡像文件。假設下載的Recovery鏡像文件是recovery-clockwork-touch-6.0.2.3-grouper.img。在bootloader模式下刷Recovery鏡像文件的命令以下:
fastboot flash recovery recovery-clockwork-touch-6.0.2.3-grouper.img
若是刷機成功,會顯示如圖1所示的信息。

1  成功刷Recovery
bootloader 模式下經過音量上下鍵切換到「Recovery mode 」選擇項(在屏幕右上角顯示),而後按電源鍵,大概等5 秒,Nexus 7 就會進入Clockwork Recovery 。若是想從新啓動Nexus 7 ,並進入正常的模式,能夠選擇Recovery 的「reboot system now 」菜單項,而後按電源鍵便可。若是讀者刷的是帶觸摸功能的Recovery ,只要點擊「reboot system now 」菜單項便可從新啓動Nexus 7 。若是讀者目前處於正常模式下,而且Nexus 7 已經過USB 線與PC 鏈接,可使用下面的命令進入Recovery 模式。
adb reboot recovery
3. su命令源代碼分析
刷完了Recovery 後,就須要將su 文件放到Android 設備中的/system/bin /system/xbin 目錄中,而後直接執行su 命令便可使當前的Shell 得到root 權限(Shell 提示符從$ 變成了# ),之前不少不能作的事也能夠作了,例如,普通用戶不能查看/data/data 目錄中的內容,使用su 命令提取root 權限後也可使用ls 命令查看/data/data 目錄的內容了。

讀者能夠從網上下載合適的su 文件,或直接從Android 源代碼中獲取su 文件。若是Android 源代碼尚未編譯,須要按着1.3.2 節的步驟編譯整個Android 源代碼。成功編譯Android 源代碼後,就能夠在以下的目錄找到編譯好的su 文件。
<Android源代碼本目錄>/out/target/product/generic/system/xbin
實際上這個su 命令徹底能夠知足目前的需求,也就是提取Android 設備當前Shell root 權限。不過先別忙將su 文件弄到Android 設備上。接下來先看一下su 文件的源代碼,瞭解一下su 文件的運行原理以及爲何能在Android 設備上成功執行。
讀者能夠從以下的目錄找到su 命令的源代碼。
<Android源代碼根目錄>/system/extras/su
su 是用C 語言編寫的普通可執行文件,主文件是su.c 。讀者能夠打開該文件看一下su 的源代碼。
su.c文件中除了引用的一些頭文件外,就只有一個main函數,代碼以下:
源代碼文件:<Android源代碼根目錄>/system/extras/su/su.c
#define LOG_TAG "su"… …/* 此處省略了#include … 語句 */int main(int argc, char **argv){ struct passwd *pw; int uid, gid, myuid; /* 獲取用戶ID,只有root和當前的Shell能執行su命令 */ myuid = getuid(); if (myuid != AID_ROOT && myuid != AID_SHELL) { fprintf(stderr,"su: uid %d not allowed to su\n", myuid); return 1; }  if(argc < 2) { uid = gid = 0;} else { /* 根據參數指定的用戶名獲取用戶屬性,若是getpwnam函數返回0,表示參數指定的是用戶ID 而不是用戶名 */ pw = getpwnam(argv[1]);  if(pw == 0) { uid = gid = atoi(argv[1]); } else { uid = pw->pw_uid; gid = pw->pw_gid; } }/*setgid函數要設置一個用戶組ID,使用屬於該用戶組的用戶執行任何文件時都擁有該文件全部者的權限。setuid函數與setgid函數相似,須要設置一個用戶ID。使用該用戶執行任何可執行文件都會擁有該文件全部者的權限。例如,sh命令的全部者是root用戶,而當前登陸用戶是user,這時使用setuid函數設置user的ID後,再執行sh命令,就至關於以root用戶的身份執行sh命令,因此進入新的Shell後就會擁有root權限*/ if(setgid(gid) || setuid(uid)) { fprintf(stderr,"su: permission denied\n"); return 1; }   /* 執行經過命令行參數指定的命令 */ if (argc == 3 ) { if (execlp(argv[2], argv[2], NULL) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } else if (argc > 3) { /* Copy the rest of the args from main. */ char *exec_args[argc - 1]; memset(exec_args, 0, sizeof(exec_args)); memcpy(exec_args, &argv[2], sizeof(exec_args)); if (execvp(argv[2], exec_args) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } /* 執行sh命令進入新的Shell,若是成功執行,當前程序會馬上退出,若是執行失敗,會繼續 執行下面的語句 */ execlp("/system/bin/sh", "sh", NULL);  fprintf(stderr, "su: exec failed\n"); return 1;}

su.c文件的代碼能夠看出,su命令支持多個命令行參數。這些命令行參數分爲以下兩類。
1類:su的第一個參數,該參數指定了要提高權限的用戶ID或用戶名,若是不指定,就是當前的用戶。
2類:其他的參數。表示提高權限後要馬上執行的命令和該命令的參數。
下面都是合法的su命令調用形式。
# su
# su user
# su user ls –al /data/data/
su提高權限的核心有以下兩個。
  • 經過setgid和setuid函數提高權限,也就是使得任何用戶在執行sh命令時都會擁有與sh命令擁有者一樣的權限。因爲sh命令的擁有者是root用戶,因此天然就將新的Shell提高到了root權限。web

  • 經過execlp函數執行sh命令。因爲前面已經調用了setgid和setuid函數,因此執行sh命令會進入新的Shell,而且該Shell與sh命令文件的全部者(root用戶)擁有一樣的權限。執行exit命令會退出擁有root權限的Shell,並從新回到原來沒有root權限的Shell。再次執行exit命令後,就會退出Android Shell,回到Ubuntu Linux的終端。shell


4. 製做第一個Recovery刷機包(編寫腳本文件)

Recovery使用的刷機包就是zip格式的壓縮文件。根據不一樣的需求,刷機包中包含的文件不一樣,一個完整的刷機包很是複雜,不過本節的目的只是將su文件複製到/system/xbin目錄中,因此暫時用不着那麼複雜的刷機包。關於Recovery刷機包的詳細製做過程將在後面跟的章節深刻探討。本文只作最基本的刷機包。
其實要作一個Recovery刷機包並不困難。製做Recovery刷機包以前一般要考慮使用的是哪一個Recovery。例如,本書主要使用了Clockwork Recovery,因此能夠利用Clockwork Recovery中的一些特性。
本文要製做的刷機包中只有兩個目錄:systemMETA-INF。其中system就是編譯Android源代碼後,在<Android源代碼根目錄>/out/target/product/generic目錄 中的system目錄,也是進入Android設備的Shell後看到的「/system」目錄,在該目錄下包含了Android的系統文件,其中包括不少命令文件以及系統應用程序 。不過本文製做的Recovery刷機包沒這麼複雜。因爲只須要將su文件複製到/system/xbin目錄,因此在system目錄中只要有一個xbin子目錄,而且在該目錄中放一個在上一節得到的su文件便可。
可能不少讀者會問,將su文件放到/system/xbin目錄中,Recovery中刷機時就會將su文件複製到Android系統的/system/xbin目錄中嗎?答案很簡單,Recovery固然不知道本身要作什麼,具體要完成什麼工做,如何來完成,玄機全在META-INF目錄中。
META-INF/com/google/android目錄中有一個updater-script腳本文件(純文本文件)和一個update-binary可執行文件。別看這兩個文件一共不到200KB,它們倒是整個Recovery刷機包中最核心的部分。尤爲是update-binary,該文件一般在190KB上下,別看文件尺寸不大,這但是內嵌於Recovery的一種輕量級腳本語言的解析器,而updater-script腳本文件就是使用這種腳本語言寫的。這種腳本語言就是edify。該語言除了定義一些簡單的語句外,還定義了幾十個用於各類操做的函數,例如,複製文件、刪除文件、創建連接等。
Edify語言會在後面的章節介紹,在本文只介紹該語言的幾個經常使用的函數。這些函數的原型、含義及其用法以下:
ui_print
原型:ui_print(msg1, ..., msgN);
含義:該函數用於在Recovery界面輸出字符串。其中msg一、…、msgN表示N個字符串參數,該函數至少須要指定一個參數。若是指定多個參數,會將這些參數值鏈接起來輸出。
用法:ui_print(" hello world ");
run_program
原型:run_program(prog, arg1, .., argN);
含義:該函數用於執行程序,其中prog參數表示要執行的程序文件(要寫完整路徑),arg1argN表示要執行程序的參數。prog參數是必須的,其餘參數都是可選的。
用法:run_program("/sbin/busybox","mount", "/system");
delete
    原型:delete(file1, file2, ..., fileN);
含義:該函數用於刪除一個或多個文件。其中file1file2fileN表示要刪除文件的路徑,至少須要指定一個文件。
用法:delete("/system/xbin/su");
 
package_extract_dir
原型:package_extract_dir(package_path, destination_path);
含義:用於提取刷機包中package_path指定目錄的全部文件到destination_path指定的目錄。其中package_path參數表示刷機包中的目錄,destination_path參數表示目標目錄。
用法:package_extract_dir("system", "/system");
 
set_perm
原型:set_perm(uid, gid, mode, file1, file2, ..., fileN);
含義:用於設置一個或多個文件的權限。其中uid參數表示用戶IDgid參數表示用戶組ID。若是想讓文件的用戶和用戶組都是rootuidgid須要都爲0mode參數表示設置的權限,這個權限與chmod命令設置的權限徹底同樣,例如,若是將一個文件設爲任何用戶均可以讀寫和執行的權限值是0777file1file2fileN表示要設置權限的文件的路徑。
用法:set_perm(0, 0, 0777, "/system/xbin/su");
 
unmount
原型:unmount(mount_point);
含義:用於解除文件系統的掛載。其中mount_point參數表示文件系統。
用法:unmount("/system");
 
本文要編寫的updater-script文件只會使用上面的函數。該腳本文件主要實現以下基本功能。
  • 以讀寫模式掛載/system。編程

  • 刪除舊的su文件。安全

  • 複製新的su文件。微信

  • 修改su文件的權限。架構

  • 卸載/system。


其中掛載/system調用了busybox命令,該命令並不屬於Android。不過該命令十分強大,常被人稱爲Android的瑞士軍刀 busybox是一個開源的命令集合,將多達上百個命令集成在了一個大概2MB的文件中。例如,本文要用的mount命令就是其中之一。儘管Android從本質上也屬於Linux系統,但較其餘Linux系統集成的命令是不多的,因此若是想在Android中執行各類操做,一般就須要將busybox文件複製到Android系統的/system/xbin或其餘存儲命令文件的系統目錄。這樣只須要一個busybox命令就能夠搞定一切。若是讀者想知道busybox到底支持多少命令,只須要直接執行busybox命令便可。

讀者能夠在http://www.busybox.net下載busybox最新版本的源代碼,並按着說明使用交叉編譯器編譯busybox便可(在ARM架構的設備上運行必需要使用交叉編譯器),爲了方便讀者,在隨書光盤中帶了一個編譯好的busybox文件,路徑是/tools/busybox。該文件只能在ARM架構的設備上運行,不能在X86 PC上使用。讀者須要將busybox文件上傳到Android設備的/system/xbin目錄中(須要root權限),並執行 chmod 777 /system/xbin/busybox命令修改其權限後便可執行該命令。

如今看一下updater-script文件的代碼。
ui_print("*********************");ui_print("My First Recovery Update");ui_print("*********************"); ui_print("----Mounting /system ----");# 以讀寫模式掛載/systemrun_program("/sbin/busybox", "mount","-o", "rw", "/system"); ui_print("----Delete /system/xbin/su ----");# 刪除舊的su文件delete("/system/xbin/su");ui_print("- Extracting files");# 將刷機包中system目錄的全部文件複製到/system目錄中的相應位置package_extract_dir("system", "/system");ui_print("----- Setting permissions");# 設置ui命令爲任何用戶均可執行set_perm(0, 0, 0777, "/system/xbin/su");# 卸載/systemunmount("/system");ui_print("finished");
updater-script文件中使用run_program函數調用了busybox命令,並經過該命令執行了mount操做,實際上,至關於在Linux終端執行以下的命令。
 busybox mount –o rw /system
若是執行mount操做時未指定「-o rw」,默認是隻讀掛載,也就是說/system目錄及其子目錄是隻讀的,爲了將/system目錄變成讀寫模式的,須要再次執行以下的命令。
busybox mount –o rw, remount /system
其中「-o rw, remount」中的rwremountmount命令的兩個選項,表示從新將/system目錄mount成可讀寫的。
若是須要修改默認的掛載點對應的路徑,例如,將/system掛載到/my_system目錄(該目錄必須存在),須要使用下面的命令。
busybox mount –o rw /system /my_system
如今updater-script腳本文件已經編寫完了,接下來還須要一個用於解析updater-script腳本文件的update-binary程序。讀者能夠從網上找一個Recovery刷機包,將其中的update-binary文件放到本身的刷機包中,或到<Android源代碼根目錄> /out/target/product/generic/system/bin目錄尋找一個updater文件,將該文件更名爲update-binary便可。其實updater文件也是Android源代碼的某個子程序編譯生成的,在後面深刻探討Recovery時再詳細分析updater的實現原理。
如今Recovery刷機包的全部文件(suupdater-scriptupdate-binary)都搞定了,接下來完成最後一步,就是將systemMETA-INF目錄用zip格式壓縮(壓縮文件名任意取)。在下一節會介紹如何將這個zip格式文件中的內容刷到Nexus 7上。爲了方便讀者,在隨書光盤上已經帶了這個zip壓縮文件(/recovery/su_update.zip),讀者能夠直接將該文件刷到Android設備上(除了Nexus 7外,其餘使用Clockwork RecoveryAndroid設備也可使用該刷機包)。
 
可能有的讀者會發現,updater-script腳本中執行了/sbin目錄中的busybox命令,但成功啓動Android後進入Shell,在/sbin目錄中並無發現busybox命令,這究竟是真麼回事呢?

實際上,busybox命令的確存在,但卻不在system文件系統裏,而是在recovery文件系統中。在Android正常啓動後,實際上掛載的是system文件系統。而進入Recovery模式後,系統會自動掛載recovery文件系統,而掛載system文件系統要在updater-script腳本文件中經過相應的函數來完成(如本文使用了run_program函數調用了busybox命令掛載system文件系統)。system和recovery文件系統都有一個sbin目錄,但目錄中的文件是不同的。實際上,經過Android源代碼編譯生成的Recovery鏡像 是不包含busybox命令的,而Clockwork Recovery的busybox命令是本身添加的,也就是說,其餘的Recovery鏡像並不必定包含busybox命令,因此本文編寫的updater-script腳本文件只適合Clockwork Recovery。若是要想使用其餘的Recovery,或者將busybox命令添加到Recovery鏡像中,或者使用edify腳本語言的mount函數掛載相應的文件系統(如/system、/data等)。在後面的章節會詳細介紹Recovery鏡像文件的生成,以及如何修改現成的Recovery鏡像。

5. 首次經過DIY方式提取ROOT權限
到如今爲止,一切準備工做都已經完成了,如今只剩下最後一步,就是提取Nexus 7root權限。不過此次提取root權限徹底是DIY方式的,這也顯得更有意義,由於做爲程序員來講,瞭解其中的過程比結果更重要。
如今須要用USB線鏈接Nexus 7PC,而後將上一節生成的zip文件上傳到Nexus 7SD卡中。若是不想上傳也沒問題。一般在Recovery模式下選擇sideloader上傳方式,而不是事先上傳到Nexus 7上,由於這樣Nexus 7不須要在正常模式和Recovery模式之間來回切換,這也更適合須要頻繁調試和刷機的程序員。
如今進入Nexus 7Recovery模式(正常模式下執行adb reboot recovery命令),若是讀者已經將zip壓縮文件(這裏假設爲update.zip)上傳到Nexus 7SD卡中,選擇「install zip from sdcard」(第2個菜單項),而後繼續選擇zip文件便可刷機。若是未將zip文件上傳,選擇「install zip from sideload」菜單項,而後Recovery模式會處於等待狀態。如今adbsideload上傳模式能夠工做了。在Linux終端輸入adb sideload update.zip命令,便可成功刷機。在刷機的過程當中會看到updater-script腳本文件中使用ui_print函數輸出的字符串。updater-script腳本文件中的命令執行完後,就會回到Recovery主界面。而後選擇「reboot system now」(第1個菜單項)重啓Nexus 7
Nexus 7進入正常模式後,進入Shell,這時尚未執行su命令,因此當前Shell仍然沒有root權限,如今執行su命令,會看到Shell提示符從「$」變爲「#」,這說明當前Shell已經擁有了root權限。如今作一些之前作不了的事,例如,使用ls /data/data命令查看系統的data目錄,如今能夠成功列出該目錄中全部的子目錄(都是系統應用或普通應用創建的私有目錄)。

6. 上傳Android應用到/system/app目錄

儘管提取root權限的目的不少,有的是爲了調用Linux的命令,有的是爲了直接訪問系統的數據。不過本章提取root權限的目的主要是爲了將系統應用的APK文件上傳到/system/app目錄中,以即可以在真機的環境下測試系統應用。
如今進入Android設備的Shell,並執行su命令提取root權限,而後看看/system/app目錄是否可寫。有的Android設備在掛載system文件系統時,/system及其子目錄是隻讀的,若是是這種狀況,執行以下的命令便可將/system目錄及其子目錄變成可讀寫的。
mount –o rw,remount /system
如今退出Android設備的Shell,從新回到Linux終端。而後找一個APK文件。但有一個問題,當執行adb shell命令進入Android設備的Shell時,一開始並無root權限,須要執行su命令才能提權,因此就不能直接使用adb push命令將APK文件上傳到/system/app目錄中(由於沒有root權限,該目錄是隻讀的)。解決的方法也很簡單,就是首先使用adb push命令將APK文件上傳到Android設備的SD卡上,而後在執行adb shell的同時執行su命令提權。例如,下面的命令能夠在Linux終端下刪除Android設備中/system/app目錄中的Test.apk文件。
adb shell su -c "mount -o remount,rw /system | rm -f /system/app/Test.apk "
下面的命令將SD卡根目錄中的Test.apk文件複製到Android設備的/system/app目錄中。
adb su -c "mount -o remount,rw /system | cp /sdcard/Test.apk /system/app/Test.apk "
爲了方便,讀者能夠編寫一個帶參數的Shell腳本文件,將adb pushadb shell命令在一塊兒使用。

- EOF -

推薦閱讀   點擊標題可跳轉

一、連Python產生器(Generator)的原理都解釋不了,還敢說Python用了5年?

二、牛掰了!鴻蒙與Android完美融合,將鴻蒙設備當Android設備用

三、【鴻蒙學院】鴻蒙App開發直播學員提問與回答

四、【鴻蒙學院】鴻蒙IDE:下載、安裝DevEco Studio

五、 Python高效編程之88條軍規(2):你真的會格式化字符串嗎?


關注「極客起源」公衆號,加星標,不錯過精彩技術乾貨


本文分享自微信公衆號 - 極客起源(geekculture)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索