Android--Activity的創(chuàng)建過程(一)

Activity的創(chuàng)建過程概述

Activity的啟動可以是應(yīng)用啟動時默認(rèn)Activity的創(chuàng)建啟動,也可以是從當(dāng)前Activity跳轉(zhuǎn)到未創(chuàng)建的目標(biāo)Activity,本篇主要針對當(dāng)前Activity跳轉(zhuǎn)到未創(chuàng)建目標(biāo)Activity的過程,新Activity的創(chuàng)建過程進(jìn)行解析。

Activity的創(chuàng)建過程的大致流程

從調(diào)用startActivity()方法到目標(biāo)Activity顯示在屏幕上驹饺,中間的執(zhí)行流程大致有以下內(nèi)容:

  1. 發(fā)起啟動請求:當(dāng)在當(dāng)前Activity中調(diào)用startActivity()方法時,會創(chuàng)建一個Intent對象檐春,并通過這個對象來描述需要啟動的目標(biāo)Activity逻淌。
  2. Binder機制交互:調(diào)用startActivity()后,客戶端(即啟動Activity的進(jìn)程)會通過Binder機制與服務(wù)端(system_server進(jìn)程)進(jìn)行交互疟暖。這一過程涉及到跨進(jìn)程通信卡儒,確保請求被正確傳遞到系統(tǒng)服務(wù)田柔。
  3. AMS處理請求:系統(tǒng)服務(wù)中的ActivityManagerService(AMS)負(fù)責(zé)處理來自客戶端的啟動請求。AMS會處理Intent骨望,并確定要啟動的Activity硬爆。
  4. Zygote進(jìn)程派生新進(jìn)程:如果目標(biāo)Activity尚未在內(nèi)存中存在,系統(tǒng)會通過Zygote進(jìn)程派生出新的進(jìn)程來承載新的Activity擎鸠。
  5. 調(diào)用目標(biāo)Activity的onCreate()方法:系統(tǒng)會調(diào)用目標(biāo)Activity的onCreate()方法缀磕,這是Activity生命周期的第一步,進(jìn)行初始化操作劣光。
  6. 調(diào)用其他生命周期方法:隨著Activity的創(chuàng)建和顯示袜蚕,系統(tǒng)還會依次調(diào)用onStart()、onResume()等生命周期方法绢涡,使Activity進(jìn)入“運行”狀態(tài)牲剃。
  7. 任務(wù)棧管理:Android系統(tǒng)會將新啟動的Activity添加到任務(wù)棧中,并根據(jù)啟動模式和任務(wù)類型進(jìn)行管理雄可。
  8. 用戶界面更新:最后凿傅,系統(tǒng)會更新用戶界面,將目標(biāo)Activity顯示在屏幕上数苫,用戶可以開始與之交互聪舒。

--------------------------------------- 具體流程與源碼解析如下 ---------------------------------------

當(dāng)前Activity啟動新Activity的操作

當(dāng)某個Activity要跳轉(zhuǎn)到另一個Activity時,會發(fā)起startActivity虐急,從程序員編寫的Activity中跳轉(zhuǎn)到Activity.java中箱残;

  • Activity中的startActivity()方法
  1. 首先會檢查是否存在需要恢復(fù)的自動填充會話mIntent, 如果包含額外的恢復(fù)會話令牌和恢復(fù)交叉活動需要執(zhí)行一些額外操作止吁;
  2. 如果當(dāng)前活動與即將啟動的活動在同一個包中疚宇,應(yīng)用會自動填充恢復(fù)機制,獲取AutofillManager.EXTRA_RESTORE_SESSION_TOKEN 的 IBinder 對象存儲在intent中赏殃,以便在啟動的新活動中進(jìn)行恢復(fù)操作;
  3. 然后將恢復(fù)能力從當(dāng)前活動中移除间涵,添加到即將啟動的活動中仁热。然后根據(jù)選項options參數(shù)調(diào)用startActivityForResult方法啟動新的Activity。
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    // 檢查是否存在需要恢復(fù)的自動填充會話
    if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
            && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
        // 檢查當(dāng)前活動和要啟動的活動是否屬于同一個應(yīng)用程序
        if (TextUtils.equals(getPackageName(),
                intent.resolveActivity(getPackageManager()).getPackageName())) {
            // 應(yīng)用自動填充恢復(fù)機制到通過startActivity()啟動的活動
            final IBinder token =
                    mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
            // 從當(dāng)前活動中移除恢復(fù)能力
            mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
            mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
            // 將恢復(fù)令牌放入intent中
            intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
            intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
        }
    }
    // 如果提供了選項勾哩,則使用選項啟動活動
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        // 注意我們想要通過這個調(diào)用來兼容可能已經(jīng)重寫了該方法的應(yīng)用程序
        startActivityForResult(intent, -1);
    }
}
  • Activity中的startActivityForResult()方法

startActivityForResult方法用于啟動一個新Activity并等待返回結(jié)果的抗蠢。首先會檢查當(dāng)前活動是否有父活動,如果有的話需要調(diào)用startActivityForChild方法來啟動新的Activity思劳,如果沒有的話則在當(dāng)前方法中啟動新的Activity迅矛。
當(dāng)前活動無父活動,啟動新的Activity:

  1. 首先對options選項進(jìn)行處理潜叛,如果options參數(shù)是空會默認(rèn)獲取當(dāng)前活動的選項秽褒,選項中的是場景過度的動畫類型壶硅;
  2. 然后使用mInstrumentation.execStartActivity() 方法啟動新的活動,并將啟動結(jié)果存儲在 ar 變量中销斟;
  3. 當(dāng)啟動結(jié)果不為空時庐椒,通過ActivityThread.sendActivityResult()方法將活動啟動結(jié)果發(fā)送給啟動該活動的父活動;
  4. 如果requestCode大于等于0表示需要等待返回結(jié)果蚂踊,將mStartedActivity設(shè)置為true约谈,在結(jié)果返回之前保持活動不可見;
  5. 最后清除輸入焦點犁钟、停止動畫棱诱。
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
    if (mParent == null) {
        // 處理傳入的選項,可能用于對選項進(jìn)行一些特定的處理或配置
        options = transferSpringboardActivityOptions(options);
        // 啟動新的活動涝动,返回一個ActivityResult對象迈勋,該對象包含了新活動的啟動結(jié)果
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            // 如果ActivityResult對象不為空,說明新活動已經(jīng)成功啟動捧存,sendActivityResult()方法發(fā)送活動結(jié)果粪躬,
            // 將令牌、嵌入式ID昔穴、請求碼镰官、結(jié)果代碼和結(jié)果數(shù)據(jù)作為參數(shù)傳遞給新活動
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            // 如果requestCode大于等于0,表示需要等待返回結(jié)果吗货,將mStartedActivity設(shè)置為true泳唠,以便在結(jié)果返回之前保持活動不可見
            mStartedActivity = true;
        }
        // 取消輸入并開始退出過渡動畫,用于清除輸入焦點宙搬、停止動畫等操作
        cancelInputsAndStartExitTransition(options);
    } else {
        // 如果該活動非父活動笨腥,則走startActivityFromChild方法,執(zhí)行流程與startActivityForResult()一致勇垛,
        // execStartActivity和sendActivityResult傳遞的參數(shù)改為子活動
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}
  • Instrumentation中的execStartActivity()方法

