Android Binder原理(二)ServiceManager中的Binder機制

本文首發(fā)于微信公眾號「后廠技術(shù)官」

前言

在上一篇文章中睦尽,我們了解了學(xué)習(xí)Binder前必須要了解的知識點荆隘,其中有一點就是Binder機制的三個部分:Java Binder捺宗、Native Binder、Kernel Binder尚粘,其中Java Binder和Native Binder都是應(yīng)用開發(fā)需要掌握的蝗蛙。Java Binder是需要借助Native Binder來工作的蝇庭,因此需要先了解Native Binder,Native Binder架構(gòu)的原型就是基于Binder通信的C/S架構(gòu)捡硅,因此我們先從它開始入手哮内。源碼是基于Android 9.0。

1.基于Binder通信的C/S架構(gòu)

在Android系統(tǒng)中壮韭,Binder進程間的通信的使用是很普遍的,在Android進階三部曲第一部的最后一章,我講解了MediaPlayer框架壕曼,這個框架基于C/S架構(gòu)月褥,并采用Binder來進行進程間通信,如下圖所示屯曹。


uZgTgJ.png

從圖中可以看出狱庇,除了常規(guī)C/S架構(gòu)的Client端和Server端,還包括了ServiceManager是牢,它用于管理系統(tǒng)中的服務(wù)僵井。
首先Server進程會注冊一些Service到ServiceManager中,Client要使用某個Service驳棱,則需要先到ServiceManager查詢Service的相關(guān)信息批什,然后根據(jù)Service的相關(guān)信息與Service所在的Server進程建立通信通路,這樣Client就可以使用Service了社搅。

2.MediaServer的main函數(shù)

Client驻债、Server、ServiceManager三者的交互都是基于Binder通信的形葬,那么任意兩者的交互都可以說明Binder的通信的原理合呐,可以說Native Binder的原理的核心就是ServiceManager的原理,為了更好的了解ServiceManager笙以,這里拿MediaPlayer框架來舉例淌实,它也是學(xué)習(xí)多媒體時必須要掌握的知識點。

MediaPlayer框架的簡單框架圖如下所示猖腕。

uMegMj.png

可以看到拆祈,MediaPlayer和MediaPlayerService是通過Binder來進行通信的,MediaPlayer是Client端倘感,MediaPlayerService是Server端放坏,MediaPlayerService是系統(tǒng)多媒體服務(wù)的一種,系統(tǒng)多媒體服務(wù)是由一個叫做MediaServer的服務(wù)進程提供的老玛,它是一個可執(zhí)行程序淤年,在Android系統(tǒng)啟動時钧敞,MediaServer也被啟動,它的入口函數(shù)如下所示麸粮。
frameworks/av/media/mediaserver/main_mediaserver.cpp

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);
    //獲取ProcessState實例
    sp<ProcessState> proc(ProcessState::self());//1
    sp<IServiceManager> sm(defaultServiceManager());//2
    ALOGI("ServiceManager: %p", sm.get());
    InitializeIcuOrDie();
    //注冊MediaPlayerService
    MediaPlayerService::instantiate();//3
    ResourceManagerService::instantiate();
    registerExtensions();
    //啟動Binder線程池
    ProcessState::self()->startThreadPool();
    //當(dāng)前線程加入到線程池
    IPCThreadState::self()->joinThreadPool();
}

注釋1處用于獲取ProcessState實例溉苛,在這一過程中會打開/dev/binder設(shè)備,并使用mmap為Binder驅(qū)動分配一個虛擬地址空間用來接收數(shù)據(jù)豹休。
注釋2處用來得到一個IServiceManager炊昆,通過這個IServiceManager,其他進程就可以和當(dāng)前的ServiceManager進行交互威根,這里就用到了Binder通信凤巨。
注釋3處用來注冊MediaPlayerService。
除了注釋3處的知識點在下一篇文章進行介紹洛搀,注釋1和注釋2處的內(nèi)容敢茁,本篇文章會分別來進行介紹,先看ProcessState實例留美。

3.每個進程唯一的ProcessState

ProcessState從名稱就可以看出來彰檬,用于代表進程的狀態(tài),先來查看上一小節(jié)的ProcessState的self函數(shù)谎砾。
frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState("/dev/binder");//1
    return gProcess;
}

這里采用了單例模式逢倍,確保每個進程只有一個ProcessState實例。注釋1處用于創(chuàng)建一個ProcessState實例景图,參數(shù)為/dev/binder较雕。接著來查看ProcessState的構(gòu)造函數(shù),代碼如下所示挚币。
frameworks/native/libs/binder/ProcessState.cpp

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))//1
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);//2
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
            close(mDriverFD);
            mDriverFD = -1;
            mDriverName.clear();
        }
    }
    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

