初探Android中的binder機(jī)制

Binder機(jī)制是Android系統(tǒng)中最主要的進(jìn)程間通信機(jī)制。雖然Android底層使用的是linux內(nèi)核伐割,但是除了匿名管道,socket外,Android并沒(méi)有使用linux中的命名管道萨惑,信號(hào)量,消息隊(duì)列等傳統(tǒng)的IPC通信方式仇矾。Binder猶如一張大網(wǎng)庸蔼,將Android整個(gè)系統(tǒng)中的組件,跨進(jìn)程的組織在一起贮匕。淡化進(jìn)程姐仅,強(qiáng)化組件是Android的一個(gè)設(shè)計(jì)理念。在這個(gè)過(guò)程中刻盐,Binder發(fā)揮了巨大作用掏膏。

binder 的作用

binder的作用可以概括為兩點(diǎn):

  1. IPC:是一種跨進(jìn)程通信手段,但是傳輸數(shù)據(jù)的大小受限制敦锌,不建議傳輸較大數(shù)據(jù)馒疹。

  2. RPC:是一種遠(yuǎn)程過(guò)程調(diào)用手段,即一個(gè)進(jìn)程中可以透明的調(diào)用另外一個(gè)進(jìn)程中的方法乙墙。

兩者經(jīng)常相互伴隨颖变,例如跨進(jìn)程調(diào)用的時(shí)候,參數(shù)的傳遞以及結(jié)果的傳遞等听想。

binder機(jī)制簡(jiǎn)述

binder實(shí)體對(duì)象: 就是binder服務(wù)的提供者腥刹,一個(gè)提供binder服務(wù)的類必須繼承BBinder類(native層),因此binder實(shí)體對(duì)象又叫做BBinder對(duì)象汉买。

binder引用對(duì)象: 是binder服務(wù)提供者在客戶端進(jìn)程的代表肛走,每個(gè)引用對(duì)象類型必須繼承BpBinder類(native層),因此binder引用對(duì)象有叫做BpBinder對(duì)象。

binder代理對(duì)象: 代理對(duì)象簡(jiǎn)單理解為內(nèi)聚了一個(gè)binder引用對(duì)象朽色,因此可以通過(guò)這個(gè)內(nèi)聚的引用對(duì)象發(fā)起RPC調(diào)用邻吞。可以有多個(gè)不同的代理對(duì)象葫男,但卻內(nèi)聚了同一個(gè)引用對(duì)象抱冷。

IBinder對(duì)象: BBinder和BpBinder都是繼承自IBinder.因此binder實(shí)體對(duì)象和binder引用對(duì)象都可以稱為IBinder對(duì)象∩液郑可以通過(guò)IBinder.queryLocalInterface()方法來(lái)判斷到底是binder實(shí)體對(duì)象還是binder引用對(duì)象旺遮。

binder跨進(jìn)程傳輸?shù)臄?shù)據(jù)類型是Parcel。

以RPC為例的示意圖如下:

android_binder-1.png

通過(guò)一個(gè)運(yùn)行在內(nèi)核空間的binder驅(qū)動(dòng)進(jìn)程盈咳,將兩個(gè)用戶空間的進(jìn)程聯(lián)系了起來(lái)耿眉。為解決由于用戶空間進(jìn)程之間虛擬地址相互獨(dú)立而引起的無(wú)法跨進(jìn)程調(diào)用別的進(jìn)程中的對(duì)象方法的難題帶來(lái)了曙光。

通過(guò)BInder引用對(duì)象發(fā)起RPC調(diào)用

假設(shè)App中的MainActivity中以startActivityForResult()方法啟動(dòng)了該App中的Main2Activity鱼响,那么Main2Activity可以通過(guò)AMS這個(gè)binder服務(wù)中的getCallingActivity()方法查詢是誰(shuí)啟動(dòng)了自己鸣剪。

AMS.getCallingActivity():

public ComponentName getCallingActivity(IBinder token)

去參數(shù)是Activity.mToken. 可以通過(guò)反射從客戶端Activity組件中獲取。

1). 獲得AMS的引用binder

AMS作為一個(gè)系統(tǒng)服務(wù)丈积,在Android系統(tǒng)啟動(dòng)過(guò)程中筐骇,會(huì)將自己注冊(cè)到ServiceManager中(注冊(cè)過(guò)程以后在分析)。現(xiàn)在只要知道客戶端可以通過(guò)ServiceManager來(lái)獲得AMS的引用binder即可江滨。

2). 使用引用binder進(jìn)行RPC調(diào)用時(shí)铛纬,需要直到要調(diào)用的方法的編號(hào),這個(gè)編號(hào)可以從Android源碼中獲取唬滑。