execStartActivity()是用于啟動一個新活動的公共方法脖母,接收7個參數(shù)(Context 當(dāng)前活動上下文,IBinder contextThread當(dāng)前活動的線程闲孤,IBinder token 當(dāng)前活動的標(biāo)識符谆级,Activity target 目標(biāo)活動,Intent intent 要啟動的活動的意圖讼积,int requestCode 請求碼肥照,Bundle options 啟動選項)。

execStartActivity()方法內(nèi)部勤众,會根據(jù)傳入的參數(shù)調(diào)用startActivityAsUser方法創(chuàng)建一個新的Activity實例舆绎,并調(diào)用其onCreate()方法進(jìn)行初始化,然后將新的Activity實例添加到Activity棧中们颜,并將其設(shè)置為當(dāng)前運行的Activity吕朵。

execStartActivity()方法是在應(yīng)用程序的主線程中執(zhí)行的猎醇,如果該方法中有耗時的操作,可能會導(dǎo)致界面卡頓或ANR錯誤边锁;在實際應(yīng)用中姑食,通常會使用Handler或其他異步機制來避免這種情況的發(fā)生。

  1. 將 contextThread 轉(zhuǎn)換為 IApplicationThread 類型的 whoThread茅坛;
  2. 調(diào)用 target.onProvideReferrer() 方法獲取引用者referrer音半,并將其添加到意圖中;
  3. 如果有活動監(jiān)視器存在贡蓖,遍歷所有ActivityMonitor:
    ① 如果有當(dāng)前ActivityMonitor忽略特定意圖匹配曹鸠,則直接通過onStartActivity(intent) 方法啟動活動,將結(jié)果存儲在 result 變量中斥铺;如果result不會空則增加ActivityMonitor的命中次數(shù)mHits彻桃,將result返回;
    ② 否則需要判斷特定意圖匹配晾蜘,如果活動監(jiān)視器與給定的上下文邻眷、包名和意圖匹配,則增加活動監(jiān)視器的命中次數(shù)(mHits)剔交;如果活動監(jiān)視器是阻塞的肆饶,則根據(jù)請求碼返回相應(yīng)的結(jié)果或 null,否則岖常,跳出循環(huán)驯镊。
  4. 最后代碼會嘗試啟動新的活動:
    ① 首先調(diào)用 intent.migrateExtraStreamToClipData(who) 方法將額外數(shù)據(jù)遷移到剪貼板;
    ② 然后調(diào)用 intent.prepareToLeaveProcess(who) 方法準(zhǔn)備離開進(jìn)程竭鞍;
    ③ 最后使用 ActivityTaskManager.getService().startActivity() 方法啟動新的活動板惑,并檢查啟動結(jié)果。
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, String resultWho,
            Intent intent, int requestCode, Bundle options, UserHandle user) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    ActivityResult result = null;
                    if (am.ignoreMatchingSpecificIntents()) {
                        result = am.onStartActivity(intent);
                    }
                    if (result != null) {
                        am.mHits++;
                        return result;
                    } else if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData(who);
            intent.prepareToLeaveProcess(who);
            int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
                    who.getBasePackageName(), who.getAttributionTag(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho,
                    requestCode, 0, null, options, user.getIdentifier());
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

總的來說偎快,execStartActivity()啟動新活動分為2種:

  1. 當(dāng)活動監(jiān)視器存在且忽略特定意圖匹配時冯乘,會通過ActivityMonitor中的onStartActivity(intent) 方法處理應(yīng)用程序中的啟動意圖,根據(jù)需要進(jìn)行相應(yīng)操作晒夹,從而啟動新活動往湿;
  2. 其他情況下都會通過ActivityTaskManager.getService().startActivity()方法,將活動的啟動意圖傳遞給系統(tǒng)服務(wù)器來啟動目標(biāo)活動的惋戏。
系統(tǒng)服務(wù)器啟動新的Activity

LauncherAppsService和ActivityTaskManagerService中都有用于啟動一個Activity的startActivityAsUser方法,ActivityTaskManagerService是負(fù)責(zé)管理Activity的生命周期和調(diào)度他膳,而LauncherAppsService是用于管理從啟動器Launcher啟動的應(yīng)用响逢,所以當(dāng)從一個Activity跳轉(zhuǎn)到另一個Activity的過程調(diào)用的是ActivityTaskManagerService中的startActivityAsUser方法。

  • ATMS棕孙,即ActivityTaskManagerService舔亭,是Android 10中引入的一個新的系統(tǒng)服務(wù)些膨,專門負(fù)責(zé)管理Activity及其容器(任務(wù)、堆棧钦铺、顯示等)订雾。
  • 在Android 10之前,Android的四大組件(Activity矛洞、Service洼哎、BroadcastReceiver和ContentProvider)統(tǒng)一由AMS(ActivityManagerService)進(jìn)行管理。但隨著Android系統(tǒng)的發(fā)展和功能的增加沼本,為了更好地管理和優(yōu)化Activity噩峦,Android 10對這一部分功能進(jìn)行了分離,將AMS中與Activity相關(guān)的管理職責(zé)劃分給了新的ATMS抽兆。
  • ActivityTaskManagerService中的startActivityAsUser()方法

