显示设备的探寻(1)

显示设备测试程序

#include <cutils/memory.h>

#include <utils/Log.h>

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>

#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <android/native_window.h>

using namespace android;


int main(int argc, char** argv)
{
    // set up the thread-pool
    sp<ProcessState> proc(ProcessState::self());
    ProcessState::self()->startThreadPool();

    // create a client to surfaceflinger
    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
    
    sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
            160, 240, PIXEL_FORMAT_RGB_565, 0);

    sp<Surface> surface = surfaceControl->getSurface();

    SurfaceComposerClient::openGlobalTransaction();
    surfaceControl->setLayer(100000);
    SurfaceComposerClient::closeGlobalTransaction();

    ANativeWindow_Buffer outBuffer;
    surface->lock(&outBuffer, NULL);
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
    surface->unlockAndPost();
    sleep(3);

    surface->lock(&outBuffer, NULL);
    android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
    surface->unlockAndPost();
    sleep(3);

    surface->lock(&outBuffer, NULL);
    android_memset16((uint16_t*)outBuffer.bits, 0x001F, bpr*outBuffer.height);
    surface->unlockAndPost();
    sleep(3);

    for (int i = 0; i < 100; i++) {
        surface->lock(&outBuffer, NULL);
        printf("%03d buff addr = 0x%x\n", i, (unsigned int)outBuffer.bits);
        surface->unlockAndPost();
    }
    
    IPCThreadState::self()->joinThreadPool();
    
    return 0;
}
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    SurfaceTest.cpp

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libutils \
    libui \
    libgui \
    libbinder

LOCAL_MODULE:= SurfaceTest

LOCAL_MODULE_TAGS := tests

include $(BUILD_EXECUTABLE)

SurfaceFlinger的创建

# Set this property so surfaceflinger is not started by system_init  
setprop system_init.startsurfaceflinger 0  
  
service surfaceflinger /system/bin/surfaceflinger  
class main  
user system  
group graphics drmrpc  
onrestart restart zygote

位置在android\frameworks\native\services\surfaceflinger下

int main(int, char**) {
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
    //实例化surfaceflinger
    sp<SurfaceFlinger> flinger =  new SurfaceFlinger();
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
    set_sched_policy(0, SP_FOREGROUND);
    //初始化
    flinger->init();
    //发布surface flinger,注册到Service Manager
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
    // 运行在当前线程
    flinger->run();
    return 0;
}

我们看一看继承关系

