Zygote孵化应用进程过程的源码分析

在Zygote进程启动过程的源代码分析一文中介绍到,Zygote是java世界的开创者,所有的java应用进程都是通过Zygote孵化出来的。我们知道在Android应用程序框架层中,ActivityManagerService组件负责管理Android应用程序的创建,ActivityManagerService也是运行在独立的进程中,System Server进程启动过程源码分析中介绍了System Server进程是如果通过开启线程来启动各种服务,ActivityManagerService也是System Server启动的服务之一。当系统决定要在一个新的进程中启动一个Activity或者Service时,
它就会创建一个新的进程,ActivityManagerService通过调用startProcessLocked函数来为应用程序启动新的进程。
在Android系统中,应用程序是由Launcher启动起来的,其实,Launcher本身也是一个应用程序,其它的应用程序安装后,就会Launcher的界面上出现一个相应的图标,点击这个图标时,Launcher就会启动对应的应用程序,这种启动方式的特点是会启动一个新的进程来加载相应的Activity。Android应用程序框架层创建的应用程序入口函数是ActivityThread.main,并且支持Binder进程间通信机制。在Launcher启动过程中,会将应用程序的相关信息保存在标签tag中,在Launcher的onActivityResult函数中,根据请求码
REQUEST_CREATE_SHORTCUT来响应应用图标的加载完成:

//Launcher.java
private void completeAddShortcut(Intent data, CellLayout.CellInfo cellInfo) {
	cellInfo.screen = mWorkspace.getCurrentScreen(); //获取当前工作区间的屏幕信息
	if (!findSingleSlot(cellInfo)) return;
    //根据data和图标单元信息产生相应的快捷图标信息
	final ShortcutInfo info = mModel.addShortcut(this, data, cellInfo, false); 

	if (!mRestoring) { 
		final View view = createShortcut(info);//创建快捷图标
		mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1,isWorkspaceLocked());//添加到当前屏幕中
	}
}

//Launcher.java
View createShortcut(ShortcutInfo info) {
	return createShortcut(R.layout.application,(ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info);
}

//Launcher.java
View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
	TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false);//装载布局文件

	favorite.setCompoundDrawablesWithIntrinsicBounds(null,new FastBitmapDrawable(info.getIcon(mIconCache)),null, null);
	favorite.setText(info.title);//设置应用名称
	favorite.setTag(info);//将应用的相关信息保存在tag标签中
	favorite.setOnClickListener(this);//设置单击监听事件
	return favorite;
}

在完成应用图标加载时,根据请求码REQUEST_PICK_APPLICATION做进一步处理:

//Launcher.java
void completeAddApplication(Context context, Intent data, CellLayout.CellInfo cellInfo) {
	cellInfo.screen = mWorkspace.getCurrentScreen();
	if (!findSingleSlot(cellInfo)) return;

	final ShortcutInfo info = mModel.getShortcutInfo(context.getPackageManager(),
			data, context);

	if (info != null) {
	    //为应用程序设置启动信息
		info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
		info.container = ItemInfo.NO_ID;
		mWorkspace.addApplicationShortcut(info, cellInfo, isWorkspaceLocked());
	} else {
		Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data);
	}
}

//ShortcutInfo.java
final void setActivity(ComponentName className, int launchFlags) {
	intent = new Intent(Intent.ACTION_MAIN);//动作为:Intent.ACTION_MAIN
	intent.addCategory(Intent.CATEGORY_LAUNCHER);
	intent.setComponent(className);//设置启动的相关类名
	intent.setFlags(launchFlags);//设置启动标志
	itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
}
当点击launcher上的应用图标时,图标将响应单击事件:

//Launcher.java
public void onClick(View v) {
	Object tag = v.getTag();
	if (tag instanceof ShortcutInfo) {
		// Open shortcut
		final Intent intent = ((ShortcutInfo) tag).intent;
		int[] pos = new int[2];
		v.getLocationOnScreen(pos);
		intent.setSourceBounds(new Rect(pos[0], pos[1],pos[0] + v.getWidth(), pos[1] + v.getHeight()));
		startActivitySafely(intent, tag);
	} else if (tag instanceof FolderInfo) {
		handleFolderClick((FolderInfo) tag);
	} else if (v == mHandleView) {
		if (isAllAppsVisible()) {
			closeAllApps(true);
		} else {
			showAllApps(true);
		}
	}
}
//Launcher.java
void startActivitySafely(Intent intent, Object tag) {
	intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	try {
		startActivity(intent); //启动activity
	} catch (ActivityNotFoundException e) {
		Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
		Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
	} catch (SecurityException e) {
		Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
		Log.e(TAG, "Launcher does not have the permission to launch " + intent +
				". Make sure to create a MAIN intent-filter for the corresponding activity " +
				"or use the exported attribute for this activity. "
				+ "tag="+ tag + " intent=" + intent, e);
	}
}
这里的intent包含的信息为:
action = "android.intent.action.Main",
category="android.intent.category.LAUNCHER"
flag = FLAG_ACTIVITY_NEW_TASK
//Activity.java
public void startActivity(Intent intent) {
     startActivityForResult(intent, -1);
}
//Activity.java
public void startActivityForResult(Intent intent, int requestCode) {
	if (mParent == null) {
	    //mMainThread.getApplicationThread() 此时为Launcher的主线程
		Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(
				this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode);
		if (ar != null) {
			mMainThread.sendActivityResult(
				mToken, mEmbeddedID, requestCode, ar.getResultCode(),
				ar.getResultData());
		}
		if (requestCode >= 0) {
			mStartedActivity = true;
		}
	} else {
		mParent.startActivityFromChild(this, intent, requestCode);
	}
}
mInstrumentation是Activity类的成员变量,它的类型是Intrumentation,它用来监控应用程序和系统的交互。mMainThread也是Activity类的成员变量,它的类型是ActivityThread,它代表的是应用程序的主线程,这里通过mMainThread.getApplicationThread获得它里面的ApplicationThread成员变量,它是一个Binder对象,
ActivityManagerService会使用它来和ActivityThread来进行进程间通信,mToken也是Activity类的成员变量,它是一个Binder对象的远程接口。

//Instrumentation.java
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, 
	Activity target,Intent intent, int requestCode) {
	IApplicationThread whoThread = (IApplicationThread) contextThread;
	if (mActivityMonitors != null) {
		synchronized (mSync) {
			final int N = mActivityMonitors.size();
			for (int i=0; i<N; i++) {
				final ActivityMonitor am = mActivityMonitors.get(i);
				if (am.match(who, null, intent)) {
					am.mHits++;
					if (am.isBlocking()) {
						return requestCode >= 0 ? am.getResult() : null;
					}
					break;
				}
			}
		}
	}
	try {
		int result = ActivityManagerNative.getDefault().startActivity(whoThread, intent,
					intent.resolveTypeIfNeeded(who.getContentResolver()),
					null, 0, token, target != null ? target.mEmbeddedID : null,
					requestCode, false, false);
		checkStartActivityResult(result, intent);
	} catch (RemoteException e) {
	}
	return null;
}
这里的ActivityManagerNative.getDefault返回ActivityManagerService的代理对象,即ActivityManagerProxy。
//ActivityManagerProxy.java
public int startActivity(IApplicationThread caller, Intent intent,
		String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
		IBinder resultTo, String resultWho,
		int requestCode, boolean onlyIfNeeded,
		boolean debug) throws RemoteException {
	Parcel data = Parcel.obtain();
	Parcel reply = Parcel.obtain();
	data.writeInterfaceToken(IActivityManager.descriptor);
	data.writeStrongBinder(caller != null ? caller.asBinder() : null);
	intent.writeToParcel(data, 0);
	data.writeString(resolvedType);
	data.writeTypedArray(grantedUriPermissions, 0);
	data.writeInt(grantedMode);
	data.writeStrongBinder(resultTo);
	data.writeString(resultWho);
	data.writeInt(requestCode);
	data.writeInt(onlyIfNeeded ? 1 : 0);
	data.writeInt(debug ? 1 : 0);
	mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
	reply.readException();
	int result = reply.readInt();
	reply.recycle();
	data.recycle();
	return result;
}
通过Binder通信调用ActivityManagerService的startActivity函数
//ActivityManagerService.java
public final int startActivity(IApplicationThread caller,
		Intent intent, String resolvedType, Uri[] grantedUriPermissions,
		int grantedMode, IBinder resultTo,
		String resultWho, int requestCode, boolean onlyIfNeeded,
		boolean debug) {
	return mMainStack.startActivityMayWait(caller, intent, resolvedType,
			grantedUriPermissions, grantedMode, resultTo, resultWho,
			requestCode, onlyIfNeeded, debug, null, null);
}