ActivityTaskManagerService中startActivityAsUser方法用于啟動一個Activity识补,并指定用戶ID,該方法會接收13個參數(shù):

  • IApplicationThread caller:調(diào)用者的應(yīng)用線程辫红,用于標(biāo)識啟動Activity的應(yīng)用程序凭涂。
  • String callingPackage:調(diào)用者的包名,用于驗證調(diào)用者的權(quán)限贴妻。
  • @Nullable String callingFeatureId:調(diào)用者的功能ID切油,用于處理特定的功能請求。
  • Intent intent:要啟動的Activity的意圖(Intent),包含了啟動Activity所需的信息。
  • String resolvedType:意圖中指定的數(shù)據(jù)類型殴穴,用于解析Intent的數(shù)據(jù)驮履。
  • IBinder resultTo:用于接收結(jié)果的Binder對象,如果不需要返回結(jié)果則為null乔外。
  • String resultWho:用于標(biāo)識結(jié)果接收者的字符串,如果不需要返回結(jié)果則為null。
  • int requestCode:請求碼巢株,用于標(biāo)識啟動Activity的請求。
  • int startFlags:啟動標(biāo)志熙涤,用于控制Activity的啟動行為阁苞。
  • ProfilerInfo profilerInfo:性能分析信息,用于監(jiān)控Activity的啟動過程祠挫。
  • Bundle bOptions:Activity選項那槽,用于配置Activity的行為。
  • int userId:目標(biāo)用戶的ID等舔,用于指定要啟動Activity的用戶骚灸。
  • boolean validateIncomingUser:是否驗證傳入的用戶ID,如果為true則進(jìn)行驗證慌植。
  1. 首先通過assertPackageMatchesCallingUid方法驗證調(diào)用者的包名與調(diào)用者的UID是否匹配甚牲,并使用enforceNotIsolatedCaller方法檢查調(diào)用者是否為隔離進(jìn)程义郑,確保只有非隔離進(jìn)程可以進(jìn)行接下來的步驟啟動新的Activity,以保護(hù)系統(tǒng)的安全性和穩(wěn)定性丈钙;
  2. 然后通過getActivityStartController().checkTargetUser方法檢查目標(biāo)用戶ID是否有效非驮,并獲取目標(biāo)用戶的進(jìn)程ID和UID;
  3. 最后使用getActivityStartController().obtainStarter方法創(chuàng)建一個啟動器(Starter)對象雏赦,并通過鏈?zhǔn)秸{(diào)用設(shè)置各種參數(shù)劫笙,最后調(diào)用execute方法執(zhí)行啟動操作。
    private int startActivityAsUser(IApplicationThread caller, String callingPackage,
            @Nullable String callingFeatureId, Intent intent, String resolvedType,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
        assertPackageMatchesCallingUid(callingPackage);
        enforceNotIsolatedCaller("startActivityAsUser");

        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setCallingFeatureId(callingFeatureId)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setUserId(userId)
                .execute();

    }

obtainStarter會獲取ActivityStarter喉誊,該對象提供了一些列設(shè)置方法配置啟動的Activity邀摆,并執(zhí)行了ActivityStarter的execute()方法:

  • ActivityStarter中的execute()方法
  1. 檢查Intent中是否包含文件描述符,如果有則拋出異常;
  2. 獲取ActivityRecord對象和LaunchingState對象;
  3. 如果調(diào)用者還沒有解析Activity伍茄,那么在這里進(jìn)行解析;
  4. 根據(jù)全局配置是否發(fā)生變化栋盹,執(zhí)行相應(yīng)的操作:

① 如果發(fā)生變化設(shè)置標(biāo)志位;② 清除調(diào)用者的身份信息敷矫;③ 嘗試解析到重量級切換器(如果需要)例获,如果解析失敗,則返回錯誤碼曹仗;④ 執(zhí)行請求executeRequest()榨汤,并恢復(fù)調(diào)用者的身份信息;⑤ 如果全局配置發(fā)生了變化怎茫,那么在當(dāng)前活動暫停時進(jìn)行新的配置切換收壕;⑥ 等待當(dāng)前活動暫停,更新全局配置轨蛤;

  1. 通知ActivityMetricsLogger活動已啟動蜜宪,并返回結(jié)果。
  1. ActivityStarter是一個控制器祥山,負(fù)責(zé)解釋解釋如何在特定的時間和方式下啟動一個Activity圃验;
  2. execute()作為外部接口,觸發(fā)整個啟動過程缝呕,而新Activity的具體的啟動邏輯和記錄創(chuàng)建會走到executeRequest()方法中執(zhí)行澳窑;
    int execute() {
        try {
            // Refuse possible leaked file descriptors
            if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
                throw new IllegalArgumentException("File descriptors passed in Intent");
            }

            final LaunchingState launchingState;
            synchronized (mService.mGlobalLock) {
                final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
                launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
                        mRequest.intent, caller);
            }

            // If the caller hasn't already resolved the activity, we're willing
            // to do so here. If the caller is already holding the WM lock here,
            // and we need to check dynamic Uri permissions, then we're forced
            // to assume those permissions are denied to avoid deadlocking.
            if (mRequest.activityInfo == null) {
                mRequest.resolveActivity(mSupervisor);
            }

            int res;
            synchronized (mService.mGlobalLock) {
                final boolean globalConfigWillChange = mRequest.globalConfig != null
                        && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
                final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
                if (stack != null) {
                    stack.mConfigWillChange = globalConfigWillChange;
                }
                if (DEBUG_CONFIGURATION) {
                    Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
                            + globalConfigWillChange);
                }

                final long origId = Binder.clearCallingIdentity();

                res = resolveToHeavyWeightSwitcherIfNeeded();
                if (res != START_SUCCESS) {
                    return res;
                }
                res = executeRequest(mRequest);

                Binder.restoreCallingIdentity(origId);

                if (globalConfigWillChange) {
                    // If the caller also wants to switch to a new configuration, do so now.
                    // This allows a clean switch, as we are waiting for the current activity
                    // to pause (so we will not destroy it), and have not yet started the
                    // next activity.
                    mService.mAmInternal.enforceCallingPermission(
                            android.Manifest.permission.CHANGE_CONFIGURATION,
                            "updateConfiguration()");
                    if (stack != null) {
                        stack.mConfigWillChange = false;
                    }
                    if (DEBUG_CONFIGURATION) {
                        Slog.v(TAG_CONFIGURATION,
                                "Updating to new configuration after starting activity.");
                    }
                    mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
                }

                // Notify ActivityMetricsLogger that the activity has launched.
                // ActivityMetricsLogger will then wait for the windows to be drawn and populate
                // WaitResult.
                mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
                        mLastStartActivityRecord);
                return getExternalResult(mRequest.waitResult == null ? res
                        : waitForResult(res, mLastStartActivityRecord));
            }
        } finally {
            onExecutionComplete();
        }
    }

  • ActivityStarter中的executeRequest()方法

執(zhí)行啟動新Activity的請求會進(jìn)行以下操作:

  1. 清除調(diào)用者的身份信息:使用Binder.clearCallingIdentity()方法清除調(diào)用者的身份信息,以便在后續(xù)的操作中以系統(tǒng)權(quán)限運行供常。
  2. 檢查并處理啟動模式:根據(jù)請求中的啟動模式(如標(biāo)準(zhǔn)啟動摊聋、單實例啟動等),確定如何處理Activity的啟動栈暇。這可能涉及檢查任務(wù)棧中是否存在要啟動的Activity實例栗精,并根據(jù)需要處理啟動模式。
  3. 解析Activity:如果調(diào)用者尚未解析目標(biāo)Activity,executeRequest會在這里進(jìn)行解析悲立。這包括查找匹配的Activity組件、驗證其存在并獲取相關(guān)的ActivityInfo對象新博。
  4. 檢查權(quán)限和URI權(quán)限:在啟動Activity之前薪夕,executeRequest還會進(jìn)行權(quán)限檢查。如果Intent攜帶了數(shù)據(jù)URI赫悄,并且需要動態(tài)檢查URI權(quán)限原献,那么會在此進(jìn)行相應(yīng)的權(quán)限驗證。
  5. 啟動Activity:通過調(diào)用mService.startActivity方法來啟動目標(biāo)Activity埂淮。這會將請求傳遞給系統(tǒng)的ActivityManagerService姑隅,由其負(fù)責(zé)實際的Activity啟動過程。
  6. 恢復(fù)調(diào)用者的身份信息:使用Binder.restoreCallingIdentity(origId)方法恢復(fù)之前清除的調(diào)用者身份信息倔撞。
  7. 處理結(jié)果:如果請求中指定了等待結(jié)果讲仰,那么executeRequest會等待目標(biāo)Activity的結(jié)果返回,并將其返回給調(diào)用者痪蝇。
  8. 處理全局配置變更:如果在啟動過程中全局配置發(fā)生了變化鄙陡,executeRequest會根據(jù)需要進(jìn)行相應(yīng)的處理,例如更新系統(tǒng)的配置信息躏啰。
  9. 通知ActivityMetricsLogger:最后趁矾,executeRequest會通知ActivityMetricsLogger活動已啟動,以便進(jìn)行性能數(shù)據(jù)的收集和記錄给僵。

