【源碼】app是如何啟動(dòng)的荚板?深入解析android應(yīng)用程序的啟動(dòng)過(guò)程(中)

前言

由上文可知凤壁,在啟動(dòng)了應(yīng)用程序的進(jìn)程后,接下來(lái)跪另,就該啟動(dòng)應(yīng)用程序本身了拧抖,你已經(jīng)知道AMS(Activity Manager Service)是專(zhuān)門(mén)管理Activity的服務(wù),而啟動(dòng)應(yīng)用程序免绿,本質(zhì)上來(lái)說(shuō)唧席,就是啟動(dòng)應(yīng)用程序的第一個(gè)Activity,這個(gè)Activity被稱(chēng)為根Activity嘲驾,所以AMS在本文中依然是主角淌哟。

本文將分為三個(gè)部分介紹,Launcher請(qǐng)求AMS辽故,AMS到ApplicationThread的調(diào)用和ActivityThread 啟動(dòng) Activity徒仓。

Launcher請(qǐng)求AMS過(guò)程

Launcher是一個(gè)進(jìn)程,他在android系統(tǒng)啟動(dòng)后會(huì)發(fā)揮作用——將應(yīng)用程序的快捷圖標(biāo)放到桌面誊垢,就是我們手機(jī)里面的app圖標(biāo)蓬衡,這些圖標(biāo)就是每一個(gè)應(yīng)用程序的入口,也是根Activity的入口彤枢,所以狰晚,要想啟動(dòng)app,就需要管理圖標(biāo)的Launcher去請(qǐng)求管理Activity的AMS

時(shí)序圖如下(mermaid畫(huà)圖更好看哈哈哈)


image.png

當(dāng)點(diǎn)擊桌面圖標(biāo)時(shí)缴啡,會(huì)啟動(dòng)Launcher``的startActivitySafely方法壁晒,如下

public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
    ...
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    ...
    try {
        if (Utilities.ATLEAST_MARSHMALLOW
               ...
        } else if (user == null || user.equals(Process.myUserHandle())) {
            // Could be launching some bookkeeping activity
            startActivity(intent, optsBundle);//10
        } else {
       ...
    return false;
}

在第3行代碼處將Flag設(shè)置為FLAG_ACTIVITY_NEW_TASK,表示啟動(dòng)一個(gè)新的任務(wù)棧业栅,如果你了解Activity的四種啟動(dòng)模式的話(huà)秒咐,應(yīng)該不會(huì)陌生他的作用捡鱼,簡(jiǎn)單說(shuō)蝉衣,就是每個(gè)應(yīng)用程序都有一個(gè)這樣的棧彪腔,當(dāng)打開(kāi)里面的新的Activity的時(shí)候柠贤,就壓入這么一個(gè)Activity,當(dāng)回退的時(shí)候雷滋,就彈出不撑,不過(guò)規(guī)則沒(méi)那么簡(jiǎn)單,有四種模式晤斩,有興趣可以自己搜搜看焕檬。

第10行代碼啟動(dòng)了Activity,而這個(gè)方法在Activity.java中實(shí)現(xiàn)澳泵。

 public void startActivity(Intent intent, @Nullable Bundle options) {
     if (options != null) {
         startActivityForResult(intent, -1, options);
     } else {
         // Note we want to go through this call for compatibility with
         // applications that may have overridden the method.
         startActivityForResult(intent, -1);
     }
 }

startActivity沒(méi)有什么內(nèi)容实愚,就是調(diào)用了startActivityForResult,第二個(gè)參數(shù)名為requestCode兔辅,這里是-1腊敲,表示Launcher不需要知道Activity的啟動(dòng)結(jié)果。

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
           ...

這里進(jìn)入startActivityForResult后维苔,由于根Activity沒(méi)有啟動(dòng)碰辅,也就是mParent==null,將會(huì)讓Instrumentation執(zhí)行execStartActivity方法蕉鸳,Instrumentation的作用是監(jiān)控應(yīng)用程序與系統(tǒng)的交互。

public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, String target,
    Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManager.getService()//9
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target, requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

在第9行處忍法,調(diào)用ActivityManagergetService方法潮尝,獲取到AMS的代理對(duì)象,然后調(diào)用該對(duì)象的startActivity方法饿序,注意這里我們已經(jīng)獲得了AMS勉失。

然后我們看getService做了什么

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}

