display_client.cpp revision 108e84f7e6a9117b66dba000dcf16c6d8c862e16
1e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include "include/private/dvr/display_client.h" 2e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 3e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <cutils/native_handle.h> 44fe60582f314e381098f8f3bc2e39c5880e9243aAlex Vakulenko#include <log/log.h> 5e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <pdx/default_transport/client_channel.h> 6e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <pdx/default_transport/client_channel_factory.h> 7e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <pdx/status.h> 8e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 9e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <mutex> 10e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 113f82d31341f66d0c58e1ec3360ea5f528ffe0ea4Corey Tabaka#include <private/dvr/display_protocol.h> 12e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <private/dvr/late_latch.h> 13e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko#include <private/dvr/native_buffer.h> 14e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 152251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakausing android::pdx::ErrorStatus; 16e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing android::pdx::LocalHandle; 17e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing android::pdx::LocalChannelHandle; 18e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing android::pdx::Status; 19e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing android::pdx::Transaction; 20e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkousing android::pdx::rpc::IfAnyOf; 21e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 22e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace android { 23e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenkonamespace dvr { 242251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabakanamespace display { 25e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 262251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaSurface::Surface(LocalChannelHandle channel_handle, int* error) 272251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka : BASE{pdx::default_transport::ClientChannel::Create( 282251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka std::move(channel_handle))} { 292251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto status = InvokeRemoteMethod<DisplayProtocol::GetSurfaceInfo>(); 302251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (!status) { 312251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Surface::Surface: Failed to get surface info: %s", 32e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko status.GetErrorMessage().c_str()); 332251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka Close(status.error()); 342251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (error) 352251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka *error = status.error(); 36e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 37e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 382251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka surface_id_ = status.get().surface_id; 392251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka z_order_ = status.get().z_order; 402251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka visible_ = status.get().visible; 41e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 42e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 432251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaSurface::Surface(const SurfaceAttributes& attributes, int* error) 442251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka : BASE{pdx::default_transport::ClientChannelFactory::Create( 452251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka DisplayProtocol::kClientPath), 462251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka kInfiniteTimeout} { 472251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto status = InvokeRemoteMethod<DisplayProtocol::CreateSurface>(attributes); 48e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (!status) { 492251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Surface::Surface: Failed to create display surface: %s", 502251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka status.GetErrorMessage().c_str()); 51e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko Close(status.error()); 522251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (error) 532251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka *error = status.error(); 54e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 55e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 562251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka surface_id_ = status.get().surface_id; 572251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka z_order_ = status.get().z_order; 582251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka visible_ = status.get().visible; 59e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 60e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 612251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<void> Surface::SetVisible(bool visible) { 622251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return SetAttributes( 632251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka {{SurfaceAttribute::Visible, SurfaceAttributeValue{visible}}}); 64e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 65e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 662251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<void> Surface::SetZOrder(int z_order) { 672251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return SetAttributes( 682251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka {{SurfaceAttribute::ZOrder, SurfaceAttributeValue{z_order}}}); 69e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 70e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 712251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<void> Surface::SetAttributes(const SurfaceAttributes& attributes) { 722251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto status = InvokeRemoteMethod<DisplayProtocol::SetAttributes>(attributes); 73e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (!status) { 74e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGE( 752251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "Surface::SetAttributes: Failed to set display surface " 76e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko "attributes: %s", 77e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko status.GetErrorMessage().c_str()); 782251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return status.error_status(); 79e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 80e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 81e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // Set the local cached copies of the attributes we care about from the full 82e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko // set of attributes sent to the display service. 83e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko for (const auto& attribute : attributes) { 84e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const auto& key = attribute.first; 85e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko const auto* variant = &attribute.second; 86e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko bool invalid_value = false; 87e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko switch (key) { 882251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka case SurfaceAttribute::Visible: 89e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko invalid_value = 90e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko !IfAnyOf<int32_t, int64_t, bool>::Get(variant, &visible_); 91e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko break; 922251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka case SurfaceAttribute::ZOrder: 93e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko invalid_value = !IfAnyOf<int32_t>::Get(variant, &z_order_); 94e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko break; 95e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 96e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 97e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (invalid_value) { 98e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko ALOGW( 992251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "Surface::SetAttributes: Failed to set display surface " 1002251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "attribute %d because of incompatible type: %d", 1012251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka key, variant->index()); 102e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 103e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 1042251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1052251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return {}; 106e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 107e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 1082251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<std::unique_ptr<ProducerQueue>> Surface::CreateQueue() { 1092251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue."); 1102251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0); 1112251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (!status) { 1122251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Surface::CreateQueue: Failed to create queue: %s", 113e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko status.GetErrorMessage().c_str()); 1142251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return status.error_status(); 115a3613612a1142c3134045f08c30a861ea43288edJiwen 'Steve' Cai } 116e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 1172251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto producer_queue = ProducerQueue::Import(status.take()); 1182251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (!producer_queue) { 1192251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE("Surface::CreateQueue: Failed to import producer queue!"); 1202251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return ErrorStatus(ENOMEM); 121e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 122e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 1232251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return {std::move(producer_queue)}; 124e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 125e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 126108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik WagenaarStatus<std::unique_ptr<ProducerQueue>> Surface::CreateQueue( 127108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik Wagenaar uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format, 128108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik Wagenaar uint64_t usage, size_t capacity) { 1292251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF(TRACE, 130108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik Wagenaar "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u " 131108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik Wagenaar "usage=%" PRIx64 " capacity=%zu", 132108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik Wagenaar width, height, layer_count, format, usage, capacity); 1332251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto status = CreateQueue(); 1342251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (!status) 1352251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return status.error_status(); 1362251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1372251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto producer_queue = status.take(); 1382251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1392251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity); 1402251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka for (size_t i = 0; i < capacity; i++) { 1412251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka size_t slot; 142108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik Wagenaar const int ret = producer_queue->AllocateBuffer(width, height, layer_count, 143108e84f7e6a9117b66dba000dcf16c6d8c862e16Hendrik Wagenaar format, usage, &slot); 1442251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (ret < 0) { 1452251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE( 1462251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s", 1472251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka producer_queue->id(), strerror(-ret)); 1482251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return ErrorStatus(ENOMEM); 1492251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 1502251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGD_IF( 1512251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka TRACE, 1522251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "Surface::CreateQueue: Allocated buffer at slot=%zu of capacity=%zu", 1532251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka slot, capacity); 154e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko } 1552251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 1562251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return {std::move(producer_queue)}; 157e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 158e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 159e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex VakulenkoDisplayClient::DisplayClient(int* error) 160e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko : BASE(pdx::default_transport::ClientChannelFactory::Create( 1612251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka DisplayProtocol::kClientPath), 162e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko kInfiniteTimeout) { 163e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko if (error) 164e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko *error = Client::error(); 165e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 166e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 1672251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<Metrics> DisplayClient::GetDisplayMetrics() { 1682251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return InvokeRemoteMethod<DisplayProtocol::GetMetrics>(); 169e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 170e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 1712251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<std::unique_ptr<Surface>> DisplayClient::CreateSurface( 1722251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka const SurfaceAttributes& attributes) { 1732251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka int error; 1742251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (auto client = Surface::Create(attributes, &error)) 1752251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return {std::move(client)}; 1762251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka else 1772251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return ErrorStatus(error); 178e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} 179e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko 1802251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<std::unique_ptr<IonBuffer>> DisplayClient::GetNamedBuffer( 181eaa5522feac452703a0836310047d4b15702487dHendrik Wagenaar const std::string& name) { 1822251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto status = InvokeRemoteMethod<DisplayProtocol::GetNamedBuffer>(name); 18310e68eb8aa4db8b6f8cfbf2c3754e2677d7bf848Hendrik Wagenaar if (!status) { 18410e68eb8aa4db8b6f8cfbf2c3754e2677d7bf848Hendrik Wagenaar ALOGE( 1852251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "DisplayClient::GetNamedBuffer: Failed to get named buffer: name=%s; " 186eaa5522feac452703a0836310047d4b15702487dHendrik Wagenaar "error=%s", 187eaa5522feac452703a0836310047d4b15702487dHendrik Wagenaar name.c_str(), status.GetErrorMessage().c_str()); 1882251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return status.error_status(); 18910e68eb8aa4db8b6f8cfbf2c3754e2677d7bf848Hendrik Wagenaar } 19010e68eb8aa4db8b6f8cfbf2c3754e2677d7bf848Hendrik Wagenaar 191eaa5522feac452703a0836310047d4b15702487dHendrik Wagenaar auto ion_buffer = std::make_unique<IonBuffer>(); 1922251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka auto native_buffer_handle = status.take(); 1932251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka const int ret = native_buffer_handle.Import(ion_buffer.get()); 1942251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka if (ret < 0) { 1952251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka ALOGE( 1962251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "DisplayClient::GetNamedBuffer: Failed to import named buffer: " 1972251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka "name=%s; error=%s", 1982251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka name.c_str(), strerror(-ret)); 1992251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return ErrorStatus(-ret); 2002251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka } 2012251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka 2022251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return {std::move(ion_buffer)}; 20310e68eb8aa4db8b6f8cfbf2c3754e2677d7bf848Hendrik Wagenaar} 20410e68eb8aa4db8b6f8cfbf2c3754e2677d7bf848Hendrik Wagenaar 2052251d822dac2a96aad4184a6fdc2690f0a58af7cCorey TabakaStatus<bool> DisplayClient::IsVrAppRunning() { 2062251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka return InvokeRemoteMethod<DisplayProtocol::IsVrAppRunning>(); 207b7c8a4bd8131ce18fb4ab4ee986c3b6b1ed27ad5Albert Chaulk} 20810e68eb8aa4db8b6f8cfbf2c3754e2677d7bf848Hendrik Wagenaar 2092251d822dac2a96aad4184a6fdc2690f0a58af7cCorey Tabaka} // namespace display 210e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace dvr 211e4eec20f6263f4a42ae462456f60ea6c4518bb0aAlex Vakulenko} // namespace android 212