在Android 6.0 中該方法編號(hào)如下:

  int GET_CALLING_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+21;

服務(wù)端根據(jù)這個(gè)編號(hào)告唆,執(zhí)行相應(yīng)的邏輯。

3). 方法參數(shù)的傳遞

binder中唯一能的傳遞的數(shù)據(jù)結(jié)構(gòu)就是Parcel晶密,所以必須將方法的參數(shù)打包到Parcel中悔详。針對(duì)不同的數(shù)據(jù)類型Parcle提供了不同的方法,來(lái)將這些對(duì)應(yīng)的數(shù)據(jù)打入Parcel中惹挟。

另外還要準(zhǔn)備一個(gè)Parcel用于接收服務(wù)端的返回?cái)?shù)據(jù)。

4). 發(fā)起RPC調(diào)用

通過(guò)引用對(duì)象的transact()方法缝驳,發(fā)起RPC調(diào)用连锯,絕大多數(shù)情況下,此調(diào)用是一個(gè)同步調(diào)用用狱,也就是說(shuō)會(huì)一直阻塞到服務(wù)端將數(shù)據(jù)返回為止运怖。

但是當(dāng)transact()方法中傳入的flag為FLAG_ONEWAY時(shí),方法會(huì)立即返回夏伊,不會(huì)等到服務(wù)端返回?cái)?shù)據(jù)摇展。

該方法會(huì)最終將上述信息傳入binder驅(qū)動(dòng)中去。

5). 客戶端從返回的Parcel中讀取數(shù)據(jù)

服務(wù)端中將請(qǐng)求的方法執(zhí)行完畢之后溺忧,將方法返回值打入到parcel中咏连,binder驅(qū)動(dòng)將其返回到客戶端組件中盯孙,然后客戶端組件按照調(diào)用方法的返回值類型,從返回的parcel中讀取即可祟滴。


public class Main2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        // 拿到AMS的引用對(duì)象
        IBinder sm = (IBinder) Reflect.on("android.os.ServiceManager").call("getService","activity").get();

        // 拿到方法編號(hào)
        int funCode = IBinder.FIRST_CALL_TRANSACTION+21;

        // 準(zhǔn)備方法參數(shù)數(shù)據(jù)
        Parcel data = Parcel.obtain();
        // 首先要寫(xiě)入的數(shù)據(jù)必須是binder服務(wù)端的descriptor
        data.writeInterfaceToken("android.app.IActivityManager");
        // 接下來(lái)是方法的參數(shù)
        data.writeStrongBinder((IBinder)Reflect.on(this).field("mToken").get());


        // 用于接受返回?cái)?shù)據(jù)
        Parcel reply = Parcel.obtain();

        // 發(fā)起RPC調(diào)用振惰,同步調(diào)用,直到調(diào)用結(jié)束垄懂,期間一直阻塞
        try {
            sm.transact(funCode,data,reply,0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        // 讀取返回?cái)?shù)據(jù)
        reply.readException();

        // 解析返回?cái)?shù)據(jù)
        ComponentName res = ComponentName.readFromParcel(reply);

        // 回收parcle
        data.recycle();
        reply.recycle();

        Log.i("shajia","calling Activity name: "+res.getClassName());
    }

}

通過(guò)binder代理對(duì)象發(fā)起RPC操作

對(duì)于前面例子中獲取調(diào)用者的情況骑晶,實(shí)際開(kāi)發(fā)中都是通過(guò)Activiy.getCallingActivity()來(lái)獲取的:

public ComponentName getCallingActivity() {
       try {
           return ActivityManagerNative.getDefault().getCallingActivity(mToken);
       } catch (RemoteException e) {
           return null;
       }
   }

其中ActivityManagerNative.getDefault()返回的是ActivityManagerProxy對(duì)象。

ActivityManagerProxy是AMS的binder代理類草慧。

binder代理對(duì)象通過(guò)內(nèi)聚的binder引用對(duì)象間接發(fā)起RPC操作桶蛔。對(duì)于系統(tǒng)服務(wù)來(lái)說(shuō),它的binder代理對(duì)象都是事先定義好的漫谷。binder代理對(duì)象還要實(shí)現(xiàn)服務(wù)接口仔雷,實(shí)際上就是對(duì)binder引用對(duì)象發(fā)起RPC操作的二次封裝。

