顯示框架之a(chǎn)pp與SurfaceFlinger通信

SurfaceFlinger是android顯示的核心進(jìn)程,在整個(gè)顯示框架中起到一個(gè)承上啟下的作用,“承上”指的是與app進(jìn)程間的通信竟痰,“啟下”指的是與Composer進(jìn)程的通信。Surfaceflinger本身不進(jìn)行繪制,是app數(shù)據(jù)上屏的中樞通路晓铆,先來(lái)看下SurfaceFlinger在整個(gè)顯示流程中的位置。


顯示流程圖.png

從顯示流程圖看可知绰播,SurfaceFlinger位于中間層的位置骄噪,目前的應(yīng)用會(huì)調(diào)起renderthread使用GPU來(lái)渲染,應(yīng)用側(cè)使用surface來(lái)管理顯示數(shù)據(jù)蠢箩,surfaceflinger使用layer來(lái)對(duì)應(yīng)應(yīng)用側(cè)的surface链蕊,surfaceflinger會(huì)根據(jù)合成的方式,選擇device還是GPU合成谬泌,最后將layer數(shù)據(jù)提交給Composer進(jìn)程滔韵,進(jìn)而通過(guò)display 驅(qū)動(dòng)上屏。本文就來(lái)研究下app和SurfaceFlinger之間的通信掌实,主要針對(duì)native層的分析陪蜻,代碼基于android11。

APP與SurfaceFlinger之間的連接

首先框架會(huì)創(chuàng)建surfaceControl來(lái)管理surface贱鼻,在jni層會(huì)創(chuàng)建一個(gè)surfaceComposerClient對(duì)象宴卖,這個(gè)對(duì)象是負(fù)責(zé)與SurfaceFlinger進(jìn)程通信的重要載體。

文件:frameworks/base/core/jni/android_view_SurfaceControl.cpp

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jobject metadataParcel) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client;
    if (sessionObj != NULL) {
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
         // 如果java側(cè)沒(méi)有該對(duì)象則創(chuàng)建SurfaceComposerClient對(duì)象
        client = SurfaceComposerClient::getDefault();
    }
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface;
   ...
    // 通過(guò)SurfaceComposerClient創(chuàng)建一個(gè)Surface
    status_t err = client->createSurfaceChecked(
            String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));
   ...
    // 返回給上層surface對(duì)象
    return reinterpret_cast<jlong>(surface.get());
}

文件:frameworks/native/libs/gui/SurfaceComposerClient.cpp 

sp<SurfaceComposerClient> SurfaceComposerClient::getDefault() {
    return DefaultComposerClient::getComposerClient();
 }

class DefaultComposerClient: public Singleton<DefaultComposerClient> {
    Mutex mLock;
    sp<SurfaceComposerClient> mClient;
    friend class Singleton<ComposerService>;
public:
    static sp<SurfaceComposerClient> getComposerClient() {
        // 使用單例模式創(chuàng)建DefaultComposerClient 對(duì)象
        DefaultComposerClient& dc = DefaultComposerClient::getInstance();
        Mutex::Autolock _l(dc.mLock);
        if (dc.mClient == nullptr) {
            // 創(chuàng)建SurfaceComposerClient 對(duì)象
            dc.mClient = new SurfaceComposerClient;
        }
        return dc.mClient;
    }
};
// 由于SurfaceComposerClient是sp指針邻悬,第一次創(chuàng)建時(shí)會(huì)執(zhí)行onFirstRef 函數(shù)
void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;
        conn = sf->createConnection();
        if (conn != nullptr) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}
//在getComposerService 函數(shù)中調(diào)connectLocked來(lái)get到SurfaceFlinger服務(wù)并注冊(cè)了死亡監(jiān)聽(tīng)
void ComposerService::connectLocked() {
    const String16 name("SurfaceFlinger");
    while (getService(name, &mComposerService) != NO_ERROR) {
        usleep(250000);
    }
    assert(mComposerService != nullptr);

    // Create the death listener.
    class DeathObserver : public IBinder::DeathRecipient {
        ComposerService& mComposerService;
        virtual void binderDied(const wp<IBinder>& who) {
            ALOGW("ComposerService remote (surfaceflinger) died [%p]",
                  who.unsafe_get());
            mComposerService.composerServiceDied();
        }
     public:
        explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
    };

    mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
    IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
}
文件:frameworks/native/services/surfaceflinger/surfaceflinger.cpp

