03.Android崩潰Crash庫(kù)之ExceptionHandler分析

目錄總結(jié)

  • 00.異常處理幾個(gè)常用api
  • 01.UncaughtExceptionHandler
  • 02.Java線程處理異常分析
  • 03.Android中線程處理異常分析
  • 04.為何使用setDefaultUncaughtExceptionHandler

前沿

00.異常處理幾個(gè)常用api

  • setUncaughtExceptionHandler
    • public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
      • 設(shè)置該線程由于未捕獲到異常而突然終止時(shí)調(diào)用的處理程序。
      • 通過(guò)明確設(shè)置未捕獲到的異常處理程序,線程可以完全控制它對(duì)未捕獲到的異常作出響應(yīng)的方式玻蝌。
      • 如果沒有設(shè)置這樣的處理程序灌危,則該線程的 ThreadGroup 對(duì)象將充當(dāng)其處理程序。
    • public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
      • 返回該線程由于未捕獲到異常而突然終止時(shí)調(diào)用的處理程序抽碌。
      • 如果該線程尚未明確設(shè)置未捕獲到的異常處理程序,則返回該線程的 ThreadGroup 對(duì)象决瞳,除非該線程已經(jīng)終止货徙,在這種情況下,將返回 null皮胡。
  • setDefaultUncaughtExceptionHandler
    • public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
      • 設(shè)置當(dāng)線程由于未捕獲到異常而突然終止痴颊,并且沒有為該線程定義其他處理程序時(shí)所調(diào)用的默認(rèn)處理程序。
      • 未捕獲到的異常處理首先由線程控制屡贺,然后由線程的 ThreadGroup 對(duì)象控制蠢棱,最后由未捕獲到的默認(rèn)異常處理程序控制锌杀。
      • 如果線程不設(shè)置明確的未捕獲到的異常處理程序,并且該線程的線程組(包括父線程組)未特別指定其 uncaughtException 方法泻仙,則將調(diào)用默認(rèn)處理程序的 uncaughtException 方法糕再。
        -- 通過(guò)設(shè)置未捕獲到的默認(rèn)異常處理程序,應(yīng)用程序可以為那些已經(jīng)接受系統(tǒng)提供的任何“默認(rèn)”行為的線程改變未捕獲到的異常處理方式(如記錄到某一特定設(shè)備或文件)玉转。
    • public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
      • 返回線程由于未捕獲到異常而突然終止時(shí)調(diào)用的默認(rèn)處理程序突想。
      • 如果返回值為 null,則沒有默認(rèn)處理程序究抓。
  • Thread.UncaughtExceptionHandler
    • public static interface Thread.UncaughtExceptionHandler
      • 所有已知實(shí)現(xiàn)類:ThreadGroup
      • 當(dāng) Thread 因未捕獲的異常而突然終止時(shí)猾担,調(diào)用處理程序的接口。
      • 當(dāng)某一線程因未捕獲的異常而即將終止時(shí)刺下,Java 虛擬機(jī)將使用 Thread.getUncaughtExceptionHandler() 查詢?cè)摼€程以獲得其 UncaughtExceptionHandler 的線程绑嘹,并調(diào)用處理程序的 uncaughtException 方法,將線程和異常作為參數(shù)傳遞橘茉。
      • 如果某一線程沒有明確設(shè)置其 UncaughtExceptionHandler工腋,則將它的 ThreadGroup 對(duì)象作為其 UncaughtExceptionHandler。
      • 如果 ThreadGroup 對(duì)象對(duì)處理異常沒有什么特殊要求畅卓,那么它可以將調(diào)用轉(zhuǎn)發(fā)給默認(rèn)的未捕獲異常處理程序夷蚊。