class SurfaceFlinger : public BnSurfaceComposer,
                       private IBinder::DeathRecipient,
                       private HWComposer::EventHandler
{
class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{

这三个可以看出来:

  • SurfaceFlinger是Binder服务&作为Binder的实体端
  • 实现了ISurfaceComposer接口

同时我们看下BnSurfaceComposer的代理端:

ISurfaceComposer.cpp

class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
{

SurfaceComposerClient.cpp

我们首先得知道SurfaceComposerClient做了什么事情,接下来追溯代码:

构造好像也没干什么

SurfaceComposerClient::SurfaceComposerClient()
    : mStatus(NO_INIT), mComposer(Composer::getInstance())
{
}

当智能指针第一次调用的时候会进入onFirstRef()

void SurfaceComposerClient::onFirstRef() {
    //见下面
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        sp<ISurfaceComposerClient> conn = sm->createConnection();//[*]
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

getComposerService()

/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
    ComposerService& instance = ComposerService::getInstance();
    if (instance.mComposerService == NULL) {
        ComposerService::getInstance().connectLocked();//[*]
    }
    return instance.mComposerService;
}

我们继续追代码

void ComposerService::connectLocked() {
    const String16 name("SurfaceFlinger");
    while (getService(name, &mComposerService) != NO_ERROR) {
        usleep(250000);
    }
    assert(mComposerService != NULL);
    // Create the death listener.
    class DeathObserver : public IBinder::DeathRecipient {
        ComposerService& mComposerService;
        virtual void binderDied(const wp<IBinder>& who) {
            mComposerService.composerServiceDied();
        }
     public:
        DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
    };

    mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
    IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
}

我们看到mComposerService得到了SurfaceFlinger这个服务,SurfaceFlinger这个服务是init.rc中定义的,所以在开机执行init进程的时候创建了这个服务。并且添加了死亡回调

同时我们也可以看到在getComposerService()方法中将生成的SurfaceFlinger服务进行返回:return instance.mComposerService;

这样就在onFirstRef()中通过sp<ISurfaceComposer> sm(ComposerService::getComposerService());这句话得到了SurfaceFlinger服务的代理对象.

得到代理对象之后呢?我们进行了:

sp<ISurfaceComposerClient> conn = sm->createConnection();//这个的调用

由于SurfaceFlinger代理对象的创建所以我们追寻createConnection()

virtual sp<ISurfaceComposerClient> createConnection()
{
    Parcel data, reply;
    data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
    remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
    return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}

这样会导致实体类对应方法被调用:

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
{
    sp<ISurfaceComposerClient> bclient;
    sp<Client> client(new Client(this));
    status_t err = client->initCheck();
    if (err == NO_ERROR) {
        bclient = client;
    }
    return bclient;
}

所以到目前为止我们就明白了SurfaceFlinger的创建过程,我们在寻找类的时候需要一些技巧,比如ISurfaceComposer这个接口中肯定有代理,实体类与代理类就是一个Bp一个Bn。当然这个是在native层的技巧,java层就是XXProxy。

小结:

我们在init进程启动过程中创建了SurfaceFlinger服务,这个服务是个Binder服务,然后在SurfaceFlinger::createConnection()中创建了Client对象,并且将对象返回。那么Client对象返回的代理是那个对象呢?

class Client : public BnSurfaceComposerClient
{

所以我们返回的是BpSurfaceComposerClient对象。

这下我们就清晰了:

void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        sp<ISurfaceComposerClient> conn = sm->createConnection();//[*]
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

在这个方法中,我们首先得到BpSurfaceComposer对象代表SurfaceFlinger服务,然后得到BpSurfaceComposerClient代表Client服务。

step2

sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),160, 240, PIXEL_FORMAT_RGB_565, 0);
sp<Surface> surface = surfaceControl->getSurface();

当我们创建好BpSurfaceComposerClient之后就通过BpSurfaceComposerClient这个方法调用Clinet中的方法做一些操作.比如上面做的工作是什么呢?

SurfaceComposerClient::createSurface()

sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags,&handle, &gbp);
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}

这里mClinet是之前创建好的Client对象

status_t Client::createSurface(
        const String8& name,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle,
        sp<IGraphicBufferProducer>* gbp)
{
    class MessageCreateLayer : public MessageBase {
        SurfaceFlinger* flinger;
        Client* client;
        sp<IBinder>* handle;
        sp<IGraphicBufferProducer>* gbp;
        status_t result;
        const String8& name;
        uint32_t w, h;
        PixelFormat format;
        uint32_t flags;
    public:
        MessageCreateLayer(SurfaceFlinger* flinger,
                const String8& name, Client* client,
                uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
                sp<IBinder>* handle,
                sp<IGraphicBufferProducer>* gbp)
            : flinger(flinger), client(client),
              handle(handle), gbp(gbp),
              name(name), w(w), h(h), format(format), flags(flags) {
        }
        status_t getResult() const { return result; }
        virtual bool handler() {
            result = flinger->createLayer(name, client, w, h, format, flags,
                    handle, gbp);
            return true;
        }
    };
    //创建MessageCreateLayer
    sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
            name, this, w, h, format, flags, handle, gbp);
    //提交MessageCreateLayer
    mFlinger->postMessageSync(msg);
    return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}

这里我们从结构可以看出来,类似于Android中线程消息处理机制,使用postMessageSync给队列中添加一个消息,这样就会调用消息中handler方法触发。所以我们这句代码最后触发的是MessageCreateLayer::handler()

同时我们注意到我们在创建msg的时候,我们传递进去gb,其实是代理类BpGraphicBufferProducer暂时在这里没有赋值,具体在哪里赋值呢?

ISurfaceComposerClient.cpp

在BnSurfaceComposerClient中我们进行赋值

