启动Activity的流程(Launcher中点击图标启动)

来源:互联网 发布:使命召唤13优化怎么样 编辑:程序博客网 时间:2024/05/19 06:49

启动Activity一般有多种方式,常见的有三种:

  1. 在Launcher桌面点击app图标

  2. 调用startActivity启动一个Activity

  3. 命令am start启动

这三种方式在服务端的处理方式基本相同,客户端的请求方式也差别不大,理解其中之一就可以类推到其他方式。本文结合案例分析在Launcher桌面点击app图标启动应用的方式,再简要给出其他两种方式的区别。

案例

应用名称为TestLaunchApp,包含A和B两个Activity,A为入口类,点击按钮跳转到B

A.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
packagecom.example.startapptest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
publicclassAextendsActivity{
privatefinalstaticStringTAG="StartAppTest";
@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.i(TAG,"A"+"--------------onCreate()");
setContentView(R.layout.a_layout);
}
@Override
protectedvoidonResume(){
// TODO Auto-generated method stub
Log.i(TAG,"A"+"--------------onResume()");
super.onResume();
}
@Override
protectedvoidonPause(){
// TODO Auto-generated method stub
Log.i(TAG,"A"+"--------------onPause()");
super.onPause();
}
publicvoidfuncA(View view){
startActivity(newIntent("com.feeyan.www.b_activity"));
}
@Override
publicvoidonBackPressed(){
// TODO Auto-generated method stub
finish();
super.onBackPressed();
}
}


B.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
packagecom.example.startapptest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
publicclassBextendsActivity{
privatefinalstaticStringTAG="StartAppTest";
@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.i(TAG,"B"+"--------------onCreate()");
setContentView(R.layout.b_layout);
}
@Override
protectedvoidonResume(){
Log.i(TAG,"B"+"--------------onResume()");
super.onResume();
}
@Override
protectedvoidonPause(){
// TODO Auto-generated method stub
Log.i(TAG,"B"+"--------------onPause()");
super.onPause();
}
publicvoidfuncB(View view){
startActivity(newIntent("com.feeyan.www.a_activity"));
finish();
}
}


a_layout.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin">
   
   <Button
       android:id="@+id/button_a_id"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
       android:layout_centerHorizontal="true"
       android:layout_marginBottom="50dp"
       android:onClick="funcA"
       android:text="@string/button_a_text"
       android:textSize="20sp"/>
   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentTop="true"
       android:layout_centerHorizontal="true"
       android:layout_marginTop="154dp"
       android:text="@string/page_a_text"
       android:textSize="30sp"/>
</RelativeLayout>


b.layout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin">
   <Button
       android:id="@+id/button_b_id"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
       android:layout_centerHorizontal="true"
       android:layout_marginBottom="50dp"
       android:onClick="funcB"
       android:text="@string/button_b_text"
       android:textSize="20sp"/>
   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_above="@+id/button_b_id"
       android:layout_centerHorizontal="true"
       android:layout_marginBottom="140dp"
       android:text="@string/page_b_text"
       android:textSize="30sp"/>
</RelativeLayout>


AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.startapptest"
   android:versionCode="1"
   android:versionName="1.0">
   <uses-sdk
       android:minSdkVersion="17"
       android:targetSdkVersion="21"/>
   <application
       android:allowBackup="true"
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name"
       android:theme="@style/AppTheme">
       <activity
           android:name=".A"
           android:label="@string/app_name">
           <intent-filter>
               <action android:name="android.intent.action.MAIN"/>
               <category android:name="android.intent.category.LAUNCHER"/>
           </intent-filter>
           <intent-filter>
               <action android:name="com.feeyan.www.a_activity">
               </action>
               <category android:name="android.intent.category.DEFAULT">
               </category>
           </intent-filter>
       </activity>
       <activity
           android:name=".B"
           android:label="@string/app_name">
           <intent-filter>
               <action android:name="com.feeyan.www.b_activity">
               </action>
               <category android:name="android.intent.category.DEFAULT">
               </category>
           </intent-filter>
       </activity>
   </application>
</manifest>

当点击A中的按钮时,跳转到B,先暂停A,A从前台转入到后台,开始执行B的onCreate、onResume方法,B被调入到栈顶,B现在可见,日志为:

1
2
3
4
5
I/StartAppTest(26256):A--------------onCreate()
I/StartAppTest(26256):A--------------onResume()
I/StartAppTest(26256):A--------------onPause()
I/StartAppTest(26256):B--------------onCreate()
I/StartAppTest(26256):B--------------onResume()

启动一个Activity的标志是开始执行生命周期onCreate方法,转入到后台的标志是onPause方法,正在运行、可见的标志是onResume方法,本文将从源码着手,分析启动activity的过程。

1. 在Launcher桌面点击app图标启动入口Activity

本文基于android5.1.1源码,在Launcher主页面当点击图表时,调用过程为:

onClick—->……—->startActivitySafely—->startActivity(v, intent, tag)—->startActivity(intent, optsBundle);

源码:packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

intent设置了FLAG_ACTIVITY_NEW_TASK标志,表示开启一个新任务,在新任务中启动activity,本案例没有特殊的动画设置,optsBundle为null。

framework层客户端

过程1    frameworks\base\core\java\android\app\Activity.java

startActivity所属的对象是this,表示当前启动类Launcher对象,下一步执行到Activity的startActivity方法,过程为:

startActivity(Intent intent, @Nullable Bundle options)

—-> startActivityForResult(intent, -1)

—-> startActivityForResult(intent, requestCode, null)

注:由于源码较长,本文不贴上全部源码,只给出方法名称、部分代码以及源码路径

action为字符串“com.feeyan.www.b_activity”,requestCode等于-1,如果>=0, B被启动后会返回到A中,且A中的onActivityResult()方法会被调用。即便是调用startActivity,还是会调到 startActivityForResult,只不过此时requestCode是-1了。

mParent:如果不为空,表示当前Activity有子类,本案例没有子类,为空,进程执行到:

1
2
3
4
Instrumentation.ActivityResult ar=
               mInstrumentation.execStartActivity(
                   this,mMainThread.getApplicationThread(),mToken,this,
                   intent,requestCode,options);

要搞懂源码,最关键的就是弄清楚参数的具体含义,源码中参数有时候多达十几个,如果不清楚参数的来龙去脉,无从分析。

this:当前进程还是在Launcher所在的进程,this就是Launcher类的一个对象。

mMainThread.getApplicationThread():返回一个ApplicationThread对象类型,也是一个IBinder对象类型,,mMainThread是ActivityThread的一个对象,代表当前Launcher主线程对象

mToken:也是一个IBinder对象类型

requestCode仍为-1,options为null

过程2    frameworks\base\core\java\android\app\Instrumentation.java

1
2
3
4
5
publicActivityResult execStartActivity(
           Context who,IBinder contextThread,IBinder token,Activity target,
           Intent intent,intrequestCode,Bundle options){
           ......
}

this对象传给execStartActivity,该函数的第一个形参who是Context类型,第4个形参target是Activity类型,其实际类型都是Launcher对象,只是名字起的不一样,这就是一种共识,代表着某种含义,读者看到名字就能猜得着其用意。