ProcessState的構(gòu)造函數(shù)中調(diào)用了很多函數(shù)亮蒋,需要注意的是注釋1處,它用來打開/dev/binder設(shè)備妆毕。
注釋2處的mmap函數(shù)慎玖,它會在內(nèi)核虛擬地址空間中申請一塊與用戶虛擬內(nèi)存相同大小的內(nèi)存,然后再申請物理內(nèi)存笛粘,將同一塊物理內(nèi)存分別映射到內(nèi)核虛擬地址空間和用戶虛擬內(nèi)存空間趁怔,實現(xiàn)了內(nèi)核虛擬地址空間和用戶虛擬內(nèi)存空間的數(shù)據(jù)同步操作,也就是內(nèi)存映射薪前。
mmap函數(shù)用于對Binder設(shè)備進行內(nèi)存映射润努,除了它還有open、ioctl函數(shù)序六,來看看它們做了什么任连。
注釋1處的open_driver函數(shù)的代碼如下所示蚤吹。
frameworks/native/libs/binder/ProcessState.cpp

static int open_driver(const char *driver)
{
    int fd = open(driver, O_RDWR | O_CLOEXEC);//1
    if (fd >= 0) {
        ...
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//2
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
    }
    return fd;
}

注釋1處用于打開/dev/binder設(shè)備并返回文件操作符fd例诀,這樣就可以操作內(nèi)核的Binder驅(qū)動了随抠。注釋2處的ioctl函數(shù)的作用就是和Binder設(shè)備進行參數(shù)的傳遞,這里的ioctl函數(shù)用于設(shè)定binder支持的最大線程數(shù)為15(maxThreads的值為15)繁涂。最終open_driver函數(shù)返回文件操作符fd拱她。

ProcessState就分析倒這里,總的來說它做了以下幾個重要的事:
1.打開/dev/binder設(shè)備并設(shè)定Binder最大的支持線程數(shù)扔罪。
2.通過mmap為binder分配一塊虛擬地址空間秉沼,達到內(nèi)存映射的目的。

4.ServiceManager中的Binder機制

回到第一小節(jié)的MediaServer的入口函數(shù)矿酵,在注釋2處調(diào)用了defaultServiceManager函數(shù)唬复。
frameworks/native/libs/binder/IServiceManager.cpp

sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

    {
        AutoMutex _l(gDefaultServiceManagerLock);
        while (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));//1
            if (gDefaultServiceManager == NULL)
                sleep(1);
        }
    }

    return gDefaultServiceManager;
}

從IServiceManager所在的文件路徑就可以知道,ServiceManager中不僅僅使用了Binder通信全肮,它自身也是屬于Binder體系的敞咧。defaultServiceManager中同樣使用了單例,注釋1處的interface_cast函數(shù)生成了gDefaultServiceManager辜腺,其內(nèi)部調(diào)用了ProcessState的getContextObject函數(shù)休建,代碼如下所示。
frameworks/native/libs/binder/ProcessState.cpp

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
    handle_entry* e = lookupHandleLocked(handle);//1
    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            b = BpBinder::create(handle);//2
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}

getContextObject函數(shù)中直接調(diào)用了getStrongProxyForHandle函數(shù)评疗,注意它的參數(shù)的值為0测砂,那么handle的值就為0,handle是一個資源標識百匆。注釋1處查詢這個資源標識對應(yīng)的資源(handle_entry)是否存在砌些,如果不存在就會在注釋2處新建BpBinder,并在注釋3處賦值給 handle_entry的binder胧华。最終返回的result的值為BpBinder寄症。

4.1 BpBinder和BBinder

說到BpBinder,不得不提到BBinder矩动,它們是Binder通信的“雙子星”有巧,都繼承了IBinder。BpBinder是Client端與Server交互的代理類悲没,而BBinder則代表了Server端篮迎。BpBinder和BBinder是一一對應(yīng)的,BpBinder會通過handle來找到對應(yīng)的BBinder示姿。
我們知道在ServiceManager中創(chuàng)建了BpBinder甜橱,通過handle(值為0)可以找到對應(yīng)的BBinder。


usIeXQ.png

分析完了ProcessState的getContextObject函數(shù)栈戳,回到interface_cast函數(shù):

 gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));

interface_cast具體實現(xiàn)如下所示岂傲。
frameworks/native/libs/binder/include/binder/IInterface.h

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

