夢(mèng)幻曲:Android系統(tǒng)啟動(dòng)

之前花過一段時(shí)間整理了下Android系統(tǒng)啟動(dòng)、Activity啟動(dòng)以及ActivityThread等系統(tǒng)內(nèi)容伏嗜。時(shí)間久遠(yuǎn)坛悉,很多細(xì)節(jié)都忘了,本著互聯(lián)共享的精神承绸,在這里把之前的文檔重新整理裸影。計(jì)劃寫三篇文章:《夢(mèng)幻曲:Android系統(tǒng)啟動(dòng)》,《沉思曲:Activity啟動(dòng)》军熏、《小夜曲:ActivityThread分析》轩猩,一家之言難免有各種問題,僅供參考荡澎。
參考 | http://blog.csdn.net/jeffbao/article/details/18242515

概念


Dalvik虛擬機(jī)

當(dāng)java程序運(yùn)行時(shí)均践,都是有一個(gè)虛擬機(jī)來解釋java的字節(jié)碼,它將這些字節(jié)碼翻譯成本地CPU的指令碼摩幔,然后執(zhí)行彤委。

AndroidRuntime

歸納起來的意思就是,Runtime 是支撐程序運(yùn)行的基礎(chǔ)庫或衡,它是與語言綁定在一起的焦影。比如:

  • C Runtime:就是C standard lib,也就是我們常說的libc封断。(有意思的是斯辰, Wiki會(huì)自動(dòng)將“C runtime" 重定向到 "C Standard Library")。
  • Java Runtime: 同樣坡疼,Wiki將其重定向到” Java Virtual Machine"彬呻,這里當(dāng)然包括Java 的支撐類庫(.jar)。
  • AndroidRuntime: 顯而易見柄瑰,就是為Android應(yīng)用運(yùn)行所需的運(yùn)行時(shí)環(huán)境废岂。包括:
    • Dalvik VM: Android的Java VM,解釋運(yùn)行Dex格式Java程序狱意。每個(gè)進(jìn)程運(yùn)行一個(gè)虛擬機(jī)(什么叫運(yùn)行虛擬機(jī)湖苞?說白了,就是一些C代碼详囤,不停的去解釋Dex格式的二進(jìn)制碼(Bytecode)财骨,把它們轉(zhuǎn)成機(jī)器碼(Machine code),然后執(zhí)行藏姐。
      • 當(dāng)然隆箩,現(xiàn)在大多數(shù)的Java 虛擬機(jī)都支持JIT,也就是說羔杨,byte code可能在運(yùn)行前就已經(jīng)被轉(zhuǎn)換成機(jī)器碼捌臊,從而大大提高了性能。過去一個(gè)普遍的認(rèn)識(shí)是Java 程序比C兜材,C++等靜態(tài)編譯的語言慢理澎,但隨著JIT的介入和發(fā)展逞力,這個(gè)已經(jīng)完全是過去時(shí)了,JIT的動(dòng)態(tài)性運(yùn)行允許虛擬機(jī)根據(jù)運(yùn)行時(shí)環(huán)境糠爬,優(yōu)化機(jī)器碼的生成寇荧,在某些情況下,Java甚至可以比C/C++跑得更快执隧,同時(shí)又兼具平臺(tái)無關(guān)的特性揩抡,這也是為什么Java如今如此流行的原因之一吧)。
    • Android的Java 類庫, 大部分來自于 Apache Hamony, 開源的Java API 實(shí)現(xiàn)镀琉,如 java.lang, java.util, java.net. 但去除了AWT, Swing 等部件峦嗤。
    • JNI: C和Java互調(diào)的接口。
    • Libc: Android也有很多C代碼屋摔,自然少不了libc烁设,注意的是,Android的libc叫 bionic C.


框架圖

在往下講之前凡壤,先看下框架圖:

框架圖.png

代碼流程圖

Android系統(tǒng)啟動(dòng)流程圖.png

init進(jìn)程


init進(jìn)程的啟動(dòng)配置在init.rc文件中署尤,
note:init.rc文件的語法可參考:init.rc分析

1.1、init進(jìn)程啟動(dòng)ServiceManager

/*service后第一個(gè)參數(shù)為進(jìn)程名亚侠,第二個(gè)參數(shù)為進(jìn)程路徑曹体,后面參數(shù)為啟動(dòng)改進(jìn)程傳遞的參數(shù)*/

//service關(guān)鍵字啟動(dòng)servicemanager
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm
  • Servicemanager負(fù)責(zé)管理所有的服務(wù)(native service、java service)硝烂,如服務(wù)的注冊(cè)箕别、查找等。
  • native service主要有: surfaceflinger滞谢、drm串稀、media等。
  • java service主要有:ActivityManagerService狮杨、WindowManagerService母截、PowerManagerService等。
  • 其中橄教,native service大多在init.rc文件中由service關(guān)鍵字創(chuàng)建啟動(dòng)清寇;java service大多由zygote創(chuàng)建啟動(dòng)。

1.2护蝶、init進(jìn)程啟動(dòng)Zygote

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
  • 由service第二個(gè)參數(shù)可知华烟,此處啟動(dòng)的進(jìn)程為zygote進(jìn)程,并由app_process實(shí)現(xiàn)持灰。
  • zygote由java編寫盔夜,不能有init進(jìn)程直接啟動(dòng);必須先生成Dalvik虛擬機(jī),再在Dalvik虛擬機(jī)中裝載zygote的實(shí)現(xiàn)類(ZygoteInit.java)喂链。

Zygote進(jìn)程


在往下講Zygote進(jìn)程前返十,先看附圖,了解下Zygote都做啥了:

Zygote.png

Zygote進(jìn)程的入口在app_main.cpp文件的main方法中衩藤,看下其main方法

2.1 main | app_main.cpp

int main(int argc, char* const argv[])
{
 ...
  //解析入?yún)陕颂幦雲(yún)椤?-zygote --start-system-server”
  while (i < argc) {
      const char* arg = argv[i++];
      if (!parentDir) {
          parentDir = arg;
      } else if (strcmp(arg, "--zygote") == 0) {
          zygote = true;
          niceName = "zygote";
      } else if (strcmp(arg, "--start-system-server") == 0) {
          startSystemServer = true;
      } else if (strcmp(arg, "--application") == 0) {
          application = true;
      } else if (strncmp(arg, "--nice-name=", 12) == 0) {
          niceName = arg + 12;
      } else {
          className = arg;
          break;
      }
  }

  //設(shè)置進(jìn)程名
  if (niceName && *niceName) {
      setArgv0(argv0, niceName);
      set_process_name(niceName);
  }

  runtime.mParentDir = parentDir;

  if (zygote) {
      //start生成并初始化Dalvik虛擬機(jī)涛漂,并加載ZygoteInit類到虛擬機(jī)中
      runtime.start("com.android.internal.os.ZygoteInit",
              startSystemServer ? "start-system-server" : "");
  } else if (className) {
      runtime.mClassName = className;
      runtime.mArgC = argc - i;
      runtime.mArgV = argv + i;
      //加載RuntimeInit類到虛擬機(jī)中
      runtime.start("com.android.internal.os.RuntimeInit",
              application ? "application" : "tool");
  } else {
      app_usage();
      return 10;
  }
}
  • 入?yún)椤?-zygote --start-system-server”赏表,通過調(diào)用runtime.start創(chuàng)建和生成Dalvik虛擬機(jī),并加載ZygoteInit類到虛擬機(jī)中匈仗。
  • 加載ZygoteInit類瓢剿,調(diào)用其main方法,啟動(dòng)SystemServer悠轩。

2.2间狂、main | ZygoteInit.java

public static void main(String argv[]) {
   try {
      //注冊(cè)server socket
      //其它進(jìn)程的創(chuàng)建,通過連接到該Socket后,由zygote孵化
      registerZygoteSocket();

      ...
      //預(yù)加載android framework類和資源
      preload();

      ...
      if (argv[1].equals("start-system-server")) {
          //啟動(dòng)SystemServer
          startSystemServer();
      } else if (!argv[1].equals("")) {
          throw new RuntimeException(argv[0] + USAGE_STRING);
      }

      //死循環(huán)接收client socket連接火架,由此創(chuàng)建新進(jìn)程
      runSelectLoop();

      closeServerSocket();
  } catch (MethodAndArgsCaller caller) {
      caller.run();
  } catch (RuntimeException ex) {
      closeServerSocket();
      throw ex;
  }
}
  • 入?yún)?start-system-server"鉴象,Zygote進(jìn)程調(diào)用 startSystemServer()方法啟動(dòng)SystemServer。

2.3何鸡、startSystemServer

startSystemServer方法在ZygoteInit.java中纺弊,看方法名是要啟動(dòng)SystemServer進(jìn)程了。

private static boolean startSystemServer()
        throws MethodAndArgsCaller, RuntimeException {
   ...
    //啟動(dòng)systemServer的參數(shù)
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "-- setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
        "--capabilities=" + capabilities + "," + capabilities,
        "--runtime-init",
        "--nice-name=system_server",
        //啟動(dòng)的SystemServer全限定名骡男,后續(xù)根據(jù)該參數(shù)反射創(chuàng)建實(shí)例
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;
    try {
        /**
         * 將傳入?yún)?shù)進(jìn)行轉(zhuǎn)換
         * 注意:參數(shù)com.android.server.SystemServer 放在parsedArgs中的remainingArgs里
         */
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        //Zygote為SystemServer創(chuàng)建子進(jìn)程
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    //子進(jìn)程執(zhí)行
    if (pid == 0) {
        handleSystemServerProcess(parsedArgs);
    }
    return true;
}
  • Zygote為SystemServer創(chuàng)建新進(jìn)程淆游,并在新進(jìn)程中調(diào)用handleSystemServerProcess。

SystemServer進(jìn)程


上一步中調(diào)用了handleSystemServerProcess方法隔盛。

3.1犹菱、handleSystemServerProcess

該方法在ZygoteInit.java文件中

private static void handleSystemServerProcess(
        ZygoteConnection.Arguments parsedArgs)
        throws ZygoteInit.MethodAndArgsCaller {

    //關(guān)閉SystemServer進(jìn)程的serversocket
    //SystemServer進(jìn)程基礎(chǔ)了父進(jìn)程zygote所有資源
    closeServerSocket();

    //設(shè)置文件權(quán)限
    Libcore.os.umask(S_IRWXG | S_IRWXO);

    //設(shè)置新進(jìn)程名
    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }

    if (parsedArgs.invokeWith != null) {
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                null, parsedArgs.remainingArgs);
    } else {
        //remainArgs中包含SystemServer的全限定名:com.android.server.SystemServer     
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
    }
}
  • 新進(jìn)程中接著調(diào)用RuntimeInit.zygoteInit方法

3.2、RuntimeInit.zygoteInit

RuntimeInit.zygoteInit為靜態(tài)方法吮炕,在RuntimeInit.java文件中腊脱。

public static final void zygoteInit(int targetSdkVersion, String[] argv)
        throws ZygoteInit.MethodAndArgsCaller {
    if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

    redirectLogStreams();

    commonInit();
    nativeZygoteInit();

    //調(diào)用該方法,往下執(zhí)行
    applicationInit(targetSdkVersion, argv);
}

3.3龙亲、applicationInit

上方法接著調(diào)用了applicationInit方法陕凹,該方法在RuntimeInit.java文件中。

private static void applicationInit(int targetSdkVersion, String[] argv)
        throws ZygoteInit.MethodAndArgsCaller {
    //應(yīng)用調(diào)用System.exit(),退出進(jìn)程
    nativeSetExitWithoutCleanup(true);

    //設(shè)置堆
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try {
        args = new Arguments(argv);
    } catch (IllegalArgumentException ex) {
        Slog.e(TAG, ex.getMessage());
        return;
    }
  
    //創(chuàng)建args.startClass實(shí)例俱笛,并調(diào)用其main方法
    invokeStaticMain(args.startClass, args.startArgs);
}
  • 該方法接著調(diào)用invokeStaticMain方法捆姜,注意:此處args.startClass為com.android.server.SystemServer

3.4、invokeStaticMain

上方法接著調(diào)用了invokeStaticMain方法迎膜,該方同樣在RuntimeInit.java中泥技。看方法名磕仅,似乎是反射調(diào)用main方法珊豹。

private static void invokeStaticMain(String className, String[] argv)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    try {
        //全限定名簸呈,此處傳入為"com.android.server.SystemServer"
        cl = Class.forName(className);
    }
    ...

    Method m;
    try {
        //main方法
        m = cl.getMethod("main", new Class[] { String[].class });
    }
    ...

    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                "Main method is not public and static on " + className);
    }

    /**
     * 該異常會(huì)在ZygoteInit.main()中被捕獲,
     * 捕獲后會(huì)觸發(fā)MethodAndArgsCaller的run()方法店茶,
     * run方法中完成類main方法的調(diào)用
     */
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
  • 該方法最后通過拋異常的方式蜕便,拋出異常MethodAndArgsCaller;該異常被Zygote捕獲贩幻,捕獲后調(diào)用該異常的run方法轿腺,而在run放中完成類main方法的調(diào)用。
  • 因此丛楚,該步最后調(diào)用SystemServer的main方法族壳。

3.5、main | SystemServer.java

終于調(diào)用SystemServer的main方法了趣些,看下其java層代碼主要干啥了仿荆。

public static void main(String[] args) {
    ...
    //SystemServer需要一直運(yùn)行,因此它需要有效的利用內(nèi)存
    VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

    Environment.setUserRequired(true);
    System.loadLibrary("android_servers");
   
    //初始化native服務(wù)
    nativeInit();

    //ServerThread并非Thread坏平,它只是運(yùn)行在SystemServer進(jìn)程的主線程中
    ServerThread thr = new ServerThread();
    //調(diào)用該方法初始化和循環(huán)處理
    thr.initAndLoop();
}

3.6拢操、initAndLoop

上面方法的主要內(nèi)容在initAndLoop方法中,該方法是SystemServer的內(nèi)部類ServerThread的方法舶替。

public void initAndLoop() {
    ...
    //main looper
    Looper.prepareMainLooper();
    ...

    try {
        //啟動(dòng)DisplayManagerService服務(wù)令境,并注冊(cè)到ServiceManager
        display = new DisplayManagerService(context, wmHandler);
        ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);

        //啟動(dòng)TelephonyRegistry服務(wù),并注冊(cè)到ServiceManager
        telephonyRegistry = new TelephonyRegistry(context);
        ServiceManager.addService("telephony.registry", telephonyRegistry);
      
        //啟動(dòng)其它服務(wù)坎穿,并注冊(cè)到ServiceManager
        ...

        //啟動(dòng)ActivityManagerService
        ActivityManagerService.setSystemProcess();

        //啟動(dòng)其它服務(wù)展父,并注冊(cè)到ServiceManager
        ...

    //調(diào)用ActivityManagerService的systemReady方法,啟動(dòng)Launcher
    ActivityManagerService.self().systemReady(new Runnable() {
        public void run() {
            ... 
            //開始系統(tǒng)啟動(dòng)畫面
            if (!headless) {
                startSystemUi(contextF);
            }
           ...
    });

    //不停的從消息隊(duì)列中獲取消息
    Looper.loop();
}
  • initAndLoop方法中玲昧,SystemServer主要負(fù)責(zé)啟動(dòng)各種服務(wù)栖茉,并將啟動(dòng)的服務(wù)注冊(cè)到ServiceManager中。
  • 上方法中注意ActivityManagerService的啟動(dòng)孵延,可知:
    • AMS在SystemServier進(jìn)程中運(yùn)行吕漂;
    • SystemServer調(diào)用AMS的systemReady方法來啟動(dòng)系統(tǒng)UI了;

插話

上面講完SystemServer進(jìn)程創(chuàng)建后,下一部分就是應(yīng)用進(jìn)程創(chuàng)建了尘应,這部分內(nèi)容在后面文章展開惶凝,這里貼副圖簡單描述下Zygote是如何創(chuàng)建應(yīng)用進(jìn)程的。改圖以Zygote創(chuàng)建Launcher進(jìn)程為例:


zygote創(chuàng)建應(yīng)用進(jìn)程.png

總結(jié)


回顧整篇內(nèi)容犬钢,可以用下圖做個(gè)簡單描述:

總結(jié).png

本文從init進(jìn)程啟動(dòng)出發(fā)苍鲜,沿著zygote進(jìn)程、SystemServer進(jìn)程創(chuàng)建流程分析了Android系統(tǒng)啟動(dòng)玷犹,其中內(nèi)容無非是這么幾點(diǎn):

  • init進(jìn)程創(chuàng)建了Zygote進(jìn)程
  • Zygote進(jìn)程孵化創(chuàng)建了SystemServer進(jìn)程
  • SystemServer進(jìn)程啟動(dòng)了Android常見的系統(tǒng)服務(wù)混滔,如AMS、PMS等。及SystemServer可理解為應(yīng)用與之交互的遠(yuǎn)程服務(wù)端坯屿。
  • 已知Android的每個(gè)進(jìn)程都與一個(gè)VM關(guān)聯(lián)油湖,上面代碼未展開描述,但可概括為:VM由Zygote創(chuàng)建领跛,Zygote每創(chuàng)建一個(gè)進(jìn)程乏德,就為為該進(jìn)程拷貝一份VM實(shí)例,從而實(shí)現(xiàn)關(guān)聯(lián)吠昭。

在后面的兩篇文章中喊括,會(huì)從Activity啟動(dòng)角度出發(fā),分析Zygote是如何創(chuàng)建應(yīng)用進(jìn)程怎诫,以及ActivityThread有如何使主線程等問題瘾晃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贷痪,一起剝皮案震驚了整個(gè)濱河市幻妓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌劫拢,老刑警劉巖肉津,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異舱沧,居然都是意外死亡妹沙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門熟吏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來距糖,“玉大人,你說我怎么就攤上這事牵寺『芬” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵帽氓,是天一觀的道長趣斤。 經(jīng)常有香客問我,道長黎休,這世上最難降的妖魔是什么浓领? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮势腮,結(jié)果婚禮上联贩,老公的妹妹穿的比我還像新娘。我一直安慰自己捎拯,他們只是感情好泪幌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般座菠。 火紅的嫁衣襯著肌膚如雪狸眼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天浴滴,我揣著相機(jī)與錄音拓萌,去河邊找鬼。 笑死升略,一個(gè)胖子當(dāng)著我的面吹牛微王,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播品嚣,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼炕倘,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了翰撑?” 一聲冷哼從身側(cè)響起罩旋,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎眶诈,沒想到半個(gè)月后涨醋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逝撬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年浴骂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宪潮。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡溯警,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出狡相,到底是詐尸還是另有隱情梯轻,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布谣光,位于F島的核電站檩淋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏萄金。R本人自食惡果不足惜蟀悦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氧敢。 院中可真熱鬧日戈,春花似錦、人聲如沸孙乖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至弯屈,卻和暖如春蜗帜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背资厉。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工厅缺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宴偿。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓湘捎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窄刘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窥妇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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