Launcher进程的启动 -电脑资料

电脑资料 时间:2019-01-01 我要投稿
【www.unjs.com - 电脑资料】

    继System进程的启动流程第二部分之后,我们来分析Launcher进程的启动,

Launcher进程的启动

public class Process {	......	public static final int start(final String processClass,		final String niceName,		int uid, int gid, int[] gids,		int debugFlags,		String[] zygoteArgs)	{		if (supportsProcesses()) {			try {				return startViaZygote(processClass, niceName, uid, gid, gids,					debugFlags, zygoteArgs);			} catch (ZygoteStartFailedEx ex) {				......			}		} else {			......			return 0;		}	}	......}
调用startViaZygote函数进一步操作。

public class Process {	......	private static int startViaZygote(final String processClass,			final String niceName,			final int uid, final int gid,			final int[] gids,			int debugFlags,			String[] extraArgs)			throws ZygoteStartFailedEx {		int pid;		synchronized(Process.class) {			ArrayList<string>argsForZygote = new ArrayList<string>();			// --runtime-init, --setuid=, --setgid=,			// and --setgroups= must go first			argsForZygote.add(--runtime-init);			argsForZygote.add(--setuid= + uid);			argsForZygote.add(--setgid= + gid);			if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {				argsForZygote.add(--enable-safemode);			}			if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {				argsForZygote.add(--enable-debugger);			}			if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {				argsForZygote.add(--enable-checkjni);			}			if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {				argsForZygote.add(--enable-assert);			}			//TODO optionally enable debuger			//argsForZygote.add(--enable-debugger);			// --setgroups is a comma-separated list			if (gids != null && gids.length > 0) {				StringBuilder sb = new StringBuilder();				sb.append(--setgroups=);				int sz = gids.length;				for (int i = 0; i < sz; i++) {					if (i != 0) {						sb.append(',');					}					sb.append(gids[i]);				}				argsForZygote.add(sb.toString());			}			if (niceName != null) {				argsForZygote.add(--nice-name= + niceName);			}			argsForZygote.add(processClass);			if (extraArgs != null) {				for (String arg : extraArgs) {					argsForZygote.add(arg);				}			}			pid = zygoteSendArgsAndGetPid(argsForZygote);		}	}	......}</string></string>
这个函数将创建进程的参数放到argsForZygote列表中去,如参数--runtime-init表示要为新创建的进程初始化运行时库,然后调用zygoteSendAndGetPid函数进一步操作。

public class Process {	......	private static int zygoteSendArgsAndGetPid(ArrayList<string>args)			throws ZygoteStartFailedEx {		int pid;		openZygoteSocketIfNeeded();		try {			/**			* See com.android.internal.os.ZygoteInit.readArgumentList()			* Presently the wire format to the zygote process is:			* a) a count of arguments (argc, in essence)			* b) a number of newline-separated argument strings equal to count			*			* After the zygote process reads these it will write the pid of			* the child or -1 on failure.			*/			sZygoteWriter.write(Integer.toString(args.size()));//向Zygote进程发送通信数据			sZygoteWriter.newLine();			int sz = args.size();			for (int i = 0; i < sz; i++) {				String arg = args.get(i);				if (arg.indexOf('') >= 0) {					throw new ZygoteStartFailedEx(						embedded newlines not allowed);				}				sZygoteWriter.write(arg);				sZygoteWriter.newLine();			}			sZygoteWriter.flush();			// Should there be a timeout on this?			pid = sZygoteInputStream.readInt();			if (pid < 0) {				throw new ZygoteStartFailedEx(fork() failed);			}		} catch (IOException ex) {			......		}		return pid;	}	......}</string>
这里的sZygoteWriter是一个Socket写入流,是由openZygoteSocketIfNeeded函数打开的:

public class Process {	......	/**	* Tries to open socket to Zygote process if not already open. If	* already open, does nothing.  May block and retry.	*/	private static void openZygoteSocketIfNeeded()			throws ZygoteStartFailedEx {		int retryCount;		if (sPreviousZygoteOpenFailed) {			/*			* If we've failed before, expect that we'll fail again and			* don't pause for retries.			*/			retryCount = 0;		} else {			retryCount = 10;		}			/*		* See bug #811181: Sometimes runtime can make it up before zygote.		* Really, we'd like to do something better to avoid this condition,		* but for now just wait a bit...		*/		for (int retry = 0			; (sZygoteSocket == null) && (retry < (retryCount + 1))			; retry++ ) {				if (retry > 0) {					try {						Log.i(Zygote, Zygote not up yet, sleeping...);						Thread.sleep(ZYGOTE_RETRY_MILLIS);					} catch (InterruptedException ex) {						// should never happen					}				}				try {					sZygoteSocket = new LocalSocket();//创建一个LocalSocket对象					sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,						LocalSocketAddress.Namespace.RESERVED));//和设备文件/dev/socket/zygote绑定,就相当于与Zygote进程中名称为zygote的Socket建立了连接					sZygoteInputStream						= new DataInputStream(sZygoteSocket.getInputStream());//输入流,以便获得Zygote进程发送过来的通信数据					sZygoteWriter =						new BufferedWriter(						new OutputStreamWriter(						sZygoteSocket.getOutputStream()),//输出流,以便可以向Zygote进程发送通信数据						256);					Log.i(Zygote, Process: zygote socket opened);					sPreviousZygoteOpenFailed = false;					break;				} catch (IOException ex) {					......				}		}		......	}	......}

