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 "android.hardware.automotive.evs@1.0-service"
18 
19 #include "EvsEnumerator.h"
20 #include "EvsCamera.h"
21 #include "EvsDisplay.h"
22 
23 namespace android {
24 namespace hardware {
25 namespace automotive {
26 namespace evs {
27 namespace V1_0 {
28 namespace implementation {
29 
30 
31 // NOTE:  All members values are static so that all clients operate on the same state
32 //        That is to say, this is effectively a singleton despite the fact that HIDL
33 //        constructs a new instance for each client.
34 std::list<EvsEnumerator::CameraRecord>   EvsEnumerator::sCameraList;
35 wp<EvsDisplay>                           EvsEnumerator::sActiveDisplay;
36 
37 
EvsEnumerator()38 EvsEnumerator::EvsEnumerator() {
39     ALOGD("EvsEnumerator created");
40 
41     // Add sample camera data to our list of cameras
42     // In a real driver, this would be expected to can the available hardware
43     sCameraList.emplace_back(EvsCamera::kCameraName_Backup);
44     sCameraList.emplace_back("LaneView");
45     sCameraList.emplace_back("right turn");
46 }
47 
48 
49 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
getCameraList(getCameraList_cb _hidl_cb)50 Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb)  {
51     ALOGD("getCameraList");
52 
53     const unsigned numCameras = sCameraList.size();
54 
55     // Build up a packed array of CameraDesc for return
56     // NOTE:  Only has to live until the callback returns
57     std::vector<CameraDesc> descriptions;
58     descriptions.reserve(numCameras);
59     for (const auto& cam : sCameraList) {
60         descriptions.push_back( cam.desc );
61     }
62 
63     // Encapsulate our camera descriptions in the HIDL vec type
64     hidl_vec<CameraDesc> hidlCameras(descriptions);
65 
66     // Send back the results
67     ALOGD("reporting %zu cameras available", hidlCameras.size());
68     _hidl_cb(hidlCameras);
69 
70     // HIDL convention says we return Void if we sent our result back via callback
71     return Void();
72 }
73 
74 
openCamera(const hidl_string & cameraId)75 Return<sp<IEvsCamera>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
76     ALOGD("openCamera");
77 
78     // Find the named camera
79     CameraRecord *pRecord = nullptr;
80     for (auto &&cam : sCameraList) {
81         if (cam.desc.cameraId == cameraId) {
82             // Found a match!
83             pRecord = &cam;
84             break;
85         }
86     }
87 
88     // Is this a recognized camera id?
89     if (!pRecord) {
90         ALOGE("Requested camera %s not found", cameraId.c_str());
91         return nullptr;
92     }
93 
94     // Has this camera already been instantiated by another caller?
95     sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
96     if (pActiveCamera != nullptr) {
97         ALOGW("Killing previous camera because of new caller");
98         closeCamera(pActiveCamera);
99     }
100 
101     // Construct a camera instance for the caller
102     pActiveCamera = new EvsCamera(cameraId.c_str());
103     pRecord->activeInstance = pActiveCamera;
104     if (pActiveCamera == nullptr) {
105         ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
106     }
107 
108     return pActiveCamera;
109 }
110 
111 
closeCamera(const::android::sp<IEvsCamera> & pCamera)112 Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& pCamera) {
113     ALOGD("closeCamera");
114 
115     if (pCamera == nullptr) {
116         ALOGE("Ignoring call to closeCamera with null camera ptr");
117         return Void();
118     }
119 
120     // Get the camera id so we can find it in our list
121     std::string cameraId;
122     pCamera->getCameraInfo([&cameraId](CameraDesc desc) {
123 // TODO(b/36532780) Should we able to just use a simple assignment?
124 //                             cameraId = desc.cameraId;
125                                cameraId.assign(desc.cameraId.c_str());
126                            }
127     );
128 
129     // Find the named camera
130     CameraRecord *pRecord = nullptr;
131     for (auto &&cam : sCameraList) {
132         if (cam.desc.cameraId == cameraId) {
133             // Found a match!
134             pRecord = &cam;
135             break;
136         }
137     }
138 
139     // Is the display being destroyed actually the one we think is active?
140     if (!pRecord) {
141         ALOGE("Asked to close a camera who's name isn't recognized");
142     } else {
143         sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
144 
145         if (pActiveCamera == nullptr) {
146             ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed");
147         } else if (pActiveCamera != pCamera) {
148             // This can happen if the camera was aggressively reopened, orphaning this previous instance
149             ALOGW("Ignoring close of previously orphaned camera - why did a client steal?");
150         } else {
151             // Drop the active camera
152             pActiveCamera->forceShutdown();
153             pRecord->activeInstance = nullptr;
154         }
155     }
156 
157     return Void();
158 }
159 
160 
openDisplay()161 Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
162     ALOGD("openDisplay");
163 
164     // If we already have a display active, then we need to shut it down so we can
165     // give exclusive access to the new caller.
166     sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
167     if (pActiveDisplay != nullptr) {
168         ALOGW("Killing previous display because of new caller");
169         closeDisplay(pActiveDisplay);
170     }
171 
172     // Create a new display interface and return it
173     pActiveDisplay = new EvsDisplay();
174     sActiveDisplay = pActiveDisplay;
175 
176     ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
177     return pActiveDisplay;
178 }
179 
180 
closeDisplay(const::android::sp<IEvsDisplay> & pDisplay)181 Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& pDisplay) {
182     ALOGD("closeDisplay");
183 
184     // Do we still have a display object we think should be active?
185     sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
186     if (pActiveDisplay == nullptr) {
187         ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed");
188     } else if (sActiveDisplay != pDisplay) {
189         ALOGW("Ignoring close of previously orphaned display - why did a client steal?");
190     } else {
191         // Drop the active display
192         pActiveDisplay->forceShutdown();
193         sActiveDisplay = nullptr;
194     }
195 
196     return Void();
197 }
198 
199 
getDisplayState()200 Return<DisplayState> EvsEnumerator::getDisplayState()  {
201     ALOGD("getDisplayState");
202 
203     // Do we still have a display object we think should be active?
204     sp<IEvsDisplay> pActiveDisplay = sActiveDisplay.promote();
205     if (pActiveDisplay != nullptr) {
206         return pActiveDisplay->getDisplayState();
207     } else {
208         return DisplayState::NOT_OPEN;
209     }
210 }
211 
212 } // namespace implementation
213 } // namespace V1_0
214 } // namespace evs
215 } // namespace automotive
216 } // namespace hardware
217 } // namespace android
218