就調(diào)用了一個(gè)IActivityManagerSingleton的get()方法

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);//6
                return am;
            }
        };

這是一個(gè)單例,在第6行中創(chuàng)建了IActivityManager并返回原探,這段代碼比較陌生乱凿,使用的是AIDL,不過(guò)我們不必深究了咽弦。

小結(jié)1

總而言之徒蟆,這一節(jié)中所有的工作都是為了獲得AMS,將代碼邏輯放到AMS中型型,中間經(jīng)歷了多個(gè)startAcitvity段审,都是為了判定或者架構(gòu)需要,非衬炙猓瑣碎寺枉,我認(rèn)為了解即可

AMS到Application Thread的調(diào)用過(guò)程

現(xiàn)在我們已經(jīng)來(lái)到了熟悉的AMS抑淫,看看他是如何工作的吧

image.png

承接上一節(jié)Launcher請(qǐng)求AMS過(guò)程的最后一步,首先調(diào)用startActivity

public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}

可以看到姥闪,這里返回的是startActivityAsUser方法始苇,就開(kāi)始了我們這一節(jié)的內(nèi)容。

注意到startActivityAsUser比起startActivity多了最后一個(gè)參數(shù)筐喳,UserHandle.getCallingUserId催式,這個(gè)是AMS用來(lái)確定調(diào)用這的權(quán)限的

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
            userId, false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, bOptions, false, userId, null, null,
            "startActivityAsUser");
}

第5行出就是在檢查調(diào)用者權(quán)限,如果沒(méi)有沒(méi)有權(quán)限就會(huì)拋出SecurityException異常疏唾。

然后就是調(diào)用startActivityMayWait方法蓄氧,這個(gè)方法在ActivityStarter中,比起startActivityAsUser槐脏,又多了幾個(gè)參數(shù)喉童,其中最后一個(gè)參數(shù)"startActivityAsUser"表示啟動(dòng)的理由,是從這個(gè)方法中調(diào)用的顿天。

final int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult,
        Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
        IActivityContainer iContainer, TaskRecord inTask, String reason) {
    // Refuse possible leaked file descriptors
    ...
        int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);
    ...
        return res;

ActivityStarter是一個(gè)加載Activity的控制類(lèi)堂氯,回去搜集很多的Intent或者Flags用來(lái)生成Activity,這段代碼的10行調(diào)用了startActivityLocked方法(我真的想吐槽牌废,調(diào)來(lái)調(diào)去的咽白,很容易暈)

int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
        TaskRecord inTask, String reason) {

    if (TextUtils.isEmpty(reason)) {
        throw new IllegalArgumentException("Need to specify a reason.");
    }
    mLastStartReason = reason;
    mLastStartActivityTimeMs = System.currentTimeMillis();
    mLastStartActivityRecord[0] = null;

    mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,//17
            aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
            callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
            options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
            container, inTask);

    if (outActivity != null) {
        // mLastStartActivityRecord[0] is set in the call to startActivity above.
        outActivity[0] = mLastStartActivityRecord[0];
    }
    return mLastStartActivityResult;
}

沒(méi)什么好看的,注意到17行處又調(diào)用了startActivity方法鸟缕,方法如下

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
        TaskRecord 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;
    ProcessRecord callerApp = null;
    if (caller != null) { //14
        callerApp = mService.getRecordForAppLocked(caller);//15
        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;
        }
    }
    ...
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
        callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
        resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
        mSupervisor, container, options, sourceRecord);
    if (outActivity != null) {
        outActivity[0] = r; //32
    }
    ...
    doPendingActivityLaunchesLocked(false);
    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
        options, inTask, outActivity);

第14行處判定caller是否為null晶框,這個(gè)caller是從前面?zhèn)鬟^(guò)來(lái)的,一直都是第一個(gè)參數(shù)懂从,代表的是Launcher所在的應(yīng)用程序的進(jìn)程的ApplicationThread對(duì)象授段,如果為null,那么執(zhí)行15行處的getRecordForAppLocked方法番甩,得到一個(gè)代替Launcher進(jìn)程的callerApp對(duì)象侵贵。

