Android图形系统分析

图形绘制概述

Android框架提供了两种绘制图形的方式:Canvas和OpenGL.

android.graphics.Canvas是一个2D图形API, 并且是在开发者中最流行的图形API. Canvas运算会在Android中绘制所有原生和自定义android.view.View. 在Android中,Canvas API通过一个名为OpenGLRender的绘制库实现硬件加速,该绘制库将Canvas运算转换为OpenGL运算,以便它们可以在GPU上执行。

从Android 4.0开始,硬件加速的Canvas默认情况下处于启用状态。因此,支持OpenGL ES 2.0的硬件GPU对于Android 4.0及更高版本的设备来说是强制要求。

除了Canvas,开发者渲染图形的另一个主要方式是使用OpenGL ES直接渲染到Surface. Android在Android.opengl包中提供了OpenGL ES接口,开发者可以使用这些接口通过SDK或Android NDK中提供的原生API调用其GL实现。

Android图形组件

无论开发者使用什么渲染API,一切内容都会渲染到”Surface”. Surface表示缓冲队列中的生产方,而缓冲队列通常会被SurfaceFlinger消耗。在Android平台上创建的每个窗口都由Surface提供支持。所有被渲染的可见Surface都被SurfaceFlinger合成到显示部分。

下图显示了关键组件是如何协作的:

所以,在App进程与WMS的通信过程中,我们会重点关注Surface的创建过程。

比喻

  • 就像我们画画需要画板一样,App绘制图形也需要,在Android中这个画板就是”Surface”,App进程中每个窗口在Java层和C++层各有一个Surface
  • Linux中有一个FrameBuffer(帧缓冲区),系统会定时地从其中取出数据并显示
  • Android中的Activity或Dialog并不能直接向FrameBuffer中写入数据,而是需要先写入到GraphicBuffer(图形缓冲区),然后进入到BufferQueue中
  • BufferQueue采用了生产者-消费者的模型,其中生产者为BufferQueueProducer,通过调用dequeueBuffer()获取一个空闲的缓冲区,并填入要绘制的图形数据,接着调用queueBuffer()将Buffer重新返回给BufferQueue
  • BufferQueue中的消费者为BufferQueueConsumer,通过调用acquireBuffer()从BufferQueue中拿到一个被填满的缓冲区并消费

图解

这是App进程与SurfaceFlinger进程的关系

这是App进程,WMS与SurfaceFlinger的关系

WMS负责控制所有App进程中窗口的显示,只有经过AMS与WMS的控制,在适当的时机,App才有向SurfaceFlinger中写入数据的机会。

图形缓冲区采用的是生产者-消费者模式:

流程如下:
1)App端与WMS建立连接,WMS与SurfaceFlinger建立连接,在这个过程中会创建大量的对象,为绘图做好准备
2)App端请求SurfaceFlinger进程的BufferQueue分配图形缓冲区;
3)BufferQueue通过Gralloc在匿名共享内存分配到空间,并将文件描述符fd通过GraphicBuffer传给App进程;
4)App进程通过fd将缓冲区映射到自己的内存空间中,并将首地址传递给图形库;
5)图形库从首地址开始绘制;
6)App端绘制完成后将缓冲区交还给BufferQueue;
7)queueBuffer()时,Layer通知SurfaceFlinger刷新

显示前的准备工作

从Activity到ViewRootImpl

一个Activity创建好之后,它的显示过程是从ActivityThread中handleResumeActivity()开始的,该方法的主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
// TODO Push resumeArgs into the activity for consideration
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
...
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
}
}
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;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if(!willBeVisible){
r.hideForNow=true;
}
...
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r);
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
r.tmpConfig.setTo(r.newConfig);
if (r.overrideConfig != null) {
r.tmpConfig.updateFrom(r.overrideConfig);
}
performConfigurationChanged(r.activity, r.tmpConfig);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
r.newConfig = null;
}
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
...
// Tell the activity manager we have resumed.
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token);
} catch (RemoteException ex) {
}
}
}
...
}

这个方法比较简单,主要就是分两种情况:第一种是当前Activity的Window还未添加到WindowManager,那么就需要调用wm.addView(decor,l);将窗体添加到WindowManager进行管理。当然,如果在resume的过程中我们启动了另外一个Activity,那么当前Activity会暂时隐藏。

第二种情况则是窗体已经添加到WM中,那么此时其实就是重新显示出来即可,这个过程中还会涉及到configuration的改变等。

由于这里我们关注一个Activity被创建后是如何显示出来的,所以这里关注第一种情况即可。

该方法中wm其实是WindowManagerImpl对象,故进入WindowManagerImpl.addView()中分析:

1
2
3
4
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}

这个方法很简单,就是调用了WindowManagerGlobal的addView()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
...
}
}

注意到在这个方法中创建了ViewRootImpl对象,并且在最后调用它的setView()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
int res; /* = WindowManagerImpl.ADD_OKAY; */
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
}
...
}

注意其中的mWindowSession.addToDisplay()这个调用,这里通过Binder通信,最终进入Session.addToDisplay()方法:

1
2
3
4
5
6
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
Rect outOutsets, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

显然,它只是调用WindowManagerService的addWindow()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
...
WindowState attachedWindow = null;
long origId;
...
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
...
WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
...
win.attach();
mWindowMap.put(client.asBinder(), win);
...
return res;
}

注意到在这里创建了WindowState对象,并且调用其attach()方法:

1
2
3
4
5
6
void attach() {
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Attaching " + this + " token=" + mToken
+ ", list=" + mToken.windows);
mSession.windowAddedLocked();
}

非常简单,就是调用Session的windowAddedLocked()方法:

1
2
3
4
5
6
7
8
9
10
void windowAddedLocked() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}

注意在这里创建了SurfaceSession对象,这个构造方法如下:

1
2
3
4
/** Create a new connection with the surface flinger. */
public SurfaceSession() {
mNativeClient = nativeCreate();
}

这个注释说得很清楚,就是建立与SurfaceFlinger的连接,那究竟是如何建立连接的呢?继续往下看便知。

nativeCreate()是个jni调用,其定义在android_view_SurfaceSession.cpp文件中:,

1
2
3
4
5
static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();
client->incStrong((void*)nativeCreate);
return reinterpret_cast<jlong>(client);
}

显然,这里创建了SurfaceComposerClient对象,其构造方法如下:

1
2
3
4
SurfaceComposerClient::SurfaceComposerClient()
: mStatus(NO_INIT), mComposer(Composer::getInstance())
{
}

其初始化列表中对Compoer对象mComposer进行了赋值。

但是还是没看到建立连接的地方呀?难道注释写错了?

SurfaceComposerClient

注意看SurfaceComposerClient的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
class SurfaceComposerClient : public RefBase
{
friend class Composer;
public:
SurfaceComposerClient();
virtual ~SurfaceComposerClient();
// Always make sure we could initialize
status_t initCheck() const;
// Return the connection of this client
sp<IBinder> connection() const;
// Forcibly remove connection before all references have gone away.
void dispose();
// callback when the composer is dies
status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
void* cookie = NULL, uint32_t flags = 0);
// Get a list of supported configurations for a given display
static status_t getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs);
// Get the DisplayInfo for the currently-active configuration
static status_t getDisplayInfo(const sp<IBinder>& display,
DisplayInfo* info);
// Get the index of the current active configuration (relative to the list
// returned by getDisplayInfo)
static int getActiveConfig(const sp<IBinder>& display);
// Set a new active configuration using an index relative to the list
// returned by getDisplayInfo
static status_t setActiveConfig(const sp<IBinder>& display, int id);
/* Triggers screen on/off or low power mode and waits for it to complete */
static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
// ------------------------------------------------------------------------
// surface creation / destruction
//! Create a surface
sp<SurfaceControl> createSurface(
const String8& name,// name of the surface
uint32_t w, // width in pixel
uint32_t h, // height in pixel
PixelFormat format, // pixel-format desired
uint32_t flags = 0 // usage flags
);
//! Create a virtual display
static sp<IBinder> createDisplay(const String8& displayName, bool secure);
//! Destroy a virtual display
static void destroyDisplay(const sp<IBinder>& display);
//! Get the token for the existing default displays.
//! Possible values for id are eDisplayIdMain and eDisplayIdHdmi.
static sp<IBinder> getBuiltInDisplay(int32_t id);
// ------------------------------------------------------------------------
// Composer parameters
// All composer parameters must be changed within a transaction
// several surfaces can be updated in one transaction, all changes are
// committed at once when the transaction is closed.
// closeGlobalTransaction() requires an IPC with the server.
//! Open a composer transaction on all active SurfaceComposerClients.
static void openGlobalTransaction();
//! Close a composer transaction on all active SurfaceComposerClients.
static void closeGlobalTransaction(bool synchronous = false);
//! Flag the currently open transaction as an animation transaction.
static void setAnimationTransaction();
status_t hide(const sp<IBinder>& id);
status_t show(const sp<IBinder>& id);
status_t setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask);
status_t setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent);
status_t setLayer(const sp<IBinder>& id, uint32_t layer);
status_t setAlpha(const sp<IBinder>& id, float alpha=1.0f);
status_t setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dsdy, float dtdy);
status_t setPosition(const sp<IBinder>& id, float x, float y);
status_t setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
status_t setCrop(const sp<IBinder>& id, const Rect& crop);
status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack);
status_t destroySurface(const sp<IBinder>& id);
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
static status_t clearAnimationFrameStats();
static status_t getAnimationFrameStats(FrameStats* outStats);
static void setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
static void setDisplayLayerStack(const sp<IBinder>& token,
uint32_t layerStack);
static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
/* setDisplayProjection() defines the projection of layer stacks
* to a given display.
*
* - orientation defines the display's orientation.
* - layerStackRect defines which area of the window manager coordinate
* space will be used.
* - displayRect defines where on the display will layerStackRect be
* mapped to. displayRect is specified post-orientation, that is
* it uses the orientation seen by the end-user.
*/
static void setDisplayProjection(const sp<IBinder>& token,
uint32_t orientation,
const Rect& layerStackRect,
const Rect& displayRect);
private:
virtual void onFirstRef();
Composer& getComposer();
mutable Mutex mLock;
status_t mStatus;
sp<ISurfaceComposerClient> mClient;
Composer& mComposer;
};

它是继承自RefBase的,从而在它首次被强引用的时候,就调用onFirstRef()方法:

1
2
3
4
5
6
7
8
9
10
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sm(ComposerService::getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();
if (conn != 0) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}

在这里,通过调用ComposerService::getComposerService()获取到ISurfaceComposer对象:

1
2
3
4
5
6
7
8
9
10
sp<ISurfaceComposer> ComposerService::getComposerService() {
ComposerService& instance = ComposerService::getInstance();
Mutex::Autolock _l(instance.mLock);
if (instance.mComposerService == NULL) {
ComposerService::getInstance().connectLocked();
assert(instance.mComposerService != NULL);
ALOGD("ComposerService reconnected");
}
return instance.mComposerService;
}

显然,会在ComposerSerivce::connectLocked()方法中建立连接,并且给mComposerService赋值。

1
2
3
4
5
6
7
void ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
while (getService(name, &mComposerService) != NO_ERROR) {
usleep(250000);
}
...
}

注意其中的getService()方法是来自IServiceManager.cpp中,其目的是根据服务名称(“SurfaceFlinger”)找到对应的服务并且返回其在C++层的代理,这是属于Binder通信的内容,不熟悉的小伙伴可以自己查看相应的内容。

经过getService(name,&mComposerService)之后,mComposerSerivce就持有了SurfaceFlinger在system_server进程中的代理,其实此时mComposerService是一个BpSurfaceComposer对象(ps.从这里可以看出这个mComposerService的命名其实相当不规范,应该取名叫mBpSurfaceComposer才恰当)。

再回到SurfaceComposerClient::onFirstRef()中,可知此时sm->createConnection()其实就是调用BpSurfaceComposer::createConnection()方法:

1
2
3
4
5
6
7
virtual sp<ISurfaceComposerClient> createConnection()
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}

这是典型的C++层Binder通信,最终会调用到SurfaceFlinger::createConnection()方法:

1
2
3
4
5
6
7
8
9
10
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
{
sp<ISurfaceComposerClient> bclient;
sp<Client> client(new Client(this));
status_t err = client->initCheck();
if (err == NO_ERROR) {
bclient = client;
}
return bclient;
}

在这里创建了一个Client对象并赋值给client,Client是SurfaceFlinger的一个帮手。

再回到SurfaceComposerClient::onFirstRef()方法中,可知conn其实就是一个SurfaceFlinger中Client对象在WMS中的一个代理,即BpSurfaceComposerClient对象(相对地,Client继承自BnSurfaceComposerClient)。mark这个,在后面会用到它。

绘图过程

虽然前面已经创建了很多对象,但是实际上还没有完全做好准备,有些对象是直到真正开始绘制时才创建。首先从SurfaceControl开始。

SurfaceControl

有很多种情况可以触发重绘,一个典型的过程是Choreographer.doFrame()—>Choreographer.doCallbacks()—>TraversalRunnable.run()—>ViewRootImpl.doTraversal()—>ViewRootImpl.performTraversals()—>ViewRootImpl.relayoutWindow(),这个方法非常重要,因为在这里面会创建SurfaceControl对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
...
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
//Log.d(TAG, "<<<<<< BACK FROM relayout");
if (restore) {
params.restore();
}
...
return relayoutResult;
}

在这个方法中进行了Binder调用,最终会调用Session.relayout()方法:

1
2
3
4
5
6
7
8
9
10
11
12
public 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, Configuration
outConfig,
Surface outSurface) {
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outConfig, outSurface);
return res;
}

显然,这里就是直接调用WMS的relayoutWindow()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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, Configuration outConfig,
Surface outSurface) {
...
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return 0;
}
WindowStateAnimator winAnimator = win.mWinAnimator;
...
try {
if (!win.mHasSurface) {
surfaceChanged = true;
}
SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
if (surfaceControl != null) {
outSurface.copyFrom(surfaceControl);
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
outSurface.release();
}
}
...
}
...
}

在这里通过调用WindowStateAnimator的createSurfaceLocked()方法创建SurfaceControl对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
SurfaceControl createSurfaceLocked() {
final WindowState w = mWin;
if (mSurfaceControl == null) {
mDrawState = DRAW_PENDING;
if (w.mAppToken != null) {
if (w.mAppToken.mAppAnimator.animation == null) {
w.mAppToken.allDrawn = false;
w.mAppToken.deferClearAllDrawn = false;
} else {
// Currently animating, persist current state of allDrawn until animation
// is complete.
w.mAppToken.deferClearAllDrawn = true;
}
}
mService.makeWindowFreezingScreenIfNeededLocked(w);
int flags = SurfaceControl.HIDDEN;
final WindowManager.LayoutParams attrs = w.mAttrs;
if (mService.isSecureLocked(w)) {
flags |= SurfaceControl.SECURE;
}
int width;
int height;
if ((attrs.flags & LayoutParams.FLAG_SCALED) != 0) {
// for a scaled surface, we always want the requested
// size.
width = w.mRequestedWidth;
height = w.mRequestedHeight;
} else {
width = w.mCompatFrame.width();
height = w.mCompatFrame.height();
}
// Something is wrong and SurfaceFlinger will not like this,
// try to revert to sane values
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
float left = w.mFrame.left + w.mXOffset;
float top = w.mFrame.top + w.mYOffset;
// Adjust for surface insets.
width += attrs.surfaceInsets.left + attrs.surfaceInsets.right;
height += attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
left -= attrs.surfaceInsets.left;
top -= attrs.surfaceInsets.top;
// We may abort, so initialize to defaults.
mSurfaceShown = false;
mSurfaceLayer = 0;
mSurfaceAlpha = 0;
mSurfaceX = 0;
mSurfaceY = 0;
w.mLastSystemDecorRect.set(0, 0, 0, 0);
mHasClipRect = false;
mClipRect.set(0, 0, 0, 0);
mLastClipRect.set(0, 0, 0, 0);
// Set up surface control with initial size.
try {
mSurfaceW = width;
mSurfaceH = height;
final boolean isHwAccelerated = (attrs.flags &
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
if (!PixelFormat.formatHasAlpha(attrs.format)
&& attrs.surfaceInsets.left == 0
&& attrs.surfaceInsets.top == 0
&& attrs.surfaceInsets.right == 0
&& attrs.surfaceInsets.bottom == 0) {
flags |= SurfaceControl.OPAQUE;
}
mSurfaceFormat = format;
if (DEBUG_SURFACE_TRACE) {
mSurfaceControl = new SurfaceTrace(
mSession.mSurfaceSession,
attrs.getTitle().toString(),
width, height, format, flags);
} else {
mSurfaceControl = new SurfaceControl(
mSession.mSurfaceSession,
attrs.getTitle().toString(),
width, height, format, flags);
}
w.mHasSurface = true;
...
}
...
// Start a new transaction and apply position & offset.
SurfaceControl.openTransaction();
try {
mSurfaceX = left;
mSurfaceY = top;
try {
mSurfaceControl.setPosition(left, top);
mSurfaceLayer = mAnimLayer;
final DisplayContent displayContent = w.getDisplayContent();
if (displayContent != null) {
mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack());
}
mSurfaceControl.setLayer(mAnimLayer);
mSurfaceControl.setAlpha(0);
mSurfaceShown = false;
}
...
}
...
}
return mSurfaceControl;
}

显然,在这里调用SurfaceControl的构造方法创建了一个SurfaceControl对象,并且开启事务模式进行相关属性的设置。SurfaceControl的构造方法中做了很多的事情:

1
2
3
4
5
6
7
8
9
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags)
throws OutOfResourcesException {
...
mName = name;
mNativeObject = nativeCreate(session, name, w, h, format, flags);
...
mCloseGuard.open("release");
}

跟上面类似,这里也有一个nativeCreate()的jni调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jstring nameStr, jint w, jint h, jint format, jint flags) {
ScopedUtfChars name(env, nameStr);
sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
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());
}

其中android_view_SurfaceSession_getClient()方法如下:

1
2
3
4
5
sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(
JNIEnv* env, jobject surfaceSessionObj) {
return reinterpret_cast<SurfaceComposerClient*>(
env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}

显然,这里是将jobject这个句柄重新转换为SurfaceComposerClient指针,而这个指针指向的就是前面创建的SurfaceComposerClient对象。

再回到nativeCreate()方法中,显然它是调用SurfaceComposerClient::createSurface()方法创建一个C++层的SurfaceControl对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sp<SurfaceControl> SurfaceComposerClient::createSurface(
const String8& name,
uint32_t w,
uint32_t h,
PixelFormat format,
uint32_t flags)
{
sp<SurfaceControl> sur;
if (mStatus == NO_ERROR) {
sp<IBinder> handle;
sp<IGraphicBufferProducer> gbp;
status_t err = mClient->createSurface(name, w, h, format, flags,
&handle, &gbp);
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
sur = new SurfaceControl(this, handle, gbp);
}
}
return sur;
}

这里的重点其实不在新建SurfaceControl对象,而在于创建这个对象之前的准备工作,其中mClient在前面说过,它其实是一个BpSurfaceComposerClient对象,所以mClient->createSurface()最终会调用到SurfaceFlinger进程中Client对象的createSurface()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
status_t Client::createSurface(
const String8& name,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp)
{
/*
* createSurface must be called from the GL thread so that it can
* have access to the GL context.
*/
class MessageCreateLayer : public MessageBase {
SurfaceFlinger* flinger;
Client* client;
sp<IBinder>* handle;
sp<IGraphicBufferProducer>* gbp;
status_t result;
const String8& name;
uint32_t w, h;
PixelFormat format;
uint32_t flags;
public:
MessageCreateLayer(SurfaceFlinger* flinger,
const String8& name, Client* client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp)
: flinger(flinger), client(client),
handle(handle), gbp(gbp),
name(name), w(w), h(h), format(format), flags(flags) {
}
status_t getResult() const { return result; }
virtual bool handler() {
result = flinger->createLayer(name, client, w, h, format, flags,
handle, gbp);
return true;
}
};
sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
name, this, w, h, format, flags, handle, gbp);
mFlinger->postMessageSync(msg);
return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}

