在介绍Framework相关模块的内容时,相比于把详细的流程代码贴出来,我更愿意把模块的层次结构、各个组件的关联以图形的形式呈现出来。所以按照国际惯例,直接上图,下面就开始介绍ViewrootImpl,SurfaceView(GlSurfaceView 本身继承自SurfaceView,没有太多可介绍的,所以没有画出来),TextureView。
1、ViewRootImpl
这个类是view的管理者,真正的根节点是mView(DecorView实例),这里将ViewRootImpl画出来,更能清楚显示出ui的结构和相关模块。如图中的WindowInputEventReceiver,就是负责接收InputManager上报上来的input事件。Surface是BufferQueue的producer端,渲染后的buffer通过它送到surfaceflinger去显示。IwindowSession和IWindow.Stub是和WindowManagerService打交道,一个充当binder的proxy端,另一个充当server端,这样就可以实现双向通信。除了和WindowManagerService有联系,还和很多其他模块相关联,这里就不一一画出来了,
1)input 事件上报
在InputManagerService中有两个线程,InputReaderThread负责从EventHub读取Event,经过处理后,交给InputDispatcherThread上报给上层,忽略其他Service对特殊事件的处理,可以简单的认为InputDispatcherThread将input事件给到了Activity(应用)。
InputReader从input driver读到input evnet后,会经过多个模块的处理,其中InputMapper的处理最为负责,有兴趣可以看一下源码,然后丢给QueuedInputListener去notify。
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
有些同学可能不理解mInnerListener 是什么,这个其实是InputDispatcher实例,所以InputReader读到的事件,经过各种处理和包装,到这里就丢到InputDispatcher的队列里面去了,接下来就由InputDispatcher (InputDispatcherThread线程)将事件给到应用。这里是一个跨进程的数据传输,这里用到的是socket方式,InputChannel就是对socket两端读写操作的封装。
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
...
return OK;
}
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
...
return OK;
}
封装得再好,最终还是得调用send(…)和recv(…)接口来发送和接收数据,这种方式和应用从sensorservice读数据方式是一样的,都是用到了socket,具体说来是socketpair。
ViewRootImpl的WindowInputEventReceiver收到input事件后,可能经常一系列的处理后,传给DecorView,例如touch事件
ViewRootImpl.java
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
mAttachInfo.mUnbufferedDispatchRequested = false;
final View eventTarget =
(event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
mCapturingView : mView;
mAttachInfo.mHandlingPointerEvent = true;
boolean handled = eventTarget.dispatchPointerEvent(event);
maybeUpdatePointerIcon(event);
mAttachInfo.mHandlingPointerEvent = false;
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
scheduleConsumeBatchedInputImmediately();
}
}
return handled ? FINISH_HANDLED : FORWARD;
}
View.java
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
DecorView.java
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
如果还不清楚这个流程的话,好吧,我把调用的backtrack也贴出来一下吧
java.lang.RuntimeException
at com.hxiong.camerademo.CameraDemoActivity.debug(CameraDemoActivity.java:44)
at com.hxiong.camerademo.CameraDemoActivity.dispatchTouchEvent(CameraDemoActivity.java:39)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:375)
at android.view.View.dispatchPointerEvent(View.java:10243)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4438)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4306)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3999)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4056)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6246)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6220)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6181)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6349)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:323)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
2)图中WindowState、WindowStateAnimator、SurfaceControl是WindowManagerService管理Surface的模块,前面讲过了Surface只是producer端的封装。这里只是简单将一下apk的ui是怎么绘制出来的,不考虑硬件加速的情况。
(1)通过Surface dequeue出一块可用的buffer
(2)将这块buffer关联到skia 的SkBitmap
(3)再从SkBitmap里抽象出SkCanvas
(4)然后用SkPaint先在SkCanvas上进行绘制
(5)最后真正同步绘制到SkBitmap上,buffer也就被修改了
(6)通过Surface queue出buffer,送给Surfaceflinger去显示
2、SurfaceView
SurfaceView里面最关键的同样是Surface,这个surface跟应用ui用的surface不是同一个,它的创建过程和ViewRootImpl中的surface差不多一样。通过Session.relayout(…)创建出来。一般用它来显示camera的preview或者播放的视频画面,本质上就是把surface(producer端)传给其他模块,让其他模块往这个producer端送数据。当然应用也可以自己在SurfaceView上绘制东西,例如
Surface.lockCanvas();
… //做各种各样的绘制
Surface.unlockCanvasAndPost();
其实这个过程和上面ui的绘制差不多,Surface.lockCanvas()就是去关联skia,用skia提供的接口实现不同功能的绘制,最用通过Surface.unlockCanvasAndPost()真正修改到surface buffer,然后送去surfaceflinger显示。
3、TextureView
这个怎么说好呢,它主要的作用就是把SurfaceTexture收到的数据显示在UI上,所以它一定是会和一个SurfaceTexture关联。在SurfaceTexture初始化的时候,通过BufferQueue创建了producer和consumer,而SurfaceTexture就充当了consumer端,也就是GLConsumer。它一般会将producer提供给其他模块,用于从其他模块获取数据流,然后再通知TextureView去更新,也就是是显示到UI上。
static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
jint texName, jboolean singleBufferMode, jobject weakThiz)
{
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
if (singleBufferMode) {
consumer->setMaxBufferCount(1);
}
sp<GLConsumer> surfaceTexture;
if (isDetached) {
surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES,
true, !singleBufferMode);
} else {
surfaceTexture = new GLConsumer(consumer, texName,
GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
}
if (surfaceTexture == 0) {
jniThrowException(env, OutOfResourcesException,
"Unable to create native SurfaceTexture");
return;
}
surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",
(isDetached ? 0 : texName),
getpid(),
createProcessUniqueId()));
// If the current context is protected, inform the producer.
if (isProtectedContext()) {
consumer->setConsumerUsageBits(GRALLOC_USAGE_PROTECTED);
}
SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
SurfaceTexture_setProducer(env, thiz, producer);
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
jniThrowRuntimeException(env,
"Can't find android/graphics/SurfaceTexture");
return;
}
sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
clazz));
surfaceTexture->setFrameAvailableListener(ctx);
SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
}
SurfaceTexture本身并没有提供接口给应用拿Producer送过来的数据,所有应用并没有办法直接那到数据,TextureView通过把它绑定到HardwareLayer,利用Render把数据内容绘制到UI上,当然还有很多其他关联的模块。可以向TextureView设置SurfaceTextureListener,在onSurfaceTextureUpdated()回调的时候通过getBitmap()接口拿到数据。
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
Bitmap bitmep= textureView.getBitmap();
// TODO
}
});