其中在執(zhí)行請求的過程中毫捣,創(chuàng)建了本次將要啟動的ActivityRecord(目標(biāo)Activity在AMS中的數(shù)據(jù)結(jié)構(gòu))

    private int executeRequest(Request request) {
        if (TextUtils.isEmpty(request.reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        mLastStartReason = request.reason;
        mLastStartActivityTimeMs = System.currentTimeMillis();
        mLastStartActivityRecord = null;

        final IApplicationThread caller = request.caller;
        Intent intent = request.intent;
        NeededUriGrants intentGrants = request.intentGrants;
        String resolvedType = request.resolvedType;
        ActivityInfo aInfo = request.activityInfo;
        ResolveInfo rInfo = request.resolveInfo;
        final IVoiceInteractionSession voiceSession = request.voiceSession;
        final IBinder resultTo = request.resultTo;
        String resultWho = request.resultWho;
        int requestCode = request.requestCode;
        int callingPid = request.callingPid;
        int callingUid = request.callingUid;
        String callingPackage = request.callingPackage;
        String callingFeatureId = request.callingFeatureId;
        final int realCallingPid = request.realCallingPid;
        final int realCallingUid = request.realCallingUid;
        final int startFlags = request.startFlags;
        final SafeActivityOptions options = request.activityOptions;
        Task inTask = request.inTask;

        int err = ActivityManager.START_SUCCESS;
        // Pull the optional Ephemeral Installer-only bundle out of the options early.
        final Bundle verificationBundle =
                options != null ? options.popAppVerificationBundle() : null;

        WindowProcessController callerApp = null;
        if (caller != null) {
            callerApp = mService.getProcessController(caller);
            if (callerApp != null) {
                callingPid = callerApp.getPid();
                callingUid = callerApp.mInfo.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
                        + ") when starting: " + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }

        final int userId = aInfo != null && aInfo.applicationInfo != null
                ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
        if (err == ActivityManager.START_SUCCESS) {
            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
                    + "} from uid " + callingUid);
        }

        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);
            if (DEBUG_RESULTS) {
                Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
            }
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }

        final int launchFlags = intent.getFlags();
        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            // Transfer the result target from the source activity to the new one being started,
            // including any failures.
            if (requestCode >= 0) {
                SafeActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            resultRecord = sourceRecord.resultTo;
            if (resultRecord != null && !resultRecord.isInStackLocked()) {
                resultRecord = null;
            }
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }
            if (sourceRecord.launchedFromUid == callingUid) {
                // The new activity is being launched from the same uid as the previous activity
                // in the flow, and asking to forward its result back to the previous.  In this
                // case the activity is serving as a trampoline between the two, so we also want
                // to update its launchedFromPackage to be the same as the previous activity.
                // Note that this is safe, since we know these two packages come from the same
                // uid; the caller could just as well have supplied that same package name itself
                // . This specifially deals with the case of an intent picker/chooser being
                // launched in the app flow to redirect to an activity picked by the user, where
                // we want the final activity to consider it to have been launched by the
                // previous app activity.
                callingPackage = sourceRecord.launchedFromPackage;
                callingFeatureId = sourceRecord.launchedFromFeatureId;
            }
        }

        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
            // We couldn't find a class that can handle the given Intent.
            // That's the end of that!
            err = ActivityManager.START_INTENT_NOT_RESOLVED;
        }

        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
            // We couldn't find the specific class specified in the Intent.
            // Also the end of the line.
            err = ActivityManager.START_CLASS_NOT_FOUND;
        }

        if (err == ActivityManager.START_SUCCESS && sourceRecord != null
                && sourceRecord.getTask().voiceSession != null) {
            // If this activity is being launched as part of a voice session, we need to ensure
            // that it is safe to do so.  If the upcoming activity will also be part of the voice
            // session, we can only launch it if it has explicitly said it supports the VOICE
            // category, or it is a part of the calling app.
            if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
                    && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
                try {
                    intent.addCategory(Intent.CATEGORY_VOICE);
                    if (!mService.getPackageManager().activitySupportsIntent(
                            intent.getComponent(), intent, resolvedType)) {
                        Slog.w(TAG, "Activity being started in current voice task does not support "
                                + "voice: " + intent);
                        err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                    }
                } catch (RemoteException e) {
                    Slog.w(TAG, "Failure checking voice capabilities", e);
                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                }
            }
        }

        if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
            // If the caller is starting a new voice session, just make sure the target
            // is actually allowing it to run this way.
            try {
                if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
                        intent, resolvedType)) {
                    Slog.w(TAG,
                            "Activity being started in new voice task does not support: " + intent);
                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failure checking voice capabilities", e);
                err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
            }
        }

        final ActivityStack resultStack = resultRecord == null
                ? null : resultRecord.getRootTask();

        if (err != START_SUCCESS) {
            if (resultRecord != null) {
                resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
                        null /* data */, null /* dataGrants */);
            }
            SafeActivityOptions.abort(options);
            return err;
        }

        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
                request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord, resultStack);
        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                callingPid, resolvedType, aInfo.applicationInfo);
        abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
                callingPackage);

        boolean restrictedBgActivity = false;
        if (!abort) {
            try {
                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
                        "shouldAbortBackgroundActivityStart");
                restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
                        callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
                        request.originatingPendingIntent, request.allowBackgroundActivityStart,
                        intent);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            }
        }

        // Merge the two options bundles, while realCallerOptions takes precedence.
        ActivityOptions checkedOptions = options != null
                ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
        if (request.allowPendingRemoteAnimationRegistryLookup) {
            checkedOptions = mService.getActivityStartController()
                    .getPendingRemoteAnimationRegistry()
                    .overrideOptionsIfNeeded(callingPackage, checkedOptions);
        }
        if (mService.mController != null) {
            try {
                // The Intent we give to the watcher has the extra data stripped off, since it
                // can contain private information.
                Intent watchIntent = intent.cloneFilter();
                abort |= !mService.mController.activityStarting(watchIntent,
                        aInfo.applicationInfo.packageName);
            } catch (RemoteException e) {
                mService.mController = null;
            }
        }

        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
                callingFeatureId);
        if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,
                callingUid, checkedOptions)) {
            // activity start was intercepted, e.g. because the target user is currently in quiet
            // mode (turn off work) or the target application is suspended
            intent = mInterceptor.mIntent;
            rInfo = mInterceptor.mRInfo;
            aInfo = mInterceptor.mAInfo;
            resolvedType = mInterceptor.mResolvedType;
            inTask = mInterceptor.mInTask;
            callingPid = mInterceptor.mCallingPid;
            callingUid = mInterceptor.mCallingUid;
            checkedOptions = mInterceptor.mActivityOptions;

            // The interception target shouldn't get any permission grants
            // intended for the original destination
            intentGrants = null;
        }

        if (abort) {
            if (resultRecord != null) {
                resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
                        null /* data */, null /* dataGrants */);
            }
            // We pretend to the caller that it was really started, but they will just get a
            // cancel result.
            ActivityOptions.abort(checkedOptions);
            return START_ABORTED;
        }

        // If permissions need a review before any of the app components can run, we
        // launch the review activity and pass a pending intent to start the activity
        // we are to launching now after the review is completed.
        if (aInfo != null) {
            if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                    aInfo.packageName, userId)) {
                final IIntentSender target = mService.getIntentSenderLocked(
                        ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
                        callingUid, userId, null, null, 0, new Intent[]{intent},
                        new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
                                | PendingIntent.FLAG_ONE_SHOT, null);

                Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);

                int flags = intent.getFlags();
                flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;

                /*
                 * Prevent reuse of review activity: Each app needs their own review activity. By
                 * default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities
                 * with the same launch parameters (extras are ignored). Hence to avoid possible
                 * reuse force a new activity via the MULTIPLE_TASK flag.
                 *
                 * Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,
                 * hence no need to add the flag in this case.
                 */
                if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {
                    flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
                }
                newIntent.setFlags(flags);

                newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
                newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
                if (resultRecord != null) {
                    newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
                }
                intent = newIntent;

                // The permissions review target shouldn't get any permission
                // grants intended for the original destination
                intentGrants = null;

                resolvedType = null;
                callingUid = realCallingUid;
                callingPid = realCallingPid;

                rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
                        computeResolveFilterUid(
                                callingUid, realCallingUid, request.filterCallingUid));
                aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
                        null /*profilerInfo*/);

                if (DEBUG_PERMISSIONS_REVIEW) {
                    final ActivityStack focusedStack =
                            mRootWindowContainer.getTopDisplayFocusedStack();
                    Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
                            true, false) + "} from uid " + callingUid + " on display "
                            + (focusedStack == null ? DEFAULT_DISPLAY
                                    : focusedStack.getDisplayId()));
                }
            }
        }

        // If we have an ephemeral app, abort the process of launching the resolved intent.
        // Instead, launch the ephemeral installer. Once the installer is finished, it
        // starts either the intent we resolved here [on install error] or the ephemeral
        // app [on install success].
        if (rInfo != null && rInfo.auxiliaryInfo != null) {
            intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
                    callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
            resolvedType = null;
            callingUid = realCallingUid;
            callingPid = realCallingPid;

            // The ephemeral installer shouldn't get any permission grants
            // intended for the original destination
            intentGrants = null;

            aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
        }

        final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, callingFeatureId, intent, resolvedType, aInfo,
                mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
                request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
                sourceRecord);
        mLastStartActivityRecord = r;

        if (r.appTimeTracker == null && sourceRecord != null) {
            // If the caller didn't specify an explicit time tracker, we want to continue
            // tracking under any it has.
            r.appTimeTracker = sourceRecord.appTimeTracker;
        }

        final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();

        // If we are starting an activity that is not from the same uid as the currently resumed
        // one, check whether app switches are allowed.
        if (voiceSession == null && stack != null && (stack.getResumedActivity() == null
                || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                    realCallingPid, realCallingUid, "Activity start")) {
                if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) {
                    mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                            sourceRecord, startFlags, stack, callerApp, intentGrants));
                }
                ActivityOptions.abort(checkedOptions);
                return ActivityManager.START_SWITCHES_CANCELED;
            }
        }

        mService.onStartActivitySetDidAppSwitch();
        mController.doPendingActivityLaunches(false);

        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
                restrictedBgActivity, intentGrants);

        if (request.outActivity != null) {
            request.outActivity[0] = mLastStartActivityRecord;
        }

        return mLastStartActivityResult;
    }

  • ActivityStarter中的startActivityUnchecked()方法