1
IApplicationThread whoThread=(IApplicationThread)contextThread;

contextThread既是IBinder对象,也是IApplicationThread对象,此处向上转型为IApplicationThread对象,

1
2
3
4
5
intresult=ActivityManagerNative.getDefault()
               .startActivity(whoThread,who.getBasePackageName(),intent,
                       intent.resolveTypeIfNeeded(who.getContentResolver()),
                       token,target!=null?target.mEmbeddedID:null,
                       requestCode,0,null,options);

ActivityManagerNative实现了IActivityManager接口,调用getDefault方法最终返回ActivityManagerService的代理类ActivityManagerProxy的一个对象,于是,startActivity便转入到ActivityManagerProxy对象中开始执行。

过程3    frameworks\base\core\java\android\app\ActivityManagerNative.java

1
2
3
4
5
publicintstartActivity(IApplicationThread caller,StringcallingPackage,Intent intent,
           StringresolvedType,IBinder resultTo,StringresultWho,intrequestCode,
           intstartFlags,ProfilerInfo profilerInfo,Bundle options)throwsRemoteException{
......
}

分析参数时,结合实际参数来看,否则单独看形参不能确定具体含义。

caller:前面传过来的值,代表ApplicationThread对象

callingPackage:由who.getBasePackageName()的值传递而来,who是Context对象,getBasePackageName()的实现在ContextImple中,返回当前启动类的包名,就是Launcher的包名

resolvedType:解析当前发送的Intent的MIME数据类型,本案例没有为intent设置type、data属性,因此,intent.resolveTypeIfNeeded(who.getContentResolver())返回null

resultTo:Ibinder对象,具体含义后面继续看

resultWho:由target != null ? target.mEmbeddedID : null得来,target是activity对象即启动类Launcher对象,不为空,该语句返回mEmbeddedID,一个id号,这个值必须要从Launcher这个apk启动中获得,在Launcher启动后,代表Launcher启动类的对象是一个ActivityClientRecord对象,该对象所属的类路径为:

frameworks\base\core\java\android\app\ActivityThread.java

该对象的scheduleLaunchActivity方法中,有一句:

ActivityClientRecord r = new ActivityClientRecord();

在ActivityClientRecord的构造方法中会把embeddedID初始化为null,因此mEmbeddedID为空

startFlags:整型值,已经初始化为0,具体作用后面分析

profilerInfo:为null,具体作用后面分析

这些参数都会被打包到持久化类Parcel的对象data中,把data作为transact的参数进行跨进程传递:

mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

该方法通过binder通信机制会传递到ActivityManagerNative的onTransact方法,在onTransact方法中,根据发送命令START_ACTIVITY_TRANSACTION找到case处理语句,把data中的数据取出来赋给相应的变量,继续调用:

1
2
intresult=startActivity(app,callingPackage,intent,resolvedType,
                   resultTo,resultWho,requestCode,startFlags,profilerInfo,options);

startActivity最终会调用到服务端ActivityManagerService中。此时,进程也从启动类Launcher所在的进程切换到了服务端进程。从ActivityManagerNative.getDefault().startActivity一直到ActivityManagerService的startActivity方法,主要由binder通信实现,该过程相当复杂,但binder通信不属于本文重点,而且binder机制贯穿于整个Android系统、内核、驱动部分,本文如再遇到binder通信机制,直接给出最终被调用的类及方法。

在进入到服务端之前,看看客户端到底做了哪些工作?

主要是获得了一些必要的参数:IApplicationThread对象、启动类包名、Intent的MIME数据类型、IApplicationToken.Stub类型对象resultTo等,除了这些,没有其他特殊的操作了,其实最关键的操作还是在服务端进行的,这就是为何本文一开始提到无论哪种启动方式,客户端都是大同小异。

framework层服务端

过程4    frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

startActivity—->startActivityAsUser—->mStackSupervisor.startActivityMayWait

1
2
3
mStackSupervisor.startActivityMayWait(caller,-1,callingPackage,intent,
               resolvedType,null,null,resultTo,resultWho,requestCode,startFlags,
               profilerInfo,null,null,options,userId,null,null);

这几步没有太多的操作,获得了一个用户id,用来作一些检测

过程5    frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

1
2
3
4
5
6
7
8
finalintstartActivityMayWait(IApplicationThread caller,intcallingUid,
           StringcallingPackage,Intent intent,StringresolvedType,
           IVoiceInteractionSession voiceSession,IVoiceInteractor voiceInteractor,
           IBinder resultTo,StringresultWho,intrequestCode,intstartFlags,
           ProfilerInfo profilerInfo,WaitResult outResult,Configuration config,
           Bundle options,intuserId,IActivityContainer iContainer,TaskRecord inTask){
   ......
}

先看多了哪些参数:
voiceSession:IVoiceInteractionSession对象类型,被初始化null。IVoiceInteractionSession本是一个aidl远程接口,定义了任务栈启动taskStarted、任务栈结束taskFinished等方法

voiceInteractor:IVoiceInteractor对象类型,被初始化为null。IVoiceInteractor也是一个aidl远程接口

outResult:WaitResult对象类型,被初始化为null。WaitResult是IActivityManager的内部类,实现了Parcelable接口,主要用来保存启动Activity后返回的结果信息

config:Configuration对象类型,被初始化为null。Configuration描述了所有设备相关的配置信息,比如,本地语言、屏幕大小、屏幕方向、输入法模式,可以通过Resources的getConfiguration获得改对象

iContainer:IActivityContainer对象类型,被初始化为null。IActivityContainer也是一个aidl远程接口

inTask:TaskRecord对象类型,被初始化为null。TaskRecord很重要,会经常用到此类,描述一个任务栈,每个任务栈可以包含多个Activity对象,每个TaskRecord对象都有一个当前栈ActivityStack的引用,每个栈可以对应多个TaskRecord对象

除了这些多余的参数,其他参数都是从客户端传递而来。

1
booleancomponentSpecified=intent.getComponent()!=null;

getComponent方法返回一个ComponentName对象,该对象表示通过intent要启动的组件类,本案例就对应A这个Activity,ComponentName对象一般用包名和类名标识一个组件,因此,componentSpecified为true

1
intent=newIntent(intent);

根据客户端传递过来的Intent对象重新构建一个Intent对象,这样做是不要破坏客户端传递来的Intent对象

1
2
3
4
5
6
7
ActivityInfo aInfo=resolveActivity(intent,resolvedType,startFlags,
               profilerInfo,userId);
ActivityInfo resolveActivity(Intent intent,StringresolvedType,intstartFlags,
           ProfilerInfo profilerInfo,intuserId){
   ......
}

resolveActivity方法开始解析Intent对象,返回intent对应的目标Activity类的ActivityInfo对象,ActivityInfo类专门用来描述AndroidManifest.xml中Activity、Receiver组件信息的,本案例返回的就是A这个类对应的信息,ActivityInfo的成员变量name就是类名称,packageName就是包名称,对应本案例分别为com.example.startapptest.A和com.example.startapptest

