AndroidU 進程進階篇-OomAdjuster(2/2)

本篇主要分三部分

  1. oomadj的計算時機
  2. oomadj的計算過程
  3. oomadj計算結果應用

一 架構圖

架構圖

二 流程圖

三 常用命令

  • adb shell dumpsys meminfo com.google.android.apps.maps -d
  • cat /proc/meminfo

四 源碼解析

4.1oomadj的更新范圍

oomadj的更新分為兩部分

  • 指定proc更新oomadj
  • 更新全部進程的oomadj
    @GuardedBy("this")
    final void updateOomAdjLocked(@OomAdjReason int oomAdjReason) {
        mOomAdjuster.updateOomAdjLocked(oomAdjReason);
    }

    /**
     * Update OomAdj for a specific process and its reachable processes.
     *
     * @param app The process to update
     * @param oomAdjReason
     * @return whether updateOomAdjLocked(app) was successful.
     */
    @GuardedBy("this")
    final boolean updateOomAdjLocked(ProcessRecord app, @OomAdjReason int oomAdjReason) {
        return mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);
    }

ams提供兩個api方法以供調(diào)用,參數(shù)含有proc則指定更新進程踏揣,否則更新全部進程气筋。

4.2 oomadj的更新過程漓摩。

冷啟動一個activity進程秉颗,觀察其oomadj的變化煎楣。

4.2.1 AMS-attachApplicationLocked]

            app.mState.setCurAdj(ProcessList.INVALID_ADJ);
            app.mState.setSetAdj(ProcessList.INVALID_ADJ);
            app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);
            mOomAdjuster.setAttachingSchedGroupLSP(app);
            app.mState.setForcingToImportant(null);
            clearProcessForegroundLocked(app);
            app.mState.setHasShownUi(false);
            app.mState.setCached(false);

在應用進程啟動后綁定AMS時,adj是默認的-10000隔显。 是否cached進程設置為false崎溃。

4.2.2 ActivityTaskSupervisor-realStartActivityLocked

        // Perform OOM scoring after the activity state is set, so the process can be updated with
        // the latest state.
        proc.onStartActivity(mService.mTopProcessState, r.info);

realStartActivityLocked ->
WindowProcessController.onStartActivity->
ProcessRecord.onStartActivity->
ProcessRecord.updateProcessInfo->
AMS.updateOomAdjLocked(this, OOM_ADJ_REASON_ACTIVITY);
mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);

4.2.3 OomAdjuster.updateOomAdjLocked

    /**
     * Update OomAdj for specific process and its reachable processes (with direction/indirect
     * bindings from this process); Note its clients' proc state won't be re-evaluated if this proc
     * is hosting any service/content provider.
     *
     * @param app The process to update, or null to update all processes
     * @param oomAdjReason
     */
    @GuardedBy("mService")
    boolean updateOomAdjLocked(ProcessRecord app, @OomAdjReason int oomAdjReason) {
        synchronized (mProcLock) {
            return updateOomAdjLSP(app, oomAdjReason);
        }
    }

更新指定進程的adj并且將它client端的oomadj也進行更新蜻直。

    @GuardedBy({"mService", "mProcLock"})
    private boolean updateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
        if (app == null || !mConstants.OOMADJ_UPDATE_QUICK) {
            updateOomAdjLSP(oomAdjReason);
            return true;
        }
//如果正在更新oomadj那么退出。
        if (checkAndEnqueueOomAdjTargetLocked(app)) {
            // Simply return true as there is an oomAdjUpdate ongoing
            return true;
        }

        try {
//正在更新oomadj
            mOomAdjUpdateOngoing = true;
//執(zhí)行更新oomadj
            return performUpdateOomAdjLSP(app, oomAdjReason);
        } finally {
            // Kick off the handling of any pending targets enqueued during the above update
            mOomAdjUpdateOngoing = false;
            updateOomAdjPendingTargetsLocked(oomAdjReason);
        }
    }

【performUpdateOomAdjLSP】

    @GuardedBy({"mService", "mProcLock"})
    private boolean performUpdateOomAdjLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
//從ams拿到topApp。
        final ProcessRecord topApp = mService.getTopApp();
//開始抓trace
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
        mService.mOomAdjProfiler.oomAdjStarted();
        mAdjSeq++;

        // Firstly, try to see if the importance of itself gets changed
        final ProcessStateRecord state = app.mState;
        final boolean wasCached = state.isCached();
        final int oldAdj = state.getCurRawAdj();
