Binder和IPC機(jī)制

進(jìn)程一般指一個(gè)執(zhí)行單元,在電腦和移動(dòng)設(shè)備上指一個(gè)程序或者一個(gè)應(yīng)用飒泻。

我們通過系統(tǒng)提供的ContentProvider去查詢數(shù)據(jù)的時(shí)候崭捍,其實(shí)也是一種進(jìn)程間通信,只不過通信細(xì)節(jié)被系統(tǒng)內(nèi)部屏蔽了侯嘀。

給一個(gè)應(yīng)用開啟多進(jìn)程模式——android:process,除此之外沒有其他辦法谱轨,也就是說我們無法給一個(gè)線程或者一個(gè)實(shí)體類指定其運(yùn)行時(shí)所在的進(jìn)程戒幔。

一個(gè)應(yīng)用默認(rèn)進(jìn)程的進(jìn)程名為包名。

進(jìn)程名為“:”開頭的進(jìn)程屬于當(dāng)前應(yīng)用的私有進(jìn)程土童,其他應(yīng)用的組件不可以和它跑在同一個(gè)進(jìn)程里诗茎,而進(jìn)程名不以“:”開頭的進(jìn)程屬于全局進(jìn)程,其他應(yīng)用通過ShareUID方式可以和它跑在一個(gè)進(jìn)程里献汗。

Android系統(tǒng)為每個(gè)應(yīng)用分配一個(gè)唯一的UID敢订,具有相同UID的應(yīng)用才能共享數(shù)據(jù)。兩個(gè)應(yīng)用通過ShareUID跑在同一個(gè)進(jìn)程中是有要求的罢吃,需要這兩個(gè)應(yīng)用有相同的ShareUID并且簽名相同才可以楚午。在這種情況下,他們可以互相訪問對方的私有數(shù)據(jù)尿招,比如data目錄矾柜、組件信息等,不管它們是否跑在同一個(gè)進(jìn)程里泊业。如果跑在同一個(gè)進(jìn)程里把沼,除了能共享data數(shù)據(jù)目錄,組件信息吁伺,還可以共享內(nèi)存數(shù)據(jù)饮睬,看上去就像同一個(gè)應(yīng)用的兩個(gè)部分。

ShareUID

android:sharedUserId 即上文中提到的UID和ShareUID是同一個(gè)概念篮奄。
Android給每個(gè)app進(jìn)程分配一個(gè)單獨(dú)的用戶空間,其manifest中的userid就是對應(yīng)一個(gè)Linux用戶Shared User id
通過Shared User id,擁有同一個(gè)User id的多個(gè)app可以配置成運(yùn)行在同一個(gè)進(jìn)程中.所以默認(rèn)就是可以互相訪問任意數(shù)據(jù). 也可以配置成運(yùn)行成不同的進(jìn)程, 同時(shí)可以訪問其他APK的數(shù)據(jù)目錄下的數(shù)據(jù)庫和文件.就像訪問本程序的數(shù)據(jù)一樣.

多進(jìn)程模式的運(yùn)行機(jī)制和需要注意的問題