ActivityRecord表示記錄一個(gè)Activity信息的對(duì)象,就像入學(xué)一樣缘薛,在新生報(bào)到前窍育,學(xué)校就應(yīng)該準(zhǔn)備好檔案,寢室宴胧,班級(jí)等等工作漱抓。

在27行處就新建了這個(gè)對(duì)象,然后在32行處將其放在outActivity數(shù)組的第一個(gè)恕齐,我想你應(yīng)該猜到了辽旋,那這個(gè)數(shù)組的其他位置是什么呢?當(dāng)然是除了根Activity之外的其他Activity的記錄信息了。

最后的36行补胚,還是返回了startActivity方法

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity) {
    int result = START_CANCELED;
    try {
        mService.mWindowManager.deferSurfaceLayout();
        result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, outActivity);
    ...
    postStartActivityProcessing(r, result, mSupervisor.getLastStack().mStackId,  mSourceRecord,
            mTargetStack);

    return result;
}

這個(gè)方法沒(méi)什么好看的码耐,就是調(diào)用了一個(gè)startActivityUnchecked方法

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity) {
    ...
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask//6
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        result = setTaskFromReuseOrCreateNewTask( //9
                taskToAffiliate, preferredLaunchStackId, topStack);
    } else if (mSourceRecord != null) {
        result = setTaskFromSourceRecord();
    } else if (mInTask != null) {
        result = setTaskFromInTask();
    } else {
        setTaskToCurrentTopOrCreateNewTask();
    }
    ...
    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                mStartActivity.getTask().topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                && mStartActivity != topTaskActivity)) {
            ...
        } else {
            if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                mTargetStack.moveToFront("startActivityUnchecked");
            }
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,//30
                    mOptions);
        }
    } else {
        mTargetStack.addRecentActivityLocked(mStartActivity);
    }
}

startActivityUnchecked方法主要處理與棧相關(guān)的邏輯,還記得嗎溶其?每一個(gè)應(yīng)用程序都有一個(gè)任務(wù)棧骚腥,Activity的四種啟動(dòng)模式就在這里,在一開(kāi)始的類(lèi)startActivitySafely中瓶逃,我們將Intent的Flag設(shè)置為FLAG_ACTIVITY_NEW_TASK束铭,這樣子,就滿(mǎn)足了第6行代碼處的if判斷厢绝,在第9行處契沫,就會(huì)創(chuàng)建新的TaskRecord

現(xiàn)在所有東西準(zhǔn)備齊全昔汉,在第30行處調(diào)用resumeFocusedStackTopActivityLocked方法懈万,我們?nèi)タ纯窗?/p>

 boolean resumeFocusedStackTopActivityLocked(
         ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
     if (targetStack != null && isFocusedStack(targetStack)) {
         return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
     }
     final ActivityRecord r = mFocusedStack.topRunningActivityLocked();//6
     if (r == null || r.state != RESUMED) {//7
         mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
     } else if (r.state == RESUMED) {
         // Kick off any lingering app transitions form the MoveTaskToFront operation.
         mFocusedStack.executeAppTransition(targetOptions);
     }
     return false;
 }

在第6行處調(diào)用的topRunningActivityLocked方法可以獲取要啟動(dòng)的Acitvity所在棧棧頂不是處于停止?fàn)顟B(tài)ActivityRecord(修飾詞很多,慢慢讀)靶病,第7行会通,如果為null,或者要啟動(dòng)的Acitvity狀態(tài)不是RESUMED娄周,就會(huì)調(diào)用resumeTopActivityUncheckedLocked方法涕侈,當(dāng)然,對(duì)于即將啟動(dòng)的Activity煤辨,滿(mǎn)足上述條件裳涛,進(jìn)入resumeTopActivityUncheckedLocked方法。

oolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
   if (mStackSupervisor.inResumeTopActivity) {
       // Don't even start recursing.
       return false;
   }

   boolean result = false;
   try {
       // Protect against recursion.
       mStackSupervisor.inResumeTopActivity = true;
       result = resumeTopActivityInnerLocked(prev, options);
   } finally {
       mStackSupervisor.inResumeTopActivity = false;
   }
   mStackSupervisor.checkReadyForSleepLocked();
   return result;

沒(méi)有什么東西众辨,進(jìn)入resumeTopActivityInnerLocked方法

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        ...   
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
        ...
    }

代碼很多端三,但是我們不關(guān)心,只看調(diào)用的startSpecificActivityLocked方法

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,//4
            r.info.applicationInfo.uid, true);

    r.getStack().setLaunchTime(r);

    if (app != null && app.thread != null) {//9
        try {
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                    || !"android".equals(r.info.packageName)) {
               
                app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                        mService.mProcessStats);
            }
            realStartActivityLocked(r, app, andResume, checkConfig);//16
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }
    }
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

在第4行處泻轰,獲得即將啟動(dòng)的Activity所在的應(yīng)用程序進(jìn)程技肩,也就是我們?cè)谏掀恼轮械闹鹘乔夜欤诘?行處判斷如果這個(gè)進(jìn)程已經(jīng)運(yùn)行了浮声,就會(huì)調(diào)用了16行處的realStartActivityLocked方法。

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
    ...
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
        System.identityHashCode(r), r.info,
        mergedConfiguration.getGlobalConfiguration(),
        mergedConfiguration.getOverrideConfiguration(), r.compat,
        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
        r.persistentState, results, newIntents, !andResume,
        mService.isNextTransitionForward(), profilerInfo);
    ...
    return true;

在這里的app.thread就是ActivityThread的內(nèi)部類(lèi)旋奢,app表示傳入這個(gè)應(yīng)用程序的進(jìn)程泳挥。

所以這段代碼的意思就是,在應(yīng)用程序的進(jìn)程中至朗,也就是ActivityThread中屉符,啟動(dòng)Activity。

小結(jié)2

上面代碼的核心,就是要把邏輯從AMS中移動(dòng)到應(yīng)用程序的進(jìn)程當(dāng)中矗钟,然后準(zhǔn)備在應(yīng)用程序的進(jìn)程中啟動(dòng)Activity唆香。

ActivityThread啟動(dòng)Acitvity的過(guò)程

歷經(jīng)千山萬(wàn)水,我們總算是要啟動(dòng)Activity了(我好餓啊……)吨艇,下次再繼續(xù)嘻嘻

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躬它,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子东涡,更是在濱河造成了極大的恐慌冯吓,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疮跑,死亡現(xiàn)場(chǎng)離奇詭異组贺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)祖娘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)失尖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人贿条,你說(shuō)我怎么就攤上這事雹仿。” “怎么了整以?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵胧辽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我公黑,道長(zhǎng)邑商,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任凡蚜,我火速辦了婚禮人断,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朝蜘。我一直安慰自己恶迈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布谱醇。 她就那樣靜靜地躺著暇仲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪副渴。 梳的紋絲不亂的頭發(fā)上奈附,一...
    開(kāi)封第一講書(shū)人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音煮剧,去河邊找鬼斥滤。 笑死将鸵,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的佑颇。 我是一名探鬼主播顶掉,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼挑胸!你這毒婦竟也來(lái)了一喘?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嗜暴,失蹤者是張志新(化名)和其女友劉穎凸克,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體闷沥,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萎战,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舆逃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚂维。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖路狮,靈堂內(nèi)的尸體忽然破棺而出虫啥,到底是詐尸還是另有隱情,我是刑警寧澤奄妨,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布涂籽,位于F島的核電站,受9級(jí)特大地震影響砸抛,放射性物質(zhì)發(fā)生泄漏评雌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一直焙、第九天 我趴在偏房一處隱蔽的房頂上張望景东。 院中可真熱鬧,春花似錦奔誓、人聲如沸斤吐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)和措。三九已至,卻和暖如春杯聚,著一層夾襖步出監(jiān)牢的瞬間臼婆,已是汗流浹背抒痒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工幌绍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓傀广,卻偏偏與公主長(zhǎng)得像颁独,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伪冰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348