Activity启动过程剖析

Activity启动过程剖析

你同样可以在Github上看到这篇文章:
https://github.com/onlynight/ActivityStartPrinciple

写在前面

在看这篇文章之前你需要了解android的IPC通信机制里面的ADIL的原理,还有一些常用的设计模式比如代理模式你也需要有所了解,了解这些会让你更容易理解android源码。阅读本文的读者我都默认你是了解这些东西的,如果你正好还没没有看过这些东西,那么我想你推荐我的另外几篇文章,希望能让你快速了解android的IPC的AIDL的设计原理:

下面我们开始正片。

阅读源码的方法

Android源码数量相当多我们不能从头逐一查看所有文件中的源码,你需要理出一条线索来,你感兴趣的线索比如本文讲的Activity的启动过程分析就是从startActivity函数开始然后逐步深入去查看其中的奥妙。还有一点需要说的是看源码的时候不要太深入细节,我们想了解的代码的逻辑而不是其中如何实现的(当然这个是我看源码的主要目的,如果你的出发点是如何实现的那我们关注的重点就不一样了),梳理代码逻辑让我们能更好的了解android的工作原理,从而在遇到问题的时候不再抓虾而能精准的定位到问题的所在,希望这篇文章能够帮到你。这里同样有一篇文章推荐给你:Android源码阅读配置

需要了解的几个类

开始之前你需要对几个类有所了解知道他们的职责这样有助于理解源码:

1.Activity

An activity is a single, focused thing that the user can do. Almost all
activities interact with the user, so the Activity class takes care of
creating a window for you in which you can place your UI with
{@link #setContentView}. While activities are often presented to the user
as full-screen windows, they can also be used in other ways: as floating
windows (via a theme with {@link android.R.attr#windowIsFloating} set)
or embedded inside of another activity (using {@link ActivityGroup}).

Activity是我们日常中最常用的组件,它通常显示给用户的是一个全屏的窗口,或者一个浮动的窗口(例如音乐播放器的浮动歌词),或者嵌入其他的Activity使用ActivityGroup。它Android四大组件中唯一能和用户交互的组件,这里就不再多做解释了。

2.Instrumentation

Base class for implementing application instrumentation code. When running
with instrumentation turned on, this class will be instantiated for you
before any of the application code, allowing you to monitor all of the
interaction the system has with the application. An Instrumentation
implementation is described to the system through an AndroidManifest.xml's
instrumentation tag.

当Instrumentation打开的时候,在你的应用代码执行之前会首先实例化一个instrumentation,你可以监听所有系统应用交互。
用于执行具体操作的类,辅助Activity的监控和测试。

3.ActivityManagerNative、ActivityManagerProxy、IActivityManager、ActivityManagerService

IPC需要的类,了解过aidl的童鞋应该都不陌生。需要有一个继承IInterface的接口定义ipc的能力接口,需要有个继承Binder类的驱动类,还需要有一个远程服务的代理类Proxy代理远程服务的操作,实现Binder的类可能是个抽象类,还需要有类实例化这个Binder或者继承它实现所有抽象方法。

  1. IActivityManager就是继承了IInterface的能力接口。
  2. ActivityManagerNative继承了Binder实现了IInterface接口。
  3. ActivityManagerProxy有一个mRemote其类型是Binder,远程服务代理。
  4. ActivityManagerService继承了ActivityManagerNative并且实现了它的所有抽象方法。

类结构图如下:

类关系图

源码逻辑梳理

首先我们来看startActivity这个函数:

// Activity.java


public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
    if (mParent == null) {
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) {
            // If this start is requesting a result, we can avoid making
            // the activity visible until the result is received.  Setting
            // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
            // activity hidden during this time, to avoid flickering.
            // This can only be done when a result is requested because
            // that guarantees we will get information back when the
            // activity is finished, no matter what happens to it.
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
        // TODO Consider clearing/flushing other event sources and events for child windows.
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            // Note we want to go through this method for compatibility with
            // existing applications that may have overridden it.
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}

可以看到startActivity函数调用的还是startActivityForResult只是传入的默认requestCode为-1,这里就提醒我们requestCode需要大于等于0,否则和直接调用startActivity是一样的效果不会回调onActivityResult

startActivityForResult出现分支判断是否有mParentmParent即为ActivityGroup,实际上两个分支执行的代码是相同的只是是谁启动activity的区别,startActivityFromChild这个函数可以验证这个说法:

public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,
            int requestCode, @Nullable Bundle options) {
    Instrumentation.ActivityResult ar =
        mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, child,
            intent, requestCode, options);
    if (ar != null) {
        mMainThread.sendActivityResult(
            mToken, child.mEmbeddedID, requestCode,
            ar.getResultCode(), ar.getResultData());
    }
    cancelInputsAndStartExitTransition(options);
}

可以看到这个函数的内部实现和startActivityForResultmParent==null的分支代码基本相同只是传入的embeddedID不同,下面我们顺着主线继续往往下看,startActivityForResult中调用了Instrumention.execStartActivity方法:

//Instrumention.java

public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, String target,
    Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break;
                }
            }
        }
    }
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target, requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

