第一節(jié)扰法、Binder IPC

1、為什么需要binder

Android 系統(tǒng)中毅厚,每個(gè)應(yīng)用程序是由 Android 的 Activity塞颁,Service,Broadcast吸耿, ContentProvider 這四劍客的中一個(gè)或多個(gè)組合而成祠锣,這四劍客所涉及的多進(jìn)程 間的通信底層都是依賴于 Binder IPC 機(jī)制。例如當(dāng)進(jìn)程 A 中的 Activity 要向進(jìn) 程 B 中的 Service 通信咽安,這便需要依賴于 Binder IPC伴网。不僅于此,整個(gè) Android 系統(tǒng)架構(gòu)中妆棒,大量采用了 Binder 機(jī)制作為 IPC(進(jìn)程間通信)方案是偷,當(dāng)然也存 在部分其他的 IPC 方式拳氢,比如 Zygote 通信便是采用 socket。

2蛋铆、IPC原理

從進(jìn)程角度來(lái)看 IPC 機(jī)制


image.png

每個(gè) Android 的進(jìn)程馋评,只能運(yùn)行在自己進(jìn)程所擁有的虛擬地址空間。對(duì)應(yīng)一個(gè) 4GB 的虛擬地址空間刺啦,其中 3GB 是用戶空間留特,1GB 是內(nèi)核空間,當(dāng)然內(nèi)核空間 的大小是可以通過(guò)參數(shù)配置調(diào)整的玛瘸。對(duì)于用戶空間蜕青,不同進(jìn)程之間彼此是不能共 享的,而內(nèi)核空間卻是可共享的糊渊。Client 進(jìn)程向 Server 進(jìn)程通信右核,恰恰是利用 進(jìn)程間可共享的內(nèi)核內(nèi)存空間來(lái)完成底層通信工作的,Client 端與 Server 端進(jìn) 程往往采用 ioctl 等方法跟內(nèi)核空間的驅(qū)動(dòng)進(jìn)行交互渺绒。

3贺喝、Binder原理

Binder 通信采用 C/S 架構(gòu),從組件視角來(lái)說(shuō)宗兼,包含 Client躏鱼、Server、 ServiceManager 以及 binder 驅(qū)動(dòng)殷绍,其中 ServiceManager 用于管理系統(tǒng)中的各 種服務(wù)染苛。架構(gòu)圖如下所示:


image.png

可以看出無(wú)論是注冊(cè)服務(wù)和獲取服務(wù)的過(guò)程都需要 ServiceManager,需要注意 的是此處的 Service Manager 是指 Native 層的 ServiceManager(C++)主到,并非 指 framework 層的 ServiceManager(Java)茶行。ServiceManager 是整個(gè) Binder 通 信機(jī)制的大管家,是 Android 進(jìn)程間通信機(jī)制 Binder 的守護(hù)進(jìn)程登钥,要掌握 Binder 機(jī)制拢军,首先需要了解系統(tǒng)是如何首次啟動(dòng) Service Manager。當(dāng) Service Manager 啟動(dòng)之后怔鳖,Client 端和 Server 端通信時(shí)都需要先獲取 Service Manager 接口, 才能開(kāi)始通信服務(wù)固蛾。 圖中 Client/Server/ServiceManage 之間的相互通信都是基于 Binder 機(jī)制结执。既然 基于 Binder 機(jī)制通信,那么同樣也是 C/S 架構(gòu)艾凯,則圖中的 3 大步驟都有相應(yīng)的 Client 端與 Server 端献幔。

  1. 注 冊(cè) 服 務(wù) (addService) : Server 進(jìn) 程 要 先 注 冊(cè) Service 到 ServiceManager。該過(guò)程:Server 是客戶端趾诗,ServiceManager 是服務(wù)端蜡感。
  2. 獲 取 服 務(wù) (getService) : Client 進(jìn) 程 使 用 某 個(gè) Service 前 蹬蚁, 須 先 向 ServiceManager 中獲取相應(yīng)的 Service。該過(guò)程:Client 是客戶端郑兴, ServiceManager 是服務(wù)端犀斋。
  3. 使用服務(wù):Client 根據(jù)得到的 Service 信息建立與 Service 所在的 Server 進(jìn)程通信的通路,然后就可以直接與 Service 交互情连。該過(guò)程:client 是客 戶端叽粹,server 是服務(wù)端。

圖中的 Client,Server,Service Manager 之間交互都是虛線表示却舀,是由于它們彼 此之間不是直接交互的虫几,而是都通過(guò)與 Binder 驅(qū)動(dòng)進(jìn)行交互的,從而實(shí)現(xiàn) IPC 通信方式挽拔。其中 Binder 驅(qū)動(dòng)位于內(nèi)核空間辆脸,Client,Server,Service Manager 位 于用戶空間。Binder 驅(qū)動(dòng)和 Service Manager 可以看做是 Android 平臺(tái)的基礎(chǔ) 架構(gòu)螃诅,而 Client 和 Server 是 Android 的應(yīng)用層啡氢,開(kāi)發(fā)人員只需自定義實(shí)現(xiàn) client、 Server 端州刽,借助 Android 的基本平臺(tái)架構(gòu)便可以直接進(jìn)行 IPC 通信空执。

3.1、C/S模式

BpBinder(客戶端)和 BBinder(服務(wù)端)都是 Android 中 Binder 通信相關(guān)的代表穗椅, 它們都從 IBinder 類中派生而來(lái)辨绊,關(guān)系圖如下:


image.png

四、Binder面試題全解析

Binder 是一種進(jìn)程間通信機(jī)制匹表,做 Android 開(kāi)發(fā)肯定離不開(kāi)跟 Binder 打交道在面試中 Binder 也是經(jīng)常被問(wèn)的一個(gè)點(diǎn)门坷,那么本篇文章就以問(wèn)答的方式,帶你 了解一下關(guān)于 Binder 的重要知識(shí)點(diǎn)袍镀。

1.Binder 有什么優(yōu)勢(shì)

1默蚌、性能方面

共享內(nèi)存 0 次數(shù)據(jù)拷貝
Binder 1 次數(shù)據(jù)拷貝
Socket/管道/消息隊(duì)列 2 次數(shù)據(jù)拷貝

2、穩(wěn)定性方面

Binder:基于 C/S 架構(gòu)苇羡,客戶端( Client)有什么需求就丟給服務(wù)端(Server)去完成
架構(gòu)清晰绸吸、職責(zé)明確又相互獨(dú)立,自然穩(wěn)定性更好
共享內(nèi)存:雖然無(wú)需拷貝设江,但是控制復(fù)雜锦茁,難以使用
從穩(wěn)定性的角度講,Binder 機(jī)制是優(yōu)于內(nèi)存共享的叉存。

3码俩、安全性方面

傳統(tǒng)的 IPC 沒(méi)有任何安全措施,安全依賴上層協(xié)議來(lái)確保歼捏。
傳統(tǒng)的 IPC 方法無(wú)法獲得對(duì)方可靠的進(jìn)程用戶 ID/進(jìn)程 UI(UID/PID)稿存,從而無(wú)法別對(duì)方身份笨篷。
傳統(tǒng)的 IPC 只能由用戶在數(shù)據(jù)包中填入 UID/PID,容易被惡意程序利用瓣履。
傳統(tǒng)的 IPC 訪問(wèn)接入點(diǎn)是開(kāi)放的率翅,無(wú)法阻止惡意程序通過(guò)猜測(cè)接收方地址獲得連續(xù)
Binder 既支持實(shí)名 Binder,又支持匿名 Binder拂苹,安全性高安聘。

2.Binder 是如何做到一次拷貝的

主要是因?yàn)?Linux 是使用的虛擬內(nèi)存尋址方式,它有如下特性:
  • 用戶空間的虛擬內(nèi)存地址是映射到物理內(nèi)存中的
  • 對(duì)虛擬內(nèi)存的讀寫(xiě)實(shí)際上是對(duì)物理內(nèi)存的讀寫(xiě)瓢棒,這個(gè)過(guò)程就是內(nèi)存映射
  • 這個(gè)內(nèi)存映射過(guò)程是通過(guò)系統(tǒng)調(diào)用 mmap()來(lái)實(shí)現(xiàn)的
    Binder 借助了內(nèi)存映射的方法浴韭,在內(nèi)核空間和接收方用戶空間的數(shù)據(jù)緩存區(qū)之間做 了一層內(nèi)存映射,就相 當(dāng)于直接拷貝到了接收方用戶空間的數(shù)據(jù)緩存區(qū)脯宿,從而減少 了一次數(shù)據(jù)拷貝

3.MMAP 的內(nèi)存映射原理了解嗎

MMAP 內(nèi)存映射的實(shí)現(xiàn)過(guò)程念颈,總的來(lái)說(shuō)可以分為三個(gè)階段:

(一)進(jìn)程啟動(dòng)映射過(guò)程,并在虛擬地址空間中為映射創(chuàng)建虛擬映射區(qū)域

  1. 進(jìn)程在用戶空間調(diào)用庫(kù)函數(shù) mmap连霉,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
  2. 在當(dāng)前進(jìn)程的虛擬地址空間中榴芳,尋找一段空閑的滿足要求的連續(xù)的虛擬地址
  3. 為此虛擬區(qū)分配一個(gè) vm_area_struct 結(jié)構(gòu),接著對(duì)這個(gè)結(jié)構(gòu)的各個(gè)域進(jìn)行了初始化
  4. 將新建的虛擬區(qū)結(jié)構(gòu)(vm_area_struct)插入進(jìn)程的虛擬地址區(qū)域鏈表或樹(shù)中

(二)調(diào)用內(nèi)核空間的系統(tǒng)調(diào)用函數(shù) mmap(不同于用戶空間函數(shù))跺撼,實(shí)現(xiàn)文件 物理地址和進(jìn)程虛擬地址的一一映射關(guān)系

  1. 為映射分配了新的虛擬地址區(qū)域后窟感,通過(guò)待映射的文件指針,在文件描述符表中找 到對(duì)應(yīng)的文件描述符歉井,通過(guò)文件描述符柿祈,鏈接到內(nèi)核“已打開(kāi)文件集”中該文件的文 件結(jié)構(gòu)體(struct file),每個(gè)文件結(jié)構(gòu)體維護(hù)著和這個(gè)已打開(kāi)文件相關(guān)各項(xiàng)信息哩至。
  2. 通過(guò)該文件的文件結(jié)構(gòu)體躏嚎,鏈接到 file_operations 模塊,調(diào)用內(nèi)核函數(shù) mmap菩貌,其原 型為:int mmap(struct file *filp, struct vm_area_struct *vma)卢佣,不同于用戶空間庫(kù)函數(shù)。
  3. 內(nèi)核 mmap 函數(shù)通過(guò)虛擬文件系統(tǒng) inode 模塊定位到文件磁盤物理地址箭阶。
  4. 通過(guò) remap_pfn_range 函數(shù)建立頁(yè)表虚茶,即實(shí)現(xiàn)了文件地址和虛擬地址區(qū)域的映射關(guān) 系。此時(shí)仇参,這片虛擬地址并沒(méi)有任何數(shù)據(jù)關(guān)聯(lián)到主存中

(三)進(jìn)程發(fā)起對(duì)這片映射空間的訪問(wèn)嘹叫,引發(fā)缺頁(yè)異常,實(shí)現(xiàn)文件內(nèi)容到物理 內(nèi)存(主存)的拷貝