1
2
3
4
5
6
7
8
if(callingUid>=0){
   callingPid=-1;
}elseif(caller==null){
   callingPid=realCallingPid;
   callingUid=realCallingUid;
}else{
   callingPid=callingUid=-1;
}

callingUid传过来时为-1,call又不为空,进程执行else字句callingPid = callingUid = -1;

1
2
3
4
5
6
7
8
ActivityContainer container=(ActivityContainer)iContainer;
finalActivityStack stack;
if(container==null||container.mStack.isOnHomeDisplay()){
   stack=getFocusedStack();
}else{
   stack=container.mStack;
}

iContainer为空,那么container也为空,调用getFocusedStack获得当前正在前台的栈,也就是Launcher所在的栈。

1
2
3
4
if(aInfo!=null&&
                   (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE)!=0){
   ......
}

aInfo虽然不为空,但aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE却为0,因为没有设置这种属性,因此跳过该if语句,开始执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
intres=startActivityLocked(caller,intent,resolvedType,aInfo,
                   voiceSession,voiceInteractor,resultTo,resultWho,
                   requestCode,callingPid,callingUid,callingPackage,
                   realCallingPid,realCallingUid,startFlags,options,
                   componentSpecified,null,container,inTask);
finalintstartActivityLocked(IApplicationThread caller,
           Intent intent,StringresolvedType,ActivityInfo aInfo,
           IVoiceInteractionSession voiceSession,IVoiceInteractor voiceInteractor,
           IBinder resultTo,StringresultWho,intrequestCode,
           intcallingPid,intcallingUid,StringcallingPackage,
           intrealCallingPid,intrealCallingUid,intstartFlags,Bundle options,
           booleancomponentSpecified,ActivityRecord[]outActivity,ActivityContainer container,
           TaskRecord inTask){
   ......
}

callingPid:int型变量,看字面意思与pid相关,具体含义后面再看

callingUid:int型变量,看字面意思与uid相关,具体含义后面再看

realCallingPid:启动类所在进程的pid,本案例是Launcher

realCallingUid:启动类所在进程的uid,本案例是Launcher

componentSpecified:为true,表明intent对应的目标Activity类存在

outActivity:ActivityRecord数组名称,初始化为null,ActivityRecord是一个动态生成的对象,代表Activity在历史栈中的记录,ActivityRecord包含了Activity所有信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
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=ActivityManager.START_PERMISSION_DENIED;
           }
       }

mService是ActivityManagerService对象,通过getRecordForAppLocked方法获得启动类所在进程的进程记录对象ProcessRecord。参数caller是IApplicationThread对象,前文提到过,实际是ApplicationThread对象,代表Launcher类的主线程,caller在ActivityManagerService和ActivityThread两个进程之间完成通信,现在终于明白了,为何在startActivity时会带着这样一个参数:服务端通过该参数获得客户端进程信息,该参数起到桥梁作用。

callerApp不为空,分别获得启动类进程的pid和uid保存到callingPid、callingUid中,这个callingPid和之前的realCallingPid获得的值一样,都是Launcher进程pid

1
2
3
4
5
6
7
8
9
10
11
12
       ActivityRecord sourceRecord=null;
       ActivityRecord resultRecord=null;
       if(resultTo!=null){
           sourceRecord=isInAnyStackLocked(resultTo);
           if(DEBUG_RESULTS)Slog.v(
               TAG,"Will send result to "+resultTo+" "+sourceRecord);
           if(sourceRecord!=null){
               if(requestCode>=0&&!sourceRecord.finishing){
                   resultRecord=sourceRecord;
               }
           }
       }

定义了两个ActivityRecord变量sourceRecord、resultRecord,用来对应启动类和目标类。上文提到,resultTo属于IBinder对象,属于启动方的对象。isInAnyStackLocked方法根据启动类的标记resultTo对象在列表栈中找出对应的栈,再在栈顶找到Activity记录保存到sourceRecord中。

1
finalintlaunchFlags=intent.getFlags();

上文提到,intent一开始在客户端就被设置了FLAG_ACTIVITY_NEW_TASK标志,getFlags方法便取出该标志,保存到launchFlags变量中。

1
2
3
ActivityRecordr=newActivityRecord(mService,callerApp,callingUid,callingPackage,
               intent,resolvedType,aInfo,mService.mConfiguration,resultRecord,resultWho,
               requestCode,componentSpecified,this,container,options);

创建一个ActivityRecord对象,这个ActivityRecord对象具体有什么作用?看看参数具体含义

前4个参数代表了启动类Launcher,第5~7参数(Intent,resolvedType, aInfo)代表了目标类

mService.mConfiguration表示系统配置,resultRecord代表目标类,resultWho代表启动类的一个id号,为空

componentSpecified为true

this:代表当前ActivityStackSupervisor对象

从参数来看,该类既包含启动类的属性,又包含目标类属性,推测该类应该用来表达目标类,后面可以证明。

startActivityLocked方法的作用:获得启动类进程信息、pid、uid,创建ActivityRecord类对象sourceRecord保存启动类信息,创建ActivityRecord对象r,暂时推测代表目标类,具体含义后面分析。进程继续调用:

1
2
err=startActivityUncheckedLocked(r,sourceRecord,voiceSession,voiceInteractor,
               startFlags,true,options,inTask);

开始调用下一步操作,第一个参数就是刚才创建的ActivityRecord对象;第二个参数是启动类对象,不为空;

1
2
3
4
5
finalintstartActivityUncheckedLocked(ActivityRecordr,ActivityRecord sourceRecord,
           IVoiceInteractionSession voiceSession,IVoiceInteractor voiceInteractor,intstartFlags,
           booleandoResume,Bundle options,TaskRecord inTask){
   ......
}


1
2
finalIntent intent=r.intent;
finalintcallingUid=r.launchedFromUid;

r.intent就是传递而来的intent对象,r.launchedFromUid就是启动类Launcher的uid

1
2
3
finalbooleanlaunchSingleTop=r.launchMode==ActivityInfo.LAUNCH_SINGLE_TOP;
finalbooleanlaunchSingleInstance=r.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE;
finalbooleanlaunchSingleTask=r.launchMode==ActivityInfo.LAUNCH_SINGLE_TASK;

这三个变量代表目标类的启动模式,本案例就是A的启动模式,没有任何设置,默认为Standard模式,因而这三个变量都是false

1
mUserLeaving=(launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION)==0;

FLAG_ACTIVITY_NO_USER_ACTION:当启动目标Activity时Intent设置了此标志,前台正在行的Activity在暂停之前(执行onPaused方法)不会回调onUserLeaveHint方法。NO_USER_ACTION表示非用户操作,如果设置了此标志,表示非用户行为时不会回调onUserLeaveHint。比如,闹钟响了、来电话了,这属于非用户操作,如果设置了此标志,就不会回调onUserLeaveHint,相反,如果是用户操作行为比如按下HOME按键,返回键等,就会回调onUserLeaveHint。本案例中发送给A的Intent没有设置该标志,mUserLeaving为true,表明不是非用户操作行为。

