1#include "vsync_service.h"
2
3#include <hardware/hwcomposer.h>
4#include <log/log.h>
5#include <poll.h>
6#include <sys/prctl.h>
7#include <time.h>
8#include <utils/Trace.h>
9
10#include <dvr/dvr_display_types.h>
11#include <pdx/default_transport/service_endpoint.h>
12#include <private/dvr/clock_ns.h>
13#include <private/dvr/display_protocol.h>
14
15using android::dvr::display::VSyncProtocol;
16using android::dvr::display::VSyncSchedInfo;
17using android::pdx::Channel;
18using android::pdx::Message;
19using android::pdx::MessageInfo;
20using android::pdx::default_transport::Endpoint;
21using android::pdx::rpc::DispatchRemoteMethod;
22
23namespace android {
24namespace dvr {
25
26VSyncService::VSyncService()
27    : BASE("VSyncService", Endpoint::Create(VSyncProtocol::kClientPath)),
28      last_vsync_(0),
29      current_vsync_(0),
30      compositor_time_ns_(0),
31      current_vsync_count_(0) {}
32
33VSyncService::~VSyncService() {}
34
35void VSyncService::VSyncEvent(int display, int64_t timestamp_ns,
36                              int64_t compositor_time_ns,
37                              uint32_t vsync_count) {
38  ATRACE_NAME("VSyncService::VSyncEvent");
39  std::lock_guard<std::mutex> autolock(mutex_);
40
41  if (display == HWC_DISPLAY_PRIMARY) {
42    last_vsync_ = current_vsync_;
43    current_vsync_ = timestamp_ns;
44    compositor_time_ns_ = compositor_time_ns;
45    current_vsync_count_ = vsync_count;
46
47    NotifyWaiters();
48    UpdateClients();
49  }
50}
51
52std::shared_ptr<Channel> VSyncService::OnChannelOpen(pdx::Message& message) {
53  const MessageInfo& info = message.GetInfo();
54
55  auto client = std::make_shared<VSyncChannel>(*this, info.pid, info.cid);
56  AddClient(client);
57
58  return client;
59}
60
61void VSyncService::OnChannelClose(pdx::Message& /*message*/,
62                                  const std::shared_ptr<Channel>& channel) {
63  auto client = std::static_pointer_cast<VSyncChannel>(channel);
64  if (!client) {
65    ALOGW("WARNING: VSyncChannel was NULL!!!\n");
66    return;
67  }
68
69  RemoveClient(client);
70}
71
72void VSyncService::AddWaiter(pdx::Message& message) {
73  std::lock_guard<std::mutex> autolock(mutex_);
74  std::unique_ptr<VSyncWaiter> waiter(new VSyncWaiter(message));
75  waiters_.push_back(std::move(waiter));
76}
77
78void VSyncService::AddClient(const std::shared_ptr<VSyncChannel>& client) {
79  std::lock_guard<std::mutex> autolock(mutex_);
80  clients_.push_back(client);
81}
82
83void VSyncService::RemoveClient(const std::shared_ptr<VSyncChannel>& client) {
84  std::lock_guard<std::mutex> autolock(mutex_);
85  clients_.remove(client);
86}
87
88// Private. Assumes mutex is held.
89void VSyncService::NotifyWaiters() {
90  ATRACE_NAME("VSyncService::NotifyWaiters");
91  auto first = waiters_.begin();
92  auto last = waiters_.end();
93
94  while (first != last) {
95    (*first)->Notify(current_vsync_);
96    waiters_.erase(first++);
97  }
98}
99
100// Private. Assumes mutex is held.
101void VSyncService::UpdateClients() {
102  ATRACE_NAME("VSyncService::UpdateClients");
103  auto first = clients_.begin();
104  auto last = clients_.end();
105
106  while (first != last) {
107    (*first)->Signal();
108    first++;
109  }
110}
111
112pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
113  switch (message.GetOp()) {
114    case VSyncProtocol::Wait::Opcode:
115      AddWaiter(message);
116      return {};
117
118    case VSyncProtocol::GetLastTimestamp::Opcode:
119      DispatchRemoteMethod<VSyncProtocol::GetLastTimestamp>(
120          *this, &VSyncService::OnGetLastTimestamp, message);
121      return {};
122
123    case VSyncProtocol::GetSchedInfo::Opcode:
124      DispatchRemoteMethod<VSyncProtocol::GetSchedInfo>(
125          *this, &VSyncService::OnGetSchedInfo, message);
126      return {};
127
128    case VSyncProtocol::Acknowledge::Opcode:
129      DispatchRemoteMethod<VSyncProtocol::Acknowledge>(
130          *this, &VSyncService::OnAcknowledge, message);
131      return {};
132
133    default:
134      return Service::HandleMessage(message);
135  }
136}
137
138pdx::Status<int64_t> VSyncService::OnGetLastTimestamp(pdx::Message& message) {
139  auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
140  std::lock_guard<std::mutex> autolock(mutex_);
141
142  // Getting the timestamp has the side effect of ACKing.
143  client->Ack();
144  return {current_vsync_};
145}
146
147pdx::Status<VSyncSchedInfo> VSyncService::OnGetSchedInfo(
148    pdx::Message& message) {
149  auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
150  std::lock_guard<std::mutex> autolock(mutex_);
151
152  // Getting the timestamp has the side effect of ACKing.
153  client->Ack();
154
155  uint32_t next_vsync_count = current_vsync_count_ + 1;
156  int64_t current_time = GetSystemClockNs();
157  int64_t vsync_period_ns = 0;
158  int64_t next_warp;
159  if (current_vsync_ == 0 || last_vsync_ == 0) {
160    // Handle startup when current_vsync_ or last_vsync_ are 0.
161    // Normally should not happen because vsync_service is running before
162    // applications, but in case it does a sane time prevents applications
163    // from malfunctioning.
164    vsync_period_ns = 20000000;
165    next_warp = current_time;
166  } else {
167    // TODO(jbates) When we have an accurate reading of the true vsync
168    // period, use that instead of this estimated value.
169    vsync_period_ns = current_vsync_ - last_vsync_;
170    // Clamp the period, because when there are no surfaces the last_vsync_
171    // value will get stale. Note this is temporary and goes away as soon
172    // as we have an accurate vsync period reported by the system.
173    vsync_period_ns = std::min(vsync_period_ns, INT64_C(20000000));
174    next_warp = current_vsync_ + vsync_period_ns - compositor_time_ns_;
175    // If the request missed the present window, move up to the next vsync.
176    if (current_time > next_warp) {
177      next_warp += vsync_period_ns;
178      ++next_vsync_count;
179    }
180  }
181
182  return {{vsync_period_ns, next_warp, next_vsync_count}};
183}
184
185pdx::Status<void> VSyncService::OnAcknowledge(pdx::Message& message) {
186  auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
187  std::lock_guard<std::mutex> autolock(mutex_);
188  client->Ack();
189  return {};
190}
191
192void VSyncWaiter::Notify(int64_t timestamp) {
193  timestamp_ = timestamp;
194  DispatchRemoteMethod<VSyncProtocol::Wait>(*this, &VSyncWaiter::OnWait,
195                                            message_);
196}
197
198pdx::Status<int64_t> VSyncWaiter::OnWait(pdx::Message& /*message*/) {
199  return {timestamp_};
200}
201
202void VSyncChannel::Ack() {
203  ALOGD_IF(TRACE, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
204  service_.ModifyChannelEvents(cid_, POLLPRI, 0);
205}
206
207void VSyncChannel::Signal() {
208  ALOGD_IF(TRACE, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
209  service_.ModifyChannelEvents(cid_, 0, POLLPRI);
210}
211
212}  // namespace dvr
213}  // namespace android
214