//ActivityStack.java
final int startActivityMayWait(IApplicationThread caller,Intent intent, String resolvedType, 
	Uri[] grantedUriPermissions,int grantedMode, IBinder resultTo,
		String resultWho, int requestCode, boolean onlyIfNeeded,
		boolean debug, WaitResult outResult, Configuration config) {
	// Refuse possible leaked file descriptors
	if (intent != null && intent.hasFileDescriptors()) {
		throw new IllegalArgumentException("File descriptors passed in Intent");
	}
	//保存应用启动的主Activity类
	boolean componentSpecified = intent.getComponent() != null;
	
	// Don't modify the client's object!
	intent = new Intent(intent);

	// Collect information about the target of the Intent.
	ActivityInfo aInfo;
	try {
		ResolveInfo rInfo =AppGlobals.getPackageManager().resolveIntent(
					intent, resolvedType,PackageManager.MATCH_DEFAULT_ONLY| ActivityManagerService.STOCK_PM_FLAGS);
		aInfo = rInfo != null ? rInfo.activityInfo : null;
	} catch (RemoteException e) {
		aInfo = null;
	}

	if (aInfo != null) {
		// Store the found target back into the intent, because now that
		// we have it we never want to do this again.  For example, if the
		// user navigates back to this point in the history, we should
		// always restart the exact same activity.
		intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));

		// Don't debug things in the system process
		if (debug) {
			if (!aInfo.processName.equals("system")) {
				mService.setDebugApp(aInfo.processName, true, false);
			}
		}
	}

	synchronized (mService) {
		int callingPid;
		int callingUid;
		if (caller == null) {
			callingPid = Binder.getCallingPid();
			callingUid = Binder.getCallingUid();
		} else {
			callingPid = callingUid = -1;
		}
		
		mConfigWillChange = config != null&& mService.mConfiguration.diff(config) != 0;
		if (DEBUG_CONFIGURATION) Slog.v(TAG,"Starting activity when config will change = " + mConfigWillChange);
		final long origId = Binder.clearCallingIdentity();

		if (mMainStack && aInfo != null &&(aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
			// This may be a heavy-weight process!  Check to see if we already
			// have another, different heavy-weight process running.
			if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
				if (mService.mHeavyWeightProcess != null &&
						(mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
						!mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
					int realCallingPid = callingPid;
					int realCallingUid = callingUid;
					if (caller != null) {
						ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
						if (callerApp != null) {
							realCallingPid = callerApp.pid;
							realCallingUid = callerApp.info.uid;
						} else {
							Slog.w(TAG, "Unable to find app for caller " + caller+ " (pid=" + realCallingPid + ") when starting: "+ intent.toString());
							return START_PERMISSION_DENIED;
						}
					}
					
					IIntentSender target = mService.getIntentSenderLocked(
							IActivityManager.INTENT_SENDER_ACTIVITY, "android",
							realCallingUid, null, null, 0, intent,
							resolvedType, PendingIntent.FLAG_CANCEL_CURRENT
							| PendingIntent.FLAG_ONE_SHOT);
					
					Intent newIntent = new Intent();
					if (requestCode >= 0) {
						// Caller is requesting a result.
						newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
					}
					newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,new IntentSender(target));
					if (mService.mHeavyWeightProcess.activities.size() > 0) {
						ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
						newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,hist.packageName);
						newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,hist.task.taskId);
					}
					newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,aInfo.packageName);
					newIntent.setFlags(intent.getFlags());
					newIntent.setClassName("android",HeavyWeightSwitcherActivity.class.getName());
					intent = newIntent;
					resolvedType = null;
					caller = null;
					callingUid = Binder.getCallingUid();
					callingPid = Binder.getCallingPid();
					componentSpecified = true;
					try {
						ResolveInfo rInfo =
							AppGlobals.getPackageManager().resolveIntent(intent, null,PackageManager.MATCH_DEFAULT_ONLY| ActivityManagerService.STOCK_PM_FLAGS);
						aInfo = rInfo != null ? rInfo.activityInfo : null;
					} catch (RemoteException e) {
						aInfo = null;
					}
				}
			}
		}
		
		int res = startActivityLocked(caller, intent, resolvedType,
				grantedUriPermissions, grantedMode, aInfo,
				resultTo, resultWho, requestCode, callingPid, callingUid,
				onlyIfNeeded, componentSpecified);
		
		if (mConfigWillChange && mMainStack) {
			// If the caller also wants to switch to a new configuration,
			// do so now.  This allows a clean switch, as we are waiting
			// for the current activity to pause (so we will not destroy
			// it), and have not yet started the next activity.
			mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
					"updateConfiguration()");
			mConfigWillChange = false;
			if (DEBUG_CONFIGURATION) Slog.v(TAG,
					"Updating to new configuration after starting activity.");
			mService.updateConfigurationLocked(config, null);
		}
		
		Binder.restoreCallingIdentity(origId);
		
		if (outResult != null) {
			outResult.result = res;
			if (res == IActivityManager.START_SUCCESS) {
				mWaitingActivityLaunched.add(outResult);
				do {
					try {
						mService.wait();
					} catch (InterruptedException e) {
					}
				} while (!outResult.timeout && outResult.who == null);
			} else if (res == IActivityManager.START_TASK_TO_FRONT) {
				ActivityRecord r = this.topRunningActivityLocked(null);
				if (r.nowVisible) {
					outResult.timeout = false;
					outResult.who = new ComponentName(r.info.packageName, r.info.name);
					outResult.totalTime = 0;
					outResult.thisTime = 0;
				} else {
					outResult.thisTime = SystemClock.uptimeMillis();
					mWaitingActivityVisible.add(outResult);
					do {
						try {
							mService.wait();
						} catch (InterruptedException e) {
						}
					} while (!outResult.timeout && outResult.who == null);
				}
			}
		}
		return res;
	}
}

