Android Java crash原理

Android系统发生Java crash时候,没有去捕获处理它的话,它就会一路往上抛,最终来到main函数,如果main函数也没有处理这个异常,就会给到JVM来处理,JVM会给到当前的线程Thread来处理。

art/runtime/well_known_classes.cc

java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");

调用到当前线程的dispatchUncaughtException 方法

libcore/ojluni/src/main/java/java/lang/Thread.java
      /**
       * Dispatch an uncaught exception to the handler. This method is
       * intended to be called only by the runtime and by tests.
       *这个方法只能被runtime执行, 当现成出现没有捕获的异常的时候执行,
       * @hide
       */
     public final void dispatchUncaughtException(Throwable e) {
         Thread.UncaughtExceptionHandler initialUeh =
                 Thread.getUncaughtExceptionPreHandler();
         if (initialUeh != null) {
             try {
                 initialUeh.uncaughtException(this, e);
             } catch (RuntimeException | Error ignored) {
                 // Throwables thrown by the initial handler are ignored
             }
         }
         getUncaughtExceptionHandler().uncaughtException(this, e);
     }

    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }

如果没有设置uncaughtExceptionHandler,将使用线程所在的线程组(ThreadGroup)来处理这个未捕获异常。线程组ThreadGroup实现了UncaughtExceptionHandler,所以可以用来处理未捕获异常。

libcore/ojluni/src/main/java/java/lang/ThreadGroup.java
    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }

默认情况下,ThreadGroup处理未捕获异常的逻辑是:
1、首先将异常消息通知给父线程组(如果parent不为空的话);
2、然后尝试利用一个默认的defaultUncaughtExceptionHandler来处理异常;
3、如果没有默认的异常处理器则将错误信息输出打印到System.err。

如果设置了uncaughtExceptionHandler ,谁回调下面的这个接口就可以处理crash异常。

/libcore/ojluni/src/main/java/java/lang/Thread.java
      @FunctionalInterface
      public interface UncaughtExceptionHandler {
          void uncaughtException(Thread t, Throwable e);
      }

setUncaughtExceptionPreHandler

      public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
          return defaultUncaughtExceptionHandler;
      }

      private static volatile UncaughtExceptionHandler uncaughtExceptionPreHandler;
  

      public static void setUncaughtExceptionPreHandler(UncaughtExceptionHandler eh) {
          uncaughtExceptionPreHandler = eh;
      }

再看下 setUncaughtExceptionPreHandler 是什么时候设置的
它的设置在RuntimeInit.java中
不管是系统进程还是App进程,启动的时候都会走到这里,进行注册。

/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

      public static final void main(String[] argv) {
          ......
          commonInit();
          ......
      }

      protected static final void commonInit() {
          
          LoggingHandler loggingHandler = new LoggingHandler();
          Thread.setUncaughtExceptionPreHandler(loggingHandler);
          //这里设置了默认的异常处理:KillApplicationHandler。
          Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
      }

再看下KillApplicationHandler:

/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

         @Override  //回调了uncaughtException接口,处理异常
          public void uncaughtException(Thread t, Throwable e) {
              try {
......
//上报给AMS 崩溃异常信息
                  ActivityManager.getService().handleApplicationCrash(
                          mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));
              } catch (Throwable t2) {
                  if (t2 instanceof DeadObjectException) {
                      // System process is dead; ignore
                  } else {
                      try {
                          Clog_e(TAG, "Error reporting crash", t2);
                      } catch (Throwable t3) {
                          // Even Clog_e() fails!  Oh well.
                      }
                  }
              } finally {
                  //杀掉进程
                  Process.killProcess(Process.myPid());
                  //退出当前进程
                  System.exit(10);
              }
          }

默认的异常处理(杀进程)是在RuntimeInit进程(作用:app运行时环境初始化,用来初始化运行时的一系列信息,其中包含异常处理)的main()方法里设置的。

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
      public void handleApplicationCrash(IBinder app,
              ApplicationErrorReport.ParcelableCrashInfo crashInfo) {
          ProcessRecord r = findAppProcess(app, "Crash");
          final String processName = app == null ? "system_server"
                  : (r == null ? "unknown" : r.processName);
  
          handleApplicationCrashInner("crash", r, processName, crashInfo);
      }

