Android进程-zygote进程

一,zygote进程

zygote进程的父进程是init,zygote也是所有应用的父进程,也是system_server进程的父进程。

 

1.1  Zygote系统源码组成

1)     Zygote.java(frameworks/base/core/java/com/android/internal/os/)

提供访问vm的zygote接口,主要是包装Linux系统的fork,以 一个新的vm实例进程。

2)     ZygoteConnection.java (frameworks/base/core/java/com/android/internal/os/)

Zygote的socket连接管理及其参数解析,AMS建立应用进程的请求是通过socket发送命令参数给zygote。

3)     ZygoteInit.java(frameworks/base/core/java/com/android/internal/os/)

Zygote系统的main函数入口。

 

1.2  Zygote的启动

System/core/rootdir/init.rc中会把具体的zygote*.rc文件import进来:

import /init.${ro.zygote}.rc

这里根据不同的硬件平台加载不同的.rc,可以参看multilibbuild:http://blog.csdn.net/lin20044140410/article/details/79265521

 

以init.zygote64.rc为例,启动命令如下:

service zygote /system/bin/app_process64-Xzygote /system/bin --zygote --start-system-server

   class main

socket zygotestream 660 root system

其中的关键字service:通知init进程创建一个名为zygote的进程,此zygote进程要执行的程序路径是system/bin/app_process64,后面是传递给app_process程序的参数。

关键字class:指定class类型是main。

关键字socket:表示这个zygote进程需要一个名称为zygote的socket资源,    系统启动后,会在/dev/socket/ 目录下看到一个名为zygote的文件。

 

App_process程序对应源码:frameworks/base/cmds/app_process/其中app_main.cpp的main函数是入口函数。

1)具体分析启动脚本:

在init.rc中,是以service的形式来启动zygote进程,在解析init.rc文件时,会调用service::start函数来启动zygote,也就是解析其中的service命令。具体代码:

Android/system/core/init/service.cpp
bool Service::Start() {
……
pid_t pid = fork();
    if (pid == 0) {
        umask(077);

        for (const auto& ei : envvars_) {
            add_environment(ei.name.c_str(), ei.value.c_str());
        }

        for (const auto& si : sockets_) {
            int socket_type = ((si.type == "stream" ? SOCK_STREAM :
                                (si.type == "dgram" ? SOCK_DGRAM :
                                 SOCK_SEQPACKET)));
            const char* socketcon =
                !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();

            int s = create_socket(si.name.c_str(), socket_type, si.perm,
                                  si.uid, si.gid, socketcon);
            if (s >= 0) {
                PublishSocket(si.name, s);
            }
        }
		
	}
}

每个service命令都会让init进程调用fork函数来创建一个新的进程,在新的进程中会处理其中的socket选项,对于每个socket选项来说,都会通过函数create_socket来在/dev/socket/目录下创建一个文件,

在看create_socket,调用函数socket()创建一个socket,使用文件描述符来描述这个socket。

System/core/init/Util.cpp
int create_socket(const char *name, int type, mode_t perm, uid_t uid,
                  gid_t gid, const char *socketcon){
    struct sockaddr_un addr;
    int fd, ret, savederrno;
char *filecon;
//创建一个socket,unix domain socket,
    fd = socket(PF_UNIX, type, 0);
    if (fd < 0) {
        ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
        return -1;
}
//为socket创建一个类型为AF_UNIX的socket地址addr。
    memset(&addr, 0 , sizeof(addr));
    addr.sun_family = AF_UNIX;
    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
             name);

	ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
	return fd;
}

接着看PublishSocket()函数,将指向socket的文件描述符fd,添加到环境变量中。

System/core/init/Service.h
#define ANDROID_SOCKET_ENV_PREFIX	"ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR		"/dev/socket"

System/core/init/Service.cpp
void Service::PublishSocket(const std::string& name, int fd) const {
    std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
    std::string val = StringPrintf("%d", fd);
    add_environment(key.c_str(), val.c_str());

    /* make sure we don't close-on-exec */
    fcntl(fd, F_SETFD, 0);
}

后面都是通过环境变量ANDROID_SOCKET_socket来获取这个文件描述的值。

 

       2)zygote的入口函数main。

       功能是创建AppRuntime实例,然后调用AppRuntime的start()启动进程。

Frameworks/base/cmds/app_process/App_main.cpp
int main(int argc, char* const argv[]){
//创建AppRuntime实例
	AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
//解析启动参数
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
String8 className;
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
//后面讲进程名字设置为niceName(zygote)
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
}
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
}
//启动zygote,第一个参数是一个className:
    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    }
}

3)zygote的启动函数start()

       调用startVM在zygote中创建一个虚拟机实例。

classAppRuntime : public AndroidRuntime…,AppRuntime继承自AndroidRuntime,runtime的start()方法调用的是AndroidRuntime中的定义。

Frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//启动虚拟机,其中mJavaVM是:JavaVM* mJavaVM;Java虚拟机指针变量,
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
onVmCreated(env);
//用虚拟机实例注册jni函数。
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
}
//根据传入的参数className调用com.android.internal.os.ZygoteInit的main,启动zygote进程。
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        }
    }
    free(slashClassName);
}

ZygoteInit.java的main()函数。

Frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
	try {
        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
    for (int i = 1; i < argv.length; i++) {
        if ("start-system-server".equals(argv[i])) {
            startSystemServer = true;
        } else if (argv[i].startsWith(ABI_LIST_ARG)) {
            abiList = argv[i].substring(ABI_LIST_ARG.length());
        } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
        	socketName = argv[i].substring(SOCKET_NAME_ARG.length());
    	}
}
//创建一个socket接口,
	registerZygoteSocket(socketName);
//预加载一些资源
	preload();
//启动systemServer组件
	startSystemServer(abiList, socketName);
//调用runSelectLoop,进入无线循环,在前面创建的socket接口上等待,等待新的到socket的连接发生,然后从连接中读取请求命令,以孵化新的进程。
	runSelectLoop(abiList);
closeServerSocket();
} (MethodAndArgsCaller caller) {
	caller.run();
}
}

private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
//通过环境变量ANDROID_SOCKET_zygote,获取/dev/socket/zygote文件的文件描述符,
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }
//通过这个socket的文件描述符创建一个LocalServerSocket,然后监听这个socket。
            try {
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                sServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
}

其中预加载资源主要是预装Framework的部分类和资源,分为两类:

1)文本文件framework/base/preload-class中定义的类,这个文本文件是由framework/base/tools/preload子项目编译生成的。

2)加载preload-resources,主要是framework/base/core/res/res/values/arrays.xml中定义的drawable资源,color资源,这些资源通常有个前缀preloaded_***


4)跟zygote进程中的socket实现连接

当启动一个应用时,AMS通过函数Process.start创建一个新的进程,Process.start会通过socket连接到zygote进程,并由zygote进程实现创建应用进程的功能。Process通过函数openZygoteSocketIfNeeded连接到zygote进程中的socket。

Frameworks/base/core/java/android/os/Process.java
static ZygoteState primaryZygoteState;
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
	primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
return primaryZygoteState;
}
public static ZygoteState connect(String socketAddress) throws IOException {
    DataInputStream zygoteInputStream = null;
    BufferedWriter zygoteWriter = null;
final LocalSocket zygoteSocket = new LocalSocket();
try {
//通过LocalSocketAddress实现LocalSocket到LocalServerSocket的连接。
     zygoteSocket.connect(new LocalSocketAddress(socketAddress,
             LocalSocketAddress.Namespace.RESERVED));

     zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
     zygoteWriter = new BufferedWriter(new OutputStreamWriter(
              zygoteSocket.getOutputStream()), 256);
     } catch (IOException ex) {
     try {
    	     zygoteSocket.close();
         } catch (IOException ignore) {
         }
       throw ex;
     }

   String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
   Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);

   return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                    Arrays.asList(abiListString.split(",")));
}

试着去打开socket,如果已经打来了就什么也不做。前面在zygoteInit.java中,提到通过registerZygoteSocket,创建了一个LocalServerSocket实例,这个LocalServerSocket类的构造函数中的参数是一个代表/dev/socket/zygote/文件的文件描述符,所以Process.java所在的进程只要能连接到LocalServerSocket,就可以通过LocalServerSocket中持有的socket文件描述符,实现跟zygote进程通信。在执行LocalSocket.connect()时,创建的LocalSocketAddress实现了到LocalServerSocket的连接,其中LocalSocket就是连接到zygote进程的本地对象,ZygoteState是对这个实现的一个封装,Process.java中实际是通过ZygoteState中输出流BufferedWriter writer往socket中写入请求命令的。


接下来Zygote进程的runSelectLoop()循环中,会接收到创建新的应用进程的请求,

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {

        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

 fds.add(sServerSocket.getFileDescriptor());

 while (true) {

            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }

 }

}

其中zygoteConnection中的runOnce()函数处理创建应用进程的请求。

AMS请求zygote创建一个进程的过程大概是:

1)AMS调用startProcessLocked函数

2)Process.java中的start方法被调用

3)Process.java中的startViaZygote方法被调用,在这个函数中把启动参数存入列表ArrayList<String> argsForZygote

4)构造一个LocalSocket类型的本地socket接口

5)通过该LocalSocket对象构造一个BufferedWriter对象

6)通过BufferedWrite对象把argsForZygote列表中的参数传递给zygote中的LocalServerSocket对象。

7)在zygote端调用Zygote.forkAndSpecialize()汗水和孕育一个新的应用进程。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值