status_t BnSurfaceComposerClient::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
     switch(code) {
        case CREATE_SURFACE: {
            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
            String8 name = data.readString8();
            uint32_t width = data.readUint32();
            uint32_t height = data.readUint32();
            PixelFormat format = static_cast<PixelFormat>(data.readInt32());
            uint32_t createFlags = data.readUint32();
            sp<IBinder> handle;
            sp<IGraphicBufferProducer> gbp;
            status_t result = createSurface(name, width, height, format,
                    createFlags, &handle, &gbp);
            reply->writeStrongBinder(handle);
            reply->writeStrongBinder(IInterface::asBinder(gbp));//核心
            reply->writeInt32(result);
            return NO_ERROR;
        }

顺序是当我们调用

也就是我们在传递创建createSurface的时候给gbp赋值了


我们回顾一下过程,我们通过sp<SurfaceComposerClient> client = new SurfaceComposerClient();首先我们获取到surfaceFliger服务。
在内部通过surfaceFliger服务创建了mClinet,然后使用mClient去做很多操作。

我们这块小结下代码:

sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags,&handle, &gbp);
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}

mClient代理是谁呢?

class Client : public BnSurfaceComposerClient
{

所以看出来是BpSurfaceComposerClient

BpSurfaceComposerClient

virtual status_t createSurface(const String8& name, uint32_t width,
        uint32_t height, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle,
        sp<IGraphicBufferProducer>* gbp) {
    remote()->transact(CREATE_SURFACE, data, &reply);
    *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
    return reply.readInt32();
}

这里我们看到了核心调用*gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());

是在reply中,我们就先看看这个Binder调用过去的对端

BnSurfaceComposerClient

status_t BnSurfaceComposerClient::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
     switch(code) {
        case CREATE_SURFACE: {
            sp<IGraphicBufferProducer> gbp;
            status_t result = createSurface(name, width, height, format,createFlags, &handle, &gbp);
            reply->writeStrongBinder(IInterface::asBinder(gbp));
            return NO_ERROR;
        }

我们看到了先调用createSurface,然后写入gbp代理。我们可以看出来创建gbp实例是在createSurface中。

class Client : public BnSurfaceComposerClient
{

所以createSurface是调用到了Client中的createSurface方法:

status_t Client::createSurface(
        const String8& name,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle,
        sp<IGraphicBufferProducer>* gbp)
{
    ...
        virtual bool handler() {
            result = flinger->createLayer(name, client, w, h, format, flags,handle, gbp);
            return true;
        }
    };

    sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
            name, this, w, h, format, flags, handle, gbp);
    mFlinger->postMessageSync(msg);
    return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}

继续进入到flinger->createLayer

调用到
 result = createNormalLayer(client,
                    name, w, h, flags, format,
                    handle, gbp, &layer);
                    
                    

我们最后在Layer中看到了啦gbp的赋值

 *gbp = (*outLayer)->getProducer();

到这里我们知道mClient->createSurface之后会得到生产者的代理
gbp,这个gbp指向的是BufferQueueProducer


virtual bool handler() {
    result = flinger->createLayer(name, client, w, h, format, flags,
            handle, gbp);
    return true;
}
status_t SurfaceFlinger::createLayer(
        const String8& name,
        const sp<Client>& client,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp){
    status_t result = NO_ERROR;
    sp<Layer> layer;
    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal:
            //[*]
            result = createNormalLayer(client,
                    name, w, h, flags, format,
                    handle, gbp, &layer);
            break;
        case ISurfaceComposerClient::eFXSurfaceDim:
            result = createDimLayer(client,
                    name, w, h, flags,
                    handle, gbp, &layer);
            break;
        default:
            result = BAD_VALUE;
            break;
    }

    if (result != NO_ERROR) {
        return result;
    }
    result = addClientLayer(client, *handle, *gbp, layer);
    if (result != NO_ERROR) {
        return result;
    }
    return result;
}

由代码可以看出,我们创建的是一个createNormalLayer()

status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
    // initialize the surfaces
    switch (format) {
    case PIXEL_FORMAT_TRANSPARENT:
    case PIXEL_FORMAT_TRANSLUCENT:
        format = PIXEL_FORMAT_RGBA_8888;
        break;
    case PIXEL_FORMAT_OPAQUE:
        format = PIXEL_FORMAT_RGBX_8888;
        break;
    }
    *outLayer = new Layer(this, client, name, w, h, flags);
    status_t err = (*outLayer)->setBuffers(w, h, format, flags);//[*]
    if (err == NO_ERROR) {
        *handle = (*outLayer)->getHandle();
        *gbp = (*outLayer)->getProducer();
    }
    return err;
}

Layer生成之后第一次引用会调用这个方法

