IPC機(jī)制 -- IPC方式 -- AIDL(2)

工作過(guò)程

在寫(xiě)完AIDL文件后攒驰,編譯器會(huì)幫我們自動(dòng)生成一個(gè)同名的 .java 文件,在我們實(shí)際編寫(xiě)客戶(hù)端和服務(wù)端代碼的過(guò)程中故爵,真正協(xié)助我們工作的其實(shí)是這個(gè) .java 文件玻粪,而 .aidl 文件從頭到尾都沒(méi)有出現(xiàn)過(guò)。事實(shí)上诬垂,就算我們不寫(xiě)AIDL文件劲室,直接按照它生成的 .java 文件那樣寫(xiě)一個(gè) .java 文件出來(lái),在服務(wù)端和客戶(hù)端中也可以照常使用這個(gè) .java 類(lèi)來(lái)進(jìn)行跨進(jìn)程通信结窘。所以說(shuō)AIDL語(yǔ)言只是在簡(jiǎn)化我們寫(xiě)這個(gè) .java 文件的工作而已很洋,而要研究AIDL是如何幫助我們進(jìn)行跨進(jìn)程通信的,其實(shí)就是研究這個(gè)生成的 .java 文件是如何工作的隧枫。

//BookManager.java
//接口喉磁,繼承接口
public interface BookManager extends android.os.IInterface { 
    //抽象類(lèi),繼承Binder官脓、實(shí)現(xiàn)接口
    public static abstract class Stub extends android.os.Binder implements com.tomorrow.androidtest7.aidl.BookManager {
        //靜態(tài)內(nèi)部類(lèi)协怒,實(shí)現(xiàn)接口
        private static class Proxy implements com.tomorrow.androidtest7.aidl.BookManager {
        }
    }
}

當(dāng)客戶(hù)端和服務(wù)端都位于同一進(jìn)程時(shí),方法調(diào)用不會(huì)走跨進(jìn)程的transact過(guò)程卑笨,由Stub類(lèi)負(fù)責(zé)孕暇;
而當(dāng)兩者位于不同進(jìn)程時(shí),方法調(diào)用需要走transact過(guò)程,由Stub的內(nèi)部代理類(lèi)Proxy來(lái)完成妖滔。

一派草、通過(guò)AIDL生成的 .java 文件位置

完整路徑是:app==>build==>generated==>source==>aidl==>debug==>com==>tomorrow==>androidtest7==>aidl==>BookManager.java(其中 com.tomorrow.androidtest7是包名,相對(duì)應(yīng)的AIDL文件為 BookManager.aidl )铛楣。在Android Studio里面目錄組織方式由默認(rèn)的 Android 改為 Project 就可以直接按照文件夾結(jié)構(gòu)訪問(wèn)到它近迁。

二、從應(yīng)用看原理

先不看冗雜的源碼簸州,從實(shí)際的應(yīng)用著手鉴竭,輔以思考分析,試圖尋找突破點(diǎn)岸浑。
從服務(wù)端開(kāi)始搏存,去掉其他無(wú)關(guān)的東西,從宏觀上分析:

//AIDLService.java
//由AIDL文件生成的BookManager
private final BookManager.Stub mBookManager = new BookManager.Stub() {
    @Override
    public List<Book> getBooks() throws RemoteException {
        //省略
    }

    @Override
    public void addBookWithTagIn(Book book) throws RemoteException {
        //省略
    }

    @Override
    public void addBookWithTagOut(Book book) throws RemoteException {
        //省略
    }

    @Override
    public void addBookWithTagInOut(Book book) throws RemoteException {
        //省略
    }
};

對(duì) BookManagerStub 里面的方法進(jìn)行了重寫(xiě)矢洲,這些方法是在 AIDL 文件里面定義的璧眠。也就是說(shuō),在這里為之前定義的方法提供了具體實(shí)現(xiàn)读虏。接著责静,在 onBind() 方法里將這個(gè) BookManagerStub 作為返回值傳遞過(guò)去。

接著看客戶(hù)端:

//AIDLActivity.java
private BookManager mBookManager = null;
private ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mBookManager = BookManager.Stub.asInterface(service);
        //省略
        mBooks = mBookManager.getBooks();
        //省略
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        //省略
    }
};

