Android ANR分析詳解

traces文件分析

簡單了解ANR
各個(gè)應(yīng)用進(jìn)程和系統(tǒng)進(jìn)程的函數(shù)堆棧信息都輸出到了/data/anr/traces.txt的文件中,

 獲取traces 文件:adb pull /data/anr

pull目錄的原因是有些手機(jī)會對不同的應(yīng)用輸出專屬的traces文件,所以/data/anr目錄下會有一堆traces文件。一般三方app開發(fā)只關(guān)心自己的應(yīng)用,而且沒有root權(quán)限。所以只能分析traces文件定位anr,根據(jù)問題復(fù)現(xiàn)的模塊、頁面再結(jié)合traces文件三大常見的anr問題都能解決。打開traces文件搜索自己的應(yīng)用包名就能在前后的位置上找到引發(fā)anr的類和方法。如下:

1.主線程被阻塞,輸入事件5s沒有響應(yīng),如onClick事件。這是anr問題的主要類型,一般開發(fā)者不會犯這樣的錯(cuò),凡是耗時(shí)的操作都另開線程處理,如果疏忽了看看自己的代碼就知道怎么處理


image.png
  1. BroadcastReceiver是在程序主線程運(yùn)行,而且默認(rèn)情況下BroadcastReceiver的運(yùn)行時(shí)間為10s,所以不能有耗時(shí)操作,如果耗時(shí)超過10s就會導(dǎo)致anr,從traces文件log就可以看出onReceive不能進(jìn)行耗時(shí)任務(wù)。
    image.png

    BroadcastReceiver是Android的消息組件,用來組件之間、應(yīng)用之間的消息傳遞,生命周期太短也不能開子線程處理耗時(shí)任務(wù),耗時(shí)任務(wù)一般轉(zhuǎn)交給IntentService或者JobIntentService去做。

3.Service是計(jì)算型組件,雖然在后臺運(yùn)行,但是本質(zhì)上它也跑在主線程,如果你的服務(wù)要做任何CPU密集型(如MP3播放)或阻塞(如網(wǎng)絡(luò))操作,都要放在子線程中,否則耗時(shí)超過20s就會導(dǎo)致anr。注意anr方法是我自己寫的方法。onStartCommand()方法中有耗時(shí)任務(wù)將其放到子線程中去就可以了,例如:將下面的anr()方法放到子線程


image.png

traces文件信息解析

//開頭顯示進(jìn)程號、ANR發(fā)生的時(shí)間點(diǎn)和進(jìn)程名稱

    ----- pid 9183 at 2012-09-28 22:20:42 ----
 Cmd line: com.example.anrdemo

DALVIK THREADS: //以下是各個(gè)線程的函數(shù)堆棧信息
//依次是:線程名、線程優(yōu)先級、線程號、線程當(dāng)前狀態(tài)(TIMED_WAIT或SUSPENDED在anr時(shí)很常見)
//線程名稱后面標(biāo)識有daemon,說明這是個(gè)守護(hù)線程

"main" prio=5 tid=1 TIMED_WAIT
//依次是:線程組名稱、suspendCount個(gè)數(shù)、debugSuspendCount個(gè)數(shù)、線程的Java對象地址、線程的Native對象地址
| group="main" sCount=1 dsCount=0 obj=0x4025b1b8 self=0xce68

//sysTid是線程號,主線程的線程號和進(jìn)程號相同
| sysTid=9183 nice=0 sched=0/0 cgrp=default     
handle=-1345002368| schedstat=( 140838632 210998525 213 )
at java.lang.VMThread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1213)
.......


//Binder線程是進(jìn)程的線程池中用來處理binder請求的線程

"Binder Thread #2" prio=5 tid=8 NATIVE
| group="main" sCount=1 dsCount=0 obj=0x40750b90 self=0x1440b8
| sysTid=9190 nice=0 sched=0/0 cgrp=default handle=1476256
| schedstat=( 915528 18463135 4 )
at dalvik.system.NativeStart.run(Native Method)



//JDWP線程是支持虛擬機(jī)調(diào)試的線程,不需要關(guān)心