注意这里调用了SurfaceFlinger的postMessageSync()方法,通知它去进行处理,最终会调用到MessageCreateLayer的handler()方法,从而调用SurfaceFlinger::createLayer()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
status_t SurfaceFlinger::createLayer(
const String8& name,
const sp<Client>& client,
uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
...
sp<Layer> layer;
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
result = createNormalLayer(client,
name, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceDim:
result = createDimLayer(client,
name, w, h, flags,
handle, gbp, &layer);
break;
default:
result = BAD_VALUE;
break;
}
if (result != NO_ERROR) {
return result;
}
result = addClientLayer(client, *handle, *gbp, layer);
if (result != NO_ERROR) {
return result;
}
setTransactionFlags(eTransactionNeeded);
return result;
}

这里会走到第一个分支,即调用createNormalLayer()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
format = PIXEL_FORMAT_RGBX_8888;
break;
}
*outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getProducer();
}
ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
return err;
}

在这里新建了Layer对象,以及给gbp赋值,其中gbp是IGraphicBufferProducer类型指针,而Layer::getProducer()方法很简单:

1
2
3
sp<IGraphicBufferProducer> Layer::getProducer() const {
return mProducer;
}

而这个类的创建在onFirstRef()中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
mProducer = new MonitoredProducer(producer, mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif
const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
updateTransformHint(hw);
}

在这个方法中,通过调用BufferQueue::createBufferQueue()创建了IGraphicBufferProducer对象和IGraphicBufferConsumer对象,它们分别是图形缓存的生产者和消费者。

下面就详细分析一下createBufferQueue()这个方法,注意最后一个参数allocator的默认值为NULL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator) {
LOG_ALWAYS_FATAL_IF(outProducer == NULL,
"BufferQueue: outProducer must not be NULL");
LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
"BufferQueue: outConsumer must not be NULL");
sp<BufferQueueCore> core(new BufferQueueCore(allocator));
LOG_ALWAYS_FATAL_IF(core == NULL,
"BufferQueue: failed to create BufferQueueCore");
sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
LOG_ALWAYS_FATAL_IF(producer == NULL,
"BufferQueue: failed to create BufferQueueProducer");
sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
LOG_ALWAYS_FATAL_IF(consumer == NULL,
"BufferQueue: failed to create BufferQueueConsumer");
*outProducer = producer;
*outConsumer = consumer;
}

可见,这个方法其实就做了三件事:

  • 创建了一个BufferQueueCore对象
  • 借助刚刚创建的BufferQueueCore对象,创建一个BufferQueueProduer对象
  • 类似地,创建一个BufferQueueConsumer对象

BpSurfaceComposerClient::createSurface()方法

再回到SurfaceComposerClient::createSurface()方法中,前面已经分析了mClient->createSurface()的跨进程调用过程,但是没有讲在跨进程之前,在WMS中是如何调用的。

由于mClient其实只是surface-flinger进程中Client对象在WMS中的代理,即BpSurfaceComposerClient对象,所以mClient->createSurface()首先是执行BpSurfaceComposerClient::createSurface()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
virtual status_t createSurface(const String8& name, uint32_t width,
uint32_t height, PixelFormat format, uint32_t flags,
sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeString8(name);
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
data.writeUint32(flags);
remote()->transact(CREATE_SURFACE, data, &reply);
*handle = reply.readStrongBinder();
*gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
return reply.readInt32();
}

可见gbp成了surface-flinger进程中BufferQueueProducer在WMS中的一个代理,即BpGraphicBufferProducer对象,后面可通过gdp进行跨进程调用到suface-flinger进程中的BufferQueueProducer对象。

C++层Surface对象的创建

再回到WMS.relayoutWindow()方法,在执行完SurfaceControl surfaceControl=winAnimator.createSurfaceLocked();之后会执行outSurface.copyFrom(surfaceControl);方法:

1
2
3
4
5
6
7
8
9
10
11
public void copyFrom(SurfaceControl other) {
...
long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
synchronized (mLock) {
if (mNativeObject != 0) {
nativeRelease(mNativeObject);
}
setNativeObjectLocked(newNativeObject);
}
}

这个方法的作用是让当前Surface指向另一个Surface所持有的数据,这里有jni调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
jlong surfaceControlNativeObj) {
/*
* This is used by the WindowManagerService just after constructing
* a Surface and is necessary for returning the Surface reference to
* the caller. At this point, we should only have a SurfaceControl.
*/
sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
sp<Surface> surface(ctrl->getSurface());
if (surface != NULL) {
surface->incStrong(&sRefBaseOwner);
}
return reinterpret_cast<jlong>(surface.get());
}