1
2
ActivityRecord notTop=
               (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)!=0?r:null;

Intent没有设置FLAG_ACTIVITY_PREVIOUS_IS_TOP,notTop为空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if(sourceRecord!=null){
           if(sourceRecord.finishing){
               // If the source is finishing, we can't further count it as our source.  This
               // is because the task it is associated with may now be empty and on its way out,
               // so we don't want to blindly throw it in to that task.  Instead we will take
               // the NEW_TASK flow and try to find a task for it. But save the task information
               // so it can be used when creating the new task.
               if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)==0){
                   Slog.w(TAG,"startActivity called from finishing "+sourceRecord
                           +"; forcing "+"Intent.FLAG_ACTIVITY_NEW_TASK for: "+intent);
                   launchFlags|=Intent.FLAG_ACTIVITY_NEW_TASK;
                   newTaskInfo=sourceRecord.info;
                   newTaskIntent=sourceRecord.task.intent;
               }
               sourceRecord=null;
               sourceStack=null;
           }else{
               sourceStack=sourceRecord.task.stack;
           }
       }else{
           sourceStack=null;
       }

sourceRecord不为空,变量finishing为空,因为此时启动类Launcher还在前台,没有进入到销毁列表中,进程执行else语句,得到启动类所在的栈对象并保存到sourceStack中。

