systemServer進程

ZygoteInit.java main 函數(shù)中

public?static?void?main(String argv[])?{

.....

if?(startSystemServer) {

Runnable r =?forkSystemServer(abiList, socketName, zygoteServer);

private?static?Runnable?forkSystemServer(String abiList, String socketName,

? ? ? ? ZygoteServer zygoteServer) {

.....

String args[] = {

?"--setuid=1000",

?"--setgid=1000",

?"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",

?"--capabilities="?+ capabilities +?","?+ capabilities,

?"--nice-name=system_server",

?"--runtime-args",

?"com.android.server.SystemServer",

};

.....

pid =?Zygote.forkSystemServer(

? ? ? ? ? ? parsedArgs.uid, parsedArgs.gid,

? ? ? ? ? ? parsedArgs.gids,

? ? ? ? ? ? parsedArgs.debugFlags,

?null,

? ? ? ? ? ? parsedArgs.permittedCapabilities,

? ? ? ? ? ? parsedArgs.effectiveCapabilities);

}?catch?(IllegalArgumentException ex) {

?throw?new?RuntimeException(ex);

}

........

/* For child process */

if?(pid ==?0) {

?if?(hasSecondZygote(abiList)) {

?waitForSecondaryZygote(socketName);

? ? }

? ? zygoteServer.closeServerSocket();

?return?handleSystemServerProcess(parsedArgs);

}

systemServer 啟動之后,干了什么 ?

1 啟用Binder機制

2 啟動各類系統(tǒng)服務(wù), 把這些服務(wù)的Binder對象注冊到sm

3 進入Loop循環(huán)

看一下?handleSystemServerProcess 這個函數(shù)

private?static?Runnable?handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)?{

....

return?ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);

看一下zygoteInit函數(shù),主要干了三件事情

public?static?final?Runnable?zygoteInit(int?targetSdkVersion, String[] argv, ClassLoader classLoader)?{

?if?(RuntimeInit.DEBUG) {

? ? ? ? Slog.d(RuntimeInit.TAG,?"RuntimeInit: Starting application from zygote");

? ? }

? ? Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,?"ZygoteInit");

? ? RuntimeInit.redirectLogStreams();

?RuntimeInit.commonInit();

?ZygoteInit.nativeZygoteInit();// 啟用binder機制,啟動了binder線程,用于跟其他進程比如app ,sm 通訊

?return?RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);// 調(diào)用一個SystemServer Java 類的入口函數(shù)

}

看一下nativeZygoteInit// AndroidRuntime.cpp

static?void?com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)

{

? ? gCurRuntime->onZygoteInit();

}

webview_zygote.cpp

