Zgyote是Android中的第一個(gè)art虛擬機(jī),他通過socket的方式與其他進(jìn)程進(jìn)行通信窘行。這里的“其他進(jìn)程”其實(shí)主要是系統(tǒng)進(jìn)程——SystemServer惶看。我們?cè)囈幌伦寫?yīng)用直接與Zgyote進(jìn)行通信,親密接觸下。
一.首先看一下SystemServer是如何跟Zgyote通信的
(1)Zgyote的socket是如何建立的?
在Zygote的main函數(shù)進(jìn)行了Socket的注冊(cè),并且開啟了監(jiān)聽。
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
...........
registerZygoteSocket(socketName);
................
}
執(zhí)行adb shell netstat偏灿,可以看到socket的情況枚荣。
(2)SystemServer如何跟Zgyote通信呢痕支?
在AMS啟動(dòng)一個(gè)新應(yīng)用的時(shí)候花嘶,會(huì)告訴Zgyote:Zgyote老兄隘击,幫我搞起一個(gè)應(yīng)用凶赁。
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
}
所以他是會(huì)調(diào)用Process的start方法來啟動(dòng)新應(yīng)用。
/frameworks/base/core/java/android/os/Process.java
依次經(jīng)過幾個(gè)方法后,最終到達(dá)zygoteSendArgsAndGetResult方法執(zhí)行。zygoteSendArgsAndGetResult會(huì)把啟動(dòng)應(yīng)用的參數(shù)告訴Zygote侈沪。Zygote干完事就把結(jié)果告訴SystemServer。
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
final BufferedWriter writer = zygoteState.writer; //寫參數(shù)給Zygote
final DataInputStream inputStream = zygoteState.inputStream; //用來讀Zygote的回應(yīng)
writer.write(Integer.toString(args.size()));
writer.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
writer.write(arg); //把參數(shù)一行行寫出去
writer.newLine();
}
writer.flush(); //把啟動(dòng)參數(shù)告訴Zygote
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
result.pid = inputStream.readInt(); //讀取Zygote的反應(yīng)
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = inputStream.readBoolean();
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
啟動(dòng)參數(shù)大概有下面幾個(gè)盲泛,主要是入口類ActivityThread,這個(gè)類老厲害了,是所有應(yīng)用的入口類另伍。另外還有uid勺爱,gid,應(yīng)用數(shù)據(jù)目錄等等參數(shù)暴构。
然后數(shù)據(jù)傳出去了晴埂,就會(huì)在Zygote收到,在runSelectLoop收到一個(gè)遠(yuǎn)方的連接恼蓬。
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
..................
boolean done = peers.get(i).runOnce();
.....................
}
進(jìn)而進(jìn)入runOnce方法,調(diào)用forkAndSpecialize完成進(jìn)程的fork操作,哈哈痹愚。
/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
}
一.應(yīng)用是如何跟Zgyote通信的
上面是系統(tǒng)進(jìn)程與Zygote進(jìn)行socket通信,應(yīng)用要怎么跟Zygote通信呢髓抑?我用了反射調(diào)用Process類的openZygoteSocketIfNeeded 方法,簡單通信了一番鸟蟹。下面是簡單例子來獲取cpu的架構(gòu)镐依。
package com.wenfeng.zygotesocketdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "zygotesocketdemotag";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
String abi = "arm64-v8a";
//process 反射調(diào)用android.os.Process類脚翘,獲取openZygoteSocketIfNeeded方法
Class<?> ProcessClazz = Class.forName("android.os.Process");
Method method = ProcessClazz.getDeclaredMethod("openZygoteSocketIfNeeded", String.class);
method.setAccessible(true);
//ZygoteState
Class<?> ZygoteStateClazz = Class.forName("android.os.Process$ZygoteState");
Field abilistfeild=ZygoteStateClazz.getDeclaredField("abiList");
abilistfeild.setAccessible(true);
//連接zygote崇堰,返回一個(gè)ZygoteState的對(duì)象
Object ZygoteStateobj=method.invoke(null,abi);
//獲取ZygoteState的abiList值咨演,他的值就是cpu的架構(gòu)
List<String> abilist= (List<String>) abilistfeild.get(ZygoteStateobj);
for(int i = 0 ;i < abilist.size();i++){
Log.i(TAG,"hehe "+ " "+ abilist.get(i));
}
}catch (Exception e){
e.printStackTrace();
Log.i(TAG,"error="+e.toString());
}
}
}
出現(xiàn)上面的結(jié)果我們必須要配好selinux權(quán)限和應(yīng)用必須是系統(tǒng)應(yīng)用炫惩。
因?yàn)檫@個(gè)socket的權(quán)限是root:system 660,這個(gè)只有root或者system才能訪問到蚣抗。
另外selinux也要配置好,為了臨時(shí)看效果瓮下,我們可以先臨時(shí)把selinux關(guān)掉,執(zhí)行下面一句就可以了翰铡。
setenforce 0