浅谈Android应用的启动流程

Android应用的启动就是指点击桌面应用icon一直到进入应用主界面的过程,这里跟Android系统的启动是有差异的,系统启动是指按下电源键到系统主界面的过程,Android系统启动后续单独另起一篇博文介绍。

本文分析的源代码依旧是Android5.1.1 API 22。

从Android4.4开始Launcher默认使用的是launcher3包下的Launcher类,在Android4.4之前一直使用的是launcher2包下的Launcher类。有关launcher2和launcher3包的差异性不在本文讨论了,有兴趣的可以参看其它资料深入了解。

Launcher类位于packages/apps/Launcher3/src/com/android/launcher3/Launcher.java。

public class Launcher extends Activity
        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
                   View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener {
				   
	...
	
}

这里Launcher类继承自Activity,所以平常我们进入Android桌面看到的都是一个Activity组件,那么Activity所具有的特征Launcher也具有。在Launcher桌面上面每一个应用视图(图片+文字)其实都是一个BubbleTextView控件,BubbleTextView是一个继承自TextView的自定义控件,如果点击桌面icon则会执行onClickAppShortcut()方法,如下是点击桌面icon后一直到startActivity()执行流程。

走到这里就又到了Activity的启动流程上面了,有对Activity的启动流程不清楚的可以参看浅谈Activity的启动流程。本文的着重点不在梳理整个流程了上面,主要介绍两点:一点是应用启动时UI线程是什么时候建立的,也可以这么理解ActivityThread是如何启动的,另外一点是Activity是有生命周期的,目标Activity的生命周期是在当前Activity生命周期的哪个流程才开始触发的。

在讨论问题之前,还是要借用Activity启动流程中介绍的ActivityStackSupervisor和ActivityStack之间调用流程图。

ActivityThread的启动

在ActivityStackSupervisor中执行到startSpecificActivityLocked()方法源码如下:

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, true);

	r.task.stack.setLaunchTime(r);

	if (app != null && app.thread != null) {
		try {
			if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
					|| !"android".equals(r.info.packageName)) {
				// Don't add this if it is a platform component that is marked
				// to run in multiple processes, because this is actually
				// part of the framework so doesn't make sense to track as a
				// separate apk in the process.
				app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
						mService.mProcessStats);
			}
			realStartActivityLocked(r, app, andResume, checkConfig);
			return;
		} catch (RemoteException e) {
			Slog.w(TAG, "Exception when starting activity "
					+ r.intent.getComponent().flattenToShortString(), e);
		}

		// If a dead object exception was thrown -- fall through to
		// restart the application.
	}

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

mService.getProcessRecordLocked()方法其实就从一个Map中获取一个ProcessRecord类型的变量,由于是首次启动应用,所以mService.getProcessRecordLocked()方法返回的ProcessRecord类型的app变量是null,mService是ActivityManagerService。

由于app是null,所以接下来执行了mService.startProcessLocked()方法,在ActivityManagerService类中startProcessLocked()有几个重载的方法,这里只贴出流程中所需要的比较关键的执行部分。

final ProcessRecord startProcessLocked(String processName,
		ApplicationInfo info, boolean knownToBeDead, int intentFlags,
		String hostingType, ComponentName hostingName, boolean allowWhileBooting,
		boolean isolated, boolean keepIfLarge) {
	return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
			hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
			null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
			null /* crashHandler */);
}

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
	...
	
	ProcessRecord app;
	//首次启动应用 app为null
	if (app == null) {
		checkTime(startTime, "startProcess: creating new process record");
		app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
		if (app == null) {
			Slog.w(TAG, "Failed making new process record for "
					+ processName + "/" + info.uid + " isolated=" + isolated);
			return null;
		}
		app.crashHandler = crashHandler;
		//将ProcessRecord存入一个Map集合中
		mProcessNames.put(processName, app.uid, app);
		if (isolated) {
			mIsolatedProcesses.put(app.uid, app);
		}
		checkTime(startTime, "startProcess: done creating new process record");
	}
	//调用另外一个重载方法
	startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
	...		
}
private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
	...
	if (entryPoint == null) entryPoint = "android.app.ActivityThread";
		checkTime(startTime, "startProcess: asking zygote to start proc");
		Process.ProcessStartResult startResult = Process.start(entryPoint,
				app.processName, uid, uid, gids, debugFlags, mountExternal,
				app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
				app.info.dataDir, entryPointArgs);
	
	...
			
}

在startSpecificActivityLocked()方法调用的startProcessLocked()方法可以知道,入参entryPoint传入的是null。由于是首次启动应用,所以ProcessRecord类型的局部变量app仍然是null,然后通过newProcessRecordLocked()方法new一个新的ProcessRecord对象,并存入一个自定义类型Map集合变量mProcessNames中,接着继续执行另外一个重载方法,由于在调用startProcessLocked()方法时入参entryPoint是null,所以这里就将entryPoint重新赋值为了"android.app.ActivityThread",最后通过Process.start()方法通过Zygote来fork一个新的进程。

这里的Process类并不是java.lang包下的Process,而是位于android.os包下的。我们知道Android应用进程之间一般采用Binder机制进行通信,但是ActivityManagerService与Zygote进程之间确是通过Socket进行通信的,在ActivityManagerService类中执行Process.start()方法与Zygote进程通信,最后通过Zygote进程fork出一个APP应用进程,然后通过反射方式直接调用执行ActivityThread的main方法。