    Process类有一个类型为LocalSocket的静态成员变量sZygoteSocket,它是Zygote进程中一个名称为zygote的Socket建立连接的。Zygote进程在启动时,会在内部创建一个名称为zygote”的Socket,这个Socket是与设备文件/dev/socket/zygote绑定在一起的。

    这个Socket由frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中的ZygoteInit类在runSelectLoopMode函数侦听的。

    当将数据通过Socket接口发送出去后,就会执行下面这个语句:

done = peers.get(index).runOnce();
这里从peers.get(index)得到的是一个ZygoteConnection对象,表示一个Socket连接,因此,接下来就是调用ZygoteConnection.runOnce函数进一步处理了。

class ZygoteConnection {	......	boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {		String args[];		Arguments parsedArgs = null;		FileDescriptor[] descriptors;		try {			args = readArgumentList();			descriptors = mSocket.getAncillaryFileDescriptors();		} catch (IOException ex) {			......			return true;		}		......		/** the stderr of the most recent request, if avail */		PrintStream newStderr = null;		if (descriptors != null && descriptors.length >= 3) {			newStderr = new PrintStream(				new FileOutputStream(descriptors[2]));		}		int pid;				try {			parsedArgs = new Arguments(args);			applyUidSecurityPolicy(parsedArgs, peer);			applyDebuggerSecurityPolicy(parsedArgs);			applyRlimitSecurityPolicy(parsedArgs, peer);			applyCapabilitiesSecurityPolicy(parsedArgs, peer);			int[][] rlimits = null;			if (parsedArgs.rlimits != null) {				rlimits = parsedArgs.rlimits.toArray(intArray2d);			}			pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,				parsedArgs.gids, parsedArgs.debugFlags, rlimits);		} catch (IllegalArgumentException ex) {			......		} catch (ZygoteSecurityException ex) {			......		}		if (pid == 0) {			// in child			handleChildProc(parsedArgs, descriptors, newStderr);			// should never happen			return true;		} else { /* pid != 0 */			// in parent...pid of < 0 means failure			return handleParentProc(pid, descriptors, parsedArgs);		}	}	......}
真正创建进程的地方就是在这里了:

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,	parsedArgs.gids, parsedArgs.debugFlags, rlimits);
详情请参考Dalvik虚拟机进程和线程的创建过程分析。

