Android硬件抽象層

Android系統(tǒng)對(duì)硬件設(shè)備的支持是分兩層的焦除。一層實(shí)現(xiàn)在內(nèi)核空間中(只有內(nèi)核空間才有特權(quán)操作硬件設(shè)備)尽楔,另一層實(shí)現(xiàn)在用戶空間中繁涂。用戶空間中的這一層就是HAL層盹靴,也就是Hardware Abstract Layer層炸茧。而傳統(tǒng)的Linux系統(tǒng)中,對(duì)硬件的支持是完全實(shí)現(xiàn)在內(nèi)核空間中的稿静,即把對(duì)硬件的支持完全實(shí)現(xiàn)在硬件驅(qū)動(dòng)模塊中梭冠。

之所以這么設(shè)計(jì),是為了保護(hù)硬件廠商的利益改备。因?yàn)長(zhǎng)inux內(nèi)核源碼是遵循GPL協(xié)議的控漠,如果硬件廠商把對(duì)硬件的支持完全實(shí)現(xiàn)在硬件驅(qū)動(dòng)模塊中,那么就必須將硬件驅(qū)動(dòng)模塊的源代碼全部公開(kāi)悬钳,這相當(dāng)于暴露了硬件的實(shí)現(xiàn)細(xì)節(jié)和參數(shù)盐捷。

因此Android的做法是在內(nèi)核空間以硬件驅(qū)動(dòng)模塊的形式來(lái)僅僅提供簡(jiǎn)單的硬件訪問(wèn)通道,而用戶空間以硬件抽象模塊的形式封裝硬件的實(shí)現(xiàn)細(xì)節(jié)和參數(shù)默勾。我的理解是碉渡,驅(qū)動(dòng)層僅僅提供硬件寄存器的讀寫操作,如getValue()和setValue()母剥。而究竟按什么順序讀寫滞诺,讀寫什么內(nèi)容形导,則是放在硬件抽象層的。

除了上述的作用外习霹,硬件抽象層的模塊接口還定義了統(tǒng)一的規(guī)范朵耕。使得上層系統(tǒng)能夠以一致的方式獲取到硬件抽象模塊的句柄hw_module_t以及虛擬硬件設(shè)備句柄hw_device_t。

舉個(gè)例子

我們以一個(gè)具有一個(gè)4字節(jié)大小寄存器的虛擬字符硬件設(shè)備為例淋叶,觀察下虛擬字符設(shè)備定義阎曹,內(nèi)核驅(qū)動(dòng)編寫,硬件抽象層模塊編寫到實(shí)際的加載與使用的整個(gè)過(guò)程爸吮。我們將該設(shè)備命名為fake_reg芬膝,對(duì)應(yīng)的驅(qū)動(dòng)程序名為freg望门。

1形娇、開(kāi)發(fā)內(nèi)核空間驅(qū)動(dòng)層

freg.h

...

struct fake_reg_dev {

? ? int val;? //虛擬寄存器

? ? struct semaphore sem;? //信號(hào)量,用來(lái)同步訪問(wèn)虛擬寄存器val

? ? struct cdev dev; //標(biāo)準(zhǔn)的Linux字符設(shè)備結(jié)構(gòu)體變量

}

...

freg.c

...

//設(shè)備文件操作方法

static int freg_open(struct inode* inode, struct file* filp);

static int reg_release(struct inode* inode, struct file* filp);

static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loft_t * f_pos);

static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loft_t * f_pos);

//設(shè)備文件操作方法表

static struct file_operations freg_fops = {

? ? .owner = THIS_MODULE,

? ? .open = freg_open,

? ? .release = freg_release,

? ? .read = freg_read,

? ? ?.write = freg_write,

};

//freg_open的主要作用就是自定義設(shè)備結(jié)構(gòu)體保存在文件指針的私有數(shù)據(jù)域中筹误,方便之后訪問(wèn)設(shè)備時(shí)可

//以直接拿來(lái)用桐早。而文件句柄fd和filp是綁定的。因此獲取打開(kāi)的文件句柄厨剪,就可以訪問(wèn)到fake_reg_dev

static int freg_open(struct inode* inode, struct file* filp) {

? ? struct fake_reg_dev* dev;

? ? dev = container_of(inode->i_cdev, struct fake_reg_dev, dev);

? ? filp->private_data = dev;

? ?return 0;

}

static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loft_t* f_pos) {

...

? ? struct fake_reg_dev* dev = filp->private-data;

? ? copy_to_user(buf, &(dev->val), sizeof(dev->val));

...

}