注:前兩個(gè)階段僅在于創(chuàng)建虛擬區(qū)間并完成地址映射冈敛,但是并沒(méi)有將任何文件數(shù) 據(jù)的拷貝至主存。真正的文件讀取是當(dāng)進(jìn)程發(fā)起讀或?qū)懖僮鲿r(shí)鸣皂。
進(jìn)程的讀或?qū)懖僮髟L問(wèn)虛擬地址空間這一段映射地址抓谴,通過(guò)查詢頁(yè)表暮蹂,發(fā)現(xiàn)這一 段地址并不在物理頁(yè)面上。因?yàn)槟壳爸唤⒘说刂酚成浒┭梗嬲挠脖P數(shù)據(jù)還沒(méi)有 拷貝到內(nèi)存中仰泻,因此引發(fā)缺頁(yè)異常。

  1. 缺頁(yè)異常進(jìn)行一系列判斷滩届,確定無(wú)非法操作后集侯,內(nèi)核發(fā)起請(qǐng)求調(diào)頁(yè)過(guò)程。
  2. 調(diào)頁(yè)過(guò)程先在交換緩存空間(swap cache)中尋找需要訪問(wèn)的內(nèi)存頁(yè)帜消,如果沒(méi)有則 調(diào)用 nopage 函數(shù)把所缺的頁(yè)從磁盤裝入到主存中棠枉。
  3. 之后進(jìn)程即可對(duì)這片主存進(jìn)行讀或者寫(xiě)的操作,如果寫(xiě)操作改變了其內(nèi)容泡挺,一定時(shí) 間后系統(tǒng)會(huì)自動(dòng)回寫(xiě)臟頁(yè)面到對(duì)應(yīng)磁盤地址辈讶,也即完成了寫(xiě)入到文件的過(guò)程。
    注:修改過(guò)的臟頁(yè)面并不會(huì)立即更新回文件中娄猫,而是有一段時(shí)間的延遲贱除,可以調(diào) 用 msync()來(lái)強(qiáng)制同步, 這樣所寫(xiě)的內(nèi)容就能立即保存到文件里了。

4.Binder 機(jī)制是如何跨進(jìn)程的

1.Binder 驅(qū)動(dòng)
  • 在內(nèi)核空間創(chuàng)建一塊接收緩存區(qū)媳溺,
  • 實(shí)現(xiàn)地址映射:將內(nèi)核緩存區(qū)月幌、接收進(jìn)程用戶空間映射到同一接收緩存區(qū)
2.發(fā)送進(jìn)程通過(guò)系統(tǒng)調(diào)用(copy_from_user)將數(shù)據(jù)發(fā)送到內(nèi)核緩存區(qū)。由于內(nèi) 核緩存區(qū)和接收進(jìn)程用戶空間存在映射關(guān)系悬蔽,故相當(dāng)于也發(fā)送了接收進(jìn)程的用戶 空間扯躺,實(shí)現(xiàn)了跨進(jìn)程通信。

5.說(shuō)說(shuō)四大組件的通信機(jī)制

1.activity

(1)一個(gè) Activity 通常就是一個(gè)單獨(dú)的屏幕(窗口)屯阀。
(2)Activity 之間通過(guò) Intent 進(jìn)行通信缅帘。
(3)android 應(yīng)用中每一個(gè) Activity 都必須要在 AndroidManifest.xml 配置文件中 聲明,否則系統(tǒng)將不識(shí)別也不執(zhí)行該 Activity难衰。

2.service
(1)service 用于在后臺(tái)完成用戶指定的操作钦无。service 分為兩種:
  • started(啟動(dòng)):當(dāng)應(yīng)用程序組件(如 activity)調(diào)用 startService()方法啟動(dòng)服務(wù)時(shí), 服務(wù)處于 started 狀態(tài)盖袭。
  • bound(綁定):當(dāng)應(yīng)用程序組件調(diào)用 bindService()方法綁定到服務(wù)時(shí)失暂,服務(wù)處于 bound 狀態(tài)
