Activity啟動(dòng)流程 上篇(Android 10)

我們知道當(dāng)調(diào)用context.startActivity()的時(shí)候?qū)嶋H上調(diào)用的是contextImpl.startActivity()闻坚,所以本篇從contextImpl.startActivity()開始法绵,一步步說明一個(gè)Activity是如何啟動(dòng)的坛善。由于源碼調(diào)用過程過于復(fù)雜歇式,這里將適當(dāng)略去一些細(xì)節(jié),本篇目的在于在查看源碼過程中做輔助作用逻住,這里推薦使用https://cs.android.com/创葡,其次也可以使用更加完整的https://android.googlesource.com來查看源碼,不過查找和跳轉(zhuǎn)就沒有前者方便了唠叛。其次只嚣,如果在不知道調(diào)用鏈路的時(shí)候,可以在目標(biāo)處拋出異常艺沼,可以利用異巢嵛瑁可以打印堆棧的原理,來查看我們的調(diào)用鏈路障般,這對(duì)查看源碼十分有幫助调鲸。

contextImpl.startActivity()內(nèi)容如下:

    @Override
    public void startActivity(Intent intent, Bundle options) {
        ....
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

這里mMainThread\frameworks\base\core\java\android\app\ActivityThread.javagetInstrumentation()得到的是\frameworks\base\core\java\android\app\Instrumentation.java其對(duì)應(yīng)函數(shù)如下:

    @UnsupportedAppUsage
    public ActivityResult execStartActivity(
        ....
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            //這里調(diào)用了ATMS啟動(dòng)Activity挽荡,而不是我們熟知的AMS藐石,ATMS是android 10新加入的用于管理Activity的輔助類,
            //其Server Name為Context.ACTIVITY_TASK_SERVICE
            int result = ActivityTaskManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

我們直接到\frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java查看對(duì)應(yīng)的函數(shù)定拟,這個(gè)函數(shù)最終會(huì)調(diào)用同文件中的startActivityAsUser()函數(shù)于微,內(nèi)容如下:

    int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        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)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();

    }

getActivityStartController()返回的是\frameworks\base\services\core\java\com\android\server\wm\ActivityStartController.java,其obtainStarter()方法如下:

    ActivityStarter obtainStarter(Intent intent, String reason) {
        return mFactory.obtain().setIntent(intent).setReason(reason);
    }

這里我們不用關(guān)心函數(shù)內(nèi)容,直接看他返回了\frameworks\base\services\core\java\com\android\server\wm\ActivityStarter.java,而上面除了對(duì)ActivityStarter設(shè)置一些參數(shù)角雷,就是調(diào)用了其execute()函數(shù)祸穷,所以我們直接看ActivityStarterexecute()函數(shù):

    int execute() {
        try {
            // TODO(b/64750076): Look into passing request directly to these methods to allow
            // for transactional diffs and preprocessing.
            if (mRequest.mayWait) {
                return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                        mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
                        mRequest.intent, mRequest.resolvedType,
                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                        mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                        mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                        mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                        mRequest.inTask, mRequest.reason,
                        mRequest.allowPendingRemoteAnimationRegistryLookup,
                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
            } else {
                return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                        mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                        mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                        mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                        mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                        mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                        mRequest.outActivity, mRequest.inTask, mRequest.reason,
                        mRequest.allowPendingRemoteAnimationRegistryLookup,
                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
            }
        } finally {
            onExecutionComplete();
        }
    }

