Layer创建流程

news2024/11/25 6:34:30

在SurfaceFlinger中,Layer表示一个显示图层,是surfaceflinger合成过程中最重要的基本单元,它提供了一系列属性定义了如何参与合成并与其他Layer交互,包括:

  • 位置:定义Layer出现在屏幕上的位置,包括Layer边缘、Zorder等......

  • 内容:定义Layer上的内容如何显示,包括裁剪(缩小/放大)、转置(旋转/翻转)......

  • 合成:定义Layer如何和其他Layer进行合成,包括混合模式、透明度等......

  • 优化:提供了一些非必要但可用于HWC优化合成的属性,包括visible region等......

同时,Layer具有树结构,子Layer可以继承父Layer的属性。

在之前文章中简单介绍过SurfaceControl,SurfaceControl是暴露给外部进程用于操作surfaceflinger进程中Layer的句柄,它定义了图形缓冲数据、元数据、大小等多个属性,来描述如何显示一个Layer。当实例化一个SurfaceControl时,便会存在一个对应的Layer,并且将持有这个Layer的句柄(LayerHandle),通过LayerHandle管理Layer的保留和销毁。 但需要注意的是,SurfaceControl并非跟Layer是一一对应关系,可以存在多个SurfaceControl对应一个Layer,这取决与SurfaceControl的创建方式。

SurfaceControl和Layer的创建过程表示如下:

从整个图形显示架构来看,应用进程的View内容,实际是在Surface上进行绘制,这个Surface通过BLASTBufferQueue跟SurfaceControl关联,并通过Transaction将图形数据传递给surfaceflinger中对应的Layer进行合成和显示。

同时,SurfaceControl在system_server进程Window Manager中通过WindowState管理,进入surfaceflinger后便以Layer的形式进行处理。

从Android U开始,对surfaceflinger进行了较大重构,引入了"SurfaceFlinger FrontEnd"概念,对“客户端”和本地内的流程和类进行了解偶,以提升可维护性、扩展性以及性能。

"SurfaceFlinger FrontEnd"主要包括三方面:

  • 事务处理;

  • Layer状态及生命周期管理;

  • CompositionEngine快照生成(LayerFE + LayerSnapshot)。

比如,Android U之前Layer对象即作为客户端设置数据的载体,给surfaceflinger中传递buffer,又参与到合成阶段,耦合严重,且不利于扩展。通过FrontEnd重构后,对这部分流程进行解耦,解除了Layer和LayerFE之间的继承关系:

  • Layer只负责"客户端"相关性高的任务;

  • LayerFE则参与到合成阶段,进行合成相关任务。

本篇文章将从SurfaceControl的创建开始,了解Layer的整体创建过程,以及了解一些重要类的使用。


一、相关类结构

客户端进程创建SurfaceControl时创建Layer,而Layer由surfaceflinger创建,因此Layer的创建过程是跨进程的操作,涉及到的跨进程所需要的类如下图所示:

  • SurfaceControl:SurfaceControl是暴露给外部进程用于操作surfaceflinger进程中Layer的句柄,它定义了图形缓冲数据、元数据、大小等多个属性,来描述如何显示一个Layer。

  • SurfaceComposerClient:作为surfaceflinger进程和应用进程间进行IPC交互的“中间件”,内部持有IPC服务实例,用于向SurfaceFlinger中发起交互;

  • Client:实现了gui::ISurfaceComposerClient接口的IPC类,也可以和surfaceflinger进行跨进程交互,在SurfaceComposerClient对象初始化时,由SurfaceComposerAIDL::createConnection()方法创建获取;

  • ComposerService:ISurfaceComposer的包裹类,持有ISurfaceComposer实现对象,负责和surfaceflinger进程的ISurfaceComposer接口进行IPC连接;

  • ComposerServiceAIDL:gui::ISurfaceComposer的包裹类,持有gui::ISurfaceComposer实现对象,负责和surfaceflinger进程的ISurfaceComposerAIDL接口进行IPC连接。

Layer相关类结构如下:

  • compositionengine::LayerFECompositionState:包含了合成过程中供CompositionEngine使用的所有Layer状态;

  • surfaceflinger::frontend::LayerSnapshot:继承于compositionengine.LayerFECompositionState,LayerFECompositionState引用的实际类型,用于保存合成过程中LayerFE和Layer的状态;

  • compositionengine.LayerFE:LayerFE实现的接口类;

  • LayerFE:表示一个"前端"Layer,跟Layer相对应,用于处理Layer在合成阶段的工作;

  • LayerCreationArgs:封装客户端传入的创建Layer所需的属性和其他组件;

  • Layer.State:保存Layer的状态;

  • LayerHandle:Layer句柄,用于传递给客户端,对Layer进行更新和销毁,在SurfaceFlinger中不会持有任何LayerHandle引用。

  • LayerCreatedState:持有Layer、Layer parent弱引用的一个封装类,用于在Layer创建过程中将Layer添加到对应的树结构上;

二、创建SurfaceControl实例

创建SurfaceControl实例,有三种方式:

  • 通过SurfaceControl.Builder构造类创建;

  • 通过SurfaceControl.copyFrom(SurfaceControl sc)拷贝创建;

  • SurfaceContrl实现了Parceable接口,通过SurfaceControl(Parcel in)构造方法创建,用于IPC场景;

其中第一种方式会创建新的SurfaceControl和Layer对象,后两种方式相当于在已创建SurfaceControl对象上拷贝了一份副本,内部共享同一个Layer。

2.1、SurfaceControl.Builder构造器

SurfaceControl.Builder用于创建SurfaceControl对象,如:

// frameworks/base/services/core/java/com/android/server/display/ColorFade.java

// 获得一个SurfaceControl.Builder实例,并填充属性
final SurfaceControl.Builder builder = new SurfaceControl.Builder()
        .setName("ColorFade")
        .setSecure(isSecure)
        .setCallsite("ColorFade.createSurface");

// 获得SurfaceControl实例
SurfaceControl mSurfaceControl = builder.build();

通过SurfaceControl.Builder可以为待创建的SurfaceControl设置属性,如:

