Binder牌膠水

Binder牌膠水章咧,如雷貫耳闷盔,在Android中無處不在弯洗,是每個Android程序猿居家旅行必備。有了它的存在逢勾,我們甚至可以不用深入了解App進(jìn)程和系統(tǒng)進(jìn)程牡整、用戶空間和內(nèi)核空間、跨進(jìn)程通訊等概念也可以做好應(yīng)用層開發(fā)溺拱。但是呢逃贝,閱讀本文之前,還是建議先看看《Binder學(xué)習(xí)指南》了解下這些概念迫摔。

Binder屬于“問題領(lǐng)域”的命名沐扳?見名知意,作為膠水句占,“粘合”是他的主要職責(zé)沪摄。在Androd世界里,他到底粘合了什么纱烘?比如我們經(jīng)常使用的startActivity()就涉及到進(jìn)程通訊杨拐,Binder粘合了這些進(jìn)程,弱化了我們對進(jìn)程的感知凹炸,降低了開發(fā)難度。

本文來聊聊四瓶Binder膠水昼弟,他們功效不同啤它,配方卻完全一致。此文的重點有兩個舱痘,其一变骡,介紹下他們的配方,也就是類圖模型芭逝,了解他們塌碌,對我們閱讀Android源碼,尋找源碼的位置有很大的幫助旬盯;其二台妆,既然作為膠水翎猛,我們要研究下他粘合了什么東西,粘合了哪些進(jìn)程接剩。這四瓶膠水的功效和配方分別是:

  1. AIDL:
    IInterface--Stub--Proxy--Stub具體實現(xiàn)
  2. ContentProvider:
    IContentProvider--ContentProviderNative--ContentProviderProxy--ContentProvider.Transport
  3. 管理四大組件的AMS:
    IActivityManager--ActivityManagerNative--ActivityManagerProxy--ActivityManagerService
  4. 負(fù)責(zé)ActivityThread和AMS之間的通訊
    IApplicationThread--ApplicationThreadNative--ApplicationThreadProxy--ApplicationThread

Binder文章很多切厘,很難寫出彩,相比于一言不合就曬C++代碼懊缺,曬cpp文件的疫稿,本文重點還是從Java層出發(fā)解釋Binder機(jī)制。本文所有代碼在此:
https://github.com/geniusmart/binder-project

Binder膠水的原始配方

image

如上圖鹃两,IInterface/IBinder/Binder/BinderProxy是Binder機(jī)制的核心api遗座,理解這些接口/類,是研究Binder的前提俊扳。

接口通常代表所具備的能力途蒋,比如我們熟悉的Api里,SerializableParcelable代表其實現(xiàn)類是可序列化的拣度;Iterable代表可迭代遍歷碎绎,因此其實現(xiàn)類HashSetArrayList可使用Iterator進(jìn)行遍歷。

在這個類圖的最頂層抗果,有兩個接口筋帖,IInterfaceIBinderIBinder代表跨進(jìn)程傳輸?shù)哪芰?/strong>冤馏,而IInterface則代表遠(yuǎn)程服務(wù)端具備的能力日麸。

BinderIBinder的實現(xiàn)類,因此它具備跨進(jìn)程傳輸?shù)哪芰Υ猓鼘嶋H上就是遠(yuǎn)程Server端的Binder對象本身代箭。

Binder對象是給Server端對象本身,是Server進(jìn)程用的涕刚,與此對應(yīng)的BinderProxy則是遠(yuǎn)程Binder的代理對象嗡综,給Client進(jìn)程用的(源碼位于Binder類內(nèi)部)。在跨越進(jìn)程的時候杜漠,Binder驅(qū)動會自動完成這兩個對象的轉(zhuǎn)換极景。

以上都是冷冰冰的理論,讀到這里我們?nèi)匀缓芾Щ蠹蒈睿覀冃枰苡H手掌控兩個進(jìn)程:Client進(jìn)程和Server進(jìn)程盼樟,并進(jìn)行通訊,以此來熟悉Binder機(jī)制锈至。因此晨缴,第一瓶膠水應(yīng)運而生——AIDL,AIDL能實現(xiàn)這個需求峡捡。