獲取 BookManager 對(duì)象盖桥,然后調(diào)用它里面的方法灾螃。

三、從客戶(hù)端開(kāi)始

//客戶(hù)端獲取 BookManager 對(duì)象:
//AIDLActivity.java
@Override
public void onServiceConnected(ComponentName name, IBinder service) { //IBinder service 為 BookManager$Stub 對(duì)象
    mBookManager = BookManager.Stub.asInterface(service);
}

//BookManager$Stub#asInterface:
public static com.tomorrow.androidtest7.aidl.BookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); //搜索本地是否已經(jīng)有可用的對(duì)象
if (((iin!=null)&&(iin instanceof com.tomorrow.androidtest7.aidl.BookManager))) {
return ((com.tomorrow.androidtest7.aidl.BookManager)iin); //如果本地有就將其返回
}
return new com.tomorrow.androidtest7.aidl.BookManager.Stub.Proxy(obj); //如果本地沒(méi)有就重新創(chuàng)建一個(gè)并返回
}

//BookManager$Stub$Proxy:客戶(hù)端最終通過(guò)這個(gè)類(lèi)與服務(wù)端進(jìn)行通信
private static class Proxy implements com.tomorrow.androidtest7.aidl.BookManager {
private android.os.IBinder mRemote;
}

Proxy(android.os.IBinder remote) //此處的 remote 正是前面我們提到的 IBinder service揩徊,即 BookManager$Stub 對(duì)象
{
    mRemote = remote;
}

@Override public java.util.List<com.tomorrow.androidtest7.aidl.Book> getBooks() throws android.os.RemoteException
{
    //省略
}

@Override public void addBookWithTagIn(com.tomorrow.androidtest7.aidl.Book book) throws android.os.RemoteException
{
    //省略
}

@Override public void addBookWithTagOut(com.tomorrow.androidtest7.aidl.Book book) throws android.os.RemoteException
{
    //省略
}

@Override public void addBookWithTagInOut(com.tomorrow.androidtest7.aidl.Book book) throws android.os.RemoteException
{
    //省略
}

//客戶(hù)端調(diào)用服務(wù)端的方法:
//BookManager$Stub$Proxy#getBooks:
@Override public java.util.List<com.tomorrow.androidtest7.aidl.Book> getBooks() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain(); //_data用來(lái)存儲(chǔ)客戶(hù)端流向服務(wù)端的數(shù)據(jù)流(參數(shù))
android.os.Parcel _reply = android.os.Parcel.obtain(); //_reply用來(lái)存儲(chǔ)服務(wù)端流回客戶(hù)端的數(shù)據(jù)流(參數(shù)及返回值)
java.util.List<com.tomorrow.androidtest7.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//調(diào)用 transact() 方法將方法id和兩個(gè) Parcel 容器傳過(guò)去
mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
_reply.readException();
//從_reply中取出服務(wù)端執(zhí)行方法的結(jié)果
_result = _reply.createTypedArrayList(com.tomorrow.androidtest7.aidl.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
//將結(jié)果返回
return _result;
}

關(guān)于 transact() 方法:這是客戶(hù)端和服務(wù)端通信的核心方法腰鬼。
調(diào)用這個(gè)方法之后,客戶(hù)端將會(huì)掛起當(dāng)前線程塑荒,等待服務(wù)端執(zhí)行完相關(guān)任務(wù)后的通知并接收返回的 _reply 數(shù)據(jù)流熄赡。關(guān)于這個(gè)方法的參數(shù)有兩點(diǎn)需要說(shuō)明:
(1)第一個(gè)參數(shù):是一個(gè)方法 ID ,這個(gè)是客戶(hù)端與服務(wù)端約定好的給方法的編碼齿税,彼此一一對(duì)應(yīng)彼硫。在AIDL文件轉(zhuǎn)化為 .java 文件的時(shí)候,系統(tǒng)將會(huì)自動(dòng)給AIDL文件里面的每一個(gè)方法自動(dòng)分配一個(gè)方法 ID偎窘。
(2)第四個(gè)參數(shù):是一個(gè) int 值乌助,它的作用是設(shè)置進(jìn)行 IPC 的模式溜在,為 0 表示數(shù)據(jù)可以雙向流通,即 _reply 流可以正常的攜帶數(shù)據(jù)回來(lái)掖肋;為 1 表示數(shù)據(jù)將只能單向流通仆葡,從服務(wù)端回來(lái)的 _reply 流將不攜帶任何數(shù)據(jù)。 AIDL生成的 .java 文件的這個(gè)參數(shù)均為 0。