//ActivityStack.java
final int startActivityLocked(IApplicationThread caller,
		Intent intent, String resolvedType,
		Uri[] grantedUriPermissions,
		int grantedMode, ActivityInfo aInfo, IBinder resultTo,
		String resultWho, int requestCode,
		int callingPid, int callingUid, boolean onlyIfNeeded,
		boolean componentSpecified) {

	int err = START_SUCCESS;

	ProcessRecord callerApp = null;
	if (caller != null) {
		callerApp = mService.getRecordForAppLocked(caller);
		if (callerApp != null) {
			callingPid = callerApp.pid;
			callingUid = callerApp.info.uid;
		} else {
			Slog.w(TAG, "Unable to find app for caller " + caller+ " (pid=" + callingPid + ") when starting: " + intent.toString());
			err = START_PERMISSION_DENIED;
		}
	}

	if (err == START_SUCCESS) {
		Slog.i(TAG, "Starting: " + intent + " from pid "+ (callerApp != null ? callerApp.pid : callingPid));
	}

	ActivityRecord sourceRecord = null;
	ActivityRecord resultRecord = null;
	if (resultTo != null) {
		int index = indexOfTokenLocked(resultTo);
		if (DEBUG_RESULTS) Slog.v(
			TAG, "Sending result to " + resultTo + " (index " + index + ")");
		if (index >= 0) {
			sourceRecord = (ActivityRecord)mHistory.get(index);
			if (requestCode >= 0 && !sourceRecord.finishing) {
				resultRecord = sourceRecord;
			}
		}
	}
	int launchFlags = intent.getFlags();
	if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
			&& sourceRecord != null) {
		// Transfer the result target from the source activity to the new
		// one being started, including any failures.
		if (requestCode >= 0) {
			return START_FORWARD_AND_REQUEST_CONFLICT;
		}
		resultRecord = sourceRecord.resultTo;
		resultWho = sourceRecord.resultWho;
		requestCode = sourceRecord.requestCode;
		sourceRecord.resultTo = null;
		if (resultRecord != null) {
			resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
		}
	}

	if (err == START_SUCCESS && intent.getComponent() == null) {
		// We couldn't find a class that can handle the given Intent.
		// That's the end of that!
		err = START_INTENT_NOT_RESOLVED;
	}

	if (err == START_SUCCESS && aInfo == null) {
		// We couldn't find the specific class specified in the Intent.
		// Also the end of the line.
		err = START_CLASS_NOT_FOUND;
	}

	if (err != START_SUCCESS) {
		if (resultRecord != null) {
			sendActivityResultLocked(-1,resultRecord, resultWho, requestCode,Activity.RESULT_CANCELED, null);
		}
		return err;
	}

	final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,
			callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
	if (perm != PackageManager.PERMISSION_GRANTED) {
		if (resultRecord != null) {
			sendActivityResultLocked(-1,resultRecord, resultWho, requestCode,Activity.RESULT_CANCELED, null);
		}
		String msg = "Permission Denial: starting " + intent.toString()+ " from " + callerApp + " (pid=" + callingPid
				+ ", uid=" + callingUid + ")"+ " requires " + aInfo.permission;
		Slog.w(TAG, msg);
		throw new SecurityException(msg);
	}

	if (mMainStack) {
		if (mService.mController != null) {
			boolean abort = false;
			try {
				// The Intent we give to the watcher has the extra data
				// stripped off, since it can contain private information.
				Intent watchIntent = intent.cloneFilter();
				abort = !mService.mController.activityStarting(watchIntent,aInfo.applicationInfo.packageName);
			} catch (RemoteException e) {
				mService.mController = null;
			}

			if (abort) {
				if (resultRecord != null) {
					sendActivityResultLocked(-1,resultRecord, resultWho, requestCode,Activity.RESULT_CANCELED, null);
				}
				// We pretend to the caller that it was really started, but
				// they will just get a cancel result.
				return START_SUCCESS;
			}
		}
	}
	
	ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
			intent, resolvedType, aInfo, mService.mConfiguration,
			resultRecord, resultWho, requestCode, componentSpecified);

	if (mMainStack) {
		if (mResumedActivity == null|| mResumedActivity.info.applicationInfo.uid != callingUid) {
			if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
				PendingActivityLaunch pal = new PendingActivityLaunch();
				pal.r = r;
				pal.sourceRecord = sourceRecord;
				pal.grantedUriPermissions = grantedUriPermissions;
				pal.grantedMode = grantedMode;
				pal.onlyIfNeeded = onlyIfNeeded;
				mService.mPendingActivityLaunches.add(pal);
				return START_SWITCHES_CANCELED;
			}
		}
	
		if (mService.mDidAppSwitch) {
			// This is the second allowed switch since we stopped switches,
			// so now just generally allow switches.  Use case: user presses
			// home (switches disabled, switch to home, mDidAppSwitch now true);
			// user taps a home icon (coming from home so allowed, we hit here
			// and now allow anyone to switch again).
			mService.mAppSwitchesAllowedTime = 0;
		} else {
			mService.mDidAppSwitch = true;
		}
	 
		mService.doPendingActivityLaunchesLocked(false);
	}
	
	return startActivityUncheckedLocked(r, sourceRecord,grantedUriPermissions, grantedMode, onlyIfNeeded, true);
}

