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
23namespace android {
24namespace hardware {
25namespace automotive {
26namespace evs {
27namespace V1_0 {
28namespace 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.
34std::list<EvsEnumerator::CameraRecord>   EvsEnumerator::sCameraList;
35wp<EvsDisplay>                           EvsEnumerator::sActiveDisplay;
36
37
38EvsEnumerator::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.
50Return<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
75Return<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
112Return<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
161Return<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
181Return<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
200Return<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