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 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 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