Activity的启动流程

一、用户启动Activity,发送消息给ATMS的过程(Launcher > ATMS阶段)

开发中我们会调用startActivity来启动一个Activity,最终会调到startActivityForResult

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
       @Nullable Bundle options) {
  //通过Instrumentation启动Activity
  Instrumentation.ActivityResult ar =
    mInstrumentation.execStartActivity(
        this, mMainThread.getApplicationThread(), mToken, this,
        intent, requestCode, options);
}

Instrumentation是Android系统里面的一套控制方法或者“钩子”。这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行。

Application和Activity的所有生命周期中,都会先调用Instrumentation提供的相应方法(如callActivityOnCreate,callApplicationOnCreate,newActivity,callActivityOnNewIntent)

Instrumentation.execStartActivity

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, String target,
        Intent intent, int requestCode, Bundle options) {
  //通过ATMS启动Activity(API 29是ATMS)
  int result = ActivityTaskManager.getService()
    .startActivity(whoThread, who.getBasePackageName(), intent,
                   intent.resolveTypeIfNeeded(who.getContentResolver()),
                   token, target, requestCode, 0, null, options);
  
}
public static IActivityTaskManager getService() {
    return IActivityTaskManagerSingleton.get();
}

@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
        new Singleton<IActivityTaskManager>() {
            @Override
            protected IActivityTaskManager create() {
                //找到Binder服务
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                return IActivityTaskManager.Stub.asInterface(b);
            }
        };

ActivityTaskManager.getService()返回了一个IActivityTaskManager,拿到的是ATMS的代理对象,跨进程调用了ATMS的startActivity方法。

二、ATMS接收到启动请求并处理的过程(ATMS > ApplicationThread阶段)
//ActivityTaskManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
    Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
    int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
  return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
           resultWho, requestCode, startFlags, profilerInfo, bOptions,
           UserHandle.getCallingUserId());
}

int startActivityAsUser(IApplicationThread caller, String callingPackage,
   Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
   int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
   boolean validateIncomingUser) {
        enforceNotIsolatedCaller("startActivityAsUser");
        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                    //调用了ActivityStarter的execute
                .execute();
    }
int execute() {
  return startActivityMayWait(/**省略参数**/);
}

ActivityStarter.startActivityMayWait

//ActivityStarter.java
private int startActivityMayWait(/**省略参数**/){
  //收集目标Intent信息(更加Intent的action,可用于双开,选择打开)
  ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
  
  int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
          voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
          callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
          ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
          allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
          allowBackgroundActivityStart);
}

private int startActivity(/**省略参数**/){
  mLastStartActivityResult = startActivity(/**省略参数**/)
}

private int startActivity(/**省略参数**/){
  //处理startActivityForResult,对result进行转发
  final int launchFlags = intent.getFlags();
  if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
    // Transfer the result target from the source activity to the new
    // one being started, including any failures.
    if (requestCode >= 0) {
      SafeActivityOptions.abort(options);
      return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
    }
    resultRecord = sourceRecord.resultTo;
    if (resultRecord != null && !resultRecord.isInStackLocked()) {
      resultRecord = null;
    }
    resultWho = sourceRecord.resultWho;
    requestCode = sourceRecord.requestCode;
    sourceRecord.resultTo = null;
    if (resultRecord != null) {
      resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
    }
    if (sourceRecord.launchedFromUid == callingUid) {
      // The new activity is being launched from the same uid as the previous
      // activity in the flow, and asking to forward its result back to the
      // previous.  In this case the activity is serving as a trampoline between
      // the two, so we also want to update its launchedFromPackage to be the
      // same as the previous activity.  Note that this is safe, since we know
      // these two packages come from the same uid; the caller could just as
      // well have supplied that same package name itself.  This specifially
      // deals with the case of an intent picker/chooser being launched in the app
      // flow to redirect to an activity picked by the user, where we want the final
      // activity to consider it to have been launched by the previous app activity.
      callingPackage = sourceRecord.launchedFromPackage;
    }
  }
  
  //接下来做一些校验判断
  
  //从Intent中找不到相应Component
  if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
    // We couldn't find a class that can handle the given Intent.
    // That's the end of that!
    err = ActivityManager.START_INTENT_NOT_RESOLVED;
  }
  //从Intent中找不到相应AppInfo
  if (err == ActivityManager.START_SUCCESS && aInfo == null) {
    // We couldn't find the specific class specified in the Intent.
    // Also the end of the line.
    err = ActivityManager.START_CLASS_NOT_FOUND;
  }
  //...
  //校验当前应用是否开启权限
  boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity,
                inTask != null, callerApp, resultRecord, resultStack);
  
  //创建目标ActivityRecord对象,存数组索引为0的位置
  ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
           callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
           resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
           mSupervisor, checkedOptions, sourceRecord);
  if (outActivity != null) {
    outActivity[0] = r;
  }
  //继续调用startActivity
  final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
        true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);
  return res;
}

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity, boolean restrictedBgActivity) {
  //startActivityUnchecked
  result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
          startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
}

