Binder(三)

接著上一篇历等,MediaPlayerService已經(jīng)被注冊(cè)到ServiceManager中了尺碰,本篇將接著分析MediaPlayerService服務(wù)的獲取,以及通過MediaPlayerService服務(wù)創(chuàng)建播放器2個(gè)流程洒宝。

<Binder(一)>一篇知道颠黎,MediaPlayer.java調(diào)用setDataSource方法,最終會(huì)調(diào)用MediaPlayer.cpp的setDataSource函數(shù)总处。

status_t MediaPlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *url, const KeyedVector<String8, String8> *headers)
{
    ALOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
        //1狈惫,獲取IMediaPlayerService服務(wù)
        const sp<IMediaPlayerService>& service(getMediaPlayerService());
        if (service != 0) {
            //2,讓遠(yuǎn)程服務(wù)創(chuàng)建播放器
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                    //通過IMediaPlayer操作播放器
                (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
    }
    return err;
}

我們先看getMediaPlayerService()函數(shù)的執(zhí)行過程鹦马。

IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        //獲取IServiceManager
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            //使用String16("media.player")獲取服務(wù)
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            //如果服務(wù)還未注冊(cè)胧谈,等待
            usleep(500000); // 0.5 s
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        //將IBinder保存到BpMediaPlayerService的成員變量mRemote中
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }

    return sMediaPlayerService;
}

defaultServiceManager()返回BpServiceManager。

class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)
    {
    }

    virtual sp<IBinder> getService(const String16& name) const
    {
        unsigned n;
        //最多查詢5次
        for (n = 0; n < 5; n++){
            
            sp<IBinder> svc = checkService(name);
            if (svc != NULL) return svc;
            ALOGI("Waiting for service %s...\n", String8(name).string());
            sleep(1);
        }
        return NULL;
    }
//發(fā)送查找指令
 virtual sp<IBinder> checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        //發(fā)送CHECK_SERVICE_TRANSACTION指令
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        //讀取響應(yīng)數(shù)據(jù)
        return reply.readStrongBinder();
    }

transact會(huì)通過BpBinder(0)發(fā)送數(shù)據(jù)給ServiceManager查找名字為"media.player"的Service荸频,在上一篇分析過菱肖,ServiceManager會(huì)通過svcmgr_handler函數(shù)來處理請(qǐng)求。

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    ......

    switch(txn->code) {
    //獲取某個(gè)Service旭从,通過msg來取
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        //s為對(duì)應(yīng)Service名字
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //查找Service稳强,返回handle值
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        //不為0則找到
        if (!handle)
            break;
        //寫入reply回傳給客戶端
        bio_put_ref(reply, handle);
        return 0;

do_find_service根據(jù)"media.player"進(jìn)行查找场仲,并返回它的句柄handle。

uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
    struct svcinfo *si;
    //檢查權(quán)限
    if (!svc_can_find(s, len, spid)) {
        ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n",
             str8(s, len), uid);
        return 0;
    }
    //查找服務(wù)
    si = find_svc(s, len);
     //si不為null退疫,handle大于0
    if (si && si->handle) {
        if (!si->allow_isolated) {
          
            uid_t appid = uid % AID_USER;
            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
                return 0;
            }
        }
        //成功返回handle
        return si->handle;
    } else {
        return 0;
    }
}

繼續(xù)看查找的關(guān)鍵函數(shù)find_svc渠缕。

struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
    struct svcinfo *si;
    //遍歷
    for (si = svclist; si; si = si->next) {
        if ((len == si->len) &&
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
            return si;
        }
    }
    return NULL;
}

Service整個(gè)查找過程薄疚,就是根據(jù)Service名去遍歷svcinfo鏈表趋距,找到svcinfo結(jié)構(gòu)體后,將svcinfo的handle值寫入緩存迅矛,回傳給客戶端棒坏。

