我是靠谱客的博主 活泼飞鸟,最近开发中收集的这篇文章主要介绍分析SurfaceFlinger过程遇到的知识点,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

使用的源码是2.3的!
1、首先看Activity的启动过程:
无论通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中。
ActivityManagerService内部开始分析:
--startSpecificActivityLocked()@ActivityManagerService.java
--realStartActivityLocked()@ActivityManagerService.java
--app.thread.scheduleLaunchActivity@ActivityManagerService.java
--scheduleLaunchActivity()@IApplicationThread.java
--scheduleLaunchActivity()@ActivityThread.java
单例?
--handleMessage()@H$ActivityThread.java
--handleLaunchActivity()@ActivityThread.java
--performLaunchActivity()@ActivityThread.java
--mInstrumentation.newActivity()@ActivityThread.java
//初始化Activity,生成一个window对象,设置各种状态等等
--activity.attach()@ActivityThread.java
//调用ActivityonCreate()方法
--mInstrumentation.callActivityOnCreate()@ActivityThread.java
2ActivityUI建立关系的入口是函数onCreate()onCreate()中调用了setContentView(),setContentView()里面又调用了getWindow().setContentView()。根据字面的理解是,获得一个Window,然后把View的内容设置到Window上。
这里有两个概念:WindowView
Window:是一个抽象基类,用于控制顶层窗口的外观和行为,即绘制背景和标题栏、默认的按键处理等,它作为一个顶层的View加入到WindowManager中。
View:是一个基本的Ui单元,占据屏幕的一块矩形区域,可用于绘制,并能处理事件。
3、既然Window是抽象基类,那它实际的对象是什么?
Activity.java中,getWindow()返回的对象是mWindow,mWindow对象是在attach()函数里面创建的:
mWindowPolicyManager.makeNewWindow(this);
WindowManager对象也是在attach()里面创建的:
mWindow.setWindowManager(null,mToken,mComponent.flattenToString());
//保存这个WindowManager对象
mWindowManager=mWindow.getWindowManager();
4、这里冒出一个 PolicyManager,它对应的文件名是 PolicyManager.java,定义在framework/base/core/java/com/android/internal/policy/
policyManager.java里,Window是由Policy.makeWindow()创建的:
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
5、这里看[Policy.java]
创建Window
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
原来在第2点中的代码:mWindowPolicyManager.makeNewWindow(this);
返回的mWindow是一个 PhoneWindow对象。
6[PhoneWindow.java]
PhoneWindowWindow类的派生类,前面调用的setWindowManager函数是由PhoneWindow的父类Window来实现的。说到这里,好像有点混乱,其实我们是以两条线路跟进来的,一条是Window的创建过程,另一条是WindowManager的创建过程,所以要区分清楚。
7[Window.java]
public void setWindowManager(WindowManager wm,
IBinder appToken, String appName) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
//注意传进来的vmnull
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm);
}
这里出现了两个对象:WindowManagerImplLocalWindowManager,后者是Window的内部类。
WindowManagerImplLocalWindowManager都实现了WindowManager的接口,这里采用了Proxy模式,LocalWindowManager将它的工作委托给WindowManagerImpl来完成。
8、再看[PhoneWindow.java]
其实在Activity创建时onCreate()中调用的setContentView()最后是走到了PhoneWindowsetContentView()里面。且看PhoneWindow.setContentView()
@Override
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
//将我们的View加入到mContentParent
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
这里有两个setContentView,前者调用了后者。
先看看installDecor()函数,其代码如下:
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
//创建mDecor,它为DecorView类型,从FrameLayout派生
.....
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor); //得到mContentParent
//创建标题栏
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
.....
}
}
从上面的过程可以看出:
1)mContentParent是一个ViewGroup类型,它从View中派生,所以也是一个UI单元,可以把它理解为一个容器,容器中的元素就是View
2)DecorView是一个装饰类,用来装饰View类,提供处理标题栏显示等一系列工作。
3)mContentParent是被DecorView装饰过的View
所以getWindow().setContentView()最终的结果是:创建了一个Window,并且在Window上创建了一个DecorView(ViewGroup类型),然后把我们的View加入到DecorView中。
9、现在回头看看handleLaunchActivity()的处理,它在文件[ActivityThread.java]:
private final void handleLaunchActivity(ActivityClientRecord r, Intent
customIntent) {
.....
//创建一个 Activity
Activity a = performLaunchActivity(r, customIntent);
.....
//调用 handleResumeActivity
handleResumeActivity(r.token, false, r.isForward);
.....
}
关键的函数有两个: performLaunchActivity()handleResumeActivity()
performLaunchActivity()创建了一个Activity,并且它里面调用了Activity.attach(),创建了上面所说到的PhoneWindowWindowManagerDecorView.
现在看 handleResumeActivity():
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
......
if (r.window == null && !a.mFinished && willBeVisible) {
//获得Window对象,其实是PhoneWindow
r.window = r.activity.getWindow();
//获得一个View对象,这个View其实是DecorView
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//获得ViewManager对象,看来是WindowManager
ViewManager wm = a.getWindowManager();
......
//DecorView加入到ViewManager中,也可以说是加到WindowManager
wm.addView(decor, l);
}
}
原来,在Activity.Attach()中创建的WindowManagerWindowDecorView等都是在这里用到的。
这冒出来一个 ViewManager,竟然把WindowManager对像传给了它,其实这里的WindowManagerLocalWindowManager。不得不说,wm.addView(decor, l)传进去的参数只有DecorView,那WindowWindowManager究竟去哪了?这里先留一个疑问,继续往前走。
现在从wm.addView(decor, l)切入,看看这个 addView
[Window.java LocalWindowManager]
它里面调用的是mWindowManager.addView(),前面说过Proxy模式,所以mWindowManager的实际对象是WindowManagerImpl。转去看WindowManagerImpl.addView()
10WindowManagerImpl.addView()里面创建了一个ViewRoot对象,并且调用了它的setView方法。
11ViewRoot的构造函数里面建立了与WindowManagerService的通讯,ViewRoot通过IWindowSessionWMS会话,WMS通过ViewRoot传过来的IWindowViewRoot通讯。此外,ViewRoot的构造函数里面还创建了一个无参的Surface
12ViewRoot.setView()里面做了关键的3件事:
1)WindowManagerImpl传过来的DecorView保存为自己的成员变量mView
2)调用了requestLayout()->scheduleTraversals()->sendEmptyMessage(DO_TRAVERSAL);由于ViewRoot继承于Handler,所以它发送的消息最后由自己来处理,看它的handleMessage():
public void handleMessage(Message msg) {
switch (msg.what) {
...
case DO_TRAVERSAL:
if (mProfile) {
Debug.startMethodTracing("ViewRoot");
}
performTraversals();
...
break;
...
}
}
关键函数performTraversals()里面调用了relayoutWindow()->sWindowSession.relayout()
sWindowSessionViewRootWMS通讯的接口,所以这里调用的是在WMS中的Session.relayout(),然后它里面调用了WMS.relayoutWindow()。这条路径走下来,主要是在WMS端创建了一个带参的Surface,然后把这个带参Surface传给ViewRoot端的无参Surface
3)调用 sWindowSession.add()
即调用WMS端的Session.add(),这里不得不说一下,Session是在WMS里定义的,继承于IWindowSession.stub。下面继续分析Session.add(),它里面调用的是WMS.addWindow()
->WMS.attach()->Session.windowAddedLocked():
[WindowManagerService.java::Session]
void windowAddedLocked() {
...
mSurfaceSession = new SurfaceSession();
...
mSessions.add(this);
}
mNumWindow++;
}
这里创建了一个 SurfaceSession
ViewRoot.setView()的后两件事主要是在WMS端创建了带参的Surface对象和SurfaceSession对象。在看了他们的构造函数以后,发现他们的成员函数init()java(WMS)进入了jni(android_view_Surface.cpp)
SurfaceSession调到jni层后创建了与SurfaceFlinger连接的对象SurfaceComposerClient,并把该对象保存到Java层,jni层的Surface就从上层(Java层)取出该对象,用于调用SF的操作。
13、前面说到ViewRoot.handleMessage()时,调用了performTraversals()performTraversals()里面有个一draw(),绘画的动作就是在这里进行的。
ViewRoot.Draw():
private void draw(boolean fullRedrawNeeded) {
…
//surface lock一块canvas
canvas = surface.lockCanvas(dirty);
…
//调用Viewdrawcanvas上绘画
mView.draw(canvas);
…
//绘画完成,释放canvas
surface.unlockCanvasAndPost(canvas);
...
}
其中 lockCanvasunlockCanvasAndPostSurface.java里面实现,其实他们最后调到了jni层,
对应的实现在android_view_Surface.cpp里,android_view_Surface封装了Surface.cpp的部分操作。
14[android_view_Surface.cpp]
1)SurfaceSession.java::init进来:主要是创建了 SurfaceComposerClient对象
static void SurfaceSession_init(JNIEnv* env, jobject clazz)
{
sp<SurfaceComposerClient> client = new SurfaceComposerClient;
client->incStrong(clazz);
env->SetIntField(clazz, sso.client, (int)client.get());
}
2)Surface.java::init进来:调用SFcreateSurface来创建Surface
static void Surface_init(
JNIEnv* env, jobject clazz,
jobject session,
jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)
{
...
SurfaceComposerClient* client =
(SurfaceComposerClient*)env->GetIntField(session, sso.client);
sp<SurfaceControl> surface;
if (jname == NULL) {
surface = client->createSurface(pid, dpy, w, h, format, flags);
} else {
const jchar* str = env->GetStringCritical(jname, 0);
const String8 name(str, env->GetStringLength(jname));
env->ReleaseStringCritical(jname, str);
surface = client->createSurface(pid, name, dpy, w, h, format, flags);
}
if (surface == 0) {
doThrow(env, OutOfResourcesException);
return;
}
15[SurfaceComposerClient.cpp]
onFirstRef中建立与SF的连接:
void SurfaceComposerClient::onFirstRef()
{
sp<ISurfaceComposer> sm(getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();
if (conn != 0) {
mClient = conn;
Composer::addClient(this);
mPrebuiltLayerState = new layer_state_t;
mStatus = NO_ERROR;
}
}
}
16、当然,在创建Surface时,里面涉及到很多复杂的buffer分配以及释放问题,本人暂时还没理清,现在先跳去看SurfaceFlinger。由于 SurfaceFlinger继承于Thread类,所以它会有自己的工作线程,也就是说它会调用run方法。我们在 SurfaceFlinger的构造函数切入:
[SurfaceFlinger.cpp]
SurfaceFlinger::SurfaceFlinger():...
{
init();
}
它的构造函数除了一系列的初始化之外,只调用了init函数,init里面也没有什么太值得关注的地方,只是设置了一些属性。那么在哪里创建了工作线程呢,是在onFirstRef()
void SurfaceFlinger::onFirstRef()
{
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
// Wait for the main thread to be done with its initialization
mReadyToRunBarrier.wait();
}
工作线程创建后,将等待一个同步条件,这个同步条件被触发的地方在readToRun(),里面涉及到一些共享内存和屏幕的操作,以及一些opengl函数的调用。
SurfaceFlinger工作线程的循环函数:threadLoop()
bool SurfaceFlinger::threadLoop()
{
waitForEvent();
...
handleConsoleEvents();
...
handleTransaction(transactionFlags);
...
handlePageFlip();
...
handleRepaint();
...
postFramebuffer();
...
}


先大致讲一下 Android组合各个窗口的原理 :Android实际上是通过计算每一个窗口的可见区域,就是我们在屏幕上可见的窗口区域(Android 的词汇来说就是visibleRegionScreen ) ,然后将各个窗口的可见区域画到一个主layer的相应部分,最后就拼接成了一个完整的屏幕,然后将主layer 输送到 FB显示。在将各个窗口可见区域画到主layer 过程中涉及到一个硬件实现和一个软件实现的问题,如果是软件实现则通过Opengl 重新画图,其中还包括存在透明度的alpha 计算;如果实现了copybit hal的话,可以直接将窗口的这部分数据直接拷贝过来,并完成可能的旋转,翻转,以及 alhpa计算等。

下面来看看 Android 组合各个layer 并送到 FB 显示的具体过程:

1)handleConsoleEvent

