1 /*
2  * Copyright (C) 2016 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 "ConfigManager.h"
18 #include "EvsStateControl.h"
19 #include "EvsVehicleListener.h"
20 
21 #include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
22 #include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
23 #include <aidl/android/hardware/automotive/vehicle/SubscribeOptions.h>
24 #include <aidl/android/hardware/automotive/vehicle/VehicleGear.h>
25 #include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
26 #include <android-base/logging.h>
27 #include <android-base/strings.h>
28 #include <android/binder_ibinder.h>
29 #include <android/binder_manager.h>
30 #include <android/binder_process.h>
31 #include <utils/Errors.h>
32 #include <utils/Log.h>
33 #include <utils/StrongPointer.h>
34 
35 #include <IVhalClient.h>
36 #include <assert.h>
37 #include <signal.h>
38 #include <stdio.h>
39 
40 namespace {
41 
42 using aidl::android::hardware::automotive::evs::IEvsDisplay;
43 using aidl::android::hardware::automotive::evs::IEvsEnumerator;
44 using aidl::android::hardware::automotive::vehicle::VehicleGear;
45 using aidl::android::hardware::automotive::vehicle::VehicleProperty;
46 using android::base::EqualsIgnoreCase;
47 using android::frameworks::automotive::vhal::ISubscriptionClient;
48 using android::frameworks::automotive::vhal::IVhalClient;
49 
50 const char CONFIG_DEFAULT_PATH[] = "/system/etc/automotive/evs/config.json";
51 const char CONFIG_OVERRIDE_PATH[] = "/vendor/etc/automotive/evs/config_override.json";
52 
53 std::shared_ptr<IEvsEnumerator> pEvsService;
54 std::shared_ptr<IEvsDisplay> pDisplay;
55 EvsStateControl* pStateController;
56 
57 // Helper to subscribe to Vhal notifications
subscribeToVHal(ISubscriptionClient * client,VehicleProperty propertyId)58 bool subscribeToVHal(ISubscriptionClient* client, VehicleProperty propertyId) {
59     assert(pVnet != nullptr);
60     assert(listener != nullptr);
61 
62     // Register for vehicle state change callbacks we care about
63     // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
64     std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions> options = {
65             {
66                     .propId = static_cast<int32_t>(propertyId),
67                     .areaIds = {},
68             },
69     };
70     if (auto result = client->subscribe(options); !result.ok()) {
71         LOG(WARNING) << "VHAL subscription for property " << static_cast<int32_t>(propertyId)
72                      << " failed with error " << result.error().message();
73         return false;
74     }
75 
76     return true;
77 }
78 
convertStringToFormat(const char * str,android_pixel_format_t * output)79 bool convertStringToFormat(const char* str, android_pixel_format_t* output) {
80     bool result = true;
81     if (EqualsIgnoreCase(str, "RGBA8888")) {
82         *output = HAL_PIXEL_FORMAT_RGBA_8888;
83     } else if (EqualsIgnoreCase(str, "YV12")) {
84         *output = HAL_PIXEL_FORMAT_YV12;
85     } else if (EqualsIgnoreCase(str, "NV21")) {
86         *output = HAL_PIXEL_FORMAT_YCrCb_420_SP;
87     } else if (EqualsIgnoreCase(str, "YUYV")) {
88         *output = HAL_PIXEL_FORMAT_YCBCR_422_I;
89     } else {
90         result = false;
91     }
92 
93     return result;
94 }
95 
96 }  // namespace
97 
98 // Main entry point
main(int argc,char ** argv)99 int main(int argc, char** argv) {
100     LOG(INFO) << "EVS app starting";
101 
102     // Set up default behavior, then check for command line options
103     bool useVehicleHal = true;
104     bool printHelp = false;
105     const char* evsServiceName = "default";
106     int displayId = -1;
107     bool useExternalMemory = false;
108     android_pixel_format_t extMemoryFormat = HAL_PIXEL_FORMAT_RGBA_8888;
109     int32_t mockGearSignal = static_cast<int32_t>(VehicleGear::GEAR_REVERSE);
110     for (int i = 1; i < argc; i++) {
111         if (strcmp(argv[i], "--test") == 0) {
112             useVehicleHal = false;
113         } else if (strcmp(argv[i], "--hw") == 0) {
114             evsServiceName = "EvsEnumeratorHw";
115         } else if (strcmp(argv[i], "--mock") == 0) {
116             evsServiceName = "EvsEnumeratorHw-Mock";
117         } else if (strcmp(argv[i], "--help") == 0) {
118             printHelp = true;
119         } else if (strcmp(argv[i], "--display") == 0) {
120             displayId = std::stoi(argv[++i]);
121         } else if (strcmp(argv[i], "--extmem") == 0) {
122             useExternalMemory = true;
123             if (i + 1 >= argc) {
124                 // use RGBA8888 by default
125                 LOG(INFO) << "External buffer format is not set.  " << "RGBA8888 will be used.";
126             } else {
127                 if (!convertStringToFormat(argv[i + 1], &extMemoryFormat)) {
128                     LOG(WARNING) << "Color format string " << argv[i + 1]
129                                  << " is unknown or not supported.  RGBA8888 will be used.";
130                 } else {
131                     // move the index
132                     ++i;
133                 }
134             }
135         } else if (strcmp(argv[i], "--gear") == 0) {
136             // Gear signal to simulate
137             if (i + 1 >= argc) {
138                 LOG(INFO) << "Gear signal is not set.  " << "Reverse signal will be used.";
139                 continue;
140             }
141             i += 1;  // increase an index to next argument
142             if (strcasecmp(argv[i], "Park") == 0) {
143                 mockGearSignal = static_cast<int32_t>(VehicleGear::GEAR_PARK);
144             } else if (strcasecmp(argv[i], "Reverse") != 0) {
145                 LOG(WARNING) << "Unknown gear signal, " << argv[i] << ", is ignored "
146                              << "and the reverse signal will be used instead";
147             }
148         } else {
149             printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
150             printHelp = true;
151         }
152     }
153     if (printHelp) {
154         printf("Options include:\n");
155         printf("  --test\n\tDo not talk to Vehicle Hal, "
156                "but simulate a given mock gear signal instead\n");
157         printf("  --gear\n\tMock gear signal for the test mode.");
158         printf("  Available options are Reverse and Park (case insensitive)\n");
159         printf("  --hw\n\tBypass EvsManager by connecting directly to EvsEnumeratorHw\n");
160         printf("  --mock\n\tConnect directly to EvsEnumeratorHw-Mock\n");
161         printf("  --display\n\tSpecify the display to use.  If this is not set, the first"
162                "display in config.json's list will be used.\n");
163         printf("  --extmem  <format>\n\t"
164                "Application allocates buffers to capture camera frames.  "
165                "Available format strings are (case insensitive):\n");
166         printf("\t\tRGBA8888: 4x8-bit RGBA format.  This is the default format to be used "
167                "when no format is specified.\n");
168         printf("\t\tYV12: YUV420 planar format with a full resolution Y plane "
169                "followed by a V values, with U values last.\n");
170         printf("\t\tNV21: A biplanar format with a full resolution Y plane "
171                "followed by a single chrome plane with weaved V and U values.\n");
172         printf("\t\tYUYV: Packed format with a half horizontal chrome resolution.  "
173                "Known as YUV4:2:2.\n");
174 
175         return EXIT_FAILURE;
176     }
177 
178     // Load our configuration information
179     ConfigManager config;
180     if (!config.initialize(CONFIG_OVERRIDE_PATH)) {
181         if (!config.initialize(CONFIG_DEFAULT_PATH)) {
182             LOG(ERROR) << "Missing or improper configuration for the EVS application.  Exiting.";
183             return EXIT_FAILURE;
184         }
185     }
186 
187     // Set thread pool size to one to avoid concurrent events from the HAL.
188     // This pool will handle the EvsCameraStream callbacks.
189     // Note:  This _will_ run in parallel with the EvsListener run() loop below which
190     // runs the application logic that reacts to the async events.
191     if (!ABinderProcess_setThreadPoolMaxThreadCount(/* numThreads= */ 1)) {
192         LOG(ERROR) << "Failed to confgiure the binder thread pool.";
193         return EXIT_FAILURE;
194     }
195     ABinderProcess_startThreadPool();
196 
197     // Construct our async helper object
198     std::shared_ptr<EvsVehicleListener> pEvsListener = std::make_shared<EvsVehicleListener>();
199 
200     // Get the EVS manager service
201     LOG(INFO) << "Acquiring EVS Enumerator";
202     std::string serviceName =
203             std::string(IEvsEnumerator::descriptor) + "/" + std::string(evsServiceName);
204     if (!AServiceManager_isDeclared(serviceName.c_str())) {
205         LOG(ERROR) << serviceName << " is not declared. Exiting.";
206         return EXIT_FAILURE;
207     }
208 
209     pEvsService = IEvsEnumerator::fromBinder(
210             ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
211     if (!pEvsService) {
212         LOG(ERROR) << "Failed to get " << serviceName << ". Exiting.";
213         return EXIT_FAILURE;
214     }
215 
216     // Request exclusive access to the EVS display
217     LOG(INFO) << "Acquiring EVS Display";
218 
219     // We'll use an available display device.
220     displayId = config.setActiveDisplayId(displayId);
221     if (displayId < 0) {
222         PLOG(ERROR) << "EVS Display is unknown.  Exiting.";
223         return EXIT_FAILURE;
224     }
225 
226     if (auto status = pEvsService->openDisplay(displayId, &pDisplay); !status.isOk()) {
227         LOG(ERROR) << "EVS Display unavailable.  Exiting.";
228         return EXIT_FAILURE;
229     }
230 
231     config.useExternalMemory(useExternalMemory);
232     config.setExternalMemoryFormat(extMemoryFormat);
233 
234     // Set a mock gear signal for the test mode
235     config.setMockGearSignal(mockGearSignal);
236 
237     // Connect to the Vehicle HAL so we can monitor state
238     std::shared_ptr<IVhalClient> pVnet;
239     if (useVehicleHal) {
240         LOG(INFO) << "Connecting to Vehicle HAL";
241         pVnet = IVhalClient::create();
242         if (pVnet == nullptr) {
243             LOG(ERROR) << "Vehicle HAL getService returned NULL.  Exiting.";
244             return EXIT_FAILURE;
245         } else {
246             auto subscriptionClient = pVnet->getSubscriptionClient(pEvsListener);
247             // Register for vehicle state change callbacks we care about
248             // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
249             if (!subscribeToVHal(subscriptionClient.get(), VehicleProperty::GEAR_SELECTION)) {
250                 LOG(ERROR) << "Without gear notification, we can't support EVS.  Exiting.";
251                 return EXIT_FAILURE;
252             }
253             if (!subscribeToVHal(subscriptionClient.get(), VehicleProperty::TURN_SIGNAL_STATE)) {
254                 LOG(WARNING) << "Didn't get turn signal notifications, so we'll ignore those.";
255             }
256         }
257     } else {
258         LOG(WARNING) << "Test mode selected, so not talking to Vehicle HAL";
259     }
260 
261     // Configure ourselves for the current vehicle state at startup
262     LOG(INFO) << "Constructing state controller";
263     pStateController = new EvsStateControl(pVnet, pEvsService, pDisplay, config);
264     if (!pStateController->startUpdateLoop()) {
265         LOG(ERROR) << "Initial configuration failed.  Exiting.";
266         return EXIT_FAILURE;
267     }
268 
269     // Run forever, reacting to events as necessary
270     LOG(INFO) << "Entering running state";
271     pEvsListener->run(pStateController);
272 
273     // In normal operation, we expect to run forever, but in some error conditions we'll quit.
274     // One known example is if another process preempts our registration for our service name.
275     LOG(ERROR) << "EVS Listener stopped.  Exiting.";
276 
277     return EXIT_SUCCESS;
278 }
279