ActivityManagerService--startActivity的流程

流程图

该流程图为:当Activity目标进程不存在时,启动Activity的流程。若进程相同的话,也只是省略了启动进程的步骤。


startActivity

在Activity启动的时候,所处的Task以及Stack都与进程无关。即,Task与Stack与进程不是绑定在一起的

启动流程

Activity.startActivity(用户进程)

startActivity会调用startActivitiyForResult,只是requestCode传入的是-1,而正常的requestCode为正数。

  • ApplicationThread
    • ActivityThread.ApplicationThread对象
    • ActivityThread对象初始化的时候,初始化唯一的ApplicationThread对象
    • 主要用于AMS告知用户进程Activity、Service生命周期的事件
  • mToken
    • IBinder对象
    • 在Activity创建的时候,AMS创建的Token
    • 主要用来在AMS中通过该Token,找到对应的ActivityRecord
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
            ...
            Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
            ...

ActivityStarter.startActivityMayWait(System_Server进程)

通过Instrumentation.execStartActivity经过IPC调用,调用到AMS的startActivity,进入后该函数后,会调用到ActivityStarter.startActivityMayWait

  • 通过PackageManagerService解析intent找到对应的ActivityInfo对象
  • 找到当前正在显示的ActivityStack
  • 初始化调用者的Pid以及Uid
      ...  
      // 根据intent以及userId查找匹配的Activity类,通过PackageManagerService根据
      // ComponentName,Action,Category来找到最合适的Activity类信息
      ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
      ...
      ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
      ···
      //  获取当前正在显示的ActivityStack
      final ActivityStack stack;
      if (container == null || container.mStack.isOnHomeDisplay()) {
          stack = mSupervisor.mFocusedStack;
      } else {
          stack = container.mStack;
      }
      //  调用startActivityLocked
      int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason)
      ...

ActivityStater.startActivity(System_Server进程)

startActivityLocked会直接调用startActivity

  • 找到调用者进程
  • 根据token找到调用者的ActivityRecord,以及requestRecord
  • 处理startActivityForResult相关的接收者
  • 判断Intent中的Flag,Components,ActivityInfo是否为空,为空则返回错误
  • 检查启动Activity的权限,没有权限则返回
       ... 
       // 根据ApplicationThread找到调用者的进程信息
       ProcessRecord callerApp = null;
        if (caller != null) {
            callerApp = mService.getRecordForAppLocked(caller);
        }
       ...
        // 调用者的ActivityRecord
       ActivityRecord sourceRecord = null;
        // 接收结果的ActivityRecord
       ActivityRecord resultRecord = null;
        if (resultTo != null) {
            // 根据调用者的mToken(即resultTo)查找所有Activity栈中的ActivityRecord
            sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                    "Will send result to " + resultTo + " " + sourceRecord);
            if (sourceRecord != null) {
                    //  如果requestCode>=0,那么就先将启动者赋值为接收者
                    //  也就是resultRecord代表接收结果的ActivityRecord对象
                    //  如果requestCode小于0的话,那么resultRecord就一直为空,代表不需要接收结果
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }
      ... 
       if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            //  如果有该Flag,那么就需要重新调整结果的接收者了
            //  该Flag的作用,就是将结果返回给上一个Activity
            
            //  例如A--->B---C,A通过startActivityForResult启动B,而B通过startActivity并且
            //  携带该参数的话,那么C的结果会返回给A,而不通过B
            if (requestCode >= 0) {
                ActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            // 将原来的接收者赋值给resultRecord
            resultRecord = sourceRecord.resultTo;
            if (resultRecord != null && !resultRecord.isInStackLocked()) {
                resultRecord = null;
            }
            //  同样赋值resultWho,这是个String类型的,同样代表Activity
            resultWho = sourceRecord.resultWho;
            //  将requestCode也重新赋值
            requestCode = sourceRecord.requestCode;
            //  将启动者的resultTo置空,代表不用接收结果
            sourceRecord.resultTo = null;
            //  也就是A接收B的结果,而B通过FLAG_ACTIVITY_FORWARTD_RESULT,将原本B接收结果改成A接收结果
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }
            if (sourceRecord.launchedFromUid == callingUid) {
                callingPackage = sourceRecord.launchedFromPackage;
            }
        }
      // 检查Intent中的Components是否为空,为空直接返回
       if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
           err = ActivityManager.START_INTENT_NOT_RESOLVED;
        }
      // 判断是否有找到匹配的Activity,没有则返回
        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
            err = ActivityManager.START_CLASS_NOT_FOUND;
        }
       // 处理语音相关数据,暂时忽略不看
        if (err == ActivityManager.START_SUCCESS && sourceRecord != null
                && sourceRecord.getTask().voiceSession != null) {
           ...
        }
        if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
            ...
        }
        // 通过AMS开始检查uid启动Activity的权限
        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
                resultRecord, resultStack, options);
        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                callingPid, resolvedType, aInfo.applicationInfo);
        ... 
        //  创建一个新的ActivityRecord
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, container, options, sourceRecord);
      // 调用startActivity
      return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);

