Android车载应用之EvsCameraPreview源码分析(四)

421 阅读7分钟

0 引言 在Android车载应用之EvsCameraPreview源码分析(三)中通过Log信息分析了Evs应用的组件和启动流程。本篇文章将具体分析“开启视频传输功能”这一过程进行分析,下面是相关代码:

    case STREAM_STATE_VISIBLE:
        // Starts a video stream
        if (mEvsManager != null) {
            int result = mEvsManager.startVideoStream(CarEvsManager.SERVICE_TYPE_REARVIEW,
                    mSessionToken, mCallbackExecutor, mStreamHandler);
           if (result != ERROR_NONE) {
                Log.e(TAG, "Failed to start a video stream, error = " + result);
           } else {
                needToUpdateState = true;
           }
           } else {
                Log.w(TAG, "EvsManager is not available");
           }
        break;

从上面的代码中可以看到,调用了EvsManager的startVideoStream函数,该函数最终调用的是CarEvsService的startVideoStream。

1 CarEvsService

CarEvsService中的startVideoStream函数代码如下:

public @CarEvsError int startVideoStream(@CarEvsServiceType int type, @Nullable IBinder token,
            @NonNull ICarEvsStreamCallback callback) {
        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_CAR_EVS_CAMERA);
        Objects.requireNonNull(callback);

        int priority;
        if (isSessionToken(token)) {
            mHandler.removeCallbacks(mActivityRequestTimeoutRunnable);
            priority = REQUEST_PRIORITY_HIGH;
        } else {
            priority = REQUEST_PRIORITY_LOW;
        }

        return mStateEngine.execute(priority, SERVICE_STATE_ACTIVE, type, token, callback);
    }

最后执行了mStateEngine的execute方法,它的部分代码如下:

switch (destination) {
            case SERVICE_STATE_UNAVAILABLE:
                result = handleTransitionToUnavailableLocked();
                break;

            case SERVICE_STATE_INACTIVE:
                result = handleTransitionToInactiveLocked(priority, service, callback);
                break;

            case SERVICE_STATE_REQUESTED:
                result = handleTransitionToRequestedLocked(priority, service);
                break;

            case SERVICE_STATE_ACTIVE:
                result = handleTransitionToActiveLocked(priority, service, token, callback);
                break;

            default:
                throw new IllegalStateException(
                        "CarEvsService is in the unknown state, " + previousState);
        }

这里会进入SERVICE_STATE_ACTIVE,执行handleTransitionToActiveLocked方法,代码如下:

private @CarEvsError int handleTransitionToActiveLocked(int priority, int service,
                IBinder token, ICarEvsStreamCallback callback) {

            @CarEvsError int result = ERROR_NONE;
            switch (mState) {
                case SERVICE_STATE_UNAVAILABLE:
                    // We do not have a valid connection to the Extended View System service.
                    return ERROR_UNAVAILABLE;

                case SERVICE_STATE_INACTIVE:
                    // CarEvsService receives a low priority request to start a video stream.
                    result = startServiceAndVideoStream(service, callback);
                    if (result != ERROR_NONE) {
                        return result;
                    }
                    break;

                case SERVICE_STATE_REQUESTED:
                    // CarEvsService is reserved for higher priority clients.
                    if (priority == REQUEST_PRIORITY_HIGH && !isSessionToken(token)) {
                        // Declines a request with an expired token.
                        return ERROR_BUSY;
                    }

                    result = startServiceAndVideoStream(service, callback);
                    if (result != ERROR_NONE) {
                        return result;
                    }
                    break;

                case SERVICE_STATE_ACTIVE:
                    // CarEvsManager will transfer an active video stream to a new client with a
                    // higher or equal priority.
                    if (priority < mLastRequestPriority) {
                        Slogf.i(TAG_EVS, "Declines a service request with a lower priority.");
                        break;
                    }

                    if (mStreamCallback != null) {
                        // keep old reference for Runnable.
                        ICarEvsStreamCallback previousCallback = mStreamCallback;
                        mStreamCallback = null;
                        mHandler.post(() -> notifyStreamStopped(previousCallback));
                    }

                    mStreamCallback = callback;
                    break;

                default:
                    throw new IllegalStateException("CarEvsService is in the unknown state.");
            }

            mState = SERVICE_STATE_ACTIVE;
            mServiceType = service;
            mLastRequestPriority = priority;
            return ERROR_NONE;
        }

这段代码会根据当前状态mState来进入不同的case。在Evs应用中,首先会请求显示CarEvsCameraPreviewActivity,这个时候会从INACTIVE状态转换为REQUESTED状态。所以在开启视频传输前,mState应该是REQUESTED状态。因此接下来会执行startServiceAndVideoStream函数:

    private @CarEvsError int startServiceAndVideoStream(
            @CarEvsServiceType int service, ICarEvsStreamCallback callback) {
        if (!startService(service)) {
            return ERROR_UNAVAILABLE;
        }

        mStreamCallback = callback;
        linkToDeathStreamCallbackLocked();

        if (!mHalWrapper.requestToStartVideoStream()) {
            Slogf.e(TAG_EVS, "Failed to start a video stream");
            mStreamCallback = null;
            return ERROR_UNAVAILABLE;
        }

        return ERROR_NONE;
    }

紧接着这里会执行startService函数,然后会调用mHalWrapper的requestToStartVideoStream开始正式请求开启视频流传输。startService函数的代码如下:

private boolean startService(@CarEvsServiceType int type) {
        if (type == CarEvsManager.SERVICE_TYPE_SURROUNDVIEW) {
            // TODO(b/179029031): Removes below when Surround View service is integrated.
            Slogf.e(TAG_EVS, "Surround view is not supported yet.");
            return false;
        }

        if (!mHalWrapper.connectToHalServiceIfNecessary()) {
            Slogf.e(TAG_EVS, "Failed to connect to EVS service");
            return false;
        }

        String cameraId;
        if (mUseCameraIdOverride) {
            cameraId = mCameraIdOverride;
        } else {
            cameraId = mContext.getString(R.string.config_evsRearviewCameraId);
        }

        if (!mHalWrapper.openCamera(cameraId)) {
            Slogf.e(TAG_EVS, "Failed to open a target camera device");
            return false;
        }

        return true;
    }

可以看到startService函数内部主要是通过mHalWrapper来调用openCamera方法,以此来打开摄像机。以上分析也可以知道,mHalWrapper是真正执行这些工作的类。下面将重点分析mHalWrapper的类型EvsHalWrapper。

2 EvsHalWrapper

EvsHalWrapper 是一个用于与EVS HAL交互的抽象类,提供了基本的HAL操作接口和默认实现。它的类定义代码如下:

public abstract class EvsHalWrapper {
    /** Callback for events from HAL */
    public interface HalEventCallback {
        /** EVS stream event handler called after a native handler */
        void onHalEvent(int eventType);

        /** EVS frame handler called after a native handler */
        void onFrameEvent(int id, HardwareBuffer buffer);

        /** EVS service death handler called after a native handler */
        void onHalDeath();
    }

    /** Initialize HAL */
    public boolean init() {
        return false;
    }

    /** Release HAL */
    public void release() {
    }

    /** is connected to HAL */
    public boolean isConnected() {
        return false;
    }

    /** Attempts to connect to the HAL service if it has not done yet */
    public boolean connectToHalServiceIfNecessary() {
        return false;
    }

    /** Attempts to disconnect from the HAL service */
    public void disconnectFromHalService() {
    }

    /** Attempts to open a target camera device */
    public boolean openCamera(String cameraId) {
        return false;
    }

    /** Requests to close a target camera device */
    public void closeCamera() {
    }

    /** Requests to start a video stream */
    public boolean requestToStartVideoStream() {
        return false;
    }

    /** Requests to stop a video stream */
    public void requestToStopVideoStream() {
    }

    /** Request to return an used buffer */
    public void doneWithFrame(int bufferId) {
    }
}

mHalWrapper是在CarEvsService的构造函数中通过createHalWrapper方法创建出来的,代码如下:

    static EvsHalWrapper createHalWrapper(Context builtinContext,
            EvsHalWrapper.HalEventCallback callback) {
        try {
            Class helperClass = builtinContext.getClassLoader().loadClass(
                    BuiltinPackageDependency.EVS_HAL_WRAPPER_CLASS);
            Constructor constructor = helperClass.getConstructor(
                    new Class[]{EvsHalWrapper.HalEventCallback.class});
            return (EvsHalWrapper) constructor.newInstance(callback);
        } catch (Exception e) {
            throw new RuntimeException(
                    "Cannot load class:" + BuiltinPackageDependency.EVS_HAL_WRAPPER_CLASS, e);
        }
    }

该函数通过反射机制将EvsHalWrapperImpl类实例化(EVS_HAL_WRAPPER_CLASS指向的就是com.android.car.evs.EvsHalWrapperImpl)。

3 EvsHalWrapperImpl

EvsHalWrapperImpl 是 EvsHalWrapper 的具体实现,通过 JNI 与 HAL 交互。