参数eventType是指事件类型,具体如下:
Java层未捕捉的异常:crash
ANR:anr
native层的异常:native_crash
现在我们看的是java的异常,所以这个类型传的是crash。
接着看handleApplicationCrashInner()函数:

      void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
              ApplicationErrorReport.CrashInfo crashInfo) {
          EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
                  UserHandle.getUserId(Binder.getCallingUid()), processName,
                  r == null ? -1 : r.info.flags,
                  crashInfo.exceptionClassName,
                  crashInfo.exceptionMessage,
                  crashInfo.throwFileName,
                  crashInfo.throwLineNumber);
  
          StatsLog.write(StatsLog.APP_CRASH_OCCURRED,
                  Binder.getCallingUid(),
                  eventType,
                  processName,
                  Binder.getCallingPid(),
                  (r != null && r.info != null) ? r.info.packageName : "",
                  (r != null && r.info != null) ? (r.info.isInstantApp()
                          ? StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE
                          : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__FALSE)
                          : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__UNAVAILABLE,
                  r != null ? (r.isInterestingToUserLocked()
                          ? StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND
                          : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND)
                          : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
          );
  
          addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
  
          mAppErrors.crashApplication(r, crashInfo);
      }

进行系统日志输出,具体的处理是在addErrorToDropBox()函数中。当启动Activity时候,如果找不到,会报错,这个时候systemserver进程中的启动数据依然存在,存在缓存信息,要清除。

接着看下AppErrors.crashApplication

/frameworks/base/services/core/java/com/android/server/am/AppErrors.java
void crashApplication{
......
crashApplicationInner(......);
......
}

 void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
            int callingPid, int callingUid) {
......
        synchronized (mService) {
......
            if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
                return;
            }
            
            AppErrorDialog.Data data = new AppErrorDialog.Data();
            data.result = result;
            data.proc = r;

            final Message msg = Message.obtain();
            msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;

            taskId = data.taskId;
            msg.obj = data;
            // 发送消息,弹出crash对话框,等待用户选择
           //如果选择重新启动,则从最近任务列表中找到崩溃进程,再次拉起
           //如果选择强制退出,则杀掉app,进入kill流程
           //如果选择显示应用信息,则启动系统页面的intent,打开应用详情页面
            mService.mUiHandler.sendMessage(msg);
        }
        // 得到用户选择结果
        int res = result.get();

        Intent appErrorIntent = null;
        MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
        // 如果是超时或者取消,则当成是强制退出
        if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
            res = AppErrorDialog.FORCE_QUIT;
        }
        synchronized (mService) {
            if (res == AppErrorDialog.MUTE) {
                stopReportingCrashesLocked(r);
            }
            // 如果是重新启动
            if (res == AppErrorDialog.RESTART) {
                mService.mProcessList.removeProcessLocked(r, false, true, "crash");
                if (taskId != INVALID_TASK_ID) {
                    try {
                     //1. 从最近的任务列表中找到崩溃进程,再次启动
                        mService.startActivityFromRecents(taskId,
                                ActivityOptions.makeBasic().toBundle());
                    } catch (IllegalArgumentException e) {
                        // Hmm...that didn't work. Task should either be in recents or associated
                        // with a stack.
                        Slog.e(TAG, "Could not restart taskId=" + taskId, e);
                    }
                }
            }
             // 如果是退出
            if (res == AppErrorDialog.FORCE_QUIT) {
                long orig = Binder.clearCallingIdentity();
                try {
                    // Kill it with fire!
                    // 杀掉这个进程
                    mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
                    if (!r.isPersistent()) {
                        mService.mProcessList.removeProcessLocked(r, false, false, "crash");
                        mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
                    }
                } finally {
                    Binder.restoreCallingIdentity(orig);
                }
            }
             // 如果是显示应用信息
            if (res == AppErrorDialog.APP_INFO) {
                appErrorIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                appErrorIntent.setData(Uri.parse("package:" + r.info.packageName));
                appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
                appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
            }
            if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
                // XXX Can't keep track of crash time for isolated processes,
                // since they don't have a persistent identity.
                mProcessCrashTimes.put(r.info.processName, r.uid,
                        SystemClock.uptimeMillis());
            }
        }

        if (appErrorIntent != null) {
            try {
            // 2. 启动一个系统页面的intent 来显示应用信息
                mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
            } catch (ActivityNotFoundException e) {
                Slog.w(TAG, "bug report receiver dissappeared", e);
            }
        }
    }

makeAppCrashingLocked

private boolean makeAppCrashingLocked(ProcessRecord app,
         String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
     app.setCrashing(true);
     // 封装崩溃信息到 ProcessErrorStateInfo 中
     app.crashingReport = generateProcessError(app,
             ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
     // 获取当前user的 error receiver;停止广播接收
     app.startAppProblemLocked();
     // 停是冻结屏幕
     app.getWindowProcessController().stopFreezingActivities();
     // 调用 handleAppCrashLocked
     return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
             data);
 }

封装崩溃信息到 ProcessErrorStateInfo 中
获取当前user的 error receiver;停止广播接收
停是冻结屏幕
handleAppCrashLocked()

