笔记:Activity的启动过程
Activity的创建特点
作为四大组件之一的Activity,它不像普通java对像那样,可以new出来,然后去使用。而是调用
startActivity()这样的方式启动。那么Android系统是如何创建并启动Activity的呢?本文就来
一探究竟。
NOTE:本文内容就是对老罗《Android系统源代码情景分析》章节的简化笔记。
因为涉及到不同进程间的通信,所以分析流程的过程中会在不同的源代码文件之间跳转,源码为Android 2.3版本,下载系统源码后,可以使用像Everything这样的软件根据类名对文件进行快速查找。
Launcher启动App
任何安装的应用几乎都是点击桌面上的图标被启动。
接下来以Launcher程序启动一个App的过程作为案例。要启动的App的包名为com.idlestar.bot
,其入口Activity为MainActivity。
Task和Back Stack
即便没有了解过Activity的启动过程、ActivityManagerService(简称AMS,它是运行在系统进程SystemServer中的系统关键服务)这些知识点,对任务(Task)和回退栈(Back Stack)的概念、Activity启动模式等多少都回了解。接下来可以在源码级稍微感受到它们的真实表现。
Task
用户完成一个任务时,可能和若干相关的Activity组件进行交互,这些相关的Activity的集合被称作一个Task,由TaskRecord对象表示。Task中所有Activity形成一个stack结构,以它们的启动顺序被添加。
ActivityStack
实际上在系统中,每一个Activity组件实例被使用一个ActivityRecord对像表示,所有的Activity组件都保存在一个ActivityStack对象的字段ArrayList mHistory
中。ActivityRecord.task字段表示其所在Task。假设把所有Activities指定编号:a0,a1,a2...an,表示mHistory中从第0,1,2...n个Activity,那么,Task就是从a0到an中连续的一个个“子序列”,一个Task包括1或多个Activity。Task中的Activity的“栈结构”是通过ArrayList间接实现的
命令adb shell dumpsys activity
可以查看当前系统中运行的Activities的信息。在启动MainActivity的前后,可以运行命令来查看有关的Activities的信息。
启动MainActivity前,显示Launcher时:
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Stack #0:
Task id #1
TaskRecord{529e7460 #1 A=com.android.launcher U=0 sz=1}
...
ProcessRecord{529e7b24 735:com.android.launcher/u0a8}
Running activities (most recent first):
TaskRecord{529e7460 #1 A=com.android.launcher U=0 sz=1}
Run #0: ActivityRecord{529e66bc u0 com.android.launcher/com.android.launcher2.Launcher t1}
...
Recent tasks:
* Recent #0: TaskRecord{529e7460 #1 A=com.android.launcher U=0 sz=1}
上面的信息有点像Json那种格式,缩进表示了信息的分组。
先是Stack #0
这种划分,#跟数字表示序号。Stack #0
是整个ActivityStack中的第一个Task。
此时,只有一个Task——Stack #0
。
其Task id
为#1,即任务id=1。
而Running activities是Task所包含的运行中的Activity的信息,最近使用的排在前面。Run #0
显示了正在运行的第一个也是唯一一个ActivityRecord,就是Launcher组件。
点击App图标,打开MainActivity之后:
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Stack #0:
Task id #1
TaskRecord{529e7460 #1 A=com.android.launcher U=0 sz=1}
...
ProcessRecord{529e7b24 735:com.android.launcher/u0a8}
Running activities (most recent first):
TaskRecord{529e7460 #1 A=com.android.launcher U=0 sz=1}
Run #0: ActivityRecord{529e66bc u0 com.android.launcher/com.android.launcher2.Launcher t1}
Stack #1:
Task id #2
TaskRecord{52a203f8 #2 A=com.idlestar.bot U=0 sz=1}
...
ProcessRecord{529704e8 3307:com.idlestar.bot/u0a82}
...
Running activities (most recent first):
TaskRecord{52a203f8 #2 A=com.idlestar.bot U=0 sz=1}
Run #0: ActivityRecord{5296eea0 u0 com.idlestar.bot/.MainActivity t2}
...
Recent tasks:
* Recent #0: TaskRecord{52a203f8 #2 A=com.idlestar.bot U=0 sz=1}
* Recent #1: TaskRecord{529e7460 #1 A=com.android.launcher U=0 sz=1}
可以看到此时多了一个Task Stack #1
,它在是栈顶位置(#序号最大的),它对应的ActivityRecord为MainActivity,正是当前处在前台(foreground)被显示的Activity。
上面启动MainActivity前后,看到Launcher和MainActivity属于不同的Task,因为Launcher为启动的MainActivity指定了NEW_TASK。
启动过程跟踪
自己的App会运行在一个包名对应的进程中,这点常识这里不去解释。
MainActivity是Launcher启动的,而Launcher是通过AMS来启动MainActivity的。它们分别运行在不同的进程中,整个过程中它们之间使用Binder完成跨进程通信。
NOTE:源代码为android系统2.3。
下面是完整的过程,非重要部分会很简单地描述下,保证流程完整性。
阶段1:Launcher通知AMS启动MainActivity。
Launcher向ActivityManagerService发送一个启动MainActivity组件的进程间通信请求。
系统启动时,会启动PackageManagerService服务,简称PMS,通过它安装系统中的应用程序。
第一个启动的就是Launcher,Launcher向PMS查询所有App的AndroidManifest.xml获得所有App
的图标,启动Activity组件(Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_LAUNCHER)的全名。
用户点击桌面App图标后,Launcher根据对应App的信息,创建一个启动它的intent,并调用startActivity()来启动它。
不同android版本中Launcher的代码会稍有差异,但基本过程是类似的。
方法调用过程,对传递调用不加说明,直接继续给出所调用的方法:
step 1:Launcher.startActivitySafely()
void startActivitySafely(Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
...
默认为intent添加了FLAG_ACTIVITY_NEW_TASK标志。
step 2:Activity.startActivity(intent)
step 3:Activity.startActivityForResult(intent, -1)
参数requestCode = -1表示不处理onActivityResult()
// set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.
private Instrumentation mInstrumentation;
void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
...
}
step 4:Instrumentation.execStartActivity()
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode) {
...
try {
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
null, 0, token, target != null ? target.mEmbeddedID : null,
requestCode, false, false);
...
}
ActivityManagerNative.getDefault()获得的是AMS的一个代理对像,类型为IActivityManager。
/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault()
{
if (gDefault != null) {
//if (Config.LOGV) Log.v(
// "ActivityManager", "returning cur default = " + gDefault);
return gDefault;
}
IBinder b = ServiceManager.getService("activity");
if (Config.LOGV) Log.v(
"ActivityManager", "default service binder = " + b);
gDefault = asInterface(b);
if (Config.LOGV) Log.v(
"ActivityManager", "default service = " + gDefault);
return gDefault;
}
asInterface(b):
/**
* Cast a Binder object into an activity manager interface, generating
* a proxy if needed.
*/
static public IActivityManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
以上2个方法是典型的Binder通信方式,将一个和远程进程通信的IBinder转为通信定义的接口类型。最终getDefault()返回的就是ActivityManagerProxy对像。
step 5:ActivityManagerProxy.startActivity()
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.writeStrongBinder(resultTo);
...
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
上面使用IBinder.transact()对系统进程中的AMS执行远程调用:START_ACTIVITY_TRANSACTION。
- 参数
caller:指向Launcher组件所在的应用程序进程的ApplicationThread对像。
intent:包含了要启动的MainActivity组件的信息。
resultTo:指向AMS内部的一个ActivityRecord对像,它保存了Launcher组件的信息。
/**
* An entry in the history stack, representing an activity.
*/
class ActivityRecord extends IApplicationToken.Stub {
}
NOTE:在多进程交互的环境下,IBinder对像可以是一个进程中供其它进程访问的“可远程访问”对像的一个BinderProxy代理。跨进程引用一个对象的作用。
以上step操作发生在Launcher应用中,其方法调用流程图:
阶段2:AMS保存启动信息,通知caller进入stop
接下来的操作在AMS中进行,处理Launcher发起的START_ACTIVITY_TRANSACTION请求。
AMS首先将要启动的MainActivity组件的信息保存起来,然后再向Launcher组件发送一个进入中止状态的进程间通信请求。
step 6:ActivityManagerService.startActivity()
AMS继承ActivityManagerNative,其onTransact()方法中,对code = START_ACTIVITY_TRANSACTION的处理是调用接口方法IActivityManager.startActivity()
,AMS实现了startActivity():
public ActivityStack mMainStack;
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);
}
step 7:ActivityStack.startActivityMayWait()
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) {
...
// 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;
...
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified);
...
}
方法先通过PackageManager根据启动intent获得关于MainActivity组件的更多信息,保存在变量ActivityInfo aInfo中。继续调用startActivityLocked()。
step 8:ActivityStack.startActivityLocked()
final ActivityManagerService mService;
/**
* The back history of all previous (and possibly still
* running) activities. It contains HistoryRecord objects.
*/
final ArrayList mHistory = new ArrayList();
...
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) {
...
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
...
ActivityRecord sourceRecord = null;
...
int index = indexOfTokenLocked(resultTo);
...
sourceRecord = (ActivityRecord)mHistory.get(index);
ActivityRecord r = new ActivityRecord(mService, this, callerApp,
callingUid,intent, resolvedType, aInfo, mService.mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
...
return startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
}
AMS内部使用ProcessRecord对象表示每一个应用程序进程,getRecordForAppLocked获得caller对应的ProcessRecord callerApp,也就是Launcher的进程信息。
mHistory正是用来保存所有已启动的Activity组件,每个Activity组件使用ActivityRecord表示。sourceRecord就是Launcher组件对应的信息,启动操作的源组件。
之后创建一个ActivityRecord r变量,它表示要启动的MainActivity组件的信息,启动操作的目标组件。
step 9:ActivityStack.startActivityUncheckedLocked()
根据启动intent获得launchFlags。
用户是点击Launcher中的图标手动启动,所以Intent.FLAG_ACTIVITY_NO_USER_ACTION不成立,之后会向源Activity Launcher发送一个“用户离开”的事件通知。
标志FLAG_ACTIVITY_NEW_TASK说明需要将要启动的MainActivity放在一个新Task中——就是和当前的Launcher组件不在一个Task中,而在AndroidManifest.xml中可以使用
android:taskAffinity来指定组件所在任务id,所以AMS检查此Task是否存在,不存在就创建它,把MainActivity放到此Task中。每个新创建的Task有一个int id,是AMS维护的一个自增字段。
最后紧接着执行重载的另一个方法
startActivityLocked(r, newTask, doResume);
如果newTask为true,也就是要启动的Activity组件在新Task中,那么它会被放在mHistory栈的顶部。
然后doResume = true,就对mHistory最后的Activity执行resume。
这里就是MainActivity被添加到栈顶,然后会被执行resume。
step 10:ActivityStack.resumeTopActivityLocked()
在启动MainActivity的ActivityRecord之前,会通知MainActivity的上一个prev处在前台的Activity组件——也就是Launcher用户离开。
step 11:ActivityStack.startPausingLocked()
ActivityRecord有一个字段ProcessRecord app,表示其Activity组件所在的进程。ProcessRecord有一个字段ApplicationThreadProxy thread,就是另一个应用程序进程中ApplicationThread的Binder代理对象。
startPausingLocked()会执行代表Launcher组件所在进程的ProcessRecord变量的方法app.thread.schedulePauseActivity()来通知Launcher组件进入pause状态。
ActivityRecord prev = mResumedActivity;
...
prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
prev.configChangeFlags);
上面代码片段中prev就是Launcher对应的组件信息。它是一个IBinder实例,对应Launcher组件。
因为app.thread.schedulePauseActivity()的执行是一个Binder通信,但指定为FLAG_ONEWAY,所以方法调用会立即返回。当前方法中会使用mHandler发送一个PAUSE_TIMEOUT_MSG的消息:
// Schedule a pause timeout in case the app doesn't respond.
// We don't give it much time because this directly impacts the
// responsiveness seen by the user.
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
作为系统进程中的服务,此处AMS没有以同步的Binder通信方式等待Launcher执行pause完成,而是异步地通知Launcher进入pause,然后,它内部使用Handler发送一个延迟消息,在延迟消息收到前若Launcher没有通知AMS已经进入pause,那么AMS做其它处理——认为Launcher未响应。
step 12:ApplicationThreadProxy.schedulePauseActivity()
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(finished ? 1 : 0);
data.writeInt(userLeaving ? 1 :0);
data.writeInt(configChanges);
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
它执行了一个Binder-IPC操作,发送命令code = SCHEDULE_PAUSE_ACTIVITY_TRANSACTION。
这个进程间操作是FLAG_ONEWAY的,它会立即返回。
参数token就是AMS中Launcher对应的ActivityRecord对象。
注意Binder的通信默认是同步的,更多为什么可以先了解下Binder通信。
以上操作都是在AMS中执行的,AMS在系统进程SystemServer中。所有方法的调用流程图:
阶段3:Launcher处理SCHEDULE_PAUSE_ACTIVITY_TRANSACTION
接下来地的几步操作在Launcher中进行,执行处理AMS发送的SCHEDULE_PAUSE_ACTIVITY_TRANSACTION通信请求。
方法调用流程如下:
Step 13:ApplicationThread.schedulePauseActivity()
注意系统源码在Binder通信的设计,如果了解AIDL生成的通信接口的实现类和Proxy内部类等,这些Binder-IPC相关的类型都很容易理解。
类似AMS和ActivityManagerNative等,ApplicationThreadNative在onTransact()中对code = SCHEDULE_PAUSE_ACTIVITY_TRANSACTION的处理是调用接口方法IApplicationThread.schedulePauseActivity()。
case SCHEDULE_PAUSE_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
IBinder b = data.readStrongBinder();
boolean finished = data.readInt() != 0;
boolean userLeaving = data.readInt() != 0;
int configChanges = data.readInt();
schedulePauseActivity(b, finished, userLeaving, configChanges);
return true;
}
变量IBinder b就是AMS中Launcher对应的ActivityRecord对象。
ApplicationThread是ActivityThread的内部类,它继承ApplicationThreadNative,实现了schedulePauseActivity()。
public final class ActivityThread {
...
private final class ApplicationThread extends ApplicationThreadNative {
...
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
queueOrSendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? 1 : 0),
configChanges);
}
}
}
可以看到,方法执行queueOrSendMessage()向应用程序Launcher的主线程的消息队列发送一个类型为PAUSE_ACTIVITY的消息。
Step 14:ActivityThread.queueOrSendMessage()
public final class ActivityThread {
...
final H mH = new H();
...
private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
}
}
ActivityThread的字段mH是在进程主线程中创建的,用来处理应用程序进程中的主线程消息,类H继承Handler。
因为对Binder方法onTransact()的执行基本是(当跨进程时)在Binder线程池中的线程中执行的,可见这里定义mH就是为了供其它非主线程的操作转到主线程中执行。
TODO:ActivityThread的创建及其相关知识后面会小结下。
Step 15:H.handleMessage()
/**
* This manages the execution of the main thread in an
* application process, scheduling and executing activities,
* broadcasts, and other operations on it as the activity
* manager requests.
*/
public final class ActivityThread {
...
private final class H extends Handler {
...
public static final int PAUSE_ACTIVITY = 101;
public void handleMessage(Message msg) {
switch (msg.what) {
...
case PAUSE_ACTIVITY:
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
...
break;
...
}
}
}
msg.obj就是AMS中执行ApplicationThreadProxy.schedulePauseActivity()时传递的代表IBinder的ActivityRecord对象。
Step 16:ActivityThread.handlePauseActivity()
应用程序进程中启动的每一个Activity组件都使用一个ActivityClientRecord对象描述,其对应AMS中的ActivityRecord对象。ActivityThread的字段mActivities就是。
方法中,根据AMS传递的表示Launcher组件的token从mActivities获得Launcher对应的ActivityClientRecord对象,通知它执行onUserLeaveHint(),然后是onPause()。
最后,ActivityManagerNative.getDefault()获得AMS代理对象,通知AMS已经完成对Launcher的pause。
Step 17:ActivityManagerProxy.activityPaused()
public void activityPaused(IBinder token, Bundle state) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
data.writeBundle(state);
mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
执行Binder通信,通知AMS事件code = ACTIVITY_PAUSED_TRANSACTION。
阶段4 AMS处理ACTIVITY_PAUSED_TRANSACTION
接下来的操作又转到AMS中进行,从响应ACTIVITY_PAUSED_TRANSACTION事件开始。
方法调用时序图:
Step 18:ActivityManagerService.activityPaused()
在onTransact()中响应ACTIVITY_PAUSED_TRANSACTION执行的方法。
请求转给ActivityStack:
mMainStack.activityPaused(token, icicle, false);
参数token指向Launcher组件对应的ActivityRecord对象。
Step 19:ActivityStack.activityPaused()
根据token从字段mHistory中找到Launcher的ActivityRecord对象,然后设置其为paused。
继续启动MainActivity。
Step 20:ActivityStack.completePauseLocked()
对ActivityRecord prev = mPausingActivity,也就是Launcher的pause完成。
执行resumeTopActivityLocked(prev)。
前面的执行中,mHistory中的topActivity就是MainActivity。
Step 21:ActivityStack.resumeTopActivityLocked()
此时的topActivity就是MainActivity,其ActivityRecord.app字段为null,因为还未为它创建进程。
Step 22:ActivityStack.startSpecificActivityLocked()
在AMS中,每一个Activity组件都有userId和进程名,用户ID是安装该Activity组件的App时由PackageManagerService分配的,进程名由该组件的android:process决定的。
方法中,AMS检查对应用户ID和进程名的进程是否存在,ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid)
,
若app为null,就先启动一个App进程,然后通知该进程启动MainActivity。
Step 23:AMS.startProcessLocked()
AMS用字段mProcessNames记录已经运行的App进程的信息:
/**
* All of the applications we currently have running organized by name.
* The keys are strings of the application package name (as
* returned by the package manager), and the keys are ApplicationRecord
* objects.
*/
final ProcessMap<ProcessRecord> mProcessNames
= new ProcessMap<ProcessRecord>();
再次检查对应app进程是否存在:
ProcessRecord app = getProcessRecordLocked(processName, info.uid)
如果app为null:
app = newProcessRecordLocked(null, info, processName);
mProcessNames.put(processName, info.uid, app);
最后,方法调用一个重载版本继续完成MainActivity的进程的创建。
startProcessLocked(app, hostingType, hostingNameStr);
方法首先得到要创建的进程的用户ID和用户组ID,然后执行Process.start()静态函数启动一个新的应用程序进程:
int pid = Process.start("android.app.ActivityThread",
mSimpleProcessManagement ? app.processName : null, uid, uid,
gids, debugFlags, null);
得到的返回值pid是对应启动的App进程的大于0的进程ID。然后将参数app指向的ProcessRecord对象保存在AMS的以pid为key的字典字段mPidsSelfLocked中:
/**
* All of the processes we currently have running organized by pid.
* The keys are the pid running the application.
*
* <p>NOTE: This object is protected by its own lock, NOT the global
* activity manager lock!
*/
final SparseArray<ProcessRecord> mPidsSelfLocked
= new SparseArray<ProcessRecord>();
....
this.mPidsSelfLocked.put(pid, app);
进程的启动还是异步的,所以这里向AMS使用Handler发送延迟消息PROC_START_TIMEOUT_MSG。
如果延迟时间后新启动的App进程未通知AMS它启动完成,否则AMS不再继续处理MainActivity的启动。
阶段5
接下来就是android应用程序进程启动的过程。
AMS中执行的Process.start()方法所启动的新进程的程序入口方法是android.app.ActivityThread的静态成员函数main()。
接下来的方法执行流程如:
Step 24:ActivityThread.main
public final class ActivityThread {
...
final ApplicationThread mAppThread = new ApplicationThread();
...
private final void attach(boolean system) {
....
mSystemThread = system;
if (!system) {
...
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException e) {
}
}
...
}
...
public static final void main(String[] args) {
..
Looper.prepareMainLooper();
...
ActivityThread thread = new ActivityThread();
thread.attach(this);
...
Looper.loop();
...
}
}
创建一个ActivityThread对象,调用其attach()向AMS发送进程启动完成通知。
开启主线程消息循环。
ApplicationThread是一个Binder本地对象,AMS使用它的代理和当前App进程通信。
attachApplication()向AMS通知进程创建完成。
Step 25:ActivityManagerProxy.attachApplication
public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
向AMS发送ATTACH_APPLICATION_TRANSACTION事件,IApplicationThread app的Binder代理作为AMS对当前ApplicationThread的标识。
阶段6 AMS响应App进程创建完成通知
接下来是AMS处理ATTACH_APPLICATION_TRANSACTION事件。
方法时序图:
Step 26:AMS.attachApplication
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
callingPid就是为MainActivity创建的新进程的pid。
Step 27:AMS.attachApplicationLocked
根据pid得到mPidsSelfLocked中的ProcessRecord app对象。
得到AMS管理的栈顶topActivity:
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
将app设置给MainActivity对应的hr。
执行mMainStack.realStartActivityLocked(hr, app, true, true)
继续启动MainActivity。
Step 28:ActivityStack.realStartActivityLocked
这时MainActivity的ActivityRecord r的app字段就是设置过的,不为null。
topActivity.app.thread就是所创建MainActivity进程中ApplicationThread mAppThread的Binder代理。
使用topActivity.app.thread.scheduleLaunchActivity()跨进程通知创建的App进程启动MainActivity组件。
Step 29:ApplicationThreadProxy.scheduleLaunchActivity
使用IBinder向MainActivity对应进程的mAppThread发送SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION通知。
消息中记录了要启动的MainActivity的ActivityInfo info。
阶段7 ActivityThread处理启动MainActivity的请求
接下来的操作就在为MainActivity所创建的新的App进程中执行。
前面的ActivityThread.main()的执行使得进程中已经存在mAppThread和创建的ActivityThread thread。
main方法进入Looper循环。
将要执行的方法时序图:
Step 30:ApplicationThread.scheduleLaunchActivity
ApplicationThreadNative的onTransact()将对SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION的响应转为ApplicationThread.scheduleLaunchActivity()的调用。
方法继续使用queueOrSendMessage()将处理打包为msg传给ActivityThread.mH。
ActivityClientRecord r = new ActivityClientRecord();
...
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
r就是从AMS端传递过来的MainActivity的信息。
Step 31:ActivityThread.queueOrSendMessage
handleMessage()中对消息LAUNCH_ACTIVITY的处理:
case LAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo);
handleLaunchActivity(r, null);
Step 32:ActivityThread.handleLaunchActivity
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity a = performLaunchActivity(r, customIntent);
...
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward);
...
}
启动MainActivity,然后设置它为resume。
Step 34:ActivityThread.performLaunchActivity
原型:
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent)
获得关于MainActivity的组件信息:
ComponentName component = r.intent.getComponent();
然后根据component,使用类加载器实例化Activity对象:
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
然后创建一个ContextImpl appContext,作为activity的运行上下文环境。
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
使用appContext和参数r对activity执行初始化:
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
然后执行onCreate:
mInstrumentation.callActivityOnCreate(activity, r.state);
callActivityOnCreate()会调用Activity.onCreate(),这时自定义MainActivity中的setContentView()等逻辑就会被调用。
activity创建完毕后,对应记录被添加到ActivityThread中:
mActivities.put(r.token, r);
ActivityClientRecord r是AMS中对应MainActivity的ActivityRecord对象的Binder代理,它们分别是MainActivity在AMS中和App进程ActivityThread中的描述。
总结
经过以上步骤,从Launcher.startActivitySafely()开始到Activity.onCreate()得以执行,可以认为MainActivity组件及其进程已经启动完毕。
启动的各个阶段
- Launcher组件向AMS发送启动MainActivity组件的进程间通信。
- AMS首先保存要启动的MainActivity的信息,然后向Launcher发送进入pause状态的进车间通信。
- Launcher进入中止状态后,向AMS发送已经进入中止状态的进程间通信请求。这样AMS就继续执行启动MainActivity的操作。
- AMS检查用来运行MainActivity的进程不存在,创建并启动一个App进程。
- 新进程启动完成后,向AMS发送启动完成的进程间通信请求。
- AMS将保存的MainActivity组件的信息发送给创建的新进程。
- 新进程启动MainActivity。
ActivityThread.mH
ActivityThread的main方法就是整个App进程的入口函数,它执行结束那么App进程就结束了。
main()中开启了Looper消息循环。
ActivityThread.mH把很多Binder操作从Binder线程中转到UI线程中执行。
(本文使用Atom编写)
笔记:Activity的启动过程的更多相关文章
- Android学习笔记——Activity的启动和创建
http://www.cnblogs.com/bastard/archive/2012/04/07/2436262.html Android Activity学习笔记——Activity的启动和创建 ...
- Android Activity的启动过程
文章编辑的太长了,请移步我的csdn博客:http://blog.csdn.net/xyh269 Android Activity的启动过程原文链接:http://blog.csdn.net/xyh2 ...
- openstack学习笔记一 虚拟机启动过程代码跟踪
openstack学习笔记一 虚拟机启动过程代码跟踪 本文主要通过对虚拟机创建过程的代码跟踪.观察虚拟机启动任务状态的变化,来透彻理解openstack各组件之间的作用过程. 当从horizon界面发 ...
- Android 儿子Activity在启动过程中的流程组件 && 儿子Activity在一个新的进程组件启动过程
1.儿子Activity在启动过程中的流程组件 在Android Activity启动过程http://blog.csdn.net/jltxgcy/article/details/35984557一文 ...
- Hook技术--Activity的启动过程的拦截
1.寻找Hook点的原则 Android中主要是依靠分析系统源码类来做到的,首先我们得找到被Hook的对象,我称之为Hook点:什么样的对象比较好Hook呢?自然是容易找到的对象.什么样的对象容易找到 ...
- Android Activity学习笔记——Activity的启动和创建
http://www.cnblogs.com/bastard/archive/2012/04/07/2436262.html 最近学习Android相关知识,感觉仅仅了解Activity几个生命周期函 ...
- (笔记)AT91SAM9260的启动过程详细解说
Bootstrap的启动过程 一. 说明: Bootstrap启动代码是官方提供的一级启动代码,包括汇编和C语言两部分组成.对AT91SAM9260来说编译完成后,代码长度必须小于4KB,烧写到dat ...
- Activity 的启动过程深入学习
手机应用也是一个app,每一个应用的icon都罗列在Launcher上,点击icon触发onItemClick事件. 我们要启动「淘宝」这个App,首先我们要在清单文件定义默认启动的Activity信 ...
- Activity的启动过程
详见: http://www.cloudchou.com/android/post-805.html
随机推荐
- Sql入门学习——关系范式
--------关系 --------范式 一.三种关系 1.一对一关系 关系数据库中,第一个表中的单个行只可以与第二个表中的一个行相关,且第二个表中的一个行也只可以与第一个表中的一个行相关. 2.一 ...
- 关于php查询mongodb限制返回字段的问题
最近想做一个前端控制接口字段返回的一个基础方法,通过mongodb 的find($query,$field)查询来规定查询的字段,但是遇到这么一个问题: 工作代码中有两个封装方法 : /** * 查询 ...
- MySQL的or/in/union与索引优化
转载自:MySQL的or/in/union与索引优化 https://blog.csdn.net/zhangweiwei2020/article/details/80005590 假设订单业务表结构为 ...
- Balls(扔鸡蛋问题)
4554 BallsThe classic Two Glass Balls brain-teaser is often posed as:“Given two identical glass sphe ...
- 443. String Compression
原题: 443. String Compression 解题: 看到题目就想到用map计数,然后将计数的位数计算处理,这里的解法并不满足题目的额外O(1)的要求,并且只是返回了结果array的长度,并 ...
- [Shell]Bash变量:数值运算及运算符
------------------------------------------------------------------------------------------------- Sh ...
- (转)SQL SERVER 生成建表脚本
https://www.cnblogs.com/champaign/p/3492510.html /****** Object: StoredProcedure [dbo].[GET_TableScr ...
- android rc文件分析
service vold /system/bin/vold \ --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:bl ...
- centos7-内核版本降级
1. 查看内核版本参考命令: [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) [roo ...
- Python类继承(转发)
目录 一.概述 二.类的继承 2.1 继承的定义 2.2 构造函数的继承 2.3 子类对父类方法的重写 三.类继承的事例 回到顶部 一.概述 面向对象编程 (OOP) 语言的一个主要功能就是“继承”. ...