Android解析WindowManagerService(二)WMS的重要成員和Window的添加過(guò)程

相關(guān)文章
Android系統(tǒng)啟動(dòng)系列
Android深入四大組件系列
Android應(yīng)用進(jìn)程啟動(dòng)過(guò)程系列
Android解析WindowManager系列

前言

在本系列的上一篇文章中靠抑,我們學(xué)習(xí)了WMS的誕生笆包,WMS被創(chuàng)建后牺汤,它的重要的成員有哪些?Window添加過(guò)程的WMS部分做了什么呢埂软?這篇文章會(huì)給你解答。

1.WMS的重要成員

所謂WMS的重要成員是指WMS中的重要的成員變量撵摆,如下所示伯顶。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    final WindowManagerPolicy mPolicy;
    final IActivityManager mActivityManager;
    final ActivityManagerInternal mAmInternal;
    final AppOpsManager mAppOps;
    final DisplaySettings mDisplaySettings;
    ...
    final ArraySet<Session> mSessions = new ArraySet<>();
    final WindowHashMap mWindowMap = new WindowHashMap();
    final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
    final ArrayList<AppWindowToken> mFinishedEarlyAnim = new ArrayList<>();
    final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>();
    final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
    final ArrayList<WindowState> mPendingRemove = new ArrayList<>();
    WindowState[] mPendingRemoveTmp = new WindowState[20];
    final ArrayList<WindowState> mDestroySurface = new ArrayList<>();
    final ArrayList<WindowState> mDestroyPreservedSurface = new ArrayList<>();
    ...
    final H mH = new H();
    ...
    final WindowAnimator mAnimator;
    ...
     final InputManagerService mInputManager

這里列出了WMS的部分成員變量碍粥,下面分別對(duì)它們進(jìn)行簡(jiǎn)單的介紹慰枕。

mPolicy:WindowManagerPolicy
WindowManagerPolicy(WMP)類型的變量。WindowManagerPolicy是窗口管理策略的接口類即纲,用來(lái)定義一個(gè)窗口策略所要遵循的通用規(guī)范,并提供了WindowManager所有的特定的UI行為博肋。它的具體實(shí)現(xiàn)類為PhoneWindowManager低斋,這個(gè)實(shí)現(xiàn)類在WMS創(chuàng)建時(shí)被創(chuàng)建蜂厅。WMP允許定制窗口層級(jí)和特殊窗口類型以及關(guān)鍵的調(diào)度和布局。

mSessions:ArraySet<Session>
ArraySet類型的變量膊畴,元素類型為Session掘猿。在Android解析WindowManager(三)Window的添加過(guò)程這篇文章中我提到過(guò)Session,它主要用于進(jìn)程間通信唇跨,其他的應(yīng)用程序進(jìn)程想要和WMS進(jìn)程進(jìn)行通信就需要經(jīng)過(guò)Session稠通,并且每個(gè)應(yīng)用程序進(jìn)程都會(huì)對(duì)應(yīng)一個(gè)Session,WMS保存這些Session用來(lái)記錄所有向WMS提出窗口管理服務(wù)的客戶端买猖。
mWindowMap:WindowHashMap
WindowHashMap類型的變量改橘,WindowHashMap繼承了HashMap,它限制了HashMap的key值的類型為IBinder玉控,value值的類型為WindowState飞主。WindowState用于保存窗口的信息,在WMS中它用來(lái)描述一個(gè)窗口高诺。綜上得出結(jié)論碌识,mWindowMap就是用來(lái)保存WMS中各種窗口的集合。

