STK Telephony學習


1概述

前言

本文檔作為一個學習輸出丽旅,通過分析STK不同層級間命令的傳遞方式,總結(jié)STK模塊在Telephony部分的知識鹏溯。涉及framework與package目錄下的代碼它碎。

背景

STK即SIM?Tool Kit券敌,它提供一系列用于移動設備與SIM卡間交互的機制岖研。通過這些機制卿操,支持STK的手機可以操作SIM卡里的應用。其Framework層負責消息的轉(zhuǎn)化和傳遞孙援,實現(xiàn)RIL層與應用層間的交互诺核。

簡介

圖解

目前的手機硬件結(jié)構(gòu)大多分AP端與BP端恢氯。AP端運行操作系統(tǒng)以及各種基于操作系統(tǒng)的應用索守,BP端負責無線通信基本能力糊啡,Telephony的業(yè)務跨越了AP與BP夭咬,是做協(xié)議開發(fā)主要涉及的內(nèi)容蓬坡,具體如下圖轿衔。

Android Telephony?

從這個結(jié)構(gòu)圖可以看出:

- Telephony主要運行在Linux Kernel上的用戶空間毕箍。

- 與Android系統(tǒng)分層對應腮鞍。

- BP端是處理無線通信部分值骇,即modem部分。

組成

1. RIL層指的是工程目錄下hardware/ril部分移国,又稱RILC吱瘩,由C代碼組成,與上層java進行通信迹缀,具體的消息傳遞方式在2.3部分講述使碾。

2. Telephony Framework分為telecom和telephony,相關(guān)目錄為:

.../frameworks/base/telephony/java/com/android/internal/telephony/

.../frameworks/base/telecomm/java/com/android/internal/telecom/

.../frameworks/opt/telephony/src/java/com/android/internal/telephony/

? Stk模塊相關(guān)代碼為第三個目錄下的CatService.java以及RIL.java祝懂,其中CatService.java負責RIL層與應用層間的消息傳遞票摇;RIL.java為RIL層的上層結(jié)構(gòu),又稱RILJ砚蓬,與Telephony做最直接的交互矢门,作為RIL的消息入口。

3.Apps層存放在目錄/packages/services/Telephony/與/packages/services/Telecom/灰蛙,不涉及STK模塊祟剔。

接下來根據(jù)Telephony的分層結(jié)構(gòu)進行單獨的分析。

Telephony Framework

這一部分實現(xiàn)了STK APP與RIL層的信息同步摩梧,在modem端上傳SIM卡命令后物延,通過廣播的方式將命令發(fā)送至應用層處理,同時將應用層下發(fā)的TR傳至RILC仅父,最終實現(xiàn)消息的轉(zhuǎn)換與傳遞(下發(fā)的還有Envelope Command以及Terminal Profile)叛薯。負責處理STK業(yè)務邏輯的實類為CatService浑吟。

CatService

類圖


CatService


CatSerice繼承Handler,實現(xiàn)了AppInterface接口耗溜。

通過handler接收應用層消息

STK APP通過調(diào)用接口函數(shù)onCmdResponse()發(fā)送消息至CatService买置,具體代碼實現(xiàn):

??? public synchronized void onCmdResponse(CatResponseMessage resMsg) {

??????? if (resMsg == null) {

??????????? return;

??????? }

??????? // queue a response message.

??????? Message msg =obtainMessage(MSG_ID_RESPONSE, resMsg);

??????? msg.sendToTarget();

??? }

可以看到最終通過sendToTarget將消息發(fā)至自身的消息隊列。(這里用法與直接new Message 再調(diào)用sendMessage不同强霎,跟進前者代碼發(fā)現(xiàn)最終走的還是sendMessage忿项,區(qū)別在于沒有新構(gòu)造一個消息對象,根據(jù)注釋解釋城舞,前者更有效率)

通過Handler接收RILJ的消息

回到CatService的構(gòu)建函數(shù)轩触,可以看到:

???? // Register ril events handling.

????? mCmdIf.setOnCatSessionEnd(this,MSG_ID_SESSION_END, null);

????? mCmdIf.setOnCatProactiveCmd(this,MSG_ID_PROACTIVE_COMMAND, null);

????? mCmdIf.setOnCatEvent(this,MSG_ID_EVENT_NOTIFY, null);

????? mCmdIf.setOnCatCallSetUp(this,MSG_ID_CALL_SETUP, null);

???? //mCmdIf.setOnSimRefresh(this,MSG_ID_REFRESH, null);

這里調(diào)用了CommandInterface的函數(shù)去注冊實現(xiàn)觀察者模式,具體實現(xiàn)在RILJ的父類BaseCommands當中:

??? public void setOnCatProactiveCmd(Handler h,int what, Object obj) {

??????? mCatProCmdRegistrant = new Registrant(h, what, obj);

??? }

這里的Handler即為CatService自身家夺,即將自身所需接收的消息注冊給RILJ脱柱。

關(guān)鍵函數(shù)

1. getInstance::向外提供CatService的單例。

2. handlemessage:處理來自APP以及RILJ的消息拉馋。

3. sendStartDecodingMessageParams:接口函數(shù)榨为,將RIL Message解碼成CommandParams Objects。

4. handleRilMsg:處理解碼器轉(zhuǎn)換后的RIL層消息煌茴。

5. handleCommand:處理具體的命令随闺。

6. handleCmdResponse:處理APP發(fā)來的Repsonse。

7. sendTerminalResponse:發(fā)送TR蔓腐。矩乐、

消息處理

完整的CatService消息處理機制如下圖:


CatService消息處理

RILJ

類圖


RILJ類圖

關(guān)鍵函數(shù)

BaseCommands: 實現(xiàn)CommandsInterface的大部分接口函數(shù),涉及多個RegistrantList與Registrant回论,向外提供多個事件的觀察者模式注冊函數(shù)散罕。查看Registrant文件,發(fā)現(xiàn)就是對Handler的封裝傀蓉,由注冊的一方指定一個需要通知的事件欧漱,另一方只需要調(diào)用notifyRegistrant()來實現(xiàn)message的創(chuàng)建、填充葬燎、發(fā)送過程误甚。RegistrantList實現(xiàn)多個注冊對象的同時通知。

如: setOnCatProactiveCmd:主動式命令的監(jiān)聽注冊萨蚕,RILJ在接收到RILC的主動式命令消息后靶草,由Registrant向注冊時指定的Handler(這里指CatService)發(fā)送消息通知。

RILJ:將Telephony的業(yè)務封裝成RILRequest并發(fā)至RILC岳遥。

1. sendTerminalResponse:將主動式命令的處理結(jié)果封裝后發(fā)送至RILC奕翔。

2. getRadioProxy: 初始化IRadio相關(guān)服務。

3. obtainRequest:創(chuàng)建RILRequest對象浩蓉。

4. processResponse: 處理RILC請求返回的結(jié)果派继。

5. processIndication: 處理RILC上報的消息宾袜。

完整流程

貼上完整的主動式命令處理時Telephony部分的傳輸過程:

Proactive Command
Terminal Response

RIL層

這一部分主要是參考《Android Telephony 原理解析與開發(fā)指南》一書進行學習。

進入RILC的目錄驾窟,可以看到代碼結(jié)構(gòu)分為四部分庆猫,分別是include、libril绅络、reference-ril月培、rild。

- Include:ril.h定義了RIL_Init恩急、RIL_register等函數(shù)和其他結(jié)構(gòu)體杉畜,以及RIL消息RIL_REQUEST_XXX和RIL_UNSOL_XXX。

- libril:ril_commands.h衷恭、ril_unsol_commands.h此叠、ril.cpp、ril_service.cpp随珠。編譯輸出libril.so灭袁。

- reference_ril:編譯輸出libreference-ril.so,實現(xiàn)了RIL AT命令的交互機制窗看。

- rild:主要關(guān)注點茸歧,編譯生成可執(zhí)行文件rild。

RILC運行機制

消息分類

RIL中的消息類型烤芦,按照發(fā)起方分為Solicited以及UnSolicited举娩。

1. Solicited是由AP端發(fā)起的消息,又根據(jù)傳遞方向分為Solicited Request和Solicited Response构罗。

2. UnSolicited是由BP側(cè)主動發(fā)起的消息。

這兩種消息命名方式為RIL_REQUEST_ XXX智玻、RIL_REQUEST_XXX遂唧,具體的消息定義查看frameworks/base/telephony/java/com/android/internal/telephony/RILConstants.java

通過Radio log可以查看具體的消息類型與傳遞方向吊奢,其中’<’盖彭,’>’表示發(fā)送的方向。:

Solicitesd:

RILJ: [4041]> RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING [SUB0]

RILJ: [4041]< RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING [SUB0]

UnSolicited:

RILJ: [UNSL]< UNSOL_STK_PROACTIVE_COMMAND [SUB0]

消息處理

1. Solicited消息

以2.2.3發(fā)送TR為例页滚,RILJ最終調(diào)用的IRadio. sendTerminalResponseToSim()召边,該函數(shù)最終在

hardware/ril/libril/ril_service.cpp中實現(xiàn):

Return<void> RadioImpl::sendTerminalResponseToSim(int32_t serial,

? ? ? ? ? ? ? ? ? ? const hidl_string& commandResponse) {

#if VDBG

? ? RLOGD("sendTerminalResponseToSim: serial %d", serial);

#endif

? ? dispatchString(serial, mSlotId, RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE,

? ? ? ? ? ? commandResponse.c_str());

? ? return Void();

}

其中dispatchString函數(shù):

bool dispatchString(int serial, int slotId, int request, const char * str) {

? ? RequestInfo *pRI = android::addRequestToList(serial, slotId, request);

? ? if (pRI == NULL) {

? ? ? ? return false;

? ? }

? ? char *pString;

? ? if (!copyHidlStringToRil(&pString, str, pRI)) {

? ? ? ? return false;

? ? }

? ? CALL_ONREQUEST(request, pString, sizeof(char *), pRI, slotId);

? ? memsetAndFreeStrings(1, pString);

? ? return true;

}

在RadioImpl中可看到所有的Solicited消息處理最終都調(diào)用了dispatchString()。

主要關(guān)注addRequestToList與CALL_ONREQUEST

addRequestToList:

RequestInfo *

addRequestToList(int serial, int slotId, int request) {

? ? RequestInfo *pRI;

? ? int ret;

? ? RIL_SOCKET_ID socket_id = (RIL_SOCKET_ID) slotId;

? ? /* Hook for current context */

? ? /* pendingRequestsMutextHook refer to &s_pendingRequestsMutex */

? ? pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex;

? ? /* pendingRequestsHook refer to &s_pendingRequests */

? ? RequestInfo**? ? pendingRequestsHook = &s_pendingRequests;

? ? ......

? ? pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));

? ? if (pRI == NULL) {

? ? ? ? RLOGE("Memory allocation failed for request %s", requestToString(request));

? ? ? ? return NULL;

? ? }

? ? pRI->token = serial;

? ? pRI->pCI = &(s_commands[request]);

? ? pRI->socket_id = socket_id;

? ? ret = pthread_mutex_lock(pendingRequestsMutexHook);

? ? assert (ret == 0);

? ? pRI->p_next = *pendingRequestsHook;

? ? *pendingRequestsHook = pRI;

? ? ret = pthread_mutex_unlock(pendingRequestsMutexHook);

? ? assert (ret == 0);

? ? return pRI;

}

其中s_commands[]定義為ril_commands.h裹驰,該頭文件定義了RIL請求類型和回調(diào)函數(shù)隧熙,如{RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, radio::sendTerminalResponseToSimResponse}

即RILC會調(diào)用sendTerminalResponseToSimResponse作為Solicited Request消息的Response。

CALL_ONREQUEST:

ril_service.cpp的宏定義為:

#define CALL_ONREQUEST(a, b, c, d, e) s_vendorFunctions->onRequest((a), (b), (c), (d))

即CALL_ONREQUEST將調(diào)用s_vendorFunctions->onRequest, 進入該函數(shù)幻林,發(fā)現(xiàn)沒有對RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE做具體的處理贞盯,只調(diào)用RIL_onRequestComplete音念。

進入該函數(shù)的定義:

extern "C" void

RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {

? ? RequestInfo *pRI;

? ? int ret;

? ? RIL_SOCKET_ID socket_id = RIL_SOCKET_1;

? ? pRI = (RequestInfo *)t;

? ? if (!checkAndDequeueRequestInfoIfAck(pRI, false)) {

? ? ? ? RLOGE ("RIL_onRequestComplete: invalid RIL_Token");

? ? ? ? return;

? ? }

? ? socket_id = pRI->socket_id;

? ? appendPrintBuf("[%04d]< %s",

? ? ? ? pRI->token, requestToString(pRI->pCI->requestNumber));

? ? if (pRI->cancelled == 0) {

? ? ? ? int responseType;

? ? ? ? ......

? ? ? ? int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);

? ? ? ? assert(rwlockRet == 0);

? ? ? ? ret = pRI->pCI->responseFunction((int) socket_id,

? ? ? ? ? ? ? ? responseType, pRI->token, e, response, responselen);

? ? ? ? rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr);

? ? ? ? assert(rwlockRet == 0);

? ? }

? ? free(pRI);

}

以上的主要處理流程是:調(diào)用checkAndDequeueRequestInfoIfAck找到RIL請求對應的RequestInfo,通過pRI->pCI->responseFunction發(fā)起XXXResponse的調(diào)用躏敢,即上一步addRequestToList指定的Solicited消息對應的Response函數(shù)闷愤。

跟進Telephony framework中RadioResponse里的sendTerminalResponseToSimResponse,可看到最終調(diào)用了RILJ的processResponseDone件余,完成response的發(fā)送讥脐。

2. UnSolicited消息

UnSolicited類型的消息不確定發(fā)起點,從RILJ往下跟進啼器,在RadioIndication.java中可看到函數(shù)stkProactiveCommand攘烛,用于通知CAT并調(diào)用RILJ進行處理。

RadioIndication繼承IRadioIndication.Stub镀首,進入ril_service.cpp坟漱,radio::stkProactiveCommandInd調(diào)用了對應的stkProactiveCommand,實現(xiàn)了消息的傳遞更哄。

消息傳遞圖

下圖即為RIL的消息處理機制芋齿,其中RILJ通過rild提供的IRadio服務發(fā)送消息,RILC通過phone提供的IRadioResponse和IRadioIndication發(fā)送消息成翩,這一部分統(tǒng)稱為HIDL觅捆,是基于Binder通信實現(xiàn)的。(AIDL麻敌,HIDL運作原理還需要進一步學習)

以IRadio為例:IRadio.hal中定義了多個函數(shù)接口栅炒,如sendTerminalResponseToSim。在ril_servise中RadioImpl再實現(xiàn)該函數(shù)术羔。RILJ通過調(diào)用IRadio的接口實現(xiàn)消息的傳遞赢赊。

圖中的3是RILC與Modem的交互方式,是由廠商實現(xiàn)级历,下文了解一下高通的實現(xiàn)方式释移。

RIL消息傳遞

與Modem通信

結(jié)構(gòu)圖

關(guān)于Telephony與Modem直接的通信,高通實現(xiàn)方式是QMI+QCRIL寥殖,QCRIL為RILC的組成部分玩讳,QMI屬于Modem。

.該部分涉及高通文檔嚼贡,不確定是否為開源熏纯,暫時不貼圖

QCRIL+QMI

Vendor RIL初始化

rild.c主函數(shù)main中獲取了vendor RIL(QCRIL)的庫以及初始化入口方法,并進行初始化與注冊:

int main(int argc, char **argv) {?

? ? .......

? ? int i;

? ? const char *clientId = NULL;

? ? RLOGD("**RIL Daemon Started**");

? ? RLOGD("**RILd param count=%d**", argc);

? ? umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);

//1.獲取QCRIL路徑

? ? for (i = 1; i < argc ;) {

? ? ? ? if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {

? ? ? ? ? ? rilLibPath = argv[i + 1];

? ? ? ? ? ? i += 2;

? ? ? ? } else if (0 == strcmp(argv[i], "--")) {

? ? ? ? ? ? i++;

? ? ? ? ? ? hasLibArgs = 1;

? ? ? ? ? ? break;

? ? ? ? } else if (0 == strcmp(argv[i], "-c") &&? (argc - i > 1)) {

? ? ? ? ? ? clientId = argv[i+1];

? ? ? ? ? ? i += 2;

? ? ? ? } else {

? ? ? ? ? ? usage(argv[0]);

? ? ? ? }

? ? }

? ? .......


//2.打開vendor ril庫

? ? dlHandle = dlopen(rilLibPath, RTLD_NOW);

? ? //3.啟動消息循環(huán)

? ? RIL_startEventLoop();

? ? //4.獲取vendor RIL的初始化入口方法

? ? rilInit =

? ? ? ? (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))

? ? ? ? dlsym(dlHandle, "RIL_Init");

? ? ......


//5.調(diào)用vendor RIL的RIL_Init方法粤策,此方法會返回RIL_RadioFunctions

? ? funcs = rilInit(&s_rilEnv, argc, rilArgv);

? ? RLOGD("RIL_Init rilInit completed");


//6.注冊vendor RIL的處理方法

? ? RIL_register(funcs);

? ? ......

}

傳入回調(diào)函數(shù)

上文中提到的funcs = rilInit(&s_rilEnv, argc, rilArgv)實際上調(diào)用了QCRIL的RIL_Init樟澜,傳入了s_rilEnv,具體結(jié)構(gòu)為:

static struct RIL_Env s_rilEnv = {

? ? RIL_onRequestComplete,

? ? RIL_onUnsolicitedResponse,

? ? RIL_requestTimedCallback,

? ? RIL_onRequestAck

};;

即傳入rilc的方法供QCRIL回調(diào)掐场,通過回調(diào)實現(xiàn)消息傳遞往扔。

獲取QCRIL的函數(shù)接口

查看QCRIL的RIL_Init贩猎,主要執(zhí)行了以下幾個函數(shù):