當(dāng)前的場景中,INTERFACE的值為IServiceManager子檀,那么替換后代碼如下所示镊掖。

inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
{
    return IServiceManager::asInterface(obj);
}

我們接著來分析IServiceManager乃戈。

4.2 解密IServiceManager

BpBinder和BBinder負責(zé)Binder的通信,而IServiceManager用于處理ServiceManager的業(yè)務(wù)亩进,IServiceManager是C++代碼症虑,因此它的定義在IServiceManager.h中。
frameworks/native/libs/binder/include/binder/IServiceManager.h

class IServiceManager : public IInterface
{
public:
    DECLARE_META_INTERFACE(ServiceManager)//1
    ...
    //一些操作Service的函數(shù)
    virtual sp<IBinder>         getService( const String16& name) const = 0;
    virtual sp<IBinder>         checkService( const String16& name) const = 0;
    virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                bool allowIsolated = false,
                                int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
    virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
    enum {
        GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
        CHECK_SERVICE_TRANSACTION,
        ADD_SERVICE_TRANSACTION,
        LIST_SERVICES_TRANSACTION,
    };
};

可以看到IServiceManager繼承了IInterface归薛,其內(nèi)部定義了一些常量和一些操作Service的函數(shù)谍憔,在注釋1處調(diào)用了DECLARE_META_INTERFACE宏,它的定義在IInterface.h中主籍。
frameworks/native/libs/binder/include/binder/IInterface.h

#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const ::android::String16 descriptor;                        \
    static ::android::sp<I##INTERFACE> asInterface(                     \
            const ::android::sp<::android::IBinder>& obj);              \
    virtual const ::android::String16& getInterfaceDescriptor() const;  \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();     

其中INTERFACE的值為ServiceManager习贫,那么經(jīng)過替換后的代碼如下所示。

    static const ::android::String16 descriptor;       
    //定義asInterface函數(shù)
    static ::android::sp<IServiceManager> asInterface(                    
            const ::android::sp<::android::IBinder>& obj);            
    virtual const ::android::String16& getInterfaceDescriptor() const;  
    //定義IServiceManager構(gòu)造函數(shù)
    IServiceManager();          
    //定義IServiceManager析構(gòu)函數(shù)
    virtual ~IServiceManager();     

從DECLARE_META_INTERFACE宏的名稱和上面的代碼中千元,可以發(fā)現(xiàn)它主要聲明了一些函數(shù)和一個變量沈条。那么這些函數(shù)和變量的實現(xiàn)在哪呢?答案還是在IInterface.h中诅炉,叫做IMPLEMENT_META_INTERFACE宏蜡歹,代碼如下所示/
frameworks/native/libs/binder/include/binder/IInterface.h

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
    const ::android::String16&                                          \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \

DECLARE_META_INTERFACE宏和IMPLEMENT_META_INTERFACE宏是配合使用的,很多系統(tǒng)服務(wù)都使用了它們涕烧,IServiceManager使用IMPLEMENT_META_INTERFACE宏只有一行代碼月而,如下所示。
frameworks/native/libs/binder/IServiceManager.cpp

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

IMPLEMENT_META_INTERFACE宏的INTERFACE值為ServiceManager议纯,NAME值為"android.os.IServiceManager"父款,進行替換后的代碼如下所示。

    const ::android::String16 IServiceManager::descriptor("android.os.IServiceManager");          
    const ::android::String16&                                          
            IServiceManager::getInterfaceDescriptor() const {              
        return IServiceManager::descriptor;                                
    } 
     //實現(xiàn)了asInterface函數(shù)
    ::android::sp<IServiceManager> IServiceManager::asInterface(              
            const ::android::sp<::android::IBinder>& obj)               
    {                                                                   
        ::android::sp<IServiceManager> intr;                               
        if (obj != NULL) {                                              
            intr = static_cast<IServiceManager>(                          
                obj->queryLocalInterface(                               
                        IServiceManager::descriptor).get());               
            if (intr == NULL) {                                         
                intr = new BpServiceManager(obj);//1                        
            }                                                           
        }                                                               
        return intr;                                                    
    }                                                                   
    IServiceManager::IServiceManager() { }                                    
    IServiceManager::~IServiceManager() { }                                   

