前言
设想这样一个需求:在屏幕上显示一个浮窗视图。程序员一般会写下如程序:
WindowManager mWindowManager = (WindowManager)getSystemService(WindowManager.class);
WindowManager.LayoutoutParms lps= new WindowManager.LayoutParms(**);
lps.x =100;
lps.y = 100;
lps.token = new Binder();
View view = LayoutInflater.from(**)inflate(**);
mWindowManager.addView(view,lps)
完工,So easy。作为一名有追求的程序员,刨根问底少不了:这个流程究竟是怎么工作。于是乎网上找资源,打断点、打日志,阅读代码,一顿操作下来也是云里雾里。这个时候一般就会十万个为什么了,其中一个或许是这样的:
有没有一个更精简的程序,可以实现上图的基本功能,哪怕只是实现一个纯色视图,精简流程,方便我们熟悉整个流程。
回答当然是 yes。
一、SurfaceControl绘制
上述代码为应用层代码,整个调用流程涉及到多个系统服务、调用了多个系统库,例如WindowManagerService、SurfaceFlineger、Skia图形库等。探索这段调用过程,很容易走向放弃,原因之一笔者认为是由于抓不住流程的主干,受困于android海量代码,受困于对android分层思想理解不够深刻。下面从SurfaceFlinger代理服务作为中间件切入,通过几行代码实现了纯色浮窗效果。
示例代码如下所示(Android软件环境为Android 11):
static const int LAYER_BASE = INT32_MAX - 10;
struct Color {
public:
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
constexpr static Color RED = {195, 63, 63, 255};
constexpr static Color BLUE = {63, 63, 195, 255};
namespace android{
using Transaction = SurfaceComposerClient::Transaction;
class SurfaceControlTest{
public:
SurfaceControlTest() {
//方法1:创建SurfaceComposerClient
mComposerClient = new SurfaceComposerClient;
if(NO_ERROR!=mComposerClient->initCheck()){
return;
}
//方法2:创建SurfaceControl
mSurfaceControl = mComposerClient->createSurface(String8("SurfaceControl Test"), 500, 500,
PIXEL_FORMAT_RGBA_8888, 0);
}
void fillSurfaceRGBA8(const Color& color,
bool unlock = true) {
ANativeWindow_Buffer outBuffer;
sp<Surface> surface = mSurfaceControl->getSurface();
//方法3
surface->lock(&outBuffer, NULL);
//方法4
uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
for (int y = 0; y < outBuffer.height; y++) {
for (int x = 0; x < outBuffer.width; x++) {
uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
pixel[0] = color.r;
pixel[1] = color.g;
pixel[2] = color.b;
pixel[3] = color.a;
}
}
if (unlock) {
//方法5
surface->unlockAndPost();
}
}
void tearDown(){
mComposerClient->dispose();
}
void fillSurfaceColor(){
}
public:
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mSurfaceControl;
};
}
int main(){
android::SurfaceControlTest sc;
sc.fillSurfaceRGBA8(RED,true);
usleep(5000000);
sc.fillSurfaceRGBA8(BLUE,true);
usleep(5000000);
sc.tearDown();
return 1;
}
代码运行效果图如下所示:
SurfaceControl测试效果图
示例代码通过5步实现了如上所示的效果。主要是对SurfaceFlinger代理类SurfaceControl进行操作。方法3、方法5对View绘制有一定了解的小伙伴应该不陌生,方法4是对数据进行填充。
SurfaceControl作为SurfaceFlinger代理类在android Framework UI绘制做了承上启下的作用:上接android UI Framework,下接SurfaceFlinger。
二、SurfaceControl上层类
本节简要介绍SurfaceControl直接对接上层类:ViewRootImpl。这里我们摘取ViewRootImpl中CPU绘制的部分代码:
//frameworks/base/core/java/android/view/ViewRootImpl.java
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
...
//步骤1:Surface进行lock操做
canvas = mSurface.lockCanvas(dirty);
...
//步骤2:调用了ViewGroup的 draw 方法
mView.draw(canvas);
...
//步骤3:数据发送给 SurfaceFlinger
surface.unlockCanvasAndPost(canvas);
}
步骤1,步骤3后续会调用native代码:
//frameworks/base/core/jni/android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
...
ANativeWindow_Buffer buffer;
status_t err = surface->lock(&buffer, dirtyRectPtr);
...
}
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
...
// unlock surface
status_t err = surface->unlockAndPost();
...
}
surface->lock(),*surface->unlockAndPost()*与C++程序方法3,方法5一致。
步骤2(作用类似C++程序方法4)流程比较复杂,调用二维图形库Skia,这里不做赘述。下面附录一张时序图,简要描述这个流程。
总结
一个简单的C++程序到这里就介绍完了。本节简要介绍了SurfaceControl,下一章笔者将从WindowManager.addView()这个方法开始,梳理View创建过程。