// 设置SurfaceControl名称
Builder setName(@NonNull String name)
// 设置buffer大小
Builder setBufferSize(@IntRange(from = 0) int width, @IntRange(from = 0) int height) 
// 设置像素格式
Builder setFormat(@PixelFormat.Format int format)
// 设置是否是受保护内容
Builder setProtected(boolean protectedContent) 
// 设置是否是安全内容
Builder setSecure(boolean secure)
// 设置是否不透明
Builder setOpaque(boolean opaque)
// 设置初始状态是否隐藏
Builder setHidden(boolean hidden)
// 设置父容器
Builder setParent(@Nullable SurfaceControl parent)
// 设置元数据
Builder setMetadata(int key, int data)
// 设置调用地址(用于Debug)
Builder setCallsite(String callsite)
// 设置为EffectLayer
Builder setEffectLayer()
// 设置标记值
Builder setFlags(int flags, int mask)

设置完成后通过SurfaceControl.Builder.build()方法创建SurfaceControl对象:

// frameworks/base/core/java/android/view/SurfaceControl.java

public SurfaceControl build() {
    ......
    return new SurfaceControl(
            mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
            mLocalOwnerView, mCallsite);
}

2.2、SurfaceControl()构造方法

SurfaceControl构造方法如下:

// frameworks/base/core/java/android/view/SurfaceControl.java
/**
* @param session  即是否需要指定SurfaceComposerClient对象,不指定使用默认SurfaceComposerClient
* @param name     Layer名称
* @param w        Layer宽
* @param h        Layer高
* @param flags    Layer标记
* @param metadata Initial metadata.
* @param callsite 调用地址,用于debug
*/
private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
        SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
        String callsite)
                throws OutOfResourcesException, IllegalArgumentException {
    ......
    // SurfaceControl名称
    mName = name;
    mWidth = w;     // 宽
    mHeight = h;    // 高
    mLocalOwnerView = localOwnerView;    // 持有该SurfaceControl的View弱引用,可为null
    // 将元数据map填充到metaParcel中
    Parcel metaParcel = Parcel.obtain();
    long nativeObject = 0;
    try {
        if (metadata != null && metadata.size() > 0) {
            metaParcel.writeInt(metadata.size());
            for (int i = 0; i < metadata.size(); ++i) {
                metaParcel.writeInt(metadata.keyAt(i));
                metaParcel.writeByteArray(
                        ByteBuffer.allocate(4).order(ByteOrder.nativeOrder())
                                .putInt(metadata.valueAt(i)).array());
            }
            metaParcel.setDataPosition(0);
        }
        // 进入JNI层创建对象
        nativeObject = nativeCreate(session, name, w, h, format, flags,
                parent != null ? parent.mNativeObject : 0, metaParcel);
    } finally {
        metaParcel.recycle();
    }
    if (nativeObject == 0) {
        throw new OutOfResourcesException(
                "Couldn't allocate SurfaceControl native object");
    }
    // 保存native对象地址
    assignNativeObject(nativeObject, callsite);
}

在以上方法中:

  1. 进行了部分全局变量初始化后,便调用nativeCreate()方法进入native层,创建native层对应的实例;

  2. 在native层创建完成Layer对象和native层SurfaceControl对象后,会返回SurfaceControl地址nativeObject,nativeObject将作为调用句柄,用于后续跟Layer的数据传递;

  3. 通过assignNativeObject()方法,将JVM中的Java对象和native层内存空间绑定,以便当Java层对象内存释放时,同步释放native层内存。

下面我们进入JNI中的流程。

2.2.1、执行android_view_SurfaceControl::nativeCreate()

JNI层对应nativeCreate()方法如下:

// frameworks/base/core/jni/android_view_SurfaceControl.cpp

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jobject metadataParcel) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client;
    // 获取SurfaceComposerClient对象
    // 如果传入SurfaceSession不为空,则从SurfaceSession中获取SurfaceComposerClient
    if (sessionObj != NULL) {
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
        // 否则,获取新的SurfaceComposerClient
        client = SurfaceComposerClient::getDefault();
    }
    
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface;
    LayerMetadata metadata;
    // 解析并校验MetaData数据格式
    Parcel* parcel = parcelForJavaObject(env, metadataParcel);
    if (parcel && !parcel->objectsCount()) {
        status_t err = metadata.readFromParcel(parcel);
        if (err != NO_ERROR) {
          jniThrowException(env, "java/lang/IllegalArgumentException",
                            "Metadata parcel has wrong format");
        }
    }

    sp<IBinder> parentHandle;
    // 如果传入parent不为空,获取parent对应的handle值
    if (parent != nullptr) {
        parentHandle = parent->getHandle();
    }
    // 开始创建native SuraceControl对象
    status_t err = client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface,
                                                flags, parentHandle, std::move(metadata));
    .......
    // 引用计数+1
    surface->incStrong((void *)nativeCreate);
    // 返回surface地址
    return reinterpret_cast<jlong>(surface.get());
}

以上方法中:

  1. 根据SurfaceSession参数获得SurfaceComposerClient实例;

  2. 通过SurfaceComposerClient::createSurfaceChecked()创建native层SurfaceControl对象;

  3. 在创建完成后,返回SurfaceControl的地址给Java层。

2.2.2.1、创建SurfaceComposerClient实例

SurfaceComposerClient作为surfaceflinger进程和应用进程间进行IPC交互的“中间件”。如果创建SurfaceControl时携带有SurfaceSession,则从SurfaceSession中获取SurfaceComposerClient实例,否则通过SurfaceComposerClient::getDefault()方法以单例的方式获取实例:

// frameworks/native/libs/gui/SurfaceComposerClient.cpp

class DefaultComposerClient: public Singleton<DefaultComposerClient> {
    ......
public:
    static sp<SurfaceComposerClient> getComposerClient() {
        DefaultComposerClient& dc = DefaultComposerClient::getInstance();
        Mutex::Autolock _l(dc.mLock);
        if (dc.mClient == nullptr) {
            dc.mClient = new SurfaceComposerClient;
        }
        return dc.mClient;
    }
};
2.2.2.2、获取ISurfaceComposerClient实例

在进行SurfaceComposerClient对象创建时,会初始化它的一个全局变量SurfaceComposerClient::mClient,它是由surfaceflinger进程创建并返回的一个ISurfaceComposerClient接口对象,专门用于客户端和surfaceflinger进程间创建Layer是的IPC:

// frameworks/native/libs/gui/SurfaceComposerClient.cpp

SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
      : mStatus(NO_ERROR), mClient(client) {}

