| /* |
| * Copyright (C) 2017 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 "libdisplayservicehidl" |
| |
| #include <displayservice/DisplayEventReceiver.h> |
| |
| #include <android-base/logging.h> |
| #include <android/frameworks/displayservice/1.0/BpHwEventCallback.h> |
| |
| #include <thread> |
| |
| namespace android { |
| namespace frameworks { |
| namespace displayservice { |
| namespace V1_0 { |
| namespace implementation { |
| |
| sp<Looper> getLooper() { |
| static sp<Looper> looper = []() { |
| sp<Looper> looper = new Looper(false /* allowNonCallbacks */); |
| |
| std::thread{[&](){ |
| int pollResult = looper->pollAll(-1 /* timeout */); |
| LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult; |
| }}.detach(); |
| |
| return looper; |
| }(); |
| |
| return looper; |
| } |
| |
| DisplayEventReceiver::AttachedEvent::AttachedEvent(const sp<IEventCallback> &callback) |
| : mCallback(callback) |
| { |
| mLooperAttached = getLooper()->addFd(mFwkReceiver.getFd(), |
| Looper::POLL_CALLBACK, |
| Looper::EVENT_INPUT, |
| this, |
| nullptr); |
| } |
| |
| DisplayEventReceiver::AttachedEvent::~AttachedEvent() { |
| if (!detach()) { |
| LOG(ERROR) << "Could not remove fd from looper."; |
| } |
| } |
| |
| bool DisplayEventReceiver::AttachedEvent::detach() { |
| if (!valid()) { |
| return true; |
| } |
| |
| return getLooper()->removeFd(mFwkReceiver.getFd()); |
| } |
| |
| bool DisplayEventReceiver::AttachedEvent::valid() const { |
| return mFwkReceiver.initCheck() == OK && mLooperAttached; |
| } |
| |
| DisplayEventReceiver::FwkReceiver &DisplayEventReceiver::AttachedEvent::receiver() { |
| return mFwkReceiver; |
| } |
| |
| int DisplayEventReceiver::AttachedEvent::handleEvent(int fd, int events, void* /* data */) { |
| CHECK(fd == mFwkReceiver.getFd()); |
| |
| if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { |
| LOG(ERROR) << "AttachedEvent handleEvent received error or hangup:" << events; |
| return 0; // remove the callback |
| } |
| |
| if (!(events & Looper::EVENT_INPUT)) { |
| LOG(ERROR) << "AttachedEvent handleEvent unhandled poll event:" << events; |
| return 1; // keep the callback |
| } |
| |
| constexpr size_t SIZE = 1; |
| |
| ssize_t n; |
| FwkReceiver::Event buf[SIZE]; |
| while ((n = mFwkReceiver.getEvents(buf, SIZE)) > 0) { |
| for (size_t i = 0; i < static_cast<size_t>(n); ++i) { |
| const FwkReceiver::Event &event = buf[i]; |
| |
| uint32_t type = event.header.type; |
| uint64_t timestamp = event.header.timestamp; |
| |
| switch(buf[i].header.type) { |
| case FwkReceiver::DISPLAY_EVENT_VSYNC: { |
| auto ret = mCallback->onVsync(timestamp, event.vsync.count); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "AttachedEvent handleEvent fails on onVsync callback" |
| << " because of " << ret.description(); |
| return 0; // remove the callback |
| } |
| } break; |
| case FwkReceiver::DISPLAY_EVENT_HOTPLUG: { |
| auto ret = mCallback->onHotplug(timestamp, event.hotplug.connected); |
| if (!ret.isOk()) { |
| LOG(ERROR) << "AttachedEvent handleEvent fails on onHotplug callback" |
| << " because of " << ret.description(); |
| return 0; // remove the callback |
| } |
| } break; |
| default: { |
| LOG(ERROR) << "AttachedEvent handleEvent unknown type: " << type; |
| } |
| } |
| } |
| } |
| |
| return 1; // keep on going |
| } |
| |
| Return<Status> DisplayEventReceiver::init(const sp<IEventCallback>& callback) { |
| std::unique_lock<std::mutex> lock(mMutex); |
| |
| if (mAttached != nullptr || callback == nullptr) { |
| return Status::BAD_VALUE; |
| } |
| |
| mAttached = new AttachedEvent(callback); |
| |
| return mAttached->valid() ? Status::SUCCESS : Status::UNKNOWN; |
| } |
| |
| Return<Status> DisplayEventReceiver::setVsyncRate(int32_t count) { |
| std::unique_lock<std::mutex> lock(mMutex); |
| |
| if (mAttached == nullptr || count < 0) { |
| return Status::BAD_VALUE; |
| } |
| |
| bool success = OK == mAttached->receiver().setVsyncRate(count); |
| return success ? Status::SUCCESS : Status::UNKNOWN; |
| } |
| |
| Return<Status> DisplayEventReceiver::requestNextVsync() { |
| std::unique_lock<std::mutex> lock(mMutex); |
| |
| if (mAttached == nullptr) { |
| return Status::BAD_VALUE; |
| } |
| |
| bool success = OK == mAttached->receiver().requestNextVsync(); |
| return success ? Status::SUCCESS : Status::UNKNOWN; |
| } |
| |
| Return<Status> DisplayEventReceiver::close() { |
| std::unique_lock<std::mutex> lock(mMutex); |
| if (mAttached == nullptr) { |
| return Status::BAD_VALUE; |
| } |
| |
| bool success = mAttached->detach(); |
| mAttached = nullptr; |
| |
| return success ? Status::SUCCESS : Status::UNKNOWN; |
| } |
| |
| } // namespace implementation |
| } // namespace V1_0 |
| } // namespace displayservice |
| } // namespace frameworks |
| } // namespace android |