這里兩個(gè)函數(shù)差不多,我們直接追蹤startActivity即可勺三,因?yàn)闊o關(guān)代碼比較多雷滚,讀者可以自行追蹤,這里直接給出調(diào)用鏈吗坚,以供參考:
\frameworks\base\services\core\java\com\android\server\wm\ActivityStarter.java中:
startActivity => 幾個(gè)startActivity同名函數(shù) => startActivityUnchecked => mTargetStack.startActivityLocked =>
\frameworks\base\services\core\java\com\android\server\wm\ActivityStack.java中:
=> startActivityLocked => ensureActivitiesVisibleLocked => makeVisibleAndRestartIfNeeded => mStackSupervisor.startSpecificActivityLocked
\frameworks\base\services\core\java\com\android\server\wm\ActivityStackSupervisor.java中:
startSpecificActivityLocked
startSpecificActivityLocked 內(nèi)容如下:

    void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        //相應(yīng)的Activity進(jìn)程是否啟動(dòng)祈远?
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);

        boolean knownToBeDead = false;
        //如果啟動(dòng)了
        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;
        }

        // Suppress transition until the new activity becomes ready, otherwise the keyguard can
        // appear for a short amount of time before the new process with the new activity had the
        // ability to set its showWhenLocked flags.
        if (getKeyguardController().isKeyguardLocked()) {
            r.notifyUnknownVisibilityLaunched();
        }

        try {
            if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
                Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
                        + r.processName);
            }
            // Post message to start process to avoid possible deadlock of calling into AMS with the
            // ATMS lock held.
            //如果沒有啟動(dòng)
            final Message msg = PooledLambda.obtainMessage(
                    ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
                    r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
            mService.mH.sendMessage(msg);
        } finally {
            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

可以看到這里對(duì)相應(yīng)的Activity進(jìn)程是否啟動(dòng)做了一次判斷,如果啟動(dòng)了則調(diào)用realStartActivityLocked商源,沒有啟動(dòng)也最終會(huì)調(diào)用這個(gè)函數(shù)车份,所以我們看沒有啟動(dòng)的情況,PooledLambda.obtainMessage()這里不細(xì)看了牡彻,其作用是在handler中運(yùn)行某個(gè)方法扫沼,從參數(shù)可以得知庄吼,應(yīng)該是mService.mAmInternalActivityManagerInternal::startProcess方法缎除,那么這是什么東西呢渐行?讀者感興趣可以自行推斷,這里直接給出結(jié)果,它就是ActivityManagerService.LocalService#startProcess()

        @Override
        public void startProcess(String processName, ApplicationInfo info,
                boolean knownToBeDead, String hostingType, ComponentName hostingName) {
            try {
                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"
                            + processName);
                }
                synchronized (ActivityManagerService.this) {
                    startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
                            new HostingRecord(hostingType, hostingName),
                            false /* allowWhileBooting */, false /* isolated */,
                            true /* keepIfLarge */);
                }
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }

這里又一次調(diào)用了:
startProcessLocked => mProcessList.startProcessLocked
\frameworks\base\services\core\java\com\android\server\am\ProcessList.java中
startProcessLocked => 幾個(gè)startProcessLocked同名函數(shù) => startProcess:

    private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkSlow(startTime, "startProcess: asking zygote to start proc");
            final Process.ProcessStartResult startResult;
            if (hostingRecord.usesWebviewZygote()) {
                startResult = startWebView(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            } else if (hostingRecord.usesAppZygote()) {
                final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
                //調(diào)用Zygote創(chuàng)建新的進(jìn)程
                startResult = appZygote.getProcess().start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, null, app.info.packageName,
                        /*useUsapPool=*/ false,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            } else {
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, app.info.packageName,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            }
            checkSlow(startTime, "startProcess: returned from zygote!");
            return startResult;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

這里執(zhí)行的是appZygote.getProcess().start孽文,appZygote.getProcess()返回的是ChildZygoteProcess驻襟,而ChildZygoteProcess繼承了ZygoteProcessstart方法也是調(diào)用的ZygoteProcessstart方法芋哭,start調(diào)用了startViaZygote方法:

private Process.ProcessStartResult startViaZygote(....) throws ZygoteStartFailedEx {
        ....

        synchronized(mLock) {
            // The USAP pool can not be used if the application will not use the systems graphics
            // driver.  If that driver is requested use the Zygote application start path.
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                              useUsapPool,
                                              argsForZygote);
        }
    }

這里首先來看openZygoteSocketIfNeeded(abi):

    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        try {
            attemptConnectionToPrimaryZygote();

            if (primaryZygoteState.matches(abi)) {
                return primaryZygoteState;
            }

            if (mZygoteSecondarySocketAddress != null) {
                // The primary zygote didn't match. Try the secondary.
                attemptConnectionToSecondaryZygote();

                if (secondaryZygoteState.matches(abi)) {
                    return secondaryZygoteState;
                }
            }
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
        }

        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