以上四個類是android.os包給我們提供的Binder機(jī)制相關(guān)的api击碗,基于這四個類筑悴,我們可以擴(kuò)展出各種各樣的Binder模型,實現(xiàn)各種各樣的跨進(jìn)程傳輸?shù)膱鼍把佣肌6疚乃枋龅乃钠磕z水便是基于此套api的四種實現(xiàn)雷猪。

第一瓶膠水AIDL

假設(shè)你已經(jīng)熟練掌握了AIDL,首先寫個ICompute.aidl晰房,代碼很簡單求摇,如下:

// ICompute.aidl
package com.geniusmart.binder.aidl;

interface ICompute {
    int add(int a,int b);
}

此時,編譯器會幫我們生成一個ICompute.java文件殊者,這個類的可讀性很差与境,為方便大家查閱,我將代碼做了格式化猖吴,并拷貝一份放在temp包下摔刁,點擊這里查看

這個類的細(xì)節(jié)我不打算多講海蔽,大家可以查看一下文章開篇的那篇文章共屈。對照著生成出來的ICompute.java文件,繪制如下Binder模型圖:

image

1. 熟悉的配方:ICompute-Proxy-Stub-Stub具體實現(xiàn)

通過上圖党窜,我們發(fā)現(xiàn)AIDL的Binder模型是基于原始配方的擴(kuò)展拗引。當(dāng)我們寫完ICompute.aidl之后,ICompute幌衣,Stub矾削,Proxy已經(jīng)自動生成出來,他們的作用如下:

  • ICompute接口繼承了IInterface豁护,并寫了add(a,b)的方法哼凯,代表Server端進(jìn)程具備計算兩數(shù)相加的能力。此方法將在Stub的具體實現(xiàn)類中重寫楚里。
  • Stub是一個抽象類断部,他本質(zhì)是一個Binder,他存在的目的之一是約定好asInterface班缎,asBinder蝴光,onTransact方法,減少我們開發(fā)具體Binder對象的工作量吝梅。此外虱疏,Stub即需要跨進(jìn)程傳輸惹骂,又需要約定遠(yuǎn)端服務(wù)端具備的能力苏携,因此他需要同時實現(xiàn)IInterfaceIBinder接口,通過上文的類圖可以看得出來对粪。
  • Proxy是代理對象右冻,它在Client進(jìn)程中使用装蓬,作用是以假亂真。他持有BinderProxy對象纱扭,BinderProxy能幫我們訪問服務(wù)端Binder對象(本例中即Stub具體實現(xiàn)類)的能力牍帚。

AIDL讓我們可以飯來張口衣來伸手,但是乳蛾,服務(wù)端具備的具體能力暗赶,AIDL是沒法給的,需要我們自力更生肃叶,所以接下來我們來寫個Stub的具體實現(xiàn)蹂随,并驗證下這個Binder模型的準(zhǔn)確性。

2.驗證遠(yuǎn)程對象和代理對象

在Server進(jìn)程啟動一個Service因惭,定義Stub的實現(xiàn)類ComputeBinder岳锁,等待Client進(jìn)程的連接,代碼如下:

public class ComputeService extends Service {

    public static final String TAG = "Server進(jìn)程";

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

    private static class ComputeBinder extends ICompute.Stub {

        @Override
        public int add(int a, int b) throws RemoteException {
            Log.i(TAG, TAG + this.getClass().getName() + "執(zhí)行add()");
            return a + b;
        }
    }
}

接下來蹦魔,我們來寫連接遠(yuǎn)程服務(wù)的代碼 激率,核心代碼如下:(完整代碼點擊查看)

private ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.i(TAG, TAG + "觸發(fā)onServiceConnected : " + service.getClass().getName());
        mICompute = ICompute.Stub.asInterface(service);
        Log.i(TAG, TAG + "觸發(fā)asInterface : " + mICompute.getClass().getName());
        Log.i(TAG, TAG + "觸發(fā)add() : 遠(yuǎn)程方法執(zhí)行結(jié)果為" + mICompute.add(3, 5));
    }
};