//新啟動的proc概而,adj開始在ams被賦值INVALID_ADJ -10000.這個理給他賦值UNKNOWN_ADJ
        final int cachedAdj = oldAdj >= CACHED_APP_MIN_ADJ
                ? oldAdj : UNKNOWN_ADJ;

//...省略
        boolean success = performUpdateOomAdjLSP(app, cachedAdj, topApp,
                SystemClock.uptimeMillis(), oomAdjReason);

【performUpdateOomAdjLSP】

    private boolean performUpdateOomAdjLSP(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, long now, @OomAdjReason int oomAdjReason) {
        if (app.getThread() == null) {
            return false;
        }
// ...省略
        computeOomAdjLSP(app, cachedAdj, topApp, false, now, false, true);
//呼巷。。赎瑰。省略
        return applyOomAdjLSP(app, false, now, SystemClock.elapsedRealtime(), oomAdjReason);

4.2.4 計算oomadj-computeOomAdjLSP

【computeOomAdjLSP】
這個函數(shù)是真正為proc計算oomadj的函數(shù)王悍。

    @GuardedBy({"mService", "mProcLock"})
    private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {
        final ProcessStateRecord state = app.mState;
//。餐曼。压储。省略
//1.如果進程是為啟動activity,則會走這里
        if (app == topApp && PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP) {
            // The last app on the list is the foreground app.
            adj = FOREGROUND_APP_ADJ;
            if (mService.mAtmInternal.useTopSchedGroupForTopProcess()) {
                schedGroup = SCHED_GROUP_TOP_APP;
                state.setAdjType("top-activity");
            } else {
                // Demote the scheduling group to avoid CPU contention if there is another more
                // important process which also uses top-app, such as if SystemUI is animating.
                schedGroup = SCHED_GROUP_DEFAULT;
                state.setAdjType("intermediate-top-activity");
            }
            foregroundActivities = true;
            hasVisibleActivities = true;
            procState = PROCESS_STATE_TOP;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
            }
//是否正在運行動畫
        } else if (state.isRunningRemoteAnimation()) {
            adj = VISIBLE_APP_ADJ;
            schedGroup = SCHED_GROUP_TOP_APP;
            state.setAdjType("running-remote-anim");
            procState = PROCESS_STATE_CUR_TOP;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
            }
//是否正在做測試
        } else if (app.getActiveInstrumentation() != null) {
            // Don't want to kill running instrumentation.
            adj = FOREGROUND_APP_ADJ;
            schedGroup = SCHED_GROUP_DEFAULT;
            state.setAdjType("instrumentation");
            procState = PROCESS_STATE_FOREGROUND_SERVICE;
            capability |= PROCESS_CAPABILITY_BFSL;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
            }
//是否啟動進程接收廣播
        } else if (state.getCachedIsReceivingBroadcast(mTmpSchedGroup)) {
            // An app that is currently receiving a broadcast also
            // counts as being in the foreground for OOM killer purposes.
            // It's placed in a sched group based on the nature of the
            // broadcast as reflected by which queue it's active in.
            adj = FOREGROUND_APP_ADJ;
            schedGroup = mTmpSchedGroup[0];
            state.setAdjType("broadcast");
            procState = ActivityManager.PROCESS_STATE_RECEIVER;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making broadcast: " + app);
            }
//是否啟動進程執(zhí)行service
        } else if (psr.numberOfExecutingServices() > 0) {
            // An app that is currently executing a service callback also
            // counts as being in the foreground.
            adj = FOREGROUND_APP_ADJ;
            schedGroup = psr.shouldExecServicesFg()
                    ? SCHED_GROUP_DEFAULT : SCHED_GROUP_BACKGROUND;
            state.setAdjType("exec-service");
            procState = PROCESS_STATE_SERVICE;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making exec-service: " + app);
            }
//是否進程是前臺進程
        } else if (app == topApp) {
            adj = FOREGROUND_APP_ADJ;
            schedGroup = SCHED_GROUP_BACKGROUND;
            state.setAdjType("top-sleeping");
            foregroundActivities = true;
            procState = PROCESS_STATE_CUR_TOP;
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top (sleeping): " + app);
            }