class ActivityManagerProxy implements IActivityManager
{
...............
public ComponentName getCallingActivity(IBinder token)
        throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(token);
    mRemote.transact(GET_CALLING_ACTIVITY_TRANSACTION, data, reply, 0);
    reply.readException();
    ComponentName res = ComponentName.readFromParcel(reply);
    data.recycle();
    reply.recycle();
    return res;
}
...............

可以看到代理類中已經(jīng)幫我們封裝好了getCallingActivity()的操作抖剿。因?yàn)橹苯油ㄟ^(guò)binder引用發(fā)起RPC操作的話朽寞,需要開(kāi)發(fā)者知道方法的編號(hào),而方法的編號(hào)又是隨著Android版本的變化而可能發(fā)生改變的斩郎。所以一般來(lái)說(shuō)都會(huì)為binder服務(wù)封裝一個(gè)binder代理類脑融。這樣做還有一個(gè)好處是通過(guò)一個(gè)binder引用對(duì)象,可以創(chuàng)建多個(gè)binder代理對(duì)象缩宜。

binder服務(wù)分類

分為兩大類:

向ServiceManager注冊(cè)的binder服務(wù)

Android系統(tǒng)中自帶的絕大多數(shù)服務(wù)肘迎,例如AMS,PMS等都會(huì)向ServiceManager注冊(cè),注冊(cè)時(shí)會(huì)傳入一個(gè)service名字锻煌,例如AMS注冊(cè)是傳入的是“activity”妓布。

客戶端可以通過(guò)名字向ServiceManager查詢對(duì)象的binder服務(wù),ServiceManager會(huì)返回一個(gè)IBinder對(duì)象宋梧。

至于說(shuō)返回的IBinder對(duì)象究竟是實(shí)體bidner呢還是引用binder匣沼,按照下面的規(guī)則決定:

  1. 當(dāng)binder服務(wù)端同進(jìn)程請(qǐng)求該服務(wù)時(shí),返回的是binder實(shí)體對(duì)象捂龄。

  2. 當(dāng)請(qǐng)求者與binder服務(wù)端在一個(gè)進(jìn)程時(shí)释涛,返回的是引用對(duì)象。

沒(méi)有向ServiceManager注冊(cè)的的bidner服務(wù)倦沧,又被稱為匿名binder服務(wù)

典型代表就是App中通過(guò)aidl實(shí)現(xiàn)的service組件唇撬。

aidl實(shí)際上幫我們完整實(shí)現(xiàn)了服務(wù)代理類,以及是是實(shí)現(xiàn)了binder服務(wù)類中與語(yǔ)義處理相關(guān)的所有操作展融,例如方法編號(hào)的分配窖认,方法參數(shù)從parcel中的提取,以及返回值打入parcel中等所有的操作。開(kāi)發(fā)者只需要實(shí)現(xiàn)服務(wù)接口即可扑浸。

因?yàn)閍pp是沒(méi)有權(quán)限向ServiceManager注冊(cè)服務(wù)的烧给,那么怎么獲取app中的額service實(shí)體的引用binder呢?首装?创夜?

那就是直接傳遞binder實(shí)體,將binder實(shí)體對(duì)象打入到Parcel中仙逻,跨進(jìn)程傳入到AMS中去驰吓。

Binder實(shí)體在Binder驅(qū)動(dòng)中的傳輸,會(huì)被特殊處理系奉,最終返回到AMS中的是一個(gè)binder引用對(duì)象檬贰。(詳細(xì)過(guò)程后續(xù)在分析嘍!H绷痢N痰印)

其他App進(jìn)程中的組件便可以通過(guò)AMS拿到要請(qǐng)求的service服務(wù)的binder引用對(duì)象了。要注意的是萌踱,此過(guò)程中是AMS將所請(qǐng)求的binder服務(wù)的引用對(duì)象打入Parcel,然后通過(guò)Binder驅(qū)動(dòng)傳遞到請(qǐng)求者進(jìn)程中葵礼。

簡(jiǎn)單的說(shuō)就是Binder實(shí)體對(duì)象的傳遞過(guò)程,伴隨著binder服務(wù)在Binder驅(qū)動(dòng)中相關(guān)數(shù)據(jù)結(jié)構(gòu)初始化以及binder引用對(duì)象的創(chuàng)建過(guò)程并鸵。

不通過(guò)aidl實(shí)現(xiàn)一個(gè)service,來(lái)熟悉一下整個(gè)過(guò)程:

1. 首先頂定義一個(gè)服務(wù)接口鸳粉,即服務(wù)要對(duì)外提供哪些方法。

IBinderService.java:

