[转]【源码向】Activity启动流程源码分析【一】【基于Android Q】

1.Activity的管理

在开始分析activity的启动流程之前,我们先做一些预备工作,这些预备知识能够让你更好的理解Actvitiy的一些设计思想。首先我们看下Android是如何管理activity的。在Android中采用栈作为管理activity的数据结构,我们用一个例子来说明这种管理方式。


上图中显示了用户在手机中的3个任务,A:短信,B:拍照,C:邮件,每一个任务在android中我们用一个task来表示。每一个task中包含许多不同的界面显示给用户,其中每一个界面,我们都可以看做是一个activity。我们从上图中可以看到,邮件task复用了短信和拍照中的activity A1和B2。这其实很容易理解,这种设计既节省了内存开销,而且保证同一功能界面每次展示给用户都是相同的,保证了用户体验的一致性。

在Android中要实现上面这样的一套管理结构,我们需要一些数据结构来帮忙。

Activity中的关键数据结构有:

  1. ActivityRecord
  2. TaskRecord
  3. ActivityStack
  4. ActivityDisplay
  5. ActivityStackSupervisor
  6. ProcessRecord

我们先用一张图来描述这些数据结构之间的关系,然后在分别对它们进行一些解释。


1. ActivityRecord

ActivityRecord: Activity管理的最小单位,它一般对应一个用户界面。它需要记录AndroidManifest.xml中所定义的Activity的静态特征,同时也需要记录Activity在调度时的状态变化。ActivityRecord中的大部分成员变量都是记录Activity的相关信息,下面介绍几个比较重要的:

1.1. 成员变量appToken
final IApplicationToken.Stub appToken; // window manager token

从定义可以看出appToken是用来进行跨进程通信的,android系统中用AMS来管理Activity,而它和应用程序是运行在不同进程中的。appToken就可以看做是连接系统进程应用进程的桥梁,我们后面会详细介绍它的作用。

1.2. 成员变量task
 private TaskRecord task;        // the task this is in.

成员变量task代表当前Activity属于哪一个栈,相关的栈信息就保存在TaskRecord中。

2. TaskRecord

TaskRecord:一个栈式管理结构,它的职责就是管理ActivityRecord,记录activity开启的先后顺序。每个ActivityRecord都必须属于一个TaskRecordTaskRecordActivityRecord是一对多的关系,栈顶的ActivityRecord表示当前用户可见的界面。TaskRecord中的成员变量

2.1 成员变量mActivities
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities;

表示当前栈中管理的所有ActivityRecord

2.2 成员变量mStack
/** Current stack. Setter must always be used to update the value. */
private ActivityStack mStack;

表示当前TaskRecord所属的ActivityStackTaskRecord除了要维护管理它包含的ActivityRecord,它本身作为一个栈,还需要维护自身任务栈的状态。

3 ActivityStack

ActivityStack:它的职责是管理TaskRecord。每个TaskRecord都必须属于一个ActivityStackTaskRecordActivityStack是一对多的关系,栈顶的TaskRecord代表当前用户可见的任务。ActivityStack中的成员变量

3.1 成员变量mTaskHistory
/**
* The back history of all previous (and possibly still
* running) activities.  It contains #TaskRecord objects.
*/
private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();

表示当前栈中管理的所有TaskRecord

3.2 成员变量ActivityState

每个Activity都会有一个状态,譬如显示,销毁。这些状态的变化都需要ActivityStack来进行管理。Activity的状态是通过ActivityStack中的成员变量ActivityState来定义的。

enum ActivityState {
    INITIALIZING,
    RESUMED,
    PAUSING,
    PAUSED,
    STOPPING,
    STOPPED,
    FINISHING,
    DESTROYING,
    DESTROYED,
    RESTARTING_PROCESS
}

4. ActivityDisplay

ActivityDisplayActivityDisplay表示一个屏幕,Android支持三种屏幕:主屏幕,外接屏幕(HDMI等),虚拟屏幕(投屏)。一般情况下,即只有主屏幕时,ActivityStackSupervisorActivityDisplay都是系统唯一。