//ActivityStack.java
final int startActivityUncheckedLocked(ActivityRecord r,
		ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
		int grantedMode, boolean onlyIfNeeded, boolean doResume) {
	final Intent intent = r.intent;
	final int callingUid = r.launchedFromUid;

	int launchFlags = intent.getFlags();
	
	// We'll invoke onUserLeaving before onPause only if the launching
	// activity did not explicitly state that this is an automated launch.
	mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
	if (DEBUG_USER_LEAVING) Slog.v(TAG,"startActivity() => mUserLeaving=" + mUserLeaving);
	// false
	if (!doResume) {
		r.delayedResume = true;
	}
	//notTop = null
	ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)!= 0 ? r : null;
	// false
	if (onlyIfNeeded) {
		ActivityRecord checkedCaller = sourceRecord;
		if (checkedCaller == null) {
			checkedCaller = topRunningNonDelayedActivityLocked(notTop);
		}
		if (!checkedCaller.realActivity.equals(r.realActivity)) {
			// Caller is not the same as launcher, so always needed.
			onlyIfNeeded = false;
		}
	}

	if (sourceRecord == null) {
		// This activity is not being started from another...  in this
		// case we -always- start a new task.
		if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
			Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "+ intent);
			launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
		}
	} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
		// The original activity who is starting us is running as a single
		// instance...  this new activity it is starting must go on its
		// own task.
		launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
	} else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK){
		// The activity being started is a single instance...  it always
		// gets launched into its own task.
		launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
	}

	if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
		// For whatever reason this activity is being launched into a new
		// task...  yet the caller has requested a result back.  Well, that
		// is pretty messed up, so instead immediately send back a cancel
		// and let the new task continue launched as normal without a
		// dependency on its originator.
		Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
		sendActivityResultLocked(-1,r.resultTo, r.resultWho, r.requestCode,Activity.RESULT_CANCELED, null);
		r.resultTo = null;
	}

	boolean addingToTask = false;
	if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
			(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
			|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
			|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
		// If bring to front is requested, and no result is requested, and
		// we can find a task that was started with this same
		// component, then instead of launching bring that one to the front.
		if (r.resultTo == null) {
			// See if there is a task to bring to the front.  If this is
			// a SINGLE_INSTANCE activity, there can be one and only one
			// instance of it in the history, and it is always in its own
			// unique task, so we do a special search.
			ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
					? findTaskLocked(intent, r.info): findActivityLocked(intent, r.info);
			if (taskTop != null) {
				if (taskTop.task.intent == null) {
					// This task was started because of movement of
					// the activity based on affinity...  now that we
					// are actually launching it, we can assign the
					// base intent.
					taskTop.task.setIntent(intent, r.info);
				}
				// If the target task is not in the front, then we need
				// to bring it to the front...  except...  well, with
				// SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
				// to have the same behavior as if a new instance was
				// being started, which means not bringing it to the front
				// if the caller is not itself in the front.
				ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
				if (curTop.task != taskTop.task) {
					r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
					boolean callerAtFront = sourceRecord == null|| curTop.task == sourceRecord.task;
					if (callerAtFront) {
						// We really do want to push this one into the
						// user's face, right now.
						moveTaskToFrontLocked(taskTop.task, r);
					}
				}
				// If the caller has requested that the target task be
				// reset, then do so.
				if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
					taskTop = resetTaskIfNeededLocked(taskTop, r);
				}
				if (onlyIfNeeded) {
					// We don't need to start a new activity, and
					// the client said not to do anything if that
					// is the case, so this is it!  And for paranoia, make
					// sure we have correctly resumed the top activity.
					if (doResume) {
						resumeTopActivityLocked(null);
					}
					return START_RETURN_INTENT_TO_CALLER;
				}
				if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
						|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
						|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
					// In this situation we want to remove all activities
					// from the task up to the one being started.  In most
					// cases this means we are resetting the task to its
					// initial state.
					ActivityRecord top = performClearTaskLocked(taskTop.task.taskId, r, launchFlags, true);
					if (top != null) {
						if (top.frontOfTask) {
							// Activity aliases may mean we use different
							// intents for the top activity, so make sure
							// the task now has the identity of the new
							// intent.
							top.task.setIntent(r.intent, r.info);
						}
						logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
						top.deliverNewIntentLocked(callingUid, r.intent);
					} else {
						// A special case: we need to
						// start the activity because it is not currently
						// running, and the caller has asked to clear the
						// current task to have this activity at the top.
						addingToTask = true;
						// Now pretend like this activity is being started
						// by the top of its task, so it is put in the
						// right place.
						sourceRecord = taskTop;
					}
				} else if (r.realActivity.equals(taskTop.task.realActivity)) {
					// In this case the top activity on the task is the
					// same as the one being launched, so we take that
					// as a request to bring the task to the foreground.
					// If the top activity in the task is the root
					// activity, deliver this new intent to it if it
					// desires.
					if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
							&& taskTop.realActivity.equals(r.realActivity)) {
						logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
						if (taskTop.frontOfTask) {
							taskTop.task.setIntent(r.intent, r.info);
						}
						taskTop.deliverNewIntentLocked(callingUid, r.intent);
					} else if (!r.intent.filterEquals(taskTop.task.intent)) {
						// In this case we are launching the root activity
						// of the task, but with a different intent.  We
						// should start a new instance on top.
						addingToTask = true;
						sourceRecord = taskTop;
					}
				} else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
					// In this case an activity is being launched in to an
					// existing task, without resetting that task.  This
					// is typically the situation of launching an activity
					// from a notification or shortcut.  We want to place
					// the new activity on top of the current task.
					addingToTask = true;
					sourceRecord = taskTop;
				} else if (!taskTop.task.rootWasReset) {
					// In this case we are launching in to an existing task
					// that has not yet been started from its front door.
					// The current task has been brought to the front.
					// Ideally, we'd probably like to place this new task
					// at the bottom of its stack, but that's a little hard
					// to do with the current organization of the code so
					// for now we'll just drop it.
					taskTop.task.setIntent(r.intent, r.info);
				}
				if (!addingToTask) {
					// true
					if (doResume) {
						resumeTopActivityLocked(null);
					}
					return START_TASK_TO_FRONT;
				}
			}
		}
	}
	if (r.packageName != null) {
		// If the activity being launched is the same as the one currently
		// at the top, then we need to check if it should only be launched
		// once.
		ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
		if (top != null && r.resultTo == null) {
			if (top.realActivity.equals(r.realActivity)) {
				if (top.app != null && top.app.thread != null) {
					if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
						|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
						|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
						logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
						// For paranoia, make sure we have correctly
						// resumed the top activity.
						if (doResume) {
							resumeTopActivityLocked(null);
						}
						if (onlyIfNeeded) {
							// We don't need to start a new activity, and
							// the client said not to do anything if that
							// is the case, so this is it!
							return START_RETURN_INTENT_TO_CALLER;
						}
						top.deliverNewIntentLocked(callingUid, r.intent);
						return START_DELIVERED_TO_TOP;
					}
				}
			}
		}

	} else {
		if (r.resultTo != null) {
			sendActivityResultLocked(-1,r.resultTo, r.resultWho, r.requestCode,Activity.RESULT_CANCELED, null);
		}
		return START_CLASS_NOT_FOUND;
	}
	boolean newTask = false;
	// Should this be considered a new task?
	if (r.resultTo == null && !addingToTask&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
		// todo: should do better management of integers.
		mService.mCurTask++;
		if (mService.mCurTask <= 0) {
			mService.mCurTask = 1;
		}
		r.task = new TaskRecord(mService.mCurTask, r.info, intent,(r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
		if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r+ " in new task " + r.task);
		newTask = true;
		if (mMainStack) {
			mService.addRecentTaskLocked(r.task);
		}
		
	} else if (sourceRecord != null) {
		if (!addingToTask &&(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
			// In this case, we are adding the activity to an existing
			// task, but the caller has asked to clear that task if the
			// activity is already running.
			ActivityRecord top = performClearTaskLocked(sourceRecord.task.taskId, r, launchFlags, true);
			if (top != null) {
				logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
				top.deliverNewIntentLocked(callingUid, r.intent);
				// For paranoia, make sure we have correctly
				// resumed the top activity.
				if (doResume) {
					resumeTopActivityLocked(null);
				}
				return START_DELIVERED_TO_TOP;
			}
		} else if (!addingToTask &&(launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
			// In this case, we are launching an activity in our own task
			// that may already be running somewhere in the history, and
			// we want to shuffle it to the front of the stack if so.
			int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
			if (where >= 0) {
				ActivityRecord top = moveActivityToFrontLocked(where);
				logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
				top.deliverNewIntentLocked(callingUid, r.intent);
				if (doResume) {
					resumeTopActivityLocked(null);
				}
				return START_DELIVERED_TO_TOP;
			}
		}
		// An existing activity is starting this new activity, so we want
		// to keep the new one in the same task as the one that is starting
		// it.
		r.task = sourceRecord.task;
		if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r+ " in existing task " + r.task);

	} else {
		// This not being started from an existing activity, and not part
		// of a new task...  just put it in the top task, though these days
		// this case should never happen.
		final int N = mHistory.size();
		ActivityRecord prev =N > 0 ? (ActivityRecord)mHistory.get(N-1) : null;
		r.task = prev != null? prev.task: new TaskRecord(mService.mCurTask, r.info, intent,(r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
		if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new guessed " + r.task);
	}

	if (grantedUriPermissions != null && callingUid > 0) {
		for (int i=0; i<grantedUriPermissions.length; i++) {
			mService.grantUriPermissionLocked(callingUid, r.packageName,grantedUriPermissions[i], grantedMode, r.getUriPermissionsLocked());
		}
	}
	mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,intent, r.getUriPermissionsLocked());
	if (newTask) {
		EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
	}
	logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
	startActivityLocked(r, newTask, doResume);
	return START_SUCCESS;
}

Activity的启动方式有四种,其余三种分别是ActivityInfo.LAUNCH_SINGLE_INSTANCE、ActivityInfo.LAUNCH_SINGLE_TASK和ActivityInfo.LAUNCH_SINGLE_TOP
//ActivityStack.java    
private final void startActivityLocked(ActivityRecord r, boolean newTask,boolean doResume) {
	final int NH = mHistory.size();
	int addPos = -1;
	if (!newTask) {
		// If starting in an existing task, find where that is...
		boolean startIt = true;
		for (int i = NH-1; i >= 0; i--) {
			ActivityRecord p = (ActivityRecord)mHistory.get(i);
			if (p.finishing) {
				continue;
			}
			if (p.task == r.task) {
				// Here it is!  Now, if this is not yet visible to the
				// user, then just add it without starting; it will
				// get started when the user navigates back to it.
				addPos = i+1;
				if (!startIt) {
					mHistory.add(addPos, r);
					r.inHistory = true;
					r.task.numActivities++;
					mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,r.info.screenOrientation, r.fullscreen);
					if (VALIDATE_TOKENS) {
						mService.mWindowManager.validateAppTokens(mHistory);
					}
					return;
				}
				break;
			}
			if (p.fullscreen) {
				startIt = false;
			}
		}
	}

	// Place a new activity at top of stack, so it is next to interact
	// with the user.
	if (addPos < 0) {
		addPos = NH;
	}
	
	// If we are not placing the new activity frontmost, we do not want
	// to deliver the onUserLeaving callback to the actual frontmost
	// activity
	if (addPos < NH) {
		mUserLeaving = false;
		if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false");
	}
	
	// Slot the activity into the history stack and proceed
	mHistory.add(addPos, r);
	r.inHistory = true;
	r.frontOfTask = newTask;
	r.task.numActivities++;
	if (NH > 0) {
		// We want to show the starting preview window if we are
		// switching to a new task, or the next activity's process is
		// not currently running.
		boolean showStartingIcon = newTask;
		ProcessRecord proc = r.app;
		if (proc == null) {
			proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
		}
		if (proc == null || proc.thread == null) {
			showStartingIcon = true;
		}
		if (DEBUG_TRANSITION) Slog.v(TAG,"Prepare open transition: starting " + r);
		if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
			mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
			mNoAnimActivities.add(r);
		} else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
			mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
			mNoAnimActivities.remove(r);
		} else {
			mService.mWindowManager.prepareAppTransition(newTask? WindowManagerPolicy.TRANSIT_TASK_OPEN: WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
			mNoAnimActivities.remove(r);
		}
		mService.mWindowManager.addAppToken(addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
		boolean doShow = true;
		if (newTask) {
			// Even though this activity is starting fresh, we still need
			// to reset it to make sure we apply affinities to move any
			// existing activities from other tasks in to it.
			// If the caller has requested that the target task be
			// reset, then do so.
			if ((r.intent.getFlags() &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
				resetTaskIfNeededLocked(r, r);
				doShow = topRunningNonDelayedActivityLocked(null) == r;
			}
		}
		if (SHOW_APP_STARTING_PREVIEW && doShow) {
			// Figure out if we are transitioning from another activity that is
			// "has the same starting icon" as the next one.  This allows the
			// window manager to keep the previous window it had previously
			// created, if it still had one.
			ActivityRecord prev = mResumedActivity;
			if (prev != null) {
				// We don't want to reuse the previous starting preview if:
				// (1) The current activity is in a different task.
				if (prev.task != r.task) prev = null;
				// (2) The current activity is already displayed.
				else if (prev.nowVisible) prev = null;
			}
			mService.mWindowManager.setAppStartingWindow(r, r.packageName, r.theme, r.nonLocalizedLabel,r.labelRes, r.icon, prev, showStartingIcon);
		}
	} else {
		// If this is the first activity, don't do any fancy animations,
		// because there is nothing for it to animate on top of.
		mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,r.info.screenOrientation, r.fullscreen);
	}
	if (VALIDATE_TOKENS) {
		mService.mWindowManager.validateAppTokens(mHistory);
	}

	if (doResume) {
		resumeTopActivityLocked(null);
	}
}

//ActivityStack.java
final boolean resumeTopActivityLocked(ActivityRecord prev) {
	// Find the first activity that is not finishing.
	ActivityRecord next = topRunningActivityLocked(null);

	// Remember how we'll process this pause/resume situation, and ensure
	// that the state is reset however we wind up proceeding.
	final boolean userLeaving = mUserLeaving;
	mUserLeaving = false;

	if (next == null) {
		// There are no more activities!  Let's just start up the
		// Launcher...
		if (mMainStack) {
			return mService.startHomeActivityLocked();
		}
	}

	next.delayedResume = false;
	
	// If the top activity is the resumed one, nothing to do.
	if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
		// Make sure we have executed any pending transitions, since there
		// should be nothing left to do at this point.
		mService.mWindowManager.executeAppTransition();
		mNoAnimActivities.clear();
		return false;
	}

	// If we are sleeping, and there is no resumed activity, and the top
	// activity is paused, well that is the state we want.
	if ((mService.mSleeping || mService.mShuttingDown)&& mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
		// Make sure we have executed any pending transitions, since there
		// should be nothing left to do at this point.
		mService.mWindowManager.executeAppTransition();
		mNoAnimActivities.clear();
		return false;
	}
	
	// The activity may be waiting for stop, but that is no longer
	// appropriate for it.
	mStoppingActivities.remove(next);
	mWaitingVisibleActivities.remove(next);

	if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);

	// If we are currently pausing an activity, then don't do anything
	// until that is done.
	if (mPausingActivity != null) {
		if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
		return false;
	}
	// Okay we are now going to start a switch, to 'next'.  We may first
	// have to pause the current activity, but this is an important point
	// where we have decided to go to 'next' so keep track of that.
	// XXX "App Redirected" dialog is getting too many false positives
	// at this point, so turn off for now.
	if (false) {
		if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
			long now = SystemClock.uptimeMillis();
			final boolean inTime = mLastStartedActivity.startTime != 0&& (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
			final int lastUid = mLastStartedActivity.info.applicationInfo.uid;
			final int nextUid = next.info.applicationInfo.uid;
			if (inTime && lastUid != nextUid&& lastUid != next.launchedFromUid && mService.checkPermission(
							android.Manifest.permission.STOP_APP_SWITCHES,-1, next.launchedFromUid)!= PackageManager.PERMISSION_GRANTED) {
				mService.showLaunchWarningLocked(mLastStartedActivity, next);
			} else {
				next.startTime = now;
				mLastStartedActivity = next;
			}
		} else {
			next.startTime = SystemClock.uptimeMillis();
			mLastStartedActivity = next;
		}
	}
	
	// We need to start pausing the current activity so the top one
	// can be resumed...
	if (mResumedActivity != null) {
		if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
		startPausingLocked(userLeaving, false);
		return true;
	}

	if (prev != null && prev != next) {
		if (!prev.waitingVisible && next != null && !next.nowVisible) {
			prev.waitingVisible = true;
			mWaitingVisibleActivities.add(prev);
			if (DEBUG_SWITCH) Slog.v(TAG, "Resuming top, waiting visible to hide: " + prev);
		} else {
			// The next activity is already visible, so hide the previous
			// activity's windows right now so we can show the new one ASAP.
			// We only do this if the previous is finishing, which should mean
			// it is on top of the one being resumed so hiding it quickly
			// is good.  Otherwise, we want to do the normal route of allowing
			// the resumed activity to be shown so we can decide if the
			// previous should actually be hidden depending on whether the
			// new one is found to be full-screen or not.
			if (prev.finishing) {
				mService.mWindowManager.setAppVisibility(prev, false);
				if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "+ prev 
					+ ", waitingVisible="+ (prev != null ? prev.waitingVisible : null)+ ", nowVisible=" + next.nowVisible);
			} else {
				if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: "+ prev + ", waitingVisible="
					+ (prev != null ? prev.waitingVisible : null)+ ", nowVisible=" + next.nowVisible);
			}
		}
	}

	// We are starting up the next activity, so tell the window manager
	// that the previous one will be hidden soon.  This way it can know
	// to ignore it when computing the desired screen orientation.
	if (prev != null) {
		if (prev.finishing) {
			if (DEBUG_TRANSITION) Slog.v(TAG,"Prepare close transition: prev=" + prev);
			if (mNoAnimActivities.contains(prev)) {
				mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
			} else {
				mService.mWindowManager.prepareAppTransition(prev.task == next.task
						? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: WindowManagerPolicy.TRANSIT_TASK_CLOSE);
			}
			mService.mWindowManager.setAppWillBeHidden(prev);
			mService.mWindowManager.setAppVisibility(prev, false);
		} else {
			if (DEBUG_TRANSITION) Slog.v(TAG,"Prepare open transition: prev=" + prev);
			if (mNoAnimActivities.contains(next)) {
				mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
			} else {
				mService.mWindowManager.prepareAppTransition(prev.task == next.task
						? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: WindowManagerPolicy.TRANSIT_TASK_OPEN);
			}
		}
		if (false) {
			mService.mWindowManager.setAppWillBeHidden(prev);
			mService.mWindowManager.setAppVisibility(prev, false);
		}
	} else if (mHistory.size() > 1) {
		if (DEBUG_TRANSITION) Slog.v(TAG,"Prepare open transition: no previous");
		if (mNoAnimActivities.contains(next)) {
			mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
		} else {
			mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
		}
	}

	if (next.app != null && next.app.thread != null) {
		if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
		// This activity is now becoming visible.
		mService.mWindowManager.setAppVisibility(next, true);
		ActivityRecord lastResumedActivity = mResumedActivity;
		ActivityState lastState = next.state;
		mService.updateCpuStats();
		next.state = ActivityState.RESUMED;
		mResumedActivity = next;
		next.task.touchActiveTime();
		mService.updateLruProcessLocked(next.app, true, true);
		updateLRUListLocked(next);

		// Have the window manager re-evaluate the orientation of
		// the screen based on the new activity order.
		boolean updated = false;
		if (mMainStack) {
			synchronized (mService) {
				Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
						mService.mConfiguration,next.mayFreezeScreenLocked(next.app) ? next : null);
				if (config != null) {
					next.frozenBeforeDestroy = true;
				}
				updated = mService.updateConfigurationLocked(config, next);
			}
		}
		if (!updated) {
			// The configuration update wasn't able to keep the existing
			// instance of the activity, and instead started a new one.
			// We should be all done, but let's just make sure our activity
			// is still at the top and schedule another run if something
			// weird happened.
			ActivityRecord nextNext = topRunningActivityLocked(null);
			if (DEBUG_SWITCH) Slog.i(TAG,"Activity config changed during resume: " + next+ ", new next: " + nextNext);
			if (nextNext != next) {
				// Do over!
				mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
			}
			if (mMainStack) {
				mService.setFocusedActivityLocked(next);
			}
			ensureActivitiesVisibleLocked(null, 0);
			mService.mWindowManager.executeAppTransition();
			mNoAnimActivities.clear();
			return true;
		}
		
		try {
			// Deliver all pending results.
			ArrayList a = next.results;
			if (a != null) {
				final int N = a.size();
				if (!next.finishing && N > 0) {
					if (DEBUG_RESULTS) Slog.v(TAG, "Delivering results to " + next+ ": " + a);
					next.app.thread.scheduleSendResult(next, a);
				}
			}
			if (next.newIntents != null) {
				next.app.thread.scheduleNewIntent(next.newIntents, next);
			}
			EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,System.identityHashCode(next),next.task.taskId, next.shortComponentName);
			next.app.thread.scheduleResumeActivity(next,mService.isNextTransitionForward());
			pauseIfSleepingLocked();

		} catch (Exception e) {
			// Whoops, need to restart this activity!
			next.state = lastState;
			mResumedActivity = lastResumedActivity;
			Slog.i(TAG, "Restarting because process died: " + next);
			if (!next.hasBeenLaunched) {
				next.hasBeenLaunched = true;
			} else {
				if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
					mService.mWindowManager.setAppStartingWindow(
							next, next.packageName, next.theme,next.nonLocalizedLabel,next.labelRes, next.icon, null, true);
				}
			}
			startSpecificActivityLocked(next, true, false);
			return true;
		}

		// From this point on, if something goes wrong there is no way
		// to recover the activity.
		try {
			next.visible = true;
			completeResumeLocked(next);
		} catch (Exception e) {
			// If any exception gets thrown, toss away this
			// activity and try the next one.
			Slog.w(TAG, "Exception thrown during resume of " + next, e);
			requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,"resume-exception");
			return true;
		}
		// Didn't need to use the icicle, and it is now out of date.
		next.icicle = null;
		next.haveState = false;
		next.stopped = false;

	} else {
		// Whoops, need to restart this activity!
		if (!next.hasBeenLaunched) {
			next.hasBeenLaunched = true;
		} else {
			if (SHOW_APP_STARTING_PREVIEW) {
				mService.mWindowManager.setAppStartingWindow(next, next.packageName, next.theme,
					next.nonLocalizedLabel,next.labelRes, next.icon, null, true);
			}
			if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
		}
		startSpecificActivityLocked(next, true, true);
	}
	return true;
}

