Android 圖形架構(gòu)

概述

要理解Android的圖形架構(gòu),我們需要先理解window的概念。維基百科中給window的定義是:Window是圖形用戶界面(GUI)系統(tǒng)中顯示器上一個(gè)單獨(dú)的視圖區(qū)域(可以想象你電腦桌面上一個(gè)個(gè)窗口)。因此,Android圖形架構(gòu)的就是把各個(gè)應(yīng)用創(chuàng)建的一個(gè)個(gè)window組合顯示到顯示屏上的架構(gòu)。

首先我們要理解Android系統(tǒng)中以下概念:

Window:代表顯示器上一個(gè)單獨(dú)的視圖區(qū)域的對(duì)象。它由WindowManager控制。由view構(gòu)成。這些view構(gòu)成一個(gè)View Hierarchy結(jié)構(gòu)。而這個(gè)View Hierarchy被渲染到WindowFlinger創(chuàng)建給Window的Surface上。

View:代表和用戶交互組件的基礎(chǔ)模塊。一個(gè)view占據(jù)屏幕上的一個(gè)矩形區(qū)域,并負(fù)責(zé)這個(gè)區(qū)域的圖形繪制和交互事件。Android中每個(gè)window的view構(gòu)成一個(gè)View Hierarchy結(jié)構(gòu)。

Surface:由SurfaceFlinger創(chuàng)建給WindowManager,并被WindowManager交給Window用來(lái)繪制window中view的內(nèi)容。這些內(nèi)容可以由view用canvas繪制,或者采用OpenGL ES等方法。它是指java對(duì)象,c++對(duì)應(yīng)的對(duì)象是ANativeWindow。

Display:Android 系統(tǒng)支持一個(gè)內(nèi)置顯示器(手機(jī)或平板上內(nèi)置的顯示器)、一個(gè)外接顯示器(如通過(guò) HDMI 連接的電視屏幕)、若干個(gè)虛擬顯示器(由 APP 調(diào)用 DisplayManager#createVirtualDisplay 創(chuàng)建,app 需要提供 surface)。

簡(jiǎn)而言之,就是,Window中的view被繪制或渲染到Surface中,才能被顯示在Display上。如圖

View vs Window vs Surface

那么,Window是怎么產(chǎn)生的呢?

每個(gè)Activity、DreamService、Dialog、MediaController、Toast或者自定義View在創(chuàng)建時(shí)都會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的Window。這些Window可以設(shè)置父子關(guān)系,如一般的Dialog會(huì)是它所屬Activity的子Window。這些子Window會(huì)擁有自己?jiǎn)为?dú)的Surface。

多個(gè)Window組合在一起就構(gòu)成了界面,也就是多個(gè)Surface的內(nèi)容組合在一起就構(gòu)成了界面的顯示,其中Surface的組合則是由SufaceFlinger根據(jù)各個(gè)Window的z-order之類的元數(shù)據(jù)組合的,SurfaceFlinger組合之后確定了顯示屏上哪個(gè)Window需要顯示、顯示多少、顯示在屏上哪個(gè)位置等,然后再把組合后的數(shù)據(jù)傳給圖形硬件抽象層(HAL)。如圖

Surface 如何被渲染(圖片來(lái)源:Android 官方)

Android graphics components

上面提到,View用Canvas把內(nèi)容繪制到Surface上,然后顯示在界面上,那么被繪制到Surface上的內(nèi)容是怎么顯示的呢?

如上圖(Surface 如何被渲染)中顯示的,它們通過(guò)Buffer Data傳遞被繪制的內(nèi)容。App通過(guò)Canvas或Media Player或Camera Preview或OpenGL ES生產(chǎn)Graphics Data并渲染到Surface,而SurfaceFlinger把這些Data組合然后通過(guò)Hardware Composer顯示。如圖:

Android 圖形架構(gòu)

簡(jiǎn)單來(lái)說(shuō),就是app生產(chǎn)graphics data,然后SurfaceFlinger合成組合所有的graphics data然后傳遞給Hardware Composer顯示。

graphics data flow(圖片來(lái)源:Android 官方)

其中,graphic data稱為Buffer,生產(chǎn)這些graphic data的Canvas、Media Player、Camera Preview等稱為圖形流生產(chǎn)方(Image Stream Producers)。而合成組合這些graphic data的SurfaceFlinger或OpenGL ES apps則稱為圖形流消耗方(Image Stream Consumers)。這些graphic data最后通過(guò)HWC(Hardware Composer)顯示在顯示器上。其中一個(gè)graphic data稱為Buffer,它們組成BufferQueue。

