当前位置: 代码迷 >> Android >> Android深入显出之Surface
  详细解决方案

Android深入显出之Surface

热度:41   发布时间:2016-05-01 16:26:37.0
Android深入浅出之Surface

目的

本节的目的就是为了讲清楚Android中的Surface系统,大家耳熟能详的SurfaceFlinger到底是个什么东西,它的工作流程又是怎样的。当然,鉴于SurfaceFlinger的复杂性,我们依然将采用情景分析的办法,找到合适的切入点。

一个Activity是怎么在屏幕上显示出来的呢?我将首先把这个说清楚。

接着我们把其中的关键调用抽象在Native层,以这些函数调用为切入点来研究SurfaceFlinger。好了,开始我们的征途吧。

Activity是如何显示的

最初的想法就是,Activity获得一块显存,然后在上面绘图,最后交给设备去显示。这个道理是没错,但是AndroidSurfaceFlinger是在System Server进程中创建的,Activity一般另有线程,这之间是如何...如何挂上关系的呢?我可以先提前告诉大家,这个过程还比较复杂。呵呵。

好吧,我们从Activity最初的启动开始。代码在

framework/base/core/java/android/app/ActivityThread.java中,这里有个函数叫handleLaunchActivity

[---->ActivityThread:: handleLaunchActivity()]