ActivityStarter.startActivityUnchecked(System_Server进程)

接着会调用startActivityUnchecked函数:

  • 将要启动的ActivityRecord、Intent、Task赋值保存到成员变量中
  • 根据LaunchMode以及Flag找到符合条件的Task
  • 根据LaunchMode以及Flag,清理目标Task上面的Activity,以及回调onNewIntent
  • 如果没有能复用的Task的话,则需要创建一个新的Task
  • 继续调用ActivityStack.startActivityLocked继续启动
    // 根据函数参数初始化要启动的Activity的mIntent等成员变量
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor);
    // 计算要启动的Task的Flag,主要是添加FLAG_NEW_TASK
    computeLaunchingTaskFlags();
    // 计算调用者的Stack
    computeSourceStack();
    // reusedActivity主要用来找TaskId ,根据launchMode以及Intent.Flag来找到可以重复使用的Task
    ActivityRecord reusedActivity = getReusableIntentActivity();
    ...
    // 如果可以复用Task的话
    if (reusedActivity != null) {
           ...
           // mStartActivity代表要启动的Activity,然后为该Activity的Task赋值
           if (mStartActivity.getTask() == null) {
                mStartActivity.setTask(reusedActivity.getTask());
            }
           // 设置Task的Intent
            if (reusedActivity.getTask().intent == null) {
                reusedActivity.getTask().setIntent(mStartActivity);
            }
            // 处理CLEAR_TOP以及singleTask、SingleInstance的情况
            if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || isDocumentLaunchesIntoExisting(mLaunchFlags)
                    || mLaunchSingleInstance || mLaunchSingleTask) {
                final TaskRecord task = reusedActivity.getTask();
                // 清理复用的Activity上方的其他Activity
                final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
                        mLaunchFlags);
                if (reusedActivity.getTask() == null) {
                    reusedActivity.setTask(task);
                }

                if (top != null) {
                    if (top.frontOfTask) {
                        top.getTask().setIntent(mStartActivity);
                    }
                    // 回调复用的Activity的onNewIntent
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                            mStartActivity.launchedFromPackage);
                }
            }
          // 将目标Activity的Task移动到前台
          reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
          ...
          // 如果是FLAG_NEW_TASK设置,并且没有可重用的Task的话,就会生成一个新的Task,并且切换到前台
          if (!mAddingToTask && mReuseTask == null) {
                // We didn't do anything...  but it was needed (a.k.a., client don't use that
                // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
                resumeTargetStackIfNeeded();
                if (outActivity != null && outActivity.length > 0) {
                    outActivity[0] = reusedActivity;
                }
                return START_TASK_TO_FRONT;
            }
          ...
          boolean newTask = false;
          final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                ? mSourceRecord.getTask() : null;
          // Should this be considered a new task?
          int result = START_SUCCESS;
          if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            // 如果不需要返回结果,并且没有匹配的Task,并且FLAG_ACTIVITY_NEW_TASK匹配了,那么就需要重新创建一个新的task
            newTask = true;
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);
          } else if (mSourceRecord != null) {
            // 否则就使用调用者的Task
            result = setTaskFromSourceRecord();
          } else if (mInTask != null) {
            // 如果调用者也为空,则使用复用的Task
            result = setTaskFromInTask();
          } else {
            // This not being started from an existing activity, and not part of a new task...
            // just put it in the top task, though these days this case should never happen.
            // 如果不是被已经存在的Activity启动的,可能从Service启动的,并且不是属于一个新的Task的话,就需要重新创建一个Task
            setTaskToCurrentTopOrCreateNewTask();
          }
          ...
          // 继续调用startActivityLocked,主要处理窗口的一些事情
          mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                mOptions);
          ...
          //  return startActivity(r, sourceRecord, voiceSession, voiceInteractor,startFlags, true,options, inTask, outActivity); doResume是true
          if (mDoResume) {
            final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                mWindowManager.executeAppTransition();
            } else {
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                // 继续执行resume操作
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }

ActivityStack.resumeTopActivityInnerLocked(System_Server进程)

resumeFocusedStackTopActivityLocked操作最后会调用ActivityStack.resumeTopActivityInnerLocked函数:

  • 判断系统状态是否在休眠,如果是则先返回
  • 从Stopping等列表中移除即将启动的Activity
  • 等待所有需要Pause的Activity执行Pause结束后,再继续
  • Pause当前显示的Activity
  • 等待所有的Activity都Pause完毕后,判断目标进程是否启动
  • 如果进程启动,则调用scheduleResumeActivity开始启动Activity
  • 进程未启动,则调用startSpecificActivityLocked启动进程并且启动Activity
      ...
      //  找到FocusedTask的顶部的ActivityRecord,也就是即将启动的Activity
       final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
      // 如果系统正在休眠或者关机,并且顶部Activity暂停,没有需要resume的Activity的话,直接返回即可
      if (mService.isSleepingOrShuttingDownLocked()
                && mLastPausedActivity == next
                && mStackSupervisor.allPausedActivitiesComplete()) {
        ...
        return false;
      }
      //  从Stopping以及Sleeping的队列中移除即将启动的Activity
      mStackSupervisor.mStoppingActivities.remove(next);
      mStackSupervisor.mGoingToSleepActivities.remove(next);
      next.sleeping = false;
      mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(next);
      //  如果当前有正在Pausing的Activity的话,则先等所有Activity都Pausing完毕后再执行Resume流程
      if (!mStackSupervisor.allPausedActivitiesComplete()) {
            return false;
        }
      ...
      //  开始Pause上一个Activity,通过ApplicationThread发送要暂停的消息,而在用户进程
      //  会根据mToken找到要暂停的Activity,然后通过H发送Pausing的消息
      boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
      if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, next, false);
      }
      if (pausing && !resumeWhilePausing) {
            if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
                    "resumeTopActivityLocked: Skip resume: need to start pausing");
           //  如果正在PausingActivity,并且不支持Resume_While_Pausing的标识位的话,则需要等待Activity Pause完毕才能启动
            if (next.app != null && next.app.thread != null) {
                mService.updateLruProcessLocked(next.app, true, null);
            }
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        } else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                mStackSupervisor.allResumedActivitiesComplete()) {
             // 如果不用等待Pause结束的话,则判断要启动的Activity与当前处于Resume的Activity是否是同一个,如果是的话,则直接返回
            executeAppTransition(options);
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Top activity resumed (dontWaitForPause) " + next);
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        }     
        // 处理Windowmanager的动画
        ...
        //  判断目标进程是否已经启动
        ActivityStack lastStack = mStackSupervisor.getLastStack();
        if (next.app != null && next.app.thread != null) {
             //  目标进程已经启动
            try{
            //  如果即将启动的Activity中有需要返回的结果的话
            ArrayList<ResultInfo> a = next.results;
                if (a != null) {
                    final int N = a.size();
                    if (!next.finishing && N > 0) {
                         //  则通过该函数将结果分发给对应的进程Activity的onActivityResult
                        next.app.thread.scheduleSendResult(next.appToken, a);
                    }
                }
                //   同理,处理newIntent
                if (next.newIntents != null) {
                    next.app.thread.scheduleNewIntent(
                            next.newIntents, next.appToken, false /* andPause */);
                }
            ...
            //  设置mResumedActivity为即将启动的Activity
            setResumedActivityLocked(next, "resumeTopActivityInnerLocked");
            mService.updateLruProcessLocked(next.app, true, null);
            updateLRUListLocked(next);
            //  更新所有进程的OomAdj
            mService.updateOomAdjLocked();        
            ...  
            //  调用该函数向目标进程发送ResumeActivity的请求
            next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                        mService.isNextTransitionForward(), resumeAnimOptions);

            }catch(Exception e){
                 // 如果发生任何异常,调用该函数重启Activity
                 mStackSupervisor.startSpecificActivityLocked(next, true, false);
            }
        } else {
            //  目标进程未启动
            ...
            //  调用该函数启动Activity
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

ActivityStackSupervisor. startSpecificActivityLocked(System_Server进程)

  • 如果目标进程已经启动,则调用realStartActivityLocked启动Activity
  • 如果目标进程未启动,则调用startProcessLocked启动进程
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
//  判断进程是否已经启动,如果已经启动,则调用realStartActivityLocked
if (app != null && app.thread != null) {
      ...
      realStartActivityLocked(r, app, andResume, checkConfig);
      ...
}
// 如果进程没有启动,则调用startProcessLocked,向Zygote进程通过Socket发送fork命令,创建进程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);

ActivityStackSupervisor.realStartActivityLocked(System_Server进程)

  • 判断所有的Activity都处于Pause状态
  • 回调用户进程,调用scheduleLaunchActivity
// 只有所有Activity Pause完毕才能开始启动
 if (!allPausedActivitiesComplete()) {
            return false;
 }
...
//  通过IApplicationThread回调到用户进程,调用scheduleLaunchActivity
 app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);
