Launcher进程的启动

     继System进程的启动流程第二部分之后,我们来分析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);
		}
	}

	......
}
     这个函数将创建进程的参数放到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('\n') >= 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;
	}

	......
}
     这里的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了。

/*
 * 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!");
    }
}

    Zygote进程同时也处理完,在Socket端口继续等待请求。


     接下来,我们说新创建的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("<pre-initialized>");

		Looper.prepareMainLooper();
		if (sMainThreadHandler == null) {
			sMainThreadHandler = new Handler();
		}

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

		if (false) {
			Looper.myLooper().setMessageLogging(new
				LogPrinter(Log.DEBUG, "ActivityThread"));
		}
		Looper.loop();

		if (Process.supportsProcesses()) {
			throw new RuntimeException("Main thread loop unexpectedly exited");
		}

		thread.detach();
		String name = (thread.mInitialApplication != null)
			? thread.mInitialApplication.getPackageName()
			: "<unknown>";
		Slog.i(TAG, "Main thread of " + name + " is now exiting");
	}

	......
}
      从这里我们可以看出,这个函数首先会在进程中创建一个ActivityThread对象:
ActivityThread thread = new ActivityThread();  
     然后进入主线程消息循环中:

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

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

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


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值