class?WebViewRuntime?:?public?AndroidRuntime {

public:

? ? WebViewRuntime(char* argBlockStart,?size_t?argBlockSize)

? ? ? ? : AndroidRuntime(argBlockStart, argBlockSize) {}

? ? ~WebViewRuntime() override {}

?void?onStarted()?override?{

?// Nothing to do since this is a zygote server.

? ? }

?void?onVmCreated(JNIEnv*)?override?{

?// Nothing to do when the VM is created in the zygote.

? ? }

?void?onZygoteInit()?override?{

?// Called after a new process is forked.

? ? ? ? sp<ProcessState> proc = ProcessState::self();

? ? ? ? proc->startThreadPool();

? ? }

看一下applicationInit方法

protected?static?Runnable?applicationInit(int?targetSdkVersion, String[] argv,

? ? ? ? ClassLoader classLoader) {

...

return?findStaticMain(args.startClass, args.startArgs, classLoader);// systemServer.main

看一下sytemServer的main函數(shù)

public?static?void?main(String[] args)?{

?new?SystemServer().run();

}

看一下這個run 函數(shù)

private?void?run()?{

?try?{

? ? ? ......

? ? ? ? Looper.prepareMainLooper();// 為主線程準(zhǔn)備一個Looper

?// Initialize native services.

?System.loadLibrary("android_servers");// 加載共享庫, systemserver系統(tǒng)服務(wù)的native層代碼

?// Check whether we failed to shut down last time we tried.

?// This call may not return.

?performPendingShutdown();

?// Initialize the system context.

?createSystemContext();// 創(chuàng)建系統(tǒng)上下文

...

?// Start services.

?try?{

?traceBeginAndSlog("StartServices");

? ? ? ? startBootstrapServices();

? ? ? ? startCoreServices();

? ? ? ? startOtherServices();

? ? ? ? SystemServerInitThreadPool.shutdown();

}?catch?(Throwable ex) {

? ? ? ? Slog.e("System",?"******************************************");

? ? ? ? Slog.e("System",?"************ Failure starting system services", ex);

?throw?ex;

}?finally?{

?traceEnd();

? ? }

?// For debug builds, log event loop stalls to dropbox for analysis.

?if?(StrictMode.conditionallyEnableDebugLogging()) {

? ? ? ? Slog.i(TAG,?"Enabled StrictMode for system server main thread.");

? ? }

?if?(!mRuntimeRestart?&& !isFirstBootOrUpgrade()) {

?int?uptimeMillis = (int) SystemClock.elapsedRealtime();

? ? ? ? MetricsLogger.histogram(null,?"boot_system_server_ready", uptimeMillis);

?final?int?MAX_UPTIME_MILLIS =?60?*?1000;

?if?(uptimeMillis > MAX_UPTIME_MILLIS) {

? ? ? ? ? ? Slog.wtf(SYSTEM_SERVER_TIMING_TAG,

?"SystemServer init took too long. uptimeMillis="?+ uptimeMillis);

? ? ? ? }

? ? }

?// Loop forever.

?Looper.loop();// 進入Loop循環(huán)

?throw?new?RuntimeException("Main thread loop unexpectedly exited");

}

如何發(fā)布系統(tǒng)服務(wù)?/systemserver進程啟動時啟動系統(tǒng)服務(wù)時,會把服務(wù)的Binder對象注冊到sm/ SytemService.java

/**

?* Publish the service so it is accessible to other services and apps.

?*/

protected?final?void?publishBinderService(String name, IBinder service)?{

publishBinderService(name, service,?false);

}

protected?final?void?publishBinderService(String name, IBinder service,

?boolean?allowIsolated) {

? ? ServiceManager.addService(name, service, allowIsolated);

}

public?static?void?addService(String name, IBinder service,?boolean?allowIsolated)?{

?try?{

?getIServiceManager().addService(name, service, allowIsolated);

}?catch?(RemoteException e) {

? ? ? ? Log.e(TAG,?"error in addService", e);

? ? }

}

如何使用系統(tǒng)服務(wù)?// ContextImpl.java

@Override

public?Object?getSystemService(String name)?{

?return?SystemServiceRegistry.getSystemService(this, name);

}

public?static?Object?getSystemService(ContextImpl ctx, String name)?{

ServiceFetcher fetcher =?SYSTEM_SERVICE_FETCHERS.get(name);// 根據(jù)名稱獲取ServiceFetcher hashmap

?return?fetcher !=?null?? fetcher.getService(ctx) :?null;

}

static?abstract?class?CachedServiceFetcher<T>?implements?ServiceFetcher<T>?{

?private?final?int?mCacheIndex;

?public?CachedServiceFetcher()?{

?mCacheIndex?=?sServiceCacheSize++;

? ? }

?@Override

?@SuppressWarnings("unchecked")

?public?final?T?getService(ContextImpl ctx)?{

?final?Object[] cache = ctx.mServiceCache;

?synchronized?(cache) {

?// Fetch or create the service.

?Object service = cache[mCacheIndex];

?if?(service ==?null) {

?try?{

? ? ? ? ? ? ? ? ? ? service = createService(ctx);

? ? ? ? ? ? ? ? ? ? cache[mCacheIndex] = service;

}?catch?(ServiceNotFoundException e) {

?onServiceNotFound(e);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

?return?(T)service;

? ? ? ? }

? ? }

?public?abstract?T?createService(ContextImpl ctx)?throws?ServiceNotFoundException;

}

registerService(Context.POWER_SERVICE, PowerManager.class,//SystemServiceRegisry.java, 以PowerManagerService為例子

?new?CachedServiceFetcher<PowerManager>() {

?@Override

?public?PowerManager?createService(ContextImpl ctx)?throws?ServiceNotFoundException?{

? ? ? ? IBinder b = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);// BpBinder對象

? ? ? ? IPowerManager service = IPowerManager.Stub.asInterface(b);

?return?new?PowerManager(ctx.getOuterContext(),

? ? ? ? ? ? ? ? service, ctx.mMainThread.getHandler());// 根據(jù)service 封裝成Powermanager對象,不用catch RemoteException,靜態(tài)代理實際上還是調(diào)用的service的函數(shù)

? ? }});

看一下getServiceOrThrow

public?static?IBinder?getServiceOrThrow(String name)?throws?ServiceNotFoundException?{

?final?IBinder binder =?getService(name);

?if?(binder !=?null) {

?return?binder;

}?else?{

?throw?new?ServiceNotFoundException(name);

? ? }

}

// 看一個getService 函數(shù)

public?static?IBinder?getService(String name)?{

?try?{

IBinder service =?sCache.get(name);// 緩存是用來放預(yù)制的IbInder對象,

?if?(service !=?null) {

?return?service;

}?else?{

?return?Binder.allowBlocking(getIServiceManager().getService(name));// 這一步并沒有放到緩存里

? ? ? ? }

}?catch?(RemoteException e) {

? ? ? ? Log.e(TAG,?"error in getService", e);

? ? }

?return?null;

}

不是所有的系統(tǒng)服務(wù)都跑在SystemServer進程里面的,比如SF,mediaserver,sm進程等,也需要注冊到sm,這樣別人才能找打它.

獨立進程的系統(tǒng)服務(wù):SF

service surfaceflinger?/system/bin/surfaceflinger// 進程啟動時加載的二進制文件路徑

?class?core?animation

? ? user system

? ? group graphics drmrpc readproc

? ? onrestart restart zygote

? ? writepid /dev/stune/foreground/tasks

看一個sf啟動時的main函數(shù)//main_surfaceflinger.cpp

int main(int, char**) {

? ? startHidlServices();

? ? signal(SIGPIPE, SIG_IGN);

?// When SF is launched in its own process, limit the number of

?// binder threads to 4.

? ? ProcessState::self()->setThreadPoolMaxThreadCount(4);

?// start the thread pool

? ? sp<ProcessState> ps(ProcessState::self());//ProcessState 的 構(gòu)造函數(shù)中啟用binder機制

? ? ps->startThreadPool();

?// instantiate surfaceflinger

? ? sp<SurfaceFlinger> flinger = DisplayUtils::getInstance()->getSFInstance();

setpriority(PRIO_PROCESS,?0, PRIORITY_URGENT_DISPLAY);

? ? set_sched_policy(0, SP_FOREGROUND);

?// Put most SurfaceFlinger threads in the system-background cpuset

?// Keeps us from unnecessarily using big cores

?// Do this after the binder thread pool init

?if?(cpusets_enabled()) set_cpuset_policy(0, SP_SMT_SYSTEM);

?// initialize before clients can connect

? ? flinger->init();

?// publish surface flinger

? ? sp<IServiceManager> sm(defaultServiceManager());

? ? sm->addService(String16(SurfaceFlinger::getServiceName()), flinger,?false);

?// publish GpuService

sp gpuservice =?new?GpuService();

sm->addService(String16(GpuService::SERVICE_NAME), gpuservice,?false);

? ? struct sched_param param = {0};

param.sched_priority =?2;

?if?(sched_setscheduler(0, SCHED_FIFO, ?m) !=?0) {

? ? ? ? ALOGE("Couldn't set SCHED_FIFO");

? ? }

?// run surface flinger in this thread

? ? flinger->run();// 進入Loop循環(huán)

?return?0;

}

系統(tǒng)服務(wù)和bind 的應(yīng)用服務(wù)有什么區(qū)別?

1 啟動方式:

啟動服務(wù),主要是做了服務(wù)的初始化工作,比如準(zhǔn)備好服務(wù)的binder的實體對象,當(dāng)client有請求過來時,就會在binder線程池中,把請求分發(fā)給對應(yīng)的binder實體對象,再回復(fù)給client端;binder線程中等待client請求,在分發(fā)給binder實體對象

系統(tǒng)服務(wù):啟動了AMS WMS PMS ?

client-->Binder線程池-->各個service ? ? ?

startBootstrapServices();

? ? ? ? startCoreServices();

? ? ? ? startOtherServices();

應(yīng)用服務(wù)的啟動,無論是startService/bindService,都是應(yīng)用端發(fā)起,都會調(diào)用到AMS

ConTextImpl.java

private?ComponentName?startServiceCommon(Intent service,?boolean?requireForeground,

? ? ? ? UserHandle user) {

?try?{

? ? ? ? validateServiceIntent(service);

? ? ? ? service.prepareToLeaveProcess(this);

? ? ? ? ComponentName cn = ActivityManager.getService().startService(// AMS 創(chuàng)建ServiceRecord,sr不是真正的service,只是service的記錄,Ams只負(fù)責(zé)service的管理和調(diào)度,真正service的啟動和加載還是需要在應(yīng)用端來做

?mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(

? ? ? ? ? ? ? ? ? ? ? ? getContentResolver()), requireForeground,

? ? ? ? ? ? ? ? ? ? ? ? getOpPackageName(), user.getIdentifier());

// 看一下Ams的startService方法

public?ComponentName?startService(IApplicationThread caller, Intent service,

String resolvedType,?boolean?requireForeground, String callingPackage,?int?userId)

?throws?TransactionTooLargeException {

.....

res =?mServices.startServiceLocked(caller, service,

? ? ? ? resolvedType, callingPid, callingUid,

? ? ? ? requireForeground, callingPackage, userId);//mServices 是ActiveServices 的實例調(diào)用到了

......

startServiceLocked-->startServiceInnerLocked-->bringUpServiceLocked-->realStartServiceLocked-->

//ActivityService.java

private?final?void?realStartServiceLocked(ServiceRecord r,

ProcessRecord app,?boolean?execInFg)?throws?RemoteException {

....

app.thread.scheduleCreateService(r, r.serviceInfo,

?mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),

? ? ? ? app.repProcState);

app.thread.scheduleCreateService 這個方法會調(diào)用到應(yīng)用端

應(yīng)用端是怎么做的?//ActivityThread.java

public?final?void?scheduleCreateService(IBinder token,

ServiceInfo info, CompatibilityInfo compatInfo,?int?processState) {

? ? AnrLogger.notesServiceTrack(info.name, token,?"create binder receive");

updateProcessState(processState,?false);

CreateServiceData s =?new?CreateServiceData();

? ? s.token?= token;

?s.info?= info;

? ? s.compatInfo?= compatInfo;

? ? sendMessage(H.CREATE_SERVICE, s);

}

// ActivityThread handleMessage方法

public?void?handleMessage(Message msg) {

......

case?CREATE_SERVICE:

? ? Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: "?+ String.valueOf(msg.obj)));

?handleCreateService((CreateServiceData)msg.obj);

? ? Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

?break;

private?void?handleCreateService(CreateServiceData?data) {

?// If we are getting ready to gc after going to the background, well

?// we are back active so skip it.

?AnrLogger.notesServiceTrack(null,?data.token,?"create main receive");

? ? unscheduleGcIdler();

? ? LoadedApk packageInfo = getPackageInfoNoCheck(

?data.info.applicationInfo,?data.compatInfo);

Service service =?null;

?try?{

? ? ? ? java.lang.ClassLoader cl = packageInfo.getClassLoader();//加載service類

? ? ? ? service = (Service) cl.loadClass(data.info.name).newInstance();// 調(diào)用service的newInstance創(chuàng)建實例

}?catch?(Exception e) {

?if?(!mInstrumentation.onException(service, e)) {

?throw?new?RuntimeException(

?"Unable to instantiate service "?+?data.info.name

?+?": "?+ e.toString(), e);

? ? ? ? }

? ? }

?try?{

?if?(localLOGV) Slog.v(TAG,?"Creating service "?+?data.info.name);

ContextImpl?context?= ContextImpl.createAppContext(this, packageInfo);

? ? ? ? context.setOuterContext(service);// 給service 創(chuàng)建上下文

? ? ? ? Application app = packageInfo.makeApplication(false,?mInstrumentation);// 創(chuàng)建appli

?service.attach(context,?this,?data.info.name,?data.token, app,

? ? ? ? ? ? ? ? ActivityManager.getService());//給service 賦予上下文

? ? ? ? service.onCreate();// 執(zhí)行生命周期方法

?mServices.put(data.token, service);

?try?{

? ? ? ? ? ? ActivityManager.getService().serviceDoneExecuting(

?data.token,?SERVICE_DONE_EXECUTING_ANON,?0,?0);

? ? ? ? ? ? AnrLogger.notesServiceTrack(null,?data.token,?"create done");

}?catch?(RemoteException e) {

?throw?e.rethrowFromSystemServer();

? ? ? ? }

}?catch?(Exception e) {

?if?(!mInstrumentation.onException(service, e)) {

?throw?new?RuntimeException(

?"Unable to create service "?+?data.info.name

?+?": "?+ e.toString(), e);

? ? ? ? }

? ? }

}

2 注冊方式:

系統(tǒng)服務(wù) sm->addService // 注冊到serviceManger,不是任意的binder實體對象都能注冊到sm,應(yīng)用端的binder實體對象注冊到sm會提示權(quán)限錯誤,只有系統(tǒng)服務(wù)才能注冊到sm

應(yīng)用服務(wù): 應(yīng)用向AMS發(fā)起bindService調(diào)用, AMS先看service注冊過沒有,如果注冊過,就把service的binder對象返回給應(yīng)用,如果沒有注冊過,就向Service請求Binder對象,service響應(yīng)請求,把自己的binder對象注冊到AMS,然后AMS在把binder對象回調(diào)給應(yīng)用

3 使用方式:

系統(tǒng)服務(wù)的使用context.getSystemService(Context.POWER_SERVICE);

應(yīng)用服務(wù)通過bindService(serviceIntent, new ServiceCOnnection){

? ? ? ? public void onServiceConnected(ComponentName name, IBinder service) {

? ? ? ? ?IMyInterface myInterface = IMyInterface.Stub.asInterface(service);


? ? ? ? }

? ? ? ? public void onServiceDisconnected(ComponentName name) {

? ? ? ? }

}

SystemServer 里面,系統(tǒng)服務(wù)大概有70-80個,1 這些系統(tǒng)服務(wù)跑在什么線程?

主線程? // 一般不在,主線程啟動之后,就睡眠了

工作線程?// AMS wms pkms pmS有自己私有的工作線程,還有DisplayThread, FgThread,IoThread,UIThread(是一個子線程)等公共的工作線程

Binder線程?

大部分的服務(wù)都是跑在binder線程里面,只有少部分的服務(wù)有自己的工作線程

為什么系統(tǒng)服務(wù)不都跑在Binder線程里?

為什么系統(tǒng)服務(wù)不都跑在自己私有的工作線程里?

跑在BInder線程和跑在工作線程,如何取舍?

2 怎么解決系統(tǒng)服務(wù)啟動的相互依賴?

2-1 分批啟動,比較基礎(chǔ)的server 先啟動,比如AMS, PMS,PKMS... 很多service都依賴他們

2-2 分階段啟動, 階段1 ,階段2......

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末桂对,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸠匀,更是在濱河造成了極大的恐慌蕉斜,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缀棍,死亡現(xiàn)場離奇詭異宅此,居然都是意外死亡,警方通過查閱死者的電腦和手機爬范,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門父腕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人青瀑,你說我怎么就攤上這事璧亮。” “怎么了斥难?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵枝嘶,是天一觀的道長。 經(jīng)常有香客問我哑诊,道長躬络,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任搭儒,我火速辦了婚禮穷当,結(jié)果婚禮上提茁,老公的妹妹穿的比我還像新娘。我一直安慰自己馁菜,他們只是感情好茴扁,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著汪疮,像睡著了一般峭火。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上智嚷,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天卖丸,我揣著相機與錄音,去河邊找鬼盏道。 笑死稍浆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的猜嘱。 我是一名探鬼主播衅枫,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼朗伶!你這毒婦竟也來了弦撩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤论皆,失蹤者是張志新(化名)和其女友劉穎益楼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體点晴,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡偏形,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了觉鼻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俊扭。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖坠陈,靈堂內(nèi)的尸體忽然破棺而出萨惑,到底是詐尸還是另有隱情,我是刑警寧澤仇矾,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布庸蔼,位于F島的核電站,受9級特大地震影響贮匕,放射性物質(zhì)發(fā)生泄漏姐仅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掏膏。 院中可真熱鬧劳翰,春花似錦、人聲如沸馒疹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颖变。三九已至生均,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腥刹,已是汗流浹背马胧。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留衔峰,地道東北人佩脊。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像朽色,于是被迫代替她去往敵國和親邻吞。 傳聞我的和親對象是個殘疾皇子组题,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355