void SurfaceComposerClient::onFirstRef() {
    sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;
        // 从sf中创建并返回ISurfaceComposerClient
        binder::Status status = sf->createConnection(&conn);
        if (status.isOk() && conn != nullptr) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

SurfaceFlinger中对应的createConnection()方法如下:
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerClient>* outClient) {
    // 创建Client实例
    const sp<Client> client = sp<Client>::make(mFlinger);
    if (client->initCheck() == NO_ERROR) {
        *outClient = client;
        return binder::Status::ok();
    } else {
        ......
    }
}

2.2.2、执行SurfaceComposerClient::createSurfaceChecked()

获得SurfaceComposerClient实例后,将执行其createSurfaceChecked()方法:

// frameworks/native/libs/gui/SurfaceComposerClient.cpp

status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                     PixelFormat format,
                                                     sp<SurfaceControl>* outSurface, int32_t flags,
                                                     const sp<IBinder>& parentHandle,
                                                     LayerMetadata metadata,
                                                     uint32_t* outTransformHint) {
    sp<SurfaceControl> sur;

    if (mStatus == NO_ERROR) {
        // 用于保存创建结果相关参数
        gui::CreateSurfaceResult result;
        // 通过Client创建Layer
        binder::Status status = mClient->createSurface(std::string(name.string()), flags,
                                                       parentHandle, std::move(metadata), &result);
        err = statusTFromBinderStatus(status);
        if (outTransformHint) {
            *outTransformHint = result.transformHint;
        }

        // 创建SurfaceControl对象
        if (err == NO_ERROR) {
            *outSurface = new SurfaceControl(this, result.handle, result.layerId,
                                             toString(result.layerName), w, h, format,
                                             result.transformHint, flags);
        }
    }
    return err;
}

以上方法中:

  1. 通过mClient->createSurface()进入surfaceflinger中创建Layer实例;

  2. 创建Native层 SurfaceControl实例;

在创建Layer时,传递了一个gui::CreateSurfaceResult变量,用于保存创建结果相关参数。surfaceflinger中完成Layer创建后,会将创建后的Layer相关属性保存在gui::CreateSurfaceResult中:

// frameworks/native/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl

parcelable CreateSurfaceResult {
    IBinder handle;       // LayerHandle
    int layerId;          // Layer Id
    String layerName;     // Layer名称
    int transformHint;    // 
}

随后的native SurfaceControl对象创建时,就是通过gui::CreateSurfaceResult获得了Layer的相关数据后,建立了关联。

Layer实例的创建过程在surfaceflinger进程中,在下面单独这部分流程进行分析。这里先来看下Native层SurfaceControl的创建。

2.2.2.1、创建Native SurfaceControl实例

在Layer创建完成后,从gui::CreateSurfaceResult获得了LayerHandle、LayerId等属性,然后创建Native SurfaceControl:

// frameworks/native/libs/gui/SurfaceControl.cpp

SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
                               int32_t layerId, const std::string& name, uint32_t w, uint32_t h,
                               PixelFormat format, uint32_t transform, uint32_t flags)
      : mClient(client),        // SurfaceComposerClient对象
        mHandle(handle),        // LayerHandle对象
        mLayerId(layerId),      // LayerId
        mName(name),            // Layer 名称
        mTransformHint(transform),  // 
        mWidth(w),              // Layer的宽
        mHeight(h),             // Layer的高 
        mFormat(format),        // Layer格式
        mCreateFlags(flags) {}  // 标记值

LayerHandle代表一个Layer的操作句柄,Layer的查找、销毁都通过LayerHandle来实现。

Native SurfaceControl创建完成后,Java层SurfaceControl将持有它的内存地址。

Java SurfaceControl、Native SurfaceControl、Layer之间的关系可表示如下图:

2.3、Native层对象内存管理

通过上面分析,Java SurfaceControl持有一个Native SurfaceControl,当Java SurfaceControl被释放或被回收后,native层对象是如何释放的呢? ——通过NativeAllocationRegistry来完成。

NativeAllocationRegistry可以对Java层对象和Native对象进行关联,并当Java层对象在释放内存时,同步Native层完成Native层资源的释放。

完成SurfaceControl创建后,在SurfaceControl.assignNativeObject()方法中,对NativeAllocationRegistry进行注册:

// frameworks/base/core/java/android/view/SurfaceControl.java

private void assignNativeObject(long nativeObject, String callsite) {
    if (mNativeObject != 0) {
        release();
    }
    if (nativeObject != 0) {
        // 注册待回收Native Allocation对象并返回Runnable
        mFreeNativeResources =
                sRegistry.registerNativeAllocation(this, nativeObject);
    }
    // 保存native对象地址
    mNativeObject = nativeObject;
    mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;
    .....
}

mFreeNativeResources用于释放native层资源,这部分内容将在Layer销毁流程中进行分析。

三、创建Layer实例

现在进入surfaceflinger中,来看下Layer的创建过程。Client::createSurface()方法如下:

// frameworks/native/services/surfaceflinger/Client.cpp

binder::Status Client::createSurface(const std::string& name, int32_t flags,
                                     const sp<IBinder>& parent, const gui::LayerMetadata& metadata,
                                     gui::CreateSurfaceResult* outResult) {
    // 创建LayerCreationArgs对象
    LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(),
                           static_cast<uint32_t>(flags), std::move(metadata));
    args.parentHandle = parent;
    // 进入SF创建layer
    const status_t status = mFlinger->createLayer(args, *outResult);
    return binderStatusFromStatusT(status);
}

这个方法中,将客户端传入的所有参数封装在了LayerCreationArgs中,LayerCreationArgs用于封装客户端传入的创建Layer所需的属性和参数。

然后便调用SurfaceFlinger::createLayer()方法继续执行创建流程。

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, gui::CreateSurfaceResult& outResult) {

    sp<Layer> layer;
    // 根据flag确定要创建的Layer类型
    switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
        case ISurfaceComposerClient::eFXSurfaceContainer:
        case ISurfaceComposerClient::eFXSurfaceBufferState:
            args.flags |= ISurfaceComposerClient::eNoColorFill;
            FMT_FALLTHROUGH;
        case ISurfaceComposerClient::eFXSurfaceEffect: {
            // 创建Layer
            result = createBufferStateLayer(args, &outResult.handle, &layer);
            std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter();
            if (pendingBufferCounter) {
                std::string counterName = layer->getPendingBufferCounterName();
                mBufferCountTracker.add(outResult.handle->localBinder(), counterName,
                                        pendingBufferCounter);
            }
        } break;
        default:
            result = BAD_VALUE;
            break;
    }
    // 判断是否可以作为根Layer(没有Parent)
    // args.addToRoot默认为true
    // 当客户端没有申请android.permission.ACCESS_SURFACE_FLINGER权限时,将不能作为根节点Layer添加
    args.addToRoot = args.addToRoot && callingThreadHasUnscopedSurfaceFlingerAccess();
    // We can safely promote the parent layer in binder thread because we have a strong reference
    // to the layer's handle inside this scope.
    sp<Layer> parent = LayerHandle::getLayer(args.parentHandle.promote());
    if (args.parentHandle != nullptr && parent == nullptr) {
        args.addToRoot = false;
    }

    uint32_t outTransformHint;
    // 添加到列表
    result = addClientLayer(args, outResult.handle, layer, parent, &outTransformHint);

    // 填充返回结果
    outResult.transformHint = static_cast<int32_t>(outTransformHint);
    outResult.layerId = layer->sequence;
    outResult.layerName = String16(layer->getDebugName());
    return result;
    }

以上方法中:

  1. 通过createBufferStateLayer()方法创建Layer实例;

  2. 通过addClientLayer()方法将Layer添加到Layer列表中。

3.1、createBufferStateLayer()创建Layer和LayerHandle

Android U之前,Layer在创建时可以设置不同的类型:

  • BufferState Layer:带有Buffer的Layer,不设置类型时默认创建BufferLayer;

  • Contain Layer:不参与合成,仅作为Layer父容器挂其他Layer;

  • Effect Layer:用于呈现颜色、阴影效果的Layer;

从Android U开始,所有类型Layer都合并统一到Layer类中(但类型标记目前依然保留,可能会部分逐步废弃)。都通过createBufferStateLayer()方法创建:


status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle,
                                                sp<Layer>* outLayer) {
    // 设置一个texture id                                            
    args.textureName = getNewTexture();
    // 创建Layer
    *outLayer = getFactory().createBufferStateLayer(args);
    // 创建LayerHandle
    *handle = (*outLayer)->getHandle();
    return NO_ERROR;
}

以上方法中,将依次完成Layer和LayerHandle的创建。

3.1.1、Layer()构造方法

Layer由surfaceflinger进程中的创建器DefaultFactory执行创建:

// frameworks/native/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp

sp<Layer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) {
    return sp<Layer>::make(args);
}

在Layer构造方法中,将同步创建LayerFE实例:

// frameworks/native/services/surfaceflinger/Layer.cpp

Layer::Layer(const LayerCreationArgs& args)
      : sequence(args.sequence),     // Layer序列号
        mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)),
        mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
        mClientRef(args.client),
        // 窗口类型,如全屏、Freeform、多窗口...
        mWindowType(static_cast<WindowInfo::Type>(
                args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),  
        // 标记位
        mLayerCreationFlags(args.flags),
        // Layer边界是否可见
        mBorderEnabled(false),
        mTextureName(args.textureName),
        // 创建LayerFE对象
        mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName)) {

    uint32_t layerFlags = 0;
    // 隐藏Layer标记
    if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
    // 不透明Layer标记
    if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
    // 安全Layer标记
    if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
    // 禁止截屏标记
    if (args.flags & ISurfaceComposerClient::eSkipScreenshot)
        layerFlags |= layer_state_t::eLayerSkipScreenshot;
    // 初始化mDrawingState
    mDrawingState.flags = layerFlags;      // Layer标记位
    mDrawingState.crop.makeInvalid();      // Layer的区域大小,默认(0,0,-1,-1)
    mDrawingState.z = 0;                   // Layer的Z-Order序列
    mDrawingState.color.a = 1.0f;          // Layer的颜色值(RGBA)
    mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK;   // Layer所在LayerStack ID
    mDrawingState.sequence = 0;            // Layer可见区域更新时的序列号
    mDrawingState.transform.set(0, 0);     // Layer的变换对象(平移、旋转、....)
    mDrawingState.frameNumber = 0;         // Layer中Buffer的帧序列号(每更新GraphicBuffer时加1)
    mDrawingState.barrierFrameNumber = 0;  // Layer中Barrier Buffer的帧序列号(Barrier Buffer不会立即应用)
    mDrawingState.producerId = 0;          // Layer中Buffer对应的BufferQueueProducer ID
    mDrawingState.barrierProducerId = 0;   // Layer中Barrier Buffer对应的BufferQueueProducer ID
    mDrawingState.bufferTransform = 0;     // Layer中Buffer的变换对象
    mDrawingState.transformToDisplayInverse = false;     // ???
    mDrawingState.acquireFence = sp<Fence>::make(-1);    // ???
    mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
    mDrawingState.dataspace = ui::Dataspace::V0_SRGB;    // Layer的dataspace,默认sRGB
    mDrawingState.hdrMetadata.validTypes = 0;            // Layer的hdr元数据
    mDrawingState.surfaceDamageRegion = Region::INVALID_REGION;   // Layer发生更新的区域
    mDrawingState.cornerRadius = 0.0f;                   // Layer的圆角半径
    mDrawingState.backgroundBlurRadius = 0;              // Layer的背景模糊半径
    mDrawingState.api = -1;                              // Layer中用于处理GraphicBuffer的本地窗口
    mDrawingState.hasColorTransform = false;             // ???
    mDrawingState.colorSpaceAgnostic = false;            // ??
    mDrawingState.frameRateSelectionPriority = PRIORITY_UNSET;
    mDrawingState.metadata = args.metadata;              // Layer元数据
    mDrawingState.shadowRadius = 0.f;                    // Layer阴影半径
    mDrawingState.fixedTransformHint = ui::Transform::ROT_INVALID;
    mDrawingState.frameTimelineInfo = {};                // ???
    mDrawingState.postTime = -1;                         // ???
    mDrawingState.destinationFrame.makeInvalid();        // ???
    mDrawingState.isTrustedOverlay = false;              // ???
    mDrawingState.dropInputMode = gui::DropInputMode::NONE;    // ???
    mDrawingState.dimmingEnabled = true;                 // ???
    mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default;    // ???

    // ISurfaceComposerClient::eNoColorFill表示创建时不会进行color填充的flag
    if (args.flags & ISurfaceComposerClient::eNoColorFill) {
        // Set an invalid color so there is no color fill.
        mDrawingState.color.r = -1.0_hf;
        mDrawingState.color.g = -1.0_hf;
        mDrawingState.color.b = -1.0_hf;
    }

    mFrameTracker.setDisplayRefreshPeriod(
            args.flinger->mScheduler->getPacesetterVsyncPeriod().ns());

    mOwnerUid = args.ownerUid;
    mOwnerPid = args.ownerPid;
    // ISurfaceComposerClient::eNonPremultiplied表示颜色转换时,对Alpha值的特殊处理的标记
    mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
    // ISurfaceComposerClient::eCursorWindow表示该Layer是一个光标layer
    mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
    // ISurfaceComposerClient::eProtectedByApp表示是否设置了在外接显式设备显示时的硬件保护路径
    mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;

    // 初始化LayerSnapshot
    mSnapshot->sequence = sequence;
    mSnapshot->name = getDebugName();
    mSnapshot->textureName = mTextureName;
    mSnapshot->premultipliedAlpha = mPremultipliedAlpha;
    mSnapshot->parentTransform = {};
}

以上方法中:

  1. 通过flinger->getFactory().createLayerFE()同步创建了LayerFE对象;

  2. 初始化mDrawingState。

3.1.1.1、创建LayerFE实例

LayerFE也由SufaceFlinger中的创建器DefaultFactory创建,其构造方法只有一个参数:

// frameworks/native/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
sp<LayerFE> DefaultFactory::createLayerFE(const std::string& layerName) {
    return sp<LayerFE>::make(layerName);
}

// frameworks/native/services/surfaceflinger/LayerFE.cpp
LayerFE::LayerFE(const std::string& name) : mName(name) {}

LayerFE作为Layer的"FrontEnd"端对象,在合成过程中,会从Layer中获取各类属性参与到合成流程中。

3.1.1.2、初始化mDrawingState

mDrawingState是Layer类中Layer.State类型全局变量,用于保存所有Layer的状态。在构造方法中,会对其进行初始化,之后的合成流程中,会根据客户端传入的参数对对应属性进行更新。

3.1.2、LayerHandle()构造方法

创建完成Layer后,通过Layer::getHandle()方法开始创建LayerHandle。LayerHandle表示一个Layer的句柄,用于传递给客户端以便对Layer进行更新或销毁,客户端持有LayerHandle引用,因此当客户端对象销毁析构后,对应的LayerHandle对象也将执行析构,并触发Layer的销毁流程。

在SurfaceFlinger进程中,不会持有任何LayerHandle的引用,否则可能会出现Layer泄漏问题。

// frameworks/native/services/surfaceflinger/Layer.cpp

sp<IBinder> Layer::getHandle() {
    Mutex::Autolock _l(mLock);
    mGetHandleCalled = true;
    mHandleAlive = true;
    return sp<LayerHandle>::make(mFlinger, sp<Layer>::fromExisting(this));
}

LayerHandle构造方法和析构方法如下:

// frameworks/native/services/surfaceflinger/FrontEnd/LayerHandle.cpp

LayerHandle::LayerHandle(const sp<android::SurfaceFlinger>& flinger,
                         const sp<android::Layer>& layer)
      : mFlinger(flinger), mLayer(layer), mLayerId(static_cast<uint32_t>(layer->getSequence())) {}

LayerHandle::~LayerHandle() {
    if (mFlinger) {
        // Layer析构时,触发SF的onHandleDestroyed()方法
        mFlinger->onHandleDestroyed(this, mLayer, mLayerId);
    }
}

3.2、SurfaceFlinger::addClientLayer()

回到SurfaceFlinger::createLayer()中,完成Layer对象创建后,下一个执行的方法是SurfaceFlinger::addClientLayer()方法:

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::addClientLayer(LayerCreationArgs& args, const sp<IBinder>& handle,
                                        const sp<Layer>& layer, const wp<Layer>& parent,
                                        uint32_t* outTransformHint) {
    // Layer泄漏情况处理
    if (mNumLayers >= MAX_LAYERS) {                                        
         ......
         // 当超过做大Layer数时,Layer创建失败,返回NO_MEMORY
        return NO_MEMORY;
    }
    ......
    // 更新Transform hint
    layer->updateTransformHint(mActiveDisplayTransformHint);
    if (outTransformHint) {
        *outTransformHint = mActiveDisplayTransformHint;
    }
    // 获取父Layer ID, 若无则返回uint32_t类型最大值
    args.parentId = LayerHandle::getLayerId(args.parentHandle.promote());
    // 获取被镜像的Layer ID,若无则返回uint32_t类型最大值,用于镜像屏幕或Layer时
    args.layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
    {
        std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
        // 创建了LayerCreatedState并添加到mCreatedLayers列表中
        mCreatedLayers.emplace_back(layer, parent, args.addToRoot);
        // 创建RequestedLayerState并添加到列表中
        mNewLayers.emplace_back(std::make_unique<frontend::RequestedLayerState>(args));
        args.mirrorLayerHandle.clear();
        args.parentHandle.clear();
        // 将LayerCreationArgs添加到mNewLayerArgs列表中
        mNewLayerArgs.emplace_back(std::move(args));
    }
    // 设置一个eTransactionNeeded标记,发起surfaceflinger提交操作
    setTransactionFlags(eTransactionNeeded);
    return NO_ERROR;
}

以上方法中:

  1. 针对Layer泄漏场景处理,当SurfaceFlinger中Layer数已经到达最大时,创建Layer失败,直接返回NO_MEMORY。其中细节此处略去;

  2. 依次创建了LayerCreatedState、RequestedLayerState对象,并保存到了对应列表中;

  3. 通过setTransactionFlags()方法设置了eTransactionNeeded标记,发起SurfaceFlinger VSYNC新的调度。

3.2.1、创建LayerCreatedState实例

LayerCreatedState只封装了三个参数:Layer、ParentLayer的弱引用、以及addToRoot,仅仅用于创建过程中为Layer设置树结构,其定义如下:

// frameworks/native/services/surfaceflinger/FrontEnd/Update.h

struct LayerCreatedState {
    LayerCreatedState(const wp<Layer>& layer, const wp<Layer>& parent, bool addToRoot)
          : layer(layer), initialParent(parent), addToRoot(addToRoot) {}
    // 所创建Layer的弱引用
    wp<Layer> layer;
    // 所创建Layer的Parent Layer 弱引用,为空将会被添加到当前根节点Layer上
    wp<Layer> initialParent;
    // 表示所创建Layer是否作为根节点Layer添加,前提是没有提供Parent Layer且已申请
    // ACCESS_SURFACE_FLINGER权限,如果该值为false、且没有Parent,将会被添加到Offscreen列表中不参与合成 
    bool addToRoot;
};

稍后会Layer的挂靠结构进行具体说明。

3.2.2、创建RequestedLayerState实例

RequestedLayerState中也封装了所有的Layer创建参数,它在"SurfaceFlinger FrontEnd"架构引入,在Android V上采用LifeCycleManager组件时使用,目前流程中并未使用到。

3.2.3、setTransactionFlags()方法发起VSYNC调度

SurfaceFlinger::setTransactionFlags()方法用于设置各类Transaction标记,并触发SurfaceFlinger中VSYNC的调度:

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
                                         const sp<IBinder>& applyToken, FrameHint frameHint) {
    mScheduler->modulateVsync({}, &VsyncModulator::setTransactionSchedule, schedule, applyToken);
    // 将标记添加到mTransactionFlags中
    uint32_t transactionFlags = mTransactionFlags.fetch_or(mask);

    if (const bool scheduled = transactionFlags & mask; !scheduled) {
        // 执行调度
        scheduleCommit(frameHint);
    } else if (frameHint == FrameHint::kActive) {
        mScheduler->resetIdleTimer();
    }
}

执行到这里时,整个从客户端SurfaceControl.Builder.build()方法开始后的流程就全部执行完毕。此时SurfaceControl、Layer、LayerHandle、LayerFE等对象均已创建完毕。

但此时,还没有对Layer设置在对应LayerTree上,是不会参与到后续的合成和显示的。这时客户端还需要通过Transaction.apply()方法对SurfaceControl进行事务提交,或SF中主动执行一次setTransactionFlags(eTransactionFlushNeeded)后,发起一帧刷新后对新创建Layer设置LayerTree。

以上流程都是执行在客户端线程和binder线程,之后在SurfaceFlinger中收到VSYNC信号后,在主线程进行事务提交流程时,会将Layer放置在合适的位置上。

以上流程时序图如下:

四、LayerTree的设置

在surfaceflinger中收到VSYNC信号进行事务提交过程中,如果存在待添加的Layer,便会将Layer添加到对应的LayerTree上。

这里从commit()方法开始,该方法体较大,这里仅看下其中与LayerTree设置相关流程:

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime)
        FTL_FAKE_GUARD(kMainThreadContext) {

    ......
    
    // 是否需要进行合成
    bool mustComposite = mMustComposite.exchange(false);
    {
        ......
        // 清除eTransactionFlushNeeded标记,并返回清除标记前是否存在被清除的标记
        const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded);
        // 初始化frontend::Update变量
        frontend::Update updates;
        if (flushTransactions) {
            // 刷新待更新状态,如事务列表、待添加的Layer、待销毁LayerHandle等
            updates = flushLifecycleUpdates();
            .......
        }
        bool transactionsAreEmpty;
        // 提交MirrorDisplay、Layer、Transaction等状态
        if (mLegacyFrontEndEnabled) {
            mustComposite |= updateLayerSnapshotsLegacy(vsyncId, updates, flushTransactions,
                                                        transactionsAreEmpty);
        }
        ......
    }
    ......
    // 返回结果决定是否执行后续合成操作
    return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}

以上方法中跟添加Layer相关主要有两步:

  1. 通过flushLifecycleUpdates()刷新待添加的Layer,并放在frontend::Update中;

  2. 通过updateLayerSnapshotsLegacy()提交待添加Layer信息,完成LayerTree设置。

5.1、flushLifecycleUpdates()填充frontend::Update

frontend::Update封装了多个会影响Layer显示状态的列表,它在每一次收到VSYNC后进行填充:

// frameworks/native/services/surfaceflinger/FrontEnd/Update.h

struct Update {
    // 保存待处理事务请求
    std::vector<TransactionState> transactions;
    // 保存待处理Layer
    std::vector<LayerCreatedState> layerCreatedStates;
    std::vector<std::unique_ptr<frontend::RequestedLayerState>> newLayers;
    // 保存待处理Layer创建参数
    std::vector<LayerCreationArgs> layerCreationArgs;
    // 保存待销毁的LayerHandle
    std::vector<uint32_t> destroyedHandles;
};

通过flushLifecycleUpdates()方法将所需数据填充到frontend::Update中:

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
frontend::Update SurfaceFlinger::flushLifecycleUpdates() {
    frontend::Update update;
    
    update.transactions = mTransactionHandler.flushTransactions();
    {

        std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
        // 取出LayerCreatedState列表,填充给Update
        update.layerCreatedStates = std::move(mCreatedLayers);
        mCreatedLayers.clear();
        // 取出RequestedLayerState列表,填充给Update
        update.newLayers = std::move(mNewLayers);
        mNewLayers.clear();
        update.layerCreationArgs = std::move(mNewLayerArgs);
        mNewLayerArgs.clear();
        ......
    }
    return update;
}

mCreatedLayers等列表是在SurfaceFlinger::addClientLayer()中添加的。在这里,frontend::Update从源列表中取出数据,同时将全局列表清空,以便用于下次VSYNC后的数据填充。

5.2、updateLayerSnapshotsLegacy()更新Layer属性

完成frontend::Update填充后,接下来执行SurfaceFlinger::updateLayerSnapshotsLegacy()方法,对Transaction、Mirror Display、Layer属性等各类状态进行commit操作,包括从frontend::Update取出Layer相关状态进行提交:


bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update,
                                                bool transactionsFlushed,
                                                bool& outTransactionsAreEmpty) {
    bool needsTraversal = false;
    if (transactionsFlushed) {
        // 提交MirrorDisplay相关状态
        needsTraversal |= commitMirrorDisplays(vsyncId);
        // 提交Layer创建列表
        needsTraversal |= commitCreatedLayers(vsyncId, update.layerCreatedStates);
        // 应用Transaction列表
        needsTraversal |= applyTransactions(update.transactions, vsyncId);
    }
    outTransactionsAreEmpty = !needsTraversal;
    const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
    // 提交Transaction列表
    if (shouldCommit) {
        commitTransactions();
    }

    bool mustComposite = latchBuffers() || shouldCommit;
    // 计算各个Layer几何边界
    updateLayerGeometry();
    return mustComposite;
}

该方法为U新增方法,Legacy后缀说明在下个版本更新中会被移除

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

bool SurfaceFlinger::commitCreatedLayers(VsyncId vsyncId,
                                         std::vector<LayerCreatedState>& createdLayers) {
    if (createdLayers.size() == 0) {
        return false;
    }

    Mutex::Autolock _l(mStateLock);
    // 将Layer添加到LayerTree结构中
    for (const auto& createdLayer : createdLayers) {
        handleLayerCreatedLocked(createdLayer, vsyncId);
    }
    // 表示Layer添加成功
    mLayersAdded = true;
    return mLayersAdded;
}

5.2.1、commitCreatedLayers()提交Layer添加事件

这里其他流程暂时略去,直接看提交Layer创建列表:

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

bool SurfaceFlinger::commitCreatedLayers(VsyncId vsyncId,
                                         std::vector<LayerCreatedState>& createdLayers) {
    if (createdLayers.size() == 0) {
        return false;
    }

    Mutex::Autolock _l(mStateLock);
    // 将Layer添加到LayerTree结构中
    for (const auto& createdLayer : createdLayers) {
        handleLayerCreatedLocked(createdLayer, vsyncId);
    }
    // 表示Layer添加成功
    mLayersAdded = true;
    return mLayersAdded;
}

在handleLayerCreatedLocked()中,将会对Layer进行LayerTree的设置。

5.2.2、handleLayerCreatedLocked()设置LayerTree

handleLayerCreatedLocked()方法如下:

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, VsyncId vsyncId) {
    sp<Layer> layer = state.layer.promote();
    MUTEX_ALIAS(mStateLock, layer->mFlinger->mStateLock);

    sp<Layer> parent;
    // 根据addToRoot和parent据定是否作为根节点Layer
    bool addToRoot = state.addToRoot;
    // 创建过程中指定了parent但已经被销毁释放,则不能将该Layer添加到根节点中
    if (state.initialParent != nullptr) {
        parent = state.initialParent.promote();
        if (parent == nullptr) {
            addToRoot = false;
        }
    }
    // 如果没有指定父layer,则添加到
    // mCurrentState.layersSortedByZ列表中作为根节点保存
    if (parent == nullptr && addToRoot) {
        // 设置为根节点
        layer->setIsAtRoot(true);
        // 添加到列表中
        mCurrentState.layersSortedByZ.add(layer);
    } else if (parent == nullptr) {
        // 如果Parent未指定,此时该Layer无法依附,会先执行Remove操作, 添加到待移除列表中
        layer->onRemovedFromCurrentState();
    } else if (parent->isRemovedFromCurrentState()) {
        // 如果指定的Parent存在,但已移除,则先添加到Parent中,再,添加到待移除列表中
        parent->addChild(layer);
        layer->onRemovedFromCurrentState();
    } else {
        // 执行到这里说明Parent一切正常,添加到父Layer中管理
        parent->addChild(layer);
    }

    ui::LayerStack layerStack = layer->getLayerStack(LayerVector::StateSet::Current);
    sp<const DisplayDevice> hintDisplay;
    // Find the display that includes the layer.
    for (const auto& [token, display] : mDisplays) {
        if (display->getLayerStack() == layerStack) {
            hintDisplay = display;
            break;
        }
    }
    // 给Layer设置Transform Hint
    if (hintDisplay) {
        layer->updateTransformHint(hintDisplay->getTransformHint());
    }
}

以上方法中,会根据addToRoot参数和父Layer情况,将Layer添加到对应的列表中保存:

  1. 如果当前Layer在创建时没有指定父Layer,且addToRoot为true,则可将它作为根节点Layer,添加到mCurrentState.layersSortedByZ列表中作为根节点保存;

  2. 如果当前Layer指定了父Layer,但执行过程中父Layer已销毁释放,此时该Layer无依附的Layer,会先执行Remove操作,并逐步添加到待移除Layer列表mLayersPendingRemoval中;

  3. 如果当前Layer指定了父Layer,但执行过程中父Layer已被移除,此时先将Layer添加到父Layer中,然后执行移除操作,并逐步添加到待移除Layer列表mLayersPendingRemoval中;

  4. 如果不满足以上所有条件,说明Layer指定了父Layer,则将它添加为父Layer的子Layer;

通过以上逻辑可知,如果在创建Layer时,没有指定Parent Layer、且客户端已授予ACCESS_SURFACE_FLINGER权限,将会默认作为根节点添加到mCurrentState.layersSortedByZ列表中,否则会添加到Parent Layer的mCurrentChildren列表中,由Parent Layer进行管理。

Layer::onRemovedFromCurrentState()方法在Parent Layer发生变化时,对Child Layer进行添加或移除到OffscreenLayers列表中,添加在OffscreenLayers列表中的Layer不会参与到合成显示,但并未销毁。

以上流程时序图如下:

到这里,Layer创建流程基本完成,关于Layer提交、合成的更多细节会在单独文章中进行分析。

回看整个创建过程,从进程角度来看,可以分成两部分:从业务进程发起SurfaceControl的创建,到surfaceflinger进程完成Layer、LayerHandle、LayerFE对象创建及LayerTree的设置;

从线程角度来看,也可以分成两部分:从业务进程发起SurfaceControl创建,通过IPC跨进程调用surfaceflinger完成Layer、LayerHandle、LayerFE等对象创建,这部分在业务线程 + binder线程完成(SF::addClientLayer()执行结束后返回);之后收到VSYNC信号后对创建Layer进行LayerTree的设置,在surfaceflinger主线程完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1651425.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

营销H5测试综述

H5页面是营销域最常见的一种运营形式&#xff0c;业务通过H5来提供服务&#xff0c;可以满足用户对于便捷、高效和低成本的需求。H5页面是业务直面用户的端点&#xff0c;其质量保证工作显得尤为重要。各业务的功能实现具有通用性&#xff0c;相应也有共性的测试方法&#xff0…

蓝桥杯13届JAVA A组 国赛

​​​​​​​ package 蓝桥杯国赛; // 贪心选个数最少的进行摆 // 2:1 ,3:1, 4:1,5 : 3,6:3,7:1 // 选 1&#xff0c;7&#xff0c;4&#xff0c;2&#xff0c;3&#xff0c;5&#xff0c;9 // 然后都选满10个 public class 火彩棒数字 {public static void main(String[] a…

人工智能-2024期中考试

