Transaction是应用与SurfaceFlinger交流的方式之一,应用通过打开一个Transaction,然后设置各种setXXX操作,最后通过apply把所有的设定操作提交给SurfaceFlinger进行处理。
Transaction最常用的使用方法(套路)一般如下:
Transaction t;
t.setLayer(mSurfaceControl, 0x7fffffff)
.show(mSurfaceControl)
.apply();
Java层的Transaction定义位于base\core\java\android\view\SurfaceControl.java文件中。先来看Transaction提供了不同类型的构造函数,做开发者在不同的场景使用。
public Transaction() { // 由系统自动生成一个全新的Transaction
this(nativeCreateTransaction());
}
private Transaction(long nativeObject) { // 根据nativeObject生成一个Transaction,这里nativeObject指一个已经存在的Trnansaction对象
mNativeObject = nativeObject;
mFreeNativeResources = sRegistry.registerNativeAllocation(this, mNativeObject); // 这里主要用于内存Transaction管理,不需要重点关注
}
private Transaction(Parcel in) { // 根据一个已经存在的Parcel对象创建一个Transaction对象
readFromParcel(in);
}
对应Native侧C++的实现分别为:
// 第一种方式,创建一个全新的Transaction
SurfaceComposerClient::Transaction::Transaction() {
mId = generateId(); // 自动生成一个Transaction id
}
std::atomic<uint32_t> idCounter = 0; // 查看aosp代码可知,idCounter代表系统已经创建过的Transaction数量
int64_t generateId() {
return (((int64_t)getpid()) << 32) | ++idCounter;
}
// 第二种方式,根据已经一个已有的Transaction对象生成一个新的Trnasaction对象
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
: mId(other.mId),
mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
mEarlyWakeupStart(other.mEarlyWakeupStart),
mEarlyWakeupEnd(other.mEarlyWakeupEnd),
mContainsBuffer(other.mContainsBuffer),
mDesiredPresentTime(other.mDesiredPresentTime),
mIsAutoTimestamp(other.mIsAutoTimestamp),
mFrameTimelineInfo(other.mFrameTimelineInfo),
mApplyToken(other.mApplyToken) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
mListenerCallbacks = other.mListenerCallbacks;
}
// 第三种方式,根据parcel传递过来的信息创建一个新的Transaction对象
std::unique_ptr<SurfaceComposerClient::Transaction>
SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
auto transaction = std::make_unique<Transaction>();
if (transaction->readFromParcel(parcel) == NO_ERROR) {
return transaction;
}
return nullptr;
}
status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
const uint32_t forceSynchronous = parcel->readUint32();
// ......
sp<IBinder> applyToken;
parcel->readNullableStrongBinder(&applyToken);
// ......
mApplyToken = applyToken;
return NO_ERROR;
}
下面重点来看Transaction都可以做哪些事情,即setXXX方法都有哪些。
1. Display相关的
操作 | 入参 | 说明 |
---|---|---|
setDisplayDecoration | 指定surface是否需要使用display decoration optimizations,主要是让SystemUI圆角走硬件RC通道 | |
setDisplayFlags | 指定display的一些flags标记,这些flag都是display相关的,不是surface相关的 | |
setDisplayLayerStack | 指定display上显示哪个layerStack | |
setDisplayProjection | * orientation:指定屏幕的方向 * layerStackRect:窗口坐标系中的一块区域 * display:指定屏幕上的一块区域,这个区域是旋转orientation后的 |
指定将layersStackRect区域以orientation方向投影到屏幕的displayRect区域 |
setDisplaySize | 指定屏幕的宽和高 | |
setDisplaySurface | 指定屏幕上显示哪个Surface |
备注:
- LayerStack是一个标识,用于唯一标识一组按z轴大小排序的layer的集合,一个layer只能被绑定到一个LayerStack中,但一个LayerStack可以关联到多个Display中,即多个Display显示同一个LayersStack的layers,也就是这些display显示的内容是完全一样的,镜像的。
2. Surface相关的
2.1 setBuffer
setBuffer有4个重载函数
- setBuffer(SurfaceControl sc, GraphicBuffer buffer)
- setBuffer(@NonNull SurfaceControl sc, @Nullable HardwareBuffer buffer)
- setBuffer(@NonNull SurfaceControl sc, @Nullable HardwareBuffer buffer, @Nullable SyncFence fence)
- setBuffer(@NonNull SurfaceControl sc, @Nullable HardwareBuffer buffer, @Nullable SyncFence fence, @Nullable Consumer
releaseCallback)
4个函数的作用均为更新surface要显示的buffer,但存在如下差异:
- 第(1)个只能用于类型为FX_SURFACE_BLAST的SurfaceControl。
- 第(2)个函数中,该buffer只能以HardwareBuffer#USAGE_COMPOSER_OVERLAY类型进行申请,而以HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE申请的buffer会可能会走GPU合成。
- 第(3)个函数与第(2)函数要求相同,但多了一个fence参数,如果fence参数为空或无效,则与第(2)个函数功能完全相同。该函数在设置要显示的buffer的同时,传入了一个presentation fence参数,主要目的是为了提升性能体验。指定了有效的fence参数后,只有等GPU完成了该Buffer的绘制后,这个transaction才能被SurfaceFlinger处理,否则SurfaceFlinger会一起等待,一起等到GPU绘制完成或者等待超时。例如,假设应用该buffer连同fence(该fence由android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)创建)一同传递给GPU进行处理,即允许transaction的下发和Buffer内容的绘制可以同时并行进行,合成器则需要等待该fence被signaled后才会将该Buffer进行合成送给Display进行显示。如果在同一个transaction中指定了多个Buffer,则在合成器合成送显之前,这些buffer的fence必须都被signaled后,合成器才能进行这一次的送显操作,主要目的是为了保证同步处理,即保证这些buffer是在一帧中被处理并送显的。
- 第(4)个函数在第(3)个函数的基础上,又加了一个releaseCallback参数。releaseCallback的主要目的是让producer知道什么可以可以放心重复使用该Buffer,这种用法主要是用于连续使用transaction进行setBuffer的操作场景场景。应用端想重复使用这个buffer,则必须等待该releaseCallback函数被SurfaceFlinger回调后(,此时表明该buffer已经在服务端处理完成并释放掉了)。换句话讲,即应用端可以通过releaseCallback回调函数知道该buffer何时被SurfaceFlinger处理完成了,以此为基础来做一些其他事情。
2.2 setFrameRate
- setFrameRate(@NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate, @Surface.FrameRateCompatibility int compatibility)
- setFrameRate(@NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate, @Surface.FrameRateCompatibility int compatibility, @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy)
- setFrameRateSelectionPriority(@NonNull SurfaceControl sc, int priority)
现今的手机产品,一般都会支持多个不同的刷新率,如60Hz,90Hz,120Hz及144Hz等。一般情况下,系统会根据不同的场景来选择合适的刷新率。改变刷新率,意思着改变了帧间隔时长,这样一般会影响Choreographer的回调节奏,但对于media codec这种则没有任何影响。
这三个函数是应用设置刷新率相关的,简单说明如下:
- 第(1)个setFrameRate设定该surface预期的刷新速率(或帧率),compatibility表示surface指定的帧率如何与系统当前的帧率兼容,一般有两种方式:FRAME_RATE_COMPATIBILITY_DEFAULT表示不需要继承当前surface的限制,当系统选择了app请求之外的刷新率时,app会以系统选择的刷新率继续运行,该模式一般用于游戏和普通UI场等非Video场景;RAME_RATE_COMPATIBILITY_FIXED_SOURCE模式表示surface的内容应该控制固定frame rate进行显示,如video一般是固定刷新率,当系统选择了app指定之外的刷新率时,app需要pull down或采取一些其他措施来适应系统的刷新节奏,可能会出现长短帧的情况,用户体验不好,该模式主要适用于video场景。还有一种只有系统有权限使用的模式FRAME_RATE_COMPATIBILITY_EXACT,表示当前surface属于高刷新黑名单,需要系统确定采用某个刷新率进行刷新。
- 第(2)个在第(1)基础上又添加了一个ChangeFrameRateStrategy参数,该参数表示该surface请求的帧率变更是否是无疑平滑切换的(无视觉中断的),用户不可感知的,若frameRate参数为0,则此参数无效。frameRate参数为0时,表示app会接受系统的帧率决策,如果应用未调用此接口,则默认策略即是如此。
2.3 其他函数
操作 | 入参 | 说明 |
---|---|---|
setAlpha | 指定surface的alhpa值,如果alpha值大于0,系统会根据alpha值将该surface会与其(z轴)下面的surface进行混合处理 | |
setAnimationTransaction | 指定此transaction为一个动画transaction,暂未研究SurfaceFlinger如何处理animaton transaction | |
setBackgroundBlurRadius | 设定模糊背景的半径范围 | |
setBlurRegions | 指定surface的哪个区域应该做模糊处理 | |
setBufferSize | 指定默认buffer大小,如果SurfaceControl关联了一个surface,即buffer的默认大小即为dequeue出来的大小(surface的大小) | |
setBufferTransform | 设置buffer的转换矩阵,与AttachedSurfaceControl#addOnBufferTransformHintChangedListener配合使用,可实现根据display orientation方向对buffer进行预旋转,避免在合成阶段再进行旋转,可减少GPU合成的概率,提升性能体验 | |
setColor | float[] color,三个元素的float数组,分别表现R、G、B | 使用指定颜色填充Surface,若颜色值无效,则取消颜色填充 |
setColorSpace | 设定SurfaceControl的颜色空间,当前支持的颜色空间为SRGB和Display P3,其他的颜色空间会被当作SRGB处理,此参数只能使用于FX_SURFACE_BLAST类型SurfaceControl | |
setColorSpaceAgnostic | 设定surface的颜色空间不确定,若一个surface的颜色空间不确定,则其颜色在任何颜色空间都可以被解析 | |
setColorTransform | matrix为一个3x3的矩阵 translation为3个元素的vector |
设定surface的颜色转换矩阵,在SurfaceComposerClient处会将这两个参数组合为一个4x4的矩阵colorTransform |
setCornerRadius | 设置SurfaceControl的圆角半径,半径的单位为pixcel | |
setCrop | 限制surface及其子图层在指定的Rect区域内。Surface的大小会被忽略掉,只有crop和buffer size会参与surface边界的计算;如果surface即未指定crp也没有buffer,则以其父图层的bounds为边界 | |
setDamageRegion | 更新surface的脏区(即内容发生变化的区域),当一帧画面中只有一部分发生变化时,可以通过该函数指定脏区,这样在合成阶段只合成这一区域的内容,减少合成时的负载,典型场景如闪烁的光标或loading indicator。如果没有脏区为null,则相当于没有指定脏区,则会合成整个画面 | |
setDataSpace | 设定SurfaceControl的dataspace,这会决定(使用setBuffer(SurfaceControl, HardwareBuffer)设置的)buffer如何被显示出来 | |
setDestationFrame | SurfaceControl sc, @NonNull Rect destinationFram | |
setDestationFrame | SurfaceControl sc, int width, int height | |
setDimmingEnabled | 设定layer的亮度是否可以调节,默认值为true,表示layer的亮度可调。禁用此项,则强制layer的亮度不可调,如layer的白色像素与屏幕亮度一致。 | |
setDropInputMode | 指定SurfaceControl的input事件的drop mode,有三种模式:NONE,ALL,OBSCURED | |
setEarlyWakeStart | 通知SurfaceFlinger接下下来的合成任务比较繁重,需要改变其offset,提前开始合成工作,尽可能的多留一些时间给合成过程 | |
setEarlyWakeEnd | 与setEarlyWakeStart作用相反,参考 | |
setEarlyWakeStart | 通知SurfaceFlinger接下下来的合成任务比较繁重,需要改变其offset,提前开始合成工作,尽可能的多留一些时间给合成过程 | |
setFixedTransformHint | 当layer及其子layer的方向与屏幕方向不一致时,由graphic producer指定一个固定的旋转hint。在不需要旋转固定方向时,调用者需要负责清理掉这个hint。当layer旋转时,这个transform hint用于防止分配一个不同大小的buffer。消费者可以选择指定这个hint以分配相同大小的buffer | |
setFocusedWindow | 指定窗口为当前的焦点窗口,当窗口状态为不可focusable时,系统会将这个请求缓存起来直到窗口变得可focusable或者被其他请求覆盖掉 | |
setFrameTimelineVsync | 设定从choreographer处接收到的的frame timeline的vsync id | |
setGeometry | 指定与surface关联的buffer如何被映射到父图层的坐标系中,在根据orientation指定的方向进行旋转后,系统会对source frame进行缩放操作以适配destination frame | |
setInputWindowInfo | 设定输入窗口相关的info | |
setLayer | 指定surfaceControl相对于其同级图层的z-order,若两个同级图层的z order相同且未定义,则z order为负数的surface会显示在其父surface下面 | |
setLayerStack | 指定surfacecontrol上的LayerStack | |
setMarix | 设置SurfaceControl的Matrix,一般为dsdx,dtdx,dtdy,dsdy | |
setMetadata | 设定surface的Metadata | |
setOpaque | 指定surface是否为不透明的,即使pixel format被设置为translucent。该参数用于决定是否从 alpha通道采样不透明数据。调用setAlpha()函数设置的Plane-alpha仍然会影响合成时的混合效果,而不会考虑opaque设置。如果底层buffer无alpha channel,则相当于自动调用了setOpaque(true)。 | |
setPosition | 指定SurfaceControl相对于其父节点的位置 | |
setRelativelayer | 指定SurfaceControl相对参考目标 | |
setScale | 指定SurfaceControl基于(0,0)点进行大小缩放的倍数 | |
setSecure | 指定该surface是否为安全图层,安全图层截图和屏幕均不可见 | |
setShadowRadius | 指定surface周边绘制阴影的长度(阴影半径),若为0,则不绘制阴影。如果surface的圆角半径小于在screen bounds内,以阴影大小以圆角半径为准。阴影效果只能合适用有buffer的图层和color图层。如果在一个container图层上设置了radius参数,则会向下传递下一级的buffer或color图层,而不是传递给其子图层。 | |
setSkipScreenshot | ||
setStretchEffect | ||
setTransparentRegionHint | ||
setTrustedOverlay | ||
setVisibility | ||
setWindowCrop | ||
unsetColor | ||
unsetFixedTransformHint |
备注:
- 针对OPAQUE和alpha对合成的影响:
- OPAQUE + alpha(1.0) == opaque composition
- OPAQUE + alpha(0.x) == blended composition
- OPAQUE + alpha(0.0) == no composition
- !OPAQUE + alpha(1.0) == blended composition
- !OPAQUE + alpha(0.x) == blended composition
- OPAQUE + alpha(0.0) == no composition