靜態(tài)變量不能在多進(jìn)程間同步捆愁。
Android為每個(gè)應(yīng)用分配了一個(gè)獨(dú)立的虛擬機(jī),或者說為每個(gè)進(jìn)程都分配了一個(gè)獨(dú)立的虛擬機(jī)窟却,不同的虛擬機(jī)在內(nèi)存分配上有不同的地址空間昼丑,這就導(dǎo)致了不同的虛擬機(jī)中訪問同一個(gè)類的對象會(huì)產(chǎn)生多個(gè)副本。
所有運(yùn)行在不同進(jìn)程中的四大組件夸赫,只要它們之間需要通過內(nèi)存來共享數(shù)據(jù)菩帝,都會(huì)共享失敗,這也是多進(jìn)程帶來的主要影響。所以在運(yùn)用IPC時(shí)要考慮共享的是不是內(nèi)存數(shù)據(jù)呼奢。
一般來說宜雀,使用多進(jìn)程會(huì)造成以下幾方面的問題

  • 靜態(tài)成員和單例模式完全失敗
  • 線程同步機(jī)制完全失敗
  • SharedPreferences的可靠性下降。因?yàn)镾haredPreferences不支持- 兩個(gè)進(jìn)程同時(shí)執(zhí)行寫操作握础,否則會(huì)有一定幾率的數(shù)據(jù)丟失辐董。
  • Application會(huì)多次創(chuàng)建。運(yùn)行在同一個(gè)進(jìn)程中的組件是屬于同一個(gè)虛擬機(jī)和同一個(gè)Application的禀综,同理简烘,運(yùn)行在不同進(jìn)程里的組件就屬于兩個(gè)不同的虛擬機(jī)和Application。

我們可以這么理解同一個(gè)應(yīng)用間的多進(jìn)程:它就相當(dāng)于兩個(gè)不同的應(yīng)用采用了ShareUID的模式定枷,這樣能夠更加直接的理解多進(jìn)程模式的本質(zhì)孤澎。

Serializable和Parcelable

Serializable是Java中的序列化接口,其使用起來簡單但是開銷很大依鸥,序列化和反序列化過程需要大量的I/O操作亥至。
Parcelable是android中的序列化方式,在android平臺(tái)上贱迟,效率很高。
Parcelable主要用在內(nèi)存序列化上絮供,通過Parcelable將對象序列化到存儲(chǔ)設(shè)備中或者將對象序列化后通過網(wǎng)絡(luò)傳輸也都是可以做到衣吠,但是這個(gè)過程會(huì)稍顯復(fù)雜,因此在這兩種情況下建議大家使用Serializable壤靶。

關(guān)于Binder

需要額外注意的兩點(diǎn)是:首先缚俏,當(dāng)客戶端發(fā)起遠(yuǎn)程請求時(shí),由于當(dāng)前線程會(huì)被掛起贮乳,直到服務(wù)端進(jìn)程返回?cái)?shù)據(jù)忧换,所以如果一個(gè)遠(yuǎn)程方法是很耗時(shí)的,那么不能在UI線程中發(fā)起此遠(yuǎn)程請求向拆。其次亚茬,由于服務(wù)端的Binder方法運(yùn)行在Binder的線程池中,所以Binder方法不管是否耗時(shí)都應(yīng)該采用同步的方式實(shí)現(xiàn)浓恳,因?yàn)樗呀?jīng)運(yùn)行在一個(gè)線程中了刹缝。

Messenger是一種輕量級的IPC方案,底層實(shí)現(xiàn)是AIDL颈将,由于它一次處理一個(gè)請求梢夯,因此在服務(wù)端,我們不用考慮線程同步的問題晴圾,因?yàn)榉?wù)端不存在并發(fā)執(zhí)行的情形颂砸。Messenger是用串行的方式處理客戶端發(fā)來的請求,如果有大量并發(fā)請求,那么使用Messenger就不太合適了人乓。Messenger的作用主要是為了傳遞消息梗醇,很多時(shí)候我們可能需要跨進(jìn)程調(diào)用服務(wù)端的方法,這種情形用Messenger就無法做到了撒蟀。但是我們可以用AIDL來實(shí)現(xiàn)跨進(jìn)程的方法調(diào)用叙谨。

Binder連接池的作用和工作機(jī)制

當(dāng)有多個(gè)業(yè)務(wù)模塊都用到AIDL進(jìn)行跨進(jìn)程通信時(shí),每個(gè)業(yè)務(wù)模塊創(chuàng)建自己的AIDL接口并實(shí)現(xiàn)此接口保屯。這個(gè)時(shí)候不同業(yè)務(wù)模塊之間是不能有耦合的手负,所有實(shí)現(xiàn)細(xì)節(jié)我們要單獨(dú)開來,然后向服務(wù)端提供自己的唯一標(biāo)識(shí)和其對應(yīng)的Binder對象姑尺;對于服務(wù)端而言竟终,只需要一個(gè)Service就可以了,服務(wù)端提供一個(gè)queryBinder接口切蟋,這個(gè)接口能夠根據(jù)業(yè)務(wù)模塊的特征來返回相應(yīng)的Binder對象給它們统捶,不同的業(yè)務(wù)模塊拿到所需的Binder對象后就可以進(jìn)行遠(yuǎn)程方法調(diào)用了,由此可見柄粹,BInder連接池的主要作用就是將每個(gè)業(yè)務(wù)模塊的Binder請求統(tǒng)一轉(zhuǎn)發(fā)給遠(yuǎn)程Service中去執(zhí)行喘鸟,從而避免了重復(fù)創(chuàng)建Service的過程。

AIDL的oneway

oneway可以用來修飾在interface之前驻右,這樣會(huì)造成interface內(nèi)所有的方法都隱式地帶上oneway什黑;
oneway也可以修飾在interface里的各個(gè)方法之前。
被oneway修飾的方法不可以有返回值堪夭。

oneway關(guān)鍵字用于修改遠(yuǎn)程調(diào)用的行為

  • 本地調(diào)用(同步調(diào)用)——如果用于本地調(diào)用愕把,則不會(huì)有任何影響,調(diào)用仍然是同步調(diào)用
  • 遠(yuǎn)程調(diào)用(異步調(diào)用)——使用oneway修飾的方法森爽,遠(yuǎn)程調(diào)用時(shí)不會(huì)阻塞恨豁;Client端調(diào)用該方法時(shí),只是發(fā)送數(shù)據(jù)并立即返回爬迟。接口的實(shí)現(xiàn)類最終接收此調(diào)用時(shí)橘蜜,是以正常的遠(yuǎn)程調(diào)用形式將其作為常規(guī)的binder調(diào)用來接收。

oneway主要有兩個(gè)特性:異步調(diào)用和串行化處理雕旨。

  • 異步調(diào)用是指Client端向binder驅(qū)動(dòng)發(fā)送調(diào)用請求后不需要掛起線程等待binder驅(qū)動(dòng)的回復(fù)扮匠,而是直接結(jié)束。向一些系統(tǒng)服務(wù)調(diào)用應(yīng)用進(jìn)程的時(shí)候就會(huì)使用oneway凡涩,比如AMS調(diào)用應(yīng)用進(jìn)程啟動(dòng)Activity勉耀,這樣就算應(yīng)用進(jìn)程中做了耗時(shí)的任務(wù)躯砰,也不會(huì)阻塞系統(tǒng)服務(wù)的運(yùn)行靴姿。
  • 串行化處理是指對于一個(gè)Server的AIDL接口而言涯冠,所有的oneway方法不會(huì)同時(shí)執(zhí)行,binder驅(qū)動(dòng)會(huì)將它們串行化處理,排隊(duì)一個(gè)一個(gè)調(diào)用克蚂。
binder的相關(guān)協(xié)議
非oneway方法調(diào)用

如果是 oneway 的話闺鲸,客戶端就不需要掛起線程等待:
oneway方法調(diào)用

涉及到的 binder 命令也有規(guī)律,由外部發(fā)送給 binder 驅(qū)動(dòng)的都是 BC_ 開頭埃叭,由 binder 驅(qū)動(dòng)發(fā)往外部的都是 BR_開頭摸恍。

waiteventinterruptible方法