...

ApplicationThread.scheduleLaunchActivity(用户进程)

  • 创建客户端的ActivityClientRecord对象,保存mToken
  • 发送H.LAUNCH_ACTIVITY的消息
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
....
sendMessage(H.LAUNCH_ACTIVITY, r);

ApplicationThread.handleLaunchActivity(用户进程)

H类接收到该消息后,会调用handleLaunchActivity,至此,Activity的启动结束。

  • 初始化WindowManager
  • 调用performLaunchActivity,创建Activity对象,并且回调onCreate、onStart等函数
  • 调用handleResumeActivity,回调onResume函数
...
Activity a = performLaunchActivity(r, customIntent);
...
if(a!=null){
    ...
    // 
    handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
    ...
}

ActivityThread.Idler

当目标Activity进程主线程队列为空时,会发送activityIdle的消息给ActivityManagerService,来处理接下来的onStop流程。

private class Idler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            ActivityClientRecord a = mNewActivities;
            ...
            if (a != null) {
                mNewActivities = null;
                IActivityManager am = ActivityManager.getService();
                ActivityClientRecord prev;
                do {
                    if (a.activity != null && !a.activity.mFinished) {
                        try {
                            am.activityIdle(a.token, a.createdConfig, stopProfiling);
                            a.createdConfig = null;
                        } catch (RemoteException ex) {
                            throw ex.rethrowFromSystemServer();
                        }
                    }
                 ...
                } while (a != null);
            }
           ...
            return false;
        }
    }

ActivityStackSupervisor.activityIdleInternalLocked

主要是调用ActivityStackSupervisor.activityIdleInternalLocked函数,在该函数中,会处理待onStop或者finish的函数

 // Atomically retrieve all of the other things to do.
        final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
                true /* remove */, processPausingActivities);
        NS = stops != null ? stops.size() : 0;
        if ((NF = mFinishingActivities.size()) > 0) {
            finishes = new ArrayList<>(mFinishingActivities);
            mFinishingActivities.clear();
        }

        if (mStartingUsers.size() > 0) {
            startingUsers = new ArrayList<>(mStartingUsers);
            mStartingUsers.clear();
        }

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