/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "android.hardware.automotive.evs@1.0-service" #include "EvsEnumerator.h" #include "EvsCamera.h" #include "EvsDisplay.h" namespace android { namespace hardware { namespace automotive { namespace evs { namespace V1_0 { namespace implementation { // NOTE: All members values are static so that all clients operate on the same state // That is to say, this is effectively a singleton despite the fact that HIDL // constructs a new instance for each client. std::list EvsEnumerator::sCameraList; wp EvsEnumerator::sActiveDisplay; EvsEnumerator::EvsEnumerator() { ALOGD("EvsEnumerator created"); // Add sample camera data to our list of cameras // In a real driver, this would be expected to can the available hardware sCameraList.emplace_back(EvsCamera::kCameraName_Backup); sCameraList.emplace_back("LaneView"); sCameraList.emplace_back("right turn"); } // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow. Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { ALOGD("getCameraList"); const unsigned numCameras = sCameraList.size(); // Build up a packed array of CameraDesc for return // NOTE: Only has to live until the callback returns std::vector descriptions; descriptions.reserve(numCameras); for (const auto& cam : sCameraList) { descriptions.push_back( cam.desc ); } // Encapsulate our camera descriptions in the HIDL vec type hidl_vec hidlCameras(descriptions); // Send back the results ALOGD("reporting %zu cameras available", hidlCameras.size()); _hidl_cb(hidlCameras); // HIDL convention says we return Void if we sent our result back via callback return Void(); } Return> EvsEnumerator::openCamera(const hidl_string& cameraId) { ALOGD("openCamera"); // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { if (cam.desc.cameraId == cameraId) { // Found a match! pRecord = &cam; break; } } // Is this a recognized camera id? if (!pRecord) { ALOGE("Requested camera %s not found", cameraId.c_str()); return nullptr; } // Has this camera already been instantiated by another caller? sp pActiveCamera = pRecord->activeInstance.promote(); if (pActiveCamera != nullptr) { ALOGW("Killing previous camera because of new caller"); closeCamera(pActiveCamera); } // Construct a camera instance for the caller pActiveCamera = new EvsCamera(cameraId.c_str()); pRecord->activeInstance = pActiveCamera; if (pActiveCamera == nullptr) { ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); } return pActiveCamera; } Return EvsEnumerator::closeCamera(const ::android::sp& pCamera) { ALOGD("closeCamera"); if (pCamera == nullptr) { ALOGE("Ignoring call to closeCamera with null camera ptr"); return Void(); } // Get the camera id so we can find it in our list std::string cameraId; pCamera->getCameraInfo([&cameraId](CameraDesc desc) { // TODO(b/36532780) Should we able to just use a simple assignment? // cameraId = desc.cameraId; cameraId.assign(desc.cameraId.c_str()); } ); // Find the named camera CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { if (cam.desc.cameraId == cameraId) { // Found a match! pRecord = &cam; break; } } // Is the display being destroyed actually the one we think is active? if (!pRecord) { ALOGE("Asked to close a camera who's name isn't recognized"); } else { sp pActiveCamera = pRecord->activeInstance.promote(); if (pActiveCamera == nullptr) { ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed"); } else if (pActiveCamera != pCamera) { // This can happen if the camera was aggressively reopened, orphaning this previous instance ALOGW("Ignoring close of previously orphaned camera - why did a client steal?"); } else { // Drop the active camera pActiveCamera->forceShutdown(); pRecord->activeInstance = nullptr; } } return Void(); } Return> EvsEnumerator::openDisplay() { ALOGD("openDisplay"); // If we already have a display active, then we need to shut it down so we can // give exclusive access to the new caller. sp pActiveDisplay = sActiveDisplay.promote(); if (pActiveDisplay != nullptr) { ALOGW("Killing previous display because of new caller"); closeDisplay(pActiveDisplay); } // Create a new display interface and return it pActiveDisplay = new EvsDisplay(); sActiveDisplay = pActiveDisplay; ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get()); return pActiveDisplay; } Return EvsEnumerator::closeDisplay(const ::android::sp& pDisplay) { ALOGD("closeDisplay"); // Do we still have a display object we think should be active? sp pActiveDisplay = sActiveDisplay.promote(); if (pActiveDisplay == nullptr) { ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed"); } else if (sActiveDisplay != pDisplay) { ALOGW("Ignoring close of previously orphaned display - why did a client steal?"); } else { // Drop the active display pActiveDisplay->forceShutdown(); sActiveDisplay = nullptr; } return Void(); } Return EvsEnumerator::getDisplayState() { ALOGD("getDisplayState"); // Do we still have a display object we think should be active? sp pActiveDisplay = sActiveDisplay.promote(); if (pActiveDisplay != nullptr) { return pActiveDisplay->getDisplayState(); } else { return DisplayState::NOT_OPEN; } } } // namespace implementation } // namespace V1_0 } // namespace evs } // namespace automotive } // namespace hardware } // namespace android