/* * 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 #include #include #include namespace android { namespace frameworks { namespace displayservice { namespace V1_0 { namespace implementation { sp getLooper() { static sp looper = []() { sp 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 &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(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 DisplayEventReceiver::init(const sp& callback) { std::unique_lock lock(mMutex); if (mAttached != nullptr || callback == nullptr) { return Status::BAD_VALUE; } mAttached = new AttachedEvent(callback); return mAttached->valid() ? Status::SUCCESS : Status::UNKNOWN; } Return DisplayEventReceiver::setVsyncRate(int32_t count) { std::unique_lock 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 DisplayEventReceiver::requestNextVsync() { std::unique_lock lock(mMutex); if (mAttached == nullptr) { return Status::BAD_VALUE; } bool success = OK == mAttached->receiver().requestNextVsync(); return success ? Status::SUCCESS : Status::UNKNOWN; } Return DisplayEventReceiver::close() { std::unique_lock 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