void Layer::onFirstRef() {
    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    //生产者消费者,都传入BufferQueue
    BufferQueue::createBufferQueue(&producer, &consumer);
    //生产者
    mProducer = new MonitoredProducer(producer, mFlinger);
    //消费者
    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
    mSurfaceFlingerConsumer->setContentsChangedListener(this);
    mSurfaceFlingerConsumer->setName(mName);

#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif

    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
    updateTransformHint(hw);
}

BufferQueue::createBufferQueue()

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
        sp<IGraphicBufferConsumer>* outConsumer,
        const sp<IGraphicBufferAlloc>& allocator) {
    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
    *outProducer = producer;
    *outConsumer = consumer;
}

走到这里我们回顾一下:

我们通过SurfaceComposerClient->OnFristRef()对应两个核心:

client = new SurfaceComposerClinet():
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
        return getService("surfaceFlinger")
    sp<SurfaceComposerClinet> conn = sm->createComection()
        return new Clinet()
client->createSurface()
    SurfaceFlinger->createLayer()
        return new Layer()
            BufferQueue::createBufferQueue(&producer, &consumer);
                sp<BufferQueueCore> core(new BufferQueueCore(allocator));
                    mAllocator = composer->createGraphicBufferAlloc();//创建mAllocator用于分配内存                  
                    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));//里面有core的引用和mSlots引用
                  sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));//里面有core的引用和mSlots引用
            mProducer = new MonitoredProducer(producer, mFlinger);//对上进行包装
            mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);//对消费者进行包装
    new SurfaceControl()

其中注意BufferQueueCore的成员变量:

BufferQueueDefs::SlotsType mSlots;
这个成员定义:
namespace android {
    class BufferQueueCore;
    namespace BufferQueueDefs {
        enum { NUM_BUFFER_SLOTS = 64 };
        typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
    }
}
定义了一个数组,这个BufferSlot[64]

我们看一看BufferSlot是什么:

{

    BufferSlot()
    : mEglDisplay(EGL_NO_DISPLAY),
      mBufferState(BufferSlot::FREE),
      mRequestBufferCalled(false),
      mFrameNumber(0),
      mEglFence(EGL_NO_SYNC_KHR),
      mAcquireCalled(false),
      mNeedsCleanupOnRelease(false),
      mAttachedByConsumer(false) {
    }

    sp<GraphicBuffer> mGraphicBuffer;
    EGLDisplay mEglDisplay;

    enum BufferState {
        FREE = 0,
        DEQUEUED = 1,
        QUEUED = 2,
        ACQUIRED = 3
    };

    static const char* bufferStateName(BufferState state);
    BufferState mBufferState;
    bool mRequestBufferCalled;
    uint64_t mFrameNumber;
    EGLSyncKHR mEglFence;
    sp<Fence> mFence;
    bool mNeedsCleanupOnRelease;
    bool mAttachedByConsumer;
}

我们通过上面堆栈草图可以看出来,在生产者和消费者中都应用BufferQueueCore中的mAllocator和BufferSlot mSlots[64]

surfaceControl->getSurface();

由于我们在创建的时候返回的是SurfaceControl所以调用SurfaceControl的方法

sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags,&handle, &gbp);
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}
sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        mSurfaceData = new Surface(mGraphicBufferProducer, false);
    }
    return mSurfaceData;
}

很简单,这句就返回一个Surface对象,这里我们也顺带注意一下,在构造SurfaceControl的时候进行gbp(生产者)的赋值。所以我们在构造Surface将生产者传入

小结

我们创建了Client对象,使用BpSurfaceComposerClient作为代理,一旦使用SurfaceComposerClient去做一些事情就牵扯到Client的实体对象。同时我们在创建Client的时候我们创建了生产者消费者,生产消费队列,我们应用程序得到了生产者,并且我们获取了SurfaceControl通过SurfaceControl的方法我们创建了Surface对象。所以再我们应用程序这里,有Client调用功能,Surface绘制,有生成者进行生产,生产者里面有core分配内存并且Buffer数组。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,565评论 6 539
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,115评论 3 423
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 177,577评论 0 382
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,514评论 1 316
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,234评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,621评论 1 326
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,641评论 3 444
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,822评论 0 289
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,380评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,128评论 3 356
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,319评论 1 371
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,879评论 5 362
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,548评论 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,970评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,229评论 1 291
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,048评论 3 397
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,285评论 2 376

推荐阅读更多精彩内容