0 引言
在Android车载应用之EvsCameraPreview源码分析(二)中重点分析了startActivity过程,指名了自定义Evs应用的重点修改位置。接下来这篇文章想要介绍一下整个Evs应用的启动流程。
分析Evs的启动过程首先从查看Evs的日志开始,这里我们可以看到Evs的启动有几个关键的组件:evsmanagerd、EvsApp、android.hardware.automotive.evs-aidl-default-service和CAR.EVS这三个部分,下面将详细介绍它们。
1 evsmanagerd
evsmanagerd 是 EVS 系统中的核心管理进程(服务),负责初始化硬件服务、配置线程池并处理与硬件服务的通信。它通过命令行参数支持灵活的配置,包括连接模拟硬件或指定目标硬件服务。启动过程中,evsmanagerd 启动一个独立线程与硬件服务进行连接,并将主线程加入到线程池中,确保硬件交互的高效性和稳定性。整个过程确保了 EVS 系统能够在多线程环境下顺畅运行,并为后续的功能提供基础。
与evsmanagerd相关的代码位置在packages/services/Car/cpp/evs/manager中。
1.1 evsmanagerd.rc和init.evs.rc
evsmanagerd.rc的配置代码如下:
service evsmanagerd /system/bin/evsmanagerd
class early_hal
priority -20
user automotive_evs
group automotive_evs system
disabled # will not automatically start with its class; must be explicitly started.
这段配置文件描述了 evsmanagerd 服务的启动方式。它将服务设置为在早期硬件抽象层阶段启动,并指定了较高的优先级以确保尽早运行。服务会以 automotive_evs 用户身份运行,并且默认是禁用的,需要显式启动。这种配置可以确保 evsmanagerd 在系统启动时按需启动,并提供与硬件交互的支持。
init.evs.rc的配置代码如下:
on late-init
start evsmanagerd
这段配置通过 on late-init 确保在系统初始化的后期阶段启动 evsmanagerd 服务。这使得 evsmanagerd 在所有早期系统服务和硬件服务准备完毕后启动,从而避免干扰系统的初期启动过程,并确保其依赖的硬件服务已就绪。
1.2 Android.bp
重点找到与evsmanagerd服务进程相关的部分:
cc_binary {
name: "evsmanagerd",
defaults: ["evsmanagerd_defaults"],
static_libs: ["libevsmanagerd"],
srcs: ["src/service.cpp"],
init_rc: ["evsmanagerd.rc"],
vintf_fragments: ["manifest_evsmanagerd.xml"],
}
可以看到service.cpp文件就是实现evsmanagerd服务进程的源代码。
1.3 service.cpp
main函数的代码如下:
int main(int argc, char** argv) {
LOG(INFO) << "EVS manager starting";
// 命令行参数解析
bool printHelp = false;
std::string_view evsHardwareServiceName = kHardwareEnumeratorName;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--mock") == 0) {
evsHardwareServiceName = kMockEnumeratorName;
} else if (strcmp(argv[i], "--target") == 0) {
i++;
if (i >= argc) {
LOG(ERROR) << "--target <service> was not provided with a service name";
} else {
evsHardwareServiceName = argv[i];
}
} else if (strcmp(argv[i], "--help") == 0) {
printHelp = true;
} else {
printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
printHelp = true;
}
}
// 打印帮助信息
if (printHelp) {
printf("Options include:\n");
printf(" --mock Connect to the mock driver at EvsEnumeratorHw-Mock\n");
printf(" --target <service_name> Connect to the named IEvsEnumerator service");
return EXIT_SUCCESS;
}
// 设置线程池的最大线程数为 1
if (!ABinderProcess_setThreadPoolMaxThreadCount(/* numThreads = */ 1)) {
LOG(ERROR) << "Failed to set thread pool";
return EXIT_FAILURE;
}
// 创建一个新的线程来启动硬件服务连接(startService函数),确保硬件服务不会阻塞主线程
std::thread registrationThread(startService, evsHardwareServiceName, kManagedEnumeratorName);
// 主线程加入线程池,开始等待和处理来自硬件服务的 RPC 请求
ABinderProcess_startThreadPool();
LOG(INFO) << "Main thread entering thread pool";
ABinderProcess_joinThreadPool();
LOG(ERROR) << "EVS Hardware Enumerator is shutting down";
return EXIT_SUCCESS;
}
通过startService函数来看看具体是怎么连接硬件服务的:
void startService(const std::string_view& hardwareServiceName,
const std::string_view& managerServiceName) {
// 创建Enumerator类型的aidlService对象,并调用init函数进行初始化
LOG(INFO) << "EVS managed service connecting to hardware service at " << hardwareServiceName;
std::shared_ptr<Enumerator> aidlService = ::ndk::SharedRefBase::make<Enumerator>();
if (!aidlService->init(hardwareServiceName)) {
LOG(FATAL) << "Error while connecting to the hardware service, " << hardwareServiceName;
}
// 注册aidl服务
const std::string instanceName =
std::string(Enumerator::descriptor) + kSeparator + std::string(managerServiceName);
LOG(INFO) << "EVS managed service is starting as " << instanceName;
auto aidlStatus =
AServiceManager_addService(aidlService->asBinder().get(), instanceName.data());
if (aidlStatus != EX_NONE) {
LOG(FATAL) << "Error while registering EVS manager service: "
<< ::android::statusToString(aidlStatus);
}
// 注册hidl服务(可选)
configureRpcThreadpool(/* maxThreads = */ 1, /* callerWillJoin = */ false);
::android::sp<::android::hardware::automotive::evs::V1_1::IEvsEnumerator> hidlService =
new (std::nothrow) HidlEnumerator(aidlService);
if (!hidlService) {
LOG(WARNING) << "Failed to initialize HIDL service";
} else {
auto hidlStatus = hidlService->registerAsService(managerServiceName.data());
if (hidlStatus != ::android::OK) {
LOG(WARNING) << "Failed to register EVS manager service to the hwservice manager, "
<< ::android::statusToString(hidlStatus);
}
}
LOG(INFO) << "Registration complete";
}
startService函数的主要工作是通过Enumerator类的init函数不断地连接硬件服务,连接上硬件服务后将其注册到服务管理器中。init函数中不断连接并重启部分的代码如下:
while (!mHwEnumerator && retryCount < (kTimeoutMilliseconds / kSleepTimeMilliseconds)) {
mHwEnumerator = connectToAidlHal(hardwareServiceName, /* blocking= */ false);
if (!mHwEnumerator) {
LOG(INFO) << "Failed to connect to AIDL EVS HAL implementation. "
<< "Trying to connect to HIDL EVS HAL implementation instead.";
mHwEnumerator = connectToHidlHal(hardwareServiceName);
if (!mHwEnumerator) {
LOG(INFO) << "No EVS HAL implementation is available. Retrying after "
<< kSleepTimeMilliseconds << " ms";
std::this_thread::sleep_for(std::chrono::milliseconds(kSleepTimeMilliseconds));
++retryCount;
}
}
}
它会首先尝试AIDL接口的EVS HAL实现,然后再尝试HIDL的EVS HAL实现,如果都无法连接则会进行重启。从log信息中也可以看出来。
可以看到,连接上的HAL实现名称为android.hardware.automotive.evs.IEvsEnumerator/default,咱们找到相关部分的代码详细分析。
2 android.hardware.automotive.evs-aidl-default-service
android.hardware.automotive.evs-aidl-default-service 是 Android 为车载系统提供的一项 AIDL 服务,用于与 EVS 硬件(如摄像头)进行交互。它主要负责为系统提供实时的视频流数据,供应用程序或系统组件使用,支持车载系统中的增强视觉功能。
和它相关的代码目录在hardware/interfaces/automotive/evs/aidl/impl/default/位置。
2.1 evs-default-service.rc
该服务的rc定义如下:
service vendor.evs-hal-default /vendor/bin/hw/android.hardware.automotive.evs-aidl-default-service
class early_hal
priority -20
user graphics
group automotive_evs camera
onrestart restart cardisplayproxyd
onrestart restart evsmanagerd
disabled
它将android.hardware.automotive.evs-aidl-default-service进程定义为vendor.evs-hal-default服务,并且在该服务崩溃重启时,同时会重启cardisplayproxyd和evsmanagerd服务。
2.2 service.cpp
service.cpp中包含了服务的具体实现代码:
int main() {
LOG(INFO) << "EVS Hardware Enumerator service is starting";
// 检测显示服务是否声明
const std::string displayServiceInstanceName =
std::string(ICarDisplayProxy::descriptor) + std::string(kDisplayServiceInstanceName);
if (!AServiceManager_isDeclared(displayServiceInstanceName.data())) {
// TODO: We may just want to disable EVS display.
LOG(ERROR) << displayServiceInstanceName << " is required.";
return EXIT_FAILURE;
}
// 获取显示服务
std::shared_ptr<ICarDisplayProxy> displayService = ICarDisplayProxy::fromBinder(
::ndk::SpAIBinder(AServiceManager_waitForService(displayServiceInstanceName.data())));
if (!displayService) {
LOG(ERROR) << "Cannot use " << displayServiceInstanceName << ". Exiting.";
return EXIT_FAILURE;
}
// 创建 EVS 枚举器服务实例 `service`,并将 `displayService` 作为参数传入,表示与显示服务集成。
std::shared_ptr<EvsEnumerator> service =
ndk::SharedRefBase::make<EvsEnumerator>(displayService);
if (!service) {
LOG(ERROR) << "Failed to instantiate the service";
return EXIT_FAILURE;
}
// 通过 AServiceManager_addService 注册 EVS 服务
const std::string instanceName =
std::string(EvsEnumerator::descriptor) + std::string(kHwInstanceName);
auto err = AServiceManager_addService(service->asBinder().get(), instanceName.data());
if (err != EX_NONE) {
LOG(ERROR) << "Failed to register " << instanceName << ", exception = " << err;
return EXIT_FAILURE;
}
// 设置线程池并加入线程循环,保证正常服务运行
if (!ABinderProcess_setThreadPoolMaxThreadCount(kNumBinderThreads)) {
LOG(ERROR) << "Failed to set thread pool";
return EXIT_FAILURE;
}
ABinderProcess_startThreadPool();
LOG(INFO) << "EVS Hardware Enumerator is ready";
ABinderProcess_joinThreadPool();
// In normal operation, we don't expect the thread pool to exit
LOG(INFO) << "EVS Hardware Enumerator is shutting down";
return EXIT_SUCCESS;
}
这段代码实现了 EVS 硬件枚举器服务的启动流程,关键步骤包括:
- 检查并获取显示服务:首先验证并获取与显示相关的服务实例。
- 实例化 EVS 枚举器服务:通过显示服务实例化
EvsEnumerator服务。 - 注册服务到服务管理器:将 EVS 服务注册到系统的服务管理器,使其他组件可以访问。
- 设置并启动线程池:配置线程池并启动,确保可以处理并发的请求。
evsmanagerd获取的硬件服务就是该服务。
3 EvsApp
从引言中日志记录可以看到,EvsApp一直在尝试获取 EVS Enumerator,直到evsmanagerd获取到硬件服务后。
EvsApp负责初始化并管理 EVS 硬件、显示、车辆信号(例如:倒车档位信号),以及与 Vehicle HAL 的通信。
和它相关的代码在packages/services/Car/cpp/evs/apps/default中。
int main(int argc, char** argv) {
LOG(INFO) << "EVS app starting";
// Set up default behavior, then check for command line options
bool useVehicleHal = true;
bool printHelp = false;
const char* evsServiceName = "default";
int displayId = -1;
bool useExternalMemory = false;
android_pixel_format_t extMemoryFormat = HAL_PIXEL_FORMAT_RGBA_8888;
int32_t mockGearSignal = static_cast<int32_t>(VehicleGear::GEAR_REVERSE);
// 命令行参数解析
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--test") == 0) {
useVehicleHal = false;
} else if (strcmp(argv[i], "--hw") == 0) {
evsServiceName = "EvsEnumeratorHw";
} else if (strcmp(argv[i], "--mock") == 0) {
evsServiceName = "EvsEnumeratorHw-Mock";
} else if (strcmp(argv[i], "--help") == 0) {
printHelp = true;
} else if (strcmp(argv[i], "--display") == 0) {
displayId = std::stoi(argv[++i]);
} else if (strcmp(argv[i], "--extmem") == 0) {
useExternalMemory = true;
if (i + 1 >= argc) {
// use RGBA8888 by default
LOG(INFO) << "External buffer format is not set. "
<< "RGBA8888 will be used.";
} else {
if (!convertStringToFormat(argv[i + 1], &extMemoryFormat)) {
LOG(WARNING) << "Color format string " << argv[i + 1]
<< " is unknown or not supported. RGBA8888 will be used.";
} else {
// move the index
++i;
}
}
} else if (strcmp(argv[i], "--gear") == 0) {
// Gear signal to simulate
if (i + 1 >= argc) {
LOG(INFO) << "Gear signal is not set. "
<< "Reverse signal will be used.";
continue;
}
i += 1; // increase an index to next argument
if (strcasecmp(argv[i], "Park") == 0) {
mockGearSignal = static_cast<int32_t>(VehicleGear::GEAR_PARK);
} else if (strcasecmp(argv[i], "Reverse") != 0) {
LOG(WARNING) << "Unknown gear signal, " << argv[i] << ", is ignored "
<< "and the reverse signal will be used instead";
}
} else {
printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
printHelp = true;
}
}
if (printHelp) {
printf("Options include:\n");
printf(" --test\n\tDo not talk to Vehicle Hal, "
"but simulate a given mock gear signal instead\n");
printf(" --gear\n\tMock gear signal for the test mode.");
printf(" Available options are Reverse and Park (case insensitive)\n");
printf(" --hw\n\tBypass EvsManager by connecting directly to EvsEnumeratorHw\n");
printf(" --mock\n\tConnect directly to EvsEnumeratorHw-Mock\n");
printf(" --display\n\tSpecify the display to use. If this is not set, the first"
"display in config.json's list will be used.\n");
printf(" --extmem <format>\n\t"
"Application allocates buffers to capture camera frames. "
"Available format strings are (case insensitive):\n");
printf("\t\tRGBA8888: 4x8-bit RGBA format. This is the default format to be used "
"when no format is specified.\n");
printf("\t\tYV12: YUV420 planar format with a full resolution Y plane "
"followed by a V values, with U values last.\n");
printf("\t\tNV21: A biplanar format with a full resolution Y plane "
"followed by a single chrome plane with weaved V and U values.\n");
printf("\t\tYUYV: Packed format with a half horizontal chrome resolution. "
"Known as YUV4:2:2.\n");
return EXIT_FAILURE;
}
// 加载配置信息(车辆、显示器和相机)
ConfigManager config;
if (!config.initialize(CONFIG_OVERRIDE_PATH)) {
if (!config.initialize(CONFIG_DEFAULT_PATH)) {
LOG(ERROR) << "Missing or improper configuration for the EVS application. Exiting.";
return EXIT_FAILURE;
}
}
// 线程池配置
if (!ABinderProcess_setThreadPoolMaxThreadCount(/* numThreads= */ 1)) {
LOG(ERROR) << "Failed to confgiure the binder thread pool.";
return EXIT_FAILURE;
}
ABinderProcess_startThreadPool();
// Construct our async helper object
std::shared_ptr<EvsVehicleListener> pEvsListener = std::make_shared<EvsVehicleListener>();
// 获取EVS Enumerator服务(evsmanagerd中注册的服务)
LOG(INFO) << "Acquiring EVS Enumerator";
std::string serviceName =
std::string(IEvsEnumerator::descriptor) + "/" + std::string(evsServiceName);
if (!AServiceManager_isDeclared(serviceName.c_str())) {
LOG(ERROR) << serviceName << " is not declared. Exiting.";
return EXIT_FAILURE;
}
pEvsService = IEvsEnumerator::fromBinder(
ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
if (!pEvsService) {
LOG(ERROR) << "Failed to get " << serviceName << ". Exiting.";
return EXIT_FAILURE;
}
// 获取EVS Display服务
LOG(INFO) << "Acquiring EVS Display";
// We'll use an available display device.
displayId = config.setActiveDisplayId(displayId);
if (displayId < 0) {
PLOG(ERROR) << "EVS Display is unknown. Exiting.";
return EXIT_FAILURE;
}
if (auto status = pEvsService->openDisplay(displayId, &pDisplay); !status.isOk()) {
LOG(ERROR) << "EVS Display unavailable. Exiting.";
return EXIT_FAILURE;
}
config.useExternalMemory(useExternalMemory);
config.setExternalMemoryFormat(extMemoryFormat);
// 设置模拟倒车信号
config.setMockGearSignal(mockGearSignal);
// 连接到Vehicl HAL
std::shared_ptr<IVhalClient> pVnet;
if (useVehicleHal) {
LOG(INFO) << "Connecting to Vehicle HAL";
pVnet = IVhalClient::create();
if (pVnet == nullptr) {
LOG(ERROR) << "Vehicle HAL getService returned NULL. Exiting.";
return EXIT_FAILURE;
} else {
auto subscriptionClient = pVnet->getSubscriptionClient(pEvsListener);
// Register for vehicle state change callbacks we care about
// Changes in these values are what will trigger a reconfiguration of the EVS pipeline
if (!subscribeToVHal(subscriptionClient.get(), VehicleProperty::GEAR_SELECTION)) {
LOG(ERROR) << "Without gear notification, we can't support EVS. Exiting.";
return EXIT_FAILURE;
}
if (!subscribeToVHal(subscriptionClient.get(), VehicleProperty::TURN_SIGNAL_STATE)) {
LOG(WARNING) << "Didn't get turn signal notifications, so we'll ignore those.";
}
}
} else {
LOG(WARNING) << "Test mode selected, so not talking to Vehicle HAL";
}
// 创建并启动 EvsStateControl(状态控制器)来管理 EVS 服务的状态。
LOG(INFO) << "Constructing state controller";
pStateController = new EvsStateControl(pVnet, pEvsService, pDisplay, config);
if (!pStateController->startUpdateLoop()) {
LOG(ERROR) << "Initial configuration failed. Exiting.";
return EXIT_FAILURE;
}
// Run forever, reacting to events as necessary
LOG(INFO) << "Entering running state";
pEvsListener->run(pStateController);
// In normal operation, we expect to run forever, but in some error conditions we'll quit.
// One known example is if another process preempts our registration for our service name.
LOG(ERROR) << "EVS Listener stopped. Exiting.";
return EXIT_SUCCESS;
}
主要功能分析如下:
- 连接 EVS 服务
Evs App通过与 EVS 管理器(如EvsEnumerator)进行交互,连接到车辆的视觉系统。EvsEnumerator是一个服务,它为车辆提供硬件视觉数据流的管理,Evs App会通过它来获取、显示或处理摄像头图像、视频流等。 - 模拟车辆档位信号
Evs App允许模拟车辆的档位信号(如倒车、停车等)。这对于在开发环境或测试环境中模拟不同车辆状态(比如倒车时显示倒车影像)非常重要。 - 与 Vehicle HAL (硬件抽象层) 的集成
Evs App可以选择是否与 Vehicle HAL 进行交互。如果与 Vehicle HAL 集成,它能够监控车辆的状态变化(如档位变化、转向信号等),并根据这些变化动态调整 EVS 流程。例如,在倒车时(GEAR_REVERSE),它可能会自动启动显示倒车影像。
4 CAR.EVS
CAR.EVS进程指的是 CarEvsService.java,它是 Framework 层中的 EVS 服务类。该服务由 CarEvsManager 类进行管理,且 CarEvsPreviewActivity 通过 CarEvsManager 直接调用 EVS 服务。该部分内容比较多且重要,将不在本篇博客进行分析。
5 总结
本篇博客通过日志信息分析了整个Evs系统的启动流程,并分别介绍了其重要的组成部分:直接与硬件打交道的# android.hardware.automotive.evs-aidl-default-service进程;管理和连接硬件服务的evsmanagerd;与 Vehicle HAL 的通信EvsApp;Framework层的CAR.EVS。