这个方法很简单,就是先将Java层的句柄转换为C++层的SurfaceControl对象(之前创建的SurfaceControl对象是以long型保存在Java层的SurfaceControl对象中),之后调用SurfaceControl::getSurface()方法获得C++层的Surface对象,并且将句柄保存在Java层的Surface对象中。其中getSurface()方法如下:

1
2
3
4
5
6
7
8
9
10
sp<Surface> SurfaceControl::getSurface() const
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == 0) {
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false.
mSurfaceData = new Surface(mGraphicBufferProducer, false);
}
return mSurfaceData;
}

显然,这里如果mSurfaceData为空的话,则会创建Surface对象。至此,C++层的Surface对象就创建好了。

准备工作总结

到这里为止,可以总结一下准备工作了,主要流程如下:

  • 从ActivityThread中handleResumeActivity()开始,调用到ViewRootImpl.setView()方法,最终通过Binder通信调用到WMS.addWindow()方法,从而在WMS中创建SurfaceSession对象,而这个Java层的SurfaceSession对象其实只是C++层SurfaceComposerClient对象的一个封装
  • 在创建SurfaceComposerClient对象的过程中,还建立了WMS与SurfaceFlinger的连接,并且在SurfaceFlinger进程中创建了Client对象, Client与SurfaceComposerClient是Binder通信的对端,它们分别在system_server和surface_flinger进程中
  • 接收到绘制信号后,触发重绘流程,即horeographer.doFrame()—>Choreographer.doCallbacks()—>TraversalRunnable.run()—>ViewRootImpl.doTraversal()—>ViewRootImpl.performTraversals()—>ViewRootImpl.relayoutWindow()
  • ViewRootImpl.relayoutWindow()中,最终会通过Binder通信调用到WMS的relayoutWindow()方法,在该方法中创建了Java层的SurfaceControl对象
  • 在创建Java层的SurfaceControl对象过程中,会通过jni调用在C++层创建一个SurfaceControl对象,并且通过Binder通信让Client对象创建一个Layer对象
  • 在WMS.relayoutWindow()方法中,创建好SurfaceControl对象之后,会调用outSurface.copyFrom(surfaceControl);创建Surface对象,并且将句柄保存在Java层的SurfaceControl对象中

开始进入绘制流程

做完了上面这些准备,建立了App与WMS的连接,以及WMS与SurfaceFlinger的连接,并且准备好了Surface对象,下面就可以开始绘图了。前面说过,触发重绘最终会走到ViewRootImpl.draw()方法中,该方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (!surface.isValid()) {
return;
}
...
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
// If accessibility focus moved, always invalidate the root.
boolean invalidateRoot = accessibilityFocusDirty;
// Draw with hardware renderer.
mIsAnimating = false;
if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
mHardwareYOffset = yOffset;
mHardwareXOffset = xOffset;
invalidateRoot = true;
}
mResizeAlpha = resizeAlpha;
if (invalidateRoot) {
mAttachInfo.mHardwareRenderer.invalidateRoot();
}
dirty.setEmpty();
mBlockResizeBuffer = false;
mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
// for instance) so we should just bail out. Locking the surface with software
// rendering at this point would lock it forever and prevent hardware renderer
// from doing its job when it comes back.
// Before we request a new frame we must however attempt to reinitiliaze the
// hardware renderer if it's in requested state. This would happen after an
// eglTerminate() for instance.
if (mAttachInfo.mHardwareRenderer != null &&
!mAttachInfo.mHardwareRenderer.isEnabled() &&
mAttachInfo.mHardwareRenderer.isRequested()) {
try {
mAttachInfo.mHardwareRenderer.initializeIfNeeded(
mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
return;
}
mFullRedrawNeeded = true;
scheduleTraversals();
return;
}
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
return;
}
}
}
...
}

显然,在绘制时有两种情况,即采用硬件加速或不采用,采用硬件加速进行绘制会在后面专门分析,这里先考虑drawSoftware()这种情况,该方法的主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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 = mSurface.lockCanvas(dirty);
...
}
...
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;
mView.draw(canvas);
drawAccessibilityFocusedDrawableIfNeeded(canvas);
}
...
} finally {
try {
surface.unlockCanvasAndPost(canvas);
}
...
}
return true;
}
  • mSurface在ViewRootImpl的构造方法之前就通过final Surface mSurface=new Surface();的定义创建了

  • 这里有三个流程很重要,分别是canvas = mSurface.lockCanvas(dirty); mView.draw(canvas);以及surface.unlockCanvasAndPost(canvas);其中mView.draw(canvas);就是真正地调用skia图形库进行绘制的过程,这个在前一篇文章中分析过,这里先不分析。

Surface.lockCanvas()方法分析

下面先分析canvas=mSurface.lockCanvas(dirty);这个调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public Canvas lockCanvas(Rect inOutDirty)
throws Surface.OutOfResourcesException, IllegalArgumentException {
synchronized (mLock) {
checkNotReleasedLocked();
if (mLockedObject != 0) {
// Ideally, nativeLockCanvas() would throw in this situation and prevent the
// double-lock, but that won't happen if mNativeObject was updated. We can't
// abandon the old mLockedObject because it might still be in use, so instead
// we just refuse to re-lock the Surface.
throw new IllegalArgumentException("Surface was already locked");
}
mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
return mCanvas;
}
}