"JDWP" daemon prio=5 tid=5 VMWAIT
| group="system" sCount=1 dsCount=0 obj=0x4074b878 self=0x16c958
| sysTid=9187 nice=0 sched=0/0 cgrp=default handle=1510224
| schedstat=( 366211 2807617 7 )
t dalvik.system.NativeStart.run(Native Method)
//“Signal Catcher”負(fù)責(zé)接收和處理kernel發(fā)送的各種信號,例如SIGNAL_QUIT、SIGNAL_USR1等就是被該線程
//接收到,這個(gè)文件的內(nèi)容就是由該線程負(fù)責(zé)輸出的,可以看到它的狀態(tài)是RUNNABLE,不過此線程也不需要關(guān)心

"Signal Catcher" daemon prio=5 tid=4 RUNNABLE
| group="system" sCount=0 dsCount=0 obj=0x4074b7b8 self=0x150008
| sysTid=9186 nice=0 sched=0/0 cgrp=default handle=1501664
| schedstat=( 1708985 6286621 9 )

三方應(yīng)用開發(fā)如何避免ANR

三方應(yīng)用開發(fā)常見的anr三種情況前文已經(jīng)詳細(xì)呈現(xiàn),避免anr思路已經(jīng)清晰,簡單總結(jié)下:

  1. 絕對不要在主線程上進(jìn)行復(fù)雜耗時(shí)的操作,比如說發(fā)送接收網(wǎng)絡(luò)數(shù)據(jù)、進(jìn)行大量計(jì)算、操作數(shù)據(jù)庫、讀寫文件等,統(tǒng)統(tǒng)采用異步操作

2.broadCastReceiver 要進(jìn)行復(fù)雜操作的的時(shí)候,可以在onReceive()方法中啟動一個(gè)IntentService或者JobIntentService去做。

  1. Service中的耗時(shí)操作最好也是采用異步任務(wù)

4.在設(shè)計(jì)及代碼編寫階段避免出現(xiàn)出現(xiàn)同步/死鎖、死循環(huán)等不恰當(dāng)情況

Android系統(tǒng)開發(fā)中的ANR

對系統(tǒng)開發(fā)者來說只有/data/anr/traces.txt文件是遠(yuǎn)遠(yuǎn)不夠的。因?yàn)殡m然anr了但是traces文件沒有anr的log或者traces文件有l(wèi)og,但是并不能定位到導(dǎo)致anr問題的原因。
ANR對系統(tǒng)的穩(wěn)定性影響是比較大的,測試中心會將ANR作為系統(tǒng)穩(wěn)定性的重要case。系統(tǒng)開發(fā)者一般就要依賴工具和系統(tǒng)log來分析,anr報(bào)在你負(fù)責(zé)的模塊,但是導(dǎo)致anr的原因很可能在別的模塊,尤其在跑穩(wěn)定性測試的時(shí)候一些個(gè)別ANR問題很難調(diào)查清楚,畢竟腳本跟手動操作還是有些區(qū)別,而且像內(nèi)存碎片,硬件故障等等的問題基本應(yīng)用層是無從查起的,至少依靠個(gè)人是很難找出來,可能需要個(gè)團(tuán)隊(duì)一起關(guān)注(比如內(nèi)核,BSP),甚至是反饋給廠商去解決。

根據(jù)我的經(jīng)驗(yàn)以下幾種情況都會導(dǎo)致ANR:
  • CPU密集,導(dǎo)致主線程沒法搶占cpu時(shí)間片,要注意cpu占用高的進(jìn)程
  • 高IO,如不當(dāng)訪問數(shù)據(jù)庫導(dǎo)致數(shù)據(jù)庫負(fù)載過重時(shí)(log中cpu的使用iowait占比高)
  • 低內(nèi)存(low memory),如內(nèi)存不足導(dǎo)致block在創(chuàng)建bitmap上
  • 死鎖引發(fā)ANR,非主線程持有主線程需要的鎖對象,導(dǎo)致主線程等待超時(shí),通常log中會有以下字段 Blocked | - locked | waiting to lock | held by thread,這個(gè)時(shí)候cpu多數(shù)是空閑,使用占比很低
  • 當(dāng)前應(yīng)用進(jìn)程進(jìn)行進(jìn)程間通信請求其他進(jìn)程,其他進(jìn)程的操作長時(shí)間沒有反饋,例如操作硬件Camera
  • Service binder數(shù)量達(dá)到上限
  • 在system_server中觸發(fā)WatchDog ANR

當(dāng)然前面app中的ANR問題也會出現(xiàn),系統(tǒng)開發(fā)比較龐雜,也沒法整理出通用的情況案例,只能說ANR之后去如何分析。
我個(gè)人是MTK平臺做的比較多,平臺都有自己的工具,也會提供文檔,看看文檔摸索一下基本就能干活了