static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loft_t* f_pos) {

...

? ? struct fake_reg_dev* dev = filp->private-data;

? ? copy_from_user(&(dev->val), buf, count)

...

}

...

在初始化硬件設(shè)備的時(shí)候哄酝,將freg_fops賦值給fake_reg_dev的cdev dev中的ops變量。那么之后在用戶空間調(diào)用

fd = open("/dev/freg", O_RDWR);

read(fd, &val, sizeof(val));

write(fd, &val, sizeof(val));

時(shí)祷膳,則會(huì)觸發(fā)內(nèi)核空間中的freg_open, freg_read以及freg_write方法被調(diào)用陶衅。從而完成硬件設(shè)備的訪問(wèn)。

硬件設(shè)備初始化

static int __freg_setup_dev(struct fake_reg_dev* dev) {

...

? ? memeset(dev, 0, sizeof(struct fake_reg_dev));

? ? cdev_init(&(dev->dev), &freg_fops);

? ? dev->dev.owner = THIS_MODULE;

? //將設(shè)備文件操作方法表賦給標(biāo)準(zhǔn)字符設(shè)備結(jié)構(gòu)體的ops變量

? ? dev->dev.ops = &freg_fops;? ?

? ? init_MUTEXT($(dev->sem));

? ? dev->val = 0;

...

}

忽略掉各種細(xì)節(jié)以后直晨,以上就是一個(gè)虛擬硬件設(shè)備的完整定義和驅(qū)動(dòng)搀军。將代碼編譯打包進(jìn)Android內(nèi)核鏡像文件后就可以使用了。

2勇皇、開(kāi)發(fā)硬件抽象層模塊

在第一節(jié)中我們定義了一個(gè)虛擬字符設(shè)備fake_reg罩句,以及相應(yīng)的驅(qū)動(dòng)程序freg。我們已經(jīng)可以通過(guò)read和write指令去讀寫其虛擬寄存器val的值敛摘。但是用這個(gè)寄存器存取什么值门烂,這個(gè)值用來(lái)做什么,我們還沒(méi)有定義兄淫。這就是我們?cè)谟布橄髮幽K中需要做的屯远。硬件抽象層模塊最終被會(huì)編譯成.so文件,通過(guò)加載該文件捕虽,我們就能夠獲取到硬件抽象層模塊的句柄氓润,也就是后文提到的hw_module_t的地址。

硬件抽象層模塊名稱與其對(duì)應(yīng)的.so文件位置有對(duì)應(yīng)的關(guān)系薯鳍,因此我們僅需要知道名稱就能打開(kāi)一個(gè)設(shè)備咖气。

2.1 硬件抽象層模塊編寫規(guī)范

硬件抽象層規(guī)范有兩個(gè)重要的結(jié)構(gòu)體:hw_module_t以及hw_device_t挨措,分別對(duì)應(yīng)硬件抽象層模塊和其包含的硬件設(shè)備。一個(gè)hw_module_t可以包含多個(gè)hw_device_t崩溪。

#define MAKE_TAG_CONSTANT(A,B,C,D) ((A) << 24) | ((B) << 16) | ((C) << 8) | (D))

#define? ? HARDWARE_MODULE_TAG? ? MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')

//每個(gè)硬件抽象層模塊的定義都必須包含一個(gè)名為HAL_MODULE_INFO_SYM的數(shù)據(jù)結(jié)構(gòu)浅役,并且該數(shù)據(jù)結(jié)構(gòu)第一個(gè)成員變量的類型必須是hw_module_t。在打開(kāi)模塊對(duì)應(yīng)的.so文件后就可以調(diào)用dlsym函數(shù)通過(guò)HAL_MODULE_INFO_SYM的字面值找到該結(jié)構(gòu)體的地址伶唯。由于該結(jié)構(gòu)體的第一個(gè)元素必須是hw_module_t觉既,于是我們其實(shí)也就拿到了hw_module_t的地址。

#define HAL_MODULE_INFO_SYM HMI

typedef struct hw_modult_t {

...

? ? uint32 tag;? //必須被初始化為HARDWARE_MODULE_TAG

? ? const char *id;? //硬件抽象層模塊的id

? ? const char *name; //硬件抽象層模塊的名字

? ?struct hw_module_methods_t *methods;? //模塊提供的方法

? ?void* dso;? //調(diào)用dlopen函數(shù)打開(kāi)此模塊對(duì)應(yīng)的.so文件時(shí)獲得的句柄乳幸,關(guān)閉的時(shí)候使用

...

} hw_module_t;