// 與SurfaceFlinger建立聯(lián)系症昏,Client持有SurfaceFlinger對(duì)象
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    const sp<Client> client = new Client(this);
    return client->initCheck() == NO_ERROR ? client : nullptr;
}

看注釋,至此完成了從SurfaceControl-> SurfaceComposerClient -> SurfaceFlinger的連接過(guò)程父丰。應(yīng)用要?jiǎng)?chuàng)建Surface時(shí)肝谭,對(duì)應(yīng)SurfaceFlinger會(huì)創(chuàng)建layer與之對(duì)應(yīng)。

文件:frameworks/native/libs/gui/SurfaceComposerClient.cpp 

status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                     PixelFormat format,
                                                     sp<SurfaceControl>* outSurface, uint32_t flags,
                                                     SurfaceControl* parent, LayerMetadata metadata,
                                                     uint32_t* outTransformHint) {
    sp<SurfaceControl> sur;
    ...
        // 會(huì)執(zhí)行到Client.cpp里面的createSurface
        err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
                                     &handle, &gbp, &transformHint);
       ...
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
        if (err == NO_ERROR) {
            // 根據(jù)返回的handle 和 gbp 創(chuàng)建 SurfaceControl
            *outSurface = new SurfaceControl(this, handle, gbp, transformHint);
        }
    }
    return err;
}

文件: frameworks/native/services/surfaceflinger/Client.cpp

status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
                               uint32_t flags, const sp<IBinder>& parentHandle,
                               LayerMetadata metadata, sp<IBinder>* handle,
                               sp<IGraphicBufferProducer>* gbp, uint32_t* outTransformHint) {
    // We rely on createLayer to check permissions.
    return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
                                 parentHandle, nullptr, outTransformHint);
}

文件: frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

tatus_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
                                     uint32_t h, PixelFormat format, uint32_t flags,
                                     LayerMetadata metadata, sp<IBinder>* handle,
                                     sp<IGraphicBufferProducer>* gbp,
                                     const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
   ...
    sp<Layer> layer;
   ...
    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
            // 對(duì)于surface類型創(chuàng)建layer類型,主要看下帶有BufferQueue的layer
            result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,
                                            std::move(metadata), format, handle, gbp, &layer);

            break;
    ...
    // 將創(chuàng)建的layer放到mCurrentState 里面分苇,SurfaceFlinger內(nèi)部管理了mCurrentState 和 mDrawingState
    result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer,
                            addToCurrentState, outTransformHint);
    ...
    setTransactionFlags(eTransactionNeeded);
    return result;
}
文件: frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name,
                                                uint32_t w, uint32_t h, uint32_t flags,
                                                LayerMetadata metadata, PixelFormat& format,
                                                sp<IBinder>* handle,
                                                sp<IGraphicBufferProducer>* gbp,
                                                sp<Layer>* outLayer) {
    ...
    sp<BufferQueueLayer> layer;
    LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
    ...
        Mutex::Autolock lock(mStateLock);
        layer = getFactory().createBufferQueueLayer(args);
    ...
    if (err == NO_ERROR) {
         // 在surfaceflinger側(cè) new了一個(gè)handle添诉,這個(gè)handle指向這個(gè)layer
        *handle = layer->getHandle();
        //gbp是創(chuàng)建的BufferQueueProducer對(duì)象
        *gbp = layer->getProducer();
        *outLayer = layer;
    }
        
    ALOGE_IF(err, "createBufferQueueLayer() failed (%s)", strerror(-err));
    return err;
}

文件: frameworks/native/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp

sp<BufferQueueLayer> DefaultFactory::createBufferQueueLayer(const LayerCreationArgs& args) {
    // new 了BufferQueueLayer對(duì)象,sp指針第一次創(chuàng)建時(shí)會(huì)執(zhí)行onFirstRef 函數(shù)
    return new BufferQueueLayer(args);
}

文件:frameworks/native/services/surfaceflinger/BufferQueueLayer.cpp