使用GAT工具

GAT是MTK在DDMS基礎(chǔ)上進(jìn)行二次開發(fā)封裝的一個(gè)集多種debug功能為一體的工具,除了包含原有DDMS的功能以外還支持kernel抓取,獲取native進(jìn)程列表,backtrace decode,提取手機(jī)端debug信息等功能。當(dāng)MTKLogger出現(xiàn)異常時(shí),經(jīng)常會需要使用GAT工具來抓取log。

mtklog里面都有意個(gè)aee_exp文件,里面有兩個(gè)文件一個(gè)是ZZ_INTERNAL,只有一句話,說出報(bào)的是什么錯(cuò)誤,發(fā)生錯(cuò)誤的進(jìn)程號,發(fā)生錯(cuò)誤的程序,報(bào)錯(cuò)時(shí)間等信息。


image.png

另外一個(gè)文件叫db.01.JE,這個(gè)文件里面放的報(bào)錯(cuò)的具體信息以及報(bào)錯(cuò)時(shí)候機(jī)器各種狀態(tài)的保存,但是這個(gè)文件只能用mtk特制的gat軟件打開。

點(diǎn)擊菜單上window--openlogView,點(diǎn)擊file-OpenAeeDB,選擇要打開的dbg格式的文件,左邊的一列目錄是各種報(bào)錯(cuò)時(shí)候的信息,最主要的是第一項(xiàng)exp_main.txt,在同級目錄下會輸出所有文件。


image.png

點(diǎn)開能發(fā)現(xiàn)最主要的報(bào)錯(cuò)信息,信息描述的很直接,對應(yīng)自己的程序就明白這些信息

Build Info:          //編譯信息
Flavor Info: 'None'
Exception Log Time:  //anr記錄時(shí)間

Exception Class: ANR
Exception Type: system_app_anr 
Current Executing Process:
com.android.settings
com.android.settings v19 (4.4.4-eng.scm.1428072972)