typedf struct hw_module_methods_t {

//打開(kāi)module模塊中對(duì)應(yīng)id值的硬件設(shè)備瞪讼,device為輸出參數(shù),用來(lái)描述一個(gè)已經(jīng)打開(kāi)的硬件設(shè)備

? ? int (*open) (const struct hw_module_t* module, const char* id, struct hw_device_t** device);

} hw_module_methods_t;



#define? ?HARDWARE_DEVICE_TAG? ?MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')

//每個(gè)硬件設(shè)備都必須定義一個(gè)硬件設(shè)備結(jié)構(gòu)體粹断,且第一個(gè)成員變量的類型必須為hw_device_t

typedef struct hw_device_t {

...

uint32_t tag;? //必須被初始化為HARDWARE_DEVICE_TAG

struct hw_module_t* module;? //硬件設(shè)備所屬于的硬件抽象層模塊

int (*close) (struct hw_device_t* device);? //硬件設(shè)備的打開(kāi)由hw_module_methods_t的open完成符欠,而關(guān)閉是由硬件設(shè)備自身完成的。

...

} hw_device_t;

以上就是硬件抽象層模塊以及硬件設(shè)備的編寫規(guī)范瓶埋∠J粒總結(jié)一下就是必須定義兩個(gè)自定義結(jié)構(gòu)體以及一個(gè)hw_module_methods_t結(jié)構(gòu)體。

一個(gè)自定義結(jié)構(gòu)體名字固定為HAL_MODULE_INFO_SYM养筒,且其第一個(gè)元素的類型必須是hw_module_t類型曾撤。

一個(gè)自定義結(jié)構(gòu)體名字不指定,但是其第一個(gè)元素的類型必須是hw_device_t類型晕粪。

接下來(lái)我們按照規(guī)范編寫之前定義的fake_reg設(shè)備的硬件抽象層模塊接口挤悉。

2.2 編寫硬件抽象層模塊接口

freg_module.h

...

#define FREG_HARDWARE_MODULE_ID "freg"? //模塊id

#define FREG_HARDWARE_DEVICE_ID "freg" //設(shè)備id

//聲明自定義模塊結(jié)構(gòu)體,后面會(huì)看到freg_module_t的實(shí)例名字為HAL_MODULE_INFO_SYM?

struct freg_module_t {

? ? struct hw_module_t common;? //第一個(gè)元素必須為hw_module_t類型

}

//自定義設(shè)備結(jié)構(gòu)體

struct freg_device_t {

? ? struct hw_device_t common;

? ? int fd;? ?//虛擬硬件設(shè)備的文件描述符

? ?int (*set_val) (struct freg_device_t* dev, int val);? ?//初始化時(shí)會(huì)被賦值為下文中定義的freg_set_val

? ?int (*get_val) (struct freg_device_t* dev, int* val); //初始化時(shí)會(huì)被賦值為下文中定義的freg_get_val

}

...

freg_module.cpp

...

#define DEVICE_NAME "/dev/freg/"

#define MODULE_NAME "Freg"

static int freg_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device);

static int freg_device_close(struct hw_device_t* device);

static int freg_get_val(struct freg_device_t* dev, int* val);

static int freg_set_val(struct freg_device_t* dev, int val);

static struct hw_module_methods_t freg_module_methods = {

? ? open:freg_device_open

}

//自定義模塊結(jié)構(gòu)體巫湘,且名字必須為HAL_MODULE_INFO_SYM

struct freg_module_t HAL_MODULE_INFO_SYM = {

? ? common: {

? ? ? ? ?tag: HARDWARE_MODULE_TAG,? ?//固定值

? ? ? ? ?version_major: 1,? //主版本號(hào)

? ? ? ? ?version_minor: 0, //次版本號(hào)

? ? ? ? ?id: FREG_HARDWARE_MODULE_ID,? //值為"freg"

? ? ? ? ?name: MODULE_NAME; //值為"Freg"

? ? ? ? ?methods: &freg_module_methods;

? ? }

};

...

以上定義了一個(gè)名為HAL_MODULE_INFO装悲,類型為自定義freg_module_t類型的結(jié)構(gòu)體,其第一個(gè)元素common為hw_module_t類型剩膘,hw_module_methods_t成員變量定義了freg_device_open方法衅斩。

定義了一個(gè)freg_device_t結(jié)構(gòu)體,其第一個(gè)元素common為hw_device_t類型怠褐。fd是該設(shè)備對(duì)應(yīng)的文件句柄畏梆。set_val以及get_val函數(shù)指針對(duì)應(yīng)著freg_get_val以及freg_set_val方法。

這樣奈懒,當(dāng)我們通過(guò)dlopen函數(shù)和dlsym函數(shù)獲取到hw_module_t指針后奠涌,就可以調(diào)用其open函數(shù)打開(kāi)對(duì)應(yīng)的freg_device_t設(shè)備,從而調(diào)用set_val和get_val函數(shù)磷杏。完成對(duì)硬件設(shè)備的操作溜畅。

接下來(lái),我們看下freg_device_open, freg_set_val,? freg_get_val的具體實(shí)現(xiàn)极祸。

static int freg_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device) {

...

? ? struct freg_device_t* dev;?

? ? dev->common.tag = HARDWARE_DEVICE_TAG;? //給hw_device_t類型的common的成員變量賦值

? ? dev->common.version = 0;

? ? dev->common.module = (hw_module_t*) module;

? ? dev->common.close = freg_device_close;

? ?dev->set_val = freg_set_val;

? ?dev->get_val = freg_get_val;

? ?dev->fd = open(DEVICE_NAME, O_RDWR);? ?//這里會(huì)調(diào)用第1節(jié)中定義在內(nèi)核空間的驅(qū)動(dòng)層的freg_fops的freg_open函數(shù)

? ?*device = &(dev->common);? //將賦好值的freg_device_t的common成員賦給輸出參數(shù)device.

? ?return 0;

...

}

static int freg_get_val(struct freg_device_t* dev, int* val) {

...

? ? read(dev->fd, val, sizeof(*val));? ?//會(huì)觸發(fā)第1節(jié)中定義在內(nèi)核空間的驅(qū)動(dòng)層的freg_fops的freg_read函數(shù)

...

}

static int freg_set_val(struct freg_device_t* dev, int val) {\

...

? ? write(dev->fd, &val, sizeof(val));?//會(huì)觸發(fā)第1節(jié)中定義在內(nèi)核空間的驅(qū)動(dòng)層的freg_fops的freg_write函數(shù)

...

}

由上可見(jiàn)慈格,獲取到hw_module_t句柄后怠晴,便可以通過(guò)其成員hw_module_methods_t中定義的freg_device_open打開(kāi)對(duì)應(yīng)的硬件設(shè)備,獲得freg_device_t句柄浴捆。從而通過(guò)其set_val和get_val來(lái)觸發(fā)之前在內(nèi)核空間中編寫的驅(qū)動(dòng)程序來(lái)訪問(wèn)硬件設(shè)備蒜田。

而其實(shí)質(zhì)還是通過(guò)硬件設(shè)備文件描述符dev->fd進(jìn)行read和write操作。freg_device_t的主要作用就是持有這個(gè)句柄选泻。

那么接下來(lái)冲粤,關(guān)鍵就是如何加載硬件驅(qū)動(dòng)層模塊并獲取到這個(gè)hw_module_t句柄。

2.3 硬件抽象層模塊的加載

由于硬件抽象層模塊對(duì)應(yīng)的.so文件的路徑是固定的页眯。因此只需要提供模塊ID梯捕,就能夠找到對(duì)應(yīng)的.so文件。其函數(shù)原型為

int hw_get_module(const char* id, const struct hw_module_t **module) {

...

? ? load(id, path, module);? //path是根據(jù)id按照一定的規(guī)則生成的路徑窝撵。一個(gè)典型值為/system/lib/hw/freg.goldfish.so

....

}

static int load(const char* id, const char* path, const struct hw_module_t **pHmi)? {

...

? ? void *handle;

? ? struct hw_module_t *hmi;

? ?handle = dlopen(path, RTLD_NOW);

? ?const char *sym = HAL_MODULE_INFO_SYM_AS_STR;? ?//在2.1節(jié)硬件抽象層模塊規(guī)范中定義了宏HAL_MODULE_INFO_SYM? HMI;

? ?hmi = (struct hw_module_t *)dlsym(handle,? sym); //HAL_MODULE_INFO結(jié)構(gòu)體的第一個(gè)成員必須是hw_module_t類型傀顾,因此可以直接轉(zhuǎn)型

? ?hmi->dso = handle;

? ?*pHmi = hmi;

...

}

于是通過(guò)hw_get_module函數(shù),我們就成功的獲取到了指定硬件抽象層模塊的hw_module_t的句柄忿族,從而可以調(diào)用freg_device_open方法打開(kāi)指定的硬件設(shè)備獲得freg_device_t句柄锣笨,從而可以以freg_device_t為參數(shù)調(diào)用set_val以及get_val函數(shù)對(duì)硬件設(shè)備進(jìn)行訪問(wèn)蝌矛。道批、

總結(jié)