当接收到 signal 或者singalEvent 事件以后,线程就停止等待开始对Client的请求进行处理,第一个步骤是handleConsoleEvent ,这个步骤我看了下和/dev/console 这个设备有关,它会取得屏幕或者释放屏幕,只有取得屏幕的时候才能够在屏幕上画图。

2)handleTransaction

窗口状态的改变只能在一个Transaction中进行。因为窗口状态的改变可能造成本窗口和其他窗口的可见区域变化,所以就必须重新来计算窗口的可见区域。在这个处理子过程中Android会根据标志位来对所有layer 进行遍历,一旦发现哪个窗口的状态发生了变化就设置标志位以在将来重新计算这个窗口的可见区域。在完成所有子layer 的遍历以后, Android还会根据标志位来处理主 layer,举个例子,比如说传感器感应到手机横过来了,会将窗口横向显示,此时就要重新设置主layer的方向。

3) handlePageFlip

这里会处理每个窗口 surfacebuffer 之间的翻转,根据layer_state_t swapsate来决定是否要翻转,当swapsate的值是 eNextFlipPending是就会翻转。处理完翻转以后它会重新计算每个layer的可见区域,这个重新计算的过程我还没看太明白,但大致是一个这么的过程:

Z 值最大的layer 开始计算,也就是说从最上层的layer计算,去掉本身的透明区域和覆盖在它上面的不透明区域,得到的就是这个layer的可见区域。然后这个layer 的不透明区域就会累加到不透明覆盖区域,这个layer 的可见区域会放入到主layer的可见区域,然后计算下一个layer ,直到计算完所有的layer 的可见区域。这中间的计算是通过定义在skia中的一种与或非的图形逻辑运算实现的,类似我们数学中的与或非逻辑图。

4)handleRepaint

计算出每个 layer的可见区域以后,这一步就是将所有可见区域的内容画到主layer的相应部分了,也就是说将各个surface buffer 里面相应的内容拷贝到主layer 相应的 buffer,其中可能还涉及到alpha运算,像素的翻转,旋转等等操作,这里就像我前面说的可以用硬件来实现也可以用软件来实现。在使用软件的opengl做计算的过程中还会用到PixFlinger 来做像素的合成。

5)postFrameBuffer

最后的任务就是翻转主 layer的两个buffer ,将刚刚写入的内容放入FB 内显示了




最后

以上就是活泼飞鸟为你收集整理的分析SurfaceFlinger过程遇到的知识点的全部内容,希望文章能够帮你解决分析SurfaceFlinger过程遇到的知识点所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部