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 总结
通过上面的分析,可以总结出下面这张图片: