#include #include #include #include #include #include #include #include #include #include namespace android { using Transaction = SurfaceComposerClient::Transaction; using ui::ColorMode; namespace { const String8 DISPLAY_NAME("Credentials Display Test"); const String8 SURFACE_NAME("Test Surface Name"); const float FRAME_SCALE = 1.0f; } // namespace /** * This class tests the CheckCredentials method in SurfaceFlinger. * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not * return anything meaningful. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" class CredentialsTest : public ::testing::Test { protected: void SetUp() override { // Start the tests as root. seteuid(AID_ROOT); ASSERT_NO_FATAL_FAILURE(initClient()); } void TearDown() override { mComposerClient->dispose(); mBGSurfaceControl.clear(); mComposerClient.clear(); // Finish the tests as root. seteuid(AID_ROOT); } sp mDisplay; sp mVirtualDisplay; sp mComposerClient; sp mBGSurfaceControl; sp mVirtualSurfaceControl; void initClient() { mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); } void setupBackgroundSurface() { mDisplay = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_FALSE(mDisplay == nullptr); DisplayConfig config; ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config)); // Background surface mBGSurfaceControl = mComposerClient->createSurface(SURFACE_NAME, config.resolution.getWidth(), config.resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mBGSurfaceControl != nullptr); ASSERT_TRUE(mBGSurfaceControl->isValid()); Transaction t; t.setDisplayLayerStack(mDisplay, 0); ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply()); } void setupVirtualDisplay() { mVirtualDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); const ssize_t displayWidth = 100; const ssize_t displayHeight = 100; // Background surface mVirtualSurfaceControl = mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, PIXEL_FORMAT_RGBA_8888, 0); ASSERT_TRUE(mVirtualSurfaceControl != nullptr); ASSERT_TRUE(mVirtualSurfaceControl->isValid()); Transaction t; t.setDisplayLayerStack(mVirtualDisplay, 0); ASSERT_EQ(NO_ERROR, t.setLayer(mVirtualSurfaceControl, INT_MAX - 3) .show(mVirtualSurfaceControl) .apply()); } /** * Sets UID to imitate Graphic's process. */ void setGraphicsUID() { seteuid(AID_ROOT); seteuid(AID_GRAPHICS); } /** * Sets UID to imitate System's process. */ void setSystemUID() { seteuid(AID_ROOT); seteuid(AID_SYSTEM); } /** * Sets UID to imitate a process that doesn't have any special privileges in * our code. */ void setBinUID() { seteuid(AID_ROOT); seteuid(AID_BIN); } /** * Template function the check a condition for different types of users: root * graphics, system, and non-supported user. Root, graphics, and system should * always equal privilegedValue, and non-supported user should equal unprivilegedValue. */ template void checkWithPrivileges(std::function condition, T privilegedValue, T unprivilegedValue) { // Check with root. seteuid(AID_ROOT); ASSERT_EQ(privilegedValue, condition()); // Check as a Graphics user. setGraphicsUID(); ASSERT_EQ(privilegedValue, condition()); // Check as a system user. setSystemUID(); ASSERT_EQ(privilegedValue, condition()); // Check as a non-supported user. setBinUID(); ASSERT_EQ(unprivilegedValue, condition()); } }; TEST_F(CredentialsTest, ClientInitTest) { // Root can init can init the client. ASSERT_NO_FATAL_FAILURE(initClient()); // Graphics can init the client. setGraphicsUID(); ASSERT_NO_FATAL_FAILURE(initClient()); // System can init the client. setSystemUID(); ASSERT_NO_FATAL_FAILURE(initClient()); // Anyone else can init the client. setBinUID(); mComposerClient = new SurfaceComposerClient; ASSERT_NO_FATAL_FAILURE(initClient()); } TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) { std::function condition = [] { return SurfaceComposerClient::getInternalDisplayToken() != nullptr; }; // Anyone can access display information. ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); } TEST_F(CredentialsTest, AllowedGetterMethodsTest) { // The following methods are tested with a UID that is not root, graphics, // or system, to show that anyone can access them. setBinUID(); const auto display = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_TRUE(display != nullptr); DisplayConfig config; ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config)); Vector configs; ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs)); ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display)); ASSERT_NE(static_cast(BAD_VALUE), SurfaceComposerClient::getActiveColorMode(display)); } TEST_F(CredentialsTest, GetDisplayColorModesTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { Vector outColorModes; return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { ui::DisplayPrimaries primaries; return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); int32_t defaultConfig; float primaryFpsMin; float primaryFpsMax; float appRequestFpsMin; float appRequestFpsMax; status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig, &primaryFpsMin, &primaryFpsMax, &appRequestFpsMin, &appRequestFpsMax); ASSERT_EQ(res, NO_ERROR); std::function condition = [=]() { return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, primaryFpsMin, primaryFpsMax, appRequestFpsMin, appRequestFpsMax); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } TEST_F(CredentialsTest, SetActiveColorModeTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } TEST_F(CredentialsTest, CreateDisplayTest) { std::function condition = [=]() { sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); return testDisplay.get() != nullptr; }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); condition = [=]() { sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false); return testDisplay.get() != nullptr; }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); } TEST_F(CredentialsTest, CaptureTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { sp outBuffer; return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, false, ui::ROTATION_0, &outBuffer); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } TEST_F(CredentialsTest, CaptureLayersTest) { setupBackgroundSurface(); sp outBuffer; std::function condition = [=]() { sp outBuffer; return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(0, 0, 1, 1), FRAME_SCALE, &outBuffer); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } /** * The following tests are for methods accessible directly through SurfaceFlinger. */ /** * An app can pass a buffer queue to the media server and ask the media server to decode a DRM video * to that buffer queue. The media server is the buffer producer in this case. Because the app may create * its own buffer queue and act as the buffer consumer, the media server wants to be careful to avoid * sending decoded video frames to the app. This is where authenticateSurfaceTexture call comes in, to check * the consumer of a buffer queue is SurfaceFlinger. */ TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) { setupBackgroundSurface(); sp producer = mBGSurfaceControl->getSurface()->getIGraphicBufferProducer(); sp sf(ComposerService::getComposerService()); std::function condition = [=]() { return sf->authenticateSurfaceTexture(producer); }; // Anyone should be able to check if the consumer of the buffer queue is SF. ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); } TEST_F(CredentialsTest, GetLayerDebugInfo) { setupBackgroundSurface(); sp sf(ComposerService::getComposerService()); // Historically, only root and shell can access the getLayerDebugInfo which // is called when we call dumpsys. I don't see a reason why we should change this. std::vector outLayers; // Check with root. seteuid(AID_ROOT); ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); // Check as a shell. seteuid(AID_SHELL); ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); // Check as anyone else. seteuid(AID_ROOT); seteuid(AID_BIN); ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers)); } TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_FALSE(display == nullptr); bool result = false; status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result); ASSERT_EQ(NO_ERROR, error); bool hasWideColorMode = false; Vector colorModes; SurfaceComposerClient::getDisplayColorModes(display, &colorModes); for (ColorMode colorMode : colorModes) { switch (colorMode) { case ColorMode::DISPLAY_P3: case ColorMode::ADOBE_RGB: case ColorMode::DCI_P3: hasWideColorMode = true; break; default: break; } } ASSERT_EQ(hasWideColorMode, result); } TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_FALSE(display == nullptr); std::function condition = [=]() { bool result = false; return SurfaceComposerClient::isWideColorDisplay(display, &result); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_FALSE(display == nullptr); ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(display); ASSERT_NE(static_cast(BAD_VALUE), colorMode); } } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion"