Loading libs/vr/libvrflinger/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -93,3 +93,7 @@ cc_library_static { header_libs: headerLibraries, name: "libvrflinger", } subdirs = [ "tests", ] libs/vr/libvrflinger/tests/Android.bp 0 → 100644 +37 −0 Original line number Diff line number Diff line shared_libs = [ "android.hardware.configstore-utils", "android.hardware.configstore@1.0", "libbinder", "libbufferhubqueue", "libcutils", "libgui", "libhidlbase", "liblog", "libui", "libutils", "libnativewindow", "libpdx_default_transport", ] static_libs = [ "libdisplay", ] cc_test { srcs: ["vrflinger_test.cpp"], // See go/apct-presubmit for documentation on how this .filter file is used // by Android's automated testing infrastructure for test filtering. data: ["vrflinger_test.filter"], static_libs: static_libs, shared_libs: shared_libs, cflags: [ "-DLOG_TAG=\"VrFlingerTest\"", "-DTRACE=0", "-O0", "-g", "-Wall", "-Werror", ], cppflags: ["-std=c++1z"], name: "vrflinger_test", } libs/vr/libvrflinger/tests/vrflinger_test.cpp 0 → 100644 +229 −0 Original line number Diff line number Diff line #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/types.h> #include <android/hardware_buffer.h> #include <binder/IServiceManager.h> #include <binder/Parcel.h> #include <binder/ProcessState.h> #include <configstore/Utils.h> #include <cutils/properties.h> #include <gtest/gtest.h> #include <gui/ISurfaceComposer.h> #include <log/log.h> #include <utils/StrongPointer.h> #include <chrono> #include <memory> #include <mutex> #include <optional> #include <thread> #include <private/dvr/display_client.h> using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; using android::dvr::display::DisplayClient; using android::dvr::display::Surface; using android::dvr::display::SurfaceAttribute; using android::dvr::display::SurfaceAttributeValue; namespace android { namespace dvr { // The transaction code for asking surface flinger if vr flinger is active. This // is done as a hidden api since it's only used for tests. See the "case 1028" // block in SurfaceFlinger::onTransact() in SurfaceFlinger.cpp. constexpr uint32_t kIsVrFlingerActiveTransactionCode = 1028; // The maximum amount of time to give vr flinger to activate/deactivate. If the // switch hasn't completed in this amount of time, the test will fail. constexpr auto kVrFlingerSwitchMaxTime = std::chrono::seconds(1); // How long to wait between each check to see if the vr flinger switch // completed. constexpr auto kVrFlingerSwitchPollInterval = std::chrono::milliseconds(50); // A Binder connection to surface flinger. class SurfaceFlingerConnection { public: static std::unique_ptr<SurfaceFlingerConnection> Create() { sp<ISurfaceComposer> surface_flinger = interface_cast<ISurfaceComposer>( defaultServiceManager()->getService(String16("SurfaceFlinger"))); if (surface_flinger == nullptr) { return nullptr; } return std::unique_ptr<SurfaceFlingerConnection>( new SurfaceFlingerConnection(surface_flinger)); } // Returns true if the surface flinger process is still running. We use this // to detect if surface flinger has crashed. bool IsAlive() { IInterface::asBinder(surface_flinger_)->pingBinder(); return IInterface::asBinder(surface_flinger_)->isBinderAlive(); } // Return true if vr flinger is currently active, false otherwise. If there's // an error communicating with surface flinger, std::nullopt is returned. std::optional<bool> IsVrFlingerActive() { Parcel data, reply; status_t result = data.writeInterfaceToken(surface_flinger_->getInterfaceDescriptor()); if (result != NO_ERROR) { return std::nullopt; } result = IInterface::asBinder(surface_flinger_) ->transact(kIsVrFlingerActiveTransactionCode, data, &reply); if (result != NO_ERROR) { return std::nullopt; } bool vr_flinger_active; result = reply.readBool(&vr_flinger_active); if (result != NO_ERROR) { return std::nullopt; } return vr_flinger_active; } enum class VrFlingerSwitchResult : int8_t { kSuccess, kTimedOut, kCommunicationError, kSurfaceFlingerDied }; // Wait for vr flinger to become active or inactive. VrFlingerSwitchResult WaitForVrFlinger(bool wait_active) { auto start_time = std::chrono::steady_clock::now(); while (1) { std::this_thread::sleep_for(kVrFlingerSwitchPollInterval); if (!IsAlive()) { return VrFlingerSwitchResult::kSurfaceFlingerDied; } std::optional<bool> vr_flinger_active = IsVrFlingerActive(); if (!vr_flinger_active.has_value()) { return VrFlingerSwitchResult::kCommunicationError; } if (vr_flinger_active.value() == wait_active) { return VrFlingerSwitchResult::kSuccess; } else if (std::chrono::steady_clock::now() - start_time > kVrFlingerSwitchMaxTime) { return VrFlingerSwitchResult::kTimedOut; } } } private: SurfaceFlingerConnection(sp<ISurfaceComposer> surface_flinger) : surface_flinger_(surface_flinger) {} sp<ISurfaceComposer> surface_flinger_ = nullptr; }; // This test activates vr flinger by creating a vr flinger surface, then // deactivates vr flinger by destroying the surface. We verify that vr flinger // is activated and deactivated as expected, and that surface flinger doesn't // crash. // // If the device doesn't support vr flinger (as repoted by ConfigStore), the // test does nothing. // // If the device is a standalone vr device, the test also does nothing, since // this test verifies the behavior of display handoff from surface flinger to vr // flinger and back, and standalone devices never hand control of the display // back to surface flinger. TEST(VrFlingerTest, ActivateDeactivate) { android::ProcessState::self()->startThreadPool(); // Exit immediately if the device doesn't support vr flinger. This ConfigStore // check is the same mechanism used by surface flinger to decide if it should // initialize vr flinger. bool vr_flinger_enabled = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useVrFlinger>( false); if (!vr_flinger_enabled) { return; } // This test doesn't apply to standalone vr devices. if (property_get_bool("ro.boot.vr", false)) { return; } auto surface_flinger_connection = SurfaceFlingerConnection::Create(); ASSERT_NE(surface_flinger_connection, nullptr); // Verify we start off with vr flinger disabled. ASSERT_TRUE(surface_flinger_connection->IsAlive()); auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive(); ASSERT_TRUE(vr_flinger_active.has_value()); ASSERT_FALSE(vr_flinger_active.value()); // Create a vr flinger surface, and verify vr flinger becomes active. // Introduce a scope so that, at the end of the scope, the vr flinger surface // is destroyed, and vr flinger deactivates. { auto display_client = DisplayClient::Create(); ASSERT_NE(display_client, nullptr); auto metrics = display_client->GetDisplayMetrics(); ASSERT_TRUE(metrics.ok()); auto surface = Surface::CreateSurface({ {SurfaceAttribute::Direct, SurfaceAttributeValue(true)}, {SurfaceAttribute::Visible, SurfaceAttributeValue(true)}, }); ASSERT_TRUE(surface.ok()); ASSERT_TRUE(surface.get() != nullptr); auto queue = surface.get()->CreateQueue( metrics.get().display_width, metrics.get().display_height, /*layer_count=*/1, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*capacity=*/1, /*metadata_size=*/0); ASSERT_TRUE(queue.ok()); ASSERT_TRUE(queue.get() != nullptr); size_t slot; pdx::LocalHandle release_fence; auto buffer = queue.get()->Dequeue(/*timeout=*/0, &slot, &release_fence); ASSERT_TRUE(buffer.ok()); ASSERT_TRUE(buffer.get() != nullptr); ASSERT_EQ(buffer.get()->width(), metrics.get().display_width); ASSERT_EQ(buffer.get()->height(), metrics.get().display_height); void* raw_buf = nullptr; ASSERT_GE(buffer.get()->Lock(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*x=*/0, /*y=*/0, buffer.get()->width(), buffer.get()->height(), &raw_buf), 0); ASSERT_NE(raw_buf, nullptr); uint32_t* pixels = static_cast<uint32_t*>(raw_buf); for (int i = 0; i < buffer.get()->stride() * buffer.get()->height(); ++i) { pixels[i] = 0x0000ff00; } ASSERT_GE(buffer.get()->Unlock(), 0); ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle(), /*meta=*/nullptr, /*user_metadata_size=*/0), 0); ASSERT_EQ( surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true), SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess); } // Now that the vr flinger surface is destroyed, vr flinger should deactivate. ASSERT_EQ( surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/false), SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess); } } // namespace dvr } // namespace android libs/vr/libvrflinger/tests/vrflinger_test.filter 0 → 100644 +5 −0 Original line number Diff line number Diff line { "presubmit": { "filter": "VrFlingerTest.*" } } services/surfaceflinger/SurfaceFlinger.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -4619,6 +4619,12 @@ status_t SurfaceFlinger::onTransact( } return NO_ERROR; } // Is VrFlinger active? case 1028: { Mutex::Autolock _l(mStateLock); reply->writeBool(getBE().mHwc->isUsingVrComposer()); return NO_ERROR; } } } return err; Loading Loading
libs/vr/libvrflinger/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -93,3 +93,7 @@ cc_library_static { header_libs: headerLibraries, name: "libvrflinger", } subdirs = [ "tests", ]
libs/vr/libvrflinger/tests/Android.bp 0 → 100644 +37 −0 Original line number Diff line number Diff line shared_libs = [ "android.hardware.configstore-utils", "android.hardware.configstore@1.0", "libbinder", "libbufferhubqueue", "libcutils", "libgui", "libhidlbase", "liblog", "libui", "libutils", "libnativewindow", "libpdx_default_transport", ] static_libs = [ "libdisplay", ] cc_test { srcs: ["vrflinger_test.cpp"], // See go/apct-presubmit for documentation on how this .filter file is used // by Android's automated testing infrastructure for test filtering. data: ["vrflinger_test.filter"], static_libs: static_libs, shared_libs: shared_libs, cflags: [ "-DLOG_TAG=\"VrFlingerTest\"", "-DTRACE=0", "-O0", "-g", "-Wall", "-Werror", ], cppflags: ["-std=c++1z"], name: "vrflinger_test", }
libs/vr/libvrflinger/tests/vrflinger_test.cpp 0 → 100644 +229 −0 Original line number Diff line number Diff line #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/types.h> #include <android/hardware_buffer.h> #include <binder/IServiceManager.h> #include <binder/Parcel.h> #include <binder/ProcessState.h> #include <configstore/Utils.h> #include <cutils/properties.h> #include <gtest/gtest.h> #include <gui/ISurfaceComposer.h> #include <log/log.h> #include <utils/StrongPointer.h> #include <chrono> #include <memory> #include <mutex> #include <optional> #include <thread> #include <private/dvr/display_client.h> using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; using android::dvr::display::DisplayClient; using android::dvr::display::Surface; using android::dvr::display::SurfaceAttribute; using android::dvr::display::SurfaceAttributeValue; namespace android { namespace dvr { // The transaction code for asking surface flinger if vr flinger is active. This // is done as a hidden api since it's only used for tests. See the "case 1028" // block in SurfaceFlinger::onTransact() in SurfaceFlinger.cpp. constexpr uint32_t kIsVrFlingerActiveTransactionCode = 1028; // The maximum amount of time to give vr flinger to activate/deactivate. If the // switch hasn't completed in this amount of time, the test will fail. constexpr auto kVrFlingerSwitchMaxTime = std::chrono::seconds(1); // How long to wait between each check to see if the vr flinger switch // completed. constexpr auto kVrFlingerSwitchPollInterval = std::chrono::milliseconds(50); // A Binder connection to surface flinger. class SurfaceFlingerConnection { public: static std::unique_ptr<SurfaceFlingerConnection> Create() { sp<ISurfaceComposer> surface_flinger = interface_cast<ISurfaceComposer>( defaultServiceManager()->getService(String16("SurfaceFlinger"))); if (surface_flinger == nullptr) { return nullptr; } return std::unique_ptr<SurfaceFlingerConnection>( new SurfaceFlingerConnection(surface_flinger)); } // Returns true if the surface flinger process is still running. We use this // to detect if surface flinger has crashed. bool IsAlive() { IInterface::asBinder(surface_flinger_)->pingBinder(); return IInterface::asBinder(surface_flinger_)->isBinderAlive(); } // Return true if vr flinger is currently active, false otherwise. If there's // an error communicating with surface flinger, std::nullopt is returned. std::optional<bool> IsVrFlingerActive() { Parcel data, reply; status_t result = data.writeInterfaceToken(surface_flinger_->getInterfaceDescriptor()); if (result != NO_ERROR) { return std::nullopt; } result = IInterface::asBinder(surface_flinger_) ->transact(kIsVrFlingerActiveTransactionCode, data, &reply); if (result != NO_ERROR) { return std::nullopt; } bool vr_flinger_active; result = reply.readBool(&vr_flinger_active); if (result != NO_ERROR) { return std::nullopt; } return vr_flinger_active; } enum class VrFlingerSwitchResult : int8_t { kSuccess, kTimedOut, kCommunicationError, kSurfaceFlingerDied }; // Wait for vr flinger to become active or inactive. VrFlingerSwitchResult WaitForVrFlinger(bool wait_active) { auto start_time = std::chrono::steady_clock::now(); while (1) { std::this_thread::sleep_for(kVrFlingerSwitchPollInterval); if (!IsAlive()) { return VrFlingerSwitchResult::kSurfaceFlingerDied; } std::optional<bool> vr_flinger_active = IsVrFlingerActive(); if (!vr_flinger_active.has_value()) { return VrFlingerSwitchResult::kCommunicationError; } if (vr_flinger_active.value() == wait_active) { return VrFlingerSwitchResult::kSuccess; } else if (std::chrono::steady_clock::now() - start_time > kVrFlingerSwitchMaxTime) { return VrFlingerSwitchResult::kTimedOut; } } } private: SurfaceFlingerConnection(sp<ISurfaceComposer> surface_flinger) : surface_flinger_(surface_flinger) {} sp<ISurfaceComposer> surface_flinger_ = nullptr; }; // This test activates vr flinger by creating a vr flinger surface, then // deactivates vr flinger by destroying the surface. We verify that vr flinger // is activated and deactivated as expected, and that surface flinger doesn't // crash. // // If the device doesn't support vr flinger (as repoted by ConfigStore), the // test does nothing. // // If the device is a standalone vr device, the test also does nothing, since // this test verifies the behavior of display handoff from surface flinger to vr // flinger and back, and standalone devices never hand control of the display // back to surface flinger. TEST(VrFlingerTest, ActivateDeactivate) { android::ProcessState::self()->startThreadPool(); // Exit immediately if the device doesn't support vr flinger. This ConfigStore // check is the same mechanism used by surface flinger to decide if it should // initialize vr flinger. bool vr_flinger_enabled = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useVrFlinger>( false); if (!vr_flinger_enabled) { return; } // This test doesn't apply to standalone vr devices. if (property_get_bool("ro.boot.vr", false)) { return; } auto surface_flinger_connection = SurfaceFlingerConnection::Create(); ASSERT_NE(surface_flinger_connection, nullptr); // Verify we start off with vr flinger disabled. ASSERT_TRUE(surface_flinger_connection->IsAlive()); auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive(); ASSERT_TRUE(vr_flinger_active.has_value()); ASSERT_FALSE(vr_flinger_active.value()); // Create a vr flinger surface, and verify vr flinger becomes active. // Introduce a scope so that, at the end of the scope, the vr flinger surface // is destroyed, and vr flinger deactivates. { auto display_client = DisplayClient::Create(); ASSERT_NE(display_client, nullptr); auto metrics = display_client->GetDisplayMetrics(); ASSERT_TRUE(metrics.ok()); auto surface = Surface::CreateSurface({ {SurfaceAttribute::Direct, SurfaceAttributeValue(true)}, {SurfaceAttribute::Visible, SurfaceAttributeValue(true)}, }); ASSERT_TRUE(surface.ok()); ASSERT_TRUE(surface.get() != nullptr); auto queue = surface.get()->CreateQueue( metrics.get().display_width, metrics.get().display_height, /*layer_count=*/1, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*capacity=*/1, /*metadata_size=*/0); ASSERT_TRUE(queue.ok()); ASSERT_TRUE(queue.get() != nullptr); size_t slot; pdx::LocalHandle release_fence; auto buffer = queue.get()->Dequeue(/*timeout=*/0, &slot, &release_fence); ASSERT_TRUE(buffer.ok()); ASSERT_TRUE(buffer.get() != nullptr); ASSERT_EQ(buffer.get()->width(), metrics.get().display_width); ASSERT_EQ(buffer.get()->height(), metrics.get().display_height); void* raw_buf = nullptr; ASSERT_GE(buffer.get()->Lock(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*x=*/0, /*y=*/0, buffer.get()->width(), buffer.get()->height(), &raw_buf), 0); ASSERT_NE(raw_buf, nullptr); uint32_t* pixels = static_cast<uint32_t*>(raw_buf); for (int i = 0; i < buffer.get()->stride() * buffer.get()->height(); ++i) { pixels[i] = 0x0000ff00; } ASSERT_GE(buffer.get()->Unlock(), 0); ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle(), /*meta=*/nullptr, /*user_metadata_size=*/0), 0); ASSERT_EQ( surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true), SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess); } // Now that the vr flinger surface is destroyed, vr flinger should deactivate. ASSERT_EQ( surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/false), SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess); } } // namespace dvr } // namespace android
libs/vr/libvrflinger/tests/vrflinger_test.filter 0 → 100644 +5 −0 Original line number Diff line number Diff line { "presubmit": { "filter": "VrFlingerTest.*" } }
services/surfaceflinger/SurfaceFlinger.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -4619,6 +4619,12 @@ status_t SurfaceFlinger::onTransact( } return NO_ERROR; } // Is VrFlinger active? case 1028: { Mutex::Autolock _l(mStateLock); reply->writeBool(getBE().mHwc->isUsingVrComposer()); return NO_ERROR; } } } return err; Loading