这个方法是用于提供一个Canvas,从而让图形数据可以写入到Surface中,当然,最终其实是写入到surface-flinger进程中的Layer中。在调用这个方法之后需要调用unlockCanvasAndPost()以将要绘制的内容提交给Surface,所以这两个方法需要成对出现。

nativeLockCanvas()方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
if (!isSurfaceValid(surface)) {
doThrowIAE(env);
return 0;
}
Rect dirtyRect;
Rect* dirtyRectPtr = NULL;
if (dirtyRectObj) {
dirtyRect.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
dirtyRect.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
dirtyRect.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
dirtyRectPtr = &dirtyRect;
}
ANativeWindow_Buffer outBuffer;
status_t err = surface->lock(&outBuffer, dirtyRectPtr);
if (err < 0) {
const char* const exception = (err == NO_MEMORY) ?
OutOfResourcesException :
"java/lang/IllegalArgumentException";
jniThrowException(env, exception, NULL);
return 0;
}
SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
convertPixelFormat(outBuffer.format),
kPremul_SkAlphaType);
if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
info.fAlphaType = kOpaque_SkAlphaType;
}
SkBitmap bitmap;
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
bitmap.setInfo(info, bpr);
if (outBuffer.width > 0 && outBuffer.height > 0) {
bitmap.setPixels(outBuffer.bits);
} else {
// be safe with an empty bitmap.
bitmap.setPixels(NULL);
}
Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
nativeCanvas->setBitmap(bitmap);
if (dirtyRectPtr) {
nativeCanvas->clipRect(dirtyRect.left, dirtyRect.top,
dirtyRect.right, dirtyRect.bottom);
}
if (dirtyRectObj) {
env->SetIntField(dirtyRectObj, gRectClassInfo.left, dirtyRect.left);
env->SetIntField(dirtyRectObj, gRectClassInfo.top, dirtyRect.top);
env->SetIntField(dirtyRectObj, gRectClassInfo.right, dirtyRect.right);
env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
}
// Create another reference to the surface and return it. This reference
// should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
// because the latter could be replaced while the surface is locked.
sp<Surface> lockedSurface(surface);
lockedSurface->incStrong(&sRefBaseOwner);
return (jlong) lockedSurface.get();
}

这个方法的主要作用如下:

  • 将之前创建的C++层的Surface对象的句柄还原为Surface指针
  • 根据Java层传递的数据获取脏区域的left,top,right,bottom这四个角点的数值,从而得到矩形的大小和位置
  • 调用Surface的lock()方法,将申请的图形缓冲区赋值给outBuffer,这个lock()方法涉及到的东西非常多,后面将会详细分析
  • 通过bitmap.setPixels(outBuffer.bits)将ANativeWindow_Buffer中的bits传递给SkBitmap对象,其中bits即为图形缓冲区的首地址。SkCanvas之后就可以通过这个首地址来输出UI数据了
  • 创建一个Skbitmap对象,并且填充它的图形缓冲区,最终赋值给Java层的Canvas对象
  • 将剪裁位置大小信息赋值给java层的inOutDirty这个Rect对象

至此,drawSoftware()方法中canvas = mSurface.lockCanvas(dirty);这个调用就分析完了。为了搞清楚ANativeWindow_Buffer的来源,下面开始分析Surface的lock方法。

C++层的Surface::lock()方法

Surface::lock()方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
status_t Surface::lock(
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
...
ANativeWindowBuffer* out;
int fenceFd = -1;
status_t err = dequeueBuffer(&out, &fenceFd);
ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
const Rect bounds(backBuffer->width, backBuffer->height);
Region newDirtyRegion;
if (inOutDirtyBounds) {
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
newDirtyRegion.andSelf(bounds);
} else {
newDirtyRegion.set(bounds);
}
// figure out if we can copy the frontbuffer back
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
const bool canCopyBack = (frontBuffer != 0 &&
backBuffer->width == frontBuffer->width &&
backBuffer->height == frontBuffer->height &&
backBuffer->format == frontBuffer->format);
if (canCopyBack) {
// copy the area that is invalid and not repainted this round
const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
if (!copyback.isEmpty())
copyBlt(backBuffer, frontBuffer, copyback);
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
newDirtyRegion.set(bounds);
mDirtyRegion.clear();
Mutex::Autolock lock(mMutex);
for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
mSlots[i].dirtyRegion.clear();
}
}
{ // scope for the lock
Mutex::Autolock lock(mMutex);
int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
if (backBufferSlot >= 0) {
Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
mDirtyRegion.subtract(dirtyRegion);
dirtyRegion = newDirtyRegion;
}
}
mDirtyRegion.orSelf(newDirtyRegion);
if (inOutDirtyBounds) {
*inOutDirtyBounds = newDirtyRegion.getBounds();
}
void* vaddr;
status_t res = backBuffer->lockAsync(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr, fenceFd);
ALOGW_IF(res, "failed locking buffer (handle = %p)",
backBuffer->handle);
if (res != 0) {
err = INVALID_OPERATION;
} else {
mLockedBuffer = backBuffer;
outBuffer->width = backBuffer->width;
outBuffer->height = backBuffer->height;
outBuffer->stride = backBuffer->stride;
outBuffer->format = backBuffer->format;
outBuffer->bits = vaddr;
}
}
return err;
}