BufferQueue:BufferQueue是一個(gè)結(jié)合了buffer pool和隊(duì)列的數(shù)據(jù)結(jié)構(gòu),它使用Binder IPC在進(jìn)程間傳遞buffers。BufferQueue的生產(chǎn)方調(diào)用IGraphicBufferProducer(SurfaceTexture的一部分)接口來(lái)生成graphic buffers。而它的消耗方和GL Consumer一起消耗它并把它渲染到Surface。


SurfaceFlinger & WindowManager

SurfaceFlinger: accepts buffers, composes buffers, and sends buffers to the display. (接收并合成buffers,然后把它們發(fā)送給display顯示。)

WindowManager: provides SurfaceFlinger with buffers and window metadata, which SurfaceFlinger uses to composite surfaces to the display. (給SurfaceFlinger提供合成surfaces所需的buffers和window metadata。)

Layer: A combination of a surface and a SurfaceControl.?

Surface: contains the BufferQueue.?一個(gè)供Image Stream生產(chǎn)者和Image Consumer交換buffers的接口。它包含BufferQuene。使應(yīng)用可以渲染要顯示在屏幕上的Images。

SurfaceControl: contains the layer metadata like the display frame. It's uses to manipulate the appeareance of the app on the screen.?

Window:?containers for view objects. Window objects always backed by surface objects and controlled by WindowManager.?

Window metadata:?lifecycles, input and focus events, screen orientation, transitions, animations, position, transforms, z-order, and many other aspects of a window. Overseen by the WindowManager.

View: represents the basic building block for user interface components.?A view occupies a rectangular area on the screen and is responsible for drawing and event handling.

When an app comes to the foreground, it requestes buffers from WindowManager. WindowManager then sends all of the window metadata to SurfaceFlinger and requests a layer. SurfaceFlinger creates the layer and sends it to WindowManager. WindowManager then sends ther surface to the app, but keeps the SurfaceControl. 如圖:

SurfaceFlinger

VSYNC:?

APP 可以在任何時(shí)候提交buffers,但SurfaceFlinger僅僅在兩次display刷新中間被喚醒并接收buffers,這樣可減少內(nèi)存使用,并避免可見(jiàn)的屏幕撕裂(如果顯示內(nèi)容在刷新期間更新,就有可能發(fā)生)。

當(dāng)display處在兩次刷新中間時(shí),display會(huì)向SufaceFlinger發(fā)送VSYNC信號(hào)。VSYNC信號(hào)表示可以更新display且不用擔(dān)心產(chǎn)生撕裂。

SurfaceFlinger收到VSYNC信號(hào)后,會(huì)遍歷它的所有visible layers:如果該layer有新的buffer,獲取它;如果沒(méi)有,繼續(xù)使用舊的buffer;如果該layer沒(méi)有任何buffer,忽略它。當(dāng)所有l(wèi)ayer的buffer都被收集完后,SurfaceFlinger向Hardware Composer(HWC)詢問(wèn)這些layer的合成類型,如果得到的結(jié)果是客戶端合成,則合成。并把output buffer傳給HWC。

VSYNC

VSYNC信號(hào)可同步display pipeline(顯示管道)。display pipeline包含app渲染、SurfaceFlinger合成、HWC在顯示器上顯示圖片。VSYNC同步app因?yàn)橐_(kāi)始渲染而被喚醒的時(shí)間、SurfaceFlinger因?yàn)橐铣善聊欢粏拘训臅r(shí)間、和顯示器刷新周期。

SurfaceFlinger通過(guò)setVsyncEnable方法控制HWC是否生成VSYNC事件,當(dāng)HWC生成VSYNC事件后,會(huì)通過(guò)回調(diào)函數(shù)通知SurfaceFlinger。

在VSYNC事件發(fā)生時(shí),顯示器開(kāi)始顯示第N幀時(shí),SurfaceFlinger開(kāi)始合成第N+1幀,而app在處理等待的input事件并生成第N+2幀。

WinScope:

可用WinScope web分析WindowManager或SurfaceFlinger在window轉(zhuǎn)換期間和轉(zhuǎn)換后的狀態(tài)。

使用步驟:

1. 啟用

WindowManager:

