Android系统_进程创建流程分析

前言

当某个应用组件启动且该应用没有运行其他任何组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。默认情况下,同一应用的所有组件在相同的进程和线程(称为“主”线程)中运行。 如果某个应用组件启动且该应用已存在进程(因为存在该应用的其他组件),则该组件会在此进程内启动并使用相同的执行线程。 但是,您可以安排应用中的其他组件在单独的进程中运行,并为任何进程创建额外的线程。

进程

每个App在启动前必须先创建一个进程,该进程是由Zygote fork出来的,进程具有独立的资源空间,用于承载App上运行的各种Activity/Service等组件。大多数情况一个App就运行在一个进程中,除非在AndroidManifest.xml中配置Android:process属性,或通过native代码fork进程。
进程是能在系统中独立运行并作为资源分配的基本单位,是CPU分配资源的最小单位,它包括独立的地址空间,资源以及一至多个线程。

线程

线程是进程中的一个实体,是CPU调度的最小单位,没有独立空间地址,多线程共享所属进程的空间地址,线程主要负责是CPU执行代码的过程
APP应用启动时,系统会为应用创建一个名为“主线程”的执行线程。

进程创建流程图

  1. 进程创建起点,Process.start,然后告知ZygoteProcess执行启动,它会构造socket通道最后将构造指令及参数发送给zygote进程
  2. zygote进程,socket会循环监听请求,在接受请求后,会封装好构建进程参数通过Zygote.forkAndSpecialize及其native方法fork出一个子进程
  3. 子进程fork后,会进行一系列fork后处理事项及Runtime的init初始化工作,最后回调到子进程的zygote.runSelectLoop方法抛出异常走到ActivityThread.main方法,进入子进程世

进程创建代码分析

进程创建入口

Process.java

public static final ProcessStartResult start(final String processClass,
                             final String niceName,
                             int uid, int gid, int[] gids,
                             int debugFlags, int mountExternal,
                             int targetSdkVersion,
                             String seInfo,
                             String abi,
                             String instructionSet,
                             String appDataDir,
                             String invokeWith,
                             String[] zygoteArgs) {
   return zygoteProcess.start(processClass, niceName, uid, gid, gids,
               debugFlags, mountExternal, targetSdkVersion, seInfo,
               abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
进程创建参数准备

主要工作是生成argsForZygote数组,该数组保存了进程的uid、gid、groups、target-sdk、nice-name等一系列的参数。

ZygoteProcess.java


public final Process.ProcessStartResult start(final String processClass,
                                             final String niceName,
                                             int uid, int gid, int[] gids,
                                             int debugFlags, int mountExternal,
                                             int targetSdkVersion,
                                             String seInfo,
                                             String abi,
                                             String instructionSet,
                                             String appDataDir,
                                             String invokeWith,
                                             String[] zygoteArgs) {
    return startViaZygote(processClass, niceName, uid, gid, gids,
         debugFlags, mountExternal, targetSdkVersion, seInfo,
         abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

private static ProcessStartResult startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[] extraArgs) throws ZygoteStartFailedEx {
    synchronized(Process.class) {
        ArrayList<String> argsForZygote = new ArrayList<String>();
        ...
        // 生成argsForZygote数组,该数组保存了进程的uid、gid、groups、target-sdk、nice-name等一系列的参数
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

        if (niceName != null) {
            argsForZygote.add("--nice-name=" + niceName);
        }
        if (appDataDir != null) {
            argsForZygote.add("--app-data-dir=" + appDataDir);
        }
        argsForZygote.add(processClass);

        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }
        
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }
}

连接Zygote服务,写入创建指令并获取返回结果

ZygoteProcess.java
通过socket向Zygote进程发送消息,从而唤醒Zygote进程,来响应socket客户端的请求

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {    
    // 向主zygote发起connect()操作
    primaryZygoteState = ZygoteState.connect(mSocket); 
    //当主zygote没能匹配成功,则采用第二个zygote,发起connect()操作
    ...
}


private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
       ZygoteState zygoteState, ArrayList<String> args)
       throws ZygoteStartFailedEx {
    try {
         
      final BufferedWriter writer = zygoteState.writer;
      final DataInputStream inputStream = zygoteState.inputStream;
       
      writer.write(Integer.toString(args.size()));
      writer.newLine();
      // 写入参数
      for (int i = 0; i < sz; i++) {
          String arg = args.get(i);
          writer.write(arg);
          writer.newLine();
      }
    
      writer.flush(); 
      
      Process.ProcessStartResult result = new Process.ProcessStartResult();
    
      //等待socket服务端(即zygote)返回新创建的进程pid;
      result.pid = inputStream.readInt();
      result.usingWrapper = inputStream.readBoolean();
    
      if (result.pid < 0) {
          throw new ZygoteStartFailedEx("fork() failed");
      }
      return result;
    } catch (IOException ex) {
      zygoteState.close();
      throw new ZygoteStartFailedEx(ex);
    }
}
Zygote接收客户端Socket请求

ZygoteInit.java

public static void main(String argv[]) {
    try {
        // 服务端等待请求,然后处理
        zygoteServer.runSelectLoop(abiList); 
    } catch (MethodAndArgsCaller caller) {
        // 新的进程会通过抛出异常后走到这里,通过反射调用main方法执行后续任务
        caller.run(); 
    } catch (RuntimeException ex) {
        zygoteServer.closeServerSocket();
        throw ex;
    }
}

ZygoteServer

  • 客户端通过openZygoteSocketIfNeeded()来跟zygote进程建立连接。zygote进程收到客户端连接请求后执行accept();然后再创建ZygoteConnection对象,并添加到fds数组列表;
  • 建立连接之后,可以跟客户端通信,进入runOnce()方法来接收客户端数据,并执行进程创建工作
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    /sServerSocket是socket通信中的服务端,即zygote进程 
    fds.add(mServerSocket.getFileDescriptor());
    peers.add(null);
        
while (true) {
     StructPollfd[] pollFds = new StructPollfd[fds.size()];
     for (int i = 0; i < pollFds.length; ++i) {
         pollFds[i] = new StructPollfd();
         pollFds[i].fd = fds.get(i);
         pollFds[i].events = (short) POLLIN;
     }
     try {
         //处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
         Os.poll(pollFds, -1);
     } catch (ErrnoException ex) {
         throw new RuntimeException("poll failed", ex);
     }
     for (int i = pollFds.length - 1; i >= 0; --i) {
         //采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;否则进入continue,跳出本次循环。
         if ((pollFds[i].revents & POLLIN) == 0) {
             continue;
         }
         if (i == 0) {
            //即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;则创建ZygoteConnection对象,并添加到fds。
             ZygoteConnection newPeer = acceptCommandPeer(abiList);
             peers.add(newPeer);
             fds.add(newPeer.getFileDesciptor());
         } else {
             //i>0,则代表通过socket接收来自对端的数据,并执行 runOnce操作
             boolean done = peers.get(i).runOnce(this);
             if (done) {
                 peers.remove(i);
                 fds.remove(i);
             }
        }
     }
   }
}