public final class EvsHalWrapperImpl extends EvsHalWrapper {


    /**
     * Because of its dependency on FMQ type, android.hardware.automotive.evs@1.1 interface does
     * not support Java backend.  Therefore, all hwbinder transactions happen in native methods
     * declared below.
     */

    static {
        System.loadLibrary("carservicejni");
    }

    private final EvsHalWrapper.HalEventCallback mCallback;

    private final Object mLock = new Object();

    /** Stores a service handle initialized in native methods */
    @GuardedBy("mLock")
    private long mNativeEvsServiceObj;

    /** Constructor */
    public EvsHalWrapperImpl(EvsHalWrapper.HalEventCallback callback) {
        super();
        mCallback = callback;
    }

    /**
     * Create a {@code EvsHalWrapperImpl} object with a given JNI library that implements native
     * methods.
     */
    @VisibleForTesting
    static EvsHalWrapperImpl create(EvsHalWrapper.HalEventCallback callback,
            String jniLibraryName) {
        System.loadLibrary(jniLibraryName);
        return new EvsHalWrapperImpl(callback);
    }

    @Override
    public boolean init() {
        long handle = nativeCreateServiceHandle();
        if (handle == 0) {
            return false;
        }
        synchronized (mLock) {
            mNativeEvsServiceObj = handle;
        }
        return true;
    }

    @Override
    public void release() {
        long handle;
        synchronized (mLock) {
            handle = mNativeEvsServiceObj;
            mNativeEvsServiceObj = 0;
        }
        if (handle == 0) {
            return;
        }
        nativeDestroyServiceHandle(handle);
    }

    @Override
    public boolean isConnected() {
        return getNativeHandle() != 0;
    }

    @Override
    public boolean connectToHalServiceIfNecessary() {
        if (!isConnected() && !init()) {
            return false;
        }

        return nativeConnectToHalServiceIfNecessary(getNativeHandle());
    }

    @Override
    public void disconnectFromHalService() {
        nativeDisconnectFromHalService(getNativeHandle());
    }

    @Override
    public boolean openCamera(String cameraId) {
        return nativeOpenCamera(getNativeHandle(), cameraId);
    }

    @Override
    public void closeCamera() {
        nativeCloseCamera(getNativeHandle());
    }

    @Override
    public boolean requestToStartVideoStream() {
        return nativeRequestToStartVideoStream(getNativeHandle());
    }

    @Override
    public void requestToStopVideoStream() {
        nativeRequestToStopVideoStream(getNativeHandle());
    }

    @Override
    public void doneWithFrame(int bufferId) {
        nativeDoneWithFrame(getNativeHandle(), bufferId);
    }

    @VisibleForTesting
    boolean setServiceHandle(long handleToUse) {
        if (handleToUse == 0) {
            return false;
        }

        long handleToDestroy;
        synchronized (mLock) {
            handleToDestroy = mNativeEvsServiceObj;
            mNativeEvsServiceObj = handleToUse;
        }

        nativeDestroyServiceHandle(handleToDestroy);
        return true;
    }

    @VisibleForTesting
    long createServiceHandleForTest() {
        return nativeCreateServiceHandleForTest();
    }


    @VisibleForTesting
    void triggerBinderDied() {
        nativeTriggerBinderDied(getNativeHandle());
    }

    private long getNativeHandle() {
        synchronized (mLock) {
            return mNativeEvsServiceObj;
        }
    }

    /** EVS stream event handler called after a native handler */
    private void postNativeEventHandler(int eventType) {
        mCallback.onHalEvent(eventType);
    }

    /** EVS frame handler called after a native handler */
    private void postNativeFrameHandler(int id, HardwareBuffer buffer) {
        mCallback.onFrameEvent(id, buffer);
    }

    /** EVS service death handler called after a native handler */
    private void postNativeDeathHandler() {
        mCallback.onHalDeath();
    }

    /** Attempts to connect to the HAL service if it has not done yet */
    private native boolean nativeConnectToHalServiceIfNecessary(long handle);

    /** Attempts to disconnect from the HAL service */
    private native void nativeDisconnectFromHalService(long handle);

    /** Attempts to open a target camera device */
    private native boolean nativeOpenCamera(long handle, String cameraId);

    /** Requests to close a target camera device */
    private native void nativeCloseCamera(long handle);

    /** Requests to start a video stream */
    private native boolean nativeRequestToStartVideoStream(long handle);

    /** Requests to stop a video stream */
    private native void nativeRequestToStopVideoStream(long handle);

    /** Request to return an used buffer */
    private native void nativeDoneWithFrame(long handle, int bufferId);