adb shell cmd window tracing start

SurfaceFlinger:adb shell su root service call SurfaceFlinger 1025 i32 1

2. 停用

WindowManager:?adb shell cmd window tracing stop

SurfaceFlinger:adb shell su root service call SurfaceFlinger 1025 i32 0

3. 獲取pb文件

WindowManager:?adb pull /data/misc/wmtrace/wm_trace.pb wm_trace.pb

SurfaceFlinger:adb pull /data/misc/wmtrace/layers_trace.pb layers_trace.pb

4. 從 Android 源代碼庫(kù)中下載winscope.html:

curl 'https://android.googlesource.com/platform/prebuilts/misc/+/master/common/winscope/winscope.html?format=TEXT' | base64 -d > winscope.html

5. 打開(kāi)winscope.html

6. 點(diǎn)擊右上角的”O(jiān)PEN FILE“按鈕,選擇要打開(kāi)的pb文件,如圖:

Analyzing a trace in WinScope

這個(gè)trace里面有下面幾個(gè)部分:

Timeline?— 事件的時(shí)間軸。

Screen?— 顯示屏幕上所有的可見(jiàn)Window。

Hierarchy?— 包含系統(tǒng)已知的所有window,包括不可見(jiàn)的(這些window沒(méi)有buffer,但是對(duì)其子window有用)。可見(jiàn)window信息的末尾會(huì)帶有一個(gè)V標(biāo)簽。

Properties?— 顯示Hierarchy選中條目的具體信息。


WindowScope還可以從bug reports中讀取WindowManager和SurfaceFlinger的快照,bug reports以proto文件的形式存儲(chǔ)在proto文件夾中,用以下命令生成pb文件:

WindowManager:?adb exec-out dumpsys window --proto > window_dump.pb

SurfaceFlinger:?adb exec-out dumpsys SurfaceFlinger --proto > sf_dump.pb


Surface & SurfaceHolder

Layer:合成中最重要的單元。是Surface和SurfaceControl的結(jié)合。每個(gè)Layer都有一系列定義和其它layers交互的屬性,如Z-order等。

Surface:A surface is an interface for a producer to exchange buffers with a consumer. Surface objects enable apps to render images to be presented on screens.

SurfaceHolder:提供可以編輯和控制Surface的接口。大部分和view交互的組件都關(guān)聯(lián)一個(gè)SurfaceHolder來(lái)操作Surface,如SurfaceView。另外一些如MediaCodec之類的API,直接操作Surface。

Surface

View

構(gòu)建用戶界面的基礎(chǔ)元素,每個(gè)View占據(jù)屏幕上的一個(gè)矩形,并負(fù)責(zé)這個(gè)矩形區(qū)域的繪圖和事件處理。

Android的UI框架是一個(gè)view hierarchy結(jié)構(gòu),所有的UI元素經(jīng)過(guò)一系列的測(cè)量和布局放置在一個(gè)矩形區(qū)域內(nèi)。

View & Window & Surface

Window是圖形用戶界面(GUI)系統(tǒng)中顯示器上一個(gè)單獨(dú)的視圖區(qū)域。界面上的dialog、activity、status bar都有其對(duì)應(yīng)的Window,每個(gè)Window都有其對(duì)應(yīng)的View Hierarchy結(jié)構(gòu)。當(dāng)應(yīng)用到前臺(tái)時(shí),WindowManager會(huì)為每個(gè)Window獲取一個(gè)Surface,并把這個(gè)Surface給應(yīng)用,應(yīng)用在這塊Surface上用Canvas或者其它方法繪制它所屬Window中包含的View。在界面的兩次刷新中間時(shí),SurfaceFlinger會(huì)根據(jù)Z-order等信息合成系統(tǒng)中所有window的顯示區(qū)域,并最后渲染到屏幕上。

如果一個(gè)view要刷新,其實(shí)就是往它所屬window的Surface的BufferQuene中更新新的buffer內(nèi)容,等下次SurfaceFlinger遍歷時(shí)取出來(lái)重新合成。

簡(jiǎn)單的說(shuō)就是,Windows中的View要被渲染到Surface上才會(huì)被顯示。

SurfaceView

