1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "Enumerator.h"
18 #include "HidlEnumerator.h"
19 #include "ServiceNames.h"
20
21 #include <android-base/logging.h>
22 #include <android/binder_manager.h>
23 #include <android/binder_process.h>
24 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
25 #include <hidl/HidlTransportSupport.h>
26
27 #include <string_view>
28
29 namespace {
30
31 using ::aidl::android::automotive::evs::implementation::Enumerator;
32 using ::aidl::android::automotive::evs::implementation::HidlEnumerator;
33 using ::android::hardware::configureRpcThreadpool;
34
35 const std::string kSeparator = "/";
36
startService(const std::string_view & hardwareServiceName,const std::string_view & managerServiceName)37 void startService(const std::string_view& hardwareServiceName,
38 const std::string_view& managerServiceName) {
39 LOG(INFO) << "EVS managed service connecting to hardware service at " << hardwareServiceName;
40 std::shared_ptr<Enumerator> aidlService = ::ndk::SharedRefBase::make<Enumerator>();
41 if (!aidlService->init(hardwareServiceName)) {
42 LOG(FATAL) << "Error while connecting to the hardware service, " << hardwareServiceName;
43 }
44
45 // Register our service -- if somebody is already registered by our name,
46 // they will be killed (their thread pool will throw an exception).
47 const std::string instanceName =
48 std::string(Enumerator::descriptor) + kSeparator + std::string(managerServiceName);
49 LOG(INFO) << "EVS managed service is starting as " << instanceName;
50 auto aidlStatus =
51 AServiceManager_addService(aidlService->asBinder().get(), instanceName.data());
52 if (aidlStatus != EX_NONE) {
53 LOG(FATAL) << "Error while registering EVS manager service: "
54 << ::android::statusToString(aidlStatus);
55 }
56
57 // We also register our service to the hwservice manager. This is an
58 // optional functionality so we ignore any errors.
59 configureRpcThreadpool(/* maxThreads = */ 1, /* callerWillJoin = */ false);
60 ::android::sp<::android::hardware::automotive::evs::V1_1::IEvsEnumerator> hidlService =
61 new (std::nothrow) HidlEnumerator(aidlService);
62 if (!hidlService) {
63 LOG(WARNING) << "Failed to initialize HIDL service";
64 } else {
65 auto hidlStatus = hidlService->registerAsService(managerServiceName.data());
66 if (hidlStatus != ::android::OK) {
67 LOG(WARNING) << "Failed to register EVS manager service to the hwservice manager, "
68 << ::android::statusToString(hidlStatus);
69 }
70 }
71
72 LOG(INFO) << "Registration complete";
73 }
74
75 } // namespace
76
main(int argc,char ** argv)77 int main(int argc, char** argv) {
78 LOG(INFO) << "EVS manager starting";
79
80 // Set up default behavior, then check for command line options
81 bool printHelp = false;
82 std::string_view evsHardwareServiceName = kHardwareEnumeratorName;
83 for (int i = 1; i < argc; i++) {
84 if (strcmp(argv[i], "--mock") == 0) {
85 evsHardwareServiceName = kMockEnumeratorName;
86 } else if (strcmp(argv[i], "--target") == 0) {
87 i++;
88 if (i >= argc) {
89 LOG(ERROR) << "--target <service> was not provided with a service name";
90 } else {
91 evsHardwareServiceName = argv[i];
92 }
93 } else if (strcmp(argv[i], "--help") == 0) {
94 printHelp = true;
95 } else {
96 printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
97 printHelp = true;
98 }
99 }
100
101 if (printHelp) {
102 printf("Options include:\n");
103 printf(" --mock Connect to the mock driver at EvsEnumeratorHw-Mock\n");
104 printf(" --target <service_name> Connect to the named IEvsEnumerator service");
105 return EXIT_SUCCESS;
106 }
107
108 // Prepare the RPC serving thread pool. We're configuring it with no additional
109 // threads beyond the main thread which will "join" the pool below.
110 if (!ABinderProcess_setThreadPoolMaxThreadCount(/* numThreads = */ 1)) {
111 LOG(ERROR) << "Failed to set thread pool";
112 return EXIT_FAILURE;
113 }
114
115 // The connection to the underlying hardware service must happen on a dedicated thread to ensure
116 // that the hwbinder response can be processed by the thread pool without blocking.
117 std::thread registrationThread(startService, evsHardwareServiceName, kManagedEnumeratorName);
118
119 // Send this main thread to become a permanent part of the thread pool.
120 // This is not expected to return.
121 ABinderProcess_startThreadPool();
122 LOG(INFO) << "Main thread entering thread pool";
123
124 // In normal operation, we don't expect the thread pool to exit
125 ABinderProcess_joinThreadPool();
126 LOG(ERROR) << "EVS Hardware Enumerator is shutting down";
127
128 return EXIT_SUCCESS;
129 }
130