5. ActivityStackSupervisor

ActivityStackSupervisor:管理多个ActivityStack

6. ProcessRecord

ProcessRecord:记录着属于一个进程的所有ActivityRecord,运行在不同TaskRecord中的ActivityRecord可能属于同一个ProcessRecord

通过我们上面的描述,我们可以看出这些数据结构是一层包含一层,层层递推的。

当我们启动一个新的activity的时候,首先会为这个activity创建一个ActivityRecord,然后在为这个Activty分配所属的TaskRecord,这个TaskRecord又要分配到对应的ActivityStackActivityStack也要分配到所属的ActivityDisplay。这一整套关系确立之后,我们才能够真正启动这个Activity。为了尽量简化我们后面Activity启动流程的分析,这里我们就先把这些数据结构的创建过程单独拎出来分析。

ActivityRecord的创建

ActivityRecord的创建比较简单,它是在activity启动过程中的startActivity函数中被创建的

//frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
private int startActivity(IApplicationThread caller, Intent intent, Intent                         
    ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
    IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
    IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
    String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
    SafeActivityOptions options,boolean ignoreTargetSecurity, boolean 
    componentSpecified, ActivityRecord[] outActivity,
    TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
    PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
......
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
    callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
    resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
    mSupervisor, checkedOptions, sourceRecord);
......

我们主要看一下ActivityDisplayActivityStackTaskRecord的创建和联系过程,这个过程相对繁琐,我们先把时序图列出来,然后跟着时序图来分析代码。

//frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
1463      // Note: This method should only be called from {@link startActivity}.
1464      private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
1465              IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
1466              int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
1467              ActivityRecord[] outActivity, boolean restrictedBgActivity) {
          ......
1665          // Should this be considered a new task?
1666          int result = START_SUCCESS;
1667          if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
1668                  && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
1669              newTask = true;
                  //开始为ActivityRecord配置对应的TaskRecord和ActivityStack
1670              result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
          ......

接下来我们看下TaskRecordActivityStack的创建和关联过程, 其实整个Activity这些重要结构体的创建以及对应关系的建立比较复杂,它有很多情况,对应不同的路径,我们这里只是选择了一种情况来进行分析。

//frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
2298      private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
2299          if (mRestrictedBgActivity && (mReuseTask == null || !mReuseTask.containsAppUid(mCallingUid))
2300                  && handleBackgroundActivityAbort(mStartActivity)) {
2301              return START_ABORTED;
2302          }
2303          // 1.创建获取ActivityStack
2304          mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
2305  
2306          // Do no move the target stack to front yet, as we might bail if
2307          // isLockTaskModeViolation fails below.
2308  
2309          if (mReuseTask == null) {
                  //2.创建TaskRecord
2310              final TaskRecord task = mTargetStack.createTaskRecord(
2311                      mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
2312                      mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
2313                      mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
2314                      mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
2315                      mOptions);
                  //3.将ActivityRecord添加到TaskRecord中
2316              addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
2317              updateBounds(mStartActivity.getTaskRecord(), mLaunchParams.mBounds);
2318  
2319              if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
2320                      + " in new task " + mStartActivity.getTaskRecord());
2321          } else {
2322              addOrReparentStartingActivity(mReuseTask, "setTaskFromReuseOrCreateNewTask");
2323          }
2324  
2325          if (taskToAffiliate != null) {
2326              mStartActivity.setTaskToAffiliateWith(taskToAffiliate);
2327          }
2328  
2329          if (mService.getLockTaskController().isLockTaskModeViolation(
2330                  mStartActivity.getTaskRecord())) {
2331              Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
2332              return START_RETURN_LOCK_TASK_MODE_VIOLATION;
2333          }
2334  
2335          if (mDoResume) {
                  //4.将当前要显示的ActivityStack移到栈顶
2336              mTargetStack.moveToFront("reuseOrNewTask");
2337          }
2338          return START_SUCCESS;
2339      }