mFinishedStarting:ArrayList<AppWindowToken>
ArrayList類型的變量虱而,元素類型為AppWindowToken筏餐,它是WindowToken的子類。要想理解mFinishedStarting的含義牡拇,需要先了解WindowToken是什么魁瞪。WindowToken主要有兩個(gè)作用:

  • 可以理解為窗口令牌,當(dāng)應(yīng)用程序想要向WMS申請(qǐng)新創(chuàng)建一個(gè)窗口诅迷,則需要向WMS出示有效的WindowToken佩番。AppWindowToken作為WindowToken的子類,主要用來(lái)描述應(yīng)用程序的WindowToken結(jié)構(gòu)罢杉,
    應(yīng)用程序中每個(gè)Activity都對(duì)應(yīng)一個(gè)AppWindowToken趟畏。
  • WindowToken會(huì)將相同組件(比如Acitivity)的窗口(WindowState)集合在一起,方便管理滩租。

mFinishedStarting就是用于存儲(chǔ)已經(jīng)完成啟動(dòng)的應(yīng)用程序窗口(比如Acitivity)的AppWindowToken的列表赋秀。
除了mFinishedStarting,還有類似的mFinishedEarlyAnim和mWindowReplacementTimeouts律想,其中mFinishedEarlyAnim存儲(chǔ)了已經(jīng)完成窗口繪制并且不需要展示任何已保存surface的應(yīng)用程序窗口的AppWindowToken猎莲。mWindowReplacementTimeout存儲(chǔ)了等待更換的應(yīng)用程序窗口的AppWindowToken,如果更換不及時(shí)技即,舊窗口就需要被處理著洼。

mResizingWindows:ArrayList<WindowState>
ArrayList類型的變量,元素類型為WindowState。
mResizingWindows是用來(lái)存儲(chǔ)正在調(diào)整大小的窗口的列表身笤。與mResizingWindows類似的還有mPendingRemove豹悬、mDestroySurface和mDestroyPreservedSurface等等。其中mPendingRemove是在內(nèi)存耗盡時(shí)設(shè)置的液荸,里面存有需要強(qiáng)制刪除的窗口瞻佛。mDestroySurface里面存有需要被Destroy的Surface。mDestroyPreservedSurface里面存有窗口需要保存的等待銷毀的Surface娇钱,為什么窗口要保存這些Surface伤柄?這是因?yàn)楫?dāng)窗口經(jīng)歷Surface變化時(shí),窗口需要一直保持舊Surface文搂,直到新Surface的第一幀繪制完成适刀。

mAnimator:WindowAnimator
WindowAnimator類型的變量,用于管理窗口的動(dòng)畫以及特效動(dòng)畫细疚。

mH:H
H類型的變量蔗彤,系統(tǒng)的Handler類,用于將任務(wù)加入到主線程的消息隊(duì)列中疯兼,這樣代碼邏輯就會(huì)在主線程中執(zhí)行然遏。

mInputManager:InputManagerService
InputManagerService類型的變量,輸入系統(tǒng)的管理者吧彪。InputManagerService(IMS)會(huì)對(duì)觸摸事件進(jìn)行處理待侵,它會(huì)尋找一個(gè)最合適的窗口來(lái)處理觸摸反饋信息赁豆,WMS是窗口的管理者厨幻,因此,WMS“理所應(yīng)當(dāng)”的成為了輸入系統(tǒng)的中轉(zhuǎn)站崩侠,WMS包含了IMS的引用不足為怪傀缩。

2.Window的添加過(guò)程(WMS部分)

我們知道Window的操作分為兩大部分那先,一部分是WindowManager處理部分,另一部分是WMS處理部分赡艰,如下所示售淡。


Android解析WindowManager(三)Window的添加過(guò)程這篇文章中,我講解了Window的添加過(guò)程的WindowManager處理部分慷垮,這一篇文章我們接著來(lái)學(xué)習(xí)Window的添加過(guò)程的WMS部分揖闸。
無(wú)論是系統(tǒng)窗口還是Activity,它們的Window的添加過(guò)程都會(huì)調(diào)用WMS的addWindow方法料身,由于這個(gè)方法代碼邏輯比較多汤纸,這里分為3個(gè)部分來(lái)閱讀。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

addWindow方法part1

 public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {

        int[] appOp = new int[1];
        int res = mPolicy.checkAddPermission(attrs, appOp);//1
        if (res != WindowManagerGlobal.ADD_OKAY) {
            return res;
        }
        ...
        synchronized(mWindowMap) {
            if (!mDisplayReady) {
                throw new IllegalStateException("Display has not been initialialized");
            }
            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);//2
            if (displayContent == null) {
                Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                        + displayId + ".  Aborting.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }
            ...
            if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {//3
                parentWindow = windowForClientLocked(null, attrs.token, false);//4
                if (parentWindow == null) {
                    Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
                if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                        && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                    Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                }
            }
           ...
}
...
}

WMS的addWindow返回的是addWindow的各種狀態(tài)芹血,比如添加Window成功贮泞,無(wú)效的display等等楞慈,這些狀態(tài)被定義在WindowManagerGlobal中。
注釋1處根據(jù)Window的屬性隙畜,調(diào)用WMP的checkAddPermission方法來(lái)檢查權(quán)限抖部,具體的實(shí)現(xiàn)在PhoneWindowManager的checkAddPermission方法中,如果沒(méi)有權(quán)限則不會(huì)執(zhí)行后續(xù)的代碼邏輯议惰。注釋2處通過(guò)displayId來(lái)獲得窗口要添加到哪個(gè)DisplayContent上,如果沒(méi)有找到DisplayContent乡恕,則返回WindowManagerGlobal.ADD_INVALID_DISPLAY這一狀態(tài)言询,其中DisplayContent用來(lái)描述一塊屏幕。注釋3處傲宜,type代表一個(gè)窗口的類型运杭,它的數(shù)值介于FIRST_SUB_WINDOW和LAST_SUB_WINDOW之間(1000~1999),這個(gè)數(shù)值定義在WindowManager中函卒,說(shuō)明這個(gè)窗口是一個(gè)子窗口辆憔,不了解窗口類型取值范圍的請(qǐng)閱讀Android解析WindowManager(二)Window的屬性這篇文章。注釋4處报嵌,attrs.token是IBinder類型的對(duì)象虱咧,windowForClientLocked方法內(nèi)部會(huì)根據(jù)attrs.token作為key值從mWindowMap中得到該子窗口的父窗口。接著對(duì)父窗口進(jìn)行判斷锚国,如果父窗口為null或者type的取值范圍不正確則會(huì)返回錯(cuò)誤的狀態(tài)腕巡。