(2)startService()與 bindService()區(qū)別:
  • started service(啟動(dòng)服務(wù))是由其他組件調(diào)用 startService()方法啟動(dòng)的,這導(dǎo)致服務(wù) 的 onStartCommand()方法被調(diào)用鳄虱。當(dāng)服務(wù)是 started 狀態(tài)時(shí)弟塞,其生命周期與啟動(dòng)它的 組件無(wú)關(guān),并且可以在后臺(tái)無(wú)限期運(yùn)行拙已,即使啟動(dòng)服務(wù)的組件已經(jīng)被銷毀决记。因此, 服務(wù)需要在完成任務(wù)后調(diào)用 stopSelf()方法停止倍踪,或者由其他組件調(diào)用 stopService() 方法停止系宫。
  • 使用 bindService()方法啟用服務(wù)索昂,調(diào)用者與服務(wù)綁定在了一起,調(diào)用者一旦退出扩借,服 務(wù)也就終止椒惨,大有“不求同時(shí)生,必須同時(shí)死”的特點(diǎn)潮罪。
(3)開(kāi)發(fā)人員需要在應(yīng)用程序配置文件中聲明全部的 service康谆,使用 <service></service>標(biāo)簽。
(4)Service 通常位于后臺(tái)運(yùn)行嫉到,它一般不需要與用戶交互沃暗,因此 Service 組件沒(méi)有 圖形用戶界面。Service 組件需要繼承 Service 基類屯碴。Service 組件通常用于為其他 組件提供后臺(tái)服務(wù)或監(jiān)控其他組件的運(yùn)行狀態(tài)描睦。
3.content provider

(1)android 平臺(tái)提供了 Content Provider 使一個(gè)應(yīng)用程序的指定數(shù)據(jù)集提供給 其他應(yīng)用程序。其他應(yīng)用可以通過(guò) ContentResolver 類從該內(nèi)容提供者中獲取或 存入數(shù)據(jù)导而。
(2)只有需要在多個(gè)應(yīng)用程序間共享數(shù)據(jù)是才需要內(nèi)容提供者忱叭。例如,通訊錄 數(shù)據(jù)被多個(gè)應(yīng)用程序使用今艺,且必須存儲(chǔ)在一個(gè)內(nèi)容提供者中韵丑。它的好處是統(tǒng)一數(shù) 據(jù)訪問(wèn)方式。
(3)ContentProvider 實(shí)現(xiàn)數(shù)據(jù)共享虚缎。ContentProvider 用于保存和獲取數(shù)據(jù)撵彻,并 使其對(duì)所有應(yīng)用程序可見(jiàn)。這是不同應(yīng)用程序間共享數(shù)據(jù)的唯一方式实牡,因?yàn)?android 沒(méi)有提供所有應(yīng)用共同訪問(wèn)的公共存儲(chǔ)區(qū)陌僵。
(4)開(kāi)發(fā)人員不會(huì)直接使用 ContentProvider 類的對(duì)象,大多數(shù)是通過(guò) ContentResolver 對(duì)象實(shí)現(xiàn)對(duì) ContentProvider 的操作创坞。
(5)ContentProvider 使用 URI 來(lái)唯一標(biāo)識(shí)其數(shù)據(jù)集碗短,這里的 URI 以 content:// 作為前綴,表示該數(shù)據(jù)由 ContentProvider 來(lái)管理题涨。

4.broadcast receiver