這里我設(shè)計了兩種場景,分別讓Server進(jìn)程和Client進(jìn)程執(zhí)行連接遠(yuǎn)程服務(wù)勿决,輸出結(jié)果如下:

  • Client進(jìn)程綁定Server進(jìn)程的Service獲取Binder
    (1)Client進(jìn)程輸出日志:
Client進(jìn)程觸發(fā)onServiceConnected : android.os.BinderProxy
Client進(jìn)程觸發(fā)asInterface : ICompute$Stub$Proxy
Client進(jìn)程觸發(fā)add() : result = 8

(2)Server進(jìn)程輸出日志:

Server進(jìn)程ComputeService$ComputeBinder執(zhí)行add()
  • Server進(jìn)程綁定自身進(jìn)程內(nèi)的Service獲取Binder
    Server進(jìn)程輸出日志:
Server進(jìn)程觸發(fā)onServiceConnected : ComputeService$ComputeBinder
Server進(jìn)程觸發(fā)asInterface : ComputeService$ComputeBinder
Server進(jìn)程ComputeService$ComputeBinder執(zhí)行add()
Server進(jìn)程觸發(fā)add() : 遠(yuǎn)程方法執(zhí)行結(jié)果為8

結(jié)論:

  • 當(dāng)Client進(jìn)程連接遠(yuǎn)程時乒躺,會經(jīng)過如下步驟:客戶端獲得BinderProxy對象->轉(zhuǎn)換為ICompute$Stub$Proxy->服務(wù)端ComputeService$ComputeBinder執(zhí)行相應(yīng)的方法,并將數(shù)據(jù)返回給客戶端->客戶端取得數(shù)據(jù)剥险。
  • 當(dāng)Server進(jìn)程連接自身時聪蘸,始終調(diào)用的是Binder本體對象ComputeService$ComputeBinder

3.工作原理

說好了不談細(xì)節(jié),但是對于講清楚Binder機(jī)制來說表制,不談細(xì)節(jié)臣妾真的做不到健爬,受限于篇幅,我還是克制住了么介,取而代之的是一張基于aidl的工作流程圖娜遵,與其貼代碼講細(xì)節(jié),還不如大家對照源碼和流程圖自己解析aidl的工作原理壤短。如下:

4. 這瓶膠水粘合了什么设拟?

這個問題對于AIDL來說很簡單,他粘合了需要通訊的兩個進(jìn)程久脯,在上文我們稱之為Server進(jìn)程和Client進(jìn)程纳胧,在上文的UML類圖中也有所體現(xiàn)。

第二瓶膠水ContentProvider

為了鞏固這個模型帘撰,Binder牌膠水隆重推出第二個款式ContentProvider跑慕。談起跨進(jìn)程,我們自然而然會想起內(nèi)容提供者。即使你不了解ContentProvider的原理核行,我們平常在使用api的時候牢硅,所做的事情就是讓內(nèi)容使用者進(jìn)程去訪問內(nèi)容提供者進(jìn)程的數(shù)據(jù),所以這第二瓶膠水很貼近我們?nèi)粘5腁ndroid開發(fā)生活芝雪。

首先先給出結(jié)論减余,也就是有關(guān)ContentProvider的Binder模型圖:

1. ContentProvider Binder模型來源

