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 #define LOG_TAG "EVSAPP"
18 
19 #include <stdio.h>
20 
21 #include <hidl/HidlTransportSupport.h>
22 #include <utils/Errors.h>
23 #include <utils/StrongPointer.h>
24 #include <utils/Log.h>
25 
26 #include "android-base/macros.h"    // arraysize
27 
28 #include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
29 #include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
30 
31 #include <hwbinder/ProcessState.h>
32 
33 #include "EvsStateControl.h"
34 #include "EvsVehicleListener.h"
35 #include "ConfigManager.h"
36 
37 
38 // libhidl:
39 using android::hardware::configureRpcThreadpool;
40 using android::hardware::joinRpcThreadpool;
41 
42 
43 // TODO:  Should this somehow be a shared definition with the module itself?
44 const static char kEvsServiceName[] = "EvsSharedEnumerator";
45 
46 
47 // Main entry point
main(int,char **)48 int main(int /* argc */, char** /* argv */)
49 {
50     printf("EVS app starting\n");
51 
52     // Load our configuration information
53     ConfigManager config;
54     config.initialize("config.json");
55 
56     // Set thread pool size to one to avoid concurrent events from the HAL.
57     // This pool will handle the EvsCameraStream callbacks.
58     // Note:  This _will_ run in parallel with the EvsListener run() loop below which
59     // runs the application logic that reacts to the async events.
60     configureRpcThreadpool(1, false /* callerWillJoin */);
61 
62     // Construct our async helper object
63     sp<EvsVehicleListener> pEvsListener = new EvsVehicleListener();
64 
65     // Get the EVS manager service
66     ALOGI("Acquiring EVS Enumerator");
67     android::sp<IEvsEnumerator> pEvs = IEvsEnumerator::getService(kEvsServiceName);
68     if (pEvs.get() == nullptr) {
69         ALOGE("getService returned NULL.  Exiting.");
70         return 1;
71     }
72 
73     // Request exclusive access to the EVS display
74     ALOGI("Acquiring EVS Display");
75     android::sp <IEvsDisplay> pDisplay;
76     pDisplay = pEvs->openDisplay();
77     if (pDisplay.get() == nullptr) {
78         ALOGE("EVS Display unavailable.  Exiting.");
79         return 1;
80     }
81 
82     // Connect to the Vehicle HAL so we can monitor state
83     ALOGI("Connecting to Vehicle HAL");
84     android::sp <IVehicle> pVnet = IVehicle::getService();
85     if (pVnet.get() == nullptr) {
86 #if 0
87         ALOGE("Vehicle HAL getService returned NULL.  Exiting.");
88         return 1;
89 #else
90         // While testing, at least, we want to be able to run without a vehicle
91         ALOGE("getService returned NULL, but we're in test, so we'll pretend to be in reverse");
92 #endif
93     } else {
94         // Register for vehicle state change callbacks we care about
95         // Changes in these values are what will trigger a reconfiguration of the EVS pipeline
96         SubscribeOptions optionsData[2] = {
97                 {
98                     .propId = static_cast<int32_t>(VehicleProperty::GEAR_SELECTION),
99                     .flags = SubscribeFlags::DEFAULT
100                 },
101                 {
102                     .propId = static_cast<int32_t>(VehicleProperty::TURN_SIGNAL_STATE),
103                     .flags = SubscribeFlags::DEFAULT
104                 },
105         };
106         hidl_vec<SubscribeOptions> options;
107         options.setToExternal(optionsData, arraysize(optionsData));
108         StatusCode status = pVnet->subscribe(pEvsListener, options);
109         if (status != StatusCode::OK) {
110             ALOGE("Subscription to vehicle notifications failed with code %d.  Exiting.", status);
111             return 1;
112         }
113     }
114 
115     // Configure ourselves for the current vehicle state at startup
116     ALOGI("Constructing state controller");
117     EvsStateControl *pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);
118     if (!pStateController->configureForVehicleState()) {
119         ALOGE("Initial configuration failed.  Exiting.");
120         return 1;
121     } else {
122         // Run forever, reacting to events as necessary
123         ALOGI("Entering running state");
124         pEvsListener->run(pStateController);
125     }
126 
127     // In normal operation, we expect to run forever, but in some error conditions we'll quit.
128     // One known example is if another process preempts our registration for our service name.
129     printf("EVS Listener stopped.  Exiting.\n");
130     return 0;
131 }
132