ActivityStarter中做了一系列的调用(收集Intent信息,处理startActivityForResult,做一些校验判断等),最终进入startActivityUnchecked。

startActivityUnchecked

// Note: This method should only be called from {@link startActivity}.
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity, boolean restrictedBgActivity) {
  //根据Intent识别启动模式
  setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
            voiceInteractor, restrictedBgActivity);
    //判断启动模式,并在mLaunchFlags追加对应的标记
  computeLaunchingTaskFlags();
  //获取Activity的启动栈
  computeSourceStack();
  //根据上面的计算,设置Intent的flags
  mIntent.setFlags(mLaunchFlags);
  
  //处理完启动栈后,准备执行发起者的Resume状态了
  if (mDoResume) {
    //resume我们的Activity
     mRootActivityContainer.resumeFocusedStacksTopActivities(
            mTargetStack, mStartActivity, mOptions);
  }
}

startActivityUnchecked中处理了关于Activity启动模式的处理,接着真正的resume我们的Activity

//RootActivityContainer.java
boolean resumeFocusedStacksTopActivities(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
  //调用ActivityStack(Activity栈)的resumeTopActivityUncheckedLocked方法
  result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
//ActivityStack.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
  result = resumeTopActivityInnerLocked(prev, options);
}

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
  //将发起者置为onPause状态
  boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
  //继续当前Activity
  mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
//ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
  // Is this activity's application already running?
  final WindowProcessController wpc =
           mService.getProcessController(r.processName, r.info.applicationInfo.uid);
  
  boolean knownToBeDead = false;
  if (wpc != null && wpc.hasThread()) {
    try {
      //如果这个app已经启动,执行realStartActivityLocked并return(热启动)
      realStartActivityLocked(r, wpc, andResume, checkConfig);
      return;
    } catch (RemoteException e) {
      Slog.w(TAG, "Exception when starting activity "
             + r.intent.getComponent().flattenToShortString(), e);
    }

    // If a dead object exception was thrown -- fall through to
    // restart the application.
    knownToBeDead = true;
  }
  
  // Post message to start process to avoid possible deadlock of calling into AMS with the
  // ATMS lock held.
  //创建应用进程
  final Message msg = PooledLambda.obtainMessage(
    ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
    r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
  mService.mH.sendMessage(msg);
}

这里会先判断应用进程是否创建,创建了就进入realStartActivityLocked,没创建就会调用ActivityManagerInternal.startProcess

①热启动realStartActivityLocked

//ActivityStackSupervisor.java
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
        boolean andResume, boolean checkConfig) throws RemoteException {
  // Create activity launch transaction.
  final ClientTransaction clientTransaction = ClientTransaction.obtain(
                    proc.getThread(), r.appToken);
  
  //addCallback,传入参数LaunchActivityItem
  clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
           System.identityHashCode(r), r.info,
           // TODO: Have this take the merged configuration instead of separate global
           // and override configs.
           mergedConfiguration.getGlobalConfiguration(),
           mergedConfiguration.getOverrideConfiguration(), r.compat,
           r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
           r.icicle, r.persistentState, results, newIntents,
           dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
           r.assistToken));
  // Schedule transaction.
  //获取ClientLifecycleManager对象进行调度
  mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}
//ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
  final IApplicationThread client = transaction.getClient();
  //调用ClientTransaction的schedule
  transaction.schedule();
  if (!(client instanceof Binder)) {
    // If client is not an instance of Binder - it's a remote call and at this point it is
    // safe to recycle the object. All objects used for local calls will be recycled after
    // the transaction is executed on client in ActivityThread.
    transaction.recycle();
  }
}
//ClientTransaction.java

/** Target client. */
private IApplicationThread mClient;

public void schedule() throws RemoteException {
  //mClient为IApplicationThread,调度到主进程处理
  mClient.scheduleTransaction(this);
}
三、ApplicationThread接收到调度请求并处理的过程(Application > Activity阶段)
private class ApplicationThread extends IApplicationThread.Stub {
  
  @Override
  public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
  }
}
public abstract class ClientTransactionHandler {

    // Schedule phase related logic and handlers.

    /** Prepare and schedule transaction for execution. */
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        //发送消息给H(H是ActivityThread的一个内部类)
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
}

接着看ActivityThread中接收并处理消息的handleMessage

public void handleMessage(Message msg) {
  switch (msg.what) {
    case EXECUTE_TRANSACTION:
      final ClientTransaction transaction = (ClientTransaction) msg.obj;
      //取出消息,执行execute方法
      mTransactionExecutor.execute(transaction);
      if (isSystem()) {
        // Client transactions inside system process are recycled on the client side
        // instead of ClientLifecycleManager to avoid being cleared before this
        // message is handled.
        transaction.recycle();
      }
      // TODO(lifecycler): Recycle locally scheduled transactions.
      break;
  }
}
//TransactionExecutor.java
public void execute(ClientTransaction transaction) {
  executeCallbacks(transaction);
    executeLifecycleState(transaction);
}

public void executeCallbacks(ClientTransaction transaction) {
  final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
  
  final int size = callbacks.size();
  for (int i = 0; i < size; ++i) {
    //取出上面realStartActivityLocked中设置的LaunchActivityItem类型的CallBack
    final ClientTransactionItem item = callbacks.get(i);
    //调用LaunchActivityItem的execute
    item.execute(mTransactionHandler, token, mPendingActions);
    item.postExecute(mTransactionHandler, token, mPendingActions);
  }
}

前面realStartActivityLocked方法中通过addCallback,传入参数LaunchActivityItem。executeCallbacks方法中取出callbacks集合中的LaunchActivityItem,并调用其execute方法

//LaunchActivityItem.java
@Override
public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
  Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
  ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
        mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
      mPendingResults, mPendingNewIntents, mIsForward,
      mProfilerInfo, client, mAssistToken);
  //ClientTransactionHandler的子类ActivityThread执行handleLaunchActivity方法
  client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
  Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

handleLaunchActivity

//ActivityThread.java
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
  
    final Activity a = performLaunchActivity(r, customIntent);
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  //通过Instrumentation创建Activity
  activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
  //拿到Application
  Application app = r.packageInfo.makeApplication(false, mInstrumentation);
  //调用Activity的attach
  activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback,
                        r.assistToken);
  //通过Instrumentation调用Activity的onCreate方法
  mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    //设置状态
  r.setState(ON_CREATE);
}

②冷启动创建应用进程ActivityManagerInternal.startProcess

ActivityManagerInternal的实现类是AMS中的LocalService,AMS通过Socket与Zygote通信,fork出App进程,app进程创建后,会执行ActivityThread的main方法(Android进程入口方法)