void BufferQueueLayer::onFirstRef() {
    BufferLayer::onFirstRef();

    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    // 創(chuàng)建一個(gè)BufferQueue對(duì)象医寿,跟著創(chuàng)建一個(gè)BufferQueueCore, BufferQueueProducer和 BufferQueueConsumer對(duì)象
    mFlinger->getFactory().createBufferQueue(&producer, &consumer, true);
    // 對(duì)producer 的一個(gè)封裝栏赴,MonitoredProducer實(shí)質(zhì)與 producer無(wú)差別
    mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this);
    // 創(chuàng)建BufferLayerConsumer ,首先創(chuàng)建父類ConsumerBase 對(duì)象
    mConsumer =
            mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(),
                                                             mTextureName, this);
   ...
    // 注冊(cè)了一個(gè)監(jiān)聽(tīng)靖秩,將BufferQueueLayer的函數(shù)方法注冊(cè)到BufferQueueCore里面须眷,說(shuō)明當(dāng)Buffer有變化時(shí)會(huì)通知BufferQueueLayer執(zhí)行相應(yīng)的動(dòng)作
    mContentsChangedListener = new ContentsChangedListener(this);
    mConsumer->setContentsChangedListener(mContentsChangedListener);
    mConsumer->setName(String8(mName.data(), mName.size()));

    // BufferQueueCore::mMaxDequeuedBufferCount is default to 1
    // 設(shè)置producer最大dequeue的buffer數(shù)量
    if (!mFlinger->isLayerTripleBufferingDisabled()) {
        mProducer->setMaxDequeuedBufferCount(2);
    }
}

文件:frameworks/native/services/surfaceflinger/Layer.cpp

sp<IBinder> Layer::getHandle() {
    Mutex::Autolock _l(mLock);
    if (mGetHandleCalled) {
        ALOGE("Get handle called twice" );
        return nullptr;
    }
    mGetHandleCalled = true;
   // 創(chuàng)建一個(gè)handle對(duì)應(yīng)layer
    return new Handle(mFlinger, this);
}

看注釋,SurfaceFlinger側(cè)創(chuàng)建了handle和GraphicsBufferProducer對(duì)象給到SurfaceControl沟突,handle 指向surfaceflinger的layer花颗,GraphicsBufferProducer 提供surface對(duì)Buffer的操作接口,上層操作surface的handle來(lái)作用到surfaceflinger的layer惠拭。至此扩劝,surfaceflinger創(chuàng)建layer的流程分析完了,比較繞的地方是涉及BufferQueue對(duì)象之間的關(guān)系职辅,用一副類的關(guān)系圖來(lái)說(shuō)明之間的關(guān)系棒呛。


BufferQueue類圖.png

APP與SurfaceFlinger之間數(shù)據(jù)的傳遞

現(xiàn)在應(yīng)用一般采用GPU去渲染加速,GPU操作在RenderThread里(HWUI 里面的邏輯很復(fù)雜域携,后續(xù)會(huì)進(jìn)行剖析)簇秒,應(yīng)用要繪制數(shù)據(jù)首先需要申請(qǐng)一塊Buffer,由前面分析可知秀鞭,應(yīng)用是一個(gè)GraphicsBufferProducer的角色趋观,故可以通過(guò)dequeueBuffer來(lái)向surfaceflinger申請(qǐng)一塊Buffer。

DequeueBuffer

文件: frameworks/native/libs/gui/Surface.cpp

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    ATRACE_CALL();
    ALOGV("Surface::dequeueBuffer");

   ...
    // 從應(yīng)用進(jìn)程調(diào)到SurfaceFlinger進(jìn)程锋边,實(shí)現(xiàn)在SurfaceFlinger側(cè)
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
                                                            reqFormat, reqUsage, &mBufferAge,
                                                            enableFrameTimestamps ? &frameTimestamps
                                                                                  : nullptr);
    ...
     // 后續(xù)會(huì)通過(guò)requestBuffer拿到Buffer
    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);

    ...
        // requestBuffer將通過(guò)importBuffer將Buffer映射到應(yīng)用進(jìn)程
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
    ...
       *buffer = gbuf.get();
    ...

       mDequeuedSlots.insert(buf);
       return OK;
}

文件: frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
                                            uint32_t width, uint32_t height, PixelFormat format,
                                            uint64_t usage, uint64_t* outBufferAge,
                                            FrameEventHistoryDelta* outTimestamps) {
    ...
    int found = BufferItem::INVALID_BUFFER_SLOT;
    while (found == BufferItem::INVALID_BUFFER_SLOT) {
          // 優(yōu)先從mFreeBuffers 里面獲取slot, 若沒(méi)有則從mFreeSlots 里面獲取皱坛,從mFreeSlots 里面獲取的都是還未分配Buffer的slot
          status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
    ...
    }
    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
        ...
        //若得到的slot對(duì)應(yīng)的buffer為空則重新分配一塊GraphicsBuffer
        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
                width, height, format, BQ_LAYER_COUNT, usage,
                {mConsumerName.string(), mConsumerName.size()});
        ...
        mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
        ...
}

文件: frameworks/native/libs/gui/BufferQueueProducer.cpp