執(zhí)行請求executeRequest,主要通過調(diào)用startActivityUnchecked方法來啟動目標(biāo)Activity帝际,將請求傳遞給系統(tǒng)的ActivityManagerService執(zhí)行Activity啟動過程:

  1. 首先調(diào)用mService.deferWindowLayout()來暫停窗口布局更新蔓同;
  2. 然后調(diào)用startActivityInner()方法執(zhí)行實際的Activity啟動操作,并將返回的結(jié)果賦值給result變量胡本;
  3. 通過handleStartResult()方法處理啟動結(jié)果牌柄,并獲取啟動的Activity所在的任務(wù)棧startedActivityStack;
  4. 調(diào)用postStartActivityProcessing()方法進(jìn)行后續(xù)處理侧甫,并返回啟動結(jié)果珊佣。

startActivityUnchecked()方法更多地處理與客戶端相關(guān)的邏輯,而startActivityInner()方法則處理與服務(wù)端即系統(tǒng)服務(wù)進(jìn)程(system_server)的交互披粟。

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                boolean restrictedBgActivity, NeededUriGrants intentGrants) {
        int result = START_CANCELED;
        final ActivityStack startedActivityStack;
        try {
            mService.deferWindowLayout();
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
            result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
            startedActivityStack = handleStartResult(r, result);
            mService.continueWindowLayout();
        }

        postStartActivityProcessing(r, result, startedActivityStack);

        return result;
    }
  • ActivityStarter中的startActivityInner()方法

