Home | History | Annotate | Download | only in libvrflinger
      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 
     15 using android::dvr::display::VSyncProtocol;
     16 using android::dvr::display::VSyncSchedInfo;
     17 using android::pdx::Channel;
     18 using android::pdx::Message;
     19 using android::pdx::MessageInfo;
     20 using android::pdx::default_transport::Endpoint;
     21 using android::pdx::rpc::DispatchRemoteMethod;
     22 
     23 namespace android {
     24 namespace dvr {
     25 
     26 VSyncService::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 
     33 VSyncService::~VSyncService() {}
     34 
     35 void 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 
     52 std::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 
     61 void 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 
     72 void 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 
     78 void VSyncService::AddClient(const std::shared_ptr<VSyncChannel>& client) {
     79   std::lock_guard<std::mutex> autolock(mutex_);
     80   clients_.push_back(client);
     81 }
     82 
     83 void 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.
     89 void 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.
    101 void 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 
    112 pdx::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 
    138 pdx::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 
    147 pdx::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 
    185 pdx::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 
    192 void VSyncWaiter::Notify(int64_t timestamp) {
    193   timestamp_ = timestamp;
    194   DispatchRemoteMethod<VSyncProtocol::Wait>(*this, &VSyncWaiter::OnWait,
    195                                             message_);
    196 }
    197 
    198 pdx::Status<int64_t> VSyncWaiter::OnWait(pdx::Message& /*message*/) {
    199   return {timestamp_};
    200 }
    201 
    202 void VSyncChannel::Ack() {
    203   ALOGD_IF(TRACE, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
    204   service_.ModifyChannelEvents(cid_, POLLPRI, 0);
    205 }
    206 
    207 void 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