| /* |
| * 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. |
| */ |
| |
| #include <hwbinder/IPCThreadState.h> |
| #include <cutils/android_filesystem_config.h> |
| |
| #include "Enumerator.h" |
| #include "HalDisplay.h" |
| |
| namespace android { |
| namespace automotive { |
| namespace evs { |
| namespace V1_0 { |
| namespace implementation { |
| |
| |
| bool Enumerator::init(const char* hardwareServiceName) { |
| ALOGD("init"); |
| |
| // Connect with the underlying hardware enumerator |
| mHwEnumerator = IEvsEnumerator::getService(hardwareServiceName); |
| bool result = (mHwEnumerator.get() != nullptr); |
| |
| return result; |
| } |
| |
| |
| bool Enumerator::checkPermission() { |
| hardware::IPCThreadState *ipc = hardware::IPCThreadState::self(); |
| if (AID_AUTOMOTIVE_EVS != ipc->getCallingUid()) { |
| ALOGE("EVS access denied: pid = %d, uid = %d", ipc->getCallingPid(), ipc->getCallingUid()); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow. |
| Return<void> Enumerator::getCameraList(getCameraList_cb list_cb) { |
| ALOGD("getCameraList"); |
| if (!checkPermission()) { |
| return Void(); |
| } |
| |
| // Simply pass through to hardware layer |
| return mHwEnumerator->getCameraList(list_cb); |
| } |
| |
| |
| Return<sp<IEvsCamera>> Enumerator::openCamera(const hidl_string& cameraId) { |
| ALOGD("openCamera"); |
| if (!checkPermission()) { |
| return nullptr; |
| } |
| |
| // Is the underlying hardware camera already open? |
| sp<HalCamera> hwCamera; |
| for (auto &&cam : mCameras) { |
| bool match = false; |
| cam->getHwCamera()->getCameraInfo([cameraId, &match](CameraDesc desc) { |
| if (desc.cameraId == cameraId) { |
| match = true; |
| } |
| } |
| ); |
| if (match) { |
| hwCamera = cam; |
| break; |
| } |
| } |
| |
| // Do we need to open a new hardware camera? |
| if (hwCamera == nullptr) { |
| // Is the hardware camera available? |
| sp<IEvsCamera> device = mHwEnumerator->openCamera(cameraId); |
| if (device == nullptr) { |
| ALOGE("Failed to open hardware camera %s", cameraId.c_str()); |
| } else { |
| hwCamera = new HalCamera(device); |
| if (hwCamera == nullptr) { |
| ALOGE("Failed to allocate camera wrapper object"); |
| mHwEnumerator->closeCamera(device); |
| } |
| } |
| } |
| |
| // Construct a virtual camera wrapper for this hardware camera |
| sp<VirtualCamera> clientCamera; |
| if (hwCamera != nullptr) { |
| clientCamera = hwCamera->makeVirtualCamera(); |
| } |
| |
| // Add the hardware camera to our list, which will keep it alive via ref count |
| if (clientCamera != nullptr) { |
| mCameras.push_back(hwCamera); |
| } else { |
| ALOGE("Requested camera %s not found or not available", cameraId.c_str()); |
| } |
| |
| // Send the virtual camera object back to the client by strong pointer which will keep it alive |
| return clientCamera; |
| } |
| |
| |
| Return<void> Enumerator::closeCamera(const ::android::sp<IEvsCamera>& clientCamera) { |
| ALOGD("closeCamera"); |
| |
| if (clientCamera.get() == nullptr) { |
| ALOGE("Ignoring call with null camera pointer."); |
| return Void(); |
| } |
| |
| // All our client cameras are actually VirtualCamera objects |
| sp<VirtualCamera> virtualCamera = reinterpret_cast<VirtualCamera*>(clientCamera.get()); |
| |
| // Find the parent camera that backs this virtual camera |
| sp<HalCamera> halCamera = virtualCamera->getHalCamera(); |
| |
| // Tell the virtual camera's parent to clean it up and drop it |
| // NOTE: The camera objects will only actually destruct when the sp<> ref counts get to |
| // zero, so it is important to break all cyclic references. |
| halCamera->disownVirtualCamera(virtualCamera); |
| |
| // Did we just remove the last client of this camera? |
| if (halCamera->getClientCount() == 0) { |
| // Take this now unused camera out of our list |
| // NOTE: This should drop our last reference to the camera, resulting in its |
| // destruction. |
| mCameras.remove(halCamera); |
| } |
| |
| return Void(); |
| } |
| |
| |
| Return<sp<IEvsDisplay>> Enumerator::openDisplay() { |
| ALOGD("openDisplay"); |
| |
| if (!checkPermission()) { |
| return nullptr; |
| } |
| |
| // We simply keep track of the most recently opened display instance. |
| // In the underlying layers we expect that a new open will cause the previous |
| // object to be destroyed. This avoids any race conditions associated with |
| // create/destroy order and provides a cleaner restart sequence if the previous owner |
| // is non-responsive for some reason. |
| // Request exclusive access to the EVS display |
| sp<IEvsDisplay> pActiveDisplay = mHwEnumerator->openDisplay(); |
| if (pActiveDisplay == nullptr) { |
| ALOGE("EVS Display unavailable"); |
| |
| return nullptr; |
| } |
| |
| // Remember (via weak pointer) who we think the most recently opened display is so that |
| // we can proxy state requests from other callers to it. |
| // TODO: Because of b/129284474, an additional class, HalDisplay, has been defined and |
| // wraps the IEvsDisplay object the driver returns. We may want to remove this |
| // additional class when it is fixed properly. |
| sp<IEvsDisplay> pHalDisplay = new HalDisplay(pActiveDisplay); |
| mActiveDisplay = pHalDisplay; |
| |
| return pHalDisplay; |
| } |
| |
| |
| Return<void> Enumerator::closeDisplay(const ::android::sp<IEvsDisplay>& display) { |
| ALOGD("closeDisplay"); |
| |
| sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote(); |
| |
| // Drop the active display |
| if (display.get() != pActiveDisplay.get()) { |
| ALOGW("Ignoring call to closeDisplay with unrecognized display object."); |
| } else { |
| // Pass this request through to the hardware layer |
| sp<HalDisplay> halDisplay = reinterpret_cast<HalDisplay *>(pActiveDisplay.get()); |
| mHwEnumerator->closeDisplay(halDisplay->getHwDisplay()); |
| mActiveDisplay = nullptr; |
| } |
| |
| return Void(); |
| } |
| |
| |
| Return<DisplayState> Enumerator::getDisplayState() { |
| ALOGD("getDisplayState"); |
| if (!checkPermission()) { |
| return DisplayState::DEAD; |
| } |
| |
| // Do we have a display object we think should be active? |
| sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote(); |
| if (pActiveDisplay != nullptr) { |
| // Pass this request through to the hardware layer |
| return pActiveDisplay->getDisplayState(); |
| } else { |
| // We don't have a live display right now |
| mActiveDisplay = nullptr; |
| return DisplayState::NOT_OPEN; |
| } |
| } |
| |
| |
| } // namespace implementation |
| } // namespace V1_0 |
| } // namespace evs |
| } // namespace automotive |
| } // namespace android |