01.UncaughtExceptionHandler

  • 官方介紹為:
    • Interface for handlers invoked when a Thread abruptly terminates due to an uncaught exception.
    • When a thread is about to terminate due to an uncaught exception the Java Virtual Machine will query the thread for its UncaughtExceptionHandler using getUncaughtExceptionHandler() and will invoke the handler's uncaughtException method, passing the thread and the exception as arguments. If a thread has not had its UncaughtExceptionHandler explicitly set, then its ThreadGroup object acts as its UncaughtExceptionHandler. If the ThreadGroup object has no special requirements for dealing with the exception, it can forward the invocation to the default uncaught exception handler.
  • 翻譯后大概的意思是
    • UncaughtExceptionHandler接口用于處理因?yàn)橐粋€(gè)未捕獲的異常而導(dǎo)致一個(gè)線程突然終止問(wèn)題。
    • 當(dāng)一個(gè)線程因?yàn)橐粋€(gè)未捕獲的異常即將終止時(shí)髓介,Java虛擬機(jī)將通過(guò)調(diào)用getUncaughtExceptionHandler() 函數(shù)去查詢?cè)摼€程的UncaughtExceptionHandler并調(diào)用處理器的 uncaughtException方法將線程及異常信息通過(guò)參數(shù)的形式傳遞進(jìn)去惕鼓。如果一個(gè)線程沒有明確設(shè)置一個(gè)UncaughtExceptionHandler,那么ThreadGroup對(duì)象將會(huì)代替UncaughtExceptionHandler完成該行為唐础。如果ThreadGroup沒有明確指定處理該異常箱歧,ThreadGroup將轉(zhuǎn)發(fā)給默認(rèn)的處理未捕獲的異常的處理器。
  • 異骋慌颍回調(diào):uncaughtException
    • uncaughtException (Thread t, Throwable e) 是一個(gè)抽象方法呀邢,當(dāng)給定的線程因?yàn)榘l(fā)生了未捕獲的異常而導(dǎo)致終止時(shí)將通過(guò)該方法將線程對(duì)象和異常對(duì)象傳遞進(jìn)來(lái)。
  • 設(shè)置默認(rèn)未捕獲異常處理器:setDefaultUncaughtExceptionHandler
    • void setDefaultUncaughtExceptionHandler (Thread.UncaughtExceptionHandler eh)
    • 設(shè)置一個(gè)處理者當(dāng)一個(gè)線程突然因?yàn)橐粋€(gè)未捕獲的異常而終止時(shí)將自動(dòng)被調(diào)用豹绪。
    • 未捕獲的異常處理的控制第一個(gè)被當(dāng)前線程處理价淌,如果該線程沒有捕獲并處理該異常,其將被線程的ThreadGroup對(duì)象處理瞒津,最后被默認(rèn)的未捕獲異常處理器處理蝉衣。
    • 通過(guò)設(shè)置默認(rèn)的未捕獲異常的處理器,對(duì)于那些早已被系統(tǒng)提供了默認(rèn)的未捕獲異常處理器的線程巷蚪,一個(gè)應(yīng)用可以改變處理未捕獲的異常的方式病毡,例如記錄到指定的設(shè)備或者文件。
  • handler將會(huì)報(bào)告線程終止和不明原因異常這個(gè)情況屁柏,如果沒有自定義handler啦膜, 線程管理組就被默認(rèn)為報(bào)告異常的handler有送。
    • ThreadHandler 這個(gè)類就是實(shí)現(xiàn)了UncaughtExceptionHandler這個(gè)接口,偽代碼代碼如下所示
    public class ThreadHandler implements Thread.UncaughtExceptionHandler {
    
        private Thread.UncaughtExceptionHandler mDefaultHandler;
        private boolean isInit = false;
        /**
         * CrashHandler實(shí)例
         */
        private static ThreadHandler INSTANCE;
    
        /**
         * 獲取CrashHandler實(shí)例 ,單例模式
         */
        public static ThreadHandler getInstance() {
            if (INSTANCE == null) {
                synchronized (CrashHandler.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new ThreadHandler();
                    }
                }
            }
            return INSTANCE;
        }
    
        /**
         * 當(dāng)UncaughtException發(fā)生時(shí)會(huì)轉(zhuǎn)入該函數(shù)來(lái)處理
         * 該方法來(lái)實(shí)現(xiàn)對(duì)運(yùn)行時(shí)線程進(jìn)行異常處理
         */
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            if (mDefaultHandler != null) {
                //收集完信息后僧家,交給系統(tǒng)自己處理崩潰
                //uncaughtException (Thread t, Throwable e) 是一個(gè)抽象方法
                //當(dāng)給定的線程因?yàn)榘l(fā)生了未捕獲的異常而導(dǎo)致終止時(shí)將通過(guò)該方法將線程對(duì)象和異常對(duì)象傳遞進(jìn)來(lái)雀摘。
                mDefaultHandler.uncaughtException(t, e);
            } else {
                //否則自己處理
            }
        }
    
        /**
         * 初始化,注冊(cè)Context對(duì)象,
         * 獲取系統(tǒng)默認(rèn)的UncaughtException處理器,
         * 設(shè)置該CrashHandler為程序的默認(rèn)處理器
         * @param ctx
         */
        public void init(Application ctx) {
            if (isInit){
                return;
            }
            //獲取系統(tǒng)默認(rèn)的UncaughtExceptionHandler
            mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
            //將當(dāng)前實(shí)例設(shè)為系統(tǒng)默認(rèn)的異常處理器
            //設(shè)置一個(gè)處理者當(dāng)一個(gè)線程突然因?yàn)橐粋€(gè)未捕獲的異常而終止時(shí)將自動(dòng)被調(diào)用。
            //未捕獲的異常處理的控制第一個(gè)被當(dāng)前線程處理八拱,如果該線程沒有捕獲并處理該異常届宠,其將被線程的ThreadGroup對(duì)象處理,最后被默認(rèn)的未捕獲異常處理器處理乘粒。
            Thread.setDefaultUncaughtExceptionHandler(this);
            isInit = true;
        }
    }
    