Backtrace:
Process: com.android.settings
Flags: 0x40c8be45
Package: com.android.settings v19 (4.4.4-eng.scm.1428072972)
Subject: Broadcast of Intent { act=[android.net]    (http://android.net/).conn.CONNECTIVITY_CHANGE flg=0x4000010 cmp=com.android.settings/.ales.NetworkReceiver (has extras) }
//如果是在某個(gè)頁面的話,會將頁面類名也輸出
Build: alps**************/1428069651:user/test-keys

Android time :[2017-12-14 20:07:52.45] [5284.377]
CPU usage from 3399ms to 151ms ago:
  100% 2281/com.***.app: 90% user + 10% kernel / faults: 20828 minor 4 major
  22% 1717/system_server: 13% user + 9.1% kernel / faults: 821 minor 7 major
  21% 192/logd: 3.6% user + 17% kernel / faults: 6 minor
  20% 237/mediaserver: 7.3% user + 13% kernel / faults: 1301 minor
  8.2% 243/mobile_log_d: 2.4% user + 5.7% kernel / faults: 66 minor
  3.3% 2442/tx_thread: 0% user + 3.3% kernel
  3.3% 6208/logcat: 0.3% user + 3% kernel
  2.7% 212/surfaceflinger: 0.3% user + 2.4% kernel
  2.4% 2138/com.android.systemui: 1.8% user + 0.6% kernel / faults: 40 minor
  1.2% 2128/sdcard: 0% user + 1.2% kernel
  0.9% 7/rcu_preempt: 0% user + 0.9% kernel
  ............
56% TOTAL: 37% user + 18% kernel + 0% iowait + 0.6% softirq

Android time :[2017-12-14 20:08:14.42] [5306.347]
CPU usage from 35171ms to 0ms ago:
  76% 2281/com.****.app: 61% user + 14% kernel / faults: 120156 minor
  52% 237/mediaserver: 21% user + 31% kernel / faults: 13346 minor
  43% 192/logd: 6.8% user + 36% kernel / faults: 116 minor
  20% 1717/system_server: 12% user + 7.6% kernel / faults: 1734 minor 6 major
  18% 212/surfaceflinger: 3.3% user + 14% kernel / faults: 30 minor
  16% 243/mobile_log_d: 5.7% user + 10% kernel / faults: 1236 minor
  7.5% 6208/logcat: 0.7% user + 6.7% kernel
  2.4% 2138/com.android.systemui: 1.5% user + 0.9% kernel / faults: 307 minor
  2.2% 2442/tx_thread: 0% user + 2.2% kernel
  ......
70% TOTAL: 33% user + 36% kernel + 0% iowait + 0.3% softirq
ANR發(fā)生之前和之后一段時(shí)間的CPU使用率

CPU使用率可以理解為一段時(shí)間(記作T)內(nèi)除CPU空閑時(shí)間(記作I)之外的時(shí)間與這段時(shí)間T的比值,用公式表示可以寫為:
CPU使用率= (T – I) / T
而時(shí)間段T是兩個(gè)采樣時(shí)間點(diǎn)的時(shí)間差值。之所以可以這樣計(jì)算,是因?yàn)長inux內(nèi)核會把從系統(tǒng)啟動開始到當(dāng)前時(shí)刻CPU活動的所有時(shí)間信息都記錄下來,我們可以通過查看“/proc/stat”文件獲取這些信息。主要包括以下幾種時(shí)間,這些時(shí)間都是從系統(tǒng)啟動開始計(jì)算的,單位都是0.01秒:
user: CPU在用戶態(tài)的運(yùn)行時(shí)間,不包括nice值為負(fù)數(shù)的進(jìn)程運(yùn)行的時(shí)間
nice: CPU在用戶態(tài)并且nice值為負(fù)數(shù)的進(jìn)程運(yùn)行的時(shí)間
system:CPU在內(nèi)核態(tài)運(yùn)行的時(shí)間
idle: CPU空閑時(shí)間,不包括iowait時(shí)間
iowait: CPU等待I/O操作的時(shí)間
irq: CPU硬中斷的時(shí)間
softirq:CPU軟中斷的時(shí)間

進(jìn)程的CPU使用率最后輸出的“faults: xxx minor/major”部分表示的是頁錯(cuò)誤次數(shù),當(dāng)次數(shù)為0時(shí)不顯示。major是指Major Page Fault(主要頁錯(cuò)誤,簡稱MPF),內(nèi)核在讀取數(shù)據(jù)時(shí)會先后查找CPU的高速緩存和物理內(nèi)存,如果找不到會發(fā)出一個(gè)MPF信息,請求將數(shù)據(jù)加載到內(nèi)存。Minor是指Minor Page Fault(次要頁錯(cuò)誤,簡稱MnPF),磁盤數(shù)據(jù)被加載到內(nèi)存后,內(nèi)核再次讀取時(shí),會發(fā)出一個(gè)MnPF信息。一個(gè)文件第一次被讀寫時(shí)會有很多的MPF,被緩存到內(nèi)存后再次訪問MPF就會很少,MnPF反而變多,這是內(nèi)核為減少效率低下的磁盤I/O操作采用的緩存技術(shù)的結(jié)果。

如果ANR發(fā)生時(shí)發(fā)現(xiàn)CPU使用率中iowait占比很高,可以通過查看進(jìn)程的major次數(shù)來推斷是哪個(gè)進(jìn)程在進(jìn)行磁盤I/O操作。

LOG怎么分析

首先了解一下主要的log文件

__exp_main.txt:異常類型,調(diào)用棧等關(guān)鍵信息。
SYS_ANDROID_LOG:android main log
SYS_KERNEL_LOG:kernel log
SYS_VERSION_INFO:kernel版本,用于和vmlinux對比,只有匹    配的vmlinux才能用于分析這個(gè)異常。
SYS_ANDROID_EVENT_LOG:系統(tǒng)事件信息
DUMPSYS_ACTIVITY:AMS日志
DUMPSYS_DBINFO :數(shù)據(jù)庫操作記錄
DUMPSYS_WINDOW :窗口記錄,記錄anr發(fā)生的窗口頁面
PROCESS_STATE: 發(fā)生ANR程序的進(jìn)程信息,虛擬機(jī)信息?
SWT_JBT_TRACES:不知道怎么描述,自認(rèn)為堆棧調(diào)用相關(guān)的記錄吧
SYS_ANDROID_EVENT_LOG:事件log,如ActivityManager、powerManager相關(guān)的活動記錄
SYS_ANDROID_LOG:  上層app以及framework相關(guān)活動的log
SYS_ANDROID_RADIO_LOG: 聯(lián)網(wǎng)相關(guān)
//binder相關(guān)
SYS_BINDER_INFO: 
SYS_BINDER_MEM_USED:
//parser解析文件夾,基本解析了anr相關(guān)的信息,CPU、內(nèi)存的診斷,binder分析    
parser

log很多沒有列舉全,常用的基本就這些,主要的log文件大概了解一下。首先ZZ_INTERNAL、__exp_main.txt文件中找到ANR的應(yīng)用進(jìn)程號、進(jìn)程名, SYS_ANDROID_EVENT_LOG中記錄的事件log中過濾am_anr,并且要對應(yīng)上進(jìn)程號,這個(gè)事件log基本就指出當(dāng)前在哪個(gè)類或者是什么操作,你就可以看看自己的代碼了


image.png

SWT_JBT_TRACES同樣找到對應(yīng)的進(jìn)程號,看看Heap是否不夠用了、線程是否被Blocked。一般線程被Blocked了,通常cpu的占用比較低。


image.png

Blocked就一定有被持有的對象,這個(gè)有時(shí)候是發(fā)生在binder,就需要分析binder相關(guān)的log
image.png

binder分配使用情況、診斷分析報(bào)告


image.png
image.png

ANR發(fā)生之后log中記錄的關(guān)鍵字段

  • am_anr: 描述了anr發(fā)生時(shí)的事件,原因,進(jìn)程。如果是自己的代碼導(dǎo)致的,這里會輸出你代碼具體的調(diào)用類


    image.png

    image.png

    image.png
  • ANR in:main_log 或 Sys_log ,描述anr發(fā)生的應(yīng)用模塊
    Reason:原因
    Android time :時(shí)間 ,有些時(shí)候需要根據(jù)時(shí)間到其他模塊追蹤問題
    上面這三個(gè)字段都會同時(shí)出現(xiàn)


    image.png
  • Blocked | - locked | waiting to lock | held by thread
    //發(fā)生在死鎖的情況下就會出現(xiàn)這三個(gè)關(guān)鍵字段

根據(jù)官網(wǎng)論述,死鎖現(xiàn)象會作為ANR的一種表現(xiàn)方式出現(xiàn),也會把日志記錄到/data/anr目錄下,但是如果死鎖發(fā)生在system server進(jìn)程中,則看門狗(watchdog)會殺掉system server進(jìn)程,并且在main log中會看到關(guān)鍵字"WATCHDOG KILLING SYSTEM PROCESS",系統(tǒng)運(yùn)行時(shí)將會重啟,system server也會重啟,此時(shí)用戶會看到開機(jī)動畫會再次播放。

  • WATCHDOG KILLING SYSTEM PROCESS

綜上所屬總結(jié)了一條快速過濾命令,一般穩(wěn)定性測試結(jié)束上傳的log非常大,解壓后幾個(gè)G的log文件是很正常,不可能打開搜索,即便時(shí)間多的用不完,打開的速度正常人也沒法忍受,所以直接linux命令過濾,之后再打開那個(gè)已經(jīng)過濾輸出的文件,命令如下:

grep -rn "ANR in\|ANRManager: Reason:\|ANRManager: Android time\|am_anr\|WATCHDOG KILLING SYSTEM PROCESS\| iowait\| Blocked\| held by thread\| waiting to lock"
高效的過濾命令,雖然grep很好用,文件超大的時(shí)候還是ag速度快
ag "ANR in|ANRManager: Reason:|ANRManager: Android time|am_anr|WATCHDOG KILLING SYSTEM PROCESS| iowait| Blocked| held by thread| waiting to lock"

ag的安裝

可以用過濾mobilelog文件夾進(jìn)行分析,不同的廠商系統(tǒng)日志輸出的地方不一樣。

ANR的一點(diǎn)源碼

ANR出現(xiàn)時(shí)調(diào)用的函數(shù)(源碼)

// 記錄ANR event log
  
        EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,app.processName, app.info.flags, annotation);

// 記錄ANR 到 main log

   StringBuilder info = new StringBuilder();
    info.setLength(0);
    info.append("ANR in ").append(app.processName); //關(guān)鍵字"ANR in"
    if (activity != null && activity.shortComponentName != null) {
        info.append(" (").append(activity.shortComponentName).append(")");
    }
    info.append("\n");
    info.append("PID: ").append(app.pid).append("\n");
    if (annotation != null) {
        info.append("Reason: ").append(annotation).append("\n");
    }
    if (parent != null && parent != activity) {
        info.append("Parent: ").append(parent.shortComponentName).append("\n");
    }

    final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);

    // dump堆棧log
    File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
            NATIVE_STACKS_OF_INTEREST);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,800評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,755評論 2 371

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