//ActivityStack.java
private final void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {
	// Is this activity's application already running?
	ProcessRecord app = mService.getProcessRecordLocked(r.processName,r.info.applicationInfo.uid);
	if (r.launchTime == 0) {
		r.launchTime = SystemClock.uptimeMillis();
		if (mInitialStartTime == 0) {
			mInitialStartTime = r.launchTime;
		}
	} else if (mInitialStartTime == 0) {
		mInitialStartTime = SystemClock.uptimeMillis();
	}
	
	if (app != null && app.thread != null) {
		try {
			realStartActivityLocked(r, app, andResume, checkConfig);
			return;
		} catch (RemoteException e) {
			Slog.w(TAG, "Exception when starting activity "+ r.intent.getComponent().flattenToShortString(), e);
		}
	}

	mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false);
}

//ActivityManagerService.java
final ProcessRecord startProcessLocked(String processName,
		ApplicationInfo info, boolean knownToBeDead, int intentFlags,
		String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
	ProcessRecord app = getProcessRecordLocked(processName, info.uid);
	// We don't have to do anything more if:
	// (1) There is an existing application record; and
	// (2) The caller doesn't think it is dead, OR there is no thread
	//     object attached to it so we know it couldn't have crashed; and
	// (3) There is a pid assigned to it, so it is either starting or
	//     already running.
	if (DEBUG_PROCESSES) Slog.v(TAG, "startProcess: name=" + processName
			+ " app=" + app + " knownToBeDead=" + knownToBeDead
			+ " thread=" + (app != null ? app.thread : null)
			+ " pid=" + (app != null ? app.pid : -1));
	if (app != null && app.pid > 0) {
		if (!knownToBeDead || app.thread == null) {
			// We already have the app running, or are waiting for it to
			// come up (we have a pid but not yet its thread), so keep it.
			if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
			return app;
		} else {
			// An application record is attached to a previous process,
			// clean it up now.
			if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app);
			handleAppDiedLocked(app, true);
		}
	}

	String hostingNameStr = hostingName != null ? hostingName.flattenToShortString() : null;
	
	if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
		// If we are in the background, then check to see if this process
		// is bad.  If so, we will just silently fail.
		if (mBadProcesses.get(info.processName, info.uid) != null) {
			if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid + "/" + info.processName);
			return null;
		}
	} else {
		// When the user is explicitly starting a process, then clear its
		// crash count so that we won't make it bad until they see at
		// least one crash dialog again, and make the process good again
		// if it had been bad.
		if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid + "/" + info.processName);
		mProcessCrashTimes.remove(info.processName, info.uid);
		if (mBadProcesses.get(info.processName, info.uid) != null) {
			EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,info.processName);
			mBadProcesses.remove(info.processName, info.uid);
			if (app != null) {
				app.bad = false;
			}
		}
	}
	
	if (app == null) {
		app = newProcessRecordLocked(null, info, processName);
		mProcessNames.put(processName, info.uid, app);
	} else {
		// If this is a new package in the process, add the package to the list
		app.addPackage(info.packageName);
	}

	// If the system is not ready yet, then hold off on starting this
	// process until it is.
	if (!mProcessesReady&& !isAllowedWhileBooting(info)&& !allowWhileBooting) {
		if (!mProcessesOnHold.contains(app)) {
			mProcessesOnHold.add(app);
		}
		if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
		return app;
	}
	startProcessLocked(app, hostingType, hostingNameStr);
	return (app.pid != 0) ? app : null;
}

//ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app,String hostingType, String hostingNameStr) {
	if (app.pid > 0 && app.pid != MY_PID) {
		synchronized (mPidsSelfLocked) {
			mPidsSelfLocked.remove(app.pid);
			mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
		}
		app.pid = 0;
	}

	if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,"startProcessLocked removing on hold: " + app);
	mProcessesOnHold.remove(app);
	updateCpuStats();
	System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
	mProcDeaths[0] = 0;
	try {
		int uid = app.info.uid;
		int[] gids = null;
		try {
			gids = mContext.getPackageManager().getPackageGids(app.info.packageName);
		} catch (PackageManager.NameNotFoundException e) {
			Slog.w(TAG, "Unable to retrieve gids", e);
		}
		if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
			if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL && mTopComponent != null && app.processName.equals(mTopComponent.getPackageName())) {
				uid = 0;
			}
			if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
				uid = 0;
			}
		}
		int debugFlags = 0;
		if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
			debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
		}
		// Run the app in safe mode if its manifest requests so or the
		// system is booted in safe mode.
		if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
			Zygote.systemInSafeMode == true) {
			debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
		}
		if ("1".equals(SystemProperties.get("debug.checkjni"))) {
			debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
		}
		if ("1".equals(SystemProperties.get("debug.assert"))) {
			debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
		}
		//它调用了Process.start函数开始为应用程序创建新的进程,
		//它传入一个第一个参数为"android.app.ActivityThread",这就是进程初始化时要加载的Java类了,
		//把这个类加载到进程之后,就会把它里面的静态成员函数main作为进程的入口点,
		int pid = Process.start("android.app.ActivityThread",mSimpleProcessManagement ? app.processName : null, uid, uid,gids, debugFlags, null);
		BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
		synchronized (bs) {
			if (bs.isOnBattery()) {
				app.batteryStats.incStartsLocked();
			}
		}
		
		EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
				app.processName, hostingType,hostingNameStr != null ? hostingNameStr : "");
		
		if (app.persistent) {
			Watchdog.getInstance().processStarted(app.processName, pid);
		}
		
		StringBuilder buf = mStringBuilder;
		buf.setLength(0);
		buf.append("Start proc ");
		buf.append(app.processName);
		buf.append(" for ");
		buf.append(hostingType);
		if (hostingNameStr != null) {
			buf.append(" ");
			buf.append(hostingNameStr);
		}
		buf.append(": pid=");
		buf.append(pid);
		buf.append(" uid=");
		buf.append(uid);
		buf.append(" gids={");
		if (gids != null) {
			for (int gi=0; gi<gids.length; gi++) {
				if (gi != 0) buf.append(", ");
				buf.append(gids[gi]);

			}
		}
		buf.append("}");
		Slog.i(TAG, buf.toString());
		if (pid == 0 || pid == MY_PID) {
			// Processes are being emulated with threads.
			app.pid = MY_PID;
			app.removed = false;
			mStartingProcesses.add(app);
		} else if (pid > 0) {
			app.pid = pid;
			app.removed = false;
			synchronized (mPidsSelfLocked) {
				this.mPidsSelfLocked.put(pid, app);
				Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
				msg.obj = app;
				mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
			}
		} else {
			app.pid = 0;
			RuntimeException e = new RuntimeException("Failure starting process " + app.processName+ ": returned pid=" + pid);
			Slog.e(TAG, e.getMessage(), e);
		}
	} catch (RuntimeException e) {
		// XXX do better error recovery.
		app.pid = 0;
		Slog.e(TAG, "Failure starting process " + app.processName, e);
	}
}

