日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時(shí)間:2024/1/8 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 启动Activity的流程(Launcher中点击图标启动) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

啟動(dòng)Activity一般有多種方式,常見的有三種:

  • 在Launcher桌面點(diǎn)擊app圖標(biāo)

  • 調(diào)用startActivity啟動(dòng)一個(gè)Activity

  • 命令am start啟動(dòng)

  • 這三種方式在服務(wù)端的處理方式基本相同,客戶端的請(qǐng)求方式也差別不大,理解其中之一就可以類推到其他方式。本文結(jié)合案例分析在Launcher桌面點(diǎn)擊app圖標(biāo)啟動(dòng)應(yīng)用的方式,再簡(jiǎn)要給出其他兩種方式的區(qū)別。

    案例

    應(yīng)用名稱為TestLaunchApp,包含A和B兩個(gè)Activity,A為入口類,點(diǎn)擊按鈕跳轉(zhuǎn)到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>

    當(dāng)點(diǎn)擊A中的按鈕時(shí),跳轉(zhuǎn)到B,先暫停A,A從前臺(tái)轉(zhuǎn)入到后臺(tái),開始執(zhí)行B的onCreate、onResume方法,B被調(diào)入到棧頂,B現(xiàn)在可見,日志為:

    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()

    啟動(dòng)一個(gè)Activity的標(biāo)志是開始執(zhí)行生命周期onCreate方法,轉(zhuǎn)入到后臺(tái)的標(biāo)志是onPause方法,正在運(yùn)行、可見的標(biāo)志是onResume方法,本文將從源碼著手,分析啟動(dòng)activity的過程。

    1. 在Launcher桌面點(diǎn)擊app圖標(biāo)啟動(dòng)入口Activity

    本文基于android5.1.1源碼,在Launcher主頁(yè)面當(dāng)點(diǎn)擊圖表時(shí),調(diào)用過程為:

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

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

    intent設(shè)置了FLAG_ACTIVITY_NEW_TASK標(biāo)志,表示開啟一個(gè)新任務(wù),在新任務(wù)中啟動(dòng)activity,本案例沒有特殊的動(dòng)畫設(shè)置,optsBundle為null。

    framework層客戶端

    過程1 ? ?frameworks\base\core\java\android\app\Activity.java

    startActivity所屬的對(duì)象是this,表示當(dāng)前啟動(dòng)類Launcher對(duì)象,下一步執(zhí)行到Activity的startActivity方法,過程為:

    startActivity(Intent intent, @Nullable Bundle options)

    —-> startActivityForResult(intent, -1)

    —-> startActivityForResult(intent, requestCode, null)

    注:由于源碼較長(zhǎng),本文不貼上全部源碼,只給出方法名稱、部分代碼以及源碼路徑

    action為字符串“com.feeyan.www.b_activity”,requestCode等于-1,如果>=0, B被啟動(dòng)后會(huì)返回到A中,且A中的onActivityResult()方法會(huì)被調(diào)用。即便是調(diào)用startActivity,還是會(huì)調(diào)到 startActivityForResult,只不過此時(shí)requestCode是-1了。

    mParent:如果不為空,表示當(dāng)前Activity有子類,本案例沒有子類,為空,進(jìn)程執(zhí)行到:

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

    要搞懂源碼,最關(guān)鍵的就是弄清楚參數(shù)的具體含義,源碼中參數(shù)有時(shí)候多達(dá)十幾個(gè),如果不清楚參數(shù)的來龍去脈,無從分析。

    this:當(dāng)前進(jìn)程還是在Launcher所在的進(jìn)程,this就是Launcher類的一個(gè)對(duì)象。

    mMainThread.getApplicationThread():返回一個(gè)ApplicationThread對(duì)象類型,也是一個(gè)IBinder對(duì)象類型,,mMainThread是ActivityThread的一個(gè)對(duì)象,代表當(dāng)前Launcher主線程對(duì)象

    mToken:也是一個(gè)IBinder對(duì)象類型

    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對(duì)象傳給execStartActivity,該函數(shù)的第一個(gè)形參who是Context類型,第4個(gè)形參target是Activity類型,其實(shí)際類型都是Launcher對(duì)象,只是名字起的不一樣,這就是一種共識(shí),代表著某種含義,讀者看到名字就能猜得著其用意。

    1 IApplicationThread?whoThread=(IApplicationThread)contextThread;

    contextThread既是IBinder對(duì)象,也是IApplicationThread對(duì)象,此處向上轉(zhuǎn)型為IApplicationThread對(duì)象,

    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實(shí)現(xiàn)了IActivityManager接口,調(diào)用getDefault方法最終返回ActivityManagerService的代理類ActivityManagerProxy的一個(gè)對(duì)象,于是,startActivity便轉(zhuǎn)入到ActivityManagerProxy對(duì)象中開始執(zhí)行。

    過程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{ ...... }

    分析參數(shù)時(shí),結(jié)合實(shí)際參數(shù)來看,否則單獨(dú)看形參不能確定具體含義。

    caller:前面?zhèn)鬟^來的值,代表ApplicationThread對(duì)象

    callingPackage:由who.getBasePackageName()的值傳遞而來,who是Context對(duì)象,getBasePackageName()的實(shí)現(xiàn)在ContextImple中,返回當(dāng)前啟動(dòng)類的包名,就是Launcher的包名

    resolvedType:解析當(dāng)前發(fā)送的Intent的MIME數(shù)據(jù)類型,本案例沒有為intent設(shè)置type、data屬性,因此,intent.resolveTypeIfNeeded(who.getContentResolver())返回null

    resultTo:Ibinder對(duì)象,具體含義后面繼續(xù)看

    resultWho:由target != null ? target.mEmbeddedID : null得來,target是activity對(duì)象即啟動(dòng)類Launcher對(duì)象,不為空,該語(yǔ)句返回mEmbeddedID,一個(gè)id號(hào),這個(gè)值必須要從Launcher這個(gè)apk啟動(dòng)中獲得,在Launcher啟動(dòng)后,代表Launcher啟動(dòng)類的對(duì)象是一個(gè)ActivityClientRecord對(duì)象,該對(duì)象所屬的類路徑為:

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

    該對(duì)象的scheduleLaunchActivity方法中,有一句:

    ActivityClientRecord r = new ActivityClientRecord();

    在ActivityClientRecord的構(gòu)造方法中會(huì)把embeddedID初始化為null,因此mEmbeddedID為空

    startFlags:整型值,已經(jīng)初始化為0,具體作用后面分析

    profilerInfo:為null,具體作用后面分析

    這些參數(shù)都會(huì)被打包到持久化類Parcel的對(duì)象data中,把data作為transact的參數(shù)進(jìn)行跨進(jìn)程傳遞:

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

    該方法通過binder通信機(jī)制會(huì)傳遞到ActivityManagerNative的onTransact方法,在onTransact方法中,根據(jù)發(fā)送命令START_ACTIVITY_TRANSACTION找到case處理語(yǔ)句,把data中的數(shù)據(jù)取出來賦給相應(yīng)的變量,繼續(xù)調(diào)用:

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

    startActivity最終會(huì)調(diào)用到服務(wù)端ActivityManagerService中。此時(shí),進(jìn)程也從啟動(dòng)類Launcher所在的進(jìn)程切換到了服務(wù)端進(jìn)程。從ActivityManagerNative.getDefault().startActivity一直到ActivityManagerService的startActivity方法,主要由binder通信實(shí)現(xiàn),該過程相當(dāng)復(fù)雜,但binder通信不屬于本文重點(diǎn),而且binder機(jī)制貫穿于整個(gè)Android系統(tǒng)、內(nèi)核、驅(qū)動(dòng)部分,本文如再遇到binder通信機(jī)制,直接給出最終被調(diào)用的類及方法。

    在進(jìn)入到服務(wù)端之前,看看客戶端到底做了哪些工作?

    主要是獲得了一些必要的參數(shù):IApplicationThread對(duì)象、啟動(dòng)類包名、Intent的MIME數(shù)據(jù)類型、IApplicationToken.Stub類型對(duì)象resultTo等,除了這些,沒有其他特殊的操作了,其實(shí)最關(guān)鍵的操作還是在服務(wù)端進(jìn)行的,這就是為何本文一開始提到無論哪種啟動(dòng)方式,客戶端都是大同小異。

    framework層服務(wù)端

    過程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);

    這幾步?jīng)]有太多的操作,獲得了一個(gè)用戶id,用來作一些檢測(cè)

    過程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){ ...... }

    先看多了哪些參數(shù):
    voiceSession:IVoiceInteractionSession對(duì)象類型,被初始化null。IVoiceInteractionSession本是一個(gè)aidl遠(yuǎn)程接口,定義了任務(wù)棧啟動(dòng)taskStarted、任務(wù)棧結(jié)束taskFinished等方法

    voiceInteractor:IVoiceInteractor對(duì)象類型,被初始化為null。IVoiceInteractor也是一個(gè)aidl遠(yuǎn)程接口

    outResult:WaitResult對(duì)象類型,被初始化為null。WaitResult是IActivityManager的內(nèi)部類,實(shí)現(xiàn)了Parcelable接口,主要用來保存啟動(dòng)Activity后返回的結(jié)果信息

    config:Configuration對(duì)象類型,被初始化為null。Configuration描述了所有設(shè)備相關(guān)的配置信息,比如,本地語(yǔ)言、屏幕大小、屏幕方向、輸入法模式,可以通過Resources的getConfiguration獲得改對(duì)象

    iContainer:IActivityContainer對(duì)象類型,被初始化為null。IActivityContainer也是一個(gè)aidl遠(yuǎn)程接口

    inTask:TaskRecord對(duì)象類型,被初始化為null。TaskRecord很重要,會(huì)經(jīng)常用到此類,描述一個(gè)任務(wù)棧,每個(gè)任務(wù)??梢园鄠€(gè)Activity對(duì)象,每個(gè)TaskRecord對(duì)象都有一個(gè)當(dāng)前棧ActivityStack的引用,每個(gè)??梢詫?duì)應(yīng)多個(gè)TaskRecord對(duì)象

    除了這些多余的參數(shù),其他參數(shù)都是從客戶端傳遞而來。

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

    getComponent方法返回一個(gè)ComponentName對(duì)象,該對(duì)象表示通過intent要啟動(dòng)的組件類,本案例就對(duì)應(yīng)A這個(gè)Activity,ComponentName對(duì)象一般用包名和類名標(biāo)識(shí)一個(gè)組件,因此,componentSpecified為true

    1 intent=newIntent(intent);

    根據(jù)客戶端傳遞過來的Intent對(duì)象重新構(gòu)建一個(gè)Intent對(duì)象,這樣做是不要破壞客戶端傳遞來的Intent對(duì)象

    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對(duì)象,返回intent對(duì)應(yīng)的目標(biāo)Activity類的ActivityInfo對(duì)象,ActivityInfo類專門用來描述AndroidManifest.xml中Activity、Receiver組件信息的,本案例返回的就是A這個(gè)類對(duì)應(yīng)的信息,ActivityInfo的成員變量name就是類名稱,packageName就是包名稱,對(duì)應(yīng)本案例分別為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傳過來時(shí)為-1,call又不為空,進(jìn)程執(zhí)行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也為空,調(diào)用getFocusedStack獲得當(dāng)前正在前臺(tái)的棧,也就是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,因?yàn)闆]有設(shè)置這種屬性,因此跳過該if語(yǔ)句,開始執(zhí)行:

    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相關(guān),具體含義后面再看

    callingUid:int型變量,看字面意思與uid相關(guān),具體含義后面再看

    realCallingPid:啟動(dòng)類所在進(jìn)程的pid,本案例是Launcher

    realCallingUid:啟動(dòng)類所在進(jìn)程的uid,本案例是Launcher

    componentSpecified:為true,表明intent對(duì)應(yīng)的目標(biāo)Activity類存在

    outActivity:ActivityRecord數(shù)組名稱,初始化為null,ActivityRecord是一個(gè)動(dòng)態(tài)生成的對(duì)象,代表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對(duì)象,通過getRecordForAppLocked方法獲得啟動(dòng)類所在進(jìn)程的進(jìn)程記錄對(duì)象ProcessRecord。參數(shù)caller是IApplicationThread對(duì)象,前文提到過,實(shí)際是ApplicationThread對(duì)象,代表Launcher類的主線程,caller在ActivityManagerService和ActivityThread兩個(gè)進(jìn)程之間完成通信,現(xiàn)在終于明白了,為何在startActivity時(shí)會(huì)帶著這樣一個(gè)參數(shù):服務(wù)端通過該參數(shù)獲得客戶端進(jìn)程信息,該參數(shù)起到橋梁作用。

    callerApp不為空,分別獲得啟動(dòng)類進(jìn)程的pid和uid保存到callingPid、callingUid中,這個(gè)callingPid和之前的realCallingPid獲得的值一樣,都是Launcher進(jìn)程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; } } }

    定義了兩個(gè)ActivityRecord變量sourceRecord、resultRecord,用來對(duì)應(yīng)啟動(dòng)類和目標(biāo)類。上文提到,resultTo屬于IBinder對(duì)象,屬于啟動(dòng)方的對(duì)象。isInAnyStackLocked方法根據(jù)啟動(dòng)類的標(biāo)記resultTo對(duì)象在列表?xiàng)V姓页鰧?duì)應(yīng)的棧,再在棧頂找到Activity記錄保存到sourceRecord中。

    1 finalintlaunchFlags=intent.getFlags();

    上文提到,intent一開始在客戶端就被設(shè)置了FLAG_ACTIVITY_NEW_TASK標(biāo)志,getFlags方法便取出該標(biāo)志,保存到launchFlags變量中。

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

    創(chuàng)建一個(gè)ActivityRecord對(duì)象,這個(gè)ActivityRecord對(duì)象具體有什么作用?看看參數(shù)具體含義

    前4個(gè)參數(shù)代表了啟動(dòng)類Launcher,第5~7參數(shù)(Intent,resolvedType, aInfo)代表了目標(biāo)類

    mService.mConfiguration表示系統(tǒng)配置,resultRecord代表目標(biāo)類,resultWho代表啟動(dòng)類的一個(gè)id號(hào),為空

    componentSpecified為true

    this:代表當(dāng)前ActivityStackSupervisor對(duì)象

    從參數(shù)來看,該類既包含啟動(dòng)類的屬性,又包含目標(biāo)類屬性,推測(cè)該類應(yīng)該用來表達(dá)目標(biāo)類,后面可以證明。

    startActivityLocked方法的作用:獲得啟動(dòng)類進(jìn)程信息、pid、uid,創(chuàng)建ActivityRecord類對(duì)象sourceRecord保存啟動(dòng)類信息,創(chuàng)建ActivityRecord對(duì)象r,暫時(shí)推測(cè)代表目標(biāo)類,具體含義后面分析。進(jìn)程繼續(xù)調(diào)用:

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

    開始調(diào)用下一步操作,第一個(gè)參數(shù)就是剛才創(chuàng)建的ActivityRecord對(duì)象;第二個(gè)參數(shù)是啟動(dòng)類對(duì)象,不為空;

    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對(duì)象,r.launchedFromUid就是啟動(dòng)類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;

    這三個(gè)變量代表目標(biāo)類的啟動(dòng)模式,本案例就是A的啟動(dòng)模式,沒有任何設(shè)置,默認(rèn)為Standard模式,因而這三個(gè)變量都是false

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

    FLAG_ACTIVITY_NO_USER_ACTION:當(dāng)啟動(dòng)目標(biāo)Activity時(shí)Intent設(shè)置了此標(biāo)志,前臺(tái)正在行的Activity在暫停之前(執(zhí)行onPaused方法)不會(huì)回調(diào)onUserLeaveHint方法。NO_USER_ACTION表示非用戶操作,如果設(shè)置了此標(biāo)志,表示非用戶行為時(shí)不會(huì)回調(diào)onUserLeaveHint。比如,鬧鐘響了、來電話了,這屬于非用戶操作,如果設(shè)置了此標(biāo)志,就不會(huì)回調(diào)onUserLeaveHint,相反,如果是用戶操作行為比如按下HOME按鍵,返回鍵等,就會(huì)回調(diào)onUserLeaveHint。本案例中發(fā)送給A的Intent沒有設(shè)置該標(biāo)志,mUserLeaving為true,表明不是非用戶操作行為。

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

    Intent沒有設(shè)置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為空,因?yàn)榇藭r(shí)啟動(dòng)類Launcher還在前臺(tái),沒有進(jìn)入到銷毀列表中,進(jìn)程執(zhí)行else語(yǔ)句,得到啟動(dòng)類所在的棧對(duì)象并保存到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沒有設(shè)置FLAG_ACTIVITY_MULTIPLE_TASK,resultTo和startActivityLocked參數(shù)中resultTo不是一個(gè)意思,前者是在startActivityLocked函數(shù)中創(chuàng)建的ActivityRecord對(duì)象resultRecord,代表目標(biāo)類一方,被初始化為空,而后者代表啟動(dòng)類一方,不能混淆。

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

    啟動(dòng)A時(shí)沒有設(shè)置啟動(dòng)模式,采用是默認(rèn)的標(biāo)準(zhǔn)模式,因此launchSingleInstance為false,調(diào)用findTaskLocked(r)在當(dāng)前棧頂中查詢是否有目標(biāo)類,如果有,就返回該類,否則,返回空。因?yàn)槭状螁?dòng)A,因此棧中肯定沒有A,返回空保存到intentActivity變量中,這樣的話,if語(yǔ)句不成立。如果棧中有實(shí)例,再次啟動(dòng)時(shí)就會(huì)執(zhí)行這段代碼。

    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{ ...... }

    目標(biāo)類包名肯定不為空,執(zhí)行if條件,getFocusedStack返回當(dāng)前棧,topRunningNonDelayedActivityLocked返回當(dāng)前ActivityRecord對(duì)象保存到top中,肯定不為空;top.realActivity表示啟動(dòng)類,r.realActivity表示目標(biāo)類,本案例前者是Launcher,后者是A,兩者肯定不相等,因此if語(yǔ)句不成立,跳過此段。如果成立的話,就會(huì)在當(dāng)前棧中找到已存在的實(shí)例繼續(xù)使用。

    既然當(dāng)前棧中沒有已存在實(shí)例,那么只能新創(chuàng)建一個(gè)任務(wù)棧,繼續(xù)看:

    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語(yǔ)句成立,launchTaskBehind為空,那么taskToAffiliate也為空

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

    newTask代表新建一個(gè)任務(wù)的標(biāo)志,設(shè)為true;adjustStackFocus獲得一個(gè)ActivityStack保存到targetStack變量作為目標(biāo)類的棧;

    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創(chuàng)建TaskRecord對(duì)象并放到棧頂,然后再放到目標(biāo)類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"); }

    調(diào)用startActivityLocked進(jìn)行下一步操作

    startActivityUncheckedLocked函數(shù)非常復(fù)雜,最關(guān)鍵的就是查詢是否有已存在的TaskRcord作為目標(biāo)類的任務(wù)棧,如果棧中有就復(fù)用,否則就創(chuàng)建一個(gè)新的TaskRcord對(duì)象作為目標(biāo)類的任務(wù)棧。該函數(shù)涉及到了FLAG標(biāo)志,啟動(dòng)模式的判斷等,其目的就是找到一個(gè)合適的任務(wù)棧,為何要找到這個(gè)棧,就是因?yàn)锳ctivity在執(zhí)行時(shí)以棧這個(gè)數(shù)據(jù)結(jié)構(gòu)來管理。

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

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

    第一個(gè)參數(shù)對(duì)應(yīng)目標(biāo)類對(duì)象記錄,newTask為true,表示新建了一個(gè)任務(wù)棧,doResume為true,keepCurTransition為false。

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

    r.task就是在startActivityUncheckedLocked中創(chuàng)建的目標(biāo)類的RaskRecord對(duì)象,取出來保存到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號(hào)為目標(biāo)類所在的棧id,如果有,表明目標(biāo)類之前已經(jīng)被創(chuàng)建過,現(xiàn)在開始復(fù)用該對(duì)象,屬于非首次啟動(dòng),否則為首次啟動(dòng)對(duì)象,本案例首次啟動(dòng)A,因此,此函數(shù)返回null;newTask傳遞過來為true,if語(yǔ)句成立,調(diào)用insertTaskAtTop函數(shù)把新創(chuàng)建的TaskRecord對(duì)象插入到列表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對(duì)象表示當(dāng)前對(duì)象ActivityStack,此ActivityStack是新建的對(duì)象,不是Launcher所在的ActivityStack,是在startActivityUncheckedLocked中的adjustStackFocus方法獲得的,目的就是把新創(chuàng)建的任務(wù)插入到該ActivityStack對(duì)象中,這個(gè)對(duì)象就代表了目標(biāo)類所屬的棧

    第二個(gè)參數(shù)r就表示目標(biāo)類對(duì)象記錄,第三個(gè)參數(shù)依然為null

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

    isFrontStack判斷新獲得的ActivityStack對(duì)象位于棧頂,判斷為真,執(zhí)行if語(yǔ)句,調(diào)用resumeTopActivityLocked(target, targetOptions)

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

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

    第一個(gè)參數(shù)prev表示目標(biāo)類ActivityRecord對(duì)象,第二個(gè)傳遞過來為空

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

    繼續(xù)調(diào)用resumeTopActivityInnerLocked方法,再調(diào)用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方法找到棧頂?shù)腁ctivityRecord對(duì)象,此處對(duì)應(yīng)著A

    mStackSupervisor.mUserLeaving的值在過程5中被設(shè)置為true,此處取出來賦值給userLeaving,表明是用戶操作行為(按下返回鍵,HOME按鍵等);無論是true還是false,此處還是再?gòu)?fù)位一下,重新設(shè)置為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);?? ? ? }

    目標(biāo)類A沒有設(shè)置FLAG_RESUME_WHILE_PAUSING標(biāo)志,dontWaitForPause為false

    pauseBackStacks函數(shù)返回false賦給pausing變量,mResumedActivity表示當(dāng)前正在前臺(tái)運(yùn)行的Activity,就是Launcher,不為空,進(jìn)程調(diào)用startPausingLocked繼續(xù)執(zhí)行

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

    startPausingLocked開始暫停當(dāng)前Activity,如果成功,返回true,否則false

    4個(gè)參數(shù)分別為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是哪個(gè)

    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進(jìn)程信息,不為空;prev.app.thread是一個(gè)IApplicationThread對(duì)象,對(duì)應(yīng)Launcher也不為空,進(jìn)程繼續(xù)調(diào)用schedulePauseActivity方法,此處是一個(gè)Binder進(jìn)程間通信,下一步調(diào)用到ApplicationThread對(duì)象的schedulePauseActivity方法中,ApplicationThread是ActivityThread內(nèi)部類


    過程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,因?yàn)長(zhǎng)auncher此時(shí)還沒有執(zhí)行生命周期方法onPause()、onDestory(),因此沒有進(jìn)入finishing狀態(tài),那么,sendMessage的第一個(gè)參數(shù)值為H.PAUSE_ACTIVITY

    sendMessage把消息發(fā)送到隊(duì)列中等待執(zhí)行,執(zhí)行方法是Handler的handleMessage方法,通過命令PAUSE_ACTIVITY可以得到執(zhí)行程序:

    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;

    繼續(xù)調(diào)用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對(duì)應(yīng)啟動(dòng)類Launcher,此處獲得Launcher的ActivityRecord對(duì)象

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

    調(diào)用performUserLeavingActivity方法,performUserLeavingActivity的最終調(diào)用過程為:

    performUserLeavingActivity—->

    mInstrumentation.callActivityOnUserLeaving(r.activity) —->

    activity.performUserLeaving() —->

    onUserInteraction()

    onUserLeaveHint()

    意味著,如果是用戶操作的主動(dòng)行為,比如返回按鍵,遙控器上下左右按鍵,HOME按鍵燈,會(huì)調(diào)用Activity的

    onUserInteraction和onUserLeaveHint方法,如果是按鍵,觸摸、軌跡球被分發(fā)到Activity時(shí),onUserInteraction會(huì)被回調(diào);onUserLeaveHint的作用是當(dāng)Activity即將進(jìn)入到后臺(tái)前被回調(diào),起到提示作用

    performUserLeavingActivity執(zhí)行完后,進(jìn)程繼續(xù)調(diào)用

    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方法中繼續(xù)調(diào)用callActivityOnPause方法,參數(shù)r.activity代表啟動(dòng)類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; }

    最終調(diào)用到Activity的performPause方法,再調(diào)用生命周期方法onPause()意味著啟動(dòng)類處于暫停狀態(tài)了,這一步執(zhí)行完后返回到performPauseActivity中,執(zhí)行r.paused = true把啟動(dòng)類的ActivityClientRecord的paused置為true,表示啟動(dòng)類此時(shí)已經(jīng)處于暫停狀態(tài)了。再返回到handlePauseActivity中,繼續(xù)執(zhí)行performPauseActivity后面的語(yǔ)句

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

    這一步通過Binder進(jìn)程間通信機(jī)制進(jìn)入到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表示啟動(dòng)類Launcher,r是Launcher的ActivityRecord對(duì)象,if條件為真,進(jìn)程繼續(xù)調(diào)用completePauseLocked(true)方法

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

    既然啟動(dòng)類都已經(jīng)暫停了,那下一步工作是不是就是把目標(biāo)類啟動(dòng)起來呢?如果是的話,應(yīng)該會(huì)執(zhí)行生命周期onResume方法,這只是猜測(cè),具體詳細(xì)看方法的執(zhí)行過程

    參數(shù)resumeNext傳遞過來為true

    prev.finishing屬性為false,這個(gè)屬性一直沒有設(shè)置

    mPausingActivity = null;

    如果啟動(dòng)類已經(jīng)stop,就把mPausingActivity設(shè)為null

    進(jìn)程繼續(xù)執(zhí)行到:

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

    當(dāng)前系統(tǒng)處于非睡眠和關(guān)機(jī)狀態(tài),if條件為真,進(jìn)程開始調(diào)用resumeTopActivitiesLocked方法


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

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

    要清楚方法具體做了什么,一定要先弄清楚參數(shù)的含義

    形參targetStack的實(shí)參是topStack,通過mStackSupervisor.getFocusedStack獲得,即當(dāng)前獲得焦點(diǎn)的棧,此處,啟動(dòng)類已經(jīng)暫停,那么當(dāng)前棧就是目標(biāo)類所在的棧,prev是啟動(dòng)類

    又調(diào)用了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){ ...... }

    繼續(xù)調(diào)用resumeTopActivityInnerLocked方法

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

    再次進(jìn)入到此方法時(shí),mResumedActivity為空,因?yàn)檫@是在過程8中startPausingLocked方法內(nèi)設(shè)置的,表明啟動(dòng)類Launcher已經(jīng)不在是當(dāng)前運(yùn)行的Activity,因此

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

    這個(gè)語(yǔ)句就不再成立,進(jìn)程跳過此句繼續(xù)執(zhí)行

    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就是目標(biāo)類A,此時(shí)A的一些棧等信息已經(jīng)構(gòu)建,但是A得進(jìn)程還沒有創(chuàng)建,正常情況下,啟動(dòng)一個(gè)新的應(yīng)用程序一般會(huì)創(chuàng)建一個(gè)新的進(jìn)程,應(yīng)用程序在此進(jìn)程中執(zhí)行,特殊情況下可以通過AndroidManifest中process屬性執(zhí)行指定應(yīng)用程序在某個(gè)進(jìn)程中執(zhí)行,本文沒有設(shè)置process屬性,默認(rèn)為啟動(dòng)一個(gè)新的進(jìn)程,本文后面會(huì)分析到。由此可知,A還沒有進(jìn)程信息,if語(yǔ)句不成立,進(jìn)程轉(zhuǎn)到else語(yǔ)句執(zhí)行


    過程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);

    此時(shí)A進(jìn)程還沒有創(chuàng)建,所以app為空,跳過if語(yǔ)句,開始調(diào)用startProcessLocked方法

    假如A的應(yīng)用程序已經(jīng)啟動(dòng),然后在A中啟動(dòng)B,B是A應(yīng)用程序的一個(gè)Activity,那么此時(shí)進(jìn)程已經(jīng)創(chuàng)建,app就不會(huì)為空,進(jìn)程會(huì)調(diào)用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){ ...... }

    該方法中會(huì)為A創(chuàng)建ProcessRecord信息,然后繼續(xù)調(diào)用

    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); ...... }

    此方法中會(huì)調(diào)用進(jìn)程的start方法創(chuàng)建一個(gè)新的進(jìn)程,具體是通過zygote進(jìn)程的來fork一個(gè)新的進(jìn)程,成為子進(jìn)程,子進(jìn)程共享父進(jìn)程資源,幾乎和父進(jìn)程一樣。當(dāng)子進(jìn)程創(chuàng)建好后,系統(tǒng)會(huì)分配一個(gè)進(jìn)程號(hào)PID給新進(jìn)程并返回,否則拋出異常

    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){ ...... }

    第一個(gè)參數(shù)processClass為新創(chuàng)建的進(jìn)程的入口類即android.app.ActivityThread.java

    niceName:新創(chuàng)建的進(jìn)程的進(jìn)程名字,用ps命令可以查看到該名字,一般情況下,應(yīng)用程序的進(jìn)程名就是包名

    如果進(jìn)程創(chuàng)建成功,待方法start執(zhí)行完后,系統(tǒng)就會(huì)轉(zhuǎn)到ActivityThread.java的main方法入口開始執(zhí)行,注意這個(gè)流程,和我們通??吹降姆椒ㄕ{(diào)用方法是不一樣的。


    過程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方法創(chuàng)建了looper對(duì)象和MessageQueue消息隊(duì)列;創(chuàng)建了并初始化ActivityThread對(duì)象,同時(shí)也創(chuàng)建并初始化了ApplicationThread對(duì)象mAppThread

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

    獲得ActivityManagerProxy對(duì)象,調(diào)用該對(duì)象的attachApplication方法,通過binder通信,最終調(diào)用到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對(duì)象,該對(duì)象上一步創(chuàng)建過,不為空

    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;

    初始化該P(yáng)rocessRecord對(duì)象

    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; } }

    這段話就是真正開始啟動(dòng)目標(biāo)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; } }

    用來啟動(dòng)Service、發(fā)送廣播,此處作為一個(gè)備注,如果要分析啟動(dòng)Service、廣播,研究這兩段語(yǔ)句,本文只研究啟動(dòng)Activity,因此,詳細(xì)看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就是目標(biāo)類ActivityRecord對(duì)象,app是進(jìn)程名字

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

    調(diào)整進(jìn)程LRU算法;參與管理進(jìn)程

    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對(duì)象,此處就是ApplicationThreadProxy對(duì)象接口,這里也是Binder通信過程,調(diào)用ApplicationThreadProxy的scheduleLaunchActivity方法,通過binder通信轉(zhuǎn)到ApplicationThread對(duì)象的scheduleLaunchActivity方法,該方法在ActivityThread對(duì)象中


    過程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){ .... }

    該方法創(chuàng)建了目標(biāo)類對(duì)應(yīng)的ActivityClientRecord對(duì)象,而后初始化該對(duì)象,作為sendMessage參數(shù)發(fā)送到消息隊(duì)列待處理

    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){ ...... }

    該方法分為兩個(gè)部分,先調(diào)用performLaunchActivity,再調(diào)用handleResumeActivity,最后還有finishActivity

    先看performLaunchActivity

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


    1 ActivityInfo?aInfo=r.activityInfo;

    從目標(biāo)類ActivityClientRecord對(duì)象中取出ActivityInfo對(duì)象,ActivityInfo對(duì)象包含了Activity、receiver對(duì)象信息

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

    再根據(jù)Intent獲得組件對(duì)象component,組件包含了啟動(dòng)類名稱和包名稱

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

    通過Java反射機(jī)制找到目標(biāo)類文件,再創(chuàng)建目標(biāo)類的一個(gè)對(duì)象賦值給activity。從此處可知,原來Android中Activity對(duì)象是在啟動(dòng)時(shí)創(chuàng)建的,系統(tǒng)已經(jīng)幫助程序員寫好了new Activity對(duì)象的動(dòng)作,無需程序員自行new對(duì)象,這解決了一開始學(xué)習(xí)android時(shí)總是搞不清楚Activity對(duì)象是從什么時(shí)候創(chuàng)建的的困惑,因此,Android并不關(guān)注組件的創(chuàng)建過程,而把關(guān)注點(diǎn)落在了組件的生命周期上。

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

    makeApplication方法也是利用反射機(jī)制找到應(yīng)用程序Application類并創(chuàng)建一個(gè)對(duì)象,并調(diào)用Application對(duì)象的onCreate方法,這就是為什么應(yīng)用一啟動(dòng)后,Application的onCreate比Activity的onCreate先執(zhí)行的原因!

    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方法中會(huì)調(diào)用createActivityContext創(chuàng)建ContextImpl對(duì)象,ContextImpl實(shí)現(xiàn)了Context,也就同時(shí)創(chuàng)建了上下文管理者Context對(duì)象,這也解決了為什么在寫程序時(shí)總是能夠獲得Context對(duì)象的原因

    attach方法把Context對(duì)象、Instrumentation對(duì)象等和Activity關(guān)聯(lián)起來

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

    通過Instrumentation對(duì)象的callActivityOnCreate方法進(jìn)入到Instrumentation對(duì)象中,Instrumentation對(duì)象就是監(jiān)控所有用戶和系統(tǒng)之間的交互操作,比如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); }

    繼續(xù)調(diào)用performCreate方法

    過程20 ? ?frameworks\base\core\java\android\app\Activity.java

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

    最終調(diào)用Activity的onCreate方法開始生命周期

    再返回到handleLaunchActivity中,進(jìn)程繼續(xù)執(zhí)行到handleResumeActivity方法

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

    這四步寫在一個(gè)代碼段,可以看到最終調(diào)用了Activity的onResume方法,目標(biāo)類A啟動(dòng)起來了并成為可見狀態(tài)

    到此處為止,在Launcher中啟動(dòng)Activity的過程就分析完了。

    整個(gè)過程相當(dāng)復(fù)雜,涉及到很多動(dòng)態(tài)對(duì)象,進(jìn)程間通信,棧的管理等,可以不必要理解每句代碼,但是清楚整個(gè)流程做了哪些核心的動(dòng)作是有必要的:

    1. ?過程5

    resolveActivity方法中調(diào)用了包管理器PackageManager的resolveIntent方法解析啟動(dòng)目標(biāo)類的Intent對(duì)象,獲得解析后的對(duì)象ActivityInfo,為何要獲得這個(gè)對(duì)象,這個(gè)對(duì)象有有什么作用?

    在AndroidManifest.xml中Activity和receiver標(biāo)簽包含了很多屬性,比如主題、啟動(dòng)模式、屏幕方向,輸入法設(shè)置,進(jìn)程名稱等,ActivityInfo就是對(duì)應(yīng)目標(biāo)類Activity的一個(gè)動(dòng)態(tài)對(duì)象,該對(duì)象包含了這些屬性信息。該對(duì)象的作用用來構(gòu)建目標(biāo)類對(duì)應(yīng)的ActivityRecord對(duì)象,該對(duì)象也是一個(gè)動(dòng)態(tài)對(duì)象,是歷史棧中的一條記錄,在內(nèi)存中對(duì)應(yīng)目標(biāo)類。

    這樣就明白一個(gè)問題:啟動(dòng)activity時(shí)有顯示和隱式,對(duì)于隱式方式,只需要在目標(biāo)類中intetn-filter中增加一個(gè)action,然后啟動(dòng)類通過這個(gè)action即可啟動(dòng)目標(biāo)類,這是如何做到的?實(shí)際上是通過包管理器PackageManager解析intent,查找到匹配的action對(duì)應(yīng)的目標(biāo)類的。

    2. 過程8

    startPausingLocked方法是進(jìn)入到暫停啟動(dòng)類過程的標(biāo)志,逐步調(diào)用prev.app.thread.schedulePauseActivity,然后又binder通信進(jìn)入到ApplicationThread對(duì)象的schedulePauseActivity方法,在此方法中,發(fā)送消息給啟動(dòng)類Launcher主線程ActivityThread,ActivityThread利用handler循環(huán)處理消息,調(diào)用handlePauseActivity方法處理,最終調(diào)用到Activity的生命周期方法onPause暫停啟動(dòng)類

    3. ?過程14

    Process對(duì)象的start方法開啟了一個(gè)新的進(jìn)程作為目標(biāo)類的主線程,由此,目標(biāo)類開始從ActivityThread的main方法開支執(zhí)行,然后由

    mgr.attachApplication(mAppThread);

    語(yǔ)句通過binder通信進(jìn)入到ActivityManagerService中,并傳遞了ApplicationThread對(duì)象,該對(duì)象傳入到ActivityManagerService中后構(gòu)建目標(biāo)類進(jìn)程信息,然后ActivityManagerService負(fù)責(zé)啟動(dòng)目標(biāo)類,最終通過該對(duì)象又通過Binder通信返回到ApplicationThread對(duì)象中,然后ApplicationThread對(duì)象又發(fā)送消息給目標(biāo)類主線程ActivityThread對(duì)象,該對(duì)象循環(huán)處理來自ActivityManagerService的消息,進(jìn)而調(diào)用Activity的生命周期方法onCreate、onResume。其中,IApplicationThread遠(yuǎn)程接口對(duì)象起著非常關(guān)鍵作用,他在主線程對(duì)象ActivityThread與Activity管理器ActivityManagerService對(duì)象之間起著通信橋梁作用。

    ActivityManagerService是Activity Manager(注意,分開大寫,代表Framework層的核心模塊,該模塊包含了ActivityManagerService、ActivityStack、Binder接口等)的核心部分,負(fù)責(zé)啟動(dòng)Activity、Service、發(fā)送Broadcast Receiver、啟動(dòng)ContentProvider;調(diào)整進(jìn)程調(diào)度算法,管理任務(wù)棧、檢查權(quán)限等一些列核心功能。


    2. 調(diào)用startActivity啟動(dòng)一個(gè)Activity

    在應(yīng)用程序內(nèi)啟動(dòng)Activity,和應(yīng)用程序外啟動(dòng)最根本的不同在于不會(huì)新創(chuàng)建進(jìn)程,也就是說,過程13中,不會(huì)執(zhí)行startProcessLocked方法,而執(zhí)行realStartActivityLocked方法,過程13~過程16可以省略不看,此時(shí)在同一個(gè)進(jìn)程中;除此之外,就是棧的獲取不一樣,用startActivity方法啟動(dòng)可能不會(huì)新建棧,直接使用已有的棧,而Launcher啟動(dòng)時(shí)一般會(huì)新建棧。

    3. 命令am start啟動(dòng)

    這種方法適合調(diào)試時(shí)使用,在串口中直接采用

    am start -n xxx/.yyy

    即可啟動(dòng)應(yīng)用程序,包名是xxx,入口類名是yyy

    am 這個(gè)可執(zhí)行程序?qū)?yīng)的源碼目錄位置:

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

    當(dāng)執(zhí)行這條命令時(shí),先從main方法開始執(zhí)行

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

    Am繼承了BaseCommand類,run方法在BaseCommand中定義,在run方法中又調(diào)用了onRun()方法,系統(tǒng)運(yùn)行時(shí)具體類型是Am,這樣就調(diào)到了Am的onRun方法。onRun中先執(zhí)行:

    1 mAm=ActivityManagerNative.getDefault();

    獲得ActivityManagerService的代理類ActivityManagerProxy的一個(gè)對(duì)象

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

    判斷參數(shù)是否有start這個(gè)字符串,如果有,就調(diào)用runStart方法,本文啟動(dòng)Activity當(dāng)然含有start參數(shù)

    在runStart方法中,會(huì)執(zhí)行這一句

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

    這一步會(huì)繼續(xù)調(diào)用ActivityStackSupervisor的startActivityMayWait方法,與上文的“過程4”一樣,后面的步驟基本上差不多。

    不管哪種方式啟動(dòng),在服務(wù)端的操作基本上相同,區(qū)別就在于是否復(fù)用當(dāng)前棧還是新創(chuàng)建一個(gè)棧,是否新建一個(gè)進(jìn)程作為目標(biāo)類的進(jìn)程等;在客戶端,區(qū)別在于啟動(dòng)Activity的方式不同,第三種命令啟動(dòng)方式缺少了startActivity部分。

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

    總結(jié)

    以上是生活随笔為你收集整理的启动Activity的流程(Launcher中点击图标启动)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    五月婷婷丁香在线观看 | 国产精品成人国产乱一区 | 天天射综合网站 | 免费看国产曰批40分钟 | 97在线看 | 最近久乱中文字幕 | 午夜av免费看 | 久久99久久99免费视频 | 国产精品久久久久久电影 | 欧美亚洲精品一区 | 成人在线免费小视频 | 2019中文在线观看 | 国产精品美女视频网站 | 人人盈棋牌 | 欧美日韩国产一区二 | 国产在线第三页 | 成人在线中文字幕 | 手机在线日韩视频 | 国产视频日韩 | 深夜精品福利 | 日韩av有码在线 | 色com网| 国内偷拍精品视频 | 免费黄色网止 | 国产精品嫩草影视久久久 | 日韩在线观看一区二区三区 | 日韩精品播放 | 九九视频这里只有精品 | 日韩中文幕 | 91夜夜夜| 蜜臀久久99精品久久久无需会员 | 亚洲伦理中文字幕 | 好看av在线 | 日本三级人妇 | 久久撸在线视频 | 男女啪啪免费网站 | 天天干,天天干 | 国产精品嫩草影院99网站 | 成年人视频在线免费观看 | 成人午夜精品福利免费 | 天天综合网天天 | 婷婷干五月 | 99精品视频网站 | 悠悠av资源片 | 在线观看久久 | 成人在线免费视频观看 | 2023天天干 | 99热在线免费观看 | 日韩一区精品 | 精品亚洲免a | 久草视频观看 | 在线色资源 | 欧美性久久久 | 超碰公开在线 | 66av99精品福利视频在线 | 在线观看黄色av | 欧美精品一区二区在线观看 | 久久试看 | 狠狠狠狠狠狠操 | 午夜久久久久久久久 | 五月天开心 | 深夜免费小视频 | 久草视频资源 | 免费观看成人av | 四虎成人av| av在线播放快速免费阴 | 国产成人精品一区一区一区 | 天天干com | 久久免费电影 | 又湿又紧又大又爽a视频国产 | 色综合久久88色综合天天免费 | 国产精品一区二区吃奶在线观看 | 黄色av网站在线观看 | 激情综合五月网 | 97福利| 欧美精品久久久久久久免费 | 日韩一区二区三区免费电影 | 精品国产电影 | 精品视频久久久久久 | 中文字幕在线观看91 | 国产视频中文字幕 | 久草免费在线视频观看 | 中文字幕一区二 | 一区av在线播放 | 成人免费观看完整版电影 | 日韩激情影院 | 国内精品久久久久久久久久久久 | 欧美久久99 | 偷拍精品一区二区三区 | 精品久久视频 | 国产精品久99 | 日本久久久久 | 天天爱天天射 | 亚洲精品99久久久久久 | 久久久久久久久爱 | 国产网红在线 | 国产成人精品久久亚洲高清不卡 | 国产综合福利在线 | 久久精品99国产精品酒店日本 | 日韩高清在线一区 | 久久国产综合视频 | 五月天中文字幕 | 成人久久久久久久久 | a黄色一级| 国产精品女人久久久久久 | 国产精品久免费的黄网站 | 国产va在线 | 天天干夜夜操视频 | 在线精品视频免费播放 | 国产xxxx| 色网免费观看 | 91亚洲夫妻 | 日本中文字幕系列 | 国产96视频 | 欧美热久久 | 久久999久久 | 欧洲av不卡 | 三级毛片视频 | 日日干天天射 | 999国内精品永久免费视频 | 天堂v中文| 国产午夜麻豆影院在线观看 | 日韩av有码在线 | 亚洲成人频道 | 日韩精品一区二区三区丰满 | 激情网站免费观看 | 开心激情网五月天 | av黄色影院 | 91在线免费视频观看 | 久久这里只有精品视频99 | 中文字幕亚洲欧美日韩2019 | 国产一级二级三级视频 | 美女福利视频在线 | 国产在线视频一区二区 | 欧美日韩三级 | 涩涩网站在线看 | 天天色成人网 | 欧美视频在线观看免费网址 | 精品国产午夜 | 亚洲情影院 | 91精品视频在线观看免费 | 久久国产精品免费一区二区三区 | 成人av播放 | 综合网五月天 | 中文字幕色播 | 日韩精品中文字幕在线观看 | 日日干 天天干 | 国内精品视频在线播放 | 中国一 片免费观看 | 激情av综合 | 97电影手机| 九色在线视频 | 五月婷婷影院 | 在线99视频 | 波多野结衣一区二区三区中文字幕 | 中文字幕av播放 | 国产精品原创av片国产免费 | www.91成人 | 欧美精品一区二区蜜臀亚洲 | 日韩欧美一区二区在线播放 | 一级黄色片在线播放 | 婷婷国产视频 | 天堂网中文在线 | 亚洲视频免费视频 | 亚洲人在线 | 久久久片| 国产麻豆视频在线观看 | 久久无码精品一区二区三区 | 国产成人三级一区二区在线观看一 | 香蕉视频国产在线 | 免费看的黄网站 | 亚洲日本在线视频观看 | 国产视频在线一区二区 | 最近中文字幕在线播放 | 国产精品成人一区二区 | 国产精品美女网站 | 午夜视频在线观看一区 | 人人草网站 | 天天爱天天操 | 久久精品这里都是精品 | 午夜视频一区二区三区 | 国产成人精品福利 | 99久久精品网 | 免费高清看电视网站 | 91精品婷婷国产综合久久蝌蚪 | 欧美一级片在线播放 | 亚洲午夜精品一区二区三区电影院 | av电影免费在线看 | 六月色 | 国产主播大尺度精品福利免费 | 久草在线视频网站 | 日韩簧片在线观看 | 99re国产视频 | 国产大陆亚洲精品国产 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 精品96久久久久久中文字幕无 | 婷香五月| 日韩av片免费在线观看 | 成人影片在线免费观看 | 国产又粗又硬又长又爽的视频 | 操久久免费视频 | 日本性高潮视频 | 色婷婷成人网 | 精品综合久久久 | 日韩网站免费观看 | 99视频免费看 | 日操操 | 久久久三级视频 | 成人在线免费视频观看 | 一级特黄aaa大片在线观看 | 精品一区二区免费视频 | 少妇性色午夜淫片aaaze | 亚洲成人第一区 | 久久精品香蕉 | 天天爽天天爽夜夜爽 | www中文在线 | 婷婷网五月天 | 夜夜躁狠狠躁日日躁视频黑人 | 激情丁香久久 | 日本在线成人 | 亚洲精品小视频 | 欧美日韩中文在线视频 | 国产精品免费久久久久久 | 日韩免费在线 | 亚洲电影第一页av | 麻豆视频一区 | 成人h在线| 天干啦夜天干天干在线线 | 成年人视频在线免费观看 | 国产黄在线播放 | 亚洲综合激情 | 在线观看av免费观看 | 欧美精品乱码久久久久 | 亚洲激情| 一级黄色片在线免费观看 | 国产视频不卡一区 | 亚洲每日更新 | 久草在线费播放视频 | 国产福利免费在线观看 | 欧美午夜剧场 | 国产精品久久久久久久久久久久午夜片 | 成年人在线免费看视频 | 欧美日韩在线视频一区二区 | 在线看国产日韩 | 狠狠插狠狠干 | 午夜久久久久久久 | 欧美精彩视频在线观看 | 九九日九九操 | 国产成人av一区二区三区在线观看 | 免费91麻豆精品国产自产在线观看 | 亚洲精品午夜久久久久久久久久久 | 超碰av在线免费观看 | 少妇超碰在线 | 久久精品视频18 | 伊人www22综合色 | 日韩精品不卡 | 黄色影院在线免费观看 | 成人免费电影 | 五月情婷婷 | 亚洲免费av网站 | 一区二区三区日韩在线 | 国产亚洲精品美女 | 91污在线 | 国产中文字幕在线看 | 天天做天天爱天天爽综合网 | 亚洲va欧美| 精品视频久久 | 五月婷婷六月丁香在线观看 | sesese图片| 免费av视屏| 亚洲激情校园春色 | 日韩中文字幕免费在线播放 | 丁香5月婷婷 | 国产精品麻豆三级一区视频 | 精品国产一区在线观看 | 天天干.com| 不卡在线一区 | 成人av片在线观看 | 99精品一区 | 色九九视频 | 久久久久久久久久久久久久免费看 | 久久久久久美女 | 久久婷婷开心 | 国产精品一区二区三区视频免费 | 中文av一区二区 | 狠狠躁日日躁狂躁夜夜躁 | 精品人人人人 | 天天操天天色天天 | 狠狠的干狠狠的操 | 久久久久久久亚洲精品 | 午夜精品99久久免费 | 日精品 | 97电影网手机版 | 欧美电影在线观看 | 98福利在线 | 久久精品久久久精品美女 | 日韩精品久久中文字幕 | 成人v| 999精品 | 美女久久视频 | 久久久久麻豆 | 国产精品视频资源 | 中文字幕丝袜美腿 | 亚洲男男gⅴgay双龙 | 欧美激情va永久在线播放 | 一区二区三区在线看 | 午夜aaaa | 狠狠操在线 | 国产91小视频 | 992tv人人草 黄色国产区 | 国产精品不卡在线播放 | 91成人精品一区在线播放 | 天天艹日日干 | 欧美一二三在线 | 五月婷婷激情 | 99国产在线观看 | 国内精品视频免费 | 麻豆视频免费入口 | 婷婷伊人综合亚洲综合网 | 91视频网址入口 | 日日爽夜夜爽 | 亚洲 欧洲av | 91精品网站在线观看 | 99久久婷婷国产综合亚洲 | 激情av网址| 激情大尺度视频 | 亚洲午夜久久久久久久久电影网 | 99r精品视频在线观看 | 亚洲欧美在线视频免费 | 不卡视频在线看 | 成年人在线播放视频 | 欧美性性网 | 亚洲h色精品 | 国产精品美女久久久久久久久久久 | 久久久69 | 亚洲最大成人免费网站 | 99在线热播精品免费99热 | 91污污视频在线观看 | 欧美亚洲三级 | 亚洲视频在线看 | 亚洲欧美国产精品18p | 午夜在线免费观看视频 | 日韩在线视频线视频免费网站 | 看黄色.com| 国产999在线观看 | 国语对白少妇爽91 | 国产无套精品久久久久久 | 免费在线色 | 91黄在线看 | www.久久成人 | 一区三区视频在线观看 | 国产精品va在线播放 | 国产色道 | 久草精品在线播放 | www.色的| 视频在线在亚洲 | 99久久精品国产毛片 | 黄色一级影院 | 操操操操网 | 国内成人精品视频 | 国产97av | 亚洲精品日韩一区二区电影 | 国产传媒一区在线 | 国产精品在线看 | 亚洲欧美日韩一级 | 国产精品久久久视频 | 亚洲成人精品影院 | 久久久久免费精品视频 | 欧美日韩中文另类 | 国产主播大尺度精品福利免费 | 久久国产精品久久精品国产演员表 | www五月天婷婷 | av在线成人 | 亚洲国产精品500在线观看 | 丁香婷婷基地 | 久久久久久久久久久黄色 | 亚洲成年人免费网站 | 碰超在线观看 | 人人澡澡人人 | 香蕉视频在线视频 | 三上悠亚一区二区在线观看 | 日韩理论在线播放 | 亚洲视频综合在线 | 日韩大片在线观看 | 亚洲aⅴ一区二区三区 | 亚洲国内精品视频 | 久久伊人婷婷 | 午夜免费在线观看 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 精品国产一区二区三区免费 | 成人av影院在线观看 | 亚洲激情av | 一本之道乱码区 | 五月天丁香亚洲 | 一区二区在线电影 | 亚洲成人999 | 日本不卡一区二区三区在线观看 | 日韩丝袜视频 | 日本不卡123区 | 欧美有色| av电影不卡在线 | 99热免费在线 | 成人高清在线 | 久久免费视频播放 | 日本久久片 | 激情视频二区 | 91九色国产在线 | 亚洲国产精品成人综合 | 亚洲精品在线视频 | japanesexxxhd奶水| 人人天天夜夜 | 日韩美女黄色片 | 丁香五婷| 久久久精品欧美 | 综合铜03| 欧美日韩高清在线观看 | 国产九色视频在线观看 | 81国产精品久久久久久久久久 | 伊人天天操 | 久久第四色| 欧美有色 | 91精品国产一区二区在线观看 | 97在线观看免费高清完整版在线观看 | 国产午夜精品久久 | 91麻豆精品一区二区三区 | 日韩精品视频久久 | 中文字幕在线不卡国产视频 | avlulu久久精品 | 夜夜干夜夜 | 麻豆视频免费在线观看 | 国产成人99久久亚洲综合精品 | 免费观看国产精品视频 | 午夜日b视频 | 国产一区在线视频观看 | 99中文字幕视频 | 日韩一级电影在线观看 | 国产精品99久久久久的智能播放 | 91最新中文字幕 | 一区二区三区四区五区在线 | 热久久电影| 97超碰人人模人人人爽人人爱 | 国内精品久久久久影院日本资源 | 在线免费视频一区 | 69av网| 欧美性生活一级片 | 国产一区高清在线 | 日韩网站免费观看 | 黄色亚洲免费 | 久久久美女| 在线黄色国产 | 国产成人精品一区二区三区福利 | 色视频网址 | 日韩精品一区二区三区外面 | 久草在线官网 | 91免费日韩| 国产精品永久在线观看 | 久久综合99 | 91男人影院| 久久久网页 | 亚洲国产成人在线观看 | 91成人在线观看喷潮 | 午夜视频在线瓜伦 | 在线免费黄 | 亚洲精品国偷自产在线99热 | 精品久久久久久一区二区里番 | 日日夜夜草 | 91视频免费看片 | 2021国产在线 | 亚洲精品视频在线观看网站 | 91麻豆精品国产91久久久使用方法 | 中文字幕视频 | 欧美动漫一区二区三区 | 欧美天天干 | 日日综合 | 在线观看免费观看在线91 | 亚洲一区二区高潮无套美女 | 国产女人18毛片水真多18精品 | 最新黄色av网址 | 91视频一8mav | 久久精品视频在线观看 | 国产一区二区久久久久 | 国产女人40精品一区毛片视频 | 精品亚洲视频在线 | 日韩欧美国产激情在线播放 | 最新日韩在线观看视频 | 国产久视频| 三级视频国产 | 亚洲一区精品二人人爽久久 | 中文成人字幕 | 天天色天天色天天色 | 美女免费视频网站 | 欧美一级片在线观看视频 | www.五月天色 | 久久婷婷综合激情 | 69绿帽绿奴3pvideos | 日韩欧美一区二区在线播放 | 欧美成人亚洲 | 精品国产色| 婷婷丁香激情 | 久久综合九色综合久久久精品综合 | 久99久在线| 色网站在线看 | 精品国产亚洲日本 | 亚州av免费 | 日本一区二区三区视频在线播放 | 日韩视频一区二区三区在线播放免费观看 | 国产啊v在线观看 | 夜夜爽夜夜操 | 国产一区国产二区在线观看 | 久免费| 久久影视网 | 天天操天天操天天操天天操天天操 | 国产精品1区 | 亚洲天堂网在线观看视频 | 国产精品久久久久永久免费 | 亚洲精品日韩av | 欧美日韩免费在线视频 | 久久精品伊人 | 黄色精品视频 | 日韩激情中文字幕 | 久久综合在线 | 日韩精品高清不卡 | 精品免费久久久久 | 欧美成人精品xxx | 黄色一区三区 | 亚洲精品网站在线 | 久久精品成人热国产成 | 一区二区欧美在线观看 | 视色网站| 日韩美视频| av官网| 亚洲成人网在线 | 久热av在线| 在线免费亚洲 | 一区二区不卡在线观看 | 天天色天天爱天天射综合 | 中文不卡视频在线 | 999久久久久久久久久久 | 日本在线视频网址 | 国产一级免费观看视频 | 国产一区免费观看 | 日韩av播放在线 | 色噜噜在线观看视频 | 亚洲精品h| 免费男女网站 | 在线免费观看欧美日韩 | 午夜.dj高清免费观看视频 | 97国产在线播放 | 久久资源在线 | 日日天天av| 国产精品久久久久久久久久久杏吧 | 人人爽人人舔 | 色婷婷综合久久久 | 三上悠亚一区二区在线观看 | av免费看在线 | 婷婷丁香激情五月 | 99久久精品免费看国产麻豆 | 欧美日韩午夜在线 | 欧美午夜精品久久久久 | 成人h在线观看 | 中文字幕在线观看第一页 | 国产美女视频网站 | av免费网站在线观看 | 久久久私人影院 | 天天插天天干 | 日韩av成人在线观看 | 久久综合久久综合这里只有精品 | 99这里精品 | 久久久久久蜜av免费网站 | 日本精品久久久久中文字幕5 | 5月丁香婷婷综合 | 久久美女精品 | 日韩视频a | 亚洲国产三级 | 欧美一级特黄高清视频 | 在线 欧美 日韩 | 黄色a在线观看 | 五月激情丁香婷婷 | 亚洲精品欧洲精品 | 天天综合网久久综合网 | 国产区久久 | a在线播放 | 亚洲精品免费播放 | 99精品一级欧美片免费播放 | 最新日韩在线观看视频 | 91亚洲在线观看 | www.久草.com | 91综合久久一区二区 | 免费情趣视频 | 综合久久久 | www.久草.com | 国产精品久久久久久久久费观看 | 欧美激情第一区 | 精品999在线观看 | 国产亚洲成av人片在线观看桃 | 中文字幕丰满人伦在线 | 九九热在线精品 | 久久国产福利 | 欧美激情综合五月色丁香小说 | 久久婷婷久久 | 国产96在线视频 | 免费av在线网| 91热这里只有精品 | 在线观看日韩专区 | 最近中文字幕mv免费高清在线 | 91精品人成在线观看 | 日韩色一区二区三区 | 欧美人操人 | 久久久久久久精 | 视频在线观看入口黄最新永久免费国产 | 日韩精品久久久久久久电影99爱 | 久草色在线观看 | 国产精品专区在线 | 日韩一级成人av | 黄色一区二区在线观看 | 免费av福利 | 97视频在线观看播放 | 国产欧美在线一区 | 久久视频精品在线 | 热久久99这里有精品 | 三级小视频在线观看 | 黄色精品网站 | 国产精品久久久久久a | 久草国产在线观看 | 黄色激情网址 | 91人人网| 999在线视频 | 99 久久久久 | 成人av网站在线播放 | va视频在线观看 | 国产精品福利午夜在线观看 | 人人cao| 91九色视频在线观看 | 麻豆免费在线播放 | 免费看黄色大全 | 久久伦理网 | 精品免费在线视频 | 免费看毛片在线 | 亚州精品天堂中文字幕 | 伊人狠狠色 | 色视频在线观看 | 五月婷婷综合网 | 天天综合导航 | 日韩一区二区三区不卡 | 国产成人在线一区 | 免费视频成人 | 久久国产剧场电影 | 精品亚洲免费 | 国内精品一区二区 | 欧美日本啪啪无遮挡网站 | 91精品国产高清自在线观看 | 日韩中文字幕免费在线播放 | 香蕉影院在线 | 91自拍成人 | va视频在线观看 | 国产精品毛片一区二区在线 | 天天插狠狠插 | 亚洲国产一区在线观看 | 国产精品美女视频 | 又黄又网站 | 国产精品h在线观看 | 欧美一级片免费在线观看 | 激情五月***国产精品 | 国产一区二区久久久久 | 国产精品久久久久影视 | 日韩av黄| 国产精品久久久久一区 | 天天操天天干天天爱 | 久久精品麻豆 | 亚洲精品啊啊啊 | 91福利在线观看 | 久久综合桃花 | 国产一级做a | 国产一区在线不卡 | 高清精品在线 | 精品一区二区三区在线播放 | 久久久综合香蕉尹人综合网 | 国产成人精品a | 亚洲欧美综合精品久久成人 | 91精品伦理| 97电影网站 | 天天操天天拍 | 成人动漫精品一区二区 | 亚洲精品国精品久久99热 | 丁香久久久| 狠狠的操你 | 国内精品视频在线 | 欧美 日韩 国产 成人 在线 | 久久99国产精品视频 | 久久免费视频2 | 97国产大学生情侣白嫩酒店 | 亚洲国产影院av久久久久 | 国产在线不卡精品 | 九色免费视频 | 国产综合91 | 久久久蜜桃一区二区 | 国内久久| 日韩在线一区二区免费 | 色综合天天在线 | 国产青春久久久国产毛片 | 成年人av在线播放 | 日韩试看| 狠狠的干狠狠的操 | 98超碰在线观看 | aav在线| 国产精品久久久久免费 | 91中文在线 | www.亚洲精品在线 | 最新av免费在线 | 88av视频| 久久99国产精品二区护士 | 国内精品久久久久久久久久久 | 天天草天天插 | 久久久人人人 | 天天操操 | 97在线精品国自产拍中文 | 亚洲黄色免费电影 | 日韩精品影视 | 国产成人精品午夜在线播放 | 中文字幕91 | 久久99视频 | 日日夜夜精品免费 | 国产高清在线a视频大全 | www.久草.com| 国产一级特黄毛片在线毛片 | 中文字幕大全 | 97超碰免费在线 | 99久热在线精品视频观看 | 亚洲精品综合一二三区在线观看 | 97色资源 | 美女网站久久 | 999久久久国产精品 高清av免费观看 | 亚洲高清精品在线 | 欧美精品中文字幕亚洲专区 | 国产片网站 | 成人av一级片| 国产色爽 | 日韩手机视频 | 在线观看日本韩国电影 | 国产在线观看,日本 | 中文字幕在线国产精品 | 欧美日韩在线免费观看视频 | www178ccom视频在线 | 蜜臀av夜夜澡人人爽人人桃色 | 免费成视频 | 精品国产乱码一区二区三区在线 | 亚洲成人精品影院 | 中文字幕乱在线伦视频中文字幕乱码在线 | 国产一区二区不卡视频 | 成年人在线观看视频免费 | 很黄很污的视频网站 | 九九热精品视频在线观看 | www.婷婷com| 国产区精品 | www夜夜操com | 中文字幕人成乱码在线观看 | 中文字幕免费高清 | 亚洲黄色小说网址 | 狠狠色噜噜狠狠狠 | 日韩中午字幕 | 成人午夜电影网站 | 免费91在线 | av无限看 | 中文字幕乱码一区二区 | 麻豆va一区二区三区久久浪 | 日韩一区二区三 | 在线免费成人 | 精品视频在线看 | 99精品在线看 | 成人免费xxxxxx视频 | 国产在线美女 | 欧美99热| 国产精品嫩草影院123 | 欧美精品乱码久久久久久按摩 | 成人在线观看你懂的 | 91成年人在线观看 | 超碰在线公开 | 成人在线播放视频 | 99久久99久久精品国产片果冰 | 久久久久久久久久久久99 | 午夜私人影院 | 麻豆视频观看 | 粉嫩av一区二区三区四区五区 | 欧美人体xx | 天天色播 | 久草在线资源观看 | 欧美精品久久久 | 天天鲁天天干天天射 | 最新av免费在线 | 超碰97人人在线 | 欧美一二三区在线观看 | 亚洲 综合 精品 | 国产精品久久精品国产 | 国产中文欧美日韩在线 | 国产传媒中文字幕 | 日本公妇色中文字幕 | 亚洲免费一级电影 | 在线视频日韩精品 | 91免费在线视频 | 午夜精品一区二区三区可下载 | 久久亚洲私人国产精品va | 免费三级在线 | 久久久久久国产精品免费 | 久久国产一区二区三区 | 日批网站在线观看 | 精品久久久久久国产 | 中文字幕999 | 成人va在线观看 | 日韩免费在线视频 | 五月天综合婷婷 | 成人小电影在线看 | 91丝袜美腿| 久久精品中文字幕少妇 | 亚洲尺码电影av久久 | 国产黄色片久久 | www.久久免费 | 正在播放亚洲精品 | 久久99亚洲精品久久久久 | 精品国内自产拍在线观看视频 | 免费男女羞羞的视频网站中文字幕 | 99 国产精品| 中文在线a天堂 | 精品亚洲欧美无人区乱码 | 国产精品久久久久久久婷婷 | 久久久久免费精品视频 | 亚洲国产成人在线观看 | 97精品在线视频 | 久草视频播放 | 中文亚洲欧美日韩 | 国产在线精品国自产拍影院 | 免费在线观看不卡av | 久久久久久久久久影视 | 日韩欧美69 | 黄色大片免费网站 | 久久er99热精品一区二区三区 | 97在线视频免费 | 欧美污污网站 | 波多野结衣视频在线 | 涩涩网站在线 | 免费在线观看不卡av | 波多野结衣在线视频一区 | 狠狠躁夜夜a产精品视频 | 中文字幕丝袜 | 精品亚洲欧美无人区乱码 | 成人av片在线观看 | 久久不卡av | 色多多在线观看 | 国产一二区免费视频 | www.天天操 | 欧美一级黄大片 | 五月婷社区 | 久久精品站 | 日本99精品| 午夜视频色 | 国产精品99久久久精品 | 亚洲综合色视频在线观看 | 亚洲精品视频在线免费播放 | 成人免费ⅴa | 国产精品久久久久久久久久免费看 | 激情婷婷av | 久久精品99国产国产 | 91亚洲精品久久久中文字幕 | 天天操,夜夜操 | 99视频| www.com黄色| 国产不卡精品视频 | 91女子私密保健养生少妇 | 午夜av日韩 | 成人小视频在线观看免费 | 日韩在线电影一区 | 中文字幕资源网 国产 | 成人网中文字幕 | 性色xxxxhd | 久久五月激情 | 日韩在线视频一区二区三区 | 国产一性一爱一乱一交 | 香蕉视频久久久 | 国产精品麻豆99久久久久久 | 国产免费一区二区三区最新6 | 丁香电影小说免费视频观看 | 久久国产高清 | 成片免费观看视频大全 | 欧美大香线蕉线伊人久久 | 日本最大色倩网站www | 国产成人综合图片 | 欧美激情精品一区 | 久久狠狠亚洲综合 | 一级片免费视频 | 国产男男gay做爰 | 中国成人一区 | 人人草人人草 | 午夜精品久久久久久久99 | av成人在线播放 | 亚洲精品乱码久久久久久按摩 | 色婷婷88av视频一二三区 | 久久久久久视频 | 日本三级全黄少妇三2023 | 久久久久国产精品免费 | 亚洲精品久久久蜜桃直播 | 色国产精品一区在线观看 | 五月天综合色激情 | 日本精品一区二区 | 99精品视频在线看 | 九九99| 亚洲欧美成人 | 欧美极品少妇xbxb性爽爽视频 | 久久综合中文色婷婷 | 国产在线一区观看 | 国产精品中文久久久久久久 | 91少妇精拍在线播放 | av东方在线 | 欧美ⅹxxxxxx | 99免费国产 | 青青草视频精品 | 久久黄网站| 极品中文字幕 | 国产精品99久久99久久久二8 | 99视频在线观看一区三区 | 97色资源| 1区2区视频 | 国产精品女同一区二区三区久久夜 | 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | 免费大片黄在线 | 91丨九色丨蝌蚪丰满 | 国产又粗又猛又黄又爽 | 午夜精品视频一区 | 日韩中午字幕 | 精品国产美女 | 久久av免费观看 | 99r在线观看 | 国产精品伦一区二区三区视频 | 日韩视频在线一区 | 日韩激情一二三区 | 日韩免费视频线观看 | 女人18毛片a级毛片一区二区 | 啪啪av在线 | 欧美日韩高清一区二区三区 | 久久99久久99精品免观看粉嫩 | 一本—道久久a久久精品蜜桃 | 欧美91av| 国产福利资源 | 美女黄频免费 | 99久久精品国产一区二区成人 | 久久精品久久精品久久39 | 欧美另类重口 | 字幕网av| 欧美一级在线看 | 天天操夜夜拍 | 在线a人片免费观看视频 | 天天五月天色 | 日韩激情三级 | 日本黄色a级大片 | 美国三级黄色大片 | 日本性生活一级片 | 伊人激情网 | 久久综合九色欧美综合狠狠 | 蜜臀av性久久久久av蜜臀妖精 | 国产精品久久久777 成人手机在线视频 | 99c视频高清免费观看 | 欧美日韩久久不卡 | 日韩在线免费视频观看 | 91亚洲永久精品 | 日韩成人免费在线 | 天天操天天爽天天干 | 夜夜高潮夜夜爽国产伦精品 | 天堂av高清| 日韩电影在线观看一区 | 一区中文字幕在线观看 | 日韩www在线| 国产一级在线免费观看 | 97高清视频 | 久综合网| 蜜桃av综合网 | 91视频在线免费看 | a黄色一级 | 91女神的呻吟细腰翘臀美女 | 日韩欧美国产免费播放 | 欧美 亚洲 另类 激情 另类 | 国产精品成人免费精品自在线观看 | avwww在线| 黄色在线看网站 | 国产精品12| 免费在线看成人av | 一区中文字幕在线观看 | 在线观看亚洲电影 | 日本精品视频在线播放 | 国产精品一区二区av影院萌芽 | 久久久久国产成人精品亚洲午夜 | 欧美国产一区二区 | 人人看人人爱 | 国产精品久久久久aaaa九色 | 91激情小视频 | 精品自拍av | 国产一级免费播放 | 国产欧美精品一区二区三区 | 欧美成人精品欧美一级乱黄 | 日日夜夜草 | 中文乱码视频在线观看 |