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 <stdio.h>
18
19 #include <hidl/HidlTransportSupport.h>
20 #include <utils/Errors.h>
21 #include <utils/StrongPointer.h>
22 #include <utils/Log.h>
23
24 #include "android-base/macros.h" // arraysize
25
26 #include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
27 #include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
28
29 #include <hwbinder/ProcessState.h>
30
31 #include "EvsStateControl.h"
32 #include "EvsVehicleListener.h"
33 #include "ConfigManager.h"
34
35
36 // libhidl:
37 using android::hardware::configureRpcThreadpool;
38 using android::hardware::joinRpcThreadpool;
39
40
41 // Helper to subscribe to VHal notifications
subscribeToVHal(sp<IVehicle> pVnet,sp<IVehicleCallback> listener,VehicleProperty propertyId)42 static bool subscribeToVHal(sp<IVehicle> pVnet,
43 sp<IVehicleCallback> listener,
44 VehicleProperty propertyId) {
45 assert(pVnet != nullptr);
46 assert(listener != nullptr);
47
48 // Register for vehicle state change callbacks we care about
49 // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
50 SubscribeOptions optionsData[] = {
51 {
52 .propId = static_cast<int32_t>(propertyId),
53 .flags = SubscribeFlags::EVENTS_FROM_CAR
54 },
55 };
56 hidl_vec <SubscribeOptions> options;
57 options.setToExternal(optionsData, arraysize(optionsData));
58 StatusCode status = pVnet->subscribe(listener, options);
59 if (status != StatusCode::OK) {
60 ALOGW("VHAL subscription for property 0x%08X failed with code %d.", propertyId, status);
61 return false;
62 }
63
64 return true;
65 }
66
67
68 // Main entry point
main(int argc,char ** argv)69 int main(int argc, char** argv)
70 {
71 ALOGI("EVS app starting\n");
72
73 // Set up default behavior, then check for command line options
74 bool useVehicleHal = true;
75 bool printHelp = false;
76 const char* evsServiceName = "default";
77 for (int i=1; i< argc; i++) {
78 if (strcmp(argv[i], "--test") == 0) {
79 useVehicleHal = false;
80 } else if (strcmp(argv[i], "--hw") == 0) {
81 evsServiceName = "EvsEnumeratorHw";
82 } else if (strcmp(argv[i], "--mock") == 0) {
83 evsServiceName = "EvsEnumeratorHw-Mock";
84 } else if (strcmp(argv[i], "--help") == 0) {
85 printHelp = true;
86 } else {
87 printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
88 printHelp = true;
89 }
90 }
91 if (printHelp) {
92 printf("Options include:\n");
93 printf(" --test Do not talk to Vehicle Hal, but simulate 'reverse' instead\n");
94 printf(" --hw Bypass EvsManager by connecting directly to EvsEnumeratorHw\n");
95 printf(" --mock Connect directly to EvsEnumeratorHw-Mock\n");
96 }
97
98 // Load our configuration information
99 ConfigManager config;
100 if (!config.initialize("/system/etc/automotive/evs/config.json")) {
101 ALOGE("Missing or improper configuration for the EVS application. Exiting.");
102 return 1;
103 }
104
105 // Set thread pool size to one to avoid concurrent events from the HAL.
106 // This pool will handle the EvsCameraStream callbacks.
107 // Note: This _will_ run in parallel with the EvsListener run() loop below which
108 // runs the application logic that reacts to the async events.
109 configureRpcThreadpool(1, false /* callerWillJoin */);
110
111 // Construct our async helper object
112 sp<EvsVehicleListener> pEvsListener = new EvsVehicleListener();
113
114 // Get the EVS manager service
115 ALOGI("Acquiring EVS Enumerator");
116 android::sp<IEvsEnumerator> pEvs = IEvsEnumerator::getService(evsServiceName);
117 if (pEvs.get() == nullptr) {
118 ALOGE("getService(%s) returned NULL. Exiting.", evsServiceName);
119 return 1;
120 }
121
122 // Request exclusive access to the EVS display
123 ALOGI("Acquiring EVS Display");
124 android::sp <IEvsDisplay> pDisplay;
125 pDisplay = pEvs->openDisplay();
126 if (pDisplay.get() == nullptr) {
127 ALOGE("EVS Display unavailable. Exiting.");
128 return 1;
129 }
130
131 // Connect to the Vehicle HAL so we can monitor state
132 sp<IVehicle> pVnet;
133 if (useVehicleHal) {
134 ALOGI("Connecting to Vehicle HAL");
135 pVnet = IVehicle::getService();
136 if (pVnet.get() == nullptr) {
137 ALOGE("Vehicle HAL getService returned NULL. Exiting.");
138 return 1;
139 } else {
140 // Register for vehicle state change callbacks we care about
141 // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
142 if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::GEAR_SELECTION)) {
143 ALOGE("Without gear notification, we can't support EVS. Exiting.");
144 return 1;
145 }
146 if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::TURN_SIGNAL_STATE)) {
147 ALOGW("Didn't get turn signal notificaitons, so we'll ignore those.");
148 }
149 }
150 } else {
151 ALOGW("Test mode selected, so not talking to Vehicle HAL");
152 }
153
154 // Configure ourselves for the current vehicle state at startup
155 ALOGI("Constructing state controller");
156 EvsStateControl *pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);
157 if (!pStateController->startUpdateLoop()) {
158 ALOGE("Initial configuration failed. Exiting.");
159 return 1;
160 }
161
162 // Run forever, reacting to events as necessary
163 ALOGI("Entering running state");
164 pEvsListener->run(pStateController);
165
166 // In normal operation, we expect to run forever, but in some error conditions we'll quit.
167 // One known example is if another process preempts our registration for our service name.
168 ALOGE("EVS Listener stopped. Exiting.");
169
170 return 0;
171 }
172