我们可以看到setTaskFromReuseOrCreateNewTask主要做了4件事:

  1. 为已创建的ActivityRecord寻找创建ActivityStack
  2. 创建TaskRecord
  3. ActivityRecord添加到TaskRecord
  4. ActivityStack移到栈顶准备显示

这样这几个重要的数据结构,就像我们上面列出的它们之间的关系图一样,建立起来了层层包含的关系。下面我们来一件件来分析它们。


//frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
2589      private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags,
2590              ActivityOptions aOptions) {
2591          final TaskRecord task = r.getTaskRecord();
2592          ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
2593          if (stack != null) {
2594              return stack;
2595          }
       ......

getLaunchStack看名字也可以猜到是寻找合适的ActivityStack,成功之后直接返回。所以上面省略的部分应该是对ActivityStack创建获取失败之后的处理,我们不用关心,直接去看getLaunchStack函数。

//frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
2673      private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
2674              ActivityOptions aOptions) {
2675          // We are reusing a task, keep the stack!
2676          if (mReuseTask != null) {
2677              return mReuseTask.getStack();
2678          }
2679  
2680          if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0)
2681                   || mPreferredDisplayId != DEFAULT_DISPLAY) {
2682              final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront();
2683              final ActivityStack stack =
2684                      mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams);
2685              return stack;
2686          }
          ......

这里调用了RootActivityContainergetLaunchStack函数

//frameworks/base/services/core/java/com/android/server/wm/RootActivityContainer.java
1673      <T extends ActivityStack> T getLaunchStack(@Nullable ActivityRecord r,
1674              @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop,
1675              @Nullable LaunchParamsController.LaunchParams launchParams) {
1676          int taskId = INVALID_TASK_ID;
1677          int displayId = INVALID_DISPLAY;
1678          //Rect bounds = null;
          ......
1706          if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) {
1707              if (r != null) {
                      //get合适的Activitystack,如果存在直接返回
1708                  stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options,
1709                          launchParams);
1710                  if (stack != null) {
1711                      return stack;
1712                  }
1713              }
                  //根据displayId获取ActivityDisplay对象
1714              final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
1715              if (display != null) {
                      //根据ActivityDisplay创建ActivityStack
1716                  stack = display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
1717                  if (stack != null) {
1718                      return stack;
1719                  }
1720              }
1721          }
          ......

这根据displayId获取对应的ActivityDisplay对象,然后通过这个ActivityDisplay对象来创建ActivityStack

375      <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
376              boolean onTop) {
377          if (!alwaysCreateStack(windowingMode, activityType)) {
378              T stack = getStack(windowingMode, activityType);
379              if (stack != null) {
380                  return stack;
381              }
382          }
383          return createStack(windowingMode, activityType, onTop);
384      }
385  
386      /**
387       * Returns an existing stack compatible with the input params or creates one
388       * if a compatible stack doesn't exist.
389       * @see #getOrCreateStack(int, int, boolean)
390       */
391      <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
392              @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
393              boolean onTop) {
394          // First preference is the windowing mode in the activity options if set.
395          int windowingMode = (options != null)
396                  ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
397          // Validate that our desired windowingMode will work under the current conditions.
398          // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
399          // it's display's windowing mode.
400          windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
401          return getOrCreateStack(windowingMode, activityType, onTop);
402      }

终于看到了createStack函数,看名字感觉离最终ActivityStack的创建已经不远。

//frameworks/base/services/core/java/com/android/server/wm/ActivityDisplay.java
420      <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
          ......
454          final int stackId = getNextStackId();
455          return createStackUnchecked(windowingMode, activityType, stackId, onTop);
456      }

获取下一个stackId,继续调用createStackUnchecked完成ActivityStack的创建


//frameworks/base/services/core/java/com/android/server/wm/ActivityDisplay.java
459      <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
460              int stackId, boolean onTop) {
461          if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
462              throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
463                      + "activity type.");
464          }
465          return (T) new ActivityStack(this, stackId,
466                  mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
467      }

