1/*
2 * Copyright (C) 2017 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 "libdisplayservicehidl"
18
19#include <displayservice/DisplayEventReceiver.h>
20
21#include <android-base/logging.h>
22#include <android/frameworks/displayservice/1.0/BpHwEventCallback.h>
23
24#include <thread>
25
26namespace android {
27namespace frameworks {
28namespace displayservice {
29namespace V1_0 {
30namespace implementation {
31
32sp<Looper> getLooper() {
33    static sp<Looper> looper = []() {
34        sp<Looper> looper = new Looper(false /* allowNonCallbacks */);
35
36        std::thread{[&](){
37            int pollResult = looper->pollAll(-1 /* timeout */);
38            LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
39        }}.detach();
40
41        return looper;
42    }();
43
44    return looper;
45}
46
47DisplayEventReceiver::AttachedEvent::AttachedEvent(const sp<IEventCallback> &callback)
48    : mCallback(callback)
49{
50    mLooperAttached = getLooper()->addFd(mFwkReceiver.getFd(),
51            Looper::POLL_CALLBACK,
52            Looper::EVENT_INPUT,
53            this,
54            nullptr);
55}
56
57DisplayEventReceiver::AttachedEvent::~AttachedEvent() {
58    if (!detach()) {
59        LOG(ERROR) << "Could not remove fd from looper.";
60    }
61}
62
63bool DisplayEventReceiver::AttachedEvent::detach() {
64    if (!valid()) {
65        return true;
66    }
67
68    return getLooper()->removeFd(mFwkReceiver.getFd());
69}
70
71bool DisplayEventReceiver::AttachedEvent::valid() const {
72    return mFwkReceiver.initCheck() == OK && mLooperAttached;
73}
74
75DisplayEventReceiver::FwkReceiver &DisplayEventReceiver::AttachedEvent::receiver() {
76    return mFwkReceiver;
77}
78
79int DisplayEventReceiver::AttachedEvent::handleEvent(int fd, int events, void* /* data */) {
80    CHECK(fd == mFwkReceiver.getFd());
81
82    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
83        LOG(ERROR) << "AttachedEvent handleEvent received error or hangup:" << events;
84        return 0; // remove the callback
85    }
86
87    if (!(events & Looper::EVENT_INPUT)) {
88        LOG(ERROR) << "AttachedEvent handleEvent unhandled poll event:" << events;
89        return 1; // keep the callback
90    }
91
92    constexpr size_t SIZE = 1;
93
94    ssize_t n;
95    FwkReceiver::Event buf[SIZE];
96    while ((n = mFwkReceiver.getEvents(buf, SIZE)) > 0) {
97        for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
98            const FwkReceiver::Event &event = buf[i];
99
100            uint32_t type = event.header.type;
101            uint64_t timestamp = event.header.timestamp;
102
103            switch(buf[i].header.type) {
104                case FwkReceiver::DISPLAY_EVENT_VSYNC: {
105                    mCallback->onVsync(timestamp, event.vsync.count);
106                } break;
107                case FwkReceiver::DISPLAY_EVENT_HOTPLUG: {
108                    mCallback->onHotplug(timestamp, event.hotplug.connected);
109                } break;
110                default: {
111                    LOG(ERROR) << "AttachedEvent handleEvent unknown type: " << type;
112                }
113            }
114        }
115    }
116
117    return 1; // keep on going
118}
119
120Return<Status> DisplayEventReceiver::init(const sp<IEventCallback>& callback) {
121    std::unique_lock<std::mutex> lock(mMutex);
122
123    if (mAttached != nullptr || callback == nullptr) {
124        return Status::BAD_VALUE;
125    }
126
127    mAttached = new AttachedEvent(callback);
128
129    return mAttached->valid() ? Status::SUCCESS : Status::UNKNOWN;
130}
131
132Return<Status> DisplayEventReceiver::setVsyncRate(int32_t count) {
133    std::unique_lock<std::mutex> lock(mMutex);
134
135    if (mAttached == nullptr || count < 0) {
136        return Status::BAD_VALUE;
137    }
138
139    bool success = OK == mAttached->receiver().setVsyncRate(count);
140    return success ? Status::SUCCESS : Status::UNKNOWN;
141}
142
143Return<Status> DisplayEventReceiver::requestNextVsync() {
144    std::unique_lock<std::mutex> lock(mMutex);
145
146    if (mAttached == nullptr) {
147        return Status::BAD_VALUE;
148    }
149
150    bool success = OK == mAttached->receiver().requestNextVsync();
151    return success ? Status::SUCCESS : Status::UNKNOWN;
152}
153
154Return<Status> DisplayEventReceiver::close() {
155    std::unique_lock<std::mutex> lock(mMutex);
156    if (mAttached == nullptr) {
157        return Status::BAD_VALUE;
158    }
159
160    bool success = mAttached->detach();
161    mAttached = nullptr;
162
163    return success ? Status::SUCCESS : Status::UNKNOWN;
164}
165
166}  // namespace implementation
167}  // namespace V1_0
168}  // namespace displayservice
169}  // namespace frameworks
170}  // namespace android
171