    applyRlimitSecurityPolicy用于安全检查,只有System进程和root进程才能请求Zygote进程,让它创建进程。

private static void applyRlimitSecurityPolicy(            Arguments args, Credentials peer)            throws ZygoteSecurityException {        int peerUid = peer.getUid();        if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) {            // All peers with UID other than root or SYSTEM_UID            if (args.rlimits != null) {                throw new ZygoteSecurityException(                        This UID may not specify rlimits.);            }        }    }
还有一处安全问题需要注意,现在uid为0,但是在forkAndSpecializeCommon中fork后,又自降uid了,

电脑资料

Launcher进程的启动》(https://www.unjs.com)。

/* * Utility routine to fork zygote and specialize the child process. */static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer){    pid_t pid;    uid_t uid = (uid_t) args[0];    gid_t gid = (gid_t) args[1];    ArrayObject* gids = (ArrayObject *)args[2];    u4 debugFlags = args[3];    ArrayObject *rlimits = (ArrayObject *)args[4];    int64_t permittedCapabilities, effectiveCapabilities;    if (isSystemServer) {        /*         * Don't use GET_ARG_LONG here for now.  gcc is generating code         * that uses register d8 as a temporary, and that's coming out         * scrambled in the child process.  b/3138621         */        //permittedCapabilities = GET_ARG_LONG(args, 5);        //effectiveCapabilities = GET_ARG_LONG(args, 7);        permittedCapabilities = args[5] | (int64_t) args[6] << 32;        effectiveCapabilities = args[7] | (int64_t) args[8] << 32;    } else {        permittedCapabilities = effectiveCapabilities = 0;    }    if (!gDvm.zygote) {        ......        return -1;    }    ......    pid = fork();    if (pid == 0) {        int err;        ......        err = setgroupsIntarray(gids);        ......        err = setrlimitsFromArray(rlimits);         ......        err = setgid(gid);        ......        err = setuid(uid);        ......        err = setCapabilities(permittedCapabilities, effectiveCapabilities);        ......        enableDebugFeatures(debugFlags);        ......        gDvm.zygote = false;        if (!dvmInitAfterZygote()) {            ......            dvmAbort();        }    } else if (pid > 0) {        /* the parent process */    }    return pid;}
返回到runOnce,我们先来看父进程Zygote的执行路线。

   

private boolean handleParentProc(int pid,            FileDescriptor[] descriptors, Arguments parsedArgs) {        if(pid > 0) {            // Try to move the new child into the peer's process group.            try {                ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid()));            } catch (IOException ex) {                // This exception is expected in the case where                // the peer is not in our session                // TODO get rid of this log message in the case where                // getsid(0) != getsid(peer.getPid())                Log.i(TAG, Zygote: setpgid failed. This is                     + normal if peer is not in our session);            }        }        try {            if (descriptors != null) {                for (FileDescriptor fd: descriptors) {                    ZygoteInit.closeDescriptor(fd);                }            }        } catch (IOException ex) {            Log.e(TAG, Error closing passed descriptors in                     + parent process, ex);        }        try {            mSocketOutStream.writeInt(pid);//向System进程写回pid        } catch (IOException ex) {            Log.e(TAG, Error reading from command socket, ex);            return true;        }        /*         * If the peer wants to use the socket to wait on the         * newly spawned process, then we're all done.         */        if (parsedArgs.peerWait) {            try {                mSocket.close();            } catch (IOException ex) {                Log.e(TAG, Zygote: error closing sockets, ex);            }            return true;        }        return false;    }
还记得,zygoteSendArgsAndGetPid中:

pid = sZygoteInputStream.readInt();
System进程在等待获得Zygote进程发送过来的通信数据,此时可以返回了。

    返回后System进程就可以调用Looper.loop()启动子线程的消息处理机制。如下所示:

class ServerThread extends Thread {@Override    public void run() {        ......        Looper.prepare();        ......        try {            ......			            Slog.i(TAG, Activity Manager);            context = ActivityManagerService.main(factoryTest);            ......            Slog.i(TAG, Package Manager);            pm = PackageManagerService.main(context,                    factoryTest != SystemServer.FACTORY_TEST_OFF);//以后分析            ActivityManagerService.setSystemProcess();            ......            ((ActivityManagerService)ActivityManagerNative.getDefault())                  .systemReady(new Runnable() {              public void run() {                }  	    });              ......        } catch (RuntimeException e) {            Slog.e(System, Failure starting core service, e);        }        ......        Looper.loop();        Slog.d(TAG, System ServerThread is exiting!);    }}

    接下来,我们说新创建的Launcher进程,也就是Zygote进程创建的子进程。

class ZygoteConnection {	......	private void handleChildProc(Arguments parsedArgs,			FileDescriptor[] descriptors, PrintStream newStderr)			throws ZygoteInit.MethodAndArgsCaller {		......		if (parsedArgs.runtimeInit) {			RuntimeInit.zygoteInit(parsedArgs.remainingArgs);		} else {			......		}	}	......}
public class RuntimeInit {	......	public static final void zygoteInit(String[] argv)			throws ZygoteInit.MethodAndArgsCaller {		// TODO: Doing this here works, but it seems kind of arbitrary. Find		// a better place. The goal is to set it up for applications, but not		// tools like am.		System.setOut(new AndroidPrintStream(Log.INFO, System.out));		System.setErr(new AndroidPrintStream(Log.WARN, System.err));		commonInit();		zygoteInitNative();		int curArg = 0;		for ( /* curArg */ ; curArg < argv.length; curArg++) {			String arg = argv[curArg];			if (arg.equals(--)) {				curArg++;				break;			} else if (!arg.startsWith(--)) {				break;			} else if (arg.startsWith(--nice-name=)) {				String niceName = arg.substring(arg.indexOf('=') + 1);				Process.setArgV0(niceName);			}		}		if (curArg == argv.length) {			Slog.e(TAG, Missing classname argument to RuntimeInit!);			// let the process exit			return;		}		// Remaining arguments are passed to the start class's static main		String startClass = argv[curArg++];		String[] startArgs = new String[argv.length - curArg];		System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);		invokeStaticMain(startClass, startArgs);	}	......}
zygoteInitNative开启了子线程的Binder线程池,请参考System进程的启动流程第一部分。

    invokeStaticMain也参考System进程的启动流程第一部分。开始执行android.app.ActivityThread类的main函数。

public final class ActivityThread {	......	public static final void main(String[] args) {		SamplingProfilerIntegration.start();		Process.setArgV0(从这里我们可以看出,这个函数首先会在进程中创建一个ActivityThread对象:

   

ActivityThread thread = new ActivityThread();
然后进入主线程消息循环中:

Looper.prepareMainLooper();Looper.loop();

    下一节Home界面的启动中我们将分析,如下代码

ActivityThread thread = new ActivityThread();		thread.attach(false);

最新文章