public static void main(String[] args) {
	SamplingProfilerIntegration.start();

	...
	Looper.prepareMainLooper();

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

	if (sMainThreadHandler == null) {
		sMainThreadHandler = thread.getHandler();
	}

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

	Looper.loop();

	...
	
}

在ActivityThread中首先通过Looper.prepareMainLooper()方法,然后调用Looper.loop()方法构建了主线程的消息循环,所以我们在主线程中使用Handler时不需要要显式的使用Looper.prepare()和loop()方法,因为在主线程启动时就绑定了MainLooper消息循环。

在main()方法中接着执行流程如下图:

最后又执行到了ActivityStackSupervisor的realStartActivityLocked()方法中了,接下来的流程还是继续Activity启动流程了。

ActivityThread的bindApplication()方法这里继续简单介绍一下,bindApplication()一直执行最后走到handleBindApplication()方法,部分代码如下:

private void handleBindApplication(AppBindData data) {
	
	TimeZone.setDefault(null);

	/*
	 * Initialize the default locale in this process for the reasons we set the time zone.
	 */
	Locale.setDefault(data.config.locale);

	final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
	
	final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
	DateFormat.set24HourTimePref(is24Hr);

	/**
	 * For apps targetting SDK Honeycomb or later, we don't allow
	 * network usage on the main event loop / UI thread.
	 *
	 * Note to those grepping:  this is what ultimately throws
	 * NetworkOnMainThreadException ...
	 */
	if (data.appInfo.targetSdkVersion > 9) {
		StrictMode.enableDeathOnNetwork();
	}

	if (data.instrumentationName != null) {
		mInstrumentation = (Instrumentation)
				cl.loadClass(data.instrumentationName.getClassName()).newInstance();
		mInstrumentation.init(this, instrContext, appContext,
			   new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
			   data.instrumentationUiAutomationConnection);
	} else {
		mInstrumentation = new Instrumentation();
	}

	// Allow disk access during application and provider setup. This could
	// block processing ordered broadcasts, but later processing would
	// probably end up doing the same disk access.
	final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
	try {
		// If the app is being launched for full backup or restore, bring it up in
		// a restricted environment with the base application class.
		Application app = data.info.makeApplication(data.restrictedBackupMode, null);

		mInstrumentation.onCreate(data.instrumentationArgs);
		
		mInstrumentation.callApplicationOnCreate(app);
		
	} finally {
		StrictMode.setThreadPolicy(savedPolicy);
	}
}

通过代码可以知道,在bindApplication()方法中,创建了待启动应用的Instrumentation,并执行了Instrumentation初始化init()以及onCreate()方法,还创建了Application,在makeApplication()时第二个参数传入的是null,代表此时不执行Application的onCreate()方法,如果不为null才会执行该方法,后面在执行了Instrumentation的onCreate()后又调用了callApplicationOnCreate()方法,此时才真正执行了Application的onCreate()方法。可以看出这里创建Application跟浅谈Activity的启动流程中很类似,不同的是在启动流程那里是在performLaunchActivity()方法中调用的makApplication()方法,所以Application首次创建是在handleBindApplication()方法,当执行到performLaunchActivity()方法时,此时Application已经被创建完成了,当然了也不排除异常情况,如果在handleBindApplication()创建不成功,在performLaunchActivity()方法中会重新执行创建,确保Application可以被创建。

不仅如此,还执行了部分StrictMode的逻辑,比如设置了线程检测策略StrictMode.allowThreadDiskWrites(),还有当SDK Version大于9时,设置了StrictMode.enableDeathOnNetwork(),平常我们说主线程不可以访问网络,其实禁止的逻辑就是在这里设置的。

目标Activity生命周期

在Activity启动流程中,位于ActivityStack类中resumeTopActivityInnerLocked()方法,有如下判断:

final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {

	...
	if (mResumedActivity != null) {
		if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
		pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
	}
	...
}

Activity启动流程走到resumeTopActivityInnerLocked()方法,这时候mResumedActivity即是当前Activity不为null,直接进入startPausingLocked()方法。

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
	
	...
	ActivityRecord prev = mResumedActivity;
	
	mResumedActivity = null;
    mPausingActivity = prev;
	
	...
	prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                    userLeaving, prev.configChangeFlags, dontWait);
	...
	
}

在startPausingLocked()方法中将当前Activity设置为prev变量,然后将mResumedActivity重置为null,mPausingActivity设置为当前Activity,并执行ActivityThread的schedulePauseActivity()方法。schedulePauseActivity()方法的执行逻辑类似前面介绍的scheduleLaunchActivity(),可以参考浅谈Activity的启动流程,经过一系列的执行最终执行到ActivityStackSupervisor类的resumeTopActivitiesLocked(),这时候就又重新进入了目标Activity的启动流程上面,并继续完成目标Activity的启动流程。

上述这一过程的执行流程如下:

通过源代码分析Activity的启动流程,这样我们可以对Activity的生命周期切换有了一个更清晰的认识。如果用一个Activity启动目标Activity,目标Activity的生命周期执行一定会在上一个Activity的onPause()方法执行之后才会执行,所以在平常开发中一定要注意Activity生命周期方法onPause()的使用,不可以在onPause()中执行一些比较耗时的逻辑,否则会影响Activity之间页面跳转的效率

参考资料

参考资料

Android8.1系统源码讲解之ActivityThread进程启动详解

Android6.0之AMS通过socket与zygote通信创建app进程

评论

您确定要删除吗?删除之后不可恢复