//Process.java
public static final int start(final String processClass,final String niceName,
							  int uid, int gid, int[] gids,int debugFlags,String[] zygoteArgs)
{
	//supportsProcesses函数返回值为true
	if (supportsProcesses()) {
		try {
			return startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, zygoteArgs);
		} catch (ZygoteStartFailedEx ex) {
			Log.e(LOG_TAG,"Starting VM process through Zygote failed");
			throw new RuntimeException("Starting VM process through Zygote failed", ex);
		}
	} else {
		// Running in single-process mode
		Runnable runnable = new Runnable() {
					public void run() {
						Process.invokeStaticMain(processClass);
					}
		};
		
		// Thread constructors must not be called with null names (see spec). 
		if (niceName != null) {
			new Thread(runnable, niceName).start();
		} else {
			new Thread(runnable).start();
		}
		return 0;
	}
}

//Process.java
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
		//"--runtime-init"表示要为新创建的进程初始化运行时库
		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);
	}
	if (pid <= 0) {
		throw new ZygoteStartFailedEx("zygote start failed:" + pid);
	}
	return pid;
}

//Process.java
private static int zygoteSendArgsAndGetPid(ArrayList<String> args)throws ZygoteStartFailedEx {
	//args =
	//[
	//"--runtime-init"
	//"--setuid=x"
	//"--setgid=x"
	//"--enable-safemode"
	//"--enable-debugger"
	//"--enable-checkjni"
	//"--enable-assert"
	//"--setgroups=x"
	//"--nice-name=x"
	//"android.app.ActivityThread"
	//]
	int pid;
	openZygoteSocketIfNeeded();
	try {
		//sZygoteWriter是一个Socket写入流,是由openZygoteSocketIfNeeded函数打开的
		sZygoteWriter.write(Integer.toString(args.size()));
		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) {
		try {
			if (sZygoteSocket != null) {
				sZygoteSocket.close();
			}
		} catch (IOException ex2) {
			// we're going to fail anyway
			Log.e(LOG_TAG,"I/O exception on routine close", ex2);
		}
		sZygoteSocket = null;
		throw new ZygoteStartFailedEx(ex);
	}

	return pid;
}

打开和Zygote通信的socket
//Process.java
private static void openZygoteSocketIfNeeded() throws ZygoteStartFailedEx {

	int retryCount;
	if (sPreviousZygoteOpenFailed) {
		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();
			sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, LocalSocketAddress.Namespace.RESERVED));
			sZygoteInputStream= new DataInputStream(sZygoteSocket.getInputStream());
			sZygoteWriter =new BufferedWriter(new OutputStreamWriter(sZygoteSocket.getOutputStream()),256);
			Log.i("Zygote", "Process: zygote socket opened");
			sPreviousZygoteOpenFailed = false;
			break;
		} catch (IOException ex) {
			if (sZygoteSocket != null) {
				try {
					sZygoteSocket.close();
				} catch (IOException ex2) {
					Log.e(LOG_TAG,"I/O exception on close after exception",ex2);
				}
			}
			sZygoteSocket = null;
		}
	}
	if (sZygoteSocket == null) {
		sPreviousZygoteOpenFailed = true;
		throw new ZygoteStartFailedEx("connect failed");                 
	}
}
应用程序进程的创建通过socket交给zygote进程完成,在Zygote进程启动过程的源代码分析中介绍了Zygote进程启动完成后,将进入
socket监听模式:

//ZygoteInit.java
private static void runSelectLoopMode() throws MethodAndArgsCaller {
	ArrayList<FileDescriptor> fds = new ArrayList();
	ArrayList<ZygoteConnection> peers = new ArrayList();
	FileDescriptor[] fdArray = new FileDescriptor[4];
	fds.add(sServerSocket.getFileDescriptor());
	peers.add(null);

	int loopCount = GC_LOOP_COUNT;
	
	while (true) {
		int index;
		if (loopCount <= 0) {
			gc();
			loopCount = GC_LOOP_COUNT;
		} else {
			loopCount--;
		}
		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) {
			ZygoteConnection newPeer = acceptCommandPeer();
			peers.add(newPeer);
			fds.add(newPeer.getFileDesciptor());
		} else {
			boolean done;
			//这里从peers.get(index)得到的是一个ZygoteConnection对象,表示一个Socket连接,
			//因此,接下来就是调用ZygoteConnection.runOnce函数进一步处理。
			done = peers.get(index).runOnce();

			if (done) {
				peers.remove(index);
				fds.remove(index);
			}
		}
	}
}
当客户端通过zygoteSendArgsAndGetPid函数向Zygote进程发送请求时,Zygote进程将监听到客户端的请求,从而执行runOnce()