private static ZygoteConnection acceptCommandPeer(String abiList) {
    // 接收客户端发送过来的connect()操作,Zygote作为服务端执行accept()操作。 再后面客户端调用write()写数据,Zygote进程调用read()读数据。
   return new ZygoteConnection(sServerSocket.accept(), abiList);
}
java层fork参数准备

ZygoteConnection.java

boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {

    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;
    
    // 读取socket客户端发送过来的参数列表
    args = readArgumentList();
    descriptors = mSocket.getAncillaryFileDescriptors();
    
    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;
    try {
      // 准备一系列fork进程的参数
      parsedArgs = new Arguments(args);
      int[][] rlimits = null;
      if (parsedArgs.rlimits != null) {
          rlimits = parsedArgs.rlimits.toArray(intArray2d);
      }
      int[] fdsToIgnore = null;
      if (parsedArgs.invokeWith != null) {
          FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
          childPipeFd = pipeFds[1];
          serverPipeFd = pipeFds[0];
          Os.fcntlInt(childPipeFd, F_SETFD, 0);
          fdsToIgnore = new int[] { childPipeFd.getInt$(), serverPipeFd.getInt$() };
      }
      int [] fdsToClose = { -1, -1 };
      FileDescriptor fd = mSocket.getFileDescriptor();
      if (fd != null) {
          fdsToClose[0] = fd.getInt$();
      }
      fd = zygoteServer.getServerSocketFileDescriptor();
      if (fd != null) {
          fdsToClose[1] = fd.getInt$();
      }
      fd = null;
      
      // 执行fork操作
      pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
              parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
              parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
              parsedArgs.appDataDir);
              
    } catch (ErrnoException ex) {
      ...
    }

   try {
       if (pid == 0) {
           // 子进程 
           zygoteServer.closeServerSocket();
           IoUtils.closeQuietly(serverPipeFd);
           serverPipeFd = null;
           // 进程初始化操作(最后抛出异常 回到runSelectLoop捕获异常方法)
           handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

           // should never get here, the child is expected to either throw Zygote.MethodAndArgsCaller or exec().
           return true;
       } else { // 父进程 (zygote进程)
           // in parent...pid of < 0 means failure
           IoUtils.closeQuietly(childPipeFd);
           childPipeFd = null;
           return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
       }
   } finally {
       IoUtils.closeQuietly(childPipeFd);
       IoUtils.closeQuietly(serverPipeFd);
   }
}