我們回頭看reply.readStrongBinder()這個(gè)方法如何解析響應(yīng)數(shù)據(jù)燕差,和返回需要的服務(wù)對(duì)象。reply是一個(gè)Parcel類坝冕。

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
   //讀取數(shù)據(jù)
    const flat_binder_object* flat = in.readObject(false);
    //此時(shí)為BINDER_TYPE_HANDLE類型
    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                //傳入handle
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);
    //構(gòu)建一個(gè)entry
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            //此時(shí)handle不為0
            if (handle == 0) {
                 Parcel data;
                //ping下驅(qū)動(dòng)是否通
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            //根據(jù)handle創(chuàng)建了一個(gè)BpBinder
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
          //將創(chuàng)建的BpBinder返回
            result = b;
        } else {
             result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

這里的流程和獲取IServiceManger是相同的徒探,只是此時(shí)的handle大于0,它通過ProcessState創(chuàng)建了一個(gè)BpBinder(handle)喂窟。

回到IMediaDeathNotifier::getMediaPlayerService函數(shù)测暗,BpBinder(handle)同樣通過interface_cast進(jìn)行了強(qiáng)轉(zhuǎn),強(qiáng)轉(zhuǎn)流程可以看前面IServiceManger的獲取流程谎替。

也就是說偷溺,最終客戶端得到一個(gè)BpMediaPlayerService蹋辅,它的成員變量mRemote持有一個(gè)BpBinder(handle)钱贯,有了這個(gè)handle句柄,就能通過Binder驅(qū)動(dòng)和MediaPlayerService進(jìn)行通訊了侦另。

流程1到此分析完成秩命,即當(dāng)前已獲取到了IMediaPlayerService。繼續(xù)分析流程2褒傅,IMediaPlayerService調(diào)用了create函數(shù)弃锐,創(chuàng)建播放器。

 virtual sp<IMediaPlayer> create(
            const sp<IMediaPlayerClient>& client, int audioSessionId) {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        data.writeStrongBinder(client->asBinder());
        data.writeInt32(audioSessionId);
        //獲取mRemote殿托,發(fā)送創(chuàng)建指令CREATE霹菊,
        remote()->transact(CREATE, data, &reply);
        //返回播放器引用
        return interface_cast<IMediaPlayer>(reply.readStrongBinder());
    }

通過remote()獲取mRemote,即BpBinder(0)發(fā)送CREATE創(chuàng)建指令支竹。上一篇分析過旋廷,MediaPlayerService在MediaServer中創(chuàng)建,并開啟了兩個(gè)線程循環(huán)執(zhí)行talkWithDriver函數(shù)礼搁,循環(huán)讀寫消息饶碘,假設(shè)其中一個(gè)線程收到CREATE這個(gè)指令,最終將執(zhí)行executeCommand函數(shù)馒吴,

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
    
    switch (cmd) {
      ......
    case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
        
            if (result != NO_ERROR) break;
            ......

            Parcel reply;
            status_t error;
           //轉(zhuǎn)為BBinder對(duì)象扎运,實(shí)際就是BnMediaPlayerService
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                error = b->transact(tr.code, buffer, &reply, tr.flags);

            } else {
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }

BpXXX對(duì)應(yīng)著服務(wù)端在客戶端的業(yè)務(wù)代理瑟曲,而Bn則對(duì)應(yīng)服務(wù)端本地的業(yè)務(wù)處理類,因此每個(gè)服務(wù)端都包含一個(gè)BnXXX內(nèi)部類豪治,它繼承模板類BnInterface和BBinder對(duì)象洞拨。

class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

};
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    virtual IBinder*            onAsBinder();
};

而transact函數(shù)定義在BBinder中,直接看transact函數(shù)负拟。

status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
          //處理消息數(shù)據(jù)
            err = onTransact(code, data, reply, flags);
            break;
    }

    if (reply != NULL) {
        reply->setDataPosition(0);
    }

    return err;
}

onTransact用于處理消息數(shù)據(jù)扣甲,它是一個(gè)虛函數(shù),由繼承關(guān)系知道齿椅,它實(shí)現(xiàn)在BnMediaPlayerService中琉挖。

status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
          ......
        case CREATE: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            sp<IMediaPlayerClient> client =
                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
            int audioSessionId = data.readInt32();
            //創(chuàng)建播放器
            sp<IMediaPlayer> player = create(client, audioSessionId);
            //將播放器轉(zhuǎn)為Binder類型的數(shù)據(jù),寫入響應(yīng)緩沖區(qū)
            reply->writeStrongBinder(player->asBinder());
            return NO_ERROR;
        } break;
     ......
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

