Android上app_process啟動java程序
Java程式是跨平臺的,由JVM虛擬機器執行位元組碼。Android應用程式開發也是Java,但是都是執行在Context環境下的。獨立的Java程式能夠在Android上獨立執行?
這裡不介紹Android啟動過程中,app_process從哪個程序fork處理,也不介紹app_process啟動App的過程。僅介紹app_process啟動純Java程式的相關知識。
一、HelloWorld示例
1. 源程式
編寫一個hellworld 的Java程式,並且編譯成.class檔案,簡單得沒啥可說的。
public class Helloworld {
public static void main(String[]args){
System.out.println("Hello, I am started by app_process!");
}
}
Android對Java虛擬機器做了修改,即使用自己的dalvik虛擬機器(後來的ART)。因此,.class的位元組碼在Dalvik虛擬機器上是不能執行的。Android Platform tool為我們提供了生成Android上可執行jar(Dex)工具:dx。編譯命令如下:
//編譯,這裡主要是Platform tool上用的是Java 7,所以顯式指定1.7
javac -source 1.7 -target 1.7 C:\Users \Venscor\Desktop\app_process\dump.java
//生成dex,當然生成jar在Android上也是可執行的
dx --dex --output=C:\Users\Venscor\Desktop\app_process\Hellworld.dex Helloworld.class
2. 執行
app_process引數格式如下:
app_process [vm-options] cmd-dir [options] start-class-name [main-options]
app_process執行引數居然沒有help,萬惡的開發者。這塊要麼查資料,要麼看原始碼。從網上找的對引數解釋如下:
vm-options – VM 選項
cmd-dir –父目錄 (/system/bin)
options –執行的引數 :
–zygote
–start-system-server
–application (api>=14)
–nice-name=nice_proc_name (api>=14)
start-class-name –包含main方法的主類 (com.android.commands.am.Am)
main-options –啟動時候傳遞到main方法中的引數
將我們前面編譯得到的dex(jar)檔案push到/data/local/tmp資料夾下,構建app_process執行引數:
app_process -Djava.class.path=Helloworld.dex /data/local/tmp Helloworld
切換/data/local/tmp目錄下執行,HelloWorld就成功執行啦!
二、被啟動的Java的Pid, Uid與許可權
上面展示了使用app_process在Android啟動獨立的Java程序的Demo。那麼,被啟動的Java程式作為一個獨立的程序,其從何處fork而來,Uid為多少,對應什麼級別許可權就是下面要解決的問題。
為了能夠檢視app_process啟動的Java程式的程序資訊,希望demo程式不立馬執行結束,以便能夠通過ps檢視程序資訊。修改上面的demo程式,變成死迴圈讓程式持久存活,並先後啟動兩個這樣的Java程式。
通過上面程序資訊可以看到,每次Java程式執行時,系統都會給其分配一個pid,並且程序名都是app_process。(至於為什麼要這麼命名,不清楚。。。)
通過追蹤ppid,還能發現啟動的java程序源自何處,即怎麼fork出來的,即:/init–>/sbin/adbd–>/system/bin/sh–>app_process(Java程序),也就是說,啟動的Java程序是從/system/bin/sh(shell)fork出來的。
知道了相應的pid,就可以通過pid檢視程序資訊,對應的shell命令為:cat /proc/[pid]/status.
通過上面資訊可以看到,app_process啟動的Java程式執行的uid是和pid是2000,也就是shell 的Uid,所以app_process啟動的Java程式擁有shell級別的許可權,下面就此來做個驗證。
三、啟動的Java程式擁有的許可權及Uid
adb shell中,dumpsys activity命令是檢視Activity棧資訊的,只有shell許可權(可能有shell許可權也不行,必須Uid為shell,沒有去看)才能呼叫。所以可以通過這個來驗證啟動的Java程式是否真的運行於shell的Uid下,測試原始碼如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class dump {
public static void main(String[]args){
String cmd="dumpsys activity";
System.out.println("Hello, I am started by app_process!");
try {
Process p=Runtime.getRuntime().exec(cmd);
BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream()));
String readLine=br.readLine();
while(readLine!=null){
System.out.println(readLine);
readLine=br.readLine();
}
if(br!=null){
br.close();
}
p.destroy();
p=null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
和前面demo一樣編譯到Android下執行,檢視結果,發現可以正常輸出,說明app_process啟動的Java程式的確具有shell級別的許可權(其實其Uid就是shell)。
總結: 上面說明了app_process啟動Java的相關知識,至於有啥重要用途,後續會陸續給出。