Client端調(diào)用Server端的非oneway方法時(shí),會(huì)造成Client端線程掛起等待遠(yuǎn)程方法返回赤屋,這個(gè)等待操作立镶,底層調(diào)用的是Linux系統(tǒng)函數(shù)waiteventinterruptible()方法。相當(dāng)于Thread的sleep方法类早,調(diào)用后媚媒,線程就不會(huì)占用CPU資源。
而用到waiteventinterruptible()方法的地方涩僻,還有Handler機(jī)制中缭召,Looper的阻塞,其實(shí)質(zhì)是MessageQueue的next()方法中逆日,調(diào)用了nativePollOnce()嵌巷,它的底層實(shí)現(xiàn)也調(diào)用了waiteventinterruptible()方法。

Binder機(jī)制的原理

BInder通信機(jī)制采用是的C/S架構(gòu)屏富,其中包括4個(gè)主要的角色:Client晴竞、Server、ServiceManager和Binder驅(qū)動(dòng)狠半。其中Client、Server和SerivceManager都是在用戶空間颤难,他們都在各自的進(jìn)程神年,Binder驅(qū)動(dòng)是屬于內(nèi)核空間。關(guān)于內(nèi)核空間和用戶空間行嗤,是Linux中的概念已日,每個(gè)Linux(Android)進(jìn)程默認(rèn)都對應(yīng)4G的虛擬地址空間,其中0~1G是內(nèi)核空間栅屏,1G到4G是用戶空間飘千,每個(gè)進(jìn)程的用戶空間都是相互獨(dú)立的,內(nèi)核空間是可共享的栈雳。
Binder機(jī)制的流程可以這樣理解:

  • (1)注冊服務(wù) Server端注冊service對象到ServiceManager护奈,在ServiceManager中生成映射關(guān)系表。這個(gè)過程中哥纫,Server相當(dāng)于客戶端霉旗,ServiceManager相當(dāng)于服務(wù)端。
  • (2)獲取服務(wù) Client向ServiceManager發(fā)送請求,獲取service對象厌秒,而ServiceManager會(huì)返回一個(gè)service的代理對象給Client读拆。這個(gè)過程中,Client相當(dāng)于客戶端鸵闪,ServiceManager相對于服務(wù)端檐晕。
  • (3)Client獲取到service的代理對象,調(diào)用service代理對象的對應(yīng)方法并獲取執(zhí)行結(jié)果蚌讼,實(shí)現(xiàn)Client和Server的跨進(jìn)程通信辟灰。這個(gè)過程中,Client就是客戶端啦逆,Server就是服務(wù)端伞矩。


    Binder機(jī)制流程

但是以上三個(gè)步驟中的,雙方都不是直接交互的夏志,都是通過Binder驅(qū)動(dòng)實(shí)現(xiàn)IPC通信的過程乃坤。比如步驟(2)中,ServiceManager是通過Binder驅(qū)動(dòng)生成service的代理對象沟蔑,然后將代理對象轉(zhuǎn)發(fā)給Client湿诊。而在步驟(3)中,Client調(diào)用service代理對象對應(yīng)方法時(shí)瘦材,會(huì)向Binder驅(qū)動(dòng)發(fā)送消息厅须,然后由Binder驅(qū)動(dòng)通知Server端,執(zhí)行service對象的同名方法食棕,并將執(zhí)行結(jié)果發(fā)送給BInder驅(qū)動(dòng)朗和,再將其轉(zhuǎn)發(fā)給Client。從Client端的視角來看簿晓,就相當(dāng)于眶拉,它直接調(diào)用了service對象的方法。

