启动Activity一般有多种方式,常见的有三种:
在Launcher桌面点击app图标
调用startActivity启动一个Activity
命令am start启动
这三种方式在服务端的处理方式基本相同,客户端的请求方式也差别不大,理解其中之一就可以类推到其他方式。本文结合案例分析在Launcher桌面点击app图标启动应用的方式,再简要给出其他两种方式的区别。
案例
应用名称为TestLaunchApp,包含A和B两个Activity,A为入口类,点击按钮跳转到B
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(); } } |
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(); } } |
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> |
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> |
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现在可见,日志为:
| 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有子类,本案例没有子类,为空,进程执行到:
| 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
| publicActivityResult execStartActivity( Context who,IBinder contextThread,IBinder token,Activity target, Intent intent,intrequestCode,Bundle options){ ...... } |
this对象传给execStartActivity,该函数的第一个形参who是Context类型,第4个形参target是Activity类型,其实际类型都是Launcher对象,只是名字起的不一样,这就是一种共识,代表着某种含义,读者看到名字就能猜得着其用意。
| IApplicationThread whoThread=(IApplicationThread)contextThread; |
contextThread既是IBinder对象,也是IApplicationThread对象,此处向上转型为IApplicationThread对象,
| 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
| 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中的数据取出来赋给相应的变量,继续调用:
| 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
| 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
| 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对象
除了这些多余的参数,其他参数都是从客户端传递而来。
| booleancomponentSpecified=intent.getComponent()!=null; |
getComponent方法返回一个ComponentName对象,该对象表示通过intent要启动的组件类,本案例就对应A这个Activity,ComponentName对象一般用包名和类名标识一个组件,因此,componentSpecified为true
| intent=newIntent(intent); |
根据客户端传递过来的Intent对象重新构建一个Intent对象,这样做是不要破坏客户端传递来的Intent对象
| 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
| if(callingUid>=0){ callingPid=-1; }elseif(caller==null){ callingPid=realCallingPid; callingUid=realCallingUid; }else{ callingPid=callingUid=-1; } |
callingUid传过来时为-1,call又不为空,进程执行else字句callingPid = callingUid = -1;
| ActivityContainer container=(ActivityContainer)iContainer; finalActivityStack stack; if(container==null||container.mStack.isOnHomeDisplay()){ stack=getFocusedStack(); }else{ stack=container.mStack; } |
iContainer为空,那么container也为空,调用getFocusedStack获得当前正在前台的栈,也就是Launcher所在的栈。
| if(aInfo!=null&& (aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE)!=0){ ...... } |
aInfo虽然不为空,但aInfo.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE却为0,因为没有设置这种属性,因此跳过该if语句,开始执行:
| 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所有信息。
| 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
| 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中。
| finalintlaunchFlags=intent.getFlags(); |
上文提到,intent一开始在客户端就被设置了FLAG_ACTIVITY_NEW_TASK标志,getFlags方法便取出该标志,保存到launchFlags变量中。
| 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,暂时推测代表目标类,具体含义后面分析。进程继续调用:
| err=startActivityUncheckedLocked(r,sourceRecord,voiceSession,voiceInteractor, startFlags,true,options,inTask); |
开始调用下一步操作,第一个参数就是刚才创建的ActivityRecord对象;第二个参数是启动类对象,不为空;
| finalintstartActivityUncheckedLocked(ActivityRecordr,ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession,IVoiceInteractor voiceInteractor,intstartFlags, booleandoResume,Bundle options,TaskRecord inTask){ ...... } |
| finalIntent intent=r.intent; finalintcallingUid=r.launchedFromUid; |
r.intent就是传递而来的intent对象,r.launchedFromUid就是启动类Launcher的uid
| finalbooleanlaunchSingleTop=r.launchMode==ActivityInfo.LAUNCH_SINGLE_TOP; finalbooleanlaunchSingleInstance=r.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE; finalbooleanlaunchSingleTask=r.launchMode==ActivityInfo.LAUNCH_SINGLE_TASK; |
这三个变量代表目标类的启动模式,本案例就是A的启动模式,没有任何设置,默认为Standard模式,因而这三个变量都是false
| 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,表明不是非用户操作行为。
| 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中。
| 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,代表目标类一方,被初始化为空,而后者代表启动类一方,不能混淆。
| ActivityRecord intentActivity=!launchSingleInstance? findTaskLocked(r):findActivityLocked(intent,r.info); if(intentActivity!=null){ ...... |
启动A时没有设置启动模式,采用是默认的标准模式,因此launchSingleInstance为false,调用findTaskLocked(r)在当前栈顶中查询是否有目标类,如果有,就返回该类,否则,返回空。因为首次启动A,因此栈中肯定没有A,返回空保存到intentActivity变量中,这样的话,if语句不成立。如果栈中有实例,再次启动时就会执行这段代码。
| 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语句不成立,跳过此段。如果成立的话,就会在当前栈中找到已存在的实例继续使用。
既然当前栈中没有已存在实例,那么只能新创建一个任务栈,继续看:
| 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也为空
| newTask=true; targetStack=adjustStackFocus(r,newTask); |
newTask代表新建一个任务的标志,设为true;adjustStackFocus获得一个ActivityStack保存到targetStack变量作为目标类的栈;
| 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变量中
| 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
| finalvoidstartActivityLocked(ActivityRecordr,booleannewTask, booleandoResume,booleankeepCurTransition,Bundle options) |
第一个参数对应目标类对象记录,newTask为true,表示新建了一个任务栈,doResume为true,keepCurTransition为false。
| TaskRecord rTask=r.task; finalinttaskId=rTask.taskId; |
r.task就是在startActivityUncheckedLocked中创建的目标类的RaskRecord对象,取出来保存到rRask变量中
| 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的尾部,也就是插入到历史栈顶;
| if(doResume){ mStackSupervisor.resumeTopActivitiesLocked(this,r,options); } |
过程7 frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
| booleanresumeTopActivitiesLocked(ActivityStack targetStack,ActivityRecord target, Bundle targetOptions) |
this对象表示当前对象ActivityStack,此ActivityStack是新建的对象,不是Launcher所在的ActivityStack,是在startActivityUncheckedLocked中的adjustStackFocus方法获得的,目的就是把新创建的任务插入到该ActivityStack对象中,这个对象就代表了目标类所属的栈
第二个参数r就表示目标类对象记录,第三个参数依然为null
| 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
| finalbooleanresumeTopActivityLocked(ActivityRecord prev,Bundle options){ ...... } |
第一个参数prev表示目标类ActivityRecord对象,第二个传递过来为空
| try{ // Protect against recursion. mStackSupervisor.inResumeTopActivity=true; ...... result=resumeTopActivityInnerLocked(prev,options); }finally{ mStackSupervisor.inResumeTopActivity=false; } |
继续调用resumeTopActivityInnerLocked方法,再调用resumeTopActivityInnerLocked
| finalbooleanresumeTopActivityInnerLocked(ActivityRecord prev,Bundle options){ ...... } |
| // 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
| 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继续执行
| pausing|=startPausingLocked(userLeaving,false,true,dontWaitForPause); finalbooleanstartPausingLocked(booleanuserLeaving,booleanuiSleeping,booleanresuming, booleandontWait){ ...... } |
startPausingLocked开始暂停当前Activity,如果成功,返回true,否则false
4个参数分别为false,false,true,false
| ActivityRecord prev=mResumedActivity; mResumedActivity=null; mPausingActivity=prev; mLastPausedActivity=prev; |
mResumedActivity代表Launcher,先赋值给prev再置空;prev赋值给mPausingActivity,表明即将要暂停的Activity是Launcher,mLastPausedActivity也赋值为prev,表示刚刚暂停的Activity是哪个
| 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
| 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可以得到执行程序:
| 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方法
| privatevoidhandlePauseActivity(IBinder token,booleanfinished, booleanuserLeaving,intconfigChanges,booleandontReport){ ...... } |
finished为false,userLeaving传递过来为true,configChanges为0,dontReport为false
| ActivityClientRecordr=mActivities.get(token); |
token对应启动类Launcher,此处获得Launcher的ActivityRecord对象
| if(userLeaving){ performUserLeavingActivity(r); } |
调用performUserLeavingActivity方法,performUserLeavingActivity的最终调用过程为:
performUserLeavingActivity—->
mInstrumentation.callActivityOnUserLeaving(r.activity) —->
activity.performUserLeaving() —->
onUserInteraction()
onUserLeaveHint()
意味着,如果是用户操作的主动行为,比如返回按键,遥控器上下左右按键,HOME按键灯,会调用Activity的
onUserInteraction和onUserLeaveHint方法,如果是按键,触摸、轨迹球被分发到Activity时,onUserInteraction会被回调;onUserLeaveHint的作用是当Activity即将进入到后台前被回调,起到提示作用
performUserLeavingActivity执行完后,进程继续调用
| 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
| publicvoidcallActivityOnPause(Activity activity){ activity.performPause(); } |
过程9.1.1 frameworks\base\core\java\android\app\Activity.java
| finalvoidperformPause(){ mDoReportFullyDrawn=false; mFragments.dispatchPause(); mCalled=false; onPause(); mResumed=false; ...... mResumed=false; } |
最终调用到Activity的performPause方法,再调用生命周期方法onPause()意味着启动类处于暂停状态了,这一步执行完后返回到performPauseActivity中,执行r.paused = true把启动类的ActivityClientRecord的paused置为true,表示启动类此时已经处于暂停状态了。再返回到handlePauseActivity中,继续执行performPauseActivity后面的语句
| ActivityManagerNative.getDefault().activityPaused(token); |
这一步通过Binder进程间通信机制进入到ActivityManagerService的activityPaused方法中
过程9.2 frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
| publicfinalvoidactivityPaused(IBinder token){ ...... stack.activityPausedLocked(token,false); ..... } |
过程10 frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
| finalvoidactivityPausedLocked(IBinder token,booleantimeout){ ...... } |
mPausingActivity表示启动类Launcher,r是Launcher的ActivityRecord对象,if条件为真,进程继续调用completePauseLocked(true)方法
| privatevoidcompletePauseLocked(booleanresumeNext){ ...... } |
既然启动类都已经暂停了,那下一步工作是不是就是把目标类启动起来呢?如果是的话,应该会执行生命周期onResume方法,这只是猜测,具体详细看方法的执行过程
参数resumeNext传递过来为true
prev.finishing属性为false,这个属性一直没有设置
mPausingActivity = null;
如果启动类已经stop,就把mPausingActivity设为null
进程继续执行到:
| 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
| booleanresumeTopActivitiesLocked(ActivityStack targetStack,ActivityRecord target, Bundle targetOptions){ ...... } |
要清楚方法具体做了什么,一定要先弄清楚参数的含义
形参targetStack的实参是topStack,通过mStackSupervisor.getFocusedStack获得,即当前获得焦点的栈,此处,启动类已经暂停,那么当前栈就是目标类所在的栈,prev是启动类
又调用了resumeTopActivityLocked方法
| if(isFrontStack(targetStack)){ result=targetStack.resumeTopActivityLocked(target,targetOptions); } |
过程12 frameworks\base\services\core\java\com\android\server\am\ActivityStack.java
| finalbooleanresumeTopActivityLocked(ActivityRecord prev,Bundle options){ ...... } |
继续调用resumeTopActivityInnerLocked方法
| finalbooleanresumeTopActivityInnerLocked(ActivityRecord prev,Bundle options){ ...... } |
再次进入到此方法时,mResumedActivity为空,因为这是在过程8中startPausingLocked方法内设置的,表明启动类Launcher已经不在是当前运行的Activity,因此
| if(mResumedActivity!=null){ if(DEBUG_STATES)Slog.d(TAG,"resumeTopActivityLocked: Pausing "+mResumedActivity); pausing|=startPausingLocked(userLeaving,false,true,dontWaitForPause); } |
这个语句就不再成立,进程跳过此句继续执行
| 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
| voidstartSpecificActivityLocked(ActivityRecordr, booleanandResume,booleancheckConfig){ ...... } |
| 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
| 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 */); } |
| finalProcessRecord startProcessLocked(StringprocessName,ApplicationInfo info, booleanknownToBeDead,intintentFlags,StringhostingType,ComponentName hostingName, booleanallowWhileBooting,booleanisolated,intisolatedUid,booleankeepIfLarge, StringabiOverride,StringentryPoint,String[]entryPointArgs,Runnable crashHandler){ ...... } |
该方法中会为A创建ProcessRecord信息,然后继续调用
| startProcessLocked( app,hostingType,hostingNameStr,abiOverride,entryPoint,entryPointArgs); |
| 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给新进程并返回,否则抛出异常
| 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
| 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
| publicfinalvoidattachApplication(IApplicationThread thread){ synchronized(this){ ...... } } |
| privatefinalbooleanattachApplicationLocked(IApplicationThread thread, intpid){ ...... } |
先通过pid获得ProcessRecord对象,该对象上一步创建过,不为空
| 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对象
| // 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
| booleanattachApplicationLocked(ProcessRecord app)throwsRemoteException{ ...... } |
| if(realStartActivityLocked(hr,app,true,true)){ didSomething=true; } |
| finalbooleanrealStartActivityLocked(ActivityRecordr, ProcessRecord app,booleanandResume,booleancheckConfig) throwsRemoteException{ ...... } |
hr就是目标类ActivityRecord对象,app是进程名字
| mService.updateLruProcessLocked(app,true,null); mService.updateOomAdjLocked(); |
调整进程LRU算法;参与管理进程
| 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
| 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参数发送到消息队列待处理
| caseLAUNCH_ACTIVITY:{ finalActivityClientRecordr=(ActivityClientRecord)msg.obj; r.packageInfo=getPackageInfoNoCheck( r.activityInfo.applicationInfo,r.compatInfo); handleLaunchActivity(r,null); } |
| privatevoidhandleLaunchActivity(ActivityClientRecordr,Intent customIntent){ ...... } |
该方法分为两个部分,先调用performLaunchActivity,再调用handleResumeActivity,最后还有finishActivity
先看performLaunchActivity
| privateActivity performLaunchActivity(ActivityClientRecordr,Intent customIntent){ ...... } |
| ActivityInfo aInfo=r.activityInfo; |
从目标类ActivityClientRecord对象中取出ActivityInfo对象,ActivityInfo对象包含了Activity、receiver对象信息
| ComponentName component=r.intent.getComponent(); |
再根据Intent获得组件对象component,组件包含了启动类名称和包名称
| 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并不关注组件的创建过程,而把关注点落在了组件的生命周期上。
| Application app=r.packageInfo.makeApplication(false,mInstrumentation); |
makeApplication方法也是利用反射机制找到应用程序Application类并创建一个对象,并调用Application对象的onCreate方法,这就是为什么应用一启动后,Application的onCreate比Activity的onCreate先执行的原因!
| 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关联起来
| mInstrumentation.callActivityOnCreate(activity,r.state); |
通过Instrumentation对象的callActivityOnCreate方法进入到Instrumentation对象中,Instrumentation对象就是监控所有用户和系统之间的交互操作,比如onCreate、onResume等
过程19 frameworks\base\core\java\android\app\Instrumentation.java
| publicvoidcallActivityOnCreate(Activity activity,Bundle icicle){ prePerformCreate(activity); activity.performCreate(icicle); postPerformCreate(activity); } |
继续调用performCreate方法
过程20 frameworks\base\core\java\android\app\Activity.java
| finalvoidperformCreate(Bundle icicle){ onCreate(icicle); mActivityTransitionState.readState(icicle); performCreateCommon(); } |
最终调用Activity的onCreate方法开始生命周期
再返回到handleLaunchActivity中,进程继续执行到handleResumeActivity方法
| 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 这个可执行程序对应的源码目录位置:
| framework\base\cmds\am\src\com\android\commands\am\Am.java |
当执行这条命令时,先从main方法开始执行
| publicstaticvoidmain(String[]args){ (newAm()).run(args); } |
Am继承了BaseCommand类,run方法在BaseCommand中定义,在run方法中又调用了onRun()方法,系统运行时具体类型是Am,这样就调到了Am的onRun方法。onRun中先执行:
| mAm=ActivityManagerNative.getDefault(); |
获得ActivityManagerService的代理类ActivityManagerProxy的一个对象
| Stringop=nextArgRequired(); if(op.equals("start")){ runStart(); } |
判断参数是否有start这个字符串,如果有,就调用runStart方法,本文启动Activity当然含有start参数
在runStart方法中,会执行这一句
| res=mAm.startActivityAsUser(null,null,intent,mimeType, null,null,0,mStartFlags,profilerInfo,null,mUserId); |
这一步会继续调用ActivityStackSupervisor的startActivityMayWait方法,与上文的“过程4”一样,后面的步骤基本上差不多。
不管哪种方式启动,在服务端的操作基本上相同,区别就在于是否复用当前栈还是新创建一个栈,是否新建一个进程作为目标类的进程等;在客户端,区别在于启动Activity的方式不同,第三种命令启动方式缺少了startActivity部分。
建议继续学习:
- osx平台上lol英雄联盟launcher启动器的分析实现 (阅读:4724)
- 启动activity的4种模式(standard、singleTop、singleTask、singleINstance) (阅读:1536)
- launchAnyWhere: Activity组件权限绕过漏洞解析(Google Bug 7699048 ) (阅读:988)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习