//ActivityThread.java
public static void main(String[] args) {
  //创建Looper
  Looper.prepareMainLooper();
  //创建ActivityThread
  ActivityThread thread = new ActivityThread();
  //[1]attach
  thread.attach(false, startSeq);
  //loop循环
  Looper.loop();
}

调用ActivityThread的attach

private void attach(boolean system, long startSeq) {
  //system传的false
  
  final IActivityManager mgr = ActivityManager.getService();
  //[2]调用AMS的attachApplication
  mgr.attachApplication(mAppThread, startSeq);
}
//ActivityManagerService.java
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        //[3]attachApplicationLocked
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
  
  //[4]bindApplication
  thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
         null, null, null, testMode,
         mBinderTransactionTrackingEnabled, enableTrackAllocation,
         isRestrictedBackupMode || !normalMode, app.isPersistent(),
         new Configuration(app.getWindowProcessController().getConfiguration()),
         app.compat, getCommonServicesLocked(app.isolated),
         mCoreSettingsObserver.getCoreSettingsLocked(),
         buildSerial, autofillOptions, contentCaptureOptions);
  
  app.makeActive(thread, mProcessStats);
  //[5]调用ATMS的attachApplication
  didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
}

[4]thread.bindApplication 这是一个binder通信的过程

public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial, boolean autofillCompatibilityEnabled) {
  
  //创建一个AppBindData
  AppBindData data = new AppBindData();
  data.processName = processName;
  data.appInfo = appInfo;
  data.providers = providers;
  //...data赋值操作...
  //最后发送Handler消息
  sendMessage(H.BIND_APPLICATION, data);
}

ActivityThread内部的Handler接收到BIND_APPLICATION消息

case BIND_APPLICATION:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
    AppBindData data = (AppBindData)msg.obj;
    handleBindApplication(data);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
private void handleBindApplication(AppBindData data) {
  //获取LoadedApk对象
  data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
  //创建ContextImpl上下文
  final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
  //创建Instrumentation
  try {
    final ClassLoader cl = instrContext.getClassLoader();
    mInstrumentation = (Instrumentation)
      cl.loadClass(data.instrumentationName.getClassName()).newInstance();
  } catch (Exception e) {
    throw new RuntimeException(
      "Unable to instantiate instrumentation "
      + data.instrumentationName + ": " + e.toString(), e);
  }
  //通过反射创建目标Application对象
  app = data.info.makeApplication(data.restrictedBackupMode, null);
  //调用Application的onCreate方法
  mInstrumentation.callApplicationOnCreate(app);
}

回到上面attachApplicationLocked的mAtmInternal.attachApplication,调用ATMS的attachApplication

//ActivityTaskManagerService.java
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
  synchronized (mGlobalLockWithoutBoost) {
    return mRootActivityContainer.attachApplication(wpc);
  }
}
//RootActivityContainer.java
boolean attachApplication(WindowProcessController app) throws RemoteException {
  //看到了似曾相识的realStartActivityLocked。
  mStackSupervisor.realStartActivityLocked(activity, app,
                  top == activity /* andResume */, true /* checkConfig */)
}

看到了似曾相识的realStartActivityLocked,后面流程和之前一样。Activity启动流程分析完毕。

总结

1)与Activity管理有关的类:

ActivityRecord:历史栈中的一个条目,代表一个Activity

TaskRecord:内部维护了一个ArrayList<ActivityRecord> ,来保存ActivityRecord

ActivityStack:内部维护了一个ArrayList<TaskRecord>,用来管理TaskRecord

ActivityStackSupervisor:用来管理ActivityStack的

2)Activity启动流程

  1. Launcher > ATMS阶段


    Launcher>ATMS阶段.png
  2. ATMS > ApplicationThread阶段


    ATMS > ApplicationThread阶段.png
  3. ApplicationThread > Activity阶段


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

推荐阅读更多精彩内容