BookManagerStubProxy的工作過(guò)程:
(1)生成 _data 和 _reply 數(shù)據(jù)流沿盅,并向 _data 中存入客戶(hù)端的數(shù)據(jù)把篓;
(2)通過(guò) transact() 方法將它們傳遞給服務(wù)端,并請(qǐng)求服務(wù)端調(diào)用指定方法腰涧;
(3)接收 _reply 數(shù)據(jù)流韧掩,并從中取出服務(wù)端傳回來(lái)的數(shù)據(jù)。

四窖铡、接著看服務(wù)端

//客戶(hù)端調(diào)用 transact() 方法疗锐,服務(wù)端回調(diào) onTransact() 方法:
//BookManager$Stub#onTransact:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
    //省略
case TRANSACTION_getBooks:
    //省略
case TRANSACTION_addBookWithTagIn:
    //省略
case TRANSACTION_addBookWithTagOut:
    //省略
case TRANSACTION_addBookWithTagInOut:
    //省略
}
return super.onTransact(code, data, reply, flags);
}

//服務(wù)端響應(yīng)客戶(hù)端的調(diào)用:
case TRANSACTION_getBooks:
{
data.enforceInterface(DESCRIPTOR);
//調(diào)用 this.getBooks() 方法,在這里開(kāi)始執(zhí)行具體的業(yè)務(wù)邏輯
//result 列表為調(diào)用 getBooks() 方法的返回值
java.util.List _result = this.getBooks();
reply.writeNoException();
//將方法執(zhí)行的結(jié)果寫(xiě)入 reply
reply.writeTypedList(_result);
return true;
}

BookManager$Stub的工作過(guò)程:
(1)獲取客戶(hù)端傳過(guò)來(lái)的數(shù)據(jù)费彼,根據(jù)方法 ID 執(zhí)行相應(yīng)操作滑臊;
(2)將傳過(guò)來(lái)的數(shù)據(jù)取出來(lái),調(diào)用本地寫(xiě)好的對(duì)應(yīng)方法箍铲;
(3)將需要回傳的數(shù)據(jù)寫(xiě)入 reply 流雇卷,傳回客戶(hù)端。

五颠猴、AIDL方法參數(shù)有定向tag的情況

1.定向tag為 in 的情況

//BookManager$Stub$Proxy#addBookWithTagIn:
@Override public void addBookWithTagIn(com.tomorrow.androidtest7.aidl.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
//將book對(duì)象寫(xiě)入_data流关划,傳遞給服務(wù)端
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
//調(diào)用transact方法
mRemote.transact(Stub.TRANSACTION_addBookWithTagIn, _data, _reply, 0);
_reply.readException();
//在執(zhí)行transact方法之后沒(méi)有針對(duì)_reply的操作
}
finally {
_reply.recycle();
_data.recycle();
}
}

//BookManager$Stub#onTransact:
case TRANSACTION_addBookWithTagIn:
{
data.enforceInterface(DESCRIPTOR);
com.tomorrow.androidtest7.aidl.Book _arg0; 
if ((0!=data.readInt())) {
//從輸入的data流中讀取book數(shù)據(jù),并將其賦值給_arg0
_arg0 = com.tomorrow.androidtest7.aidl.Book.CREATOR.createFromParcel(data); 
}
else {
_arg0 = null;
}
//調(diào)用服務(wù)端寫(xiě)好的實(shí)現(xiàn)
this.addBookWithTagIn(_arg0); 
reply.writeNoException();
//執(zhí)行完方法之后就結(jié)束了翘瓮,沒(méi)有針對(duì)reply流的操作祭玉,因此客戶(hù)端不會(huì)同步服務(wù)端的變化
return true;
}

2.定向tag為 out 的情況