startActivityInner方法是啟動一個Activity的核心方法咒锻,處理了啟動Activity所需的各種參數(shù)和邏輯,包括任務(wù)棧管理守屉、權(quán)限檢查惑艇、URI權(quán)限授予等:

  1. setInitialState設(shè)置初始狀態(tài):根據(jù)傳入的參數(shù)設(shè)置Activity的初始狀態(tài),如啟動標(biāo)志、任務(wù)棧等滨巴。
  2. computeLaunchingTaskFlags計算任務(wù)棧標(biāo)志:根據(jù)當(dāng)前任務(wù)棧的情況計算任務(wù)棧標(biāo)志思灌。
  3. computeSourceStack計算源任務(wù)棧:獲取啟動Activity的任務(wù)棧。
  4. Intent.setFlags設(shè)置Intent標(biāo)志:將計算出的任務(wù)棧標(biāo)志設(shè)置到Intent中恭取。
  5. getReusableTask獲取可重用的任務(wù):嘗試從最近任務(wù)列表中獲取可重用的任務(wù)泰偿。
  6. isAllowedToStart檢查是否有權(quán)限啟動:檢查調(diào)用者是否有權(quán)限啟動目標(biāo)Activity。
  7. recycleTask回收任務(wù):如果有可重用的任務(wù)蜈垮,將其回收到目標(biāo)任務(wù)棧中耗跛。
  8. getLaunchStack獲取目標(biāo)任務(wù)棧:根據(jù)計算出的任務(wù)棧標(biāo)志獲取目標(biāo)任務(wù)棧。
  9. 創(chuàng)建新任務(wù):如果需要創(chuàng)建新任務(wù)攒发,則創(chuàng)建新任務(wù)并將其setNewTask關(guān)聯(lián)到目標(biāo)任務(wù)棧调塌。
  10. Service.getLockTaskController().isLockTaskModeViolation檢查鎖屏模式:如果啟動的Activity違反了鎖屏模式,則返回錯誤惠猿。
  11. addOrReparentStartingActivity添加或重新設(shè)置啟動活動Activity的父級:將啟動的Activity添加到目標(biāo)任務(wù)棧中羔砾。
  12. isTopStackInDisplayArea移動到前臺:如果需要,將目標(biāo)任務(wù)棧移動到前臺紊扬。
  13. getUriPermissionsLocked授予URI權(quán)限:從Intent中獲取URI權(quán)限并授予給目標(biāo)Activity蜒茄。
  14. getPackageManagerInternalLocked授予隱式訪問權(quán)限:如果需要,為目標(biāo)Activity授予隱式訪問權(quán)限餐屎。
  15. logStartActivity記錄任務(wù)創(chuàng)建事件:記錄任務(wù)創(chuàng)建事件檀葛。
  16. 啟動Activity:調(diào)用目標(biāo)任務(wù)棧的startActivityLocked方法啟動Activity。
  17. resumeFocusedStacksTopActivities恢復(fù)焦點:如果需要腹缩,恢復(fù)目標(biāo)任務(wù)棧的焦點屿聋。
  18. updateUserStack更新用戶任務(wù)棧:更新用戶的任務(wù)棧信息。
  19. handleNonResizableTaskIfNeeded處理不可調(diào)整大小的Task:如果需要藏鹊,處理不可調(diào)整大小的Task润讥。
  20. 最后,return START_SUCCESS返回成功啟動的結(jié)果盘寡。
  1. 這個方法會判斷目標(biāo)Activity應(yīng)該歸屬哪個TaskRecord和ActivityStack楚殿,默認(rèn)情況下會調(diào)用setTaskFromSourceRecord(),即新建的Activity默認(rèn)是屬于發(fā)起方Activity所在的TaskRecord竿痰;
  2. 新的Activity的啟動是調(diào)用ActivityStack中的startActivityLocked方法脆粥,將新的Activity放到棧頂;
  3. 新的Activity移到棧頂后調(diào)用RootWindowContainer中的resumeFocusedStacksTopActivities()方法顯示新的Activity影涉;
    int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            boolean restrictedBgActivity, NeededUriGrants intentGrants) {
        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                voiceInteractor, restrictedBgActivity);

        computeLaunchingTaskFlags();

        computeSourceStack();

        mIntent.setFlags(mLaunchFlags);

        final Task reusedTask = getReusableTask();

        // If requested, freeze the task list
        if (mOptions != null && mOptions.freezeRecentTasksReordering()
                && mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
                && !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
            mFrozeTaskList = true;
            mSupervisor.mRecentTasks.setFreezeTaskListReordering();
        }

        // Compute if there is an existing task that should be used for.
        final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
        final boolean newTask = targetTask == null;
        mTargetTask = targetTask;

        computeLaunchParams(r, sourceRecord, targetTask);

        // Check if starting activity on given task or on a new task is allowed.
        int startResult = isAllowedToStart(r, newTask, targetTask);
        if (startResult != START_SUCCESS) {
            return startResult;
        }

        final ActivityRecord targetTaskTop = newTask
                ? null : targetTask.getTopNonFinishingActivity();
        if (targetTaskTop != null) {
            // Recycle the target task for this launch.
            startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
            if (startResult != START_SUCCESS) {
                return startResult;
            }
        } else {
            mAddingToTask = true;
        }

        // If the activity being launched is the same as the one currently at the top, then
        // we need to check if it should only be launched once.
        final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack();
        if (topStack != null) {
            startResult = deliverToCurrentTopIfNeeded(topStack, intentGrants);
            if (startResult != START_SUCCESS) {
                return startResult;
            }
        }

        if (mTargetStack == null) {
            mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, targetTask, mOptions);
        }
        if (newTask) {
            final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                    ? mSourceRecord.getTask() : null;
            setNewTask(taskToAffiliate);
            if (mService.getLockTaskController().isLockTaskModeViolation(
                    mStartActivity.getTask())) {
                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
        } else if (mAddingToTask) {
            addOrReparentStartingActivity(targetTask, "adding to task");
        }

        if (!mAvoidMoveToFront && mDoResume) {
            mTargetStack.getStack().moveToFront("reuseOrNewTask", targetTask);
            if (mOptions != null) {
                if (mOptions.getTaskAlwaysOnTop()) {
                    mTargetStack.setAlwaysOnTop(true);
                }
            }
            if (!mTargetStack.isTopStackInDisplayArea() && mService.mInternal.isDreaming()) {
                // Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
                // -behind transition so the Activity gets created and starts in visible state.
                mLaunchTaskBehind = true;
                r.mLaunchTaskBehind = true;
            }
        }

        mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
                mStartActivity.getUriPermissionsLocked());
        if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {
            // we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
            final PackageManagerInternal pmInternal =
                    mService.getPackageManagerInternalLocked();
            final int resultToUid = pmInternal.getPackageUidInternal(
                            mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
            pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
                    UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
                    resultToUid /*visible*/, true /*direct*/);
        }
        if (newTask) {
            EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
                    mStartActivity.getTask().mTaskId);
        }
        mStartActivity.logStartActivity(
                EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());

        mTargetStack.mLastPausedActivity = null;

        mRootWindowContainer.sendPowerHintForLaunchStartIfNeeded(
                false /* forceSend */, mStartActivity);

        mTargetStack.startActivityLocked(mStartActivity, topStack.getTopNonFinishingActivity(),
                newTask, mKeepCurTransition, mOptions);
        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isTopActivityFocusable()
                    || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                    && mStartActivity != topTaskActivity)) {
                // If the activity is not focusable, we can't resume it, but still would like to
                // make sure it becomes visible as it starts (this will also trigger entry
                // animation). An example of this are PIP activities.
                // Also, we don't want to resume activities in a task that currently has an overlay
                // as the starting activity just needs to be in the visible paused state until the
                // over is removed.
                // Passing {@code null} as the start parameter ensures all activities are made
                // visible.
                mTargetStack.ensureActivitiesVisible(null /* starting */,
                        0 /* configChanges */, !PRESERVE_WINDOWS);
                // Go ahead and tell window manager to execute app transition for this activity
                // since the app transition will not be triggered through the resume channel.
                mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
            } else {
                // If the target stack was not previously focusable (previous top running activity
                // on that stack was not visible) then any prior calls to move the stack to the
                // will not update the focused stack.  If starting the new activity now allows the
                // task stack to be focusable, then ensure that we now update the focused stack
                // accordingly.
                if (mTargetStack.isTopActivityFocusable()
                        && !mRootWindowContainer.isTopDisplayFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityInner");
                }
                mRootWindowContainer.resumeFocusedStacksTopActivities(
                        mTargetStack, mStartActivity, mOptions);
            }
        }
        mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);

        // Update the recent tasks list immediately when the activity starts
        mSupervisor.mRecentTasks.add(mStartActivity.getTask());
        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
                mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetStack);

        return START_SUCCESS;
    }

  • ActivityStack中的startActivityLocked()方法

