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