nativeFork前准备

Zygote.java
调用虚拟机执行preFork工作:停止Daemon子线程、等待所有子线程结束、完成gc堆的初始化工作

public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
     int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
     int[] fdsToIgnore, String instructionSet, String appDataDir) {
   VM_HOOKS.preFork();
   // Resets nice priority for zygote process.
   resetNicePriority();
   int pid = nativeForkAndSpecialize(
             uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
             fdsToIgnore, instructionSet, appDataDir);
   VM_HOOKS.postForkCommon();
   return pid;
}

调用native的fork方法

com_android_internal_os_Zygote.cpp

static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
        jlong effectiveCapabilities) {
  // fork子进程,
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities,effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,NULL, NULL);
  ...
  return pid;
}

static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                     jint debug_flags, jobjectArray javaRlimits,
                                     jlong permittedCapabilities, jlong effectiveCapabilities,
                                     jint mount_external,
                                     jstring java_se_info, jstring java_se_name,
                                     bool is_system_server, jintArray fdsToClose,
                                     jstring instructionSet, jstring dataDir) {
  ...
  
  pid_t pid = fork(); //!!! fork子进程 (COW 方式)
  
  if (pid == 0) { //进入子进程,初始化设置等
    DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符

    if (!is_system_server) {
        //对于非system_server子进程,则创建进程组
        int rc = createProcessGroup(uid, getpid());
    }
    SetGids(env, javaGids); //设置设置group
    SetRLimits(env, javaRlimits); //设置资源limit

    int rc = setresgid(gid, gid, gid);
    rc = setresuid(uid, uid, uid);

    SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
    SetSchedulerPolicy(env); //设置调度策略

     //selinux上下文
    rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);

    if (se_info_c_str == NULL && is_system_server) {
      se_name_c_str = "system_server";
    }
    if (se_info_c_str != NULL) {
      SetThreadName(se_name_c_str); //设置线程名为system_server,方便调试
    }
    //在Zygote子进程中,设置信号SIGCHLD的处理器恢复为默认行为
    UnsetSigChldHandler();
    //调用zygote.callPostForkChildHooks() 
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                              is_system_server ? NULL : instructionSet);
    ...
  } else if (pid > 0) { //进入父进程,即zygote进程
    ...
  }
  return pid;
}

fork

fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次,返回值有3种类型。父进程中,fork返回新创建的子进程的pid;子进程中,fork返回0;当出现错误时,fork返回负数。(当进程数超过上限或者系统内存不足时会出错)

fork()的主要工作是寻找空闲的进程号pid,然后从父进程拷贝进程信息,例如数据段和代码段,fork()后子进程要执行的代码等。 Zygote进程是所有Android进程的母体,包括system_server和各个App进程。zygote利用fork()方法生成新进程,对于新进程A复用Zygote进程本身的资源,再加上新进程A相关的资源,构成新的应用进程A。

int fork() {
  __bionic_atfork_run_prepare(); //[见小节2.1.1]

  pthread_internal_t* self = __get_thread();

  //fork期间,获取父进程pid,并使其缓存值无效
  pid_t parent_pid = self->invalidate_cached_pid();
  //系统调用【见小节2.2】
  int result = syscall(__NR_clone, FORK_FLAGS, NULL, NULL, NULL, &(self->tid));
  if (result == 0) {
    self->set_cached_pid(gettid());
    __bionic_atfork_run_child(); //fork完成执行子进程回调方法
  } else {
    self->set_cached_pid(parent_pid);
    __bionic_atfork_run_parent(); //fork完成执行父进程回调方法
  }
  return result;
}

执行子进程fork完成后的hooks

private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer, String instructionSet) {
    //调用ZygoteHooks.postForkChild()
    VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
}
public void postForkChild(int debugFlags, String instructionSet) {
    // 调用native方法
    nativePostForkChild(token, debugFlags, instructionSet);
Math.setRandomSeedInternal(System.currentTimeMillis());
}

dalvik_system_ZygoteHooks.cc
设置新进程的主线程id,重置gc性能数据,设置信号处理函数等功能。

static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags, jstring instruction_set) {
    //此处token是由nativePreFork创建的,记录着当前线程
    Thread* thread = reinterpret_cast<Thread*>(token);
    //设置新进程的主线程id
    thread->InitAfterFork();
    ..
    if (instruction_set != nullptr) {
      ScopedUtfChars isa_string(env, instruction_set);
      InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
      Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
      if (isa != kNone && isa != kRuntimeISA) {
        action = Runtime::NativeBridgeAction::kInitialize;
      }
      //Runtime 执行 fork事项
      Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
    } else {
      Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
    }
}

Runtime.cc
创建Java堆处理的线程池、设置信号处理函数