(1)你的應(yīng)用可以使用它對(duì)外部事件進(jìn)行過(guò)濾偎谁,只對(duì)感興趣的外部事件(如當(dāng)電 話呼入時(shí),或者數(shù)據(jù)網(wǎng)絡(luò)可用時(shí))進(jìn)行接收并做出響應(yīng)纲堵。廣播接收器沒(méi)有用戶界 面巡雨。然而,它們可以啟動(dòng)一個(gè) activity 或 serice 來(lái)響應(yīng)它們收到的信息席函,或者用 NotificationManager 來(lái)通知用戶铐望。通知可以用很多種方式來(lái)吸引用戶的注意力, 例如閃動(dòng)背燈、震動(dòng)正蛙、播放聲音等炕舵。一般來(lái)說(shuō)是在狀態(tài)欄上放一個(gè)持久的圖標(biāo), 用戶可以打開(kāi)它并獲取消息跟畅。 (2)廣播接收者的注冊(cè)有兩種方法,分別是程序動(dòng)態(tài)注冊(cè)和 AndroidManifest 文 件中進(jìn)行靜態(tài)注冊(cè)溶推。
(3)動(dòng)態(tài)注冊(cè)廣播接收器特點(diǎn)是當(dāng)用來(lái)注冊(cè)的 Activity 關(guān)掉后徊件,廣播也就失效了。 靜態(tài)注冊(cè)無(wú)需擔(dān)憂廣播接收器是否被關(guān)閉蒜危,只要設(shè)備是開(kāi)啟狀態(tài)虱痕,廣播接收器也 是打開(kāi)著的。也就是說(shuō)哪怕 app 本身未啟動(dòng)辐赞,該 app 訂閱的廣播在觸發(fā)時(shí)也會(huì)對(duì) 它起作用部翘。

7.為什么 Intent 不能傳遞大數(shù)據(jù)

Intent 攜帶信息的大小其實(shí)是受 Binder 限制。數(shù)據(jù)以 Parcel 對(duì)象的形式存放在 Binder 傳遞緩存中响委。如果數(shù)據(jù)或返回值比傳遞 buffer 大新思,則此次傳遞調(diào)用失敗并 拋出 TransactionTooLargeException 異常。 Binder 傳遞緩存有一個(gè)限定大小赘风,通常是 1Mb夹囚。但同一個(gè)進(jìn)程中所有的傳輸共享 緩存空間。多個(gè)地方在進(jìn)行傳輸時(shí)邀窃,即時(shí)它們各自傳輸?shù)臄?shù)據(jù)不超出大小限制荸哟, TransactionTooLargeException 異常也可能會(huì)被拋出。在使用 Intent 傳遞數(shù)據(jù)時(shí)瞬捕, 1Mb 并不是安全上限鞍历。因?yàn)?Binder 中可能正在處理其它的傳輸工作。不同的機(jī) 型和系統(tǒng)版本肪虎,這個(gè)上限值也可能會(huì)不同劣砍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市笋轨,隨后出現(xiàn)的幾起案子秆剪,更是在濱河造成了極大的恐慌,老刑警劉巖爵政,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仅讽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡钾挟,警方通過(guò)查閱死者的電腦和手機(jī)洁灵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人徽千,你說(shuō)我怎么就攤上這事苫费。” “怎么了双抽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵百框,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我牍汹,道長(zhǎng)铐维,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任慎菲,我火速辦了婚禮嫁蛇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘露该。我一直安慰自己睬棚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布解幼。 她就那樣靜靜地躺著抑党,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撵摆。 梳的紋絲不亂的頭發(fā)上新荤,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音台汇,去河邊找鬼苛骨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛苟呐,可吹牛的內(nèi)容都是我干的痒芝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼牵素,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼严衬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起笆呆,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤请琳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后赠幕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體俄精,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年榕堰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了竖慧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖圾旨,靈堂內(nèi)的尸體忽然破棺而出踱讨,到底是詐尸還是另有隱情,我是刑警寧澤砍的,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布痹筛,位于F島的核電站忍疾,受9級(jí)特大地震影響舶替,放射性物質(zhì)發(fā)生泄漏倚舀。R本人自食惡果不足惜领铐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驮宴。 院中可真熱鬧,春花似錦、人聲如沸夕土。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)怨绣。三九已至,卻和暖如春拷获,著一層夾襖步出監(jiān)牢的瞬間篮撑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工匆瓜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赢笨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓驮吱,卻偏偏與公主長(zhǎng)得像茧妒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子左冬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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