一般來(lái)說(shuō)一個(gè)View會(huì)和它所屬window中的view共用一塊Surface,但是SurfaceView擁有自己?jiǎn)为?dú)的Surface。當(dāng)SurfaceView所屬的window變成可見(jiàn)時(shí),framework會(huì)讓SurfaceControl向SurfaceFlinger申請(qǐng)一塊新的Surface給它。默認(rèn)情況下,這塊surface會(huì)被放在app其它UI surface的后面,如果要把它放在top可以override默認(rèn)的Z-order。

如果沒(méi)有SurfaceView,當(dāng)應(yīng)用需要使用如GL context(OpenGL ES context)或media decoder(Camera API)這類external buffer source進(jìn)行渲染時(shí),需要復(fù)制buffer source中的buffers,并把它們合成到window對(duì)應(yīng)surface中,才能讓它們顯示在屏幕上。而使用SurfaceView的話,SurfaceFlinger直接把source buffers合成到屏幕上。

SurfaceView的surface是BufferQueue的生產(chǎn)方,SurfaceFlinger是消耗方。

SurfaceTexture

SurfaceTexture是Surface和OpenGL ES(GLES) texture的組合。SurfaceTexture提供Surface給GLES渲染。

SurfaceTexture為消耗sources buffers的app持有一個(gè)BufferQueue。當(dāng)source buffers的生產(chǎn)方往BufferQueue里插入一個(gè)新buffer時(shí),onFrameAvailable() callback會(huì)被調(diào)用。然后app可以調(diào)用updateTexImage(),這個(gè)方法會(huì)釋放之前持有的buffer,從隊(duì)列中獲取生產(chǎn)方新插入的buffer,并進(jìn)行EGL調(diào)用使buffer可作為external texture供GLES使用。

SurfaceTexture使用external texture,external texture的優(yōu)點(diǎn)是能夠直接用BufferQueue中的數(shù)據(jù)進(jìn)行渲染。SurfaceTexutre在為external textures創(chuàng)建BufferQueues時(shí)會(huì)把消耗方的使用標(biāo)記設(shè)置為GRALLOC_USAGE_HW_TEXTURE,以確保GLES可以識(shí)別buffer中的數(shù)據(jù)。

SurfaceTexture 提供Surface給GLES渲染

TextureView

TextureView是SurfaceTexture和View的組合。

TextureView類里面封裝了一個(gè)SurfaceTexture,所以可以接收SurfaceTexture的回調(diào)和獲取可用buffer。當(dāng)buffer更新后,TextureView會(huì)觸發(fā)view的invalidate()方法請(qǐng)求重繪。

GLES可以通過(guò)把TextureView中的SurfaceTexture傳給創(chuàng)建EGL的調(diào)用來(lái)在TextureView上渲染。

如圖,表示一個(gè)應(yīng)用顯示Camera preview的數(shù)據(jù):

Camera buffer flow

Camera的數(shù)據(jù)渲染到SurfaceTexture提供給它的Surface上,然后再把這些數(shù)據(jù)渲染到TextureView所屬Window的Surface上,或渲染到SurfaceView自己的Surface上。

SurfaceView or TextureView

SurfaceView有自己專用的Surface,而TextureView和它所屬Window上的view共用一塊Suface。

在 API 24 及更高版本中,建議使用SurfaceView而不是TextureView。

兩者功能類似并且都是 view hierarchy 中的一員。但是,它們實(shí)現(xiàn)方法不一樣。SurfaceView雖然和其它view共享window的參數(shù),但它的內(nèi)容在渲染時(shí)是透明的。

TextureView具有更好的alpha和rotation處理能力.

SurfaceView在合成視頻上分層的UI元素時(shí)性能更好:

1. 使用SurfaceView時(shí),系統(tǒng)會(huì)為SurfaceView提供一個(gè)單獨(dú)的合在層(layer),SurfaceFlinger將直接使用這個(gè)layer做為一個(gè)硬件疊加層和其它window的layer合成在一起。

2. 使用TextureView時(shí),UI工具通過(guò)GPU將TextureView中的內(nèi)容合成到它的view hierarchy中——當(dāng)TextureView內(nèi)容更新時(shí),可能會(huì)導(dǎo)致其它view的重繪,比如,放置在TextureView上面的view;而且因?yàn)樵趘iew的渲染完成后,SurfaceFlinger還要把它所屬的app UI layer和其它layer合成在一起,所以導(dǎo)致所有TextureView上的可見(jiàn)像素都被合成了兩次。