qmi_ril_set_thread_name( pthread_self() , QMI_RIL_QMI_RILD_THREAD_NAME);

// Initialize the event thread */

qcril_event_init();

// Initialize QCRIL

qcril_init();

// Start event thread

qcril_event_start();

// start bootup if applicable

qmi_ril_initiate_bootup();

return &qcril_request_api[ QCRIL_DEFAULT_INSTANCE_ID ];

即初始化以及返回接口函數(shù)。

1. 其中qcril_event_int為初始化EventLoop線程萍膛,通過查看qcril_event_main的注釋可知EventLoop用于讀取并處理QMI的消息吭服。

2. 通過return &qcril_request_api[ QCRIL_DEFAULT_INSTANCE_ID ]返回函數(shù)列表供RILC使用。

消息傳遞

以RILC到QMI為例

在QCRIL初始化時提供的qcril_request_api具體定義如下:

static const RIL_RadioFunctions qcril_request_api[] = {

? { QCRIL_RIL_VERSION, onRequest_rid, currentState_rid, onSupports_rid, onCancel_rid, getVersion_rid }

};

當RIL層有請求時蝗罗,RILC調(diào)用其中的onRequest_rid:

static void onRequest_rid

(

? int request,

? void *data,

? size_t datalen,

? RIL_Token t

)

{

? onRequest( qmi_ril_process_instance_id, request, data, datalen, t );

}

實際上調(diào)用了onRequest艇棕,查看onRequest發(fā)現(xiàn)調(diào)用qcril_dispatch_event將消息發(fā)至對應的handler:

/* Dispatch the request to the appropriate handler */

(entry_ptr->handler)(params_ptr, &ret);

這里entry_ptr指的是qcril_dispatch_table_entry_type,該結(jié)構(gòu)定義了各種消息類型下對應的調(diào)用方法串塑,以發(fā)送TR為例:

{ QCRIL_REG_ALL_STATES( RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, qcril_gstk_qmi_request_stk_send_terminal_response ) }

查看該方法發(fā)現(xiàn)調(diào)用了QMI的qmi_client_send_msg_async沼琉,進一步調(diào)用qmi_service_msg發(fā)送消息至modem。

具體時序圖如下:


RILC to QMI

消息從QMI到QCRIL的處理過程與上圖類似:將消息發(fā)至QCRIL的隊列桩匪、QCRIL調(diào)用qcril_dispatch_event將消息發(fā)至對應的handler打瘪,qcril_dispatch_table_entry_type這個結(jié)構(gòu)不僅定義了上層消息對應的處理方法,還涉及modem發(fā)至QCRIL的各種消息傻昙。

總結(jié)

Telephony層涉及到的STK部分基本都是消息的傳遞闺骚,包括廣播,Handler妆档,HIDL僻爽。

RILJ以上的部分源碼相對來說不難閱讀和理解,且資料多贾惦。QCRIL+QMI部分僅根據(jù)log跟進了消息的傳遞胸梆。

以一張圖總結(jié)整體的消息傳遞方式:


STK Telephony
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市须板,隨后出現(xiàn)的幾起案子碰镜,更是在濱河造成了極大的恐慌,老刑警劉巖逼纸,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洋措,死亡現(xiàn)場離奇詭異,居然都是意外死亡杰刽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門王滤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贺嫂,“玉大人,你說我怎么就攤上這事雁乡〉谠” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵踱稍,是天一觀的道長曲饱。 經(jīng)常有香客問我悠抹,道長,這世上最難降的妖魔是什么扩淀? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任楔敌,我火速辦了婚禮,結(jié)果婚禮上驻谆,老公的妹妹穿的比我還像新娘卵凑。我一直安慰自己,他們只是感情好胜臊,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布勺卢。 她就那樣靜靜地躺著,像睡著了一般象对。 火紅的嫁衣襯著肌膚如雪黑忱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天勒魔,我揣著相機與錄音甫煞,去河邊找鬼。 笑死沥邻,一個胖子當著我的面吹牛危虱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播唐全,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼埃跷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了邮利?” 一聲冷哼從身側(cè)響起弥雹,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎延届,沒想到半個月后剪勿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡方庭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年厕吉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片械念。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡头朱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出龄减,到底是詐尸還是另有隱情项钮,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站烁巫,受9級特大地震影響署隘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜亚隙,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一磁餐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恃鞋,春花似錦崖媚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至水由,卻和暖如春荠呐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砂客。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工泥张, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鞠值。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓媚创,卻偏偏與公主長得像,于是被迫代替她去往敵國和親彤恶。 傳聞我的和親對象是個殘疾皇子钞钙,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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