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 #include "EvsStateControl.h"
17 #include "RenderDirectView.h"
18 #include "RenderTopView.h"
19 #include "RenderPixelCopy.h"
20 #include "FormatConvert.h"
21 
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include <android-base/logging.h>
26 #include <inttypes.h>
27 #include <utils/SystemClock.h>
28 #include <binder/IServiceManager.h>
29 
30 using ::android::hardware::automotive::evs::V1_0::EvsResult;
31 using EvsDisplayState = ::android::hardware::automotive::evs::V1_0::DisplayState;
32 using BufferDesc_1_0  = ::android::hardware::automotive::evs::V1_0::BufferDesc;
33 using BufferDesc_1_1  = ::android::hardware::automotive::evs::V1_1::BufferDesc;
34 
isSfReady()35 static bool isSfReady() {
36     const android::String16 serviceName("SurfaceFlinger");
37     return android::defaultServiceManager()->checkService(serviceName) != nullptr;
38 }
39 
40 // TODO:  Seems like it'd be nice if the Vehicle HAL provided such helpers (but how & where?)
getPropType(VehicleProperty prop)41 inline constexpr VehiclePropertyType getPropType(VehicleProperty prop) {
42     return static_cast<VehiclePropertyType>(
43             static_cast<int32_t>(prop)
44             & static_cast<int32_t>(VehiclePropertyType::MASK));
45 }
46 
47 
EvsStateControl(android::sp<IVehicle> pVnet,android::sp<IEvsEnumerator> pEvs,android::sp<IEvsDisplay> pDisplay,const ConfigManager & config)48 EvsStateControl::EvsStateControl(android::sp <IVehicle>       pVnet,
49                                  android::sp <IEvsEnumerator> pEvs,
50                                  android::sp <IEvsDisplay>    pDisplay,
51                                  const ConfigManager&         config) :
52     mVehicle(pVnet),
53     mEvs(pEvs),
54     mDisplay(pDisplay),
55     mConfig(config),
56     mCurrentState(OFF) {
57 
58     // Initialize the property value containers we'll be updating (they'll be zeroed by default)
59     static_assert(getPropType(VehicleProperty::GEAR_SELECTION) == VehiclePropertyType::INT32,
60                   "Unexpected type for GEAR_SELECTION property");
61     static_assert(getPropType(VehicleProperty::TURN_SIGNAL_STATE) == VehiclePropertyType::INT32,
62                   "Unexpected type for TURN_SIGNAL_STATE property");
63 
64     mGearValue.prop       = static_cast<int32_t>(VehicleProperty::GEAR_SELECTION);
65     mTurnSignalValue.prop = static_cast<int32_t>(VehicleProperty::TURN_SIGNAL_STATE);
66 
67     // This way we only ever deal with cameras which exist in the system
68     // Build our set of cameras for the states we support
69     LOG(DEBUG) << "Requesting camera list";
70     mEvs->getCameraList_1_1(
71         [this, &config](hidl_vec<CameraDesc> cameraList) {
72             LOG(INFO) << "Camera list callback received " << cameraList.size() << "cameras.";
73             for (auto&& cam: cameraList) {
74                 LOG(DEBUG) << "Found camera " << cam.v1.cameraId;
75                 bool cameraConfigFound = false;
76 
77                 // Check our configuration for information about this camera
78                 // Note that a camera can have a compound function string
79                 // such that a camera can be "right/reverse" and be used for both.
80                 // If more than one camera is listed for a given function, we'll
81                 // list all of them and let the UX/rendering logic use one, some
82                 // or all of them as appropriate.
83                 for (auto&& info: config.getCameras()) {
84                     if (cam.v1.cameraId == info.cameraId) {
85                         // We found a match!
86                         if (info.function.find("reverse") != std::string::npos) {
87                             mCameraList[State::REVERSE].emplace_back(info);
88                             mCameraDescList[State::REVERSE].emplace_back(cam);
89                         }
90                         if (info.function.find("right") != std::string::npos) {
91                             mCameraList[State::RIGHT].emplace_back(info);
92                             mCameraDescList[State::RIGHT].emplace_back(cam);
93                         }
94                         if (info.function.find("left") != std::string::npos) {
95                             mCameraList[State::LEFT].emplace_back(info);
96                             mCameraDescList[State::LEFT].emplace_back(cam);
97                         }
98                         if (info.function.find("park") != std::string::npos) {
99                             mCameraList[State::PARKING].emplace_back(info);
100                             mCameraDescList[State::PARKING].emplace_back(cam);
101                         }
102                         cameraConfigFound = true;
103                         break;
104                     }
105                 }
106                 if (!cameraConfigFound) {
107                     LOG(WARNING) << "No config information for hardware camera "
108                                  << cam.v1.cameraId;
109                 }
110             }
111         }
112     );
113 
114     LOG(DEBUG) << "State controller ready";
115 }
116 
117 
startUpdateLoop()118 bool EvsStateControl::startUpdateLoop() {
119     // Create the thread and report success if it gets started
120     mRenderThread = std::thread([this](){ updateLoop(); });
121     return mRenderThread.joinable();
122 }
123 
124 
terminateUpdateLoop()125 void EvsStateControl::terminateUpdateLoop() {
126     // Join a rendering thread
127     if (mRenderThread.joinable()) {
128         mRenderThread.join();
129     }
130 }
131 
132 
postCommand(const Command & cmd,bool clear)133 void EvsStateControl::postCommand(const Command& cmd, bool clear) {
134     // Push the command onto the queue watched by updateLoop
135     mLock.lock();
136     if (clear) {
137         std::queue<Command> emptyQueue;
138         std::swap(emptyQueue, mCommandQueue);
139     }
140 
141     mCommandQueue.push(cmd);
142     mLock.unlock();
143 
144     // Send a signal to wake updateLoop in case it is asleep
145     mWakeSignal.notify_all();
146 }
147 
148 
updateLoop()149 void EvsStateControl::updateLoop() {
150     LOG(DEBUG) << "Starting EvsStateControl update loop";
151 
152     bool run = true;
153     while (run) {
154         // Process incoming commands
155         {
156             std::lock_guard <std::mutex> lock(mLock);
157             while (!mCommandQueue.empty()) {
158                 const Command& cmd = mCommandQueue.front();
159                 switch (cmd.operation) {
160                 case Op::EXIT:
161                     run = false;
162                     break;
163                 case Op::CHECK_VEHICLE_STATE:
164                     // Just running selectStateForCurrentConditions below will take care of this
165                     break;
166                 case Op::TOUCH_EVENT:
167                     // Implement this given the x/y location of the touch event
168                     break;
169                 }
170                 mCommandQueue.pop();
171             }
172         }
173 
174         // Review vehicle state and choose an appropriate renderer
175         if (!selectStateForCurrentConditions()) {
176             LOG(ERROR) << "selectStateForCurrentConditions failed so we're going to die";
177             break;
178         }
179 
180         // If we have an active renderer, give it a chance to draw
181         if (mCurrentRenderer) {
182             // Get the output buffer we'll use to display the imagery
183             BufferDesc_1_0 tgtBuffer = {};
184             mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
185                                           tgtBuffer = buff;
186                                       }
187             );
188 
189             if (tgtBuffer.memHandle == nullptr) {
190                 LOG(ERROR) << "Didn't get requested output buffer -- skipping this frame.";
191             } else {
192                 // Generate our output image
193                 if (!mCurrentRenderer->drawFrame(convertBufferDesc(tgtBuffer))) {
194                     // If drawing failed, we want to exit quickly so an app restart can happen
195                     run = false;
196                 }
197 
198                 // Send the finished image back for display
199                 mDisplay->returnTargetBufferForDisplay(tgtBuffer);
200             }
201         } else if (run) {
202             // No active renderer, so sleep until somebody wakes us with another command
203             // or exit if we received EXIT command
204             std::unique_lock<std::mutex> lock(mLock);
205             mWakeSignal.wait(lock);
206         }
207     }
208 
209     LOG(WARNING) << "EvsStateControl update loop ending";
210 
211     if (mCurrentRenderer) {
212         // Deactive the renderer
213         mCurrentRenderer->deactivate();
214     }
215 
216     printf("Shutting down app due to state control loop ending\n");
217     LOG(ERROR) << "Shutting down app due to state control loop ending";
218 }
219 
220 
selectStateForCurrentConditions()221 bool EvsStateControl::selectStateForCurrentConditions() {
222     static int32_t sDummyGear   = int32_t(VehicleGear::GEAR_REVERSE);
223     static int32_t sDummySignal = int32_t(VehicleTurnSignal::NONE);
224 
225     if (mVehicle != nullptr) {
226         // Query the car state
227         if (invokeGet(&mGearValue) != StatusCode::OK) {
228             LOG(ERROR) << "GEAR_SELECTION not available from vehicle.  Exiting.";
229             return false;
230         }
231         if ((mTurnSignalValue.prop == 0) || (invokeGet(&mTurnSignalValue) != StatusCode::OK)) {
232             // Silently treat missing turn signal state as no turn signal active
233             mTurnSignalValue.value.int32Values.setToExternal(&sDummySignal, 1);
234             mTurnSignalValue.prop = 0;
235         }
236     } else {
237         // While testing without a vehicle, behave as if we're in reverse for the first 20 seconds
238         static const int kShowTime = 20;    // seconds
239 
240         // See if it's time to turn off the default reverse camera
241         static std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
242         std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
243         if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() > kShowTime) {
244             // Switch to drive (which should turn off the reverse camera)
245             sDummyGear = int32_t(VehicleGear::GEAR_DRIVE);
246         }
247 
248         // Build the dummy vehicle state values (treating single values as 1 element vectors)
249         mGearValue.value.int32Values.setToExternal(&sDummyGear, 1);
250         mTurnSignalValue.value.int32Values.setToExternal(&sDummySignal, 1);
251     }
252 
253     // Choose our desired EVS state based on the current car state
254     // TODO:  Update this logic, and consider user input when choosing if a view should be presented
255     State desiredState = OFF;
256     if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_REVERSE)) {
257         desiredState = REVERSE;
258     } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::RIGHT)) {
259         desiredState = RIGHT;
260     } else if (mTurnSignalValue.value.int32Values[0] == int32_t(VehicleTurnSignal::LEFT)) {
261         desiredState = LEFT;
262     } else if (mGearValue.value.int32Values[0] == int32_t(VehicleGear::GEAR_PARK)) {
263         desiredState = PARKING;
264     }
265 
266     // Apply the desire state
267     return configureEvsPipeline(desiredState);
268 }
269 
270 
invokeGet(VehiclePropValue * pRequestedPropValue)271 StatusCode EvsStateControl::invokeGet(VehiclePropValue *pRequestedPropValue) {
272     StatusCode status = StatusCode::TRY_AGAIN;
273 
274     // Call the Vehicle HAL, which will block until the callback is complete
275     mVehicle->get(*pRequestedPropValue,
276                   [pRequestedPropValue, &status]
277                   (StatusCode s, const VehiclePropValue& v) {
278                        status = s;
279                        if (s == StatusCode::OK) {
280                            *pRequestedPropValue = v;
281                        }
282                   }
283     );
284 
285     return status;
286 }
287 
288 
configureEvsPipeline(State desiredState)289 bool EvsStateControl::configureEvsPipeline(State desiredState) {
290     static bool isGlReady = false;
291 
292     if (mCurrentState == desiredState) {
293         // Nothing to do here...
294         return true;
295     }
296 
297     LOG(DEBUG) << "Switching to state " << desiredState;
298     LOG(DEBUG) << "  Current state " << mCurrentState
299                << " has " << mCameraList[mCurrentState].size() << " cameras";
300     LOG(DEBUG) << "  Desired state " << desiredState
301                << " has " << mCameraList[desiredState].size() << " cameras";
302 
303     if (!isGlReady && !isSfReady()) {
304         // Graphics is not ready yet; using CPU renderer.
305         if (mCameraList[desiredState].size() >= 1) {
306             mDesiredRenderer = std::make_unique<RenderPixelCopy>(mEvs,
307                                                                  mCameraList[desiredState][0]);
308             if (!mDesiredRenderer) {
309                 LOG(ERROR) << "Failed to construct Pixel Copy renderer.  Skipping state change.";
310                 return false;
311             }
312         } else {
313             LOG(DEBUG) << "Unsupported, desiredState " << desiredState
314                        << " has " << mCameraList[desiredState].size() << " cameras.";
315         }
316     } else {
317         // Assumes that SurfaceFlinger is available always after being launched.
318 
319         // Do we need a new direct view renderer?
320         if (mCameraList[desiredState].size() == 1) {
321             // We have a camera assigned to this state for direct view.
322             mDesiredRenderer = std::make_unique<RenderDirectView>(mEvs,
323                                                                   mCameraDescList[desiredState][0],
324                                                                   mConfig);
325             if (!mDesiredRenderer) {
326                 LOG(ERROR) << "Failed to construct direct renderer.  Skipping state change.";
327                 return false;
328             }
329         } else if (mCameraList[desiredState].size() > 1 || desiredState == PARKING) {
330             //TODO(b/140668179): RenderTopView needs to be updated to use new
331             //                   ConfigManager.
332             mDesiredRenderer = std::make_unique<RenderTopView>(mEvs,
333                                                                mCameraList[desiredState],
334                                                                mConfig);
335             if (!mDesiredRenderer) {
336                 LOG(ERROR) << "Failed to construct top view renderer.  Skipping state change.";
337                 return false;
338             }
339         } else {
340             LOG(DEBUG) << "Unsupported, desiredState " << desiredState
341                        << " has " << mCameraList[desiredState].size() << " cameras.";
342         }
343 
344         // GL renderer is now ready.
345         isGlReady = true;
346     }
347 
348     // Since we're changing states, shut down the current renderer
349     if (mCurrentRenderer != nullptr) {
350         mCurrentRenderer->deactivate();
351         mCurrentRenderer = nullptr; // It's a smart pointer, so destructs on assignment to null
352     }
353 
354     // Now set the display state based on whether we have a video feed to show
355     if (mDesiredRenderer == nullptr) {
356         LOG(DEBUG) << "Turning off the display";
357         mDisplay->setDisplayState(EvsDisplayState::NOT_VISIBLE);
358     } else {
359         mCurrentRenderer = std::move(mDesiredRenderer);
360 
361         // Start the camera stream
362         LOG(DEBUG) << "EvsStartCameraStreamTiming start time: "
363                    << android::elapsedRealtime() << " ms.";
364         if (!mCurrentRenderer->activate()) {
365             LOG(ERROR) << "New renderer failed to activate";
366             return false;
367         }
368 
369         // Activate the display
370         LOG(DEBUG) << "EvsActivateDisplayTiming start time: "
371                    << android::elapsedRealtime() << " ms.";
372         Return<EvsResult> result = mDisplay->setDisplayState(EvsDisplayState::VISIBLE_ON_NEXT_FRAME);
373         if (result != EvsResult::OK) {
374             LOG(ERROR) << "setDisplayState returned an error "
375                        << result.description();
376             return false;
377         }
378     }
379 
380     // Record our current state
381     LOG(INFO) << "Activated state " << desiredState;
382     mCurrentState = desiredState;
383 
384     return true;
385 }
386