summaryrefslogtreecommitdiff
path: root/libs/vr/libvrflinger/display_manager_service.cpp
blob: ef8cca38dd79d37277db59f4021eca9e75b6dd5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "display_manager_service.h"

#include <pdx/channel_handle.h>
#include <pdx/default_transport/service_endpoint.h>
#include <private/android_filesystem_config.h>
#include <private/dvr/display_protocol.h>
#include <private/dvr/trusted_uids.h>
#include <sys/poll.h>

#include <array>

using android::dvr::display::DisplayManagerProtocol;
using android::pdx::Channel;
using android::pdx::LocalChannelHandle;
using android::pdx::Message;
using android::pdx::default_transport::Endpoint;
using android::pdx::ErrorStatus;
using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::rpc::IfAnyOf;
using android::pdx::rpc::RemoteMethodError;

namespace android {
namespace dvr {

void DisplayManager::SetNotificationsPending(bool pending) {
  auto status = service_->ModifyChannelEvents(channel_id_, pending ? 0 : POLLIN,
                                              pending ? POLLIN : 0);
  ALOGE_IF(!status,
           "DisplayManager::SetNotificationPending: Failed to modify channel "
           "events: %s",
           status.GetErrorMessage().c_str());
}

DisplayManagerService::DisplayManagerService(
    const std::shared_ptr<DisplayService>& display_service)
    : BASE("DisplayManagerService",
           Endpoint::Create(DisplayManagerProtocol::kClientPath)),
      display_service_(display_service) {
  display_service_->SetDisplayConfigurationUpdateNotifier(
      std::bind(&DisplayManagerService::OnDisplaySurfaceChange, this));
}

std::shared_ptr<pdx::Channel> DisplayManagerService::OnChannelOpen(
    pdx::Message& message) {
  const int user_id = message.GetEffectiveUserId();
  const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);

  // Prevent more than one display manager from registering at a time or
  // untrusted UIDs from connecting.
  if (display_manager_ || !trusted) {
    RemoteMethodError(message, EPERM);
    return nullptr;
  }

  display_manager_ =
      std::make_shared<DisplayManager>(this, message.GetChannelId());
  return display_manager_;
}

void DisplayManagerService::OnChannelClose(
    pdx::Message& /*message*/, const std::shared_ptr<pdx::Channel>& channel) {
  // Unregister the display manager when the channel closes.
  if (display_manager_ == channel)
    display_manager_ = nullptr;
}

pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) {
  ATRACE_NAME("DisplayManagerService::HandleMessage");
  auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());

  switch (message.GetOp()) {
    case DisplayManagerProtocol::GetSurfaceState::Opcode:
      DispatchRemoteMethod<DisplayManagerProtocol::GetSurfaceState>(
          *this, &DisplayManagerService::OnGetSurfaceState, message);
      return {};

    case DisplayManagerProtocol::GetSurfaceQueue::Opcode:
      DispatchRemoteMethod<DisplayManagerProtocol::GetSurfaceQueue>(
          *this, &DisplayManagerService::OnGetSurfaceQueue, message);
      return {};

    default:
      return Service::DefaultHandleMessage(message);
  }
}

pdx::Status<std::vector<display::SurfaceState>>
DisplayManagerService::OnGetSurfaceState(pdx::Message& /*message*/) {
  std::vector<display::SurfaceState> items;

  display_service_->ForEachDisplaySurface(
      SurfaceType::Application,
      [&items](const std::shared_ptr<DisplaySurface>& surface) mutable {
        items.push_back({surface->surface_id(), surface->process_id(),
                         surface->user_id(), surface->attributes(),
                         surface->update_flags(), surface->GetQueueIds()});
        surface->ClearUpdate();
      });

  // The fact that we're in the message handler implies that display_manager_ is
  // not nullptr. No check required, unless this service becomes multi-threaded.
  display_manager_->SetNotificationsPending(false);
  return items;
}

pdx::Status<pdx::LocalChannelHandle> DisplayManagerService::OnGetSurfaceQueue(
    pdx::Message& /*message*/, int surface_id, int queue_id) {
  auto surface = display_service_->GetDisplaySurface(surface_id);
  if (!surface || surface->surface_type() != SurfaceType::Application)
    return ErrorStatus(EINVAL);

  auto queue =
      std::static_pointer_cast<ApplicationDisplaySurface>(surface)->GetQueue(
          queue_id);
  if (!queue)
    return ErrorStatus(EINVAL);

  auto status = queue->CreateConsumerQueueHandle();
  ALOGE_IF(
      !status,
      "DisplayManagerService::OnGetSurfaceQueue: Failed to create consumer "
      "queue for queue_id=%d: %s",
      queue->id(), status.GetErrorMessage().c_str());

  return status;
}

void DisplayManagerService::OnDisplaySurfaceChange() {
  if (display_manager_)
    display_manager_->SetNotificationsPending(true);
}

}  // namespace dvr
}  // namespace android