1
2
3
4
5
6
7
8
9
if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)!=0&&
               (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK)==0)
               ||launchSingleInstance||launchSingleTask){
           // If bring to front is requested, and no result is requested and we have not
           // been given an explicit task to launch in to, and
           // we can find a task that was started with this same
           // component, then instead of launching bring that one to the front.
           if(inTask==null&&r.resultTo==null){
......

Intent没有设置FLAG_ACTIVITY_MULTIPLE_TASK,resultTo和startActivityLocked参数中resultTo不是一个意思,前者是在startActivityLocked函数中创建的ActivityRecord对象resultRecord,代表目标类一方,被初始化为空,而后者代表启动类一方,不能混淆。

1
2
3
4
ActivityRecord intentActivity=!launchSingleInstance?
                       findTaskLocked(r):findActivityLocked(intent,r.info);
               if(intentActivity!=null){
......

启动A时没有设置启动模式,采用是默认的标准模式,因此launchSingleInstance为false,调用findTaskLocked(r)在当前栈顶中查询是否有目标类,如果有,就返回该类,否则,返回空。因为首次启动A,因此栈中肯定没有A,返回空保存到intentActivity变量中,这样的话,if语句不成立。如果栈中有实例,再次启动时就会执行这段代码。

1
2
3
4
5
6
7
8
9
if(r.packageName!=null){
   ActivityStack topStack=getFocusedStack();
   ActivityRecord top=topStack.topRunningNonDelayedActivityLocked(notTop);
        if(top!=null&&r.resultTo==null){
               if(top.realActivity.equals(r.realActivity)&&top.userId==r.userId){
......
}else{
......
}

目标类包名肯定不为空,执行if条件,getFocusedStack返回当前栈,topRunningNonDelayedActivityLocked返回当前ActivityRecord对象保存到top中,肯定不为空;top.realActivity表示启动类,r.realActivity表示目标类,本案例前者是Launcher,后者是A,两者肯定不相等,因此if语句不成立,跳过此段。如果成立的话,就会在当前栈中找到已存在的实例继续使用。

既然当前栈中没有已存在实例,那么只能新创建一个任务栈,继续看:

1
2
3
4
5
6
7
8
booleannewTask=false;
booleankeepCurTransition=false;
TaskRecord taskToAffiliate=launchTaskBehind&&sourceRecord!=null?
        sourceRecord.task:null;
// Should this be considered a new task?
if(r.resultTo==null&&inTask==null&&!addingToTask
        &&(launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)!=0){
......

此if语句成立,launchTaskBehind为空,那么taskToAffiliate也为空

1
2
newTask=true;
targetStack=adjustStackFocus(r,newTask);

newTask代表新建一个任务的标志,设为true;adjustStackFocus获得一个ActivityStack保存到targetStack变量作为目标类的栈;

1
2
3
4
5
6
7
8
9
if(reuseTask==null){
               r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                       newTaskInfo!=null?newTaskInfo:r.info,
                       newTaskIntent!=null?newTaskIntent:intent,
                       voiceSession,voiceInteractor,!launchTaskBehind/* toTop */),
                       taskToAffiliate);
               if(DEBUG_TASKS)Slog.v(TAG,"Starting new activity "+r+" in new task "+
                       r.task);
           }

createTaskRecord创建TaskRecord对象并放到栈顶,然后再放到目标类ActivityRecord的task变量中

1
2
3
4
5
6
targetStack.mLastPausedActivity=null;
targetStack.startActivityLocked(r,newTask,doResume,keepCurTransition,options);
if(!launchTaskBehind){
    // Don't set focus on an activity that's going to the back.
     mService.setFocusedActivityLocked(r,"startedActivity");
}

调用startActivityLocked进行下一步操作

startActivityUncheckedLocked函数非常复杂,最关键的就是查询是否有已存在的TaskRcord作为目标类的任务栈,如果栈中有就复用,否则就创建一个新的TaskRcord对象作为目标类的任务栈。该函数涉及到了FLAG标志,启动模式的判断等,其目的就是找到一个合适的任务栈,为何要找到这个栈,就是因为Activity在执行时以栈这个数据结构来管理。

过程6    frameworks\base\services\core\java\com\android\server\am\ActivityStack.java

1
2
finalvoidstartActivityLocked(ActivityRecordr,booleannewTask,
           booleandoResume,booleankeepCurTransition,Bundle options)

第一个参数对应目标类对象记录,newTask为true,表示新建了一个任务栈,doResume为true,keepCurTransition为false。

1
2
TaskRecord rTask=r.task;
finalinttaskId=rTask.taskId;

r.task就是在startActivityUncheckedLocked中创建的目标类的RaskRecord对象,取出来保存到rRask变量中

1
2
3
4
5
6
7
if(!r.mLaunchTaskBehind&&(taskForIdLocked(taskId)==null||newTask)){
           // Last activity in task had been removed or ActivityManagerService is reusing task.
           // Insert or replace.
           // Might not even be in.
           insertTaskAtTop(rTask);
           mWindowManager.moveTaskToTop(taskId);
}

mLaunchTaskBehind在上文得知为空,taskForIdLocked在历史栈中查询是否含有id号为目标类所在的栈id,如果有,表明目标类之前已经被创建过,现在开始复用该对象,属于非首次启动,否则为首次启动对象,本案例首次启动A,因此,此函数返回null;newTask传递过来为true,if语句成立,调用insertTaskAtTop函数把新创建的TaskRecord对象插入到列表mTaskHistory的尾部,也就是插入到历史栈顶;

1
2
3
if(doResume){
           mStackSupervisor.resumeTopActivitiesLocked(this,r,options);
}

过程7    frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

1
2
booleanresumeTopActivitiesLocked(ActivityStack targetStack,ActivityRecord target,
           Bundle targetOptions)

this对象表示当前对象ActivityStack,此ActivityStack是新建的对象,不是Launcher所在的ActivityStack,是在startActivityUncheckedLocked中的adjustStackFocus方法获得的,目的就是把新创建的任务插入到该ActivityStack对象中,这个对象就代表了目标类所属的栈

第二个参数r就表示目标类对象记录,第三个参数依然为null

1
2
3
if(isFrontStack(targetStack)){
       result=targetStack.resumeTopActivityLocked(target,targetOptions);
}

isFrontStack判断新获得的ActivityStack对象位于栈顶,判断为真,执行if语句,调用resumeTopActivityLocked(target, targetOptions)

过程8    frameworks\base\services\core\java\com\android\server\am\ActivityStack.java

1
2
3
finalbooleanresumeTopActivityLocked(ActivityRecord prev,Bundle options){
   ......
}

第一个参数prev表示目标类ActivityRecord对象,第二个传递过来为空

1
2
3
4
5
6
7
8
try{
           // Protect against recursion.
           mStackSupervisor.inResumeTopActivity=true;
          ......
           result=resumeTopActivityInnerLocked(prev,options);
       }finally{
           mStackSupervisor.inResumeTopActivity=false;
       }

继续调用resumeTopActivityInnerLocked方法,再调用resumeTopActivityInnerLocked

1
2
3
finalbooleanresumeTopActivityInnerLocked(ActivityRecord prev,Bundle options){
   ......
}


1
2
3
4
5
6
7
// Find the first activity that is not finishing.
finalActivityRecord next=topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
finalbooleanuserLeaving=mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving=false;

topRunningActivityLocked方法找到栈顶的ActivityRecord对象,此处对应着A

mStackSupervisor.mUserLeaving的值在过程5中被设置为true,此处取出来赋值给userLeaving,表明是用户操作行为(按下返回键,HOME按键等);无论是true还是false,此处还是再复位一下,重新设置为false

1
2
3
4
5
booleandontWaitForPause=(next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING)!=0;
booleanpausing=mStackSupervisor.pauseBackStacks(userLeaving,true,dontWaitForPause);
if(mResumedActivity!=null){
      pausing|=startPausingLocked(userLeaving,false,true,dontWaitForPause);      
}

目标类A没有设置FLAG_RESUME_WHILE_PAUSING标志,dontWaitForPause为false

pauseBackStacks函数返回false赋给pausing变量,mResumedActivity表示当前正在前台运行的Activity,就是Launcher,不为空,进程调用startPausingLocked继续执行

1
2
3
4
5
6
pausing|=startPausingLocked(userLeaving,false,true,dontWaitForPause);
finalbooleanstartPausingLocked(booleanuserLeaving,booleanuiSleeping,booleanresuming,
           booleandontWait){
   ......
}

startPausingLocked开始暂停当前Activity,如果成功,返回true,否则false

4个参数分别为false,false,true,false

1
2
3
4
ActivityRecord prev=mResumedActivity;
mResumedActivity=null;
mPausingActivity=prev;
mLastPausedActivity=prev;

mResumedActivity代表Launcher,先赋值给prev再置空;prev赋值给mPausingActivity,表明即将要暂停的Activity是Launcher,mLastPausedActivity也赋值为prev,表示刚刚暂停的Activity是哪个

1
2
3
4
5
6
if(prev.app!=null&&prev.app.thread!=null){
   ......
   prev.app.thread.schedulePauseActivity(prev.appToken,prev.finishing,
                       userLeaving,prev.configChangeFlags,dontWait);
   ......
}

prev.app表示Launcher进程信息,不为空;prev.app.thread是一个IApplicationThread对象,对应Launcher也不为空,进程继续调用schedulePauseActivity方法,此处是一个Binder进程间通信,下一步调用到ApplicationThread对象的schedulePauseActivity方法中,ApplicationThread是ActivityThread内部类


过程9    frameworks\base\core\java\android\app\ActivityThread.java

1
2
3
4
5
6
7
8
publicfinalvoidschedulePauseActivity(IBinder token,booleanfinished,
               booleanuserLeaving,intconfigChanges,booleandontReport){
           sendMessage(
                   finished?H.PAUSE_ACTIVITY_FINISHING:H.PAUSE_ACTIVITY,
                   token,
                   (userLeaving?1:0)|(dontReport?2:0),
                   configChanges);
}

finished传递过来为false,因为Launcher此时还没有执行生命周期方法onPause()、onDestory(),因此没有进入finishing状态,那么,sendMessage的第一个参数值为H.PAUSE_ACTIVITY

sendMessage把消息发送到队列中等待执行,执行方法是Handler的handleMessage方法,通过命令PAUSE_ACTIVITY可以得到执行程序:

1
2
3
4
5
6
7
casePAUSE_ACTIVITY:
   Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"activityPause");
   handlePauseActivity((IBinder)msg.obj,false,(msg.arg1&1)!=0,msg.arg2,
            (msg.arg1&2)!=0);
   maybeSnapshot();
   Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
   break;

继续调用handlePauseActivity方法

1
2
3
4
privatevoidhandlePauseActivity(IBinder token,booleanfinished,
           booleanuserLeaving,intconfigChanges,booleandontReport){
   ......
}

finished为false,userLeaving传递过来为true,configChanges为0,dontReport为false

1
ActivityClientRecordr=mActivities.get(token);

token对应启动类Launcher,此处获得Launcher的ActivityRecord对象

1
2
3
if(userLeaving){
       performUserLeavingActivity(r);
}

调用performUserLeavingActivity方法,performUserLeavingActivity的最终调用过程为:

performUserLeavingActivity—->

mInstrumentation.callActivityOnUserLeaving(r.activity) —->

activity.performUserLeaving() —->

onUserInteraction()

onUserLeaveHint()

意味着,如果是用户操作的主动行为,比如返回按键,遥控器上下左右按键,HOME按键灯,会调用Activity的

onUserInteraction和onUserLeaveHint方法,如果是按键,触摸、轨迹球被分发到Activity时,onUserInteraction会被回调;onUserLeaveHint的作用是当Activity即将进入到后台前被回调,起到提示作用

performUserLeavingActivity执行完后,进程继续调用

1
2
3
4
5
6
7
8
performPauseActivity(token,finished,r.isPreHoneycomb());
finalBundle performPauseActivity(ActivityClientRecordr,booleanfinished,
           booleansaveState){
     .....
     mInstrumentation.callActivityOnPause(r.activity);
     r.paused=true;
}

performPauseActivity方法中继续调用callActivityOnPause方法,参数r.activity代表启动类Launcher


过程9.1    frameworks\base\core\java\android\app\Instrumentation.java

1
2
3
publicvoidcallActivityOnPause(Activity activity){
       activity.performPause();
}


过程9.1.1    frameworks\base\core\java\android\app\Activity.java

1
2
3
4
5
6
7
8
9
finalvoidperformPause(){
       mDoReportFullyDrawn=false;
       mFragments.dispatchPause();
       mCalled=false;
       onPause();
       mResumed=false;
   ......
       mResumed=false;
}

最终调用到Activity的performPause方法,再调用生命周期方法onPause()意味着启动类处于暂停状态了,这一步执行完后返回到performPauseActivity中,执行r.paused = true把启动类的ActivityClientRecord的paused置为true,表示启动类此时已经处于暂停状态了。再返回到handlePauseActivity中,继续执行performPauseActivity后面的语句

1
ActivityManagerNative.getDefault().activityPaused(token);

这一步通过Binder进程间通信机制进入到ActivityManagerService的activityPaused方法中


过程9.2    frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

1
2
3
4
5
publicfinalvoidactivityPaused(IBinder token){
   ......
   stack.activityPausedLocked(token,false);
   .....
}


过程10    frameworks\base\services\core\java\com\android\server\am\ActivityStack.java

1
2
3
finalvoidactivityPausedLocked(IBinder token,booleantimeout){
   ......
}

mPausingActivity表示启动类Launcher,r是Launcher的ActivityRecord对象,if条件为真,进程继续调用completePauseLocked(true)方法

1
2
3
privatevoidcompletePauseLocked(booleanresumeNext){
   ......
}

既然启动类都已经暂停了,那下一步工作是不是就是把目标类启动起来呢?如果是的话,应该会执行生命周期onResume方法,这只是猜测,具体详细看方法的执行过程

参数resumeNext传递过来为true

prev.finishing属性为false,这个属性一直没有设置

mPausingActivity = null;

如果启动类已经stop,就把mPausingActivity设为null

进程继续执行到:

1
2
3
4
finalActivityStack topStack=mStackSupervisor.getFocusedStack();
if(!mService.isSleepingOrShuttingDown()){
       mStackSupervisor.resumeTopActivitiesLocked(topStack,prev,null);
}

当前系统处于非睡眠和关机状态,if条件为真,进程开始调用resumeTopActivitiesLocked方法


过程11    frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

1
2
3
4
booleanresumeTopActivitiesLocked(ActivityStack targetStack,ActivityRecord target,
           Bundle targetOptions){
   ......
}

要清楚方法具体做了什么,一定要先弄清楚参数的含义

形参targetStack的实参是topStack,通过mStackSupervisor.getFocusedStack获得,即当前获得焦点的栈,此处,启动类已经暂停,那么当前栈就是目标类所在的栈,prev是启动类

又调用了resumeTopActivityLocked方法

1
2
3
if(isFrontStack(targetStack)){
        result=targetStack.resumeTopActivityLocked(target,targetOptions);
}


过程12    frameworks\base\services\core\java\com\android\server\am\ActivityStack.java

1
2
3
finalbooleanresumeTopActivityLocked(ActivityRecord prev,Bundle options){
   ......
}

继续调用resumeTopActivityInnerLocked方法

1
2
3
finalbooleanresumeTopActivityInnerLocked(ActivityRecord prev,Bundle options){
   ......
}

再次进入到此方法时,mResumedActivity为空,因为这是在过程8中startPausingLocked方法内设置的,表明启动类Launcher已经不在是当前运行的Activity,因此

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

这个语句就不再成立,进程跳过此句继续执行

1
2
3
4
5
6
7
8
9
if(next.app!=null&&next.app.thread!=null){
   ......
   mStackSupervisor.startSpecificActivityLocked(next,true,false);
   ......
}else{
   ......
   mStackSupervisor.startSpecificActivityLocked(next,true,false);
   ......
}

next就是目标类A,此时A的一些栈等信息已经构建,但是A得进程还没有创建,正常情况下,启动一个新的应用程序一般会创建一个新的进程,应用程序在此进程中执行,特殊情况下可以通过AndroidManifest中process属性执行指定应用程序在某个进程中执行,本文没有设置process属性,默认为启动一个新的进程,本文后面会分析到。由此可知,A还没有进程信息,if语句不成立,进程转到else语句执行


过程13    frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

1
2
3
4
voidstartSpecificActivityLocked(ActivityRecordr,
           booleanandResume,booleancheckConfig){
   ......
}


1
2
3
4
5
6
7
8
9
ProcessRecord app=mService.getProcessRecordLocked(r.processName,
               r.info.applicationInfo.uid,true);
if(app!=null&&app.thread!=null){
   ......
   realStartActivityLocked(r,app,andResume,checkConfig);
   ......
}
mService.startProcessLocked(r.processName,r.info.applicationInfo,true,0,
               "activity",r.intent.getComponent(),false,false,true);

此时A进程还没有创建,所以app为空,跳过if语句,开始调用startProcessLocked方法

假如A的应用程序已经启动,然后在A中启动B,B是A应用程序的一个Activity,那么此时进程已经创建,app就不会为空,进程会调用realStartActivityLocked方法


过程14    frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

1
2
3
4
5
6
7
8
9
finalProcessRecord startProcessLocked(StringprocessName,
           ApplicationInfo info,booleanknownToBeDead,intintentFlags,
           StringhostingType,ComponentName hostingName,booleanallowWhileBooting,
           booleanisolated,booleankeepIfLarge){
       returnstartProcessLocked(processName,info,knownToBeDead,intentFlags,hostingType,
               hostingName,allowWhileBooting,isolated,0/* isolatedUid */,keepIfLarge,
               null/* ABI override */,null/* entryPoint */,null/* entryPointArgs */,
               null/* crashHandler */);
   }


1
2
3
4
5
6
7
8
9
finalProcessRecord startProcessLocked(StringprocessName,ApplicationInfo info,
           booleanknownToBeDead,intintentFlags,StringhostingType,ComponentName hostingName,
           booleanallowWhileBooting,booleanisolated,intisolatedUid,booleankeepIfLarge,
           StringabiOverride,StringentryPoint,String[]entryPointArgs,Runnable crashHandler){
   
   ......
   
}

该方法中会为A创建ProcessRecord信息,然后继续调用

1
2
startProcessLocked(
               app,hostingType,hostingNameStr,abiOverride,entryPoint,entryPointArgs);


1
2
3
4
5
6
7
8
9
privatefinalvoidstartProcessLocked(ProcessRecord app,StringhostingType,
           StringhostingNameStr,StringabiOverride,StringentryPoint,String[]entryPointArgs){
   ......
   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);
   ......
}

此方法中会调用进程的start方法创建一个新的进程,具体是通过zygote进程的来fork一个新的进程,成为子进程,子进程共享父进程资源,几乎和父进程一样。当子进程创建好后,系统会分配一个进程号PID给新进程并返回,否则抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
publicstaticfinalProcessStartResult start(finalStringprocessClass,
                                 finalStringniceName,
                                 intuid,intgid,int[]gids,
                                 intdebugFlags,intmountExternal,
                                 inttargetSdkVersion,
                                 StringseInfo,
                                 Stringabi,
                                 StringinstructionSet,
                                 StringappDataDir,
                                 String[]zygoteArgs){
   ......
}

第一个参数processClass为新创建的进程的入口类即android.app.ActivityThread.java

niceName:新创建的进程的进程名字,用ps命令可以查看到该名字,一般情况下,应用程序的进程名就是包名

如果进程创建成功,待方法start执行完后,系统就会转到ActivityThread.java的main方法入口开始执行,注意这个流程,和我们通常看到的方法调用方法是不一样的。


过程15    frameworks\base\core\java\android\app\ActivityThread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
publicstaticvoidmain(String[]args){
       ......
       Process.setArgV0("<pre-initialized>");
       Looper.prepareMainLooper();
       ActivityThread thread=newActivityThread();
       thread.attach(false);
       if(sMainThreadHandler==null){
           sMainThreadHandler=thread.getHandler();
       }
       if(false){
           Looper.myLooper().setMessageLogging(new
                   LogPrinter(Log.DEBUG,"ActivityThread"));
       }
       Looper.loop();
       thrownewRuntimeException("Main thread loop unexpectedly exited");
}

prepareMainLooper方法创建了looper对象和MessageQueue消息队列;创建了并初始化ActivityThread对象,同时也创建并初始化了ApplicationThread对象mAppThread

1
2
3
4
5
6
thread.attach(false);
privatevoidattach(booleansystem){
   ......
   finalIActivityManager mgr=ActivityManagerNative.getDefault();
   mgr.attachApplication(mAppThread);
}

获得ActivityManagerProxy对象,调用该对象的attachApplication方法,通过binder通信,最终调用到ActivityManagerService的attachApplication方法


过程16    frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

1
2
3
4
5
publicfinalvoidattachApplication(IApplicationThread thread){
       synchronized(this){
   ......
       }
}


1
2
3
4
privatefinalbooleanattachApplicationLocked(IApplicationThread thread,
           intpid){
   ......
}

先通过pid获得ProcessRecord对象,该对象上一步创建过,不为空

1
2
3
4
5
6
7
8
9
app.makeActive(thread,mProcessStats);
app.curAdj=app.setAdj=-100;
app.curSchedGroup=app.setSchedGroup=Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground=null;
updateProcessForegroundLocked(app,false,false);
app.hasShownUi=false;
app.debugging=false;
app.cached=false;
app.killedByAm=false;

初始化该ProcessRecord对象

1
2
3
4
5
6
7
8
9
10
11
// See if the top visible activity is waiting to run in this process...
       if(normalMode){
           try{
               if(mStackSupervisor.attachApplicationLocked(app)){
                   didSomething=true;
               }
           }catch(Exceptione){
               Slog.wtf(TAG,"Exception thrown launching activities in "+app,e);
               badApp=true;
           }
}

这段话就是真正开始启动目标Activity了,本案例就是A

注:在这段话后面分别有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Find any services that should be running in this process...
       if(!badApp){
           try{
               Slog.i("zhulf","---------------------601");
               didSomething|=mServices.attachApplicationLocked(app,processName);
           }catch(Exceptione){
               Slog.wtf(TAG,"Exception thrown starting services in "+app,e);
               badApp=true;
           }
       }
       // Check if a next-broadcast receiver is in this process...
       if(!badApp&&isPendingBroadcastProcessLocked(pid)){
           try{
               didSomething|=sendPendingBroadcastsLocked(app);
           }catch(Exceptione){
               // If the app died trying to launch the receiver we declare it 'bad'
               Slog.wtf(TAG,"Exception thrown dispatching broadcasts in "+app,e);
               badApp=true;
           }
}

用来启动Service、发送广播,此处作为一个备注,如果要分析启动Service、广播,研究这两段语句,本文只研究启动Activity,因此,详细看attachApplicationLocked方法


过程17    frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

1
2
3
booleanattachApplicationLocked(ProcessRecord app)throwsRemoteException{
   ......
}


1
2
3
if(realStartActivityLocked(hr,app,true,true)){
       didSomething=true;
}


1
2
3
4
5
finalbooleanrealStartActivityLocked(ActivityRecordr,
           ProcessRecord app,booleanandResume,booleancheckConfig)
           throwsRemoteException{
   ......
}

hr就是目标类ActivityRecord对象,app是进程名字

1
2
mService.updateLruProcessLocked(app,true,null);
mService.updateOomAdjLocked();

调整进程LRU算法;参与管理进程

1
2
3
4
5
app.thread.scheduleLaunchActivity(newIntent(r.intent),r.appToken,
                   System.identityHashCode(r),r.info,newConfiguration(mService.mConfiguration),
                   r.compat,r.launchedFromPackage,r.task.voiceInteractor,app.repProcState,
                   r.icicle,r.persistentState,results,newIntents,!andResume,
                   mService.isNextTransitionForward(),profilerInfo);

app.thrad是IApplicationThread对象,此处就是ApplicationThreadProxy对象接口,这里也是Binder通信过程,调用ApplicationThreadProxy的scheduleLaunchActivity方法,通过binder通信转到ApplicationThread对象的scheduleLaunchActivity方法,该方法在ActivityThread对象中


过程18    frameworks\base\core\java\android\app\ActivityThread.java

1
2
3
4
5
6
7
8
publicfinalvoidscheduleLaunchActivity(Intent intent,IBinder token,intident,
               ActivityInfo info,Configuration curConfig,CompatibilityInfo compatInfo,
               Stringreferrer,IVoiceInteractor voiceInteractor,intprocState,Bundle state,
               PersistableBundle persistentState,List<ResultInfo>pendingResults,
               List<ReferrerIntent>pendingNewIntents,booleannotResumed,booleanisForward,
               ProfilerInfo profilerInfo){
   ....
}

该方法创建了目标类对应的ActivityClientRecord对象,而后初始化该对象,作为sendMessage参数发送到消息队列待处理

1
2
3
4
5
6
caseLAUNCH_ACTIVITY:{
                   finalActivityClientRecordr=(ActivityClientRecord)msg.obj;
                   r.packageInfo=getPackageInfoNoCheck(
                           r.activityInfo.applicationInfo,r.compatInfo);
                   handleLaunchActivity(r,null);
                   }


1
2
3
privatevoidhandleLaunchActivity(ActivityClientRecordr,Intent customIntent){
   ......
}

该方法分为两个部分,先调用performLaunchActivity,再调用handleResumeActivity,最后还有finishActivity

先看performLaunchActivity

1
2
3
privateActivity performLaunchActivity(ActivityClientRecordr,Intent customIntent){
   ......
}


1
ActivityInfo aInfo=r.activityInfo;

从目标类ActivityClientRecord对象中取出ActivityInfo对象,ActivityInfo对象包含了Activity、receiver对象信息

1
ComponentName component=r.intent.getComponent();

再根据Intent获得组件对象component,组件包含了启动类名称和包名称

1
2
3
java.lang.ClassLoader cl=r.packageInfo.getClassLoader();
activity=mInstrumentation.newActivity(
                   cl,component.getClassName(),r.intent);

通过Java反射机制找到目标类文件,再创建目标类的一个对象赋值给activity。从此处可知,原来Android中Activity对象是在启动时创建的,系统已经帮助程序员写好了new Activity对象的动作,无需程序员自行new对象,这解决了一开始学习android时总是搞不清楚Activity对象是从什么时候创建的的困惑,因此,Android并不关注组件的创建过程,而把关注点落在了组件的生命周期上。

1
Application app=r.packageInfo.makeApplication(false,mInstrumentation);

makeApplication方法也是利用反射机制找到应用程序Application类并创建一个对象,并调用Application对象的onCreate方法,这就是为什么应用一启动后,Application的onCreate比Activity的onCreate先执行的原因!

1
2
3
4
5
Context appContext=createBaseContextForActivity(r,activity);
activity.attach(appContext,this,getInstrumentation(),r.token,
                       r.ident,app,r.intent,r.activityInfo,title,r.parent,
                       r.embeddedID,r.lastNonConfigurationInstances,config,
                       r.referrer,r.voiceInteractor);

createBaseContextForActivity方法中会调用createActivityContext创建ContextImpl对象,ContextImpl实现了Context,也就同时创建了上下文管理者Context对象,这也解决了为什么在写程序时总是能够获得Context对象的原因

attach方法把Context对象、Instrumentation对象等和Activity关联起来

1
mInstrumentation.callActivityOnCreate(activity,r.state);

通过Instrumentation对象的callActivityOnCreate方法进入到Instrumentation对象中,Instrumentation对象就是监控所有用户和系统之间的交互操作,比如onCreate、onResume等

过程19    frameworks\base\core\java\android\app\Instrumentation.java

1
2
3
4
5
publicvoidcallActivityOnCreate(Activity activity,Bundle icicle){
       prePerformCreate(activity);
       activity.performCreate(icicle);
       postPerformCreate(activity);
}

继续调用performCreate方法

过程20    frameworks\base\core\java\android\app\Activity.java

1
2
3
4
5
finalvoidperformCreate(Bundle icicle){
       onCreate(icicle);
       mActivityTransitionState.readState(icicle);
       performCreateCommon();
}

最终调用Activity的onCreate方法开始生命周期

再返回到handleLaunchActivity中,进程继续执行到handleResumeActivity方法

1
2
3
4
ActivityClientRecordr=performResumeActivity(token,clearHide);
r.activity.performResume();
mInstrumentation.callActivityOnResume(this);
activity.onResume();

这四步写在一个代码段,可以看到最终调用了Activity的onResume方法,目标类A启动起来了并成为可见状态

到此处为止,在Launcher中启动Activity的过程就分析完了。

整个过程相当复杂,涉及到很多动态对象,进程间通信,栈的管理等,可以不必要理解每句代码,但是清楚整个流程做了哪些核心的动作是有必要的:

1.  过程5

resolveActivity方法中调用了包管理器PackageManager的resolveIntent方法解析启动目标类的Intent对象,获得解析后的对象ActivityInfo,为何要获得这个对象,这个对象有有什么作用?

在AndroidManifest.xml中Activity和receiver标签包含了很多属性,比如主题、启动模式、屏幕方向,输入法设置,进程名称等,ActivityInfo就是对应目标类Activity的一个动态对象,该对象包含了这些属性信息。该对象的作用用来构建目标类对应的ActivityRecord对象,该对象也是一个动态对象,是历史栈中的一条记录,在内存中对应目标类。

这样就明白一个问题:启动activity时有显示和隐式,对于隐式方式,只需要在目标类中intetn-filter中增加一个action,然后启动类通过这个action即可启动目标类,这是如何做到的?实际上是通过包管理器PackageManager解析intent,查找到匹配的action对应的目标类的。

2. 过程8

startPausingLocked方法是进入到暂停启动类过程的标志,逐步调用prev.app.thread.schedulePauseActivity,然后又binder通信进入到ApplicationThread对象的schedulePauseActivity方法,在此方法中,发送消息给启动类Launcher主线程ActivityThread,ActivityThread利用handler循环处理消息,调用handlePauseActivity方法处理,最终调用到Activity的生命周期方法onPause暂停启动类

3.  过程14

Process对象的start方法开启了一个新的进程作为目标类的主线程,由此,目标类开始从ActivityThread的main方法开支执行,然后由

mgr.attachApplication(mAppThread);

语句通过binder通信进入到ActivityManagerService中,并传递了ApplicationThread对象,该对象传入到ActivityManagerService中后构建目标类进程信息,然后ActivityManagerService负责启动目标类,最终通过该对象又通过Binder通信返回到ApplicationThread对象中,然后ApplicationThread对象又发送消息给目标类主线程ActivityThread对象,该对象循环处理来自ActivityManagerService的消息,进而调用Activity的生命周期方法onCreate、onResume。其中,IApplicationThread远程接口对象起着非常关键作用,他在主线程对象ActivityThread与Activity管理器ActivityManagerService对象之间起着通信桥梁作用。

ActivityManagerService是Activity Manager(注意,分开大写,代表Framework层的核心模块,该模块包含了ActivityManagerService、ActivityStack、Binder接口等)的核心部分,负责启动Activity、Service、发送Broadcast Receiver、启动ContentProvider;调整进程调度算法,管理任务栈、检查权限等一些列核心功能。


2. 调用startActivity启动一个Activity

在应用程序内启动Activity,和应用程序外启动最根本的不同在于不会新创建进程,也就是说,过程13中,不会执行startProcessLocked方法,而执行realStartActivityLocked方法,过程13~过程16可以省略不看,此时在同一个进程中;除此之外,就是栈的获取不一样,用startActivity方法启动可能不会新建栈,直接使用已有的栈,而Launcher启动时一般会新建栈。

3. 命令am start启动

这种方法适合调试时使用,在串口中直接采用

am start -n xxx/.yyy

即可启动应用程序,包名是xxx,入口类名是yyy

am 这个可执行程序对应的源码目录位置:

1
framework\base\cmds\am\src\com\android\commands\am\Am.java

当执行这条命令时,先从main方法开始执行

1
2
3
publicstaticvoidmain(String[]args){
       (newAm()).run(args);
}

Am继承了BaseCommand类,run方法在BaseCommand中定义,在run方法中又调用了onRun()方法,系统运行时具体类型是Am,这样就调到了Am的onRun方法。onRun中先执行:

1
mAm=ActivityManagerNative.getDefault();

获得ActivityManagerService的代理类ActivityManagerProxy的一个对象

1
2
3
4
Stringop=nextArgRequired();
if(op.equals("start")){
    runStart();
}

判断参数是否有start这个字符串,如果有,就调用runStart方法,本文启动Activity当然含有start参数

在runStart方法中,会执行这一句

1
2
res=mAm.startActivityAsUser(null,null,intent,mimeType,
                       null,null,0,mStartFlags,profilerInfo,null,mUserId);

这一步会继续调用ActivityStackSupervisor的startActivityMayWait方法,与上文的“过程4”一样,后面的步骤基本上差不多。

不管哪种方式启动,在服务端的操作基本上相同,区别就在于是否复用当前栈还是新创建一个栈,是否新建一个进程作为目标类的进程等;在客户端,区别在于启动Activity的方式不同,第三种命令启动方式缺少了startActivity部分。

http://blogread.cn/it/article/8026 

0 0
原创粉丝点击