接下來我們來分析下這張圖是怎么來的:
作為一名Coder,應(yīng)該永遠(yuǎn)保持好奇心惩系,使用ContentProvider時位岔,我們經(jīng)常用這樣的api:getContentResolver().query()/insert()/update()/delete(),你只要點進(jìn)去看看源碼堡牡,都能很輕易發(fā)現(xiàn)這個模型圖赃承,這個過程大概是這樣的:

  • (1) 從內(nèi)容使用者的角度出發(fā),查看insert()源碼
  • (2) 發(fā)現(xiàn)關(guān)鍵代碼IContentProvider provider = acquireProvider(url);
  • (3) 活捉一只IInterface的子接口IContentProvider悴侵,對應(yīng)AIDL的ICompute
  • (4) 那么問題來了瞧剖,對應(yīng)的Proxy\Stub\Stub具體實現(xiàn)在哪?一籌莫展中可免。
  • (5) 此路不通抓于,換一條路,即從內(nèi)容提供者角度出發(fā)浇借,查看 ContentProvider的源碼捉撮,找找線索。
  • (6) AS切換到Structure視圖妇垢,觀察類的結(jié)構(gòu)巾遭,此時應(yīng)該有點運氣成分,我們發(fā)現(xiàn)了內(nèi)部類Transport闯估,他的繼承關(guān)系是:class Transport extends ContentProviderNative{}灼舍。雖說此步需要點運氣,但是Transport的中文意思為運輸涨薪,頗有點跨進(jìn)程傳輸?shù)囊馑计锼兀砸膊⒎呛翢o根據(jù)。
  • (7) 看ContentProviderNative源碼刚夺,發(fā)現(xiàn)其繼承關(guān)系class ContentProviderNative extends Binder implements IContentProvider{}献丑,這就是我們熟悉的模型啊,對應(yīng)AIDL中的Stub侠姑,而Transport則對應(yīng)著Stub的具體實現(xiàn)類ComputeBinder创橄。
  • (8) 在ContentProviderNative內(nèi)部,與他同一級的還有一個類莽红,即ContentProviderProxy妥畏,至此,Binder模型相關(guān)的4個類或接口,我們已經(jīng)集齊完畢咖熟。
  • (9) 最后,召喚神龍柳畔,深入學(xué)習(xí)ContentProvider的原理馍管。

2.驗證遠(yuǎn)程對象和代理對象

ContentProvider與AIDL不一樣,AIDL中Binder對象可以輕易拿到薪韩,而我們在使用ContentProvider時候确沸,通常都是通過ContentResolver來執(zhí)行CRUD的操作,顯然俘陷,他并不是一個Binder對象罗捎,追溯其源碼,我們可以發(fā)現(xiàn)這樣一行關(guān)鍵的代碼:

public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {
IContentProvider provider = acquireProvider(url);
//省略若干代碼..

}

看到返回類型IContentProvider時就是你大聲呼喊“真相只有一個”的時候拉盾,閱讀源碼的樂趣就在于抽絲剝繭桨菜,輕解衣裳,窺探最本真和純潔的胴體捉偏。倒得。。

這時候問題又來了夭禽,acquireProvider(url)是一個@hide方法霞掺,沒法直接調(diào)用。解決辦法很簡單讹躯,即使用反射菩彬。核心代碼如下:

Uri uri = Uri.parse("[content://com.geniusmart.binder.AccountProvider/account](https://link.jianshu.com?t=content://com.geniusmart.binder.AccountProvider/account)");
ContentResolver contentResolver = getContentResolver();
//通過反射調(diào)用hide方法
Method method = ContentResolver.class.getMethod("acquireProvider", new Class[]{Uri.class});
Object object = method.invoke(contentResolver, uri);
//打印Binder類型
Log.i(TAG, object.getClass().toString());

與AIDL中的驗證思路一樣,我們來分別驗證下客戶端和服務(wù)端執(zhí)行此段邏輯之后的結(jié)果:

  • Client進(jìn)程使用Server進(jìn)程的ContentProvider
    輸出結(jié)果為:class android.content.ContentProviderProxy
  • Server進(jìn)程使用自己的ContentProvider
    輸出結(jié)果為:class android.content.ContentProvider$Transport

結(jié)論:Client進(jìn)程通過ContentProviderProxy訪問Server進(jìn)程的ContentProvider$Transport潮梯,實現(xiàn)進(jìn)程間通訊骗灶。

以上所有代碼均在文章開篇的Github項目里。

3. 這瓶膠水粘合了什么秉馏?

這個問題也比較簡單矿卑,ContentProvider這瓶膠水粘合了內(nèi)容使用者和內(nèi)容提供者兩個進(jìn)程,寫ContentProvider的這一方稱之為Server進(jìn)程沃饶,用ContentResolver的這一方稱之為Client進(jìn)程母廷,兩個進(jìn)程通過Binder進(jìn)行通訊。

另外兩瓶膠水AMS和ApplicationThread