//啟動了一個空進程
        } else {
            // As far as we know the process is empty.  We may change our mind later.
            schedGroup = SCHED_GROUP_BACKGROUND;
            // At this point we don't actually know the adjustment.  Use the cached adj
            // value that the caller wants us to.
            adj = cachedAdj;
            procState = PROCESS_STATE_CACHED_EMPTY;
            if (!state.containsCycle()) {
                state.setCached(true);
                state.setEmpty(true);
                state.setAdjType("cch-empty");
            }
            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making empty: " + app);
            }
        }
//源譬。集惋。。省略
//踩娘。刮刑。。 為此進程相關的綁定進程提權
        // Do final modification to adj.  Everything we do between here and applying
        // the final setAdj must be done in this function, because we will also use
        // it when computing the final cached adj later.  Note that we don't need to
        // worry about this for max adj above, since max adj will always be used to
        // keep it out of the cached vaues.
        state.setCurAdj(adj);
        state.setCurCapability(capability);
        state.setCurrentSchedulingGroup(schedGroup);
        state.setCurProcState(procState);
        state.setCurRawProcState(procState);
        state.updateLastInvisibleTime(hasVisibleActivities);
        state.setHasForegroundActivities(foregroundActivities);
        state.setCompletedAdjSeq(mAdjSeq);
        state.setCurBoundByNonBgRestrictedApp(boundByNonBgRestricted);

        // if curAdj or curProcState improved, then this process was promoted
// 如果此進程的adj提高了霸饲,返回true为朋。
        return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
                || state.getCurCapability() != prevCapability;

這里我們啟動的是activity進程,因此會為進程賦值以下數(shù)據(jù)

  • adj = FOREGROUND_APP_ADJ厚脉;
  • schedGroup = SCHED_GROUP_TOP_APP;
  • state.setAdjType("top-activity");
  • procState = PROCESS_STATE_TOP;

4.2.5 applyOomAdjLSP

通過computeOomAdjLSP為proc經(jīng)確計算了adj和綁定到它之上組件的proc adj习寸。這個函數(shù)

ProcessList