这个方法的主要工作为:

  • 调用dequeueBuffer()函数获取图形缓冲区
  • 计算需要绘制的dirty区域,旧的区域则只需copy数据即可

其实注释都已经写得很清楚了,就是将需要更新的dirty区域剪裁出来,剩余不需要更新的区域则不用重绘。在大部分情况下,UI只有一小部分发生变化(如点击按钮时,按钮颜色发生变化),这一小部分UI只对应整个GraphicBuffer中的一小块存储(即代码中的dirtyRegion),如果此时所有区域都更新,则会造成很大的资源浪费。

此时就需要将变化的图像和没有发生变化的图像进行叠加,上一次绘制的信息保存在mPostedBuffer中,而这个mPostedBuffer则要在unLockAndPost函数中设置。这里将根据需要,将mPostedBuffer中的旧数据copy到BackBuffer中。后续的绘画只需要更新脏区即可。

  • lock和unlock分别用来锁定和解锁一个指定的图形缓冲区,在访问一块图形缓冲区的时候,例如,向一块缓冲区写入内容的时候,需要将该图形缓冲区锁定,用来避免访问冲突,锁定之后,就可以确定缓冲区的起始地址,并保存在vaddr中。在访问完一场图形缓冲区之后,需要解锁它。

图形缓冲区的分配

Surface的dequeueBuffer()方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
...
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero,
reqWidth, reqHeight, reqFormat, reqUsage);
...
Mutex::Autolock lock(mMutex);
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
...
if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
freeAllBuffers();
}
...
*buffer = gbuf.get();
return OK;
}

显然,这个方法是通过调用IGraphicBufferProducer对象(其实是BpGraphicBufferProducer对象,在前面分析过)的dequeueBuffer()方法来获得图形缓冲区,如果没有找到空闲的缓冲区,就需要调用mGraphicBufferProducer->requestBuffer(buf,&gbuf);从匿名共享内存中重新分配。

显然,这里会通过跨进程调用到BufferQueueProducer::dequeueBuffer()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
sp<android::Fence> *outFence, bool async,
uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) {
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked();
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// Enable the usage bits the consumer requested
usage |= mCore->mConsumerUsageBits;
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
}
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
&found, &returnFlags);
if (status != NO_ERROR) {
return status;
}
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
// If we are not allowed to allocate new buffers,
// waitForFreeSlotThenRelock must have returned a slot containing a
// buffer. If this buffer would require reallocation to meet the
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
if (buffer->needsReallocation(width, height, format, usage)) {
mCore->freeBufferLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mAttachedByConsumer;
mSlots[found].mBufferState = BufferSlot::DEQUEUED;
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if ((buffer == NULL) ||
buffer->needsReallocation(width, height, format, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->mBufferAge = 0;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
} else {
// We add 1 because that will be the frame number when this buffer
// is queued
mCore->mBufferAge =
mCore->mFrameCounter + 1 - mSlots[found].mFrameNumber;
}
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
*outFence = mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
mCore->validateConsistencyLocked();
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
width, height, format, usage, &error));
if (graphicBuffer == NULL) {
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
if (eglFence != EGL_NO_SYNC_KHR) {
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
if (result == EGL_FALSE) {
BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
eglGetError());
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
BQ_LOGE("dequeueBuffer: timeout waiting for fence");
}
eglDestroySyncKHR(eglDisplay, eglFence);
}
return returnFlags;
}

这个方法虽然看起来很长,但是其实很简单,就是根据指定的index取出mSlots中的slot中的buffer,然后让buf指向它。

Surface.unlockCanvasAndPost()方法分析

Surface.unlockCanvasAndPost()方法如下:

1
2
3
4
5
6
7
8
9
10
11
public void unlockCanvasAndPost(Canvas canvas) {
synchronized (mLock) {
checkNotReleasedLocked();
if (mHwuiContext != null) {
mHwuiContext.unlockAndPost(canvas);
} else {
unlockSwCanvasAndPost(canvas);
}
}
}

由于我们这里只分析非硬件加速的情况,所以执行unlockSwCanvasAndPost()方法:

1
2
3
4
5
6
7
8
9
private void unlockSwCanvasAndPost(Canvas canvas) {
...
try {
nativeUnlockCanvasAndPost(mLockedObject, canvas);
} finally {
nativeRelease(mLockedObject);
mLockedObject = 0;
}
}

没啥好说的,就是jni调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
if (!isSurfaceValid(surface)) {
return;
}
// detach the canvas from the surface
Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
nativeCanvas->setBitmap(SkBitmap());
// unlock surface
status_t err = surface->unlockAndPost();
if (err < 0) {
doThrowIAE(env);
}
}

这个方法的主要作用为:

  • 获取java层保存的Surface句柄,还原为Surface指针
  • 解除java层对native层的SkBitmap对象的引用