AIDL和ContentProvider這兩個Binder模型糊肤,都有清晰的Client進(jìn)程和Server進(jìn)程琴昆,理解起來相對容易,而另外兩個Binder模型所涉及到的進(jìn)程雙方則比較模糊馆揉。AMS和ApplicationThread有著千絲萬縷的關(guān)系业舍,所以我們放在一起講。首先貼一下這兩瓶膠水的配方:

AMS的Binder模型
ApplicationThread的Binder模型

看到這兩個Binder模型圖,真是感慨舷暮,這簡直是一樣的配方态罪,熟悉的味道,所以以后如果有看到類似IXxxx/XxxxProxy/XxxxNative/Xxxx的命名規(guī)則下面,一定要想起這是Binder的配方复颈。

Binder模型來源

這兩個Binder模型圖從何而來?
在一個夜黑風(fēng)高的晚上沥割,你我寂寞難耐耗啦,準(zhǔn)備Fuck Source Code,于是決定挑個并不軟的柿子來捏一捏机杜,他就是startActivity()帜讲,大概會這么一些個前戲:
(1)context.startActivity()
(2)mBase.startActivity()
(3)ContextImpl.startActivity()
(4)mMainThread.getInstrumentation().execStartActivity()
(5)Instrumentation.execStartActivity()

源碼閱到這里已經(jīng)有一個小高潮了,因為我們發(fā)現(xiàn)了如下代碼:


//IApplicationThread 是IInterface類型
IApplicationThread whoThread = (IApplicationThread) contextThread;
//ActivityManagerNative是Binder和IInterface類型
ActivityManagerNative.getDefault().startActivityAsUser()

此時Binder機(jī)制的雛形我們已經(jīng)心中有數(shù),之后少俠們可以各自發(fā)揮椒拗,深入理解這兩個Binder機(jī)制的作用似将,獲得更多的快感。

所以蚀苛,理解這個模型的意義在于玩郊,當(dāng)我們看到XxxxProxy執(zhí)行邏輯時,當(dāng)前進(jìn)程所屬的角色是Client進(jìn)程枉阵,要查看該邏輯源碼的時候译红,應(yīng)該找到Server進(jìn)程的Xxxx類查看。

Activity的啟動流程的解析漫長而枯燥兴溜,不是此文的重點侦厚,大家了解下這兩個類的意義即可:

  • ActivityManagerService
    AMS是Android中最核心的服務(wù),主要負(fù)責(zé)系統(tǒng)中四大組件的啟動、切換、調(diào)度及應(yīng)用進(jìn)程的管理和調(diào)度等工作呼巷。
  • ApplicationThread
    ApplicationThreadActivityThread的內(nèi)部類,負(fù)責(zé)ActivityThreadActivityManagerService之間的通訊想诅。

這兩瓶膠水粘合了哪些進(jìn)程?

通過Activity啟動流程圖我們來看下這兩個Binder模型是如何發(fā)揮作用的岛心,如下圖:

Activity啟動流程圖

注:此張圖片來源于這篇文章《startActivity流程分析(一)》来破,已征得博主同意引用在此處。

在這張圖里忘古,我們意識到除了第一徘禁、二瓶膠水描述到的App進(jìn)程之外,Android世界里還有Launcher進(jìn)程髓堪,系統(tǒng)進(jìn)程等等送朱,而Binder在其中如魚得水娘荡,散發(fā)著萬丈光芒。

AMS位于系統(tǒng)進(jìn)程驶沼,處于Server進(jìn)程的位置炮沐,Launcher進(jìn)程和App進(jìn)程作為Client進(jìn)程,持有ActivityManagerProxy回怜,與AMS進(jìn)行通訊大年,召喚四大組件。而ApplicationThread位于應(yīng)用進(jìn)程鹉戚,處于Server進(jìn)程的位置,系統(tǒng)進(jìn)程則作為Client進(jìn)程专控,持有ApplicationThreadProxy抹凳,使得應(yīng)用進(jìn)程中的主線程(ActivityThread)和AMS之間可以進(jìn)行通訊。

至此伦腐,對于Binder機(jī)制的認(rèn)知應(yīng)該要有所升華赢底。

總結(jié)