//BookManager$Stub$Proxy#addBookWithTagOut:
@Override public void addBookWithTagOut(com.tomorrow.androidtest7.aidl.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
//沒(méi)有將book對(duì)象寫(xiě)入_data流,因此服務(wù)端接收不到客戶(hù)端傳過(guò)來(lái)的數(shù)據(jù)
//調(diào)用transact方法
mRemote.transact(Stub.TRANSACTION_addBookWithTagOut, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
//在執(zhí)行transact方法之后還有針對(duì)_reply的操作春畔,并且將book賦值為_(kāi)reply流中的數(shù)據(jù)
book.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}

//BookManager$Stub#onTransact:
case TRANSACTION_addBookWithTagOut:
{
data.enforceInterface(DESCRIPTOR);
com.tomorrow.androidtest7.aidl.Book _arg0;
//沒(méi)有從data流讀取book對(duì)象脱货,而是直接new一個(gè)book對(duì)象
_arg0 = new com.tomorrow.androidtest7.aidl.Book();
//調(diào)用服務(wù)端寫(xiě)好的實(shí)現(xiàn)
this.addBookWithTagOut(_arg0); 
reply.writeNoException();
if ((_arg0!=null)) {
reply.writeInt(1);
//執(zhí)行完方法之后還有針對(duì)reply的操作,并且將參數(shù)_arg0寫(xiě)入reply流律姨,因此客戶(hù)端可以接收到服務(wù)端傳過(guò)來(lái)的數(shù)據(jù)
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}

3.定向tag為 inout 的情況

//BookManager$Stub$Proxy#addBookWithTagInOut:
@Override public void addBookWithTagInOut(com.tomorrow.androidtest7.aidl.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
//將book對(duì)象寫(xiě)入_data流振峻,傳遞給服務(wù)端
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
//調(diào)用transact方法
mRemote.transact(Stub.TRANSACTION_addBookWithTagInOut, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
//在執(zhí)行transact方法之后還有針對(duì)_reply的操作,并且將book賦值為_(kāi)reply流中的數(shù)據(jù)
book.readFromParcel(_reply);
}
}
finally {
_reply.recycle();
_data.recycle();
}
}

//BookManager$Stub#onTransact:
case TRANSACTION_addBookWithTagInOut:
{
data.enforceInterface(DESCRIPTOR);
com.tomorrow.androidtest7.aidl.Book _arg0;
if ((0!=data.readInt())) {
//從輸入的data流中讀取book數(shù)據(jù)择份,并將其賦值給_arg0
_arg0 = com.tomorrow.androidtest7.aidl.Book.CREATOR.createFromParcel(data); 
}
else {
_arg0 = null;
}
//調(diào)用服務(wù)端寫(xiě)好的實(shí)現(xiàn)
this.addBookWithTagInOut(_arg0);
reply.writeNoException();
if ((_arg0!=null)) {
reply.writeInt(1);
//執(zhí)行完方法之后還有針對(duì)reply的操作扣孟,并且將參數(shù)_arg0寫(xiě)入reply流,因此客戶(hù)端可以接收到服務(wù)端傳過(guò)來(lái)的數(shù)據(jù)
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}

六荣赶、Stub及Proxy方法介紹

1.DESCRIPTOR:
Binder的唯一標(biāo)識(shí)凤价,一般用當(dāng)前Binder的類(lèi)名表示,比如"com.tomorrow.androidtest7.aidl.BookManager"拔创。
2.asInterface(android.os.IBinder obj):
用于將服務(wù)端的Binder對(duì)象轉(zhuǎn)換成客戶(hù)端所需的AIDL接口類(lèi)型的對(duì)象利诺,這種轉(zhuǎn)換過(guò)程是區(qū)分進(jìn)程的,如果客戶(hù)端和服務(wù)端位于同一進(jìn)程剩燥,那么此方法返回的就是服務(wù)端的Stub對(duì)象本身慢逾,否則返回的是系統(tǒng)封裝后的Stub$proxy對(duì)象。
3.asBinder:
此方法用于返回當(dāng)前Binder對(duì)象。
4.onTransact:
這個(gè)方法運(yùn)行在服務(wù)端中的Binder線程池中侣滩,當(dāng)客戶(hù)端發(fā)起跨進(jìn)程請(qǐng)求時(shí)口注,遠(yuǎn)程請(qǐng)求會(huì)通過(guò)系統(tǒng)底層封裝后交由此方法來(lái)處理。該方法的原型是:

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) 

執(zhí)行過(guò)程為:
(1)服務(wù)端通過(guò)code可以確定客戶(hù)端所請(qǐng)求的目標(biāo)方法是什么君珠,接著從data中取出目標(biāo)方法所需的參數(shù)(如果目標(biāo)方法有參數(shù)的話)寝志;
(2)執(zhí)行目標(biāo)方法;
(3)當(dāng)目標(biāo)方法執(zhí)行完畢后策添,就向reply中寫(xiě)入返回值(情況1:目標(biāo)方法有返回值澈段;情況2:目標(biāo)方法參數(shù)的定向tag為 out 或者 inout)。
需要注意的是舰攒,如果此方法返回false败富,那么客戶(hù)端的請(qǐng)求會(huì)失敗,因此我們可以利用這個(gè)特性來(lái)做權(quán)限驗(yàn)證摩窃。
5.Proxy#getBooks:
這個(gè)方法運(yùn)行在客戶(hù)端兽叮,執(zhí)行過(guò)程為:
(1)創(chuàng)建該方法所需要的輸入型Parcel對(duì)象_data、輸出型Parcel對(duì)象_reply和返回值對(duì)象List猾愿,然后把該方法的參數(shù)信息寫(xiě)入_data中(如果有參數(shù)的話)鹦聪;
(2)調(diào)用transact方法來(lái)發(fā)起RPC(遠(yuǎn)程過(guò)程調(diào)用)請(qǐng)求,同時(shí)當(dāng)前線程掛起蒂秘;
(3)服務(wù)端的onTransact方法會(huì)被調(diào)用泽本,直到RPC過(guò)程返回后,當(dāng)前線程繼續(xù)執(zhí)行姻僧,并從_reply中取出RPC過(guò)程的返回結(jié)果规丽,返回_reply中的數(shù)據(jù)。
6.注意:
(1)當(dāng)客戶(hù)端發(fā)起遠(yuǎn)程請(qǐng)求時(shí)撇贺,由于當(dāng)前線程會(huì)被掛起直至服務(wù)端進(jìn)程返回?cái)?shù)據(jù)赌莺,所以如果一個(gè)遠(yuǎn)程方法是很耗時(shí)的,那么不能在UI線程中發(fā)起此遠(yuǎn)程請(qǐng)求松嘶;
(2)由于服務(wù)端的Binder方法運(yùn)行在Binder的線程池中艘狭,所以Binder方法不管是否耗時(shí)都應(yīng)該采用同步的方式去實(shí)現(xiàn),因?yàn)樗呀?jīng)運(yùn)行在一個(gè)線程中了翠订。