但TextureView在某些功能的實(shí)現(xiàn)上比SurfaceView要簡(jiǎn)單,比如縮放功能的實(shí)現(xiàn):縮放SurfaceView需要FrameLayout的自定義實(shí)現(xiàn),WindowManager需要告訴SurfaceFlinger新窗口的位置和大小等信息。而縮放TextureView只需要使用TextureView#setTransform()配置轉(zhuǎn)換矩陣。


EGLSurface & OpenGL ES

OpenGL ES:Open Graphics Libarary Embedded Systems,GLES,免費(fèi)的、用于在嵌入式和移動(dòng)系統(tǒng)如手機(jī)上渲染圖形的跨平臺(tái)API。

EGL:Embedded Graphics Libarary. EGL是Khronos渲染API(如GLES)與本地窗口系統(tǒng)之間的一個(gè)中間接口層。

texture:OpenGL的對(duì)象,包含一張或多張擁有相同圖片格式的圖片。可以做為Shader(著色器)的來(lái)源,也可以做為渲染目標(biāo)。texture圖片比光滑的圖片多了表面的紋理。

不同設(shè)備的窗口系統(tǒng)千變?nèi)f化,但GLES的API卻是不變的,所以需要EGL協(xié)調(diào)設(shè)備的窗口系統(tǒng)和GLES。

Android用GLES來(lái)渲染圖形,并用EGL來(lái)創(chuàng)建GLES的contexts和為GLES渲染提供繪制的地方。GLES方法用來(lái)渲染textured多邊形,而EGL方法用來(lái)把渲染顯示在屏幕上。

在使用GLES繪制前,你需要?jiǎng)?chuàng)建GL context。在EGL中,這意味著要?jiǎng)?chuàng)建一個(gè)EGLContext和一個(gè)EGLSurface。這個(gè)GL context通過(guò)thread-local storage的方式被GLES訪問(wèn)操作,而不是當(dāng)做一個(gè)參數(shù)被傳遞給GLES訪問(wèn)操作。渲染代碼應(yīng)該在當(dāng)前的GLES線程而不是UI線程執(zhí)行。

EGL

EGLSurface(Android)

EGLSurface是操作系統(tǒng)分配的window,它由eglCreateWindowSurface()方法創(chuàng)建。這個(gè)方法不僅創(chuàng)建一個(gè)EGLSurface,還會(huì)把創(chuàng)建的EGLSurface連接到做為輸入?yún)?shù)的Surface的BufferQueue上(做為BufferQueue的生產(chǎn)方),而這個(gè)Surface由BufferQueue的消耗方(SurfaceView、SurfaceTexture、TextureView或者ImageReader等)創(chuàng)建。

這樣,渲染這個(gè)EGLSurface的整個(gè)流程是:從BufferQueue中取出一個(gè)new buffer,渲染這個(gè)buffer,再把被填充的buffer重新插入到BufferQueue中供consumer使用。如下

rendering to EGLSurface

EGL不提供lock/unlock方法,提供eglSwapBuffers()方法來(lái)提交當(dāng)前繪制的幀。

一個(gè)Surface一次只能和一個(gè)EGLSurface關(guān)聯(lián)(只能有一個(gè)生產(chǎn)方連接到BufferQueue),只有當(dāng)關(guān)聯(lián)的EGLSurface被銷毀后(它將斷開(kāi)與BufferQueue的連接),才允許其它的EGLSurface關(guān)聯(lián)。

一個(gè)線程可以更改它當(dāng)前使用的EGLSurface,但一個(gè)EGLSurface只能同時(shí)被一個(gè)線程使用。

EGL和SurfaceHolder不一樣,它是獨(dú)立與Surface的一個(gè)概念。你可以在一個(gè)并不由Surface支持的EGLSurface上繪圖,你也可以在沒(méi)有EGL的情況下使用Surface。EGLSurface僅僅為GLES提供一個(gè)繪圖的地方。

ANativeWindow

公開(kāi)的Surface類是用Java實(shí)現(xiàn)的,其對(duì)應(yīng)的C/C++類Android NDK中半公開(kāi)的ANativeWindow類。


參考

android develop圖形文檔:https//source.android.com/devices/graphics


原創(chuàng)內(nèi)容歡迎轉(zhuǎn)載,但請(qǐng)注明出處,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,087評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,521評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,493評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,207評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,603評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,813評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,364評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,110評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,305評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,532評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,953評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,209評(píng)論 1 291
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,033評(píng)論 3 396
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,268評(píng)論 2 375