void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
  is_zygote_ = false;
  if (is_native_bridge_loaded_) {
    switch (action) {
      case NativeBridgeAction::kUnload:
        UnloadNativeBridge(); //卸载用于跨平台的桥连库
        is_native_bridge_loaded_ = false;
        break;
      case NativeBridgeAction::kInitialize:
        InitializeNativeBridge(env, isa);//初始化用于跨平台的桥连库
        break;
    }
  }
  //创建Java堆处理的线程池
  heap_->CreateThreadPool();
  //重置gc性能数据,以保证进程在创建之前的GCs不会计算到当前app上。
  heap_->ResetGcPerformanceInfo();
  if (jit_.get() == nullptr && jit_options_->UseJIT()) {
    //当flag被设置,并且还没有创建JIT时,则创建JIT
    CreateJit();
  }
  //设置信号处理函数
  StartSignalCatcher();
  //启动JDWP线程,当命令debuger的flags指定"suspend=y"时,则暂停runtime
  Dbg::StartJdwp();
}
VM_HOOKS的fork后续操作

ZygoteHooks.java
主要功能是在fork新进程后,启动Zygote的4个Daemon线程,java堆整理,引用队列,以及析构线程。

public void postForkCommon() {
    Daemons.start();
}

public static void start() {
    ReferenceQueueDaemon.INSTANCE.start();
    FinalizerDaemon.INSTANCE.start();
    FinalizerWatchdogDaemon.INSTANCE.start();
    HeapTaskDaemon.INSTANCE.start();
}
新进程创建后的初始化事项

ZygoteConnection.java

private void handleChildProc(Arguments parsedArgs,
       FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
       throws Zygote.MethodAndArgsCaller {
   // 关闭子进程的socket链接
   closeSocket();
   if (descriptors != null) {
   
   if (parsedArgs.invokeWith != null) {
       WrapperInit.execApplication(parsedArgs.invokeWith,
               parsedArgs.niceName, parsedArgs.targetSdkVersion,
               VMRuntime.getCurrentInstructionSet(),
               pipeFd, parsedArgs.remainingArgs);
   } else { // true
       // 初始化
       ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
               parsedArgs.remainingArgs, null /* classLoader */);
   }
}

RuntimeInit.java

  • commonInit,初始化时区、代理、异常捕获处理类等
  • nativeZygoteInit,启动binder相关初始化
  • applicationInit,app相关初始化,最后抛出异常回到runSelectLoop,该方法的参数m是指main()方法, argv是指ActivityThread. 根据前面的中可知,下一步进入caller.run()方法,也就是执行ActivityThread的main方法。
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
       throws ZygoteInit.MethodAndArgsCaller {
   ......
   commonInit();
   nativeZygoteInit();
   applicationInit(targetSdkVersion, argv, classLoader);
}

private static final void commonInit() {
    // 设置默认的未捕捉异常处理方法
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

    // 设置市区,中国时区为"Asia/Shanghai"
    TimezoneGetter.setInstance(new TimezoneGetter() {
        @Override
        public String getId() {
            return SystemProperties.get("persist.sys.timezone");
        }
    });
    TimeZone.setDefault(null);

    //重置log配置
    LogManager.getLogManager().reset();
    new AndroidConfig();

    // 设置默认的HTTP User-agent格式,用于 HttpURLConnection。
    String userAgent = getDefaultUserAgent();
    System.setProperty("http.agent", userAgent);

    // 设置socket的tag,用于网络流量统计
    NetworkManagementSocketTagger.install();
}

//  /frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz){
   
    gCurRuntime->onZygoteInit();
}
//  /frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit(){
    sp<ProcessState> proc = ProcessState::self();
    proc->startThreadPool(); //启动新binder线程
}


private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    ...
    //设置虚拟机的内存利用率参数值为0.75 , 设置目标sdk
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try {
        args = new Arguments(argv); //解析参数
    } catch (IllegalArgumentException ex) {
        return;
    }

    // 调用startClass的static方法 main();args.startClass为”com.android.server.SystemServer
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}  

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
   Class<?> cl = Class.forName(className, true, classLoader);
   Method m;
   try {
       m = cl.getMethod("main", new Class[] { String[].class });
   } catch (Exception ex) {
     ...
   }

   int modifiers = m.getModifiers();
   ...

   // ! 回到 ZygoteInit.main()方法中,直接进入catch语句(这样做好处是能清空栈帧,提高栈帧利用率,比较巧妙)
   throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}


最后执行ActivityThread的main方法

ActivityThread.java

public static void main(String[] args) {
    ...
    Environment.initForCurrentUser();
    ...
    Process.setArgV0("<pre-initialized>");
    //创建主线程looper
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    //attach到系统进程
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    //主线程进入循环状态
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

推荐阅读:图形系统总结

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

推荐阅读更多精彩内容