可以看到該函數(shù)調(diào)用了attemptConnectionToPrimaryZygoteattemptConnectionToSecondaryZygote()這其實(shí)和Zygote()運(yùn)行的位數(shù)有關(guān)沉衣,32或者64位,他們都調(diào)用了ZygoteState.connect减牺,只是傳入的參數(shù)不同豌习,我們選擇看attemptConnectionToPrimaryZygote:

    private void attemptConnectionToPrimaryZygote() throws IOException {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            primaryZygoteState =
                    ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);

            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
            maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
            maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState);
        }
    }

然后看ZygoteState.connect:

        static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
                @Nullable LocalSocketAddress usapSocketAddress)
                throws IOException {

            DataInputStream zygoteInputStream;
            BufferedWriter zygoteOutputWriter;
            final LocalSocket zygoteSessionSocket = new LocalSocket();

            if (zygoteSocketAddress == null) {
                throw new IllegalArgumentException("zygoteSocketAddress can't be null");
            }

            try {
                zygoteSessionSocket.connect(zygoteSocketAddress);
                zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
                zygoteOutputWriter =
                        new BufferedWriter(
                                new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
                                Zygote.SOCKET_BUFFER_SIZE);
            } catch (IOException ex) {
                try {
                    zygoteSessionSocket.close();
                } catch (IOException ignore) { }

                throw ex;
            }

            return new ZygoteState(zygoteSocketAddress, usapSocketAddress,
                                   zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
                                   getAbiList(zygoteOutputWriter, zygoteInputStream));
        }

這段代碼比較好理解存谎,就是創(chuàng)建一個(gè)LocalSocketZygote建立連接,并獲取輸入輸出流設(shè)置到ZygoteState中肥隆,待會(huì)兒我們們會(huì)用到既荚,至此openZygoteSocketIfNeeded(abi)調(diào)用完成,回到上面的startViaZygote栋艳,代碼繼續(xù)調(diào)用了:

    private Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, boolean useUsapPool, @NonNull ArrayList<String> args)
            throws ZygoteStartFailedEx {
        ....
        if (useUsapPool && mUsapPoolEnabled && canAttemptUsap(args)) {
            try {
                return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
            } catch (IOException ex) {
                // If there was an IOException using the USAP pool we will log the error and
                // attempt to start the process through the Zygote.
                Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
                        + ex.getMessage());
            }
        }

        return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
    }

這段代碼意思是恰聘,如果使用UASP,就調(diào)用attemptUsapSendArgsAndGetResult吸占,否則調(diào)用attemptUsapSendArgsAndGetResult晴叨,Android Q(10)開始,Google引入了一種新的機(jī)制:USAP(Unspecialized App Process)矾屯,詳細(xì)內(nèi)容請(qǐng)看:Android Framework | 一種新型的應(yīng)用啟動(dòng)機(jī)制:USAP兼蕊,也可以看我的另一篇文章Android UASP進(jìn)程的啟動(dòng),該篇對(duì)UASP進(jìn)程的啟動(dòng)進(jìn)行了詳細(xì)說明件蚕,同時(shí)也解釋了調(diào)用attemptUsapSendArgsAndGetResult的情況孙技,這里我們還是看attemptUsapSendArgsAndGetResult,沒有使用USAP的情況:

    private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
            ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
        try {
            final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
            final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;

            zygoteWriter.write(msgStr);
            zygoteWriter.flush();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            Process.ProcessStartResult result = new Process.ProcessStartResult();
            result.pid = zygoteInputStream.readInt();
            result.usingWrapper = zygoteInputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }

            return result;
        } catch (IOException ex) {
            zygoteState.close();
            Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                    + ex.toString());
            throw new ZygoteStartFailedEx(ex);
        }
    }

這里可以看到骤坐,我們?nèi)〕錾厦鎸懭?code>zygoteState的輸入輸出流绪杏,向其中寫入?yún)?shù),并獲取zygote傳回來的創(chuàng)建的進(jìn)程pid值纽绍,至此ActivityManagerService中的工作就完成了,接下來需要到zygote看看是如何創(chuàng)建新的進(jìn)程的了势似。