private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {

????? Activity a = performLaunchActivity(r, customIntent);

?

??????? if (a != null) {

??????????? r.createdConfig = new Configuration(mConfiguration);

??????????? Bundle oldState = r.state;

??????????? handleResumeActivity(r.token, false, r.isForward);

---->调用handleResumeActivity

}

handleLaunchActivity中会调用handleResumeActivity

[--->ActivityThread:: handleResumeActivity]

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {

???????? boolean willBeVisible = !a.mStartedActivity;

??????????

if (r.window == null && !a.mFinished && willBeVisible) {

??????????????? r.window = r.activity.getWindow();

??????????????? View decor = r.window.getDecorView();

??????????????? decor.setVisibility(View.INVISIBLE);

??????????????? ViewManager wm = a.getWindowManager();

??????????????? WindowManager.LayoutParams l = r.window.getAttributes();

??????????????? a.mDecor = decor;

??????????????? l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

??????????????? if (a.mVisibleFromClient) {

??? ????????????????a.mWindowAdded = true;

??????????????????? wm.addView(decor, l); //这个很关键。

??????????????? }

上面addView那几行非常关键,它关系到咱们在ActivitysetContentView后,整个Window到底都包含了些什么。我先告诉大家。所有你创建的View之上,还有一个DecorView,这是一个FrameLayout,另外还有一个PhoneWindow。上面这些东西的代码在

framework/Policies/Base/Phone/com/android/Internal/policy/impl。这些隐藏的View的创建都是由你在AcitivtyonCreate中调用setContentView导致的。

[---->PhoneWindow:: addContentView]

?? public void addContentView(View view, ViewGroup.LayoutParams params) {

??????? if (mContentParent == null) {? //刚创建的时候mContentParent为空

??????????? installDecor();

??????? }

??????? mContentParent.addView(view, params);

??????? final Callback cb = getCallback();

??????? if (cb != null) {

??????????? cb.onContentChanged();

??????? }

}

installDecor将创建mDecormContentParentmDecorDecorView类型,

mContentParentViewGroup类型

private void installDecor() {

??????? if (mDecor == null) {

??????????? mDecor = generateDecor();

??????????? mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

??????????? mDecor.setIsRootNamespace(true);

??????? }

??????? if (mContentParent == null) {

??????????? mContentParent = generateLayout(mDecor);

那么,ViewManager wm = a.getWindowManager()又返回什么呢?

PhoneWindowWindow中派生,Acitivity创建的时候会调用它的setWindowManager。而这个函数由Window类实现。

代码在framework/base/core/java/android/view/Window.java

public void setWindowManager(WindowManager wm,IBinder appToken, String appName) {

??????? mAppToken = appToken;

??????? mAppName = appName;

??????? if (wm == null) {

??????????? wm = WindowManagerImpl.getDefault();

??????? }

??????? mWindowManager = new LocalWindowManager(wm);

??? }

你看见没,分析JAVA代码这个东西真的很复杂。mWindowManager的实现是LocalWindowManager,但由通过Bridge模式把功能交给WindowManagerImpl去实现了。

真的很复杂!

好了,罗里罗嗦的,我们回到wm.addView(decor, l)。最终会由WindowManagerImpl来完成

addView操作,我们直接看它的实现好了。

代码在framework/base/core/java/android/view/WindowManagerImpl.java

[---->addView]

private void addView(View view, ViewGroup.LayoutParams params, boolean nest)

??? {

????????? ViewRoot root; //ViewRoot,我们的主人公终于登场!

???????? synchronized (this) {

???????? root = new ViewRoot(view.getContext());

????????? root.mAddNesting = 1;

????????? view.setLayoutParams(wparams);

???????????

??????????? if (mViews == null) {

??????????????? index = 1;

??????????????? mViews = new View[1];

??????????????? mRoots = new ViewRoot[1];

??????????????? mParams = new WindowManager.LayoutParams[1];

??????????? } else {

?????????? }

??????????? index--;

??????????? mViews[index] = view;

??????????? mRoots[index] = root;

??????????? mParams[index] = wparams;

??????? }

???? ??root.setView(view, wparams, panelParentView);

}

ViewRoot是整个显示系统中最为关键的东西,看起来这个东西好像和View有那么点关系,其实它根本和ViewUI关系不大,它不过是一个Handler罢了,唯一有关系的就是它其中有一个变量为Surface类型。我们看看它的定义。ViewRoot代码在

framework/base/core/java/android/view/ViewRoot.java

public final class ViewRoot extends Handler implements ViewParent,

??????? View.AttachInfo.Callbacks

{

private final Surface mSurface = new Surface();

}

它竟然从handler派生,而ViewParent不过定义了一些接口函数罢了。

看到Surface直觉上感到它和SurfaceFlinger有点关系。要不先去看看?

Surface代码在framework/base/core/java/android/view/Surface.java中,我们调用的是无参构造函数。

public Surface() {

?????? mCanvas = new CompatibleCanvas(); //就是创建一个Canvas

}

如果你有兴趣的话,看看Surface其他构造函数,最终都会调用native的实现,而这些native的实现将和SurfaceFlinger建立关系,但我们这里ViewRoot中的mSurface显然还没有到这一步。那它到底是怎么和SurfaceFlinger搞上的呢?这一切待会就会水落石出的。

另外,为什么ViewRoot是主人公呢?因为ViewRoot建立了客户端和SystemServer的关系。我们看看它的构造函数。

public ViewRoot(Context context) {

??????? super();

?????? ....

?????? getWindowSession(context.getMainLooper());

}

getWindowsession将建立和WindowManagerService的关系。

ublic static IWindowSession getWindowSession(Looper mainLooper) {

??????? synchronized (mStaticInit) {

??????????? if (!mInitialized) {

??????????????? try {

??????????????? //sWindowSession是通过Binder机制创建的。终于让我们看到点希望了

??????????????????? InputMethodManager imm = InputMethodManager.getInstance(mainLooper);

??????????????????? sWindowSession = IWindowManager.Stub.asInterface(

??????????????????????????? ServiceManager.getService("window"))

??????????????????????????? .openSession(imm.getClient(), imm.getInputContext());

?????????????????? ?mInitialized = true;

??????????????? } catch (RemoteException e) {

??????????????? }

??????????? }

??????????? return sWindowSession;

??????? }

??? }

上面跨Binder的进程调用另一端是WindowManagerService,代码在

framework/base/services/java/com/android/server/WindowManagerService.java中。我们先不说这个。

回过头来看看ViewRoot接下来的调用。

[-->ViewRoot::setView()],这个函数很复杂,我们看其中关键几句。

public void setView(View view, WindowManager.LayoutParams attrs,

??????????? View panelParentView) {

??????? synchronized (this) {

??????????? requestLayout();

??????????????? try {

??????????????????? res = sWindowSession.add(mWindow, mWindowAttributes,

??????????????????????????? getHostVisibility(), mAttachInfo.mContentInsets);

??????????????? }

}

requestLayout实现很简单,就是往handler中发送了一个消息。

public void requestLayout() {

??????? checkThread();

??????? mLayoutRequested = true;

??????? scheduleTraversals(); //发送DO_TRAVERSAL消息

}

public void scheduleTraversals() {

??????? if (!mTraversalScheduled) {

??????? ????mTraversalScheduled = true;

??????????? sendEmptyMessage(DO_TRAVERSAL);

??????? }

}

我们看看跨进程的那个调用。sWindowSession.add。它的最终实现在WindowManagerService中。

[--->WindowSession::add()]

public int add(IWindow window, WindowManager.LayoutParams attrs,

????????????? ??int viewVisibility, Rect outContentInsets) {

??????????? return addWindow(this, window, attrs, viewVisibility, outContentInsets);

??????? }

WindowSession是个内部类,会调用外部类的addWindow

这个函数巨复杂无比,但是我们的核心目标是找到创建显示相关的部分。所以,最后精简的话就简单了。

[--->WindowManagerService:: addWindow]

public int addWindow(Session session, IWindow client,

??????????? WindowManager.LayoutParams attrs, int viewVisibility,

??????????? Rect outContentInsets) {

??????? //创建一个WindowState,这个又是什么玩意儿呢?

????????????? win = new WindowState(session, client, token,

??????????????????? attachedWindow, attrs, viewVisibility);

?????????? win.attach();

?????????? return res;

}

WindowState类中有一个和Surface相关的成员变量,叫SurfaceSession。它会在

attach函数中被创建。SurfaceSession嘛,就和SurfaceFlinger有关系了。我们待会看。

好,我们知道ViewRoot创建及调用add后,我们客户端的View系统就和WindowManagerService建立了牢不可破的关系。

另外,我们知道ViewRoot是一个handler,而且刚才我们调用了requestLayout,所以接下来消息循环下一个将调用的就是ViewRoothandleMessage

public void handleMessage(Message msg) {

??????? switch (msg.what) {

?????? case DO_TRAVERSAL:

??????????? performTraversals();

performTraversals更加复杂无比,经过我仔细挑选,目标锁定为下面几个函数。当然,后面我们还会回到performTraversals,不过我们现在更感兴趣的是Surface是如何创建的。

private void performTraversals() {

??????? // cache mView since it is used so much below...

??????? final View host = mView;

?

??????? ?boolean initialized = false;

??????????? boolean contentInsetsChanged = false;

??????????? boolean visibleInsetsChanged;

??????????? try {

//ViewRoot也有一个Surface成员变量,叫mSurface,这个就是代表SurfaceFlinger的客户端

//ViewRoot在这个Surface上作画,最后将由SurfaceFlinger来合成显示。刚才说了mSurface还没有什么内容。

???? ?????relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

[---->ViewRoot:: relayoutWindow()]

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,

??????????? boolean insetsPending) throws RemoteException {

??????

//relayOut是跨进程调用,mSurface做为参数传进去了,看来离真相越来越近了呀!

??????? int relayoutResult = sWindowSession.relayout(

??????????????? mWindow, params,

??????????????? (int) (mView.mMeasuredWidth * appScale + 0.5f),

??????????????? (int) (mView.mMeasuredHeight * appScale + 0.5f),

??????????????? viewVisibility, insetsPending, mWinFrame,

??????????????? mPendingContentInsets, mPendingVisibleInsets,

??????????????? mPendingConfiguration, mSurface); mSurface做为参数传进去了。

?????? }

我们赶紧转到WindowManagerService去看看吧。、

public int relayoutWindow(Session session, IWindow client,

??????????? WindowManager.LayoutParams attrs, int requestedWidth,

??????????? int requestedHeight, int viewVisibility, boolean insetsPending,

??????????? Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,

??????????? Configuration outConfig, Surface outSurface){

?????????????? .....

? ???????try {

?????????? //看到这里,我内心一阵狂喜,有戏,太有戏了!

???????? //其中win是我们最初创建的WindowState

??????????????????? Surface surface = win.createSurfaceLocked();

??????????????????? if (surface != null) {

????????????????? //先创建一个本地surface,然后把传入的参数outSurface copyFrom一下

?????????? ?????????????outSurface.copyFrom(surface);

??????????????????????? win.mReportDestroySurface = false;

??????????????????????? win.mSurfacePendingDestroy = false;

?????????????????????? } else {

?????????????????????? outSurface.release();

???????????????? ???}

??????????????? }

}

[--->WindowState::createSurfaceLocked]

Surface createSurfaceLocked() {

?????????

??????????????? try {

??????????????????? mSurface = new Surface(

??????????????????????????? mSession.mSurfaceSession, mSession.mPid,

????????????? ??????????????mAttrs.getTitle().toString(),

??????????????????????????? 0, w, h, mAttrs.format, flags);

????????????????? }

??????????????? Surface.openTransaction();

这里使用了Surface的另外一个构造函数。

??? public Surface(SurfaceSession s,

??????????? int pid, String name, int display, int w, int h, int format, int flags)

??????? throws OutOfResourcesException {

??????? mCanvas = new CompatibleCanvas();

??????? init(s,pid,name,display,w,h,format,flags); ---->调用了nativeinit函数。

??????? mName = name;

}

到这里,不进入JNI是不可能说清楚了。不过我们要先回顾下之前的关键步骤。

l???????? add中,new了一个SurfaceSession

l???????? 创建new了一个Surface

l???????? 调用copyFrom,把本地Surface信息传到outSurface

JNI

上面两个类的JNI实现都在framework/base/core/jni/android_view_Surface.cpp中。

?[---->SurfaceSession:: SurfaceSession()]

public class SurfaceSession {

??? /** Create a new connection with the surface flinger. */

??? public SurfaceSession() {

??????? init();

}

它的init函数对应为:

[--->SurfaceSession_init]

static void SurfaceSession_init(JNIEnv* env, jobject clazz)

{

?? //SurfaceSession对应为SurfaceComposerClient

??? sp<SurfaceComposerClient> client = new SurfaceComposerClient;

client->incStrong(clazz);

//Google常用做法,在JAVA对象中保存C++对象的指针。

??? env->SetIntField(clazz, sso.client, (int)client.get());

}

Surfaceinit对应为:

[--->Surface_init]

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) {</

  相关解决方案