關(guān)鍵的點就在于注釋1處瞻凤,新建了一個BpServiceManager憨攒,傳入的參數(shù)obj的值為BpBinder》Р危看到這里肝集,我們也就明白了,asInterface函數(shù)就是用BpBinder為參數(shù)創(chuàng)建了BpServiceManager蛛壳,從而推斷出interface_cast函數(shù)創(chuàng)建了BpServiceManager杏瞻,再往上推斷,IServiceManager的defaultServiceManager函數(shù)返回的就是BpServiceManager衙荐。
BpServiceManager有什么作用呢捞挥,先從BpServiceManager的構(gòu)造函數(shù)看起。
frameworks/native/libs/binder/IServiceManager.cpp

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

impl的值其實就是BpBinder忧吟,BpServiceManager的構(gòu)造函數(shù)調(diào)用了基類BpInterface的構(gòu)造函數(shù)砌函。
frameworks/native/libs/binder/include/binder/IInterface.h

template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
...
};

BpInterface繼承了BpRefBase,BpRefBase的實現(xiàn)如下所示溜族。
frameworks/native/libs/binder/Binder.cpp

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    if (mRemote) {
        mRemote->incStrong(this);           
        mRefs = mRemote->createWeak(this);  
    }
}

mRemote是一個IBinder* 指針讹俊,它最終的指向為BpBinder雏掠,也就是說BpServiceManager的mRemote指向了BpBinder。那么BpServiceManager的作用也就知道了劣像,就是它實現(xiàn)了IServiceManager,并且通過BpBinder來實現(xiàn)通信摧玫。

4.3 IServiceManager家族

可能上面講的會讓你有些頭暈耳奕,這是因為對各個類的關(guān)系不大明確,通過下圖也許你就會豁然開朗诬像。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4HtEwN0A-1578825026363)(https://s2.ax1x.com/2019/10/08/ufWhRI.png)]

1.BpBinder和BBinder都和通信有關(guān)屋群,它們都繼承自IBinder。
2.BpServiceManager派生自IServiceManager坏挠,它們都和業(yè)務(wù)有關(guān)芍躏。
3.BpRefBase包含了mRemote,通過不斷的派生降狠,BpServiceManager也同樣包含mRemote对竣,它指向了BpBinder,通過BpBinder來實現(xiàn)通信榜配。

5.小節(jié)

本篇文章我們學(xué)到了Binder通信的C/S架構(gòu)否纬,也知道了Native Binder的原理的核心其實就是ServiceManager的原理,為了講解ServiceManager的原理蛋褥,我們需要一個框架來舉例临燃,那就是MediaPlayer框架。在講解MediaServer的入口函數(shù)時烙心,我們遇到了三個問題膜廊,其中前兩個問題相關(guān)的知識點ProcessState和IServiceManager都講解到了,下一篇文章會講解第三個問題淫茵,MediaPlayerService是如何注冊的爪瓜。

更多的見我的原創(chuàng)知識體系:
https://github.com/henrymorgen/android-knowledge-system

這里不僅分享大前端、Android匙瘪、Java等技術(shù)钥勋,還有程序員成長類文章。


qrcode_for_gh_28bf22ba9ab4_258.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辆苔,一起剝皮案震驚了整個濱河市算灸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驻啤,老刑警劉巖菲驴,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異骑冗,居然都是意外死亡赊瞬,警方通過查閱死者的電腦和手機先煎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巧涧,“玉大人薯蝎,你說我怎么就攤上這事“” “怎么了占锯?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缩筛。 經(jīng)常有香客問我消略,道長,這世上最難降的妖魔是什么瞎抛? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任艺演,我火速辦了婚禮,結(jié)果婚禮上桐臊,老公的妹妹穿的比我還像新娘胎撤。我一直安慰自己,他們只是感情好断凶,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布哩照。 她就那樣靜靜地躺著,像睡著了一般懒浮。 火紅的嫁衣襯著肌膚如雪飘弧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天砚著,我揣著相機與錄音次伶,去河邊找鬼。 笑死稽穆,一個胖子當(dāng)著我的面吹牛冠王,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舌镶,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼柱彻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了餐胀?” 一聲冷哼從身側(cè)響起哟楷,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎否灾,沒想到半個月后卖擅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年惩阶,在試婚紗的時候發(fā)現(xiàn)自己被綠了挎狸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡断楷,死狀恐怖锨匆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冬筒,我是刑警寧澤恐锣,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站账千,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏暗膜。R本人自食惡果不足惜匀奏,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望学搜。 院中可真熱鬧娃善,春花似錦、人聲如沸瑞佩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炬丸。三九已至瘫寝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間稠炬,已是汗流浹背焕阿。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留首启,地道東北人暮屡。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像毅桃,于是被迫代替她去往敵國和親褒纲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

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