终于完成了ActivityStack的创建。而且我们会发现ActivityStack是由ActivityDisplay创建的,至此ActivityRecordActivityStack都已经创建完成,我们接着回到setTaskFromReuseOrCreateNewTask函数去看下TaskRecord的创建。

//frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java
5475      TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
5476              IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
5477              boolean toTop, ActivityRecord activity, ActivityRecord source,
5478              ActivityOptions options) {
              //创建TaskRecord
5479          final TaskRecord task = TaskRecord.create(
5480                  mService, taskId, info, intent, voiceSession, voiceInteractor);
5481          // add the task to stack first, mTaskPositioner might need the stack association
              //新建的TaskRecord插入到了ActivityStack中mTaskHistory中,将TaskRecord和ActivityStack关联在了一起。
5482          addTask(task, toTop, "createTaskRecord");
5483          final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
5484          final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
5485                  .isKeyguardOrAodShowing(displayId);
5486          if (!mStackSupervisor.getLaunchParamsController()
5487                  .layoutTask(task, info.windowLayout, activity, source, options)
5488                  && !matchParentBounds() && task.isResizeable() && !isLockscreenShown) {
5489              task.updateOverrideConfiguration(getRequestedOverrideBounds());
5490          }
5491          task.createTask(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
5492          return task;
5493      }

到这我们完成了TaskRecord的创建,并且将TaskRecordActivityStack建立起了联系。我们继续回到setTaskFromReuseOrCreateNewTask接着执行第3步操作。

//frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
2554      private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
2555          if (mStartActivity.getTaskRecord() == null || mStartActivity.getTaskRecord() == parent) {
                  //将当前Activity插入到TaskRecord中的mActivities的顶部,建立ActivityRecord与TaskRecord的联系
2556              parent.addActivityToTop(mStartActivity);
2557          } else {
2558              mStartActivity.reparent(parent, parent.mActivities.size() /* top */, reason);
2559          }
2560      }

最后调用moveToFront,将stack移到栈的顶部。至此我们已经完成了Acitivity启动所需要的ActivityRecordTaskRecordActivityStack的创建,并按照我们最开始讲的Activity的管理方式,对它们建立起了关联。Activity的运行过程中,可能的情况非常之多,但我们只要牢记这几个结构体之间的关系,Activity的管理就是对这几个关键结构体根据不同的情况一直进行调整,这样分析代码的时候思路就会清晰很多。

2. Activity的通信

Android中有一些系统进程运行着系统中重要的服务(AMS,PMS,WMS)。对系统进程AMS来说,它需要与应用程序进行通信,调度Activity执行,管理Activity的状态。对每一个应用程序来说,它运行在独立的进程中,有自己独立的内存空间,它需要接受AMS的调度,执行Activity相应的生命周期回调函数。所以不管是从系统到应用还是从应用到系统,它们都需要跨进程调用。Android中的跨进程通信方法就是Binder。Android为系统与应用中间的相互通信设计了两个Binder接口。

IApplicationThread:系统进程请求应用进程的接口。

IActivityTaskManager, IActivityManagerService:应用进程请求系统进程的接口。原来的版本只有IActivityManagerService一个接口,但是因为AMS的代码实在太多了,所以google在最近的版本里新加了IActivityTaskManager,把之前一些ActivityManagerService里面的工作挪到了ActivityTaskManager里面。

我们在开始介绍Activiy中的重要数据结构的时候提到了ProcessRecord,但一直没有介绍它。ProcessRecord的一个重要的作用就是AMS可以利用它远程调用到应用进程中的函数。在应用进程ActivityThread创建的时候,它会将自己的ApplictaionThread绑定到AMS中,整个绑定过程如下:

ActivityThread.main()--->ActivityThread.attach()--->IActivityManagerService.attachApplication(ApplicationThread)

AMS作为IActivityManagerService接口服务端的实现,会响应客户端的请求,最终AMS.attachApplication()会被执行,该函数接收跨进程传递过来的ApplicationThread实例,然后将其赋值给AMS维护的ProcessRecord.thread。这样后面AMS就可以通过ProcessRecord.thread调用应用进程中的函数了。