这里就有一些比较复杂的代码,本着研究的心理总要把代码是如何实现的看个清楚,其实不然,你大可根据变量和方法的命名大概知道是什么作用就可以继续看代码了,例如这个mActivityMonitors我们看到它的类型是List<ActivityMonitor>,通过名字和类型我们就大概知道它是用来记录Activity的,大概分析下这里应该不是真正启动Activity的地方这里应该是请求activity返回的检测。继续往下看,这里调用了ActivityManagerNative.startActivity方法,我们继续深入:

//ActivityManagerNative.java

static public IActivityManager getDefault() {
    return gDefault.get();
}

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }

    return new ActivityManagerProxy(obj);
}


class ActivityManagerProxy implements IActivityManager
{
    private IBiner mRemote;

    public ActivityManagerProxy(IBinder remote)
    {
        mRemote = remote;
    }

    public IBinder asBinder()
    {
        return mRemote;
    }

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

    ...
}

这里看到ActivityManagerNative.getDefault中的gDefault是一个单例其中的Binder就是我们要的远程Binder了,ServiceManager.getService获取到的Binder,这里我们先放放先不看ServiceManager的内部实现,只要我们知道这个远程Binder是从这里获取到的就可以了。拿到这个Binder后通过ActivityManagerNative.asInterface方法将其强转为IActivityManager接口:

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }

    return new ActivityManagerProxy(obj);
}

如果这个Binder在本地能找到那么就直接返回,如果找不到就通过Binder创建一个远程服务的代理类。ActivityManagerProxy将传入的IBinder作为远程服务的Binder,可以看到ActivityManagerProxy.startActivity方法的本质实际上是调用了mRemote.transact方法,请求远程服务完成操作。懂AIDL的朋友都知道transactonTransact是成对出现的,onTransact才是真正的实现。那么问题来了这个onTransact实在哪里实现的呢,当然是ActivityManagerProxy.mRemote已经实现了,现在我们再倒回来找找这个mRemote是从哪里来的。

//ServiceManager.java

/**
 * Returns a reference to a service with the given name.
 * 
 * @param name the name of the service to get
 * @return a reference to the service, or <code>null</code> if the service doesn't exist
 */
public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

private static IServiceManager getIServiceManager() {
    if (sServiceManager != null) {
        return sServiceManager;
    }

    // Find the service manager
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}

看到这些熟悉的命名方式ServiceManagerIServiceManagerServiceManagerNative,那么这个ServiceManager也是AIDL实现,我们再来看下这个AIDL的远程代理从哪里来的,这里没有gDefault但是有个静态方法getIServiceManager来获取IInterface接口,继续往里深入:

//BinderInternal.java

/**
 * Return the global "context object" of the system.  This is usually
 * an implementation of IServiceManager, which you can use to find
 * other services.
 */
public static final native IBinder getContextObject();
//ServiceManagerNative.java

/**
 * Native implementation of the service manager.  Most clients will only
 * care about getDefault() and possibly asInterface().
 * @hide
 */
public abstract class ServiceManagerNative extends Binder implements IServiceManager{}

这里获取IBinder是通过native方式来实现的,这里我们就不再深入了。我们知道ServiceManager是用来获取其他service的接口那么它的实现必然跟普通的service有所不同,再回到我们之前的方法ServiceManager.getService("activity"),中通过activity参数获取到了一个Binder这个Binder必然是已经继承自Binder并且实现了IActivityManager接口的类,这样的类我们现在只能定位到ActivityManagerNative这个类,但是这个类是个抽象类它并没有实现IActivityManager中的方法,我们再全局搜索一下ActivityManagerNative这个类看有没有实例化这个类的地方或者继承这个类的分抽象类,很幸运我们找到了ActivityManagerService这个类继承了ActivityManagerNative并且实现了接口的方法。

ServiceManager中有个sCache其类型是HashMap<String, IBinder>,既然有getService那么会有相应的addService将service加入到其中:

//ServiceManager.java

private HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();

/**
 * Returns a reference to a service with the given name.
 * 
 * @param name the name of the service to get
 * @return a reference to the service, or <code>null</code> if the service doesn't exist
 */
public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}


/**
 * Returns a reference to a service with the given name.
 * 
 * @param name the name of the service to get
 * @return a reference to the service, or <code>null</code> if the service doesn't exist
 */