該方法主要負(fù)責(zé)實際的Task和Activity的進(jìn)棧處理:

  1. 獲取ActivityRecore所屬的任務(wù)变隔,并將其任務(wù)positionChildAtTop移到棧頂;
  2. 如果有其他Activity遮擋新Activity蟹倾,將新Activity放在已有任務(wù)的頂部匣缘;
  3. 根據(jù)新Activity的Intent來準(zhǔn)備啟動的過渡動畫猖闪;
  4. 根據(jù)Intent來設(shè)置新Activity是否顯示的變量doShow;
  5. 設(shè)置后臺啟動邏輯肌厨,調(diào)用ensureActivitiesVisible方法確保所有活動都可見培慌;
  6. 根據(jù)doShow變量處理新Activity顯示啟動預(yù)覽邏輯,調(diào)用showStartingWindow方法來顯示新Activity的啟動預(yù)覽窗口柑爸;
  7. 如果不滿足條件检柬,則ActivityOptions.abort(options)取消動畫選項;
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
            boolean newTask, boolean keepCurTransition, ActivityOptions options) {
        Task rTask = r.getTask();
        final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
        final boolean isOrhasTask = rTask == this || hasChild(rTask);
        // mLaunchTaskBehind tasks get placed at the back of the task stack.
        if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) {
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
            positionChildAtTop(rTask);
        }
        Task task = null;
        if (!newTask && isOrhasTask) {
            // Starting activity cannot be occluding activity, otherwise starting window could be
            // remove immediately without transferring to starting activity.
            final ActivityRecord occludingActivity = getOccludingActivityAbove(r);
            if (occludingActivity != null) {
                // Here it is!  Now, if this is not yet visible (occluded by another task) to the
                // user, then just add it without starting; it will get started when the user
                // navigates back to it.
                if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task,
                        new RuntimeException("here").fillInStackTrace());
                rTask.positionChildAtTop(r);
                ActivityOptions.abort(options);
                return;
            }
        }

        // Place a new activity at top of stack, so it is next to interact with the user.

        // If we are not placing the new activity frontmost, we do not want to deliver the
        // onUserLeaving callback to the actual frontmost activity
        final Task activityTask = r.getTask();
        if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) {
            mStackSupervisor.mUserLeaving = false;
            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                    "startActivity() behind front, mUserLeaving=false");
        }

        task = activityTask;

        // Slot the activity into the history stack and proceed
        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
                new RuntimeException("here").fillInStackTrace());
        task.positionChildAtTop(r);

        // The transition animation and starting window are not needed if {@code allowMoveToFront}
        // is false, because the activity won't be visible.
        if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {
            final DisplayContent dc = getDisplay().mDisplayContent;
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                    "Prepare open transition: starting " + r);
            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
                mStackSupervisor.mNoAnimActivities.add(r);
            } else {
                int transit = TRANSIT_ACTIVITY_OPEN;
                if (newTask) {
                    if (r.mLaunchTaskBehind) {
                        transit = TRANSIT_TASK_OPEN_BEHIND;
                    } else if (getDisplay().isSingleTaskInstance()) {
                        // If a new task is being launched in a single task display, we don't need
                        // to play normal animation, but need to trigger a callback when an app
                        // transition is actually handled. So ignore already prepared activity, and
                        // override it.
                        transit = TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
                        keepCurTransition = false;
                    } else {
                        // If a new task is being launched, then mark the existing top activity as
                        // supporting picture-in-picture while pausing only if the starting activity
                        // would not be considered an overlay on top of the current activity
                        // (eg. not fullscreen, or the assistant)
                        if (canEnterPipOnTaskSwitch(focusedTopActivity,
                                null /* toFrontTask */, r, options)) {
                            focusedTopActivity.supportsEnterPipOnTaskSwitch = true;
                        }
                        transit = TRANSIT_TASK_OPEN;
                    }
                }
                dc.prepareAppTransition(transit, keepCurTransition);
                mStackSupervisor.mNoAnimActivities.remove(r);
            }
            boolean doShow = true;
            if (newTask) {
                // Even though this activity is starting fresh, we still need
                // to reset it to make sure we apply affinities to move any
                // existing activities from other tasks in to it.
                // If the caller has requested that the target task be
                // reset, then do so.
                if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                    resetTaskIfNeeded(r, r);
                    doShow = topRunningNonDelayedActivityLocked(null) == r;
                }
            } else if (options != null && options.getAnimationType()
                    == ActivityOptions.ANIM_SCENE_TRANSITION) {
                doShow = false;
            }
            if (r.mLaunchTaskBehind) {
                // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
                // tell WindowManager that r is visible even though it is at the back of the stack.
                r.setVisibility(true);
                ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
                // Go ahead to execute app transition for this activity since the app transition
                // will not be triggered through the resume channel.
                getDisplay().mDisplayContent.executeAppTransition();
            } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
                // Figure out if we are transitioning from another activity that is
                // "has the same starting icon" as the next one.  This allows the
                // window manager to keep the previous window it had previously
                // created, if it still had one.
                Task prevTask = r.getTask();
                ActivityRecord prev = prevTask.topActivityWithStartingWindow();
                if (prev != null) {
                    // We don't want to reuse the previous starting preview if:
                    // (1) The current activity is in a different task.
                    if (prev.getTask() != prevTask) {
                        prev = null;
                    }
                    // (2) The current activity is already displayed.
                    else if (prev.nowVisible) {
                        prev = null;
                    }
                }
                r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
            }
        } else {
            // If this is the first activity, don't do any fancy animations,
            // because there is nothing for it to animate on top of.
            ActivityOptions.abort(options);
        }
    }
  • RootWindowContainer中的resumeFocusedStacksTopActivities()方法

resumeFocusedStacksTopActivities()方法的作用是恢復(fù)焦點棧頂部的Activity竖配,即將當(dāng)前處于焦點狀態(tài)的Activity恢復(fù)到棧頂,使其成為用戶界面中可見和可交互的狀態(tài)里逆;

在Android系統(tǒng)中进胯,每個窗口容器ActivityStack都有一個焦點棧,用于管理當(dāng)前處于焦點狀態(tài)的Activity原押,當(dāng)用戶切換到其他應(yīng)用程序或任務(wù)時胁镐,焦點棧會發(fā)生變化,此時需要調(diào)用resumeFocusedStacksTopActivities()方法來恢復(fù)焦點棧頂部的Activity诸衔,確保用戶界面的正確顯示和交互體驗盯漂;

  1. 首先檢查是否準(zhǔn)備好恢復(fù),如果目標(biāo)棧不為空且目標(biāo)棧位于顯示區(qū)域頂部或當(dāng)前焦點棧為目標(biāo)棧笨农,那么調(diào)用targetStack.resumeTopActivityUncheckedLocked()方法恢復(fù)目標(biāo)棧頂部的Activity就缆,并將結(jié)果賦值給result變量;
  2. 遍歷所有顯示區(qū)域谒亦,找到可聚焦且可見的堆棧竭宰,如果任務(wù)顯示區(qū)域中的堆棧是頂部堆棧且頂部運行的Activity處于RESUMED狀態(tài),則executeAppTransition執(zhí)行應(yīng)用界面間的過渡操作份招;否則切揭,調(diào)用makeActiveIfNeeded()方法使頂部運行的Activity變?yōu)榛顒訝顟B(tài);
  3. 如果在顯示區(qū)域中沒有恢復(fù)任何有效的Activity锁摔,則請求顯式恢復(fù)焦點堆棧中的頂部Activity廓旬,以確保至少啟動并恢復(fù)主Activity,并且不會發(fā)生遞歸谐腰;
  4. 最后孕豹,返回result變量的值。
    boolean resumeFocusedStacksTopActivities(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

        if (!mStackSupervisor.readyToResume()) {
            return false;
        }

        boolean result = false;
        if (targetStack != null && (targetStack.isTopStackInDisplayArea()
                || getTopDisplayFocusedStack() == targetStack)) {
            result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }

        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            boolean resumedOnDisplay = false;
            final DisplayContent display = getChildAt(displayNdx);
            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
                    final ActivityRecord topRunningActivity = stack.topRunningActivity();
                    if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
                        continue;
                    }
                    if (stack == targetStack) {
                        // Simply update the result for targetStack because the targetStack had
                        // already resumed in above. We don't want to resume it again, especially in
                        // some cases, it would cause a second launch failure if app process was
                        // dead.
                        resumedOnDisplay |= result;
                        continue;
                    }
                    if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
                        // Kick off any lingering app transitions form the MoveTaskToFront
                        // operation, but only consider the top task and stack on that display.
                        stack.executeAppTransition(targetOptions);
                    } else {
                        resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
                    }
                }
            }
            if (!resumedOnDisplay) {
                // In cases when there are no valid activities (e.g. device just booted or launcher
                // crashed) it's possible that nothing was resumed on a display. Requesting resume
                // of top activity in focused stack explicitly will make sure that at least home
                // activity is started and resumed, and no recursion occurs.
                final ActivityStack focusedStack = display.getFocusedStack();
                if (focusedStack != null) {
                    result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
                } else if (targetStack == null) {
                    result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
                            display.getDefaultTaskDisplayArea());
                }
            }
        }

        return result;
    }

  • ActivityStack中的resumeTopActivityUncheckedLocked()方法

