Android应用与SurfaceFlinger建立连接的过程

基于Android 9.0源码分析

类图

  • DecorView
    • Android窗口的顶级View
  • PhoneWindow
    • 代表Android窗口
  • WindowManagerImpl
    • 应用通过该类与系统窗口管理服务通信,关联特定的窗口
  • WindowManagerGlobal
    • 进程全局对象,实现WindowManagerImpl与系统窗口管理服务的通信
  • ViewRootImpl
    • 实现了View与窗口管理之间的协议
  • Choreographer
    • Choreographer收到显示子系统发送的Vsync信号后,协调下一帧渲染中的动画、输入和绘制过程
  • FrameDisplayEventReceiver
    • 在应用内请求、接收显示事件(Vsync信号等)
  • ISurfaceComposer
    • 定义访问SurfaceFlinger的Binder IPC接口
  • BitTube
    • Socket的封装,用于进程间通信,可跨进程传递

Android应用与SurfaceFlinger建立连接的过程

Android应用在执行完Activity的onResume()后会建立与SurfaceFlinger的连接,以便接受SurfaceFlinger发送的Vsync信号,下面从ActivityThreadhandleResumeActivity()开始分析。

public void handleResumeActivity(IBinder token, boolean finalStateRequest, booleanisForward,
        String reason) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;
    // TODO Push resumeArgs into the activity for consideration
    // 调用Activity的onResume的方法
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    if (r == null) {
        // We didn't actually resume the activity, so skipping any follow-up actions.
        return;
    }
    ......
    if (r.window == null && !a.mFinished && willBeVisible) {
        // PhoneWindow对象
        r.window = r.activity.getWindow();
        // DecorView对象
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        // wm为WindowManagerImpl对象
        ViewManager wm = a.getWindowManager();
        // 窗口布局参数
        WindowManager.LayoutParams l = r.window.getAttributes();
        // 设置Activity的DecorView
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        if (r.mPreserveWindow) {
            a.mWindowAdded = true;
            r.mPreserveWindow = false;
            // Normally the ViewRoot sets up callbacks with the Activity
            // in addView->ViewRootImpl#setView. If we are instead reusing
            // the decor view we have to notify the view root that the
            // callbacks may have changed.
            ViewRootImpl impl = decor.getViewRootImpl();
            if (impl != null) {
                impl.notifyChildRebuilt();
            }
        }
        // 通常mVisibleFromClient为true
        if (a.mVisibleFromClient) {
            // mWindowAdded这里为false
            if (!a.mWindowAdded) {
                a.mWindowAdded = true;
                // 设置DecorView的LayoutParams,添加DecorView到Window
                wm.addView(decor, l);
            } else {
                // The activity will get a callback for this {@link LayoutParams} change
                // earlier. However, at that time the decor will not be set (this is set
                // in this method), so no action will be taken. This call ensures the
                // callback occurs with the decor set.
                a.onWindowAttributesChanged(l);
            }
        }
        // If the window has already been added, but during resume
        // we started another activity, then don't yet make the
        // window visible.
    } else if (!willBeVisible) {
        if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
        r.hideForNow = true;
    }
    ......
}

下面看WindowManagerImpladdView()的实现

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    // 设置params的token
    applyDefaultToken(params);
    // 调用WindowManagerGlobal的addView
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    // view为DecorView
    // params为DecorView关联的LayoutParams
    // parentWindow为PhoneWindow
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (display == null) {
        throw new IllegalArgumentException("display must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if (parentWindow != null) {
        // 设置LayoutParams的token、Title和包名等
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } else {
        // If there's no parent, then hardware acceleration for this view is
        // set from the application's hardware acceleration setting.
        final Context context = view.getContext();
        if (context != null
                && (context.getApplicationInfo().flags
                        & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
            wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }
    synchronized (mLock) {
        // Start watching for system property changes.
        // 监听系统属性的改变,观察者模式
        if (mSystemPropertyUpdater == null) {
            mSystemPropertyUpdater = new Runnable() {
                @Override public void run() {
                    synchronized (mLock) {
                        for (int i = mRoots.size() - 1; i >= 0; --i) {
                            mRoots.get(i).loadSystemProperties();
                        }
                    }
                }
            };
            SystemProperties.addChangeCallback(mSystemPropertyUpdater);
        }
        // 查找DecorView
        int index = findViewLocked(view, false);
        if (index >= 0) {
            if (mDyingViews.contains(view)) {
                // Don't wait for MSG_DIE to make it's way through root's queue.
                mRoots.get(index).doDie();
            } else {
                throw new IllegalStateException("View " + view
                        + " has already been added to the window manager.");
            }
            // The previous removeView() had not completed executing. Now it has.
        }
        // If this is a panel window, then find the window it is being
        // attached to for future reference.
        if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
            final int count = mViews.size();
            for (int i = 0; i < count; i++) {
                if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                    panelParentView = mViews.get(i);
                }
            }
        }
        // 创建ViewRootImpl
        root = new ViewRootImpl(view.getContext(), display);
        // 设置View布局参数
        view.setLayoutParams(wparams);
        // DecorView/ViewRootImpl/LayoutParams添加到WindowManagerGlobal
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
        // do this last because it fires off messages to start doing things
        try {
            // 调用ViewRootImpl的setView()
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throw e;
        }
    }
}

ViewRootImpl的构造方法中建立与SurfaceFlinger的连接,下面看ViewRootImpl的构造方法

public ViewRootImpl(Context context, Display display) {
    mContext = context;
    // mWindowSession为IWindowSession.Stub.Proxy对象,单例模式
    mWindowSession = WindowManagerGlobal.getWindowSession();
    mDisplay = display;
    mBasePackageName = context.getBasePackageName();
    mThread = Thread.currentThread();
    mLocation = new WindowLeaked(null);
    mLocation.fillInStackTrace();
    mWidth = -1;
    mHeight = -1;
    mDirty = new Rect();
    mTempRect = new Rect();
    mVisRect = new Rect();
    mWinFrame = new Rect();
    // 创建W对象,Binder服务对象
    // 用于接收WindowManager发送的应用窗口感兴趣的事件
    mWindow = new W(this);
    mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    mViewVisibility = View.GONE;
    mTransparentRegion = new Region();
    mPreviousTransparentRegion = new Region();
    mFirst = true; // true for the first time the view is added
    mAdded = false;
    // 创建View.AttachInfo记录添加到窗口的View的信息
    mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
            context);
    mAccessibilityManager = AccessibilityManager.getInstance(context);
    mAccessibilityManager.addAccessibilityStateChangeListener(
            mAccessibilityInteractionConnectionManager, mHandler);
    mHighContrastTextManager = new HighContrastTextManager();
    mAccessibilityManager.addHighTextContrastStateChangeListener(
            mHighContrastTextManager, mHandler);
    mViewConfiguration = ViewConfiguration.get(context);
    mDensity = context.getResources().getDisplayMetrics().densityDpi;
    mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
    mFallbackEventHandler = new PhoneFallbackEventHandler(context);
    // 获取Choreographer对象,在Choreographer构造函数中建立与SurfaceFlinger的连接
    mChoreographer = Choreographer.getInstance();
    mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    if (!sCompatibilityDone) {
        sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
        sCompatibilityDone = true;
    }
    loadSystemProperties();
}

下面看ChoreographergetInstance()的实现

// Choreographer为ThreadLocal对象,关联的线程必须有looper
public static Choreographer getInstance() {
    // 调用initialValue()创建Choreographer
    return sThreadInstance.get();
}

private static final ThreadLocal<Choreographer> sThreadInstance =
        new ThreadLocal<Choreographer>() {
    @Override
    protected Choreographer initialValue() {
        Looper looper = Looper.myLooper();
        if (looper == null) {
            throw new IllegalStateException("The current thread must have a looper!");
        }
        Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
        if (looper == Looper.getMainLooper()) {
            mMainInstance = choreographer;
        }
        return choreographer;
    }
};

private Choreographer(Looper looper, int vsyncSource) {
    mLooper = looper;
    mHandler = new FrameHandler(looper);
    // 创建FrameDisplayEventReceiver,用于接收SurfaceFlinger发给应用的Vsync信号
    mDisplayEventReceiver = USE_VSYNC
            ? new FrameDisplayEventReceiver(looper, vsyncSource)
            : null;
    mLastFrameTimeNanos = Long.MIN_VALUE;
    mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
    // 创建CallbackQueue
    mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
    for (int i = 0; i <= CALLBACK_LAST; i++) {
        mCallbackQueues[i] = new CallbackQueue();
    }
    // b/68769804: For low FPS experiments.
    setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
}

mCallbackQueues是一个CallbackQueue数组,包含四个链表

  • CALLBACK_INPUT
    • 输入回调,当接收到Vsync信号时首先运行,如处理Move事件
  • CALLBACK_ANIMATION
    • 动画回调,在TRAVERSAL之前运行
  • CALLBACK_TRAVERSAL
    • TRAVERSAL回调,执行Measure/Layout/Draw
  • CALLBACK_COMMIT
    • COMMIT回调,处理帧绘制完成后的操作,如应用整理内存等

FrameDisplayEventReceiver继承自DisplayEventReceiver,下面分析它构造方法

public DisplayEventReceiver(Looper looper, int vsyncSource) {
    if (looper == null) {
        throw new IllegalArgumentException("looper must not be null");
    }
    // Looper关联的MessageQueue
    mMessageQueue = looper.getQueue();
    // Native层的DisplayEventReceiver初始化
    mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
            vsyncSource);
    // CloseGuard用于当DisplayEventReceiver被回收时,释放资源
    mCloseGuard.open("dispose");
}

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj, jint vsyncSource) {
    // 所在线程的MessageQueue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }
    // 创建NativeDisplayEventReceiver,与SurfaceFlinger建立连接
    // 获取显示事件socket接收端
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue, vsyncSource);
    // 监听显示事件socket接收端
    status_t status = receiver->initialize();
    if (status) {
        String8 message;
        message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return 0;
    }

    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}

下面看NativeDisplayEventReceiver的构造方法

NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
        jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource) :
        // 创建DisplayEventDispatcher
        DisplayEventDispatcher(messageQueue->getLooper(),
                static_cast<ISurfaceComposer::VsyncSource>(vsyncSource)),
        // Java层DisplayEventReceiver弱引用的JNI全局引用保存在mReceiverWeakGlobal中
        // 用于后续向Java层DisplayEventReceiver传递显示事件(Vsync/Hotplug)
        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
        mMessageQueue(messageQueue) {
    ALOGV("receiver %p ~ Initializing display event receiver.", this);
}

// 成员子对象mReceiver为DisplayEventReceiver对象
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
        ISurfaceComposer::VsyncSource vsyncSource) :
        mLooper(looper), mReceiver(vsyncSource), mWaitingForVsync(false) {
    ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}

DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
    // sf是BpSurfaceComposer对象的强指针(对象)
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != NULL) {
        // mEventConnection为BpDisplayEventConnection的强指针
        // 为客户端创建显示事件连接,通过该连接可以请求SurfaceFlinger发送Vsync以及接收
        // SurfaceFlinger发送的显示事件
        mEventConnection = sf->createDisplayEventConnection(vsyncSource);
        if (mEventConnection != NULL) {
            // 创建BitTube
            mDataChannel = std::make_unique<gui::BitTube>();
            // 通过Binder IPC获取对应的Connection的socket接收端
            mEventConnection->stealReceiveChannel(mDataChannel.get());
        }
    }
}

createDisplayEventConnection()是一个Binder IPC,它的实现在ISurfaceComposer中。

virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSourcevsyncSource)
{
    Parcel data, reply;
    sp<IDisplayEventConnection> result;
    // 接口描述字符串写入Parcel中
    int err = data.writeInterfaceToken(
            ISurfaceComposer::getInterfaceDescriptor());
    if (err != NO_ERROR) {
        return result;
    }
    // vsyncSource写入Parcel中
    data.writeInt32(static_cast<int32_t>(vsyncSource));
    // 请求SurfaceFlinger处理CREATE_DISPLAY_EVENT_CONNECTION
    err = remote()->transact(
            BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
            data, &reply);
    if (err != NO_ERROR) {
        ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing "
                "transaction: %s (%d)", strerror(-err), -err);
        return result;
    }
    // 在应用端reply.readStrongBinder()返回BpBinder的强指针
    // interface_case是模板方法
    // result为BpDisplayEventConnection的强指针
    result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
    return result;
}

下面看SurfaceFlinger处理CREATE_DISPLAY_EVENT_CONNECTION请求。

status_t BnSurfaceComposer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        ......
        case CREATE_DISPLAY_EVENT_CONNECTION: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            // 为客户端创建连接
            sp<IDisplayEventConnection> connection(createDisplayEventConnection(
                    static_cast<ISurfaceComposer::VsyncSource>(data.readInt32())));
            // connection写入reply Parcel中
            reply->writeStrongBinder(IInterface::asBinder(connection));
            return NO_ERROR;
        }
        ......
    }
}

sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
        ISurfaceComposer::VsyncSource vsyncSource) {
    if (vsyncSource == eVsyncSourceSurfaceFlinger) {
        return mSFEventThread->createEventConnection();
    } else {
        // 调用EventThread的createEventConnection()
        return mEventThread->createEventConnection();
    }
}

sp<BnDisplayEventConnection> EventThread::createEventConnection() const {
    // 创建Connection
    return new Connection(const_cast<EventThread*>(this));
}

Connection是一个Binder服务类,继承自BnDisplayEventConnection,它的作用

  • 处理客户端应用的Vsync请求
  • 向客户端应用发送显示事件(Vsync/Hotplug)

下面看Connection的构造方法

EventThread::Connection::Connection(EventThread* eventThread)
      // 创建BitTube
      : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}

BitTube::BitTube(size_t bufsize) {
    // 创建socket pair,用于发送显示事件
    init(bufsize, bufsize);
}

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
        // 设置socket buffer
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
        // since we don't use the "return channel", we keep it small...
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
        // socket[0]用于接收端,最终通过Binder IPC返回给客户端应用
        mReceiveFd.reset(sockets[0]);
        // socket[1]用于发送端
        mSendFd.reset(sockets[1]);
    } else {
        mReceiveFd.reset();
        ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
    }
}

BitTube的作用主要有

  • 封装用于显示事件的socket通信
  • 跨进程传递socket文件描述符

回到createEventConnection()方法中,由于返回Connection的强指针,在sp的构造函数中会增加强引用计数从而调用ConnectiononFirstRef()方法。

void EventThread::Connection::onFirstRef() {
    // NOTE: mEventThread doesn't hold a strong reference on us
    // 向EventThread注册连接
    mEventThread->registerDisplayEventConnection(this);
}

status_t EventThread::registerDisplayEventConnection(
        const sp<EventThread::Connection>& connection) {
    std::lock_guard<std::mutex> lock(mMutex);
    // Connection添加到mDisplayEventConnections中
    mDisplayEventConnections.add(connection);
    mCondition.notify_all();
    return NO_ERROR;
}

ConnectionEventThread采用观察者模式,当有显示事件发生时,EventThreadConnection传递事件。至此,createDisplayEventConnection()的实现就分析完了,下面看stealReceiveChannel()的实现

status_t stealReceiveChannel(gui::BitTube* outChannel) override {
    // callRemote是一个模板方法,用于实现同步Binder IPC
    return callRemote<decltype(
            &IDisplayEventConnection::stealReceiveChannel)>(Tag::STEAL_RECEIVE_CHANNEL,
                                                            outChannel);
}

下面看Connection处理STEAL_RECEIVE_CHANNEL请求

status_t BnDisplayEventConnection::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                              uint32_t flags) {
    if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
        return BBinder::onTransact(code, data, reply, flags);
    }
    auto tag = static_cast<Tag>(code);
    switch (tag) {
        case Tag::STEAL_RECEIVE_CHANNEL:
            // 调用stealReceiveChannel处理请求
            // 最终通过BitTube(outChannel)的writeToParcel将socket接收端文件描述符写入reply
            return callLocal(data, reply, &IDisplayEventConnection::stealReceiveChannel);
        ......
    }
}

status_t EventThread::Connection::stealReceiveChannel(gui::BitTube* outChannel) {
    // 设置socket接收端文件描述符
    outChannel->setReceiveFd(mChannel.moveReceiveFd());
    return NO_ERROR;
}

最终,客户端应用通过BitTubereadFromParcel()获取来自SurfaceFlinger的socket文件描述符。这样客户端就可以接收SurfaceFlinger发送的显示事件了。回到nativeInit()中,继续看监听socket接收端文件描述符的过程。

status_t DisplayEventDispatcher::initialize() {
    status_t result = mReceiver.initCheck();
    if (result) {
        ALOGW("Failed to initialize display event receiver, status=%d", result);
        return result;
    }
    // Looper监听socket文件描述符
    int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
            this, NULL);
    if (rc < 0) {
        return UNKNOWN_ERROR;
    }
    return OK;
}

DisplayEventDispatcher继承自LooperCallback,当有显示事件到来时,Looper关联的线程将调用DisplayEventDispatcherhandleEvent()处理事件。这样Android应用与SurfaceFlinger就建立了连接,可以接收SurfaceFlinger发送的显示事件了。

为了后续分析,下面继续分析ViewRootImplsetView()

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView {
    synchronized (this) {
        if (mView == null) {
            mView = view;
            mAttachInfo.mDisplayState = mDisplay.getState();
            mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
            mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
            mFallbackEventHandler.setView(view);
            mWindowAttributes.copyFrom(attrs);
            if (mWindowAttributes.packageName == null) {
                mWindowAttributes.packageName = mBasePackageName;
            }
            attrs = mWindowAttributes;
            setTag();
            ......
            // If the application owns the surface, don't enable hardware acceleration
            // 如果应用有自己的Surface,不使能硬件加速
            if (mSurfaceHolder == null) {
                // While this is supposed to enable only, it can effectively disable
                // the acceleration too.
                // 使能硬件加速,也可以禁止
                enableHardwareAcceleration(attrs);
                final boolean useMTRenderer = MT_RENDERER_AVAILABLE
                        && mAttachInfo.mThreadedRenderer != null;
                if (mUseMTRenderer != useMTRenderer) {
                    // Shouldn't be resizing, as it's done only in window setup,
                    // but end just in case.
                    endDragResizing();
                    mUseMTRenderer = useMTRenderer;
                }
            }
            ......
            // Schedule the first layout -before- adding to the window
            // manager, to make sure we do the relayout before receiving
            // any other events from the system.
            // 调度首次layout, 请求SurfaceFlinger发送Vsync
            requestLayout();
            ......
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
                // 窗口注册到WindowManagerService
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
            } catch (RemoteException e) {
                mAdded = false;
                mView = null;
                mAttachInfo.mRootView = null;
                mInputChannel = null;
                mFallbackEventHandler.setView(null);
                unscheduleTraversals();
                setAccessibilityFocus(null, null);
                throw new RuntimeException("Adding window failed", e);
            } finally {
                if (restore) {
                    attrs.restore();
                }
            }
            ......
        }
    }
}                                

下面重点分析上述方法中的以下三个过程

  • 使能硬件加速的过程
  • 调度首次layout的过程
  • 窗口注册到WindowManagerService的过程

使能硬件加速的过程

下面从enableHardwareAcceleration()开始分析。

private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
    mAttachInfo.mHardwareAccelerated = false;
    mAttachInfo.mHardwareAccelerationRequested = false;
    // Don't enable hardware acceleration when the application is in compatibility mode
    if (mTranslator != null) return;
    // Try to enable hardware acceleration if requested
    // 默认hardwareAccelerated为true
    // 在低端设备上,Persistent进程(包括system进程)不应该使用hardwareAccelerated,因为hardwareAccelerated消耗更多的资源,比如内存
    final boolean hardwareAccelerated =
            (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
    if (hardwareAccelerated) {
        if (!ThreadedRenderer.isAvailable()) {
            return;
        }
        ......
        // 对于startingWindow,设置窗口的FLAG_HARDWARE_ACCELERATED及PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED使得绘制与应用窗口绘制相似(并非真正的hardwareAccelerated)
        final boolean fakeHwAccelerated = (attrs.privateFlags &
                WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
        // 用于在system进程中,某些UI绘制强制使用hardwareAccelerated
        final boolean forceHwAccelerated = (attrs.privateFlags &
                WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
        if (fakeHwAccelerated) {
            // This is exclusively for the preview windows the window manager
            // shows for launching applications, so they will look more like
            // the app being launched.
            mAttachInfo.mHardwareAccelerationRequested = true;
        } else if (!ThreadedRenderer.sRendererDisabled
                || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
            // 使能硬件加速
            if (mAttachInfo.mThreadedRenderer != null) {
                mAttachInfo.mThreadedRenderer.destroy();
            }
            final Rect insets = attrs.surfaceInsets;
            final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
                    || insets.top != 0 || insets.bottom != 0;
            // 是否透明
            final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
            final boolean wideGamut =
                    mContext.getResources().getConfiguration().isScreenWideColorGamut()
                    && attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
            // 创建ThreadedRenderer
            mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
                    attrs.getTitle().toString());
            mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
            if (mAttachInfo.mThreadedRenderer != null) {
                mAttachInfo.mHardwareAccelerated =
                        mAttachInfo.mHardwareAccelerationRequested = true;
            }
        }
    }
}
  • ThreaderedRenderer用于将渲染工作委托给RenderThread

下面看ThreaderedRenderercreate()方法

public static ThreadedRenderer create(Context context, boolean translucent, Stringname) {
    ThreadedRenderer renderer = null;
    if (isAvailable()) {
        // 检查是否支持Threaded rendering
        // 旧版本的模拟器可能不支持
        renderer = new ThreadedRenderer(context, translucent, name);
    }
    return renderer;
}

ThreadedRenderer(Context context, boolean translucent, String name) {
    final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
    mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
    mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
    mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
    mAmbientShadowAlpha =
            (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
    mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
    a.recycle();
    // 创建Native RootRenderNode对象,rootNodePtr为对象的地址
    long rootNodePtr = nCreateRootRenderNode();
    // 产生一个Java RenderNode关联Native RenderNode
    mRootNode = RenderNode.adopt(rootNodePtr);
    mRootNode.setClipToBounds(false);
    mIsOpaque = !translucent;
    // 创建RenderProxy及RenderThread
    mNativeProxy = nCreateProxy(translucent, rootNodePtr);
    nSetName(mNativeProxy, name);
    // 1) 设置RenderThread的调度信息
    // 2) 请求系统GraphicsStatsService创建匿名共享内存,用于存储应用渲染信息(dumpsys gfxinfo)
    ProcessInitializer.sInstance.init(context, mNativeProxy);
    // 加载渲染所需的系统属性
    loadSystemProperties();
}
  • RenderNode
    • 存储记录的画布命令,以及View/ViewGroup的显示属性
  • RenderProxy
    • 创建以及管理RenderThread中的CanvasContext
  • RenderThread
    • 真正的渲染线程
      下面首先看RootRenderNode的创建,然后分析RenderProxy及RenderThread。
static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
    // 创建RootRenderNode
    RootRenderNode* node = new RootRenderNode(env);
    node->incStrong(0);
    node->setName("RootRenderNode");
    return reinterpret_cast<jlong>(node);
}

explicit RootRenderNode(JNIEnv* env) : RenderNode() {
    // 获取调用线程关联的Looper
    mLooper = Looper::getForThread();
    LOG_ALWAYS_FATAL_IF(!mLooper.get(),
            "Must create RootRenderNode on a thread with a looper!");
    // 返回JavaVM
    env->GetJavaVM(&mVm);
}

这里只是简单的创建RootRenderNode,下面看RenderProxy及RenderThread的创建。

static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
        jboolean translucent, jlong rootRenderNodePtr) {
    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
    // 创建ContextFactoryImpl
    ContextFactoryImpl factory(rootRenderNode);
    // 创建RenderProxy
    return (jlong) new RenderProxy(translucent, rootRenderNode, &factory);
}

RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
                         IContextFactory* contextFactory)
        // 创建启动RenderThread线程
        : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
    // 匿名函数创建CanvasContext
    mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
        return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
    });
    设置DrawFrameTask关联的RenderThread、CanvasContext、RootRenderNode
    mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
}

RenderThread& RenderThread::getInstance() {
    // This is a pointer because otherwise __cxa_finalize
    // will try to delete it like a Good Citizen but that causes us to crash
    // because we don't want to delete the RenderThread normally.
    static RenderThread* sInstance = new RenderThread();
    gHasRenderThreadInstance = true;
    return *sInstance;
}

RenderThread::RenderThread()
        : ThreadBase()
        , mVsyncSource(nullptr)
        , mVsyncRequested(false)
        , mFrameCallbackTaskPending(false)
        , mRenderState(nullptr)
        , mEglManager(nullptr)
        , mVkManager(nullptr) {
    Properties::load();
    // 启动线程,最终执行RenderThread的threadLoop方法
    start("RenderThread");
}

bool RenderThread::threadLoop() {
    // 设置RenderThread的优先级
    setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
    if (gOnStartHook) {
        gOnStartHook();
    }
    // 与SurfaceFlinger建立连接
    // 设置EglManager、RenderState、VulkanManager等
    initThreadLocals();

    while (true) {
        // 等待工作
        waitForWork();
        // 处理工作项
        processQueue();

        if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
            drainDisplayEventQueue();
            mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
                                   mPendingRegistrationFrameCallbacks.end());
            mPendingRegistrationFrameCallbacks.clear();
            requestVsync();
        }

        if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
            // TODO: Clean this up. This is working around an issue where a combination
            // of bad timing and slow drawing can result in dropping a stale vsync
            // on the floor (correct!) but fails to schedule to listen for the
            // next vsync (oops), so none of the callbacks are run.
            requestVsync();
        }
    }

    return false;
}

RenderThread启动后,RenderProxy向RenderThread发送创建CanvasContext的同步请求。下面看CanvasContext的创建。

CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
                                     RenderNode* rootRenderNode, IContextFactory* contextFactory) {
    // 获取RenderPipeline类型,默认是SkiaGL
    auto renderType = Properties::getRenderPipelineType();

    switch (renderType) {
        case RenderPipelineType::OpenGL:
            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
                                     std::make_unique<OpenGLPipeline>(thread));
        case RenderPipelineType::SkiaGL:
            // 根据renderType创建CanvasContext
            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
                                     std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
        case RenderPipelineType::SkiaVulkan:
            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
                                     std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
        default:
            LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
            break;
    }
    return nullptr;
}

调度首次layout的过程

下面从requestLayout()开始分析。

public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        // 向Looper关联的消息队列中投递SyncBarrier
        // 下一次执行performTraversal时移除SyncBarrier
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // 添加CALLBACK_TRAVERSAL回调,当下一帧(Vsync)到来时执行绘制
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        // 通知ThreadedRenderer下一帧很快到来
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

关于synchronization barrier(target为null的特殊消息), 一般的,消息队列中的消息为同步消息,按照时间先后进行处理。当synchronization barrier进入消息队列中,队列中的同步消息被挂起(异步消息可以处理),直到synchronization barrier从消息队列中移除。尽管postAtFrontOfQueue()可以使同步消息不被挂起,请不要滥用。

下面看ChoreographerpostCallback()的实现。

public void postCallback(int callbackType, Runnable action, Object token) {
    postCallbackDelayed(callbackType, action, token, 0);
}

public void postCallbackDelayed(int callbackType,
        Runnable action, Object token, long delayMillis) {
    ......
    postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}

private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {
    ......
    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        // 添加到CALLBACK_TRAVERSAL类型的CallbackQueue中
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
        if (dueTime <= now) {
            // 请求Vsync信号
            scheduleFrameLocked(now);
        } else {
            ......
        }
    }
}

下面看scheduleFrameLocked()的实现

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        if (USE_VSYNC) {
            if (DEBUG_FRAMES) {
                Log.d(TAG, "Scheduling next frame on vsync.");
            }
            // If running on the Looper thread, then schedule the vsync immediately,
            // otherwise post a message to schedule the vsync from the UI thread
            // as soon as possible.
            if (isRunningOnLooperThreadLocked()) {
                // 立即请求Vsync
                scheduleVsyncLocked();
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {
            ......
        }
    }
}

private void scheduleVsyncLocked() {
    // 调用FrameDisplayEventReceiver的scheduleVsync()
    mDisplayEventReceiver.scheduleVsync();
}

public void scheduleVsync() {
    if (mReceiverPtr == 0) {
        Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                + "receiver has already been disposed.");
    } else {
        // 当下一帧到来时请求SurfaceFlinger发送Vsync
        nativeScheduleVsync(mReceiverPtr);
    }
}

static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
    sp<NativeDisplayEventReceiver> receiver =
            reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
    // 调用NativeDisplayEventReceiver的scheduleVsync()
    status_t status = receiver->scheduleVsync();
    ......
}

NativeDisplayEventReceiver继承自DisplayEventDispatcher,下面scheduleVsync()的实现

status_t DisplayEventDispatcher::scheduleVsync() {
    if (!mWaitingForVsync) {
        ALOGV("dispatcher %p ~ Scheduling vsync.", this);

        // Drain all pending events.
        nsecs_t vsyncTimestamp;
        int32_t vsyncDisplayId;
        uint32_t vsyncCount;
        // 如果有待处理的事件(Vsync/Hotplug),丢弃
        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
            ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
                    this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
        }
        // 调用DisplayEventReceiver的requestNextVsync(),请求SurfaceFlinger发送Vsync
        status_t status = mReceiver.requestNextVsync();
        if (status) {
            ALOGW("Failed to request next vsync, status=%d", status);
            return status;
        }

        mWaitingForVsync = true;
    }
    return OK;
}

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != NULL) {
        // mEventConnection是BpDisplayEventConnection的强指针
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return NO_INIT;
}

requestNextVsync()是一个异步Binder IPC,它的实现在IDisplayEventConnection中,下面直接看Binder服务端Connection处理REQUEST_NEXT_VSYNC请求。

void EventThread::Connection::requestNextVsync() {
    // 调用EventThread的requestNextVsync处理客户端Vsync请求
    mEventThread->requestNextVsync(this);
}

void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) {
    std::lock_guard<std::mutex> lock(mMutex);

    ......
    // 修改连接状态
    if (connection->count < 0) {
        connection->count = 0;
        mCondition.notify_all();
    }
}

客户端请求Vsync的过程相对简单,主要是修改Connection的状态。当EventThread收到Vsync时,根据Connection的状态决定是否向Connection发送Vsync。

使用dumpsys SurfaceFlinger命令可以查看所有Connection的状态
****chn:/ $ dumpsys SurfaceFlinger
......
VSYNC state: enabled
  soft-vsync: disabled
  numListeners=43,
  events-delivered: 11406
    0x7b3a052300: count=-1
    0x7b3a052360: count=-1
    0x7b3a0523c0: count=-1
    0x7b3a052420: count=-1
    0x7b3a0524e0: count=-1
    0x7b3a052960: count=-1
    0x7b3a0529c0: count=-1
    ......
    0x7b3abfe200: count=1
    ......

其中,numListeners表示连接数量,count的值表示状态
  • count >= 1
    • 连续的Vsync请求
  • count = 0
    • 单次Vsync请求(还没有收到Vsync)
  • count = -1
    • 单次Vsync请求(已经收到Vsync)或者不请求Vsync

窗口注册到WindowManagerService的过程

下面从addToDisplay()开始分析,addToDisplay()是一个Binder IPC,对应的服务端的实现在Session中。

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
        Rect outStableInsets, Rect outOutsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    // 调用WindowManagerService的addWindow
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
            outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}