status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
    ...
    mSlots[slot].mRequestBufferCalled = true;
     // GraphicsBuffer跨進(jìn)程傳遞執(zhí)行unflatten
    *buf = mSlots[slot].mGraphicBuffer;
    return NO_ERROR;
}

文件: frameworks/native/libs/ui/GraphicBuffer.cpp

status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
                                  size_t& count) {
...

if (handle != nullptr) {
        buffer_handle_t importedHandle;
        status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
                uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
...
        handle = importedHandle;
...

       return NO_ERROR;
}

應(yīng)用的surface執(zhí)行dequeueBuffer是在應(yīng)用進(jìn)程,具體實(shí)現(xiàn)是通過(guò)BufferQueueProducer的dequeueBuffer豆巨,是在SurfaceFlinger進(jìn)程麸恍,所以需要通過(guò)requestBuffer將Buffer映射到應(yīng)用進(jìn)程,具體實(shí)現(xiàn)是通過(guò)importBuffer搀矫。真正分配Buffer的地方是在ion抹沪,ion是怎么分配Buffer的,以及Buffer怎么實(shí)現(xiàn)app和SurfaceFlinger共享瓤球,先用一張簡(jiǎn)圖概述下融欧,后續(xù)會(huì)分析。


Buffer共享.png

至此app就拿到了可繪制的Buffer卦羡,GPU可以將數(shù)據(jù)渲染到這塊Buffer上噪馏。GPU將數(shù)據(jù)渲染到Buffer后麦到,會(huì)執(zhí)行eglSwapBuffers交換front和back buffer,eglSwapBuffers會(huì)調(diào)用queueBuffer欠肾,android系統(tǒng)用queueBuffer來(lái)請(qǐng)求vsync 喚醒SurfaceFlinger刷新瓶颠。

queueBuffer

文件: frameworks/native/libs/gui/Surface.cpp

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
    ...
     // dequeue出來(lái)的buffer對(duì)應(yīng)的slot
    int i = getSlotFromBufferLocked(buffer);
    ...
    // 傳入一些參數(shù),其中 fenceFd 是由GPU帶過(guò)來(lái)的刺桃,表示GPU渲染是否完成粹淋,這里為acquireFence
    IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
            static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
            mTransform ^ mStickyTransform, fence, mStickyTransform,
            mEnableFrameTimestamps);
    ...
    // 調(diào)到SurfaceFlinger進(jìn)程的queueBuffer
    status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
    ...
}

文件: frameworks/native/libs/gui/BufferQueueProducer.cpp