public interface IBinderService extends IInterface {
    String getMessage();
    /**
     * 服務(wù)的描述园担,客戶端在使用parcel跨進(jìn)程傳輸數(shù)據(jù)的時(shí)候
     * 必須首先寫(xiě)入服務(wù)的描述届谈,即該數(shù)據(jù)是發(fā)給哪個(gè)binder的。
     * 將來(lái)服務(wù)端收到數(shù)據(jù)后會(huì)檢查這個(gè)服務(wù)描述是否和自己的一致弯汰,不一致就不做處理了
     */
    String DESCRIPITON = "MyBinderService";
    // 定義方法編號(hào)
    int GET_MESSAGE = IBinder.FIRST_CALL_TRANSACTION+0;
}

binder服務(wù)接口必須繼承自IInterface接口艰山,該接口中只有一個(gè)方法:

public IBinder asBinder()

binder服務(wù)接口一般要包含三部分內(nèi)容:

首先是該binder服務(wù)的描述DESCRIPITON,發(fā)送數(shù)據(jù)時(shí)必須先發(fā)送該描述咏闪,接收數(shù)據(jù)時(shí)必須先對(duì)該描述進(jìn)行檢查曙搬,和自己不匹配的話那就不用繼續(xù)進(jìn)行了。

然后是方法編號(hào)鸽嫂,這個(gè)編號(hào)實(shí)際含義要在binder實(shí)體對(duì)象中的onTransact()方法中才能體現(xiàn)出來(lái)纵装。可以理解為onTransact()根據(jù)這個(gè)編號(hào)調(diào)用不同的處理分支溪胶。

最后就是該服務(wù)對(duì)外提供的具體方法聲明了。

binder實(shí)體端和代理對(duì)象端必須都繼承這個(gè)服務(wù)接口稳诚,并實(shí)現(xiàn)其中的方法哗脖。另外服務(wù)端還要重載binder的onTransact()方法。

2. 實(shí)現(xiàn)bidner服務(wù)端

binder服務(wù)端的重點(diǎn)在于實(shí)現(xiàn)onTransact()方法,該方法中會(huì)依據(jù)客戶端傳入的方法編號(hào)才避,調(diào)用恰當(dāng)?shù)姆种нM(jìn)行處理橱夭。

處理過(guò)程也是很簡(jiǎn)單的,就是從parcel中解析參數(shù)桑逝,調(diào)用對(duì)應(yīng)的方法執(zhí)行棘劣,將執(zhí)行結(jié)果打入parcel中。

public class BinderServiceStub extends Binder implements IBinderService {

    public BinderServiceStub(){
        // 調(diào)用該方法后binder實(shí)體端的binder.queryLocalInterface()
        // 返回就不會(huì)為null楞遏。
        attachInterface(this,DESCRIPITON);
    }
    // 實(shí)現(xiàn)服務(wù)接口方法
    public String getMessage() {
        return " i am from Message!!!!!";
    }

    /**
     * 顧名思義茬暇,將自身轉(zhuǎn)換為一個(gè)IBinder對(duì)象,
     * 因?yàn)锽inder繼承子Binder,Binder繼承自IBinder
     */
    @Override
    public IBinder asBinder() {
        return this;
    }

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code){
            case GET_MESSAGE:{
                // 客戶端先發(fā)送的是服務(wù)描述寡喝,所以這里先接收服務(wù)描述并判斷是否和自己一致
                data.enforceInterface(DESCRIPITON);
                // 開(kāi)始執(zhí)行客戶端請(qǐng)求的服務(wù)端的方法
                String msg = getMessage();
                // 將結(jié)果打入Parcel
                reply.writeNoException();
                reply.writeString(msg);
                return true;
            }
        }
        /**
         * 必須調(diào)用父類onTransact處理其他code
         */
        return super.onTransact(code, data, reply, flags);
    }


}

實(shí)現(xiàn)binder代理端

前面介紹了糙俗,binder代理對(duì)象類會(huì)內(nèi)聚一個(gè)binder引用對(duì)象,該引用對(duì)象通過(guò)構(gòu)造方法傳入即可:

public class BinderServiceProxy implements IBinderService {

    /**
     * 內(nèi)聚的binder引用對(duì)象
     */
    private IBinder remote;

    public BinderServiceProxy(IBinder binder){
        if(binder.queryLocalInterface(DESCRIPITON) == null )
            remote = binder;
        else
            throw new RuntimeException(" this is not a BpBinder.");
    }


