Home | History | Annotate | Download | only in app
      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