相關(guān)鏈接

Binder工作原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巢音,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子尽超,更是在濱河造成了極大的恐慌官撼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橙弱,死亡現(xiàn)場(chǎng)離奇詭異歧寺,居然都是意外死亡燥狰,警方通過(guò)查閱死者的電腦和手機(jī)棘脐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)斜筐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蛀缝,你說(shuō)我怎么就攤上這事顷链。” “怎么了屈梁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵嗤练,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我在讶,道長(zhǎng)煞抬,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任构哺,我火速辦了婚禮革答,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘曙强。我一直安慰自己残拐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布碟嘴。 她就那樣靜靜地躺著溪食,像睡著了一般。 火紅的嫁衣襯著肌膚如雪娜扇。 梳的紋絲不亂的頭發(fā)上错沃,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音雀瓢,去河邊找鬼捎废。 笑死,一個(gè)胖子當(dāng)著我的面吹牛致燥,可吹牛的內(nèi)容都是我干的登疗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼嫌蚤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼辐益!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起脱吱,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤智政,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后箱蝠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體续捂,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垦垂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了牙瓢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劫拗。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖矾克,靈堂內(nèi)的尸體忽然破棺而出页慷,到底是詐尸還是另有隱情,我是刑警寧澤胁附,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布酒繁,位于F島的核電站,受9級(jí)特大地震影響控妻,放射性物質(zhì)發(fā)生泄漏州袒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一弓候、第九天 我趴在偏房一處隱蔽的房頂上張望郎哭。 院中可真熱鬧,春花似錦弓叛、人聲如沸彰居。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)陈惰。三九已至,卻和暖如春毕籽,著一層夾襖步出監(jiān)牢的瞬間抬闯,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工关筒, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留溶握,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓蒸播,卻偏偏與公主長(zhǎng)得像睡榆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子袍榆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354