status_t BufferQueueProducer::queueBuffer(int slot,
        const QueueBufferInput &input, QueueBufferOutput *output) {
...
    BufferItem item;
...
        // 將數(shù)據(jù)同步到item對(duì)象
        item.mAcquireCalled = mSlots[slot].mAcquireCalled;
        item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
        item.mCrop = crop;
        item.mTransform = transform &
                ~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
        item.mTransformToDisplayInverse =
                (transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
        item.mScalingMode = static_cast<uint32_t>(scalingMode);
        item.mTimestamp = requestedPresentTimestamp;
        item.mIsAutoTimestamp = isAutoTimestamp;
        item.mDataSpace = dataSpace;
        item.mHdrMetadata = hdrMetadata;
        item.mFrameNumber = currentFrameNumber;
        item.mSlot = slot;
        item.mFence = acquireFence;
        item.mFenceTime = acquireFenceTime;
        item.mIsDroppable = mCore->mAsyncMode ||
                (mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
                (mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
                (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
        item.mSurfaceDamage = surfaceDamage;
        item.mQueuedBuffer = true;
        item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
        item.mApi = mCore->mConnectedApi;
       ...
      
       // 把item放到mQueue里面
       mCore->mQueue.push_back(item);
       // 這里的mCore->mConsumerListener 實(shí)際上為ConsumerBase對(duì)象
       frameAvailableListener = mCore->mConsumerListener;
       ...
      if (frameAvailableListener != nullptr) {
        frameAvailableListener->onFrameAvailable(item);
      }...
}

文件: frameworks/native/libs/gui/ConsumerBase.cpp

void ConsumerBase::onFrameAvailable(const BufferItem& item) {
    CB_LOGV("onFrameAvailable");

    sp<FrameAvailableListener> listener;
    { // scope for the lock
        Mutex::Autolock lock(mFrameAvailableMutex);
        listener = mFrameAvailableListener.promote();
    }

    if (listener != nullptr) {
        CB_LOGV("actually calling onFrameAvailable");
        // listener實(shí)際上是BufferQueueLayer對(duì)象
        listener->onFrameAvailable(item);
    }
}

根據(jù)類圖關(guān)系,frameAvailableListener 實(shí)際上是ConsumerBase 對(duì)象瑟慈,在ConsumerBase 初始化的時(shí)候進(jìn)行賦值桃移,通過(guò) mConsumer->consumerConnect(proxy, controlledByApp)接口,所以會(huì)調(diào)到ConsumerBase::onFrameAvailable葛碧, 而mFrameAvailableListener 是BufferQueueLayer -> setContentsChangedListener(mContentsChangedListener) 設(shè)的借杰,實(shí)際上是 BufferQueueLayer對(duì)象,因此最后走到BufferQueueLayer::onFrameAvailable 邏輯里面了进泼。

文件: frameworks/native/services/surfaceflinger/BufferQueueLayer.cpp

void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
   ...
    // 將item 放到mQueueItems里面
    mQueueItems.push_back(item);
    mQueuedFrames++;
   ...
    // 申請(qǐng)vsync去觸發(fā)surfaceflinger刷新
    mFlinger->signalLayerUpdate();
    mConsumer->onBufferAvailable(item);
}

文件: frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
    if (connection->resyncCallback) {
        connection->resyncCallback();
    }
    std::lock_guard<std::mutex> lock(mMutex);

    if (connection->vsyncRequest == VSyncRequest::None) {
        // Vsync請(qǐng)求置為Single
        connection->vsyncRequest = VSyncRequest::Single;
        mCondition.notify_all();
    }
}

讓Surfaceflinger刷新需要2個(gè)必要條件: 1. 有requestNextVsync 的請(qǐng)求 2. 軟件vsync計(jì)算模型回調(diào) onVSyncEvent創(chuàng)建一個(gè)vsyncEvent蔗衡,涉及到vsync模型,后面會(huì)介紹乳绕。
到這里绞惦,app完成了與SurfaceFlinger的連接以及將應(yīng)用數(shù)據(jù)傳給到SurfaceFlinger。這里需要注意的是刷袍,其實(shí)SurfaceFlinger并不會(huì)動(dòng)Buffer里面的數(shù)據(jù),只是中間傳遞的一個(gè)過(guò)程樊展,Buffer數(shù)據(jù)是由GPU渲染呻纹,display顯示,下篇分析下SurfaceFlinger在刷新時(shí)做了哪些動(dòng)作专缠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雷酪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子涝婉,更是在濱河造成了極大的恐慌哥力,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,080評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件墩弯,死亡現(xiàn)場(chǎng)離奇詭異吩跋,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)渔工,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門锌钮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人引矩,你說(shuō)我怎么就攤上這事梁丘∏纸” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,630評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵氛谜,是天一觀的道長(zhǎng)掏觉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)值漫,這世上最難降的妖魔是什么澳腹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,554評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮惭嚣,結(jié)果婚禮上遵湖,老公的妹妹穿的比我還像新娘。我一直安慰自己晚吞,他們只是感情好延旧,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著槽地,像睡著了一般迁沫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捌蚊,一...
    開(kāi)封第一講書(shū)人閱讀 49,856評(píng)論 1 290
  • 那天集畅,我揣著相機(jī)與錄音,去河邊找鬼缅糟。 笑死挺智,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的窗宦。 我是一名探鬼主播赦颇,決...
    沈念sama閱讀 39,014評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赴涵!你這毒婦竟也來(lái)了媒怯?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,752評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤髓窜,失蹤者是張志新(化名)和其女友劉穎扇苞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體寄纵,經(jīng)...
    沈念sama閱讀 44,212評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鳖敷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了程拭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哄陶。...
    茶點(diǎn)故事閱讀 38,687評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖哺壶,靈堂內(nèi)的尸體忽然破棺而出屋吨,到底是詐尸還是另有隱情蜒谤,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評(píng)論 4 331
  • 正文 年R本政府宣布至扰,位于F島的核電站鳍徽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏敢课。R本人自食惡果不足惜阶祭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望直秆。 院中可真熱鬧濒募,春花似錦、人聲如沸圾结。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,777評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)筝野。三九已至晌姚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間歇竟,已是汗流浹背挥唠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,006評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焕议,地道東北人宝磨。 一個(gè)月前我還...
    沈念sama閱讀 46,406評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像盅安,于是被迫代替她去往敵國(guó)和親唤锉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評(píng)論 2 349

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