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