02.Java線程處理異常分析

  • 線程出現(xiàn)未捕獲異常后,JVM將調(diào)用Thread中的dispatchUncaughtException方法把異常傳遞給線程的未捕獲異常處理器伤塌。
    public final void dispatchUncaughtException(Throwable e) {
        Thread.UncaughtExceptionHandler initialUeh = Thread.getUncaughtExceptionPreHandler();
        if (initialUeh != null) {
            try {
                initialUeh.uncaughtException(this, e);
            } catch (RuntimeException | Error ignored) {
                // Throwables thrown by the initial handler are ignored
            }
        }
        getUncaughtExceptionHandler().uncaughtException(this, e);
    }
    
    public static UncaughtExceptionHandler getUncaughtExceptionPreHandler() {
        return uncaughtExceptionPreHandler;
    }
    
  • Thread中存在兩個(gè)UncaughtExceptionHandler灯萍。一個(gè)是靜態(tài)的defaultUncaughtExceptionHandler,另一個(gè)是非靜態(tài)uncaughtExceptionHandler每聪。
    // null unless explicitly set
    private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
    
    // null unless explicitly set
    private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
    
    • defaultUncaughtExceptionHandler:設(shè)置一個(gè)靜態(tài)的默認(rèn)的UncaughtExceptionHandler旦棉。來(lái)自所有線程中的Exception在拋出并且未捕獲的情況下,都會(huì)從此路過(guò)药薯。進(jìn)程fork的時(shí)候設(shè)置的就是這個(gè)靜態(tài)的defaultUncaughtExceptionHandler绑洛,管轄范圍為整個(gè)進(jìn)程。
    • uncaughtExceptionHandler:為單個(gè)線程設(shè)置一個(gè)屬于線程自己的uncaughtExceptionHandler童本,轄范圍比較小真屯。
  • 沒有設(shè)置uncaughtExceptionHandler怎么辦?
    • 如果沒有設(shè)置uncaughtExceptionHandler穷娱,將使用線程所在的線程組來(lái)處理這個(gè)未捕獲異常绑蔫。
    • 線程組ThreadGroup實(shí)現(xiàn)了UncaughtExceptionHandler,所以可以用來(lái)處理未捕獲異常泵额。ThreadGroup類定義:
    private ThreadGroup group;
    //可以發(fā)現(xiàn)ThreadGroup類是集成Thread.UncaughtExceptionHandler接口的
    class ThreadGroup implements Thread.UncaughtExceptionHandler{}
    
  • 然后看一下ThreadGroup中實(shí)現(xiàn)uncaughtException(Thread t, Throwable e)方法配深,代碼如下
    • 默認(rèn)情況下,線程組處理未捕獲異常的邏輯是嫁盲,首先將異常消息通知給父線程組篓叶,
    • 然后嘗試?yán)靡粋€(gè)默認(rèn)的defaultUncaughtExceptionHandler來(lái)處理異常,
    • 如果沒有默認(rèn)的異常處理器則將錯(cuò)誤信息輸出到System.err羞秤。
    • 也就是JVM提供給我們?cè)O(shè)置每個(gè)線程的具體的未捕獲異常處理器缸托,也提供了設(shè)置默認(rèn)異常處理器的方法。
    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }
    

03.Android中線程處理異常分析

  • 在Android平臺(tái)中瘾蛋,應(yīng)用進(jìn)程fork出來(lái)后會(huì)為虛擬機(jī)設(shè)置一個(gè)未截獲異常處理器嗦董, 即在程序運(yùn)行時(shí),如果有任何一個(gè)線程拋出了未被截獲的異常瘦黑, 那么該異常最終會(huì)拋給未截獲異常處理器處理京革。
    • 具體可以找到RuntimeInit類奇唤,然后在找到KillApplicationHandler類。首先看該類的入口main方法--->commonInit()--->匹摇,然后接著往下走咬扇,找到setDefaultUncaughtExceptionHandler代碼如下所示
    • 如果報(bào)告崩潰,不要再次進(jìn)入——避免無(wú)限循環(huán)廊勃。如果ActivityThread分析器在此時(shí)運(yùn)行懈贺,我們殺死進(jìn)程,內(nèi)存中的緩沖區(qū)將丟失坡垫。并且打開崩潰對(duì)話框
    • 最后會(huì)執(zhí)行finally中殺死進(jìn)程的方法干掉app
    Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
    
    private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
        private final LoggingHandler mLoggingHandler;
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            try {
                if (mCrashing) return;
                mCrashing = true;
                if (ActivityThread.currentActivityThread() != null) {
                    ActivityThread.currentActivityThread().stopProfiling();
                }
                // Bring up crash dialog, wait for it to be dismissed
                ActivityManager.getService().handleApplicationCrash(
                        mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
            } catch (Throwable t2) {
                if (t2 instanceof DeadObjectException) {
                    // System process is dead; ignore
                } else {
                    try {
                        Clog_e(TAG, "Error reporting crash", t2);
                    } catch (Throwable t3) {
                        // Even Clog_e() fails!  Oh well.
                    }
                }
            } finally {
                // Try everything to make sure this process goes away.
                Process.killProcess(Process.myPid());
                System.exit(10);
            }
        }
    }
    
  • UncaughtExceptionHandler存在于Thread中.當(dāng)異常發(fā)生且未捕獲時(shí)梭灿。異常會(huì)透過(guò)UncaughtExceptionHandler拋出。并且該線程會(huì)消亡冰悠。所以在Android中子線程死亡是允許的堡妒。主線程死亡就會(huì)導(dǎo)致ANR。
  • 所以其實(shí)在fork出app進(jìn)程的時(shí)候溉卓,系統(tǒng)已經(jīng)為app設(shè)置了一個(gè)異常處理皮迟,并且最終崩潰后會(huì)直接導(dǎo)致執(zhí)行該handler的finallly方法最后殺死app直接退出app。如果你要自己處理桑寨,你可以自己實(shí)現(xiàn)Thread.UncaughtExceptionHandler伏尼。