1、Android對(duì)于硬件設(shè)備的支持分為兩部分入撒。

一是內(nèi)核空間層的驅(qū)動(dòng)部分隆豹,封裝了對(duì)硬件設(shè)備的簡(jiǎn)單存取邏輯。其中驅(qū)動(dòng)的編寫的步驟為

(1) 為fake_reg_dev結(jié)構(gòu)體的cdev標(biāo)準(zhǔn)字符設(shè)備結(jié)構(gòu)體的ops變量賦值茅逮。其類型為file_operations類型璃赡。

(2) 實(shí)現(xiàn)file_operations中的open, release, read, write指向的函數(shù)體,其中read, write的實(shí)現(xiàn)主要依靠copy_from_user以及copy_to_user兩個(gè)函數(shù)献雅,來(lái)實(shí)現(xiàn)用戶空間和內(nèi)核空間之間的數(shù)值傳遞碉考。

(3)調(diào)用文件操作函數(shù)open, read以及write時(shí),則會(huì)觸發(fā)我們?cè)?2)中指向的函數(shù)挺身。

二是硬件抽象層模塊部分侯谁,封裝了對(duì)于硬件設(shè)備的業(yè)務(wù)操作邏輯部分。其關(guān)鍵步驟為

(1)按照規(guī)范自定義硬件抽象層模塊結(jié)構(gòu)體章钾,其名字必須為HAL_MODULE_INFO_SYM墙贱,其第一個(gè)成員變量必須為hw_module_t類型。

(2)實(shí)現(xiàn)hw_module_t中hw_module_methods_t成員變量的open函數(shù)贱傀。打開(kāi)指定id的硬件設(shè)備惨撇。

(3)按照規(guī)范自定義硬件設(shè)備結(jié)構(gòu)體,其第一個(gè)成員變量必須是hw_device_t類型府寒。緊跟著硬件設(shè)備操作的函數(shù)

(4)調(diào)用hw_get_module函數(shù)獲取到指定id的硬件抽象層模塊的hw_module_t句柄魁衙,調(diào)用open打開(kāi)指定id的硬件設(shè)備报腔,獲得freg_device_t句柄。調(diào)用freg_device_t中定義的業(yè)務(wù)邏輯方法剖淀。

至此榄笙,整個(gè)硬件加載和訪問(wèn)流程就結(jié)束了。

這里有個(gè)需要注意的點(diǎn)是:freg_device_t和hw_device_t的地址祷蝌,以及freg_module_t和hw_module_t的地址是一樣的茅撞。所以freg_device_t和hw_device_t是可以互相強(qiáng)制轉(zhuǎn)型的,freg_module_t和hw_module_t也是如此巨朦。

本文的代碼示例都來(lái)源于老羅的《Android系統(tǒng)源代碼情景分析》第二章硬件抽象層米丘,只截取了關(guān)鍵代碼,初始化以及錯(cuò)誤處理部分進(jìn)行了省略糊啡。如需進(jìn)一步了解詳情可以查看該書(shū)相關(guān)章節(jié)拄查。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市棚蓄,隨后出現(xiàn)的幾起案子堕扶,更是在濱河造成了極大的恐慌,老刑警劉巖梭依,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稍算,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡役拴,警方通過(guò)查閱死者的電腦和手機(jī)糊探,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)河闰,“玉大人科平,你說(shuō)我怎么就攤上這事〗裕” “怎么了瞪慧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)部念。 經(jīng)常有香客問(wèn)我弃酌,道長(zhǎng),這世上最難降的妖魔是什么印机? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任矢腻,我火速辦了婚禮,結(jié)果婚禮上射赛,老公的妹妹穿的比我還像新娘多柑。我一直安慰自己,他們只是感情好楣责,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布竣灌。 她就那樣靜靜地躺著聂沙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪初嘹。 梳的紋絲不亂的頭發(fā)上及汉,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音屯烦,去河邊找鬼坷随。 笑死,一個(gè)胖子當(dāng)著我的面吹牛驻龟,可吹牛的內(nèi)容都是我干的温眉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼翁狐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼类溢!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起露懒,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤闯冷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后懈词,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蛇耀,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年钦睡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒂窒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躁倒。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荞怒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秧秉,到底是詐尸還是另有隱情褐桌,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布象迎,位于F島的核電站荧嵌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏砾淌。R本人自食惡果不足惜啦撮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汪厨。 院中可真熱鬧赃春,春花似錦、人聲如沸劫乱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至狭吼,卻和暖如春层坠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刁笙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工破花, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疲吸。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓旧乞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親磅氨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尺栖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355