在Android系统里,做应用开发基本没什么进程的概念,Activity,Service都属于应用,在传统的程序开发者,我们都能清楚的知道进程是什么,进程什么时候启动,什么时候结束,但在Android应用里,设计者们屏蔽了这个概念,让你感觉到Android就是由一引起APK包组成,这对一个程序员来说,非常难受,就如WIN32安装程序一样,做了那么多事情,你却不知道他做了什么,将程序拷贝到哪去了,又在注册表里做了些什么,删除时你还必须用卸载程序。所以,要想真正了解Android系统,我们必需要深入,Android属于Linux内核,是一定有进程的概念,而且,无论Unix,Windows,Linux都有进程,Android当然也有。
其实,在Android里,不论是Activity应用,还是Service应用,最终都需要先启动进程,再在进程里做真正的处理。
1. 启动流程图
进程的启动流程如下图:
上图清晰的描述了进程启动至最后加载Activity或Service之前的过程,fork进程之后,走父进程和子进程两个分支,这在Unix和Linux的C程序里很常用,但在Java里没有这个概念。由于最终采用了Zygote的native本地化接口(C,C++)来Fork进程,所以,这里延续了C的处理风格,相信这对Java程序员非常难以理解。
2. 关键流程说明
2.1 Zygote服务器Fork进程
Caller经由ActivityManagerService.startProcessLocked->Process.start -> Process.startViaZygote->Process.zygoteSendArgsAndGetResult,向zygote服务器发送进程创建的参数,并从zygote服务器获取进程创建的返回结果。中间的过程并不复杂,不分析此部分的源代码。
Zygote是Android大名鼎鼎的Java进程孵化器,Zygote在启动后,会注册Zygote套接字服务器,并运行runSelectLoop来侦听客户端的请求。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public ZygoteInit{
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
// 注册套接字服务器
registerZygoteSocket();
...
// 启动SystemServer
if (argv[1].equals("start-system-server")) {
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
// 循环监听Socket请求
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
...
private static void runSelectLoop() throws MethodAndArgsCaller {
ArrayList<filedescriptor> fds = new ArrayList<filedescriptor>();
ArrayList<zygoteconnection> peers = new ArrayList<zygoteconnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
// server socket的index为0,由于不是client,所以,放peers里往一个null,保持index索引的同步。
// 其实,这个没有必要,后面的peers.get(index-1)就行。
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
...
try {
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray); // 阻塞等待所有的套接字
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
// 如果索引为0,表示有新的client请求连接,创建一个新的ZygoteConnection,并加入peers和fds列表中
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
// 如果是客户端Socket有数据,则执行一次操作
boolean done;
done = peers.get(index).runOnce();
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
}
当Zygote服务器通过selectReadable获取到有客户端连接,立即new一个ZygoteConnection连接,并监听到此连接有数据后,调用此连接的runOnce来处理客户端的请求。
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
public class ZygoteConnection ...{
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
// 读取参数列表
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
...
try {
...
// fork进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}
try {
if (pid == 0) {// 子进程处理
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else { // 父进程处理
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
}
Fork完进程之后,如果是父进程,则执行handleParentProc处理,并返回pid等信息给ActivityManagerService保存;如果是子进程,则继续执行,将进程与ActivityThread连接,并处理后续的Activity或Service的启动。
2.2 父进程处理
见源代码:
private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
...
try {
// 向套接字里回写pid和usingWrapper
mSocketOutStream.writeInt(pid);
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error reading from command socket", ex);
return true;
}
return false;
}
从上面的代码可以看出,父进程结束会向客户端套接字回写pid的信息,这样ActivityManagerService就可以收到此回复。上面的套接字是同步通信的,Process.start会等待zygote服务器的回复,并返回给ActivityManagerService.startProcessLocked。
public class ActivityManagerService ...{
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
...
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
...
Slog.i(TAG, buf.toString());
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
synchronized (mPidsSelfLocked) {
// 保存进程信息
this.mPidsSelfLocked.put(startResult.pid, app);
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
} catch (RuntimeException e) {
// XXX do better error recovery.
app.setPid(0);
Slog.e(TAG, "Failure starting process " + app.processName, e);
}
}
}
2.3 子进程处理
子进程进入了handleChildProc,主要是调用了ActivityThread.main函数,创建了一个新的ActivityThread对象,并连接应用。
2.3.1 ActivityThread.attach
frameworks/base/core/java/android/app/ActivityThread.java
public class ActivityThread{
// ApplicationThread继承自ApplicationThreadNative,是一个Binder服务端
private class ApplicationThread extends ApplicationThreadNative {
...
}
...
// 创建应用服务端Binder对象mAppThread
final ApplicationThread mAppThread = new ApplicationThread();
...
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
// 非系统应用
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
// 通过Binder,通知ActivityManagerService,连接应用
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
} else {
...
}
...
}
...
}
通过ActivityServiceProxy,经由Binder,进入ActivityManagerService服务。
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
public class ActivityManagerService ...{
...
// 参数thread,经过Binder调用,已经转换成远程接口,此接口对象可以在ActivityManagerService内部远程访问Activity应用里的thread服务对象
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
...
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
// 根据pid,获取app信息,此信息在父进程Fork完后会保存。
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
...
// 保存app.thread=thread
app.makeActive(thread, mProcessStats);
...
try {
int testMode = IApplicationThread.DEBUG_OFF;
if (mDebugApp != null && mDebugApp.equals(processName)) {
testMode = mWaitForDebugger
? IApplicationThread.DEBUG_WAIT
: IApplicationThread.DEBUG_ON;
app.debugging = true;
if (mDebugTransient) {
mDebugApp = mOrigDebugApp;
mWaitForDebugger = mOrigWaitForDebugger;
}
}
String profileFile = app.instrumentationProfileFile;
ParcelFileDescriptor profileFd = null;
boolean profileAutoStop = false;
if (mProfileApp != null && mProfileApp.equals(processName)) {
mProfileProc = app;
profileFile = mProfileFile;
profileFd = mProfileFd;
profileAutoStop = mAutoStopProfiler;
}
boolean enableOpenGlTrace = false;
if (mOpenGlTraceApp != null && mOpenGlTraceApp.equals(processName)) {
enableOpenGlTrace = true;
mOpenGlTraceApp = null;
}
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
if (mBackupTarget != null && mBackupAppName.equals(processName)) {
isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
|| (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
}
ensurePackageDexOpt(app.instrumentationInfo != null
? app.instrumentationInfo.packageName
: app.info.packageName);
if (app.instrumentationClass != null) {
ensurePackageDexOpt(app.instrumentationClass.getPackageName());
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "
+ processName + " with config " + mConfiguration);
ApplicationInfo appInfo = app.instrumentationInfo != null
? app.instrumentationInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
if (profileFd != null) {
profileFd = profileFd.dup();
}
thread.bindApplication(processName, appInfo, providers,
app.instrumentationClass, profileFile, profileFd, profileAutoStop,
app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
// todo: Yikes! What should we do? For now we will try to
// start another process, but that could easily get us in
// an infinite loop of restarting processes...
Slog.w(TAG, "Exception thrown during bind!", e);
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
startProcessLocked(app, "bind fail", processName);
return false;
}
...
if (normalMode) {
try {
// 尝试启动应用
if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
didSomething = true;
}
} catch (Exception e) {
// 启动应用失败
badApp = true;
}
}
// Find any services that should be running in this process...
if (!badApp) {
//尝试启动服务
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
badApp = true;
}
}
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
// 服务启动失败,则尝试发送广播
try {
didSomething |= sendPendingBroadcastsLocked(app);
} catch (Exception e) {
// If the app died trying to launch the receiver we declare it 'bad'
badApp = true;
}
}
// Check whether the next backup agent is in this process...
if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
// 尝试发送广播失败,则尝试启动备份代理
if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
try {
thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
mBackupTarget.backupMode);
} catch (Exception e) {
Slog.w(TAG, "Exception scheduling backup agent creation: ");
e.printStackTrace();
}
}
...
return true;
}
}
此函数,会先通过pid获取进程的信息,再依次尝试启动应用,启动服务,发送广播和启动备份代理,从上至少,只要有一个启动成功,则后面的动作不再继续处理。由此,我们也知道了,应用、服务、广播放、备份等都与进程启动相关。
到此进程启动完成,接下来就是讨论如何启动应用或服务等了,将在后面的文章中描述。