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