    /** Trigger a onBinderDied callback for tests */
    private native void nativeTriggerBinderDied(long handle);

    /** Creates a EVS service handle */
    private static native long nativeCreateServiceHandle();

    /** Creates a EVS service handle for tests */
    private static native long nativeCreateServiceHandleForTest();

    /** Destroys a EVS service handle */
    private static native void nativeDestroyServiceHandle(long handle);
}

它内部函数实现几乎都是native函数,因此需要找到它的具体实现。这指向了CarEvsService.cpp,这是jni调用的具体的cpp函数。

4 CarEvsService.cpp

CarEvsService.cpp里面是 EvsHalWrapperImpl 的 JNI 实现。具体看看openCamera和startVideoStream函数:

jboolean openCamera(JNIEnv* env, jobject /*thiz*/, jlong handle, jstring cameraId) {
    EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
    if (!ctxt) {
        LOG(ERROR) << __FUNCTION__ << ": EVS service context is not available.";
        return JNI_FALSE;
    }

    // Attempts to open the target camera device
    const char* id = env->GetStringUTFChars(cameraId, NULL);
    if (!id || !ctxt->openCamera(id)) {
        LOG(ERROR) << "Failed to open a camera device";
        return JNI_FALSE;
    }

    env->ReleaseStringUTFChars(cameraId, id);
    return JNI_TRUE;
}

jboolean startVideoStream(JNIEnv* /*env*/, jobject /*thiz*/, jlong handle) {
    EvsServiceContext* ctxt = reinterpret_cast<EvsServiceContext*>(handle);
    if (!ctxt) {
        LOG(ERROR) << __FUNCTION__ << ": EVS service context is not available.";
        return JNI_FALSE;
    }

    return ctxt->startVideoStream() ? JNI_TRUE : JNI_FALSE;
}

可以看到无论是打开摄像头还是进行视频流传输,都还需要借助EvsServiceContext类来实现。

5 EvsServiceContext类

EvsServiceContext 是 EVS 服务的核心实现类,封装了与 EVS 服务的交互逻辑。这里首先看一下EvsServiceContext 类的openCamera函数:

bool EvsServiceContext::openCamera(const char* id) {
    if (!isAvailable()) {
        LOG(ERROR) << "Has not connected to EVS service yet.";
        return false;
    }

    if (isCameraOpened()) {
        if (mCameraIdInUse == id) {
            LOG(DEBUG) << "Camera " << id << " is has opened already.";
            return true;
        }

        // Close a current camera device.
        if (!mServiceFactory->getService()->closeCamera(mCamera).isOk()) {
            LOG(WARNING) << "Failed to close a current camera device";
        }
    }

    auto it = std::find_if(mCameraList.begin(), mCameraList.end(),
                           [target = std::string(id)](const CameraDesc& desc) {
                               return target == desc.id;
                           });
    if (it == mCameraList.end()) {
        LOG(ERROR) << id << " is not available";
        return false;
    }

    std::vector<Stream> availableStreams;
    {
        std::lock_guard<std::mutex> lock(mLock);
        mServiceFactory->getService()->getStreamList(*it, &availableStreams);

        Stream streamConfig = selectStreamConfiguration(availableStreams);
        std::shared_ptr<IEvsCamera> camObj;
        if (!mServiceFactory->getService()->openCamera(id, streamConfig, &camObj).isOk() ||
            !camObj) {
            LOG(ERROR) << "Failed to open a camera " << id;
            return false;
        }

        std::shared_ptr<StreamHandler> streamHandler =
                ::ndk::SharedRefBase::make<StreamHandler>(camObj, this,
                                                          EvsServiceContext::kMaxNumFramesInFlight);
        if (!streamHandler) {
            LOG(ERROR) << "Failed to initialize a stream streamHandler.";
            if (!mServiceFactory->getService()->closeCamera(camObj).isOk()) {
                LOG(ERROR) << "Failed to close a temporary camera device";
            }
            return false;
        }

        mCamera = std::move(camObj);
        mStreamHandler = std::move(streamHandler);
        mCameraIdInUse = id;
    }

    return true;
}

从代码中可以看到,这里是通过mServiceFactory->getService()->openCamera来打开摄像机。mServiceFactory通过获取IEvsEnumerator服务来完成打开摄像机功能。因此Framework层的所有操作最终都指向了EvsEnumerator类,而在上一篇文章中我们也具体分析了这个类。

这段代码在后面创建了一个streamHandler,它用来管理视频流,完成视频流的开启和暂停传输等工作。

6 总结

通过上面的分析,可以总结出下面这张图片:

image.png