Binder機(jī)制實(shí)現(xiàn)IPC的優(yōu)勢:
  • 性能相比于socket憔儿、管道和消息隊(duì)列要高忆植。因?yàn)閟ocket、管道和消息隊(duì)列都是采用存儲(chǔ)-轉(zhuǎn)發(fā)方式谒臼,即數(shù)據(jù)先從發(fā)送方拷貝到內(nèi)核緩沖區(qū)朝刊,再從內(nèi)核緩沖區(qū)拷貝到接收方。需要兩次拷貝過程蜈缤。而Binder機(jī)制只需要一次數(shù)據(jù)拷貝拾氓。
  • 穩(wěn)定性 Binder基于C/S架構(gòu),架構(gòu)清晰劫樟,職責(zé)明確又相對獨(dú)立痪枫。
  • 安全性 傳統(tǒng)的IPC方法织堂,接收端無法獲得發(fā)送端的UID/PID,也就無法鑒別發(fā)送方的身份奶陈。而Android系統(tǒng)中給每個(gè)進(jìn)程都分配了UID易阳,可以當(dāng)做鑒別進(jìn)程身份的重要標(biāo)識(shí)。傳統(tǒng)的IPC只能由用戶將UID填寫在數(shù)據(jù)包里吃粒,容易被截獲利用潦俺。其次,傳統(tǒng)的IPC訪問接入點(diǎn)是開放的徐勃,只要知道接入點(diǎn)事示,就可以與對端建立連接,這樣就容易被惡意程序猜測到接入點(diǎn)而與接收方建立連接僻肖。同時(shí)肖爵,Binder既支持實(shí)名Binder又支持匿名BInder,安全性高臀脏。
binder機(jī)制基于mmap一次拷貝的實(shí)現(xiàn)原理
mmap

Client端和Server端處于不同的進(jìn)程有些不同的虛擬地址規(guī)則劝堪,所以無法直接通信,而一個(gè)頁框可以映射給多個(gè)頁揉稚,那么就可以將一塊物理內(nèi)存分別與Client和Server的虛擬內(nèi)存塊進(jìn)行映射秒啦,如圖所示,Client向Server發(fā)消息搀玖,只需調(diào)用copy_from_user進(jìn)行一次數(shù)據(jù)拷貝余境,Server進(jìn)程就能讀取到數(shù)據(jù)了,另外映射的虛擬內(nèi)存塊大小將近1M(1M~8K)灌诅,所以IPC通信的數(shù)據(jù)量也被限制為這個(gè)值芳来。通過Intent向Acivity或者Service等組件傳參時(shí),也因?yàn)檫@個(gè)映射內(nèi)存的大小問題猜拾,也會(huì)影響到Intent傳遞數(shù)據(jù)的大小绣张。

通過Intent傳遞數(shù)據(jù)的大小具體限制
1.1傳512K以下的數(shù)據(jù)的數(shù)據(jù)可以正常傳遞。
1.2傳512K~1024K的數(shù)據(jù)會(huì)出錯(cuò)关带,閃退。
1.3傳1024K以上的數(shù)據(jù)會(huì)報(bào)錯(cuò):TransactionTooLargeException沼撕。
1.4考慮到Intent還包括要啟動(dòng)的Activity等信息宋雏,實(shí)際可以傳的數(shù)據(jù)略小于512K
原文鏈接:https://blog.csdn.net/pingfangx/article/details/52093225

怎么理解頁和頁框
頁框是指一塊實(shí)際的物理內(nèi)存,頁是指程序的一塊內(nèi)存數(shù)據(jù)單元务豺,內(nèi)存數(shù)據(jù)一定是存儲(chǔ)在實(shí)際的物理內(nèi)存上磨总,即頁必然對應(yīng)于一個(gè)頁框,頁數(shù)據(jù)實(shí)際上是存儲(chǔ)在頁框上的笼沥。
頁和頁框一樣大蚪燕,都是內(nèi)核對內(nèi)存的分塊單位娶牌。一個(gè)頁框可以映射給多個(gè)頁,也就是說一塊實(shí)際的物理存儲(chǔ)空間可以映射給多個(gè)進(jìn)程的多個(gè)虛擬內(nèi)存空間馆纳,這也是mmap機(jī)制依賴的基礎(chǔ)規(guī)則诗良。

Binder的整體架構(gòu)
Binder的整體架構(gòu)