從一個Activity跳轉(zhuǎn)到另一個Activity通常會調(diào)用ActivityStack中的resumeTopActivityUncheckedLocked()方法恢復(fù)目標(biāo)棧頂部的Activity怔蚌,該方法的作用是恢復(fù)棧頂?shù)腁ctivity實例巩步,使其進(jìn)入活動狀態(tài);

  1. 檢查是否已經(jīng)在恢復(fù)棧頂?shù)腁ctivity桦踊,然后調(diào)用resumeTopActivityInnerLocked()方法來實際恢復(fù)棧頂?shù)腁ctivity椅野,并將結(jié)果保存在result變量中;
  2. 在恢復(fù)棧頂?shù)腁ctivity之后,需要調(diào)用checkReadyForSleep方法來確保必要的暫停邏輯發(fā)生竟闪;
  3. 設(shè)置變量以允許后續(xù)的恢復(fù)操作离福;
  4. 返回恢復(fù)操作的結(jié)果result;
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mInResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mInResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);

            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
            // end. We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here
            // to ensure any necessary pause logic occurs. In the case where the Activity will be
            // shown regardless of the lock screen, the call to
            // {@link ActivityStackSupervisor#checkReadyForSleepLocked} is skipped.
            final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mInResumeTopActivity = false;
        }

        return result;
    }
  • ActivityStack中的resumeTopActivityInnerLocked()方法

resumeTopActivityInnerLocked()方法是ActivityStack中用于管理和控制Activity狀態(tài)的關(guān)鍵方法炼蛤,作用是恢復(fù)棧頂?shù)腁ctivity實例妖爷,使目標(biāo)Activity進(jìn)入活動狀態(tài),并確保其可見性理朋;

  1. 檢查系統(tǒng)狀態(tài):首先確認(rèn) AMS是否已經(jīng)啟動并準(zhǔn)備好處理 Activity絮识;
  2. 尋找可恢復(fù)的頂部 Activity:查找當(dāng)前任務(wù)棧中下一個最頂層的、非結(jié)束狀態(tài)且可獲得焦點的 Activity 來恢復(fù)嗽上;
  3. 觸發(fā)發(fā)起者 Activity 的暫停過程:在恢復(fù)目標(biāo) Activity 之前次舌,會調(diào)用 startPausingLocked() 方法對當(dāng)前運行的 Activity(發(fā)起者 Activity)觸發(fā) Pause 動作;
  4. 執(zhí)行具體的恢復(fù)邏輯:執(zhí)行 startSpecificActivity()進(jìn)一步處理目標(biāo) Activity 的啟動和恢復(fù)過程兽愤;
 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {

    ...

        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            // 終止當(dāng)前的activity
            pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next);
        }

    ...

        if (next.attachedToProcess()) {

            ...

        }else {
            // Whoops, need to restart this activity!
            if (!next.hasBeenLaunched) {
                next.hasBeenLaunched = true;
            } else {
                if (SHOW_APP_STARTING_PREVIEW) {
                    next.showStartingWindow(null /* prev */, false /* newTask */,
                            false /* taskSwich */);
                }
                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
            }
            if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
            // 重新啟動這個activity
            mStackSupervisor.startSpecificActivity(next, true, true);
        }
  • ActivityStackSupervisor中的startSpecificActivity()方法

startSpecificActivity()方法會判斷Activity對應(yīng)的進(jìn)程是否存在彼念,如果不存在,就會給ActivityManagerService發(fā)送一條創(chuàng)建新進(jìn)程的消息浅萧;

  1. 檢查目標(biāo) Activity 的狀態(tài):如果目標(biāo) Activity 的進(jìn)程已經(jīng)被啟動逐沙,那么會直接調(diào)用 realStartActivityLocked() 方法來恢復(fù)該 Activity;
  2. 啟動新的 Activity:對于尚未啟動的 Activity洼畅,該方法負(fù)責(zé)啟動它吩案,創(chuàng)建新的 Activity 實例,并將其加入到任務(wù)棧中土思;
  3. 如果Activity是當(dāng)前任務(wù)棧的頂部Activity务热,并且需要恢復(fù)(用戶正在與Activity交互),調(diào)用ATMS的startProcessAsync方法異步地啟動目標(biāo)Activity己儒;
    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);

        boolean knownToBeDead = false;
        if (wpc != null && wpc.hasThread()) {
            try {
                realStartActivityLocked(r, wpc, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }

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

        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

        final boolean isTop = andResume && r.isTopRunningActivity();
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }
  • ActivityTaskManagerService中的startProcessAsync()方法

startSpecificActivity()未啟動目標(biāo)Activity所在的進(jìn)程就會走到ATMS中的startProcessAsync()方法崎岂,給AMS發(fā)送一條創(chuàng)建新進(jìn)程的消息,創(chuàng)建目標(biāo)Activity對應(yīng)的進(jìn)程闪湾;

  1. 首先檢查是否啟用了跟蹤標(biāo)簽冲甘,跟蹤操作;
  2. 創(chuàng)建一個消息途样,包含啟動進(jìn)程所需的所有信息江醇,包括進(jìn)程名、應(yīng)用程序信息何暇、是否已知進(jìn)程已經(jīng)死亡陶夜、是否是頂層Activity以及宿主類型等;
  3. 將消息發(fā)送給Handler裆站,由Handler來處理這個消息并啟動進(jìn)程条辟,避免在調(diào)用AMS時可能發(fā)生的死鎖黔夭。
    void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
            String hostingType) {
        try {
            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"
                        + activity.processName);
            }
            // Post message to start process to avoid possible deadlock of calling into AMS with the
            // ATMS lock held.
            final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
                    mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
                    isTop, hostingType, activity.intent.getComponent());
            mH.sendMessage(m);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

然后啟動新Activity的流程就從ATMS走到了AMS中 Activity的創(chuàng)建過程(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市羽嫡,隨后出現(xiàn)的幾起案子本姥,更是在濱河造成了極大的恐慌,老刑警劉巖杭棵,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婚惫,死亡現(xiàn)場離奇詭異,居然都是意外死亡魂爪,警方通過查閱死者的電腦和手機先舷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滓侍,“玉大人密浑,你說我怎么就攤上這事〈志” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵街图,是天一觀的道長浇衬。 經(jīng)常有香客問我,道長餐济,這世上最難降的妖魔是什么耘擂? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮絮姆,結(jié)果婚禮上醉冤,老公的妹妹穿的比我還像新娘。我一直安慰自己篙悯,他們只是感情好蚁阳,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鸽照,像睡著了一般螺捐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上矮燎,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天定血,我揣著相機與錄音,去河邊找鬼诞外。 笑死澜沟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的峡谊。 我是一名探鬼主播茫虽,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼刊苍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了席噩?” 一聲冷哼從身側(cè)響起班缰,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悼枢,沒想到半個月后埠忘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡馒索,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年莹妒,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绰上。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡旨怠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜈块,到底是詐尸還是另有隱情鉴腻,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布百揭,位于F島的核電站爽哎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏器一。R本人自食惡果不足惜课锌,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祈秕。 院中可真熱鬧渺贤,春花似錦、人聲如沸请毛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽方仿。三九已至述雾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兼丰,已是汗流浹背玻孟。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鳍征,地道東北人黍翎。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像艳丛,于是被迫代替她去往敵國和親匣掸。 傳聞我的和親對象是個殘疾皇子趟紊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容