addWindow方法part2

   ...
            AppWindowToken atoken = null;
            final boolean hasParent = parentWindow != null;
            WindowToken token = displayContent.getWindowToken(
                    hasParent ? parentWindow.mAttrs.token : attrs.token);//1
            final int rootType = hasParent ? parentWindow.mAttrs.type : type;//2
            boolean addToastWindowRequiresToken = false;

            if (token == null) {
                if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                    Slog.w(TAG_WM, "Attempted to add application window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_INPUT_METHOD) {
                    Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_VOICE_INTERACTION) {
                    Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (rootType == TYPE_WALLPAPER) {
                    Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
                          + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                ...
                if (type == TYPE_TOAST) {
                    // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
                    if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
                            parentWindow)) {
                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
                                + attrs.token + ".  Aborting.");
                        return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                    }
                }
                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                token = new WindowToken(this, binder, type, false, displayContent,
                        session.mCanAddInternalSystemWindow);//3
            } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {//4
                atoken = token.asAppWindowToken();//5
                if (atoken == null) {
                    Slog.w(TAG_WM, "Attempted to add window with non-application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                } else if (atoken.removed) {
                    Slog.w(TAG_WM, "Attempted to add window with exiting application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_APP_EXITING;
                }
            } else if (rootType == TYPE_INPUT_METHOD) {
                if (token.windowType != TYPE_INPUT_METHOD) {
                    Slog.w(TAG_WM, "Attempted to add input method window with bad token "
                            + attrs.token + ".  Aborting.");
                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            }
      ...      

注釋1處通過(guò)displayContent的getWindowToken方法來(lái)得到WindowToken。注釋2處血筑,如果有父窗口就將父窗口的type值賦值給rootType绘沉,如果沒(méi)有將當(dāng)前窗口的type值賦值給rootType。接下來(lái)如果WindowToken為null豺总,則根據(jù)rootType或者type的值進(jìn)行區(qū)分判斷车伞,如果rootType值等于TYPE_INPUT_METHOD、TYPE_WALLPAPER等值時(shí)喻喳,則返回狀態(tài)值WindowManagerGlobal.ADD_BAD_APP_TOKEN另玖,說(shuō)明rootType值等于TYPE_INPUT_METHOD、TYPE_WALLPAPER等值時(shí)是不允許WindowToken為null的沸枯。通過(guò)多次的條件判斷篩選日矫,最后會(huì)在注釋3處隱式創(chuàng)建WindowToken,這說(shuō)明當(dāng)我們添加窗口時(shí)是可以不向WMS提供WindowToken的绑榴,前提是rootType和type的值不為前面條件判斷篩選的值哪轿。WindowToken隱式和顯式的創(chuàng)建肯定是要加以區(qū)分的,注釋3處的第4個(gè)參數(shù)為false就代表這個(gè)WindowToken是隱式創(chuàng)建的翔怎。接下來(lái)的代碼邏輯就是WindowToken不為null的情況窃诉,根據(jù)rootType和type的值進(jìn)行判斷杨耙,比如在注釋4處判斷如果窗口為應(yīng)用程序窗口,在注釋5處會(huì)將WindowToken轉(zhuǎn)換為專門針對(duì)應(yīng)用程序窗口的AppWindowToken飘痛,然后根據(jù)AppWindowToken的值進(jìn)行后續(xù)的判斷珊膜。

addWindow方法part3

   ...
  final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], seq, attrs, viewVisibility, session.mUid,
                    session.mCanAddInternalSystemWindow);//1
            if (win.mDeathRecipient == null) {//2
                // Client has apparently died, so there is no reason to
                // continue.
                Slog.w(TAG_WM, "Adding window client " + client.asBinder()
                        + " that is dead, aborting.");
                return WindowManagerGlobal.ADD_APP_EXITING;
            }

            if (win.getDisplayContent() == null) {//3
                Slog.w(TAG_WM, "Adding window to Display that has been removed.");
                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
            }

            mPolicy.adjustWindowParamsLw(win.mAttrs);//4
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
            res = mPolicy.prepareAddWindowLw(win, attrs);//5
            ...
            win.attach();
            mWindowMap.put(client.asBinder(), win);//6
            if (win.mAppOp != AppOpsManager.OP_NONE) {
                int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
                        win.getOwningPackage());
                if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
                        (startOpResult != AppOpsManager.MODE_DEFAULT)) {
                    win.setAppOpVisibilityLw(false);
                }
            }

            final AppWindowToken aToken = token.asAppWindowToken();
            if (type == TYPE_APPLICATION_STARTING && aToken != null) {
                aToken.startingWindow = win;
                if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
                        + " startingWindow=" + win);
            }

            boolean imMayMove = true;
            win.mToken.addWindow(win);//7
             if (type == TYPE_INPUT_METHOD) {
                win.mGivenInsetsPending = true;
                setInputMethodWindowLocked(win);
                imMayMove = false;
            } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                displayContent.computeImeTarget(true /* updateImeTarget */);
                imMayMove = false;
            } else {
                if (type == TYPE_WALLPAPER) {
                    displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
            }
         ...

在注釋1處創(chuàng)建了WindowState,它存有窗口的所有的狀態(tài)信息宣脉,在WMS中它代表一個(gè)窗口车柠。從WindowState傳入的參數(shù),可以發(fā)現(xiàn)WindowState中包含了WMS塑猖、Session竹祷、WindowToken、父類的WindowState羊苟、LayoutParams等信息塑陵。緊接著在注釋2和3處分別判斷請(qǐng)求添加窗口的客戶端是否已經(jīng)死亡、窗口的DisplayContent是否為null蜡励,如果是則不會(huì)再執(zhí)行下面的代碼邏輯令花。注釋4處調(diào)用了WMP的adjustWindowParamsLw方法,該方法的實(shí)現(xiàn)在PhoneWindowManager中凉倚,會(huì)根據(jù)窗口的type對(duì)窗口的LayoutParams的一些成員變量進(jìn)行修改兼都。注釋5處調(diào)用WMP的prepareAddWindowLw方法,用于準(zhǔn)備將窗口添加到系統(tǒng)中占遥。
注釋6處將WindowState添加到mWindowMap中俯抖。注釋7處將WindowState添加到該WindowState對(duì)應(yīng)的WindowToken中(實(shí)際是保存在WindowToken的父類WindowContainer中),這樣WindowToken就包含了相同組件的WindowState瓦胎。

addWindow方法總結(jié)

addWindow方法分了3個(gè)部分來(lái)進(jìn)行講解芬萍,主要就是做了下面4件事:

  1. 對(duì)所要添加的窗口進(jìn)行檢查,如果窗口不滿足一些條件搔啊,就不會(huì)再執(zhí)行下面的代碼邏輯柬祠。
  2. WindowToken相關(guān)的處理,比如有的窗口類型需要提供WindowToken负芋,沒(méi)有提供的話就不會(huì)執(zhí)行下面的代碼邏輯漫蛔,有的窗口類型則需要由WMS隱式創(chuàng)建WindowToken。
  3. WindowState的創(chuàng)建和相關(guān)處理旧蛾,將WindowToken和WindowState相關(guān)聯(lián)莽龟。
  4. 創(chuàng)建和配置DisplayContent,完成窗口添加到系統(tǒng)前的準(zhǔn)備工作锨天。

結(jié)語(yǔ)

在本篇文章中我們首先學(xué)習(xí)了WMS的重要成員毯盈,了解這些成員有利于對(duì)WMS的進(jìn)一步分析。接下來(lái)我們又學(xué)習(xí)了Window的添加過(guò)程的WMS部分病袄,將addWindow方法分為了3個(gè)部分來(lái)進(jìn)行講解搂赋,從addWindow方法我們得知WMS有3個(gè)重要的類分別是WindowToken赘阀、WindowState和DisplayContent,關(guān)于它們會(huì)在本系列后續(xù)的文章中進(jìn)行介紹脑奠。

參考資料
《深入理解Android卷III》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末基公,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宋欺,更是在濱河造成了極大的恐慌轰豆,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齿诞,死亡現(xiàn)場(chǎng)離奇詭異秒咨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)掌挚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)菩咨,“玉大人吠式,你說(shuō)我怎么就攤上這事〕槊祝” “怎么了特占?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)云茸。 經(jīng)常有香客問(wèn)我是目,道長(zhǎng),這世上最難降的妖魔是什么标捺? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任懊纳,我火速辦了婚禮,結(jié)果婚禮上亡容,老公的妹妹穿的比我還像新娘嗤疯。我一直安慰自己,他們只是感情好闺兢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布茂缚。 她就那樣靜靜地躺著,像睡著了一般屋谭。 火紅的嫁衣襯著肌膚如雪脚囊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天桐磁,我揣著相機(jī)與錄音悔耘,去河邊找鬼。 笑死所意,一個(gè)胖子當(dāng)著我的面吹牛淮逊,可吹牛的內(nèi)容都是我干的催首。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼泄鹏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼郎任!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起备籽,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤舶治,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后车猬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霉猛,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年珠闰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惜浅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伏嗜,死狀恐怖坛悉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情承绸,我是刑警寧澤裸影,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站军熏,受9級(jí)特大地震影響轩猩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荡澎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一均践、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衔瓮,春花似錦浊猾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至薇宠,卻和暖如春偷办,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背澄港。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工椒涯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人回梧。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓废岂,卻偏偏與公主長(zhǎng)得像祖搓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子湖苞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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