OOM adjustments for processes in various states:

    // OOM adjustments for processes in various states:

    // Uninitialized value for any major or minor adj fields
    public static final int INVALID_ADJ = -10000;

    // Adjustment used in certain places where we don't know it yet.
    // (Generally this is something that is going to be cached, but we
    // don't know the exact value in the cached range to assign yet.)
    public static final int UNKNOWN_ADJ = 1001;

    // This is a process only hosting activities that are not visible,
    // so it can be killed without any disruption.
    public static final int CACHED_APP_MAX_ADJ = 999;
    public static final int CACHED_APP_MIN_ADJ = 900;

    // This is the oom_adj level that we allow to die first. This cannot be equal to
    // CACHED_APP_MAX_ADJ unless processes are actively being assigned an oom_score_adj of
    // CACHED_APP_MAX_ADJ.
    public static final int CACHED_APP_LMK_FIRST_ADJ = 950;

    // Number of levels we have available for different service connection group importance
    // levels.
    static final int CACHED_APP_IMPORTANCE_LEVELS = 5;

    // The B list of SERVICE_ADJ -- these are the old and decrepit
    // services that aren't as shiny and interesting as the ones in the A list.
    public static final int SERVICE_B_ADJ = 800;

    // This is the process of the previous application that the user was in.
    // This process is kept above other things, because it is very common to
    // switch back to the previous app.  This is important both for recent
    // task switch (toggling between the two top recent apps) as well as normal
    // UI flow such as clicking on a URI in the e-mail app to view in the browser,
    // and then pressing back to return to e-mail.
    public static final int PREVIOUS_APP_ADJ = 700;

    // This is a process holding the home application -- we want to try
    // avoiding killing it, even if it would normally be in the background,
    // because the user interacts with it so much.
    public static final int HOME_APP_ADJ = 600;

    // This is a process holding an application service -- killing it will not
    // have much of an impact as far as the user is concerned.
    public static final int SERVICE_ADJ = 500;

    // This is a process with a heavy-weight application.  It is in the
    // background, but we want to try to avoid killing it.  Value set in
    // system/rootdir/init.rc on startup.
    public static final int HEAVY_WEIGHT_APP_ADJ = 400;

    // This is a process currently hosting a backup operation.  Killing it
    // is not entirely fatal but is generally a bad idea.
    public static final int BACKUP_APP_ADJ = 300;

    // This is a process bound by the system (or other app) that's more important than services but
    // not so perceptible that it affects the user immediately if killed.
    public static final int PERCEPTIBLE_LOW_APP_ADJ = 250;

    // This is a process hosting services that are not perceptible to the user but the
    // client (system) binding to it requested to treat it as if it is perceptible and avoid killing
    // it if possible.
    public static final int PERCEPTIBLE_MEDIUM_APP_ADJ = 225;

    // This is a process only hosting components that are perceptible to the
    // user, and we really want to avoid killing them, but they are not
    // immediately visible. An example is background music playback.
    public static final int PERCEPTIBLE_APP_ADJ = 200;

    // This is a process only hosting activities that are visible to the
    // user, so we'd prefer they don't disappear.
    public static final int VISIBLE_APP_ADJ = 100;
    static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;

    // This is a process that was recently TOP and moved to FGS. Continue to treat it almost
    // like a foreground app for a while.
    // @see TOP_TO_FGS_GRACE_PERIOD
    public static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;

    // This is the process running the current foreground app.  We'd really
    // rather not kill it!
    public static final int FOREGROUND_APP_ADJ = 0;

    // This is a process that the system or a persistent process has bound to,
    // and indicated it is important.
    public static final int PERSISTENT_SERVICE_ADJ = -700;

    // This is a system persistent process, such as telephony.  Definitely
    // don't want to kill it, but doing so is not completely fatal.
    public static final int PERSISTENT_PROC_ADJ = -800;

    // The system process runs at the default adjustment.
    public static final int SYSTEM_ADJ = -900;

    // Special code for native processes that are not being managed by the system (so
    // don't have an oom adj assigned by the system).
    public static final int NATIVE_ADJ = -1000;

    // Memory pages are 4K.
    static final int PAGE_SIZE = 4 * 1024;

    // Activity manager's version of an undefined schedule group
    static final int SCHED_GROUP_UNDEFINED = Integer.MIN_VALUE;
    // Activity manager's version of Process.THREAD_GROUP_BACKGROUND
    static final int SCHED_GROUP_BACKGROUND = 0;
      // Activity manager's version of Process.THREAD_GROUP_RESTRICTED
    static final int SCHED_GROUP_RESTRICTED = 1;
    // Activity manager's version of Process.THREAD_GROUP_DEFAULT
    static final int SCHED_GROUP_DEFAULT = 2;
    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
    public static final int SCHED_GROUP_TOP_APP = 3;
    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
    // Disambiguate between actual top app and processes bound to the top app
    static final int SCHED_GROUP_TOP_APP_BOUND = 4;

Process

Keep in sync with SP_* constants of enum type SchedPolicy
declared in system/core/include/cutils/sched_policy.h,
except THREAD_GROUP_DEFAULT does not correspond to any SP_* value.

    /**
     * Default thread group -
     * has meaning with setProcessGroup() only, cannot be used with setThreadGroup().
     * When used with setProcessGroup(), the group of each thread in the process
     * is conditionally changed based on that thread's current priority, as follows:
     * threads with priority numerically less than THREAD_PRIORITY_BACKGROUND
     * are moved to foreground thread group.  All other threads are left unchanged.
     * @hide
     */
    public static final int THREAD_GROUP_DEFAULT = -1;

    /**
     * Background thread group - All threads in
     * this group are scheduled with a reduced share of the CPU.
     * Value is same as constant SP_BACKGROUND of enum SchedPolicy.
     * @hide
     */
    public static final int THREAD_GROUP_BACKGROUND = 0;

    /**
     * Foreground thread group - All threads in
     * this group are scheduled with a normal share of the CPU.
     * Value is same as constant SP_FOREGROUND of enum SchedPolicy.
     * Not used at this level.
     * @hide
     **/
    private static final int THREAD_GROUP_FOREGROUND = 1;

    /**
     * System thread group.
     * @hide
     **/
    public static final int THREAD_GROUP_SYSTEM = 2;

    /**
     * Application audio thread group.
     * @hide
     **/
    public static final int THREAD_GROUP_AUDIO_APP = 3;

    /**
     * System audio thread group.
     * @hide
     **/
    public static final int THREAD_GROUP_AUDIO_SYS = 4;

    /**
     * Thread group for top foreground app.
     * @hide
     **/
    public static final int THREAD_GROUP_TOP_APP = 5;

    /**
     * Thread group for RT app.
     * @hide
     **/
    public static final int THREAD_GROUP_RT_APP = 6;

    /**
     * Thread group for bound foreground services that should
     * have additional CPU restrictions during screen off
     * @hide
     **/
    public static final int THREAD_GROUP_RESTRICTED = 7;

