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