我们除了要在应用进程和系统进程中进行通信,还需要一个方法能够在应用进程和系统进程中同步Activity的状态。AMS中采用ActivityRecord来描述Activity,应用进程中采用ActivityClientRecordActivity。这三者之间一一对应,从而达到Activity状态在系统进程和应用进程之间的同步。而达到这一目的的关键就是我们在讲解ActivityRecord时提到的成员变量appToken

final class ActivityRecord {
    final IApplicationToken.Stub appToken; // window manager token
 
    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
            int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
            ActivityInfo aInfo, Configuration _configuration,
            ActivityRecord _resultTo, String _resultWho, int _reqCode,
            boolean _componentSpecified, boolean _rootVoiceInteraction,
            ActivityStackSupervisor supervisor,
            ActivityContainer container, Bundle options) {
            ……
            appToken = new Token(this, service);
            ……
    }
 
    static class Token extends IApplicationToken.Stub {
        private final WeakReference<ActivityRecord> weakActivity;
        private final ActivityManagerService mService;
 
        Token(ActivityRecord activity, ActivityManagerService service) {
            weakActivity = new WeakReference<>(activity);
            mService = service;
        }
    }
}

在创建ActivityRecord的时候我们会对appToken进行赋值,然后我们发现Token中持有ActivityRecord的弱引用,也就是说可以通过appToken找到ActivityRecord。因此我们只要把appToken传到App进程中,并赋值给ActivityClientRecordActivity,就可以建立这三者之间的对用关系。

//frameworks/base/core/java/android/app/ActivityThread.java
2980      public final Activity startActivityNow(Activity parent, String id,
2981          Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
2982          Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken) {
2983          ActivityClientRecord r = new ActivityClientRecord();
2984              r.token = token;
2985              r.assistToken = assistToken;
2986              r.ident = 0;
2987              r.intent = intent;
2988              r.state = state;
2989              r.parent = parent;
2990              r.embeddedID = id;
2991              r.activityInfo = activityInfo;
2992              r.lastNonConfigurationInstances = lastNonConfigurationInstances;

可以看到ActivityThread中创建了ActivityClientRecord,并将token赋值给了该ActivityClientRecord.

//frameworks/base/core/java/android/app/ActivityThread.java
3159      private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
3160          ActivityInfo aInfo = r.activityInfo;
3161          if (r.packageInfo == null) {
3162              r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
3163                      Context.CONTEXT_INCLUDE_CODE);
3164          }
              ......
 
3224                  activity.attach(appContext, this, getInstrumentation(), r.token,
3225                          r.ident, app, r.intent, r.activityInfo, title, r.parent,
3226                          r.embeddedID, r.lastNonConfigurationInstances, config,
3227                          r.referrer, r.voiceInteractor, window, r.configCallback,
3228                          r.assistToken);
              ......
 
//frameworks/base/core/java/android/app/Activity.java
7701      final void attach(Context context, ActivityThread aThread,
7702              Instrumentation instr, IBinder token, int ident,
7703              Application application, Intent intent, ActivityInfo info,
7704              CharSequence title, Activity parent, String id,
7705              NonConfigurationInstances lastNonConfigurationInstances,
7706              Configuration config, String referrer, IVoiceInteractor voiceInteractor,
7707              Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
7708          attachBaseContext(context);
              ......
7727          mToken = token;
               ......

Activity.attach()中将ActivityClientRecord.token赋值给了Activity.mToken。至此,ActivityRecordActivityClientRecordActivity三者的一一对应关系就建立完毕了。总结一下,ActivityRecordActivityClientRecord都是保存Activity信息的对象。只不过,ActivityRecord归系统进程使用,ActivityClientRecord归应用进程使用。他们之间通过token建立同步关系。

有了这些预备知识,我们在下一篇博客中就可以直接分析Activity的启动流程代码了。

转自 https://blog.csdn.net/nanyou519/article/details/104716759

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

推荐阅读更多精彩内容