boolean handleAppCrashLocked(ProcessRecord app, String reason,
         String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
......
      // 同一个进程,如果连续两次崩溃的间隔小于 一分钟,则认为崩溃过于频繁
     if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {
         // The process crashed again very quickly. If it was a bound foreground service, let's
         // try to restart again in a while, otherwise the process loses!
         Slog.w(TAG, "Process " + app.info.processName
                 + " has crashed too many times: killing!");
         EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                 app.userId, app.info.processName, app.uid);
                 // 2.8.1 回调 atm的onHandleAppCrash 
         mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
       
         if (!app.isPersistent()) {
           // 如果不是persistent进程,则不再重启,除非用户主动触发
             // We don't want to start this process again until the user
             // explicitly does so...  but for persistent process, we really
             // need to keep it running.  If a persistent process is actually
             // repeatedly crashing, then badness for everyone.
            
             if (!app.isolated) {
                 // XXX We don't have a way to mark isolated processes
                 // as bad, since they don't have a peristent identity.
                 mBadProcesses.put(app.info.processName, app.uid,
                         new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
                 mProcessCrashTimes.remove(app.info.processName, app.uid);
             }
             app.bad = true;
             app.removed = true;
             // Don't let services in this process be restarted and potentially
             // annoy the user repeatedly.  Unless it is persistent, since those
             // processes run critical code.
             // 移除进程中的所有服务
             mService.mProcessList.removeProcessLocked(app, false, tryAgain, "crash");
             // 恢复顶部的activity
             mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
             if (!showBackground) {
                 return false;
             }
         }
         mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
     } else {
     // 不是一分钟内连续崩溃
         final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
                         app.getWindowProcessController(), reason);
         if (data != null) {
             data.taskId = affectedTaskId;
         }
         if (data != null && crashTimePersistent != null
                 && now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
             data.repeating = true;
         }
     }

......
      // 如果 app的crashHandler存在,则交给其处理
     if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
     return true;
 }

如果是两次连续崩溃小于一分钟,则认为是频繁崩溃。
调用onHandleAppCrash方法
如果不是persistent进程,则不再重启,除非用户主动触发
移除进程中的所有服务,且不再重启
恢复栈顶的activity

不是连续崩溃,则记录崩溃受影响的taskid
如果 app的crashHandler存在,则交给其处理

/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@Override
public void onHandleAppCrash(WindowProcessController wpc) {
   synchronized (mGlobalLock) {
       mRootActivityContainer.handleAppCrash(wpc);
   }
}

//RootActivityContainer.java
void handleAppCrash(WindowProcessController app) {
   // 遍历所有的ActivityDisplay
  for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
      final ActivityDisplay display = mActivityDisplays.get(displayNdx);
      // 遍历ActivityDisplay中管理的所有 ActivityStack 
      for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
         // 获取activity stack对象 
          final ActivityStack stack = display.getChildAt(stackNdx);
          stack.handleAppCrash(app);
      }
  }
}

>ActivityStack.java
void handleAppCrash(WindowProcessController app) {
  // 循环ActivityStack中管理的 TaskRecord
  for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
      // 得到 TaskRecord中管理的所有  ActivityRecord集合
      final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
      // 遍历 ActivityRecord集合,得到每一个 ActivityRecord对象
      for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
          final ActivityRecord r = activities.get(activityNdx);
          // 如果是崩溃的进程,则销毁activity
          if (r.app == app) {
                      
              // Force the destroy to skip right to removal.
              r.app = null;
              // 
              getDisplay().mDisplayContent.prepareAppTransition(
                      TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
              // finish销毁当前activity
              finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
                      "handleAppCrashedLocked");
          }
      }
  }
}

AMS端在收到App的崩溃后,大概流程如下:

把崩溃信息通过 DBS 服务,写入到Dropbox文件中。dropbox支持错误类型:crash、wtf、anr
停止崩溃进程接收广播;增加ServiceRecord中的crashcount数;销毁所有的activies;
弹出崩溃对话框,等待用户选择

  1. 如果选择重新启动,则从最近任务列表中找到崩溃进程,再次拉起
  2. 如果选择强制退出,则杀掉app,进入kill流程
  3. 如果选择显示应用信息,则启动系统页面的intent,打开应用详情页面

Binder服务死亡通知

在RuntimeInit uncaughtException 末尾会执行
finally {
   // Try everything to make sure this process goes away.
   // 最终关闭kill掉进程
   Process.killProcess(Process.myPid());
   System.exit(10);
}
public static final void killProcess(int pid) {
     sendSignal(pid, SIGNAL_KILL);
 }
public static final native void sendSignal(int pid, int signal);