public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

好了我们再来看看activity这个service是怎么被添加到里面去的,在ActivityManagerService中找到了相应的代码:

// ActivityManagerService.java


public void setSystemProcess() {
    try {
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
        ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
        ServiceManager.addService("meminfo", new MemBinder(this));
        ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
        ServiceManager.addService("dbinfo", new DbBinder(this));
        if (MONITOR_CPU_USAGE) {
            ServiceManager.addService("cpuinfo", new CpuBinder(this));
        }
        ServiceManager.addService("permission", new PermissionController(this));

        ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                "android", STOCK_PM_FLAGS);
        mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

        synchronized (this) {
            ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
            app.persistent = true;
            app.pid = MY_PID;
            app.maxAdj = ProcessList.SYSTEM_ADJ;
            app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
            mProcessNames.put(app.processName, app.uid, app);
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.put(app.pid, app);
            }
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }
    } catch (PackageManager.NameNotFoundException e) {
        throw new RuntimeException(
                "Unable to find android system package", e);
    }
}

这个setSystemProcess方法在系统启动的时候会被调用,那么ActivityManagerService就被添加到ServiceManager中去了,这里可以看出ActivityManagerService是一个系统级的Service在系统启动的时候就被加载了。

找到来了ActivityManagerNative.gDefault中的源头我们再回过头来理顺Activity的启动过程,我们知道transact后的真正执行者是onTransact方法,那么我们这里的onTransact方法就是ActivityManagerService.onTransact实际就是ActivityManagerNative.onTransact

// ActivityManagerNative.java

/** {@hide} */
public abstract class ActivityManagerNative extends Binder implements IActivityManager {
    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
            case START_ACTIVITY_TRANSACTION: {
                data.enforceInterface(IActivityManager.descriptor);
                IBinder b = data.readStrongBinder();
                IApplicationThread app = ApplicationThreadNative.asInterface(b);
                String callingPackage = data.readString();
                Intent intent = Intent.CREATOR.createFromParcel(data);
                String resolvedType = data.readString();
                IBinder resultTo = data.readStrongBinder();
                String resultWho = data.readString();
                int requestCode = data.readInt();
                int startFlags = data.readInt();
                ProfilerInfo profilerInfo = data.readInt() != 0
                        ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
                Bundle options = data.readInt() != 0
                        ? Bundle.CREATOR.createFromParcel(data) : null;
                int result = startActivity(app, callingPackage, intent, resolvedType,
                        resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
                reply.writeNoException();
                reply.writeInt(result);
                return true;
            }
        }
    }
}


class ActivityManagerProxy implements IActivityManager
{
    public ActivityManagerProxy(IBinder remote)
    {
        mRemote = remote;
    }

    public IBinder asBinder()
    {
        return mRemote;
    }

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }
}

ActivityManagerNative中的mRemote.transact发送了一个START_ACTIVITY_TRANSACTION消息,接着onTransact方法真正将方法最终落地调用了startActivity方法,由于ActivityManagerNative是抽象类,那么就要查看它子类中的这个方法:

//ActivityManagerService.java

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());
}

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
    enforceNotIsolatedCaller("startActivity");
    userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
            userId, false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, bOptions, false, userId, null, null);
}

继续深入查看mActivityStarter.startActivityMayWait:

// ActivityStarter.java

/**
 * Controller for interpreting how and then launching activities.
 *
 * This class collects all the logic for determining how an intent and flags should be turned into
 * an activity and associated task and stack.
 */
class ActivityStarter {

    ...

    final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {
        
        ...
        //化繁为简,省略的这些代码就是为了给startActivityLocked构造参数

        final ActivityRecord[] outRecord = new ActivityRecord[1];
        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);

        ...
    }


    final int startActivityLocked(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,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
        ...
        try {
            mService.mWindowManager.deferSurfaceLayout();
            err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                    true, options, inTask);
        } finally {
            mService.mWindowManager.continueSurfaceLayout();
        }
        ...
    }

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
        ...
        mWindowManager.executeAppTransition();
        ...
    }
    ...
}

我们就深入到这里就好了不再深入研究代码,mWindowManager的类型是WindowManagerService也是一个aidl的实现,具体实现有兴趣的读者可以深入研究WindowManagerService的内部实现。

本文实际上就是详细讲了ActivityManagerService是如何与前端链接上的,Android中许多其他的服务例如MediaCenter等都是IPC的实现,可以根据本文的的线索和思路查看相应的源码。在梳理完相应的代码逻辑以后就可以关注内部的代码实现了,最后希望本文能够真正帮到你理解Activity的启动过程。

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

推荐阅读更多精彩内容