    @Override
    public String getMessage() {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(DESCRIPITON);
        try {
            remote.transact(GET_MESSAGE,data,reply,0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        reply.readException();
        String msg =  reply.readString();
        data.recycle();
        data.recycle();
        return msg;
    }

    @Override
    public IBinder asBinder() {
        return null;
    }
}

這里要特別注意的是,因?yàn)閎inder代理對(duì)象類內(nèi)聚的是一個(gè)binder引用對(duì)象预鬓,所以要對(duì)構(gòu)造方法中傳入的Ibinder對(duì)象進(jìn)行檢查巧骚,保證其是binder引用對(duì)象。

然后就是實(shí)現(xiàn)服務(wù)接口方法格二,這里很簡(jiǎn)單了劈彪,就是組裝Parcel數(shù)據(jù),然后利用引用binder對(duì)象發(fā)起RPC調(diào)用顶猜。

4. 獲取binder引用對(duì)象

這就要借助Android中的service組件了沧奴,并且以bindService()方法啟動(dòng)該service。

首先定義service組件:

public class MyBinderService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new BinderServiceStub();
    }
}

然后在清單文件中驶兜,聲明該service組件扼仲,并且設(shè)置process屬性,保證該service運(yùn)行在另外一個(gè)進(jìn)程中:

<service android:name="com.godin.studydemo.MyBinderService"
                 android:process=":S0"/>

最后以bindService()方式綁定該service:

Intent intent = new Intent();
        intent.setClass(this,MyBinderService.class);
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                if(service.queryLocalInterface(IBinderService.DESCRIPITON)==null){
                    // 得到binder代理對(duì)象
                    BinderServiceProxy proxy = new BinderServiceProxy(service);
                    // 開(kāi)始執(zhí)行方法
                    Log.i("shajia","message: "+proxy.getMessage());
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        },BIND_AUTO_CREATE);

binder 安全基礎(chǔ)

binder服務(wù)端可以通過(guò)binder提供的兩個(gè)api拿到客戶端的uid和pid抄淑,從而決定是否要對(duì)這次請(qǐng)求進(jìn)行處理:


getCallingUid();
getCallingPid();

binder 死亡通知機(jī)制

當(dāng)端服務(wù)進(jìn)程掛掉的時(shí)候屠凶,客戶端是有必要知道的,可以通過(guò)binder引用對(duì)象的linkToDeath()方法來(lái)設(shè)置binder服務(wù)死亡監(jiān)聽(tīng)機(jī)制肆资。

如下代碼所示:

public BinderServiceProxy(IBinder binder){
        if(binder.queryLocalInterface(DESCRIPITON) == null ){
            remote = binder;
            try {
                binder.linkToDeath(new IBinder.DeathRecipient() {
                    @Override
                    public void binderDied() {
                        Log.i("shajia"," binder server is deaded.");
                    }
                },0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        else
            throw new RuntimeException(" this is not a BpBinder.");
    }

可以在死亡通知處理中做一些資源回收的操作矗愧,或者再次重啟服務(wù)等操作。

到現(xiàn)在為止郑原,已經(jīng)對(duì)binder的表象有了一個(gè)大概的了解了唉韭,注意只是表象。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末犯犁,一起剝皮案震驚了整個(gè)濱河市属愤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酸役,老刑警劉巖住诸,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驾胆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贱呐,警方通過(guò)查閱死者的電腦和手機(jī)丧诺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奄薇,“玉大人驳阎,你說(shuō)我怎么就攤上這事∧俚伲” “怎么了呵晚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)远搪。 經(jīng)常有香客問(wèn)我劣纲,道長(zhǎng),這世上最難降的妖魔是什么谁鳍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任癞季,我火速辦了婚禮,結(jié)果婚禮上倘潜,老公的妹妹穿的比我還像新娘绷柒。我一直安慰自己,他們只是感情好涮因,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布废睦。 她就那樣靜靜地躺著,像睡著了一般养泡。 火紅的嫁衣襯著肌膚如雪嗜湃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天澜掩,我揣著相機(jī)與錄音购披,去河邊找鬼。 笑死肩榕,一個(gè)胖子當(dāng)著我的面吹牛刚陡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播株汉,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼筐乳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了乔妈?” 一聲冷哼從身側(cè)響起蝙云,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎路召,沒(méi)想到半個(gè)月后勃刨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體匀泊,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年朵你,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揣非。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抡医,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出早敬,到底是詐尸還是另有隱情忌傻,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布搞监,位于F島的核電站水孩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏琐驴。R本人自食惡果不足惜俘种,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绝淡。 院中可真熱鬧宙刘,春花似錦、人聲如沸牢酵。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)馍乙。三九已至布近,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丝格,已是汗流浹背撑瞧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铁追,地道東北人季蚂。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像琅束,于是被迫代替她去往敵國(guó)和親扭屁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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