现在的位置: 首页 > 综合 > 正文

Android深入浅出之Surface

2013年08月01日 ⁄ 综合 ⁄ 共 9631字 ⁄ 字号 评论关闭

一 目的

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

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

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

  二 Activity 是如何显示的

  最初的想法就是, Activity 获得一块显存,然后在上面绘图,最后交给设备去显示。这个道理是没错,但是 Android 的 SurfaceFlinger 是在 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 那几行非常关键,它关系到咱们在 Activity 中 setContentView 后,整个 Window 到底都包含了些什么。我先告诉大家。所有你创建的 View 之上,还有一个 DecorView ,这是一个 FrameLayout ,另外还有一个 PhoneWindow 。上面这些东西的代码在

  framework/Policies/Base/Phone/com/android/Internal/policy/impl 。这些隐藏的 View 的创建都是由你在 Acitivty 的 onCreate 中调用 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 将创建mDecor 和mContentParent 。mDecor 是DecorView 类型,

  mContentParent 是ViewGroup 类型

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() 又返回什么呢?

  PhoneWindow 从 Window 中派生, 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 有那么点关系,其实它根本和 View 等 UI 关系不大,它不过是一个 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 的关系。

public 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 ,所以接下来消息循环下一个将调用的就是

  

ViewRoot 的 handleMessage 。

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); ----> 调用了native 的init 函数。
  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 client = new SurfaceComposerClient;
  client->incStrong(clazz);
  //Google 常用做法,在JAVA 对象中保存C++ 对象的指针。
  env->SetIntField(clazz, sso.client, (int)client.get());
  }

  Surface 的 init 对应为:

  [--->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 surface;
  if (jname == NULL) {

抱歉!评论已关闭.