`
jgsj
  • 浏览: 956739 次
文章分类
社区版块
存档分类
最新评论

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应用进程的启动过程的时序图:


分享到:
评论

相关推荐

    Android系统进程Zygote启动过程的源代码分析.pdf

    Android系统进程Zygote启动过程的源代码分析.pdf

    zygote源码分析

    zygote源码分析

    zygote启动过程

    zygote启动过程zygote启动过程zygote启动过程zygote启动过程zygote启动过程

    Android Zygote启动流程源码解析

    Android Zygote启动流程源码解析

    Android应用程序进程管理

    这个PPT讲Android应用程序进程的启动和回收,主要涉及到Zygote进程、System Server进程,以及组件管理服务ActivityManagerService、窗口服务WindowManagerService,还有专用驱动Low Memory Killer。通过了解Android...

    ANDROID源码分析实录

    《Android源码分析实录》共分为15章,主要内容包括走进Android世界、硬件抽象层详解、分析JNI(Java本地接口)层、Android内存系统分析、Andmid虚拟机系统详解、IPC通信机制详解、Zygote进程/System进程和应用程序...

    详细分析Android中实现Zygote的

    概述 在Android系统中,所有的应用程序进程,以及用来运行系统关键服务的System进程都是由zygote进程负责创建的。因此,我们将它称为进程孵化器。zygote进程是通过复制自身的方式来创建System进程和应用...zygote分析

    最全java面试题.zip

    Zygote和System进程的启动过程 Android中的MVC,MVP和MVVM MVP Android开机过程 Retrofit源码分析 Glide源码分析 EventBus用法详解 EventBus源码分析 Android ORM 框架之 greenDAO 使用心得 Data Binding(数

    Java最全面试题宝典.rar

    Zygote和System进程的启动过程 Android中的MVC,MVP和MVVM MVP Android开机过程 Retrofit源码分析 Glide源码分析 EventBus用法详解 EventBus源码分析 Android ORM 框架之 greenDAO 使用心得 Data Binding(数据绑定...

    Zygote启动流程-systemServer启动流程-homeLauncher启动

    zygote启动流程源码分析, 文件包含zygote systemService activityManager启动homeLauncher. 因为本地文字较长 不方便写blog发布 所以上传一下文档

    Zygote解析

    init会创建Zygote进程,SystemServer进程和应用进程都是Zygote(孵化器)fock(复制进程)出来的。所以有必要了解下Zygote的流程。 二、Zygote启动流程 分析Zygote启动首先会调用ZygoteInit的main函数。 frameworks/...

    老罗的android之旅时序图

    (Android系统进程Zygote启动过程的源代码分析UML,Android系统默认Home应用程序(Launcher)的启动过程源代码分析uml,Android系统在新进程中启动自定义服务过程(startService)的原理分析UML,Android应用程序...

    Android启动-Zygote启动介绍

    Android启动,第二大阶段,Zygote启动。...紧接上一篇《 Android启动-init介绍》Linux内核启动之后,执行第一个进程 Init,init会启动本地服务,创建Zygote等。 这里我们就来研究一下Zygote启动过程。

    大厂高频面试题:说说你对Zygote的理解.docx

    Zygote可以说是Android开发面试很高频的一道问题,但总有小伙伴在回答这道问题总不能让面试满意, 在这你就要搞清楚面试问你对Zygote的理解时,面试官最想听到的和其实想问的应该是哪些?下面我们通过以下几点来剖析...

    Android 系统启动流分析 & Zygote启动流程分析

    Zygote在Android系统扮演着不可或缺的角色,Android系统的启动首先需要Zygote参与,比如启动SystemService , 还有一个就是孵化应用的进程,比如我们创建一个Activity也是需要Zygote参与.  Zygote 启动分为两个部分: 1....

    Android Framework实战开发篇

    广大的Android应用开发者是不是对Android系统充满着好奇,是不是很想学习Android系统...-学习zygote的进程创建过程源码分析 -学习zygote启动systemserver过程分析 -学习systemserver的启动分析 -学习systemserver的Home

    Android进程整理

    在所有进程中,以父进程的姿态存在的进程(即图中的浅红色项),如下:kthreadd进程:是所有内核进程的父进程init进程:是所有用户进程的父进程(或者父父进程)zygote进程:是所有上层Java进程的父进程,另外zygote的父...

    Android系统源代码情景分析-罗升阳-源码

    第11章 Zygote和System进程的启动过程 11.1 Zygote进程的启动脚本 11.2 Zygote进程的启动过程 11.3 System进程的启动过程 第12章 Android应用程序进程的启动过程 12.1 应用程序进程的创建过程 12.2 Binder...

    zygote

    NULL 博文链接:https://yishizhu.iteye.com/blog/843632

Global site tag (gtag.js) - Google Analytics