Framework基础:应用与Zygote的一次亲密接触

西雅图.png

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的情况。

Paste_Image.png
(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。

Paste_Image.png

    private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList 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,应用数据目录等等参数。

Paste_Image.png

然后数据传出去了,就会在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 abilist= (List) 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());
        }
    }
}

结果.png

出现上面的结果我们必须要配好selinux权限和应用必须是系统应用。
因为这个socket的权限是root:system 660,这个只有root或者system才能访问到。


Paste_Image.png

另外selinux也要配置好,为了临时看效果,我们可以先临时把selinux关掉,执行下面一句就可以了。
setenforce 0

例子传送门:
https://github.com/wenfengtou/ZygoteSocketDemo

你可能感兴趣的:(Framework基础:应用与Zygote的一次亲密接触)