Android系統(tǒng)啟動(dòng)流程末尾拌夏,我們說到Zygote進(jìn)程會(huì)執(zhí)行zygoteServer.runSelectLoop(abiList),接收并處理AMS傳過來的消息履因,比如fork app進(jìn)程障簿。這里我們直接看runSelectLoop函數(shù)即可:

Runnable runSelectLoop(String abiList) {
       while (true) {
            ....
            try {
                Os.poll(pollFDs, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            ....
                ....
                        ZygoteConnection connection = peers.get(pollIndex);
                        final Runnable command = connection.processOneCommand(this);

       }
}

這里runSelectLoop會(huì)使用epoll機(jī)制,阻塞在Os.poll(pollFDs, -1)栅迄,獲取對(duì)方連接請(qǐng)求后站故,執(zhí)行\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.javaprocessOneCommand方法:

    Runnable processOneCommand(ZygoteServer zygoteServer) {

        ....

        pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
                parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);

        try {
            if (pid == 0) {
                // in child
                zygoteServer.setForkChild();

                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;

                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.mStartChildZygote);
            } else {
                // In the parent. A pid < 0 indicates a failure and will be handled in
                // handleParentProc.
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                handleParentProc(pid, descriptors, serverPipeFd);
                return null;
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

這里fork出進(jìn)程后在子進(jìn)程執(zhí)行了handleChildProc => ZygoteInit.ZygoteInit:

    public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        //開啟線程池
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }
    protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        // If the application calls System.exit(), terminate the process
        // immediately without running any shutdown hooks.  It is not possible to
        // shutdown an Android application gracefully.  Among other things, the
        // Android runtime shutdown hooks close the Binder driver, which can cause
        // leftover running threads to crash before the process actually exits.
        nativeSetExitWithoutCleanup(true);

        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        final Arguments args = new Arguments(argv);

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        ////返回可以執(zhí)行ActivityThread的main函數(shù)的Runable
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

這里findStaticMain其實(shí)就是利用反射機(jī)制將ActivityThread的main方法打包成Runnable,這個(gè)Runnable將會(huì)在新的進(jìn)程中運(yùn)行起來毅舆,ActivityThread的main也就是我們熟知的App進(jìn)程開始的地方西篓。在下篇,我們將詳細(xì)了解ActivityThread的main憋活,一直執(zhí)行到Activity的onCreate的過程岂津。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悦即,隨后出現(xiàn)的幾起案子吮成,更是在濱河造成了極大的恐慌橱乱,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粱甫,死亡現(xiàn)場(chǎng)離奇詭異泳叠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)茶宵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門危纫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人节预,你說我怎么就攤上這事叶摄。” “怎么了安拟?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蛤吓,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我糠赦,道長(zhǎng)会傲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任拙泽,我火速辦了婚禮淌山,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘顾瞻。我一直安慰自己泼疑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布荷荤。 她就那樣靜靜地躺著退渗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蕴纳。 梳的紋絲不亂的頭發(fā)上会油,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音古毛,去河邊找鬼翻翩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛稻薇,可吹牛的內(nèi)容都是我干的嫂冻。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼颖低,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼絮吵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起忱屑,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤蹬敲,失蹤者是張志新(化名)和其女友劉穎暇昂,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伴嗡,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡急波,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瘪校。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澄暮。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖阱扬,靈堂內(nèi)的尸體忽然破棺而出泣懊,到底是詐尸還是另有隱情,我是刑警寧澤麻惶,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布馍刮,位于F島的核電站,受9級(jí)特大地震影響窃蹋,放射性物質(zhì)發(fā)生泄漏卡啰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一警没、第九天 我趴在偏房一處隱蔽的房頂上張望匈辱。 院中可真熱鬧,春花似錦杀迹、人聲如沸亡脸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)梗掰。三九已至,卻和暖如春嗅回,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摧茴。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工绵载, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人苛白。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓娃豹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親购裙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懂版,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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