Zgyote是Android中的第一个art虚拟机,他通过socket的方式与其他进程进行通信。这里的“其他进程”其实主要是系统进程——SystemServer。我们试一下让应用直接与Zgyote进行通信,亲密接触下。
一.首先看一下SystemServer是如何跟Zgyote通信的
(1)Zgyote的socket是如何建立的?
在Zygote的main函数进行了Socket的注册,并且开启了监听。
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
...........
registerZygoteSocket(socketName);
................
}
执行adb shell netstat,可以看到socket的情况。
(2)SystemServer如何跟Zgyote通信呢?
在AMS启动一个新应用的时候,会告诉Zgyote:Zgyote老兄,帮我搞起一个应用。
/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);
}
所以他是会调用Process的start方法来启动新应用。
/frameworks/base/core/java/android/os/Process.java
依次经过几个方法后,最终到达zygoteSendArgsAndGetResult方法执行。zygoteSendArgsAndGetResult会把启动应用的参数告诉Zygote。Zygote干完事就把结果告诉SystemServer。
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
final BufferedWriter writer = zygoteState.writer; //写参数给Zygote
final DataInputStream inputStream = zygoteState.inputStream; //用来读Zygote的回应
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); //把参数一行行写出去
writer.newLine();
}
writer.flush(); //把启动参数告诉Zygote
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
result.pid = inputStream.readInt(); //读取Zygote的反应
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = inputStream.readBoolean();
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
启动参数大概有下面几个,主要是入口类ActivityThread,这个类老厉害了,是所有应用的入口类。另外还有uid,gid,应用数据目录等等参数。
然后数据传出去了,就会在Zygote收到,在runSelectLoop收到一个远方的连接。
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
..................
boolean done = peers.get(i).runOnce();
.....................
}
进而进入runOnce方法,调用forkAndSpecialize完成进程的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);
}
一.应用是如何跟Zgyote通信的
上面是系统进程与Zygote进行socket通信,应用要怎么跟Zygote通信呢?我用了反射调用Process类的openZygoteSocketIfNeeded 方法,简单通信了一番。下面是简单例子来获取cpu的架构。
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 反射调用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,返回一个ZygoteState的对象
Object ZygoteStateobj=method.invoke(null,abi);
//获取ZygoteState的abiList值,他的值就是cpu的架构
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());
}
}
}
出现上面的结果我们必须要配好selinux权限和应用必须是系统应用。
因为这个socket的权限是root:system 660,这个只有root或者system才能访问到。
另外selinux也要配置好,为了临时看效果,我们可以先临时把selinux关掉,执行下面一句就可以了。
setenforce 0