Client通過ServiceManager或者AMS獲取到的遠(yuǎn)程binder實(shí)體,一般會(huì)用Proxy做一層封裝鲁驶,比如ServiceManagerProxy鉴裹、AIDL生成的Proxy類。而被封裝的遠(yuǎn)程binder實(shí)體是一個(gè)BInderProxy钥弯。
BpBinder和BinderProxy其實(shí)是一個(gè)東西径荔,遠(yuǎn)程binder實(shí)體,只不過一個(gè)Native層脆霎,一個(gè)Java層总处。BpBinder內(nèi)部持有一個(gè)binder句柄值handle。
ProcessState是進(jìn)程單例睛蛛,負(fù)責(zé)啟動(dòng)binder驅(qū)動(dòng)以及mmap鹦马;IPCThreadState是線程單例,負(fù)責(zé)與binder驅(qū)動(dòng)進(jìn)行具體的命令通信玖院。
由Client端通過Proxy發(fā)起遠(yuǎn)程方法調(diào)用菠红,會(huì)將數(shù)據(jù)打包到Parcel中,層層向下調(diào)用到BpBinder难菌,在BpBinder中調(diào)用IPCThreadState的transact()方法并傳入handle句柄值试溯,IPCThreadState再去執(zhí)行具體的binder命令。
由binder驅(qū)動(dòng)到Server端的大概流程是:Server端通過IPCThreadState接收到Client端的請求后郊酒,層層向上遇绞,最后回調(diào)Stub的onTransact() 方法。
以上不代表所有IPC的流程燎窘,比如Service Manager作為Server端時(shí)摹闽,便沒有上層的封裝,也沒有借助IPCThreadState褐健,而是初始化后通過binder_loop()方法直接和binder驅(qū)動(dòng)通信的付鹿。

本文參考:
https://blog.csdn.net/qq_42300133/article/details/103402635
https://blog.csdn.net/zhwadezh/article/details/79301909?depth_1-utm_source=distribute.pc_relevant_right.none-task&utm_source=distribute.pc_relevant_right.none-task
https://mp.weixin.qq.com/s/Mp8A1VreFsuj2USbyHRZjw
https://blog.csdn.net/u011033906/article/details/89316543
https://mp.weixin.qq.com/s/Jc2mrxeMVTJXudoPx5K4-w
https://blog.csdn.net/anlian523/article/details/98476033
https://blog.csdn.net/u010164190/article/details/73292012

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蚜迅,隨后出現(xiàn)的幾起案子舵匾,更是在濱河造成了極大的恐慌,老刑警劉巖谁不,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坐梯,死亡現(xiàn)場離奇詭異,居然都是意外死亡刹帕,警方通過查閱死者的電腦和手機(jī)吵血,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門谎替,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹋辅,你說我怎么就攤上這事钱贯。” “怎么了晕翠?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵喷舀,是天一觀的道長。 經(jīng)常有香客問我淋肾,道長硫麻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任樊卓,我火速辦了婚禮拿愧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碌尔。我一直安慰自己浇辜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布唾戚。 她就那樣靜靜地躺著柳洋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叹坦。 梳的紋絲不亂的頭發(fā)上熊镣,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天,我揣著相機(jī)與錄音募书,去河邊找鬼绪囱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛莹捡,可吹牛的內(nèi)容都是我干的鬼吵。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼篮赢,長吁一口氣:“原來是場噩夢啊……” “哼齿椅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起启泣,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤媒咳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后种远,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡顽耳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年坠敷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妙同。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膝迎,死狀恐怖粥帚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情限次,我是刑警寧澤芒涡,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站卖漫,受9級特大地震影響费尽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜羊始,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一旱幼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧突委,春花似錦柏卤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至敌蚜,卻和暖如春桥滨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钝侠。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工该园, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人帅韧。 一個(gè)月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓里初,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忽舟。 傳聞我的和親對象是個(gè)殘疾皇子双妨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評論 2 349

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