blob: 5a9360c2aee062eb8d34c13ae67b2268bb50cd1c [file] [log] [blame]
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08001#include "display_service.h"
2
Hendrik Wagenaareaa55222017-04-06 10:56:23 -07003#include <unistd.h>
Corey Tabaka0b485c92017-05-19 12:02:58 -07004
5#include <algorithm>
6#include <sstream>
7#include <string>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08008#include <vector>
9
Hendrik Wagenaarbcb03d02017-05-23 14:59:08 -070010#include <android-base/file.h>
11#include <android-base/properties.h>
Corey Tabaka2251d822017-04-20 16:04:07 -070012#include <dvr/dvr_display_types.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080013#include <pdx/default_transport/service_endpoint.h>
14#include <pdx/rpc/remote_method.h>
Corey Tabaka99c2d732017-06-07 17:54:33 -070015#include <private/android_filesystem_config.h>
Corey Tabaka3f82d312017-04-20 14:42:08 -070016#include <private/dvr/display_protocol.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080017#include <private/dvr/numeric.h>
Corey Tabaka99c2d732017-06-07 17:54:33 -070018#include <private/dvr/trusted_uids.h>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080019#include <private/dvr/types.h>
20
Corey Tabaka2251d822017-04-20 16:04:07 -070021using android::dvr::display::DisplayProtocol;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080022using android::pdx::Channel;
Corey Tabaka2251d822017-04-20 16:04:07 -070023using android::pdx::ErrorStatus;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080024using android::pdx::Message;
Corey Tabaka2251d822017-04-20 16:04:07 -070025using android::pdx::Status;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080026using android::pdx::default_transport::Endpoint;
27using android::pdx::rpc::DispatchRemoteMethod;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080028
Hendrik Wagenaarbcb03d02017-05-23 14:59:08 -070029namespace {
30
31const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
32const char kDvrDeviceMetricsProperty[] = "ro.dvr.device_metrics";
33const char kDvrDeviceConfigProperty[] = "ro.dvr.device_configuration";
34
35} // namespace
36
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080037namespace android {
38namespace dvr {
39
Corey Tabaka2251d822017-04-20 16:04:07 -070040DisplayService::DisplayService(Hwc2::Composer* hidl,
Steven Thomas6e8f7062017-11-22 14:15:29 -080041 hwc2_display_t primary_display_id,
Corey Tabaka2251d822017-04-20 16:04:07 -070042 RequestDisplayCallback request_display_callback)
43 : BASE("DisplayService",
Steven Thomasd7f49c52017-07-26 18:48:28 -070044 Endpoint::Create(display::DisplayProtocol::kClientPath)) {
Steven Thomas6e8f7062017-11-22 14:15:29 -080045 hardware_composer_.Initialize(
46 hidl, primary_display_id, request_display_callback);
mamika08194b2019-07-25 13:07:21 -070047
48 uint8_t port;
49 const auto error = hidl->getDisplayIdentificationData(
mamik94e91f62019-08-19 09:11:33 -070050 primary_display_id, &display_identification_port_,
51 &display_identification_data_);
mamika08194b2019-07-25 13:07:21 -070052 if (error != android::hardware::graphics::composer::V2_1::Error::NONE) {
53 if (error !=
54 android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) {
55 ALOGI("DisplayService: identification data error\n");
56 } else {
57 ALOGI("DisplayService: identification data unsupported\n");
58 }
59 }
Stephen Kiazyk016e5e32017-02-21 17:09:22 -080060}
61
62bool DisplayService::IsInitialized() const {
63 return BASE::IsInitialized() && hardware_composer_.IsInitialized();
64}
Alex Vakulenkoa8a92782017-01-27 14:41:57 -080065
Corey Tabaka2251d822017-04-20 16:04:07 -070066std::string DisplayService::DumpState(size_t /*max_length*/) {
Corey Tabaka0b485c92017-05-19 12:02:58 -070067 std::ostringstream stream;
68
69 auto surfaces = GetDisplaySurfaces();
70 std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
71 return a->surface_id() < b->surface_id();
72 });
73
74 stream << "Application Surfaces:" << std::endl;
75
76 size_t count = 0;
77 for (const auto& surface : surfaces) {
78 if (surface->surface_type() == SurfaceType::Application) {
79 stream << "Surface " << count++ << ":";
80 stream << " surface_id=" << surface->surface_id()
81 << " process_id=" << surface->process_id()
82 << " user_id=" << surface->user_id()
83 << " visible=" << surface->visible()
84 << " z_order=" << surface->z_order();
85
86 stream << " queue_ids=";
87 auto queue_ids = surface->GetQueueIds();
88 std::sort(queue_ids.begin(), queue_ids.end());
89 for (int32_t id : queue_ids) {
90 if (id != queue_ids[0])
91 stream << ",";
92 stream << id;
93 }
94 stream << std::endl;
95 }
96 }
97 stream << std::endl;
98
99 stream << "Direct Surfaces:" << std::endl;
100
101 count = 0;
102 for (const auto& surface : surfaces) {
103 if (surface->surface_type() == SurfaceType::Direct) {
104 stream << "Surface " << count++ << ":";
105 stream << " surface_id=" << surface->surface_id()
106 << " process_id=" << surface->process_id()
107 << " user_id=" << surface->user_id()
108 << " visible=" << surface->visible()
109 << " z_order=" << surface->z_order();
110
111 stream << " queue_ids=";
112 auto queue_ids = surface->GetQueueIds();
113 std::sort(queue_ids.begin(), queue_ids.end());
114 for (int32_t id : queue_ids) {
115 if (id != queue_ids[0])
116 stream << ",";
117 stream << id;
118 }
119 stream << std::endl;
120 }
121 }
122 stream << std::endl;
123
124 stream << hardware_composer_.Dump();
125 return stream.str();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800126}
127
Corey Tabaka2251d822017-04-20 16:04:07 -0700128void DisplayService::OnChannelClose(pdx::Message& message,
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800129 const std::shared_ptr<Channel>& channel) {
Corey Tabaka2251d822017-04-20 16:04:07 -0700130 if (auto surface = std::static_pointer_cast<DisplaySurface>(channel)) {
131 surface->OnSetAttributes(message,
132 {{display::SurfaceAttribute::Visible,
133 display::SurfaceAttributeValue{false}}});
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800134 }
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800135}
136
137// First-level dispatch for display service messages. Directly handles messages
138// that are independent of the display surface (metrics, creation) and routes
139// surface-specific messages to the per-instance handlers.
Corey Tabaka2251d822017-04-20 16:04:07 -0700140Status<void> DisplayService::HandleMessage(pdx::Message& message) {
141 ALOGD_IF(TRACE, "DisplayService::HandleMessage: opcode=%d", message.GetOp());
Corey Tabakab3732f02017-09-16 00:58:54 -0700142 ATRACE_NAME("DisplayService::HandleMessage");
143
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800144 switch (message.GetOp()) {
Corey Tabaka2251d822017-04-20 16:04:07 -0700145 case DisplayProtocol::GetMetrics::Opcode:
146 DispatchRemoteMethod<DisplayProtocol::GetMetrics>(
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800147 *this, &DisplayService::OnGetMetrics, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700148 return {};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800149
Hendrik Wagenaarbcb03d02017-05-23 14:59:08 -0700150 case DisplayProtocol::GetConfigurationData::Opcode:
151 DispatchRemoteMethod<DisplayProtocol::GetConfigurationData>(
152 *this, &DisplayService::OnGetConfigurationData, message);
153 return {};
154
mamik94e91f62019-08-19 09:11:33 -0700155 case DisplayProtocol::GetDisplayIdentificationPort::Opcode:
156 DispatchRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>(
157 *this, &DisplayService::OnGetDisplayIdentificationPort, message);
158 return {};
159
Corey Tabaka2251d822017-04-20 16:04:07 -0700160 case DisplayProtocol::CreateSurface::Opcode:
161 DispatchRemoteMethod<DisplayProtocol::CreateSurface>(
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800162 *this, &DisplayService::OnCreateSurface, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700163 return {};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800164
Corey Tabaka99c2d732017-06-07 17:54:33 -0700165 case DisplayProtocol::SetupGlobalBuffer::Opcode:
166 DispatchRemoteMethod<DisplayProtocol::SetupGlobalBuffer>(
167 *this, &DisplayService::OnSetupGlobalBuffer, message);
168 return {};
169
170 case DisplayProtocol::DeleteGlobalBuffer::Opcode:
171 DispatchRemoteMethod<DisplayProtocol::DeleteGlobalBuffer>(
172 *this, &DisplayService::OnDeleteGlobalBuffer, message);
173 return {};
174
Okan Arikan36d23802017-05-15 15:20:39 -0700175 case DisplayProtocol::GetGlobalBuffer::Opcode:
176 DispatchRemoteMethod<DisplayProtocol::GetGlobalBuffer>(
177 *this, &DisplayService::OnGetGlobalBuffer, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700178 return {};
Hendrik Wagenaar10e68eb2017-03-15 13:29:02 -0700179
Corey Tabaka2251d822017-04-20 16:04:07 -0700180 case DisplayProtocol::IsVrAppRunning::Opcode:
181 DispatchRemoteMethod<DisplayProtocol::IsVrAppRunning>(
Albert Chaulkb7c8a4b2017-03-20 13:03:39 -0400182 *this, &DisplayService::IsVrAppRunning, message);
Alex Vakulenkof0a7bd02017-03-31 18:06:19 -0700183 return {};
Albert Chaulkb7c8a4b2017-03-20 13:03:39 -0400184
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800185 // Direct the surface specific messages to the surface instance.
Corey Tabaka2251d822017-04-20 16:04:07 -0700186 case DisplayProtocol::SetAttributes::Opcode:
187 case DisplayProtocol::CreateQueue::Opcode:
188 case DisplayProtocol::GetSurfaceInfo::Opcode:
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800189 return HandleSurfaceMessage(message);
190
191 default:
192 return Service::HandleMessage(message);
193 }
194}
195
Corey Tabaka2251d822017-04-20 16:04:07 -0700196Status<display::Metrics> DisplayService::OnGetMetrics(
197 pdx::Message& /*message*/) {
Steven Thomasbfe46a02018-02-16 14:27:35 -0800198 const auto& params = hardware_composer_.GetPrimaryDisplayParams();
199 return {{static_cast<uint32_t>(params.width),
200 static_cast<uint32_t>(params.height),
201 static_cast<uint32_t>(params.dpi.x),
202 static_cast<uint32_t>(params.dpi.y),
203 static_cast<uint32_t>(params.vsync_period_ns),
Corey Tabaka2251d822017-04-20 16:04:07 -0700204 0,
205 0,
206 0,
207 0.0,
208 {},
209 {}}};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800210}
211
Hendrik Wagenaarbcb03d02017-05-23 14:59:08 -0700212pdx::Status<std::string> DisplayService::OnGetConfigurationData(
213 pdx::Message& /*message*/, display::ConfigFileType config_type) {
214 std::string property_name;
215 switch (config_type) {
216 case display::ConfigFileType::kLensMetrics:
217 property_name = kDvrLensMetricsProperty;
218 break;
219 case display::ConfigFileType::kDeviceMetrics:
220 property_name = kDvrDeviceMetricsProperty;
221 break;
222 case display::ConfigFileType::kDeviceConfiguration:
223 property_name = kDvrDeviceConfigProperty;
224 break;
mamika08194b2019-07-25 13:07:21 -0700225 case display::ConfigFileType::kDeviceEdid:
226 if (display_identification_data_.size() == 0) {
227 return ErrorStatus(ENOENT);
228 }
229 return std::string(display_identification_data_.begin(),
230 display_identification_data_.end());
Hendrik Wagenaarbcb03d02017-05-23 14:59:08 -0700231 default:
232 return ErrorStatus(EINVAL);
233 }
234 std::string file_path = base::GetProperty(property_name, "");
235 if (file_path.empty()) {
236 return ErrorStatus(ENOENT);
237 }
238
239 std::string data;
240 if (!base::ReadFileToString(file_path, &data)) {
241 return ErrorStatus(errno);
242 }
243
244 return std::move(data);
245}
246
mamik94e91f62019-08-19 09:11:33 -0700247pdx::Status<uint8_t> DisplayService::OnGetDisplayIdentificationPort(
248 pdx::Message& /*message*/) {
249 return display_identification_port_;
250}
251
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800252// Creates a new DisplaySurface and associates it with this channel. This may
253// only be done once per channel.
Corey Tabaka2251d822017-04-20 16:04:07 -0700254Status<display::SurfaceInfo> DisplayService::OnCreateSurface(
255 pdx::Message& message, const display::SurfaceAttributes& attributes) {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800256 // A surface may only be created once per channel.
257 if (message.GetChannel())
Corey Tabaka2251d822017-04-20 16:04:07 -0700258 return ErrorStatus(EINVAL);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800259
260 ALOGI_IF(TRACE, "DisplayService::OnCreateSurface: cid=%d",
261 message.GetChannelId());
262
263 // Use the channel id as the unique surface id.
264 const int surface_id = message.GetChannelId();
265 const int process_id = message.GetProcessId();
Corey Tabaka2251d822017-04-20 16:04:07 -0700266 const int user_id = message.GetEffectiveUserId();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800267
268 ALOGI_IF(TRACE,
Corey Tabaka2251d822017-04-20 16:04:07 -0700269 "DisplayService::OnCreateSurface: surface_id=%d process_id=%d",
270 surface_id, process_id);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800271
Corey Tabaka2251d822017-04-20 16:04:07 -0700272 auto surface_status =
273 DisplaySurface::Create(this, surface_id, process_id, user_id, attributes);
274 if (!surface_status) {
275 ALOGE("DisplayService::OnCreateSurface: Failed to create surface: %s",
276 surface_status.GetErrorMessage().c_str());
277 return ErrorStatus(surface_status.error());
278 }
Corey Tabaka00d9bb32017-08-16 19:59:48 -0700279 auto surface = surface_status.take();
280 message.SetChannel(surface);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800281
Corey Tabaka00d9bb32017-08-16 19:59:48 -0700282 // Update the surface with the attributes supplied with the create call. For
283 // application surfaces this has the side effect of notifying the display
284 // manager of the new surface. For direct surfaces, this may trigger a mode
285 // change, depending on the value of the visible attribute.
286 surface->OnSetAttributes(message, attributes);
Corey Tabaka2251d822017-04-20 16:04:07 -0700287
Corey Tabaka00d9bb32017-08-16 19:59:48 -0700288 return {{surface->surface_id(), surface->visible(), surface->z_order()}};
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800289}
290
Corey Tabaka2251d822017-04-20 16:04:07 -0700291void DisplayService::SurfaceUpdated(SurfaceType surface_type,
292 display::SurfaceUpdateFlags update_flags) {
293 ALOGD_IF(TRACE, "DisplayService::SurfaceUpdated: update_flags=%x",
294 update_flags.value());
295 if (update_flags.value() != 0) {
296 if (surface_type == SurfaceType::Application)
297 NotifyDisplayConfigurationUpdate();
298 else
299 UpdateActiveDisplaySurfaces();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800300 }
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800301}
302
Corey Tabaka99c2d732017-06-07 17:54:33 -0700303pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnSetupGlobalBuffer(
304 pdx::Message& message, DvrGlobalBufferKey key, size_t size,
305 uint64_t usage) {
306 const int user_id = message.GetEffectiveUserId();
307 const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
308
309 if (!trusted) {
310 ALOGE(
311 "DisplayService::OnSetupGlobalBuffer: Permission denied for user_id=%d",
312 user_id);
313 return ErrorStatus(EPERM);
314 }
315 return SetupGlobalBuffer(key, size, usage);
316}
317
318pdx::Status<void> DisplayService::OnDeleteGlobalBuffer(pdx::Message& message,
319 DvrGlobalBufferKey key) {
320 const int user_id = message.GetEffectiveUserId();
321 const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
322
323 if (!trusted) {
324 ALOGE(
325 "DisplayService::OnDeleteGlobalBuffer: Permission denied for "
326 "user_id=%d",
327 user_id);
328 return ErrorStatus(EPERM);
329 }
330 return DeleteGlobalBuffer(key);
331}
332
Okan Arikan36d23802017-05-15 15:20:39 -0700333pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetGlobalBuffer(
334 pdx::Message& /* message */, DvrGlobalBufferKey key) {
335 ALOGD_IF(TRACE, "DisplayService::OnGetGlobalBuffer: key=%d", key);
336 auto global_buffer = global_buffers_.find(key);
337 if (global_buffer != global_buffers_.end())
338 return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
Corey Tabaka2251d822017-04-20 16:04:07 -0700339 else
340 return pdx::ErrorStatus(EINVAL);
Hendrik Wagenaar10e68eb2017-03-15 13:29:02 -0700341}
342
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800343// Calls the message handler for the DisplaySurface associated with this
344// channel.
Corey Tabaka2251d822017-04-20 16:04:07 -0700345Status<void> DisplayService::HandleSurfaceMessage(pdx::Message& message) {
346 auto surface = std::static_pointer_cast<DisplaySurface>(message.GetChannel());
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800347 ALOGW_IF(!surface,
348 "DisplayService::HandleSurfaceMessage: surface is nullptr!");
349
350 if (surface)
351 return surface->HandleMessage(message);
352 else
Corey Tabaka2251d822017-04-20 16:04:07 -0700353 return ErrorStatus(EINVAL);
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800354}
355
356std::shared_ptr<DisplaySurface> DisplayService::GetDisplaySurface(
357 int surface_id) const {
358 return std::static_pointer_cast<DisplaySurface>(GetChannel(surface_id));
359}
360
361std::vector<std::shared_ptr<DisplaySurface>>
362DisplayService::GetDisplaySurfaces() const {
363 return GetChannels<DisplaySurface>();
364}
365
Corey Tabaka2251d822017-04-20 16:04:07 -0700366std::vector<std::shared_ptr<DirectDisplaySurface>>
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800367DisplayService::GetVisibleDisplaySurfaces() const {
Corey Tabaka2251d822017-04-20 16:04:07 -0700368 std::vector<std::shared_ptr<DirectDisplaySurface>> visible_surfaces;
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800369
370 ForEachDisplaySurface(
Corey Tabaka2251d822017-04-20 16:04:07 -0700371 SurfaceType::Direct,
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800372 [&](const std::shared_ptr<DisplaySurface>& surface) mutable {
Corey Tabaka2251d822017-04-20 16:04:07 -0700373 if (surface->visible()) {
374 visible_surfaces.push_back(
375 std::static_pointer_cast<DirectDisplaySurface>(surface));
376 surface->ClearUpdate();
377 }
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800378 });
379
380 return visible_surfaces;
381}
382
Steven Thomas050b2c82017-03-06 11:45:16 -0800383void DisplayService::UpdateActiveDisplaySurfaces() {
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800384 auto visible_surfaces = GetVisibleDisplaySurfaces();
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800385 ALOGD_IF(TRACE,
386 "DisplayService::UpdateActiveDisplaySurfaces: %zd visible surfaces",
387 visible_surfaces.size());
Steven Thomas050b2c82017-03-06 11:45:16 -0800388 hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800389}
390
Okan Arikan36d23802017-05-15 15:20:39 -0700391pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupGlobalBuffer(
392 DvrGlobalBufferKey key, size_t size, uint64_t usage) {
393 auto global_buffer = global_buffers_.find(key);
394 if (global_buffer == global_buffers_.end()) {
Jiwen 'Steve' Cai0057fdd2017-05-02 11:21:18 -0700395 auto ion_buffer = std::make_unique<IonBuffer>(static_cast<int>(size), 1,
396 HAL_PIXEL_FORMAT_BLOB, usage);
John Bates954796e2017-05-11 11:00:31 -0700397
398 // Some buffers are used internally. If they were configured with an
399 // invalid size or format, this will fail.
400 int result = hardware_composer_.OnNewGlobalBuffer(key, *ion_buffer.get());
401 if (result < 0)
402 return ErrorStatus(result);
Okan Arikan36d23802017-05-15 15:20:39 -0700403 global_buffer =
404 global_buffers_.insert(std::make_pair(key, std::move(ion_buffer)))
Hendrik Wagenaareaa55222017-04-06 10:56:23 -0700405 .first;
Hendrik Wagenaar10e68eb2017-03-15 13:29:02 -0700406 }
407
Okan Arikan36d23802017-05-15 15:20:39 -0700408 return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
Hendrik Wagenaar10e68eb2017-03-15 13:29:02 -0700409}
410
John Bates954796e2017-05-11 11:00:31 -0700411pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
412 auto global_buffer = global_buffers_.find(key);
413 if (global_buffer != global_buffers_.end()) {
414 // Some buffers are used internally.
415 hardware_composer_.OnDeletedGlobalBuffer(key);
416 global_buffers_.erase(global_buffer);
417 }
418
419 return {0};
420}
421
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800422void DisplayService::SetDisplayConfigurationUpdateNotifier(
423 DisplayConfigurationUpdateNotifier update_notifier) {
424 update_notifier_ = update_notifier;
425}
426
427void DisplayService::NotifyDisplayConfigurationUpdate() {
428 if (update_notifier_)
429 update_notifier_();
430}
431
Corey Tabaka2251d822017-04-20 16:04:07 -0700432Status<bool> DisplayService::IsVrAppRunning(pdx::Message& /*message*/) {
Albert Chaulk356bc372017-04-05 18:01:58 -0400433 bool visible = false;
Hendrik Wagenaareaa55222017-04-06 10:56:23 -0700434 ForEachDisplaySurface(
Corey Tabaka2251d822017-04-20 16:04:07 -0700435 SurfaceType::Application,
Hendrik Wagenaareaa55222017-04-06 10:56:23 -0700436 [&visible](const std::shared_ptr<DisplaySurface>& surface) {
Corey Tabaka2251d822017-04-20 16:04:07 -0700437 if (surface->visible())
Hendrik Wagenaareaa55222017-04-06 10:56:23 -0700438 visible = true;
439 });
Albert Chaulkb7c8a4b2017-03-20 13:03:39 -0400440
Corey Tabaka2251d822017-04-20 16:04:07 -0700441 return {visible};
Albert Chaulkb7c8a4b2017-03-20 13:03:39 -0400442}
443
Alex Vakulenkoa8a92782017-01-27 14:41:57 -0800444} // namespace dvr
445} // namespace android