Android应用启动流程

本文基于Android10
参考:Activity启动流程

Launcher进程请求ATMS(AMS)

image

Launcher

请求的入口为Launcher的startActivitySafe方法

调用父类的startActivity方法

// Launcher是一个Activity
public class Launcher extends BaseDraggingActivity implements LauncherExterns,
        LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate{

        public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        ...
        // 在新的任务栈中启动
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        try {
            ...
            if (isShortcut) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // 调用startActivity
                startActivity(intent, optsBundle);
            } else {
                LauncherAppsCompat.getInstance(this).startActivityForProfile(
                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
            }
            ...
            return true;
        } catch (ActivityNotFoundException|SecurityException e) {
            ...
        }
        return false;
      }
}

Activity

通过Instrumentation启动Activity

public class Activity extends ...{

        // startActivity最终都会走到这里
        public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {

        // mParent表示当前Activity的父类,当根活动还没创建则mParent==null    
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);

            // 通过Instrumentation启动Activity
            // 比较重要的几个参数:ApplicationThread(Binder)、Token
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
           ... 
        } 
        ...
    }

}

Instrumentation

Instrumentation具有跟踪application及activity生命周期的功能,用于android 应用测试框架中代码检测

每个Activity都持有Instrumentation对象的一个引用,但是整个进程只会存在一个Instrumentation对象

public class Instrumentation {

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
      ...
      try {
          ...
          // 获取ActivityTaskManagerService(ATMS),是个跨进程Binder服务
          // ATMS 是Android10新增的,在此之前,这里获取的是AMS
          // whoThread为ApplicationThread
            int result = ActivityTaskManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

          // 检查Activity启动的结果,如果异常则抛出错误,如Activity没有注册的错误等
          checkStartActivityResult(result, intent);
      } catch (RemoteException e) {
          throw new RuntimeException("Failure from system", e);
      }
      return null;
  }

}

ActivityTaskManager(ATMS、AMS)

Android10新增,Android10之前,调用的是AMS。

Android10的AMS内部,也是调用ATMS。

  1. ATMS(AMS)做为服务端的服务,存在于SystemServer进程中。

其实现了IActivityTaskManager.Stub(IActivityManager.Stub),是个系统服务。

  1. Launcher做为客户端进程,通过IActivityTaskManager.Stub.asInterface拿到了服务端ATMS的代理对象,可以跨进程调用ATMS(AMS)的方法来实现具体功能
// ActivityTaskManager
public static IActivityTaskManager getService() {
    return IActivityTaskManagerSingleton.get();
}

private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
                @Override
                protected IActivityTaskManager create() {
                        // 获取ATMS,是个Binder服务
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
                }
            };

ATMS(AMS)发送创建应用进程请求

ActivityTaskManagerService.startActivity 整个流程图如下:

图是android10之前的,跟本文会有所差异

image

这几个类跳来跳去,有点懵逼,就不贴代码了,可以自己去点看看,不同Android版本会有差异。

调用路径:

-> ActivityTaskManager#startActivity

-> ActivityTaskManager#startActivityAsUser

-> ActivityStarter#execute

-> ActivityStarter#startActivity

-> ActivityStarter#startActivityUnchecked

-> RootActivityContainer#resumeFocusedStacksTopActivities

-> ActivityStack#resumeTopActivityUncheckedLocked

-> ActivityStack#resumeTopActivityInnerLocked

-> ActivityStackSupervisor#startSpecificActivityLocked

这里面主要做了几件事情:

  1. 启动模式处理

  2. 创建ActivityRecord

  3. .....,

  4. 冷启动取activity的主题背景,展示StartingWindow(冷启动白屏的原因,在发起fork进程前就显示主题)

  5. 通过IApplicationThread是否为null来判断应用进程是否已经存在,有则表示进程已经存在

IApplicationThread是应用进程在系统进程的代理

  1. 如果进程不存在,通过AMS发起创建进程的请求
  2. AMS通过Process向Zygote进程发送创建应用进程请求
// ActivityStack#resumeTopActivityInnerLocked
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
     ...
     // pause一个Activity
     startPausingLocked(userLeaving, false, next, false);
     ...
     // 如果activity已经启动
     if (next.attachedToProcess()) {
        ...
        //启动了的Activity就发送ResumeActivityItem事务给客户端了,后面会讲到
        transaction.setLifecycleStateRequest(
                  ResumeActivityItem.obtain(next.app.getReportedProcState(),
                                getDisplay().mDisplayContent.isNextTransitionForward()));
        mService.getLifecycleManager().scheduleTransaction(transaction);
        ....
     } else {
        ....
        if (SHOW_APP_STARTING_PREVIEW) {
           // 冷启动时出现白屏的原因:取根activity的主题背景,展示StartingWindow
           next.showStartingWindow(null, false ,false);
        }
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
     }
     return true;
}

判断进程是否已存在

// ActivityStackSupervisor#startSpecificActivityLocked
void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {

     // 通过进程名及uid获取即将启动的进程
     final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);
     // 如果应用进程已经存在,内部通过IApplicationThread是否为null来判断
     if (wpc != null && wpc.hasThread()) {
            // Activity热启动
        realStartActivityLocked(r, wpc, andResume, checkConfig);
        return;
     }
     ...
         // 否则,创建进程
     // ActivityManagerInternal::startProcess 调用ActivityManagerService(AMS)
     final Message msg = PooledLambda.obtainMessage(
                    ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
                    r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
     mService.mH.sendMessage(msg);
}

Process向Zygote发送创建进程的请求

private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
     ...
     startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, app.info.packageName,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
     }
     checkSlow(startTime, "startProcess: returned from zygote!");
     return startResult;
}
// Process#start
public static ProcessStartResult start(@NonNull final String processClass,
                                           @Nullable final String niceName,
                                           int uid, int gid, @Nullable int[] gids,
                                           int runtimeFlags,
                                           int mountExternal,
                                           int targetSdkVersion,
                                           @Nullable String seInfo,
                                           @NonNull String abi,
                                           @Nullable String instructionSet,
                                           @Nullable String appDataDir,
                                           @Nullable String invokeWith,
                                           @Nullable String packageName,
                                           @Nullable String[] zygoteArgs) {
        // 与Zygote进程建立了Socket连接,并发送创建进程请求                             
        return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, packageName,
                    /*useUsapPool=*/ true, zygoteArgs);
    }

Zygote进程接受请求并fork应用进程

image

Zygote:在Android系统中,DVM(Dalvik虚拟机)、应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程来创建的,我们也将它称为孵化器。它通过fork(复制进程)的形式来创建应用程序进程和SystemServer进程,由于Zygote进程在启动时会创建DVM,因此通过fork而创建的应用程序进程和SystemServer进程可以在内部获取一个DVM的实例拷贝。

  1. 启动SystemServer进程,其main方法创建了应用所需的各种服务,如AMS,WMS等

  2. 调用ZygoteServer.runSelectLoop死循环,用于等待AMS请求

  3. 当收到AMS请求,会fork一个应用进程

等待AMS请求

// ZygoteInit#main
public static void main(String argv[]) {
     // 创建Socket
   ZygoteServer zygoteServer = new ZygoteServer();
   ....
     // 启动SystemServer, 可见SystemServer是由Zygote创建的第一个进程
   forkSystemServer(abiList, zygoteSocketName, zygoteServer)
   ...
   // 等待客户端(AMS)请求
   zygoteServer.runSelectLoop(abiList);
   ...
}
Runnable runSelectLoop(String abiList) {
   ...
   while (true) {
                ...
                // 不断处理客户端的AMS的请求,然后交给processOneCommand
        ZygoteConnection connection = peers.get(pollIndex);
        final Runnable command = connection.processOneCommand(this);
        ...
   }
}

Zygote fork 子进程(应用进程)

// ZygoteConnect#processOneCommand
Runnable processOneCommand(ZygoteServer zygoteServer) {
        ....
        // fork当前进程创建一个子进程
    int pid = Zygote.forkAndSpecialize(一堆启动参数);

        // pid为0则表示当前进程已经是子进程了,即应用进程
    if (pid == 0) {
         ...
         // 
         return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.mStartChildZygote);
     }
         ... 
}

启动ActivityThread

image
  1. 当zygote fork一个进程后返回一个pid

当pid=0的时,则代表了当前进程已经是子进程了,即应用进程。所下一步将执行handleChildProc方法

  1. 通过反射调用ActivityThread 的main方法完成初始化
// ZygoteConnect#handleChildProc
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
    .....
    ZygoteInit.zygoteInit(参数);
    ...
}
// ZygoteInit#zygoteInit
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        // 为当前的VM设置未捕获异常器
    RuntimeInit.commonInit();
        // Binder驱动初始化,该方法完成后,可通过Binder进行进程通信
    ZygoteInit.nativeZygoteInit();
        // 主要调用SystemServer的main方法
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
 // RuntimeInit#applicationInit
 protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
    ...
    final Arguments args = new Arguments(argv);
    // 这里的startClass为ActivityThread, 找到它的main方法并反射调用
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}
// RuntimeInit#findStaticMain
protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
    // className为ActivityThread
    // 反射获取到ActivityThread类并调用main方法
    Class<?> cl = Class.forName(className, true, classLoader);
    Method m = cl.getMethod("main", new Class[] { String[].class });
    return new MethodAndArgsCaller(m, argv);
}

应用进程绑定到AMS

image
  1. 创建主线程Looper并开启循环

  2. 将ApplicationThread绑定到AMS,使AMS持有当前进程的ApplicationThread代理

  3. 创建Applicaiton,并调用onCreate

public final class ActivityThread extends ClientTransactionHandler {

    // ActivityThread的内部类,实现IApplicationThread.Stub,负责与AMS通讯
    final ApplicationThread mAppThread = new ApplicationThread();

        // ActivityThread#main
        public static void main(String[] args) {
            ....
                // 创建主线程的Looper
         Looper.prepareMainLooper();
         ...
         // 创建ActivityThread
         ActivityThread thread = new ActivityThread();
         thread.attach(false, startSeq);
             // 开启主线程的消息循环
         Looper.loop();
         ...
        }

        private void attach(boolean system, long startSeq) {
         ...
       // 获取 AMS 服务
         final IActivityManager mgr = ActivityManager.getService();
       // ApplicationThread 绑定到AMS,这是一个IPC过程
       mgr.attachApplication(mAppThread, startSeq);
    }

        // 应用创建Application
        private void handleBindApplication(AppBindData data) {
        ....
        // 创建Application
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        // 调用Application的onCreate的方法
        // 此时的Activity还没启动
        mInstrumentation.callApplicationOnCreate(app);
            ...
        }

    class H extends Handler {
        public static final int BIND_APPLICATION        = 110;
        ...
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BIND_APPLICATION:
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    break;
            ...
        }
    }

    private class ApplicationThread extends IApplicationThread.Stub {

             public final void bindApplication(一堆参数) {

               ...
               AppBindData data = new AppBindData();
               ...
               // AMS绑定ApplicationThread时,发送消息到ActivityThread创建Application
               sendMessage(H.BIND_APPLICATION, data);
         }
     }

}
// ActivityManagerService
private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {

      ProcessRecord app;
            ....
      // AMS 调用ApplicationThread, 创建Applicaition,回调onCreate
      thread.bindApplication(一堆参数);
      ...
      // 将 applicationThread 设置到 ProcessRecord
      // 所以启动activity时,能够拿到当前进程的 applicationThrea, 由此判断进程是否已经存在
      app.makeActive(thread, mProcessStats);
            ...
      // 启动Activity
      // mAtmInternal实现类为ATMS的内部类 LocalService
      mAtmInternal.attachApplication(app.getWindowProcessController());
      .....
}

AMS发送启动Activity的请求

image

流程:

-> ActivityTaskManagerService.LocalService#attachApplication

-> RootActivityContiner#attachApplication

-> ActivityStackSupervisor#realStartActivityLocked

热启动,ActivityStackSupervisor#startSpecificActivityLocked判断如果是热启动,走这里的流程)

-> ClientLifecycleManager#scheduleTransaction

-> ClientTransaction#schedule

-> IApplicationThread#scheduleTransaction

-> ActivityThread#scheduleTransaction(这里调用的是父类ClientTransactionHandler的方法)

-> Handle发送ActivityThread.H.EXECUTE_TRANSACTION 消息

-> TransactionExecutor#execute (Handle收到消息后)

-> TransactionExecutor#executeCallbacks

-> LaunchActivityItem#execute

-> ActivityThread#handleLaunchActivity

-> 创建Activity、Window、DecorView

-> ActivityThread#handleStartActivity

-> ResumeActivityItem#execute

-> ActivityThread#handleResumeActivity

  1. 由上可知,在AMS绑定ApplicationThread之后,调用mAtmInternal(实现类LocalService)绑定Application

  2. 经过一些列类与方法的调用最终通过AMS调用应用进程的ApplicationThread代理创建事务

  3. ApplicationThread通过ActivityThread的Handler发送消息到主线程创建Activity

  4. ActivityThread执行handleLaunchActivity,进行Activity、Window的创建流程

Window的创建流程

  1. ActivityThread执行handleStartActivity
  2. ActivityThread执行handleResumeActivity,通过WMS进行window的添加
// ActivityStackSupervisor#realStartActivityLocked
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
       .....
       final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                        r.appToken);
             // 添加callback
       // 创建LaunchActivityItem
       clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),...));

       // ResumeActivityItem
       final ActivityLifecycleItem lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());

       // 设置当前的生命周期
       clientTransaction.setLifecycleStateRequest(lifecycleItem);

       mService.getLifecycleManager().scheduleTransaction(clientTransaction);
             ....
       return true;
}
// TransactionExecutor#execute
public void execute(ClientTransaction transaction) {
         ...
     // 其实就是执行LaunchActivityItem,回调onCreate
     executeCallbacks(transaction);
     // 其实就是执行ResumeActivityItem,回调onStart、onCreate
     executeLifecycleState(transaction);
}
// TransactionExecutor#executeCallbacks
// 执行LaunchActivityItem
public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    ......
    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        // 这里的item为LaunchActivityItem
        final ClientTransactionItem item = callbacks.get(i);
        ......
        item.execute(mTransactionHandler, token, mPendingActions);
        item.postExecute(mTransactionHandler, token, mPendingActions);
        ......
   }
}
// LaunchActivityItem#execute
@Override
public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
    // 创建ActivityClientRecord
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client);
        // 这里的client为ActivityThread
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
// ActivityThread#handleLaunchActivity
public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
     // 反射创建Activity,执行Activity.attach创建window,然后回掉onCreate
     final Activity a = performLaunchActivity(r, customIntent);
     return a;
}
// TransactionExecutor#executeLifecycleState
// 执行ResumeActivityItem
private void executeLifecycleState(ClientTransaction transaction) {
      final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
      ....
      // 执行当前生命周期状态之前的状态,当前为onResume,所以这里执行的是onStart,调用ActivityThread#handleStartActivity
      cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);

      // 切换状态到onResume,调用ActivityThread#handleResumeActivity
      lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
      lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
 }

总结

  1. Zygote进程启动时,首先fork一个SystemServer进程,SystemServer进程创建了如AMS、WMS等系统服务

  2. Zygote进程,开启一个循环,用于等待AMS的请求

  3. Launcher做为一个Activity,发起创建Activity的请求,添加Flag为Intent.FLAG_ACTIVITY_NEW_TASK

  4. Instrementation获取到ATMS(android10之前为AMS),发送启动Activity的请求

  5. 如果是冷启动,ATMS(AMS)向Zygote发起创建进程的请求

并取activity的主题背景,用于展示StartingWindow(白屏原因

  1. Zygote收到请求后,fork一个进程,通过反射调用ActivityThread的main方法进行初始化

  2. ActivityThread创建一个当前进程的ApplicationThread的,并将其绑定到AMS

  3. AMS收到ApplicationThread的代理后,调用ApplicationThread进行Applicaition的初始化

  4. Application通过Handle发送消息到主线程,ActivityThread收到消息后,创建Application,并执行attach、onCreate等方法

  5. AMS调用ApplicationThread开启创建Activity的事务

  6. Application通过Handle发送消息到主线程,ActivityThread收到消息后,进行Activity的启动

  7. ActivityThread执行handleLaunchActivity,进行Activity、Window的创建流程

Window的创建流程

  1. ActivityThread执行handleStartActivity
  2. ActivityThread执行handleResumeActivity,通过WMS进行window的添加

PS:

  • 如果是热启动,AMS持有了当前进程的ApplicationThread代理,所以步骤4之后会直接走步骤10的流程
  • 由于冷启动,会先在主线程创建Application并执行生命周期方法,所以如果在Application执行耗时方法,会导致Activity的启动被阻塞,所以Application如果有耗时操作需要放在异步线程中执行。

到此,就完成了Activity的启动

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,961评论 5 473
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,444评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,009评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,082评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,101评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,271评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,738评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,395评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,539评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,434评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,481评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,160评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,749评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,816评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,038评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,548评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,140评论 2 341

推荐阅读更多精彩内容