用一張表格描述一下上文所講的四個Binder模型:

能力 IInterface Binder抽象 BinderProxy Binder
AIDL ICompute Stub Proxy ComputeBinder
內(nèi)容提供者 IContentProvider ContentProviderNative ContentProviderProxy ContentProvider.Transport
AMS IActivityManager ActivityManagerNative ActivityManagerProxy ActivityManagerService
ActivityThread和AMS之間的通訊 IApplicationThread ApplicationThreadNative ApplicationThreadProxy ApplicationThread

Binder并不神秘,對于應(yīng)用層來說柏蘑,Binder便是上文中我所繪制的各種模型圖幸冻,我們需要明確兩點,第一咳焚,Proxy作為代理對象洽损,以假亂真,Client進(jìn)程通過持有Proxy對象革半,進(jìn)而調(diào)用Server進(jìn)程中實際Binder對象的能力碑定;第二,在使用任何一個Binder對象時又官,我們要明確延刘,此時進(jìn)行通訊的是哪兩個進(jìn)程,以及哪個進(jìn)程充當(dāng)Client或Server進(jìn)程六敬。

最后多說一句碘赖,關(guān)于Binder寫了那么多,大牛們自成體系自然無需閱讀此小文外构,而小小牛們看完之后也許仍然十分懵懂普泡,所以寫B(tài)inder文章略顯尷尬,而在這個過程中收獲最大的其實是作者本人审编。學(xué)習(xí)Binder劫哼,沒有捷徑,找準(zhǔn)切入點(本文的切入點在于應(yīng)用層的Binder模型以及每種模型涉及通訊的兩個進(jìn)程)割笙,然后Read the Fucking Source Code权烧,最后寫寫文章做總結(jié)眯亦。

參考文章

Binder學(xué)習(xí)指南
startActivity流程分析(一)
Android應(yīng)用程序組件Content Provider簡要介紹和學(xué)習(xí)計劃
Android進(jìn)程間通信(IPC)機(jī)制Binder簡要介紹和學(xué)習(xí)計劃

作者:geniusmart
鏈接:http://www.reibang.com/p/3d053abba04b
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)般码,非商業(yè)轉(zhuǎn)載請注明出處妻率。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市板祝,隨后出現(xiàn)的幾起案子宫静,更是在濱河造成了極大的恐慌,老刑警劉巖券时,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孤里,死亡現(xiàn)場離奇詭異,居然都是意外死亡橘洞,警方通過查閱死者的電腦和手機(jī)捌袜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炸枣,“玉大人虏等,你說我怎么就攤上這事∈食Γ” “怎么了霍衫?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長侯养。 經(jīng)常有香客問我敦跌,道長,這世上最難降的妖魔是什么逛揩? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任峰髓,我火速辦了婚禮,結(jié)果婚禮上息尺,老公的妹妹穿的比我還像新娘携兵。我一直安慰自己,他們只是感情好搂誉,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布徐紧。 她就那樣靜靜地躺著,像睡著了一般炭懊。 火紅的嫁衣襯著肌膚如雪并级。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天侮腹,我揣著相機(jī)與錄音嘲碧,去河邊找鬼。 笑死父阻,一個胖子當(dāng)著我的面吹牛愈涩,可吹牛的內(nèi)容都是我干的望抽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼履婉,長吁一口氣:“原來是場噩夢啊……” “哼煤篙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起毁腿,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤辑奈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后已烤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸠窗,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年胯究,在試婚紗的時候發(fā)現(xiàn)自己被綠了稍计。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡唐片,死狀恐怖丙猬,靈堂內(nèi)的尸體忽然破棺而出涨颜,到底是詐尸還是另有隱情费韭,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布庭瑰,位于F島的核電站星持,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏弹灭。R本人自食惡果不足惜督暂,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望穷吮。 院中可真熱鬧逻翁,春花似錦、人聲如沸捡鱼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驾诈。三九已至缠诅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乍迄,已是汗流浹背管引。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留闯两,地道東北人褥伴。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓谅将,卻偏偏與公主長得像,于是被迫代替她去往敵國和親噩翠。 傳聞我的和親對象是個殘疾皇子戏自,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345