為ams開啟的線程設置進程組和cpust

        // bind background threads to little cores
        // this is expected to fail inside of framework tests because apps can't touch cpusets directly
        // make sure we've already adjusted system_server's internal view of itself first
        updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT);
        try {
            Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
                    Process.THREAD_GROUP_SYSTEM);
            Process.setThreadGroupAndCpuset(
                    mOomAdjuster.mCachedAppOptimizer.mCachedAppOptimizerThread.getThreadId(),
                    Process.THREAD_GROUP_SYSTEM);
        } catch (Exception e) {
            Slog.w(TAG, "Setting background thread cpuset failed");
        }

將后臺線程綁定到小核上。例如UIThread則會綁定到大核上傻工,如下:

[UIThread.java]
    @Override
    public void run() {
        // Make sure UiThread is in the fg stune boost group
        Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
        super.run();
    }

ProcessRecord


    /**
     * Profiling info of the process, such as PSS, cpu, etc.
     */
    final ProcessProfileRecord mProfile;

    /**
     * All about the services in this process.
     */
    final ProcessServiceRecord mServices;

    /**
     * All about the providers in this process.
     */
    final ProcessProviderRecord mProviders;

    /**
     * All about the receivers in this process.
     */
    final ProcessReceiverRecord mReceivers;

    /**
     * All about the error state(crash, ANR) in this process.
     */
    final ProcessErrorStateRecord mErrorState;

    /**
     * All about the process state info (proc state, oom adj score) in this process.
     */
    final ProcessStateRecord mState;

ProcessProfileRecord :Profiling info of the process, such as PSS, cpu, etc.
ProcessStateRecord 用于記錄oom adj score霞溪。

AppProfiler

/**
 * A helper class taking care of the profiling, memory and cpu sampling of apps
 */
public class AppProfiler {

cpuSet介紹

根據(jù)我搜索到的結果,cpuset 是 Linux cgroup 子系統(tǒng)的一部分中捆,它可以為 cgroup 任務分配單獨的 CPU 和內(nèi)存1鸯匹。Android 系統(tǒng)使用 cpuset 來控制不同優(yōu)先級的應用可以使用的 CPU 范圍,以保證更好的交互響應和性能23泄伪。cpuset 的設置和操作是通過 cgroup 抽象層和任務配置文件來實現(xiàn)的殴蓬,這些文件可以在 Android 10 及更高版本中自定義12。cpuset 的名稱和屬性可以在 cgroups.json 文件和 task_profiles.json 文件中查看12蟋滴。例如染厅,Android 系統(tǒng)中有以下幾種 cpuset:

你可以參考這篇文章來了解更多關于 Android/Linux EAS 優(yōu)化的知識须教。

<cib-overlay></cib-overlay>

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市斩芭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乐疆,老刑警劉巖划乖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挤土,居然都是意外死亡琴庵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門仰美,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迷殿,“玉大人,你說我怎么就攤上這事咖杂∏焖拢” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵诉字,是天一觀的道長懦尝。 經(jīng)常有香客問我,道長壤圃,這世上最難降的妖魔是什么陵霉? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮伍绳,結果婚禮上踊挠,老公的妹妹穿的比我還像新娘。我一直安慰自己冲杀,他們只是感情好效床,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著漠趁,像睡著了一般扁凛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闯传,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天谨朝,我揣著相機與錄音卤妒,去河邊找鬼。 笑死字币,一個胖子當著我的面吹牛则披,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洗出,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼士复,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翩活?” 一聲冷哼從身側響起阱洪,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎菠镇,沒想到半個月后冗荸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡利耍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年蚌本,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片隘梨。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡程癌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出轴猎,到底是詐尸還是另有隱情嵌莉,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布税稼,位于F島的核電站烦秩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏郎仆。R本人自食惡果不足惜只祠,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扰肌。 院中可真熱鬧抛寝,春花似錦、人聲如沸曙旭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桂躏。三九已至钻趋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剂习,已是汗流浹背蛮位。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工较沪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人失仁。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓尸曼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萄焦。 傳聞我的和親對象是個殘疾皇子控轿,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

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