04.為何使用setDefaultUncaughtExceptionHandler

  • Thread.UncaughtExceptionHandler 接口代碼如下所示
    @FunctionalInterface
    public interface UncaughtExceptionHandler {
        void uncaughtException(Thread t, Throwable e);
    }
    
    • UncaughtExceptionHandler 未捕獲異常處理接口,當(dāng)一個(gè)線程由于一個(gè)未捕獲異常即將崩潰時(shí)尉尾,JVM 將會(huì)通過(guò) getUncaughtExceptionHandler() 方法獲取該線程的 UncaughtExceptionHandler爆阶,并將該線程和異常作為參數(shù)傳給 uncaughtException()方法。
    • 如果沒有顯式設(shè)置線程的 UncaughtExceptionHandler沙咏,那么會(huì)將其 ThreadGroup 對(duì)象會(huì)作為 UncaughtExceptionHandler扰她。
    • 如果其 ThreadGroup 對(duì)象沒有特殊的處理異常的需求,那么就會(huì)調(diào) getDefaultUncaughtExceptionHandler() 方法獲取默認(rèn)的 UncaughtExceptionHandler 來(lái)處理異常芭碍。
  • 難道要為每一個(gè)線程創(chuàng)建UncaughtExceptionHandler嗎徒役?
    • 應(yīng)用程序通常都會(huì)創(chuàng)建很多線程,如果為每一個(gè)線程都設(shè)置一次 UncaughtExceptionHandler 未免太過(guò)麻煩窖壕。
    • 既然出現(xiàn)未處理異常后 JVM 最終都會(huì)調(diào) getDefaultUncaughtExceptionHandler()忧勿,那么我們可以在應(yīng)用啟動(dòng)時(shí)設(shè)置一個(gè)默認(rèn)的未捕獲異常處理器。即調(diào)用Thread.setDefaultUncaughtExceptionHandler(handler)
  • setDefaultUncaughtExceptionHandler被調(diào)用多次如何理解瞻讽?
    • Thread.setDefaultUncaughtExceptionHandler(handler) 方法如果被多次調(diào)用的話鸳吸,會(huì)以最后一次傳遞的 handler 為準(zhǔn),所以如果用了第三方的統(tǒng)計(jì)模塊速勇,可能會(huì)出現(xiàn)失靈的情況晌砾。對(duì)于這種情況,在設(shè)置默認(rèn) hander 之前烦磁,可以先通過(guò) getDefaultUncaughtExceptionHandler() 方法獲取并保留舊的 hander养匈,然后在默認(rèn) handler 的uncaughtException 方法中調(diào)用其他 handler 的 uncaughtException 方法哼勇,保證都會(huì)收到異常信息。

項(xiàng)目地址:https://github.com/yangchong211/YCAndroidTool

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呕乎,一起剝皮案震驚了整個(gè)濱河市积担,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌猬仁,老刑警劉巖帝璧,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異湿刽,居然都是意外死亡的烁,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門诈闺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)渴庆,“玉大人,你說(shuō)我怎么就攤上這事买雾。” “怎么了杨帽?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵漓穿,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我注盈,道長(zhǎng)晃危,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任老客,我火速辦了婚禮僚饭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胧砰。我一直安慰自己鳍鸵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布尉间。 她就那樣靜靜地躺著偿乖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哲嘲。 梳的紋絲不亂的頭發(fā)上贪薪,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音眠副,去河邊找鬼画切。 笑死,一個(gè)胖子當(dāng)著我的面吹牛囱怕,可吹牛的內(nèi)容都是我干的霍弹。 我是一名探鬼主播毫别,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼庞萍!你這毒婦竟也來(lái)了拧烦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钝计,失蹤者是張志新(化名)和其女友劉穎恋博,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體私恬,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡债沮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了本鸣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疫衩。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖荣德,靈堂內(nèi)的尸體忽然破棺而出闷煤,到底是詐尸還是另有隱情,我是刑警寧澤涮瞻,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布鲤拿,位于F島的核電站,受9級(jí)特大地震影響署咽,放射性物質(zhì)發(fā)生泄漏近顷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一宁否、第九天 我趴在偏房一處隱蔽的房頂上張望窒升。 院中可真熱鬧,春花似錦慕匠、人聲如沸饱须。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)冤寿。三九已至,卻和暖如春青伤,著一層夾襖步出監(jiān)牢的瞬間督怜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工狠角, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留号杠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像姨蟋,于是被迫代替她去往敵國(guó)和親屉凯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355