public int addWindow(Session session, IWindow client, int seq,
        LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
        Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
        DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
    // client为IWindow.Stub.Proxy对象
    ......
    boolean reportNewConfig = false;
    WindowState parentWindow = null;
    long origId;
    final int callingUid = Binder.getCallingUid();
    final int type = attrs.type; 
    synchronized(mWindowMap) {
        if (!mDisplayReady) {
            throw new IllegalStateException("Display has not been initialialized");
        }
        // DisplayContent用于记录特定屏幕的WindowStates以及相关的内容
        final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
        ......
        // 检查应用是否有权限向特定屏幕添加窗口
        if (!displayContent.hasAccess(session.mUid)
                && !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) {
            Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
                    + "does not have access: " + displayId + ".  Aborting.");
            return WindowManagerGlobal.ADD_INVALID_DISPLAY;
        }
        ......
        // 检查窗口是否已经添加
        // mWindowMap为IWindow IBinder(BinderProxy)到WindowState的映射
        if (mWindowMap.containsKey(client.asBinder())) {
            Slog.w(TAG_WM, "Window " + client + " is already added");
            return WindowManagerGlobal.ADD_DUPLICATE_ADD;
        }
        ......
        AppWindowToken atoken = null;
        final boolean hasParent = parentWindow != null;
        // Use existing parent window token for child windows since they go in the same token
        // as there parent window so we can apply the same policy on them.
        // 对于Activity窗口,根据token(IApplicationToken.Stub)查找对应的AppWindowToken
        // AppWindowToken是在之前Activity启动时创建
        WindowToken token = displayContent.getWindowToken(
                hasParent ? parentWindow.mAttrs.token : attrs.token);
        // If this is a child window, we want to apply the same type checking rules as the
        // parent window type.
        final int rootType = hasParent ? parentWindow.mAttrs.type : type;
        boolean addToastWindowRequiresToken = false;
        ......
        // 创建WindowState用于描述一个窗口
        final WindowState win = new WindowState(this, session, client, token, parentWindow,
                appOp[0], seq, attrs, viewVisibility, session.mUid,
                session.mCanAddInternalSystemWindow);
        ......
        // 根据窗口类型调整布局参数
        mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
        win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
        // 窗口添加到系统前的检查
        res = mPolicy.prepareAddWindowLw(win, attrs);
        ......
        // 创建SurfaceSession,添加Session到WindowManagerService
        win.attach();
        // WindowState添加到mWindowMap
        mWindowMap.put(client.asBinder(), win);
        win.initAppOpsState(); 
        ......
        // 窗口WindowState添加到系统
        win.mToken.addWindow(win); 
        ......
        // 这里WindowState的Parent为AppWindowToken
        win.getParent().assignChildLayers();
    }                               
}

下面重点分析WindowStateattach()方法

void attach() {
    if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
    // 调用Session的windowAddedLocked
    mSession.windowAddedLocked(mAttrs.packageName);
}

void windowAddedLocked(String packageName) {
    mPackageName = packageName;
    mRelayoutTag = "relayoutWindow: " + mPackageName;
    if (mSurfaceSession == null) {
        if (WindowManagerService.localLOGV) Slog.v(
            TAG_WM, "First window added to " + this + ", creating SurfaceSession");
        // SurfaceSession代表一个到SurfaceFlinger的连接
        // 可以有一个或多个参与合成的Surface
        mSurfaceSession = new SurfaceSession();
        if (SHOW_TRANSACTIONS) Slog.i(
                TAG_WM, "  NEW SURFACE SESSION " + mSurfaceSession);
        // Session添加到WindowManagerService的mSessions中
        mService.mSessions.add(this);
        if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
            mService.dispatchNewAnimatorScaleLocked(this);
        }
    }
    mNumWindow++;
}

下面看SurfaceSession的构造方法。

public SurfaceSession() {
    mNativeClient = nativeCreate();
}

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    // 创建SurfaceComposerClient
    SurfaceComposerClient* client = new SurfaceComposerClient();
    // SurfaceComposerClient继承自RefBase,增加强引用计数,会调用onFirstRef
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(client);
}

void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != 0 && mStatus == NO_INIT) {
        // 这里rootProducer为nullptr
        auto rootProducer = mParent.promote();
        sp<ISurfaceComposerClient> conn;
        // 请求SurfaceFlinger为客户端创建连接
        // conn为BpSurfaceComposerClient对象的智能指针
        conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
                sf->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

createConnection()是一个Binder IPC,下面直接看SurfaceFlinger处理CREATE_CONNECTION请求。

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    return initClient(new Client(this));
}

Client为参与合成的客户端在SurfaceFlinger侧的代表,是一个Binder服务对象,通过Binder IPC传递后,在客户端得到BpSurfaceComposerClient对象。

小结

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