给指定的进程发送一个 SIGNAL_KILL 信号。应用进程已经被杀死,但是还没完。因为system server进程中有注册Binder服务的死亡监听。当App进程死亡后,会回调到AMS
的死亡监听中,此时还需要处理Binder死亡通知回调逻辑。

在创建进程的过程中,ActivityThread会调用AMS的 attachApplication(), 内部会调用到 attachApplicationLocked()方法。在这里注册的Binder的死亡通知。

ActivityThread.java
@GuardedBy("this")
 private final boolean attachApplicationLocked(IApplicationThread thread,
         int pid, int callingUid, long startSeq) {
         //...
   try {
         AppDeathRecipient adr = new AppDeathRecipient(
                 app, pid, thread);
         thread.asBinder().linkToDeath(adr, 0);
         app.deathRecipient = adr;
     } catch (RemoteException e) {
         app.resetPackageList(mProcessStats);
         mProcessList.startProcessLocked(app,
                 new HostingRecord("link fail", processName));
         return false;
     }
   //...
}

当有binder服务死亡,会调用 AppDeathRecipient 的 binderDied()方法:

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
      private final class AppDeathRecipient implements IBinder.DeathRecipient {
          final ProcessRecord mApp;
          final int mPid;
          final IApplicationThread mAppThread;
  
          AppDeathRecipient(ProcessRecord app, int pid,
                  IApplicationThread thread) {
              if (DEBUG_ALL) Slog.v(
                  TAG, "New death recipient " + this
                  + " for thread " + thread.asBinder());
              mApp = app;
              mPid = pid;
              mAppThread = thread;
          }
  
          @Override
          public void binderDied() {
              if (DEBUG_ALL) Slog.v(
                  TAG, "Death received in " + this
                  + " for thread " + mAppThread.asBinder());
              synchronized(ActivityManagerService.this) {
                  appDiedLocked(mApp, mPid, mAppThread, true);
              }
          }
      }
@GuardedBy("this")
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
      boolean fromBinderDied) {
......
   // 如果没有被杀,再次杀app
  if (!app.killed) {
      if (!fromBinderDied) {
          killProcessQuiet(pid);
      }
      ProcessList.killProcessGroup(app.uid, pid);
      app.killed = true;
  }
......
      //  调用 handleAppDiedLocked
      handleAppDiedLocked(app, false, true);
......
  }
  //...
}
final void handleAppDiedLocked(ProcessRecord app,
         boolean restarting, boolean allowRestart) {
     int pid = app.pid;
     // 清理service、broadcastreveiver、contentprovider等信息
     boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
             false /*replacingPid*/);
     if (!kept && !restarting) {
     // 移除崩溃进程在AMS中的代表 ProcessRecord
         removeLruProcessLocked(app);
         if (pid > 0) {
             ProcessList.remove(pid);
         }
     }

     if (mProfileData.getProfileProc() == app) {
         clearProfilerLocked();
     }
      // 继续调用 atm的 handleAppDied
     mAtmInternal.handleAppDied(app.getWindowProcessController(), restarting, () -> {
         Slog.w(TAG, "Crash of app " + app.processName
                 + " running instrumentation " + app.getActiveInstrumentation().mClass);
         Bundle info = new Bundle();
         info.putString("shortMsg", "Process crashed.");
         finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
     });
 }

/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public void handleAppDied(WindowProcessController wpc, boolean restarting,
       Runnable finishInstrumentationCallback) {
   synchronized (mGlobalLockWithoutBoost) {
       // Remove this application's activities from active lists.
       // 清理activities相关信息
       boolean hasVisibleActivities = mRootActivityContainer.handleAppDied(wpc);

       wpc.clearRecentTasks();
       wpc.clearActivities();

       if (wpc.isInstrumenting()) {
           finishInstrumentationCallback.run();
       }

       if (!restarting && hasVisibleActivities) {
           mWindowManager.deferSurfaceLayout();
           try {
               if (!mRootActivityContainer.resumeFocusedStacksTopActivities()) {
                   // If there was nothing to resume, and we are not already restarting
                   // this process, but there is a visible activity that is hosted by the
                   // process...then make sure all visible activities are running, taking
                   // care of restarting this process.
                   // 确保恢复顶部的activity
                   mRootActivityContainer.ensureActivitiesVisible(null, 0,
                           !PRESERVE_WINDOWS);
               }
           } finally {
              // windows相关
               mWindowManager.continueSurfaceLayout();
           }
       }
   }
}

当App发生崩溃后,除了弹出对话框,发送kill命令杀掉自身后。AMS还会收到App进程的Binder服务死亡通知,只有当走完Binder的 binderDied()流程后,整个崩溃流程才算真正结束。

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

推荐阅读更多精彩内容