Activity的显示过程主要经历了Activity的Launch和Resume过程,下面针对其显示过程中的一些重要步骤进行分析。
1. ActivityThread - performLaunchActivity
- 创建PhoneWindow
- 创建WindowManager
- setContentView
activity = mInstrumentation.newActivity(...);
activity.attach(...);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setWindowManager(...);
wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowManager = new LocalWindowManager(wm); // PhoneWindow的WindowManager是一个LocalWindowManager里面包含一个WindowManagerImpl
mWindowManager = mWindow.getWindowManager(); // activity也保存一份LocalWindowManager
mInstrumentation.callActivityOnCreate(activity, r.state);
activity.performCreate(state);
onCreate(state);
setContentView(view);
getWindow().setContentView(view);
setContentView(view, params);
installDecro();
mContentParent.addView(view, params); // mContentParent即android.R.id.content
2. ActivityThread - handleResumeActivity
- 创建ViewRoot并获取WindowSession和W类
- 调用WindowSession.add -> WMS.addWindow,并将W类传给WMS(RPC,SYNC)
- 调用ViewRoot的requestLayout(ASYNC)
wm = a.getWindowManager(); // 获取activity的LocalWindowManager
wm.addView(decor, l);
mWindowManager.addView(view, params); // 这里才是WindowManagerImpl
root = new ViewRoot(view.getContext);
getWindowSession
// 将IBinder装进一个IWindowManager.Proxy,Proxy也是一个IWindowManager
sWindowSession = IWindowManager.Stub.asInterface(ServiceManager.getService("window")).openSession(...);
mWindow = new W(this, context); // W是在这时创建的
root.setView(view, wparams, panelParentView);
mView = view; // 保存PhoneWindow中的DecorView
requestLayout(); // 最终异步调用到ViewRoot#performTraversals
res = sWindowSession.add(mWindow, ...); // 远程调用WMS的addWindow
对于ViewRoot的理解:
按照平时写布局的直观感觉,认为一个View树的根节点应该是一个ViewGroup,而实现上却是一个ViewRoot,那么这是为什么呢,这个就要看其实现的接口ViewParent的意义了。 ViewParent意为一个View的父节点,那么一个View的父节点理应是ViewGroup啊,其实不然,ViewGroup是一个ViewParent没错,而它本身也是一个View,那么ViewGroup的作用就是要把自己显示出来,并且把自己的子View也显示出来 而ViewRoot只是一个ViewParent,其自身并不是一个View,那么他就负责把子View显示出来,而把忙着要显示自己的精力留出来,处理一些与显示相关的更重要的事情,比如与WMS打交道 这就犹如一个程序员要写代码,项目组长要管理程序员,同时自己也要写代码,而技术总监管理项目组长,自己却不用写代码,把写代码的精力空出来去处理一些更重要的工作
经过上面的步骤,已经为Activity添加了window,并调用requestLayout,进行了显示,接下来就进一步分析Sessionr的添加window和ViewRoot的requelstLayout的过程。
2.1 Session - add
- 创建WindowState来表示一个Window
- 创建SurfaceSession与SurfaceFlinger建立连接
- 将应用端的Binder(即W类)传给WMS,并在mWindowMap中保存W类和WindowState对应关系
WindowManagerService.addWindwow
win = new WindowState(...); // 用来表示一个Window
win.attach();
mSession.windowAddedLocked();
mSurfaceSession = new SurfaceSession(); // 在这里终于与SurfaceFlinger扯上关系了
mNumWindow++;
mWindowMap.put(client.asBinder(), win); // 用map来存储Binder和WindowState的对应关系
return res;
2.2 ViewRoot - requestLayout
relayoutWindow
// 这里的mSurface相当于一个传出参数,接收远程WMS创建的Surface
// 远端通过SurfaceSession创建一个Surface,则该Surface是已绑定一段与显示相关的内存的,往该内存里写数据即可显示在屏幕上
// 远端创建的Surface的mNativeObject是一个SurfaceControl类型,将其通过parcel传送过来,而传到本地后,根据parcel构建出的是一个Surface类型
sWindowSession.relayout(..., mSurface);
draw
// 调用上面得到的surface的lockCanvas,可以得到一个绑定了其内存的canvas
// 调用mView(即DecorView)的draw函数,并将canvas传入进去,即可将DecorView及下各层级子view绘制在该canvas所绑定的内存中并显示在屏幕上
Surface surface = mSurface;
canvas = surface.lockCanvas(dirty);
mView.draw(canvas); // mView为DecorView
surface.unlockCanvasAndPost(canvas);
2.2.1 Session - relayout
- 在服务端创建Surface,并传回给应用端
WindowManagerService.relayoutWindow
Surface surface = win.createSurfaceLocked(); // win为addWindow时创建的WindowState
mSurface = new Surface(mSession.mSurfaceSession, ...);
outSurface.copyFrom(surface); // 将Service端创建的surface传给Client端
2.2.2 Surface - lockCanvas
- 从Surface中获取SurfaceInfo,其包含绑定的内存,将该内存绑定到一个bitmap并赋给canvas
lockCanvasNative -> Surface_lockCanvas
// 这里先取出Native的Surface
const sp<Surface>& surface(getSurface(env, clazz));
// 调用native的surface的lock并获取SurfaceInfo
Surface::SurfaceInfo info;
status_t err = surface->lock(&info, &dirtyRegion);
// 获取canvas和nativeCanvas
jobject canvas = env->GetObjectField(clazz, so.canvas);
SkCanvas* nativeCanvas = (SkCanvas*) env.GetIntField(canvas, no.native_canvas);
// 设置format,width,height,size和内存
bitmap.setConfig(...);
bit.setPixels(info.bits);
// 给canvas设置bitmap;
nativeCanvas.setBitmapDevice(bitmap);
2.3 ViewRoot和WMS关系
ViewRoot通过 IWindowManager.Stub.asInterface(ServiceManager.getService("window"))
获得一个IWindowManager,然后通过其openSession获得一个IWindowSession
ViewRoot通过IWindowSession远程调用WMS
WMS通过IWindow远程调用ViewRoot中的W对象
(待续)
3. 画图四大组件
- Bitmap
- Canvas
- Drawing primitive
- Paint
4. FrameBuffer
图像数据的传输过程是:
- 由客户端把数据写到共享内存中
- 然后由SurfaceFlinger从共享内存中取出数据再往硬件发送
承载图像数据的就是FrameBuffer(简称FB)
FrameBuffer的中文名叫缓冲帧,它实际上包含两方面:
- Frame:帧,指一幅图像,即屏幕上的一帧。
- Buffer:缓冲,就是一段内存,用来存储帧数据。
FrameBuffer中的Buffer,是通过mmap系统调用把显示设备中的显存映射到用户空间,在这块缓冲区上写数据,就相当于在屏幕上绘画。
Linux FrameBuffer(简称LFB),是Linux平台提供的一种可直接操作FB的机制,依托这个机制,应用层通过标准的系统调用,就可以直接操作显示设备了。