1 Surface有關(guān)流程梳理
在
ViewRootImpl
的字段中有一個Surface
類型的mSurface
咆霜,直接調(diào)用了無參的構(gòu)造函數(shù)創(chuàng)建继准。final Surface mSurface = new Surface();
-
在
ViewRootImpl
的setView()
函數(shù)中北苟,通過了IWindowSession
跨進程與WindowManagerService
中的Session
交互闪朱,調(diào)用了IWindowSession.addToDisplay()
函數(shù)薛匪。調(diào)用流程:
frameworks/base/services/core/java/com/android/server/wm/Session.java
@Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { //WindowManagerService.addWindow return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); }
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { ...// synchronized(mWindowMap) { ...// boolean addToken = false; WindowToken token = mTokenMap.get(attrs.token); AppWindowToken atoken = null; if (token == null) { ...// token = new WindowToken(this, attrs.token, -1, false); addToken = true; ..// } ..// WindowState win = new WindowState(this, session, client, token, attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent); ..// //重要的函數(shù) win.attach(); ...// } if (reportNewConfig) { sendNewConfiguration(); } Binder.restoreCallingIdentity(origId); return res; }
frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void attach() { //Session mSession.windowAddedLocked(); }
frameworks/base/services/core/java/com/android/server/wm/Session.java
void windowAddedLocked() { if (mSurfaceSession == null) { //創(chuàng)建了一個SurfaceSeesion對象 mSurfaceSession = new SurfaceSession(); mService.mSessions.add(this); if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) { mService.dispatchNewAnimatorScaleLocked(this); } } mNumWindow++; }
-
ViewRootImpl
在performTransval()
的處理過程中會調(diào)用relayoutWindow()
,最后是調(diào)用的IWindowSession
的relayout()
函數(shù)捐川。 -
ViewRootImpl
調(diào)用Surface
的lockCanvas()
,得到一塊畫布。 -
ViewRootImpl
調(diào)用Surface
的unlockCanvasAndPost()
,釋放畫布逸尖。
-
2 surface的轉(zhuǎn)化
通過梳理古沥,在performTransval()
中會與WindowManagerServic
交互
frameworks/base/services/core/java/com/android/server/wm/Session.java
ublic int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
Configuration outConfig, Surface outSurface) {
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);
return res;
}
這個函數(shù)本身沒有任何實際操作,實際操作對象時WindowManagerService
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int relayoutWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
Configuration outConfig, Surface outSurface) {
...//
long origId = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
...//
if (viewVisibility == View.VISIBLE &&
(win.mAppToken == null || !win.mAppToken.clientHidden)) {
result = relayoutVisibleWindow(outConfig, result, win, winAnimator, attrChanges,
oldVisibility);
try {
//創(chuàng)建sufaceControl
result = createSurfaceControl(outSurface, result, win, winAnimator);
} catch (Exception e) {
...//
}
..//
}
return result;
}
7.0的源碼這部分非常復(fù)雜娇跟,就光一個本地的surface
對象的創(chuàng)建都找了天才找到岩齿,而且還是多層封裝
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private int createSurfaceControl(Surface outSurface, int result, WindowState win,
WindowStateAnimator winAnimator) {
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
}
//創(chuàng)建WindowSurfaceController對象
WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
if (surfaceController != null) {
//這里面才是原書中的copyFrom()
surfaceController.getSurface(outSurface);
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
outSurface.release();
}
return result;
}
void getSurface(Surface outSurface) {
outSurface.copyFrom(mSurfaceControl);
}
然而還是沒有找到surface
的創(chuàng)建,那么一定是在surfaceController
對中了苞俘。
frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
WindowSurfaceController createSurfaceLocked() {
final WindowState w = mWin;
if (w.hasSavedSurface()) {
return mSurfaceController;
}
if (mSurfaceController != null) {
return mSurfaceController;
}
w.setHasSurface(false);
..//
// We may abort, so initialize to defaults.
mLastSystemDecorRect.set(0, 0, 0, 0);
mHasClipRect = false;
mClipRect.set(0, 0, 0, 0);
mLastClipRect.set(0, 0, 0, 0);
try{
...//
//創(chuàng)建WindowSurfaceController實例
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
attrs.getTitle().toString(),
width, height, format, flags, this);
w.setHasSurface(true);
} catch (OutOfResourcesException e) {
mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
mDrawState = NO_SURFACE;
return null;
} catch (Exception e) {
mDrawState = NO_SURFACE;
return null;
}
// Start a new transaction and apply position & offset.
final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
mLastHidden = true;
return mSurfaceController;
}
真是深啊盹沈,繼續(xù)看下去
frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java
public WindowSurfaceController(SurfaceSession s,
String name, int w, int h, int format, int flags, WindowStateAnimator animator) {
mAnimator = animator;
mSurfaceW = w;
mSurfaceH = h;
title = name;
// For opaque child windows placed under parent windows,
// we use a special SurfaceControl which mirrors commands
// to a black-out layer placed one Z-layer below the surface.
// This prevents holes to whatever app/wallpaper is underneath.
//如果是childwindow那么進這個分支,里面最終還是會穿件一個surfaceControl對象
if (animator.mWin.isChildWindow() &&
animator.mWin.mSubLayer < 0) {
mSurfaceControl = new SurfaceControlWithBackground(s,
name, w, h, format, flags);
} else if (DEBUG_SURFACE_TRACE) {
mSurfaceControl = new SurfaceTrace(
s, name, w, h, format, flags);
} else {
//關(guān)注這個
mSurfaceControl = new SurfaceControl(
s, name, w, h, format, flags);
}
}
frameworks/base/services/core/java/com/android/server/wm/SurfaceControl.java
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
throws OutOfResourcesException {
...//
mName = name;
//創(chuàng)建本地surface對象
mNativeObject = nativeCreate(session, name, w, h, format, flags);
if (mNativeObject == 0) {
throw new OutOfResourcesException(
"Couldn't allocate SurfaceControl native object");
}
mCloseGuard.open("release");
}
現(xiàn)在終于找到了苗胀。繼續(xù)返回原書中襟诸。
在WindowManagerService
中創(chuàng)建的本地surface
瓦堵,然后將信息拷貝到outSurface
中,也就是ViewRootImpl
中的Surface
2.1 JNI層
原書中提及了Surface
的構(gòu)造歌亲,7.0代碼中Surface
的操作應(yīng)該都移到了native
中菇用,無參構(gòu)造中什么都沒做,就是默認的構(gòu)造函數(shù)陷揪。
SurfaceSession
的構(gòu)造惋鸥,在前面的梳理過程中知道,在調(diào)用WindowManagerService.addWindow()
中悍缠,創(chuàng)建了一個SurfaceSession
對象卦绣。采用new
的方式創(chuàng)建。
frameworks/base/core/java/android/view/SurfaceSession.java
public SurfaceSession() {
//調(diào)用native函數(shù)
mNativeClient = nativeCreate();
}
frameworks/base/core/jni/android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
//創(chuàng)建了一個SurfaceComposerClient
SurfaceComposerClient* client = new SurfaceComposerClient();
client->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(client);
}
2.1.1 Surface JNI
在WindowManagerService.relayoutWindow()
過程中飞蚓,創(chuàng)建SurfaceControl
對象時滤港,同時創(chuàng)建了一個native
的SurfaceControl
對象
frameworks/base/core/jni/android_view_SurfaceContrl.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags) {
ScopedUtfChars name(env, nameStr);
//先創(chuàng)建了一個SurfaceComposerClient
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
//通過SurfaceComposerClient創(chuàng)建native SurfaceControl
sp<SurfaceControl> surface = client->createSurface(
String8(name.c_str()), w, h, format, flags);
if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return 0;
}
surface->incStrong((void *)nativeCreate);
return reinterpret_cast<jlong>(surface.get());
}
2.1.2 copyFrom
在創(chuàng)建好native
的SurfaceControl
后面,調(diào)用了SurfaceController.getSurface()
,SurfaceController
里保存了一個JAVA
層的SurfaceControl
,JAVA
層的SurfaceControl
持有native
層的SurfaceControl
.
傳入的的Surface
調(diào)用copyFrom()
方法趴拧,參數(shù)是SurfaceControl
,我們知道溅漾,在client
端也就是在viewRootImpl
里面創(chuàng)建的Surface
對象什么都沒做,要使用draw
就必須要關(guān)聯(lián)native
的Surface
才能在屏幕上有圖像著榴。
frameworks/core/java/android/view/Surface.java
public void copyFrom(SurfaceControl other) {
..//
long surfaceControlPtr = other.mNativeObject;
...///
//創(chuàng)建了一個native surface
long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
//這個函數(shù)中做了Java層也native層關(guān)聯(lián)
setNativeObjectLocked(newNativeObject);
}
}
frameworks/core/java/android/view/Surface.java
private void setNativeObjectLocked(long ptr) {
if (mNativeObject != ptr) {
if (mNativeObject == 0 && ptr != 0) {
mCloseGuard.open("release");
} else if (mNativeObject != 0 && ptr == 0) {
mCloseGuard.close();
}
//保存本地surface對象
mNativeObject = ptr;
mGenerationId += 1;
if (mHwuiContext != null) {
mHwuiContext.updateSurface();
}
}
}
通過上面的操作就將本身沒有什么作用的ViewRootImpl
中的Surface
填充了數(shù)據(jù)添履。就可以使用draw
相關(guān)的調(diào)用了。
當然脑又,最后還是通過binder
通信交換數(shù)據(jù)暮胧,通過Parcelable
接口的readFromParcel
和writeFromParcel
.
3 Surface和圖畫
通過與WindowManagerService
交互,構(gòu)造好了Surface
,記下來就進入了draw
的流程问麸,在perfromTraversals()
代碼走到了performDraw()
往衷,最后去到了drawSoftware()
frameworks/base/core/java/android/view/ViewRootImpl.java
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
// Draw with software renderer.
final Canvas canvas;
try {
final int left = dirty.left;
final int top = dirty.top;
final int right = dirty.right;
final int bottom = dirty.bottom;
//得到一個canvas
canvas = mSurface.lockCanvas(dirty);
// The dirty rectangle can be modified by Surface.lockCanvas()
//noinspection ConstantConditions
if (left != dirty.left || top != dirty.top || right != dirty.right
|| bottom != dirty.bottom) {
attachInfo.mIgnoreDirtyState = true;
}
// TODO: Do this in native
canvas.setDensity(mDensity);
} catch (Surface.OutOfResourcesException e) {
handleOutOfResourcesException(e);
return false;
} catch (IllegalArgumentException e) {
Log.e(mTag, "Could not lock surface", e);
// Don't assume this is due to out of memory, it could be
// something else, and if it is something else then we could
// kill stuff (or ourself) for no reason.
mLayoutRequested = true; // ask wm for a new surface next time.
return false;
}
try {
// If this bitmap's format includes an alpha channel, we
// need to clear it before drawing so that the child will
// properly re-composite its drawing on a transparent
// background. This automatically respects the clip/dirty region
// or
// If we are applying an offset, we need to clear the area
// where the offset doesn't appear to avoid having garbage
// left in the blank areas.
if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
dirty.setEmpty();
mIsAnimating = false;
mView.mPrivateFlags |= View.PFLAG_DRAWN;
try {
canvas.translate(-xoff, -yoff);
if (mTranslator != null) {
mTranslator.translateCanvas(canvas);
}
canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
attachInfo.mSetIgnoreDirtyState = false;
//繪制方法調(diào)用
mView.draw(canvas);
drawAccessibilityFocusedDrawableIfNeeded(canvas);
} finally {
if (!attachInfo.mSetIgnoreDirtyState) {
// Only clear the flag if it was not set during the mView.draw() call
attachInfo.mIgnoreDirtyState = false;
}
}
} finally {
try {
//釋放canvas
surface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException e) {
mLayoutRequested = true; // ask wm for a new surface next time.
//noinspection ReturnInsideFinallyBlock
return false;
}
}
return true;
}
這里就看出來了。軟件方式繪制口叙,就是通過surface lock
一塊區(qū)域炼绘,然后調(diào)用View
的draw
方法繪制,最后釋放這個區(qū)域妄田。