//ZygoteConnection.java
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;
	}
	if (args == null) {
		// EOF reached.
		closeSocket();
		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值,而在子进程中的返回值是0。
		pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, parsedArgs.debugFlags, rlimits);
	} catch (IllegalArgumentException ex) {
		logAndPrintError (newStderr, "Invalid zygote arguments", ex);
		pid = -1;
	} catch (ZygoteSecurityException ex) {
		logAndPrintError(newStderr,"Zygote security policy prevents request: ", ex);
		pid = -1;
	}
	//子进程执行,即指新创建的应用程序进程
	if (pid == 0) {
		// in child
		handleChildProc(parsedArgs, descriptors, newStderr);
		// should never happen
		return true;
	} 
	//父进程执行,即指Zygote进程
	else { /* pid != 0 */
		//Zygote进程的执行路线请参考在Zygote进程启动过程的源代码分析
		return handleParentProc(pid, descriptors, parsedArgs);
	}
}
创建的应用进程的执行函数
//ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs,
		FileDescriptor[] descriptors, PrintStream newStderr)throws ZygoteInit.MethodAndArgsCaller {
	//因此应用程序进程是从Zygote中fork出来,因此继承了父进程的Socket,
	//应用进程无需该Socket,因此需要关闭该Socket
	if (parsedArgs.peerWait) {
		try {
			ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
			sPeerWaitSocket = mSocket;
		} catch (IOException ex) {
			Log.e(TAG, "Zygote Child: error setting peer wait "+ "socket to be close-on-exec", ex);
		}
	} else {
		closeSocket();
		ZygoteInit.closeServerSocket();
	}

	if (descriptors != null) {
		try {
			ZygoteInit.reopenStdio(descriptors[0],descriptors[1], descriptors[2]);

			for (FileDescriptor fd: descriptors) {
				ZygoteInit.closeDescriptor(fd);
			}
			newStderr = System.err;
		} catch (IOException ex) {
			Log.e(TAG, "Error reopening stdio", ex);
		}
	}
    //由于在应用程序请求创建新进程的参数中设置了"--runtime-init",因此需要初始化运行库
	if (parsedArgs.runtimeInit) {
		RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
	} 
	else //未设置"--runtime-init"
	{
		ClassLoader cloader;
		if (parsedArgs.classpath != null) {
			cloader= new PathClassLoader(parsedArgs.classpath,ClassLoader.getSystemClassLoader());
		} else {
			cloader = ClassLoader.getSystemClassLoader();
		}

		String className;
		try {
			className = parsedArgs.remainingArgs[0];
		} catch (ArrayIndexOutOfBoundsException ex) {
			logAndPrintError (newStderr,"Missing required class name argument", null);
			return;
		}
		String[] mainArgs= new String[parsedArgs.remainingArgs.length - 1];

		System.arraycopy(parsedArgs.remainingArgs, 1,mainArgs, 0, mainArgs.length);

		try {
			ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
		} catch (RuntimeException ex) {
			logAndPrintError (newStderr, "Error starting. ", ex);
		}
	}
}

//RuntimeInit.java
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);
	//调用"android.app.ActivityThread"类的main函数
	invokeStaticMain(startClass, startArgs);
}
关于zygoteInit函数的详细介绍请参阅System Server进程启动过程源码分析
//RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv)
		throws ZygoteInit.MethodAndArgsCaller {

	// We want to be fairly aggressive about heap utilization, to avoid
	// holding on to a lot of memory that isn't needed.
	VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
	Class<?> cl;
	try {
		cl = Class.forName(className);//查找className类
	} catch (ClassNotFoundException ex) {
		throw new RuntimeException("Missing class when invoking static main " + className,ex);
	}
	Method m;
	try {
		//查找该类的main方法
		m = cl.getMethod("main", new Class[] { String[].class });
	} catch (NoSuchMethodException ex) {
		throw new RuntimeException("Missing static main on " + className, ex);
	} catch (SecurityException ex) {
		throw new RuntimeException("Problem getting static main on " + className, ex);
	}
	int modifiers = m.getModifiers();
	if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
		throw new RuntimeException("Main method is not public and static on " + className);
	}
	/*
	 * 这个异常将会在ZygoteInit.main()中被捕获,并调用run()方法来响应
	 */
	throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

//ZygoteInit.java
public static void main(String argv[]) {
	try {
		VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024);

		// Start profiling the zygote initialization.
		SamplingProfilerIntegration.start();

		registerZygoteSocket();
		EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
			SystemClock.uptimeMillis());
		preloadClasses();
		//cacheRegisterMaps();
		preloadResources();
		EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
			SystemClock.uptimeMillis());

		// Finish profiling the zygote initialization.
		SamplingProfilerIntegration.writeZygoteSnapshot();

		// Do an initial gc to clean up after startup
		gc();

		// If requested, start system server directly from Zygote
		if (argv.length != 2) {
			throw new RuntimeException(argv[0] + USAGE_STRING);
		}

		if (argv[1].equals("true")) {
			startSystemServer();
		} else if (!argv[1].equals("false")) {
			throw new RuntimeException(argv[0] + USAGE_STRING);
		}

		Log.i(TAG, "Accepting command socket connections");

		if (ZYGOTE_FORK_MODE) {
			runForkMode();
		} else {
			runSelectLoopMode();
		}

		closeServerSocket();
	// 捕获invokeStaticMain函数抛出的异常
	} catch (MethodAndArgsCaller caller) {
		caller.run();
	} catch (RuntimeException ex) {
		Log.e(TAG, "Zygote died with exception", ex);
		closeServerSocket();
		throw ex;
	}
}

//ZygoteInit.java
public void run() {
	try {
	    //调用ActivityThread.main函数
		mMethod.invoke(null, new Object[] { mArgs });
	} catch (IllegalAccessException ex) {
		throw new RuntimeException(ex);
	} catch (InvocationTargetException ex) {
		Throwable cause = ex.getCause();
		if (cause instanceof RuntimeException) {
			throw (RuntimeException) cause;
		} else if (cause instanceof Error) {
			throw (Error) cause;
		}
		throw new RuntimeException(ex);
	}
}

//ActivityThread.java
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"));
        }

        try {
			//应用进程进入消息循环
        	Looper.loop();
        } catch (OutOfMemoryError e) {
        	String pname = thread.getProcessName();
        	String file = "/data/misc/hprofs/";
        	File dir = new File(file);
        	if (!dir.exists() || !dir.isDirectory() || !dir.canWrite()) {
        		file = "/data/data/" + pname + "/";
        		dir = new File(file);
        	}
        	
        	if (dir.exists() && dir.isDirectory() && dir.canWrite()) {
        		File[] files = dir.listFiles();
        		for (File f : files) {
        			String p = f.getPath();
        			if (f.isFile() && p.contains(pname) && p.endsWith("hprof")) {
        				f.delete();
        			}
        		}
        		int pid = Process.myPid();
        		Date d = new Date();
        		String date = d.getDate() + "-" + d.getHours() + "-" + d.getMinutes() + "-" + d.getSeconds();
        		file += pname +  "_" + pid + "_" + date + ".hprof";
        		try {
        			android.os.Debug.dumpHprofData(file);
        		} catch (IOException e1) {
        			e1.printStackTrace();
        		}
        	}
			throw e;
        }

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

至此,Android应用程序进程启动过程的源代码就分析完成了,以下是android应用进程的启动过程的时序图:


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值