前言 人工智能期中考试&#xff0c;认真准备了但是没考好&#xff0c;结果中游偏下水平。 第4题没拿分 &#xff08;遗传算法&#xff1a;知识点在课堂上一笔带过没有细讲&#xff0c;轮盘赌算法在书本上没有提到&#xff0c;考试的时候也没讲清楚&#xff0c;只能靠猜&…

主数据准确性和完整性竟如此重要?确保这两大特性做好这些就够了

主数据是企业运营的心脏&#xff0c;它包含了客户、产品、供应商和员工等关键业务实体的详细信息。这些数据的准确性、一致性和完整性对于确保企业决策的质量、优化业务流程、提高客户满意度、推动数据驱动的创新、遵守法规要求以及维护数据安全至关重要。 主数据的准确性指的…

亚信科技精彩亮相2024中国移动算力网络大会,数智创新共筑“新质生产力”

4月28至29日&#xff0c;江苏省人民政府指导、中国移动通信集团有限公司主办的2024中国移动算力网络大会在苏州举办。大会以“算力网络点亮AI时代”为主题&#xff0c;旨在凝聚生态伙伴合力&#xff0c;共同探索算力网络、云计算等数智能力空间&#xff0c;共促我国算网产业和数…

目标检测实战(八): 使用YOLOv7完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)

文章目录 一、目标检测介绍二、YOLOv7介绍三、源码/论文获取四、环境搭建4.1 环境检测 五、数据集准备六、 模型训练七、模型验证八、模型测试九、错误总结9.1 错误1-numpy jas mp attribute int9.2 错误2-测试代码未能跑出检测框9.3 错误3- Command git tag returned non-zero…

利用Jenkins完成Android项目打包

问题和思路 目前存在的问题 打包操作由开发人员完成&#xff0c;这样开发进度容易被打断。 解决问题的思路 将打包操作交测试/产品/开发人员来完成&#xff0c;主要是测试/开发。 按照以上的思路&#xff0c;那么JenkinsGradle的解决方案是比较经济的&#xff0c;实现起来…

[Kotlin]创建一个私有包并使用

1.创建Kotlin项目 创建项目&#xff1a; 在Android Studio或其他IDE中选择“Create New Project”。选择Kotlin和Gradle作为项目类型和构建系统。指定项目名称和位置&#xff0c;完成设置。 添加依赖: 如果你的库需要额外的依赖&#xff0c;可以在 build.gradle (Module: app…

PostgreSQL自带的命令行工具13- pg_waldump

PostgreSQL自带的命令行工具13- pg_waldump 基础信息 OS版本&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本&#xff1a;16.2 pg软件目录&#xff1a;/home/pg16/soft pg数据目录&#xff1a;/home/pg16/data 端口&#xff1a;5777pg_waldump 是 Po…

扩展van Emde Boas树以支持卫星数据:设计与实现

扩展van Emde Boas树以支持卫星数据&#xff1a;设计与实现 1. 引言2. vEB树的基本概念3. 支持卫星数据的vEB树设计3.1 数据结构的扩展3.2 操作的修改3.3 卫星数据的存储和检索 4. 详细设计和实现4.1 定义卫星数据结构体4.2 修改vEB树节点结构4.3 插入操作的伪代码4.4 C语言实现…

STM32学习笔记--疑问篇

STM32学习笔记–疑问篇 GPIO是什么的缩写通用寄存器的缩写和全程 3.、这是什么的缩写 不同输出模式之间的差异 PB是GPIOB的缩写&#xff1f; 怎样知道端口应该设置成输入模式还是设置成输出模式

Mybatis的简介和下载安装

什么是 MyBatis &#xff1f; MyBatis 是一款优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将接口和 Java 的…

mysql workbench如何导出insert语句?

进行导出设置 导出的sql文件 CREATE DATABASE IF NOT EXISTS jeesite /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ /*!80016 DEFAULT ENCRYPTIONN */; USE jeesite; -- MySQL dump 10.13 Distrib 8.0.28, for Win64 (x86_64) -- -- Host: 127.0…

MCU通过UART/SPI等接口更新flash的方法

MCU可提供一种方便的方式来更新flash内容以进行错误修复bugfix或产品更新update。可以使用以下任何模式更新flash内容: •系统内编程(ISP,In-System Programming):用于使用内部bootloader程序和UART/SPI对片上闪存进行编程program或重新编程reprogram。 •应用程序内编程…

vector介绍与使用【C++】

C vector 前言一、vector的介绍c文档介绍简介 二、vector的定义和使用vector的定义vector代码演示 vector的使用vector iterator 的使用vector 空间增长问题vector 增删查改vector 迭代器失效问题引起底层空间改变eraseg与vs检测比较string迭代器失效 vector 在OJ中的使用只出现…

Cisco NX-OS System Software - ACI 16.0(5h)

Cisco NX-OS System Software - ACI 16.0(5h) 适用于 ACI 模式下的 Cisco Nexus 9000 系列交换机 请访问原文链接&#xff1a;Cisco NX-OS System Software - ACI 16.0(5h)&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Cis…

AI预警未来:山体滑坡与塌方事故的潜在发现者

在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;的应用已经渗透到了我们生活的各个领域。而在防灾减灾的领域中&#xff0c;AI技术的引入无疑为我们打开了一扇新的大门。以梅大高速大埔往福建方向K11900m附近发生的路面塌方灾害为例&#xff0c;我们不禁思…

DockerUI安装使用

DockerUI安装使用 主机环境 [roottest01 ~]# uname -a Linux test01 3.10.0-862.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux [roottest01 ~]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core)安装 [roottest01 ~]# doc…

第12章 软件测试基础(第三部分)测试类型、测试工具

七、测试类型&#xff08;按工程阶段划分&#xff09; 单集系确收 &#xff08;一&#xff09;单元测试 1、单元测试/模块测试 单元就是软件中最小单位&#xff08;或模块&#xff09;。可以是一个函数、一个过程、一个类。主要依据是模块的详细设计文档。价值在于尽早发现…

MacOS快速安装FFmpeg,并使用FFmpeg转换视频

前言&#xff1a;目前正在接入flv视频流&#xff0c;但是没有一个合适的flv视频流地址。网上提供的flv也都不是H264AAC&#xff08;一种视频和音频编解码器组合&#xff09;&#xff0c;所以想通过fmpeg来将flv文件转换为H264AAC。 一、MacOS环境 博主的MacOS环境&#xff08;…