如上涣脚,BnMediaPlayerService將會(huì)創(chuàng)建一個(gè)播放器示辈,返回給MediaPlayer.cpp客戶端,這個(gè)MediaPlayer.cpp的遠(yuǎn)程服務(wù)端是一個(gè)MediaPlayerService的內(nèi)部類遣蚀,為Client矾麻,它繼承自IMediaPlayer。

sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
        int audioSessionId)
{
    pid_t pid = IPCThreadState::self()->getCallingPid();
    int32_t connId = android_atomic_inc(&mNextConnId);
   //創(chuàng)建Client對(duì)象芭梯,它是BnMediaPlayer的子類
    sp<Client> c = new Client(
            this, pid, connId, client, audioSessionId,
            IPCThreadState::self()->getCallingUid());

    wp<Client> w = c;
    {
        Mutex::Autolock lock(mLock);
        mClients.add(w);
    }
    return c;
}

Client是MediaPlayerService的內(nèi)部類险耀,它繼承自BnMediaPlayer,也就是IMediaPlayer的服務(wù)端玖喘,函數(shù)返回后甩牺,也就是客戶端得到Client的遠(yuǎn)程對(duì)象代理,那么緊接著會(huì)執(zhí)行Client的setDataSource函數(shù)累奈。

status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
    struct stat sb;
    int ret = fstat(fd, &sb);
    if (ret != 0) {
   
        return UNKNOWN_ERROR;
    }


    if (offset >= sb.st_size) {
        ALOGE("offset error");
        ::close(fd);
        return UNKNOWN_ERROR;
    }
    if (offset + length > sb.st_size) {
        length = sb.st_size - offset;
        ALOGV("calculated length = %lld", length);
    }
  //獲取到當(dāng)前適合播放該視頻源的播放器類型
    player_type playerType = MediaPlayerFactory::getPlayerType(this,
                                                               fd,
                                                               offset,
                                                               length);
   // 根據(jù)得到的播放器類型去創(chuàng)建對(duì)應(yīng)的播放器實(shí)例:
    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
    if (p == NULL) {
        return NO_INIT;
    }
   
    setDataSource_post(p, p->setDataSource(fd, offset, length));
    return mStatus;
}

這里分兩步執(zhí)行贬派,先獲取到適合播放該視頻源的播放器類型,再根據(jù)這個(gè)類型去創(chuàng)建播放器澎媒。MediaPlayerFactory保存的工廠類搞乏,在MediaPlayerService構(gòu)造時(shí)就注冊(cè)好了。

MediaPlayerService::MediaPlayerService()
{
    ALOGV("MediaPlayerService created");
    mNextConnId = 1;

    mBatteryAudio.refCount = 0;
    for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
        mBatteryAudio.deviceOn[i] = 0;
        mBatteryAudio.lastTime[i] = 0;
        mBatteryAudio.totalTime[i] = 0;
    }

    mBatteryAudio.deviceOn[SPEAKER] = 1;

    const sp<IServiceManager> sm(defaultServiceManager());
    if (sm != NULL) {
        const String16 name("batterystats");
        sp<IBatteryStats> batteryStats =
                interface_cast<IBatteryStats>(sm->getService(name));
        if (batteryStats != NULL) {
            batteryStats->noteResetVideo();
            batteryStats->noteResetAudio();
        }
    }
    //注冊(cè)播放器工廠類
    MediaPlayerFactory::registerBuiltinFactories();
}

構(gòu)造函數(shù)最后一行注冊(cè)了所有類型播放器工廠戒努。

void MediaPlayerFactory::registerBuiltinFactories() {
    Mutex::Autolock lock_(&sLock);

    if (sInitComplete)
        return;

    registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
    registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
    registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
    registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);

    sInitComplete = true;
}

我們回頭看根據(jù)類型獲取播放器的函數(shù)setDataSource_pre请敦。

sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
        player_type playerType)
{
     //根據(jù)類型創(chuàng)建播放器
    sp<MediaPlayerBase> p = createPlayer(playerType);
    if (p == NULL) {
        return p;
    }

    if (!p->hardwareOutput()) {
        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                mPid, mAudioAttributes);
        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
    }

    return p;
}

sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
  
    sp<MediaPlayerBase> p = mPlayer;
    if ((p != NULL) && (p->playerType() != playerType)) {
        ALOGV("delete player");
        p.clear();
    }
    //通過工廠類創(chuàng)建播放器
    if (p == NULL) {
        p = MediaPlayerFactory::createPlayer(playerType, this, notify);
    }

    if (p != NULL) {
        p->setUID(mUID);
    }

    return p;
}

關(guān)鍵代碼所示,MediaPlayerFactory工廠類獲取播放器储玫。

sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
        player_type playerType,
        void* cookie,
        notify_callback_f notifyFunc) {
    sp<MediaPlayerBase> p;
    IFactory* factory;
    status_t init_result;
    Mutex::Autolock lock_(&sLock);

    if (sFactoryMap.indexOfKey(playerType) < 0) {
        ALOGE("Failed to create player object of type %d, no registered"
              " factory", playerType);
        return p;
    }
    //從sFactoryMap獲取對(duì)應(yīng)的工廠類
    factory = sFactoryMap.valueFor(playerType);
    CHECK(NULL != factory);

    //通過IFactory內(nèi)部類的不同實(shí)現(xiàn)類侍筛,創(chuàng)建不同的MediaPlayer
    p = factory->createPlayer();

    if (p == NULL) {
        ALOGE("Failed to create player object of type %d, create failed",
               playerType);
        return p;
    }

    init_result = p->initCheck();
    if (init_result == NO_ERROR) {
        p->setNotifyCallback(cookie, notifyFunc);
    } else {
        p.clear();
    }

    return p;
}

在注冊(cè)工廠類時(shí)已經(jīng)將各類型工廠加入到成員sFactoryMap中,此時(shí)根據(jù)類型獲取到特定的工廠缘缚,并通過createPlayer創(chuàng)建播放器勾笆,安卓有2種類型的播放器,以NuPlayerFactory為例來看下創(chuàng)建的函數(shù)桥滨。

class NuPlayerFactory : public MediaPlayerFactory::IFactory {
  public:
    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                               const char* url,
                               float curScore) {
        static const float kOurScore = 0.8;

        if (kOurScore <= curScore)
            return 0.0;

        if (!strncasecmp("http://", url, 7)
                || !strncasecmp("https://", url, 8)
                || !strncasecmp("file://", url, 7)) {
            size_t len = strlen(url);
            if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
                return kOurScore;
            }

            if (strstr(url,"m3u8")) {
                return kOurScore;
            }

            if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
                return kOurScore;
            }
        }

        if (!strncasecmp("rtsp://", url, 7)) {
            return kOurScore;
        }

        return 0.0;
    }

    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                               const sp<IStreamSource>& /*source*/,
                               float /*curScore*/) {
        return 1.0;
    }
    //創(chuàng)建播放器
    virtual sp<MediaPlayerBase> createPlayer() {
        ALOGV(" create NuPlayer");
        return new NuPlayerDriver;
    }
};

到此播放器便創(chuàng)建完成窝爪,

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弛车,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蒲每,更是在濱河造成了極大的恐慌纷跛,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邀杏,死亡現(xiàn)場(chǎng)離奇詭異贫奠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)望蜡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門唤崭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脖律,你說我怎么就攤上這事谢肾。” “怎么了小泉?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵芦疏,是天一觀的道長。 經(jīng)常有香客問我微姊,道長酸茴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任兢交,我火速辦了婚禮薪捍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘魁淳。我一直安慰自己飘诗,他們只是感情好与倡,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布界逛。 她就那樣靜靜地躺著,像睡著了一般纺座。 火紅的嫁衣襯著肌膚如雪息拜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天净响,我揣著相機(jī)與錄音少欺,去河邊找鬼。 笑死馋贤,一個(gè)胖子當(dāng)著我的面吹牛赞别,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播配乓,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼仿滔,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼惠毁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起崎页,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤鞠绰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后飒焦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜈膨,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年牺荠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翁巍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡休雌,死狀恐怖曙咽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挑辆,我是刑警寧澤例朱,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站鱼蝉,受9級(jí)特大地震影響洒嗤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜魁亦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一渔隶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧洁奈,春花似錦间唉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至印叁,卻和暖如春被冒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背轮蜕。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工昨悼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人跃洛。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓率触,卻偏偏與公主長得像,于是被迫代替她去往敵國和親汇竭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子葱蝗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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