diff options
| author | 2024-08-15 16:54:39 +0000 | |
|---|---|---|
| committer | 2024-08-15 16:54:39 +0000 | |
| commit | 93555841df70bd9ee2d5fae79d98c8d4bd6918e0 (patch) | |
| tree | 64ac3e9d6c6bb51b3c7c09a0cdcb2a83b3664b2d /libs/gui | |
| parent | cb0f460a55de131d12c14199a0e3cf1ada8ce7e4 (diff) | |
| parent | 550dbaa588e02bfb2f356a73967e0615471a787a (diff) | |
Merge changes I37ee51b1,I86ea29a8,I2a43d22d,I832d274b into main
* changes:
libgui: Add a test server utility for unit tests.
view::Surface: Add toString()
libui/libui: Remove extraneous semicolons
libgui: Expose methods to Surface API to support Camera3StreamSplitter
Diffstat (limited to 'libs/gui')
| -rw-r--r-- | libs/gui/include/gui/FrameTimestamps.h | 2 | ||||
| -rw-r--r-- | libs/gui/include/gui/IGraphicBufferProducer.h | 2 | ||||
| -rw-r--r-- | libs/gui/include/gui/Surface.h | 15 | ||||
| -rw-r--r-- | libs/gui/include/gui/view/Surface.h | 3 | ||||
| -rw-r--r-- | libs/gui/tests/Android.bp | 51 | ||||
| -rw-r--r-- | libs/gui/tests/LibGuiMain.cpp | 38 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp | 11 | ||||
| -rw-r--r-- | libs/gui/tests/TestServer_test.cpp | 99 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/TestServer.cpp | 114 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/TestServer.h | 31 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/TestServerClient.cpp | 199 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/TestServerClient.h | 42 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/TestServerCommon.h | 43 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/TestServerHost.cpp | 95 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/TestServerHost.h | 38 | ||||
| -rw-r--r-- | libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl | 12 | ||||
| -rw-r--r-- | libs/gui/view/Surface.cpp | 6 |
17 files changed, 783 insertions, 18 deletions
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index 3d1be4d2eb..462081bfd2 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -116,7 +116,7 @@ public: // Public for testing. static nsecs_t snapToNextTick( nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval); - nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; }; + nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; } nsecs_t getNextCompositeDeadline(const nsecs_t now) const; nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; } diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 8fca9460aa..3aac457a09 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -867,6 +867,6 @@ class BnGraphicBufferProducer : public IGraphicBufferProducer { #endif // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif // ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 39207f835f..0f51f2dc13 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -194,6 +194,14 @@ public: * in <system/window.h>. */ int setScalingMode(int mode); + virtual int setBuffersTimestamp(int64_t timestamp); + virtual int setBuffersDataSpace(ui::Dataspace dataSpace); + virtual int setCrop(Rect const* rect); + virtual int setBuffersTransform(uint32_t transform); + virtual int setBuffersStickyTransform(uint32_t transform); + virtual int setBuffersFormat(PixelFormat format); + virtual int setUsage(uint64_t reqUsage); + // See IGraphicBufferProducer::setDequeueTimeout status_t setDequeueTimeout(nsecs_t timeout); @@ -354,16 +362,9 @@ protected: virtual int connect(int api); virtual int setBufferCount(int bufferCount); virtual int setBuffersUserDimensions(uint32_t width, uint32_t height); - virtual int setBuffersFormat(PixelFormat format); - virtual int setBuffersTransform(uint32_t transform); - virtual int setBuffersStickyTransform(uint32_t transform); - virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setBuffersDataSpace(ui::Dataspace dataSpace); virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata); virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata); virtual int setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata); - virtual int setCrop(Rect const* rect); - virtual int setUsage(uint64_t reqUsage); virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); public: diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h index b7aba2b9dc..7ddac8139a 100644 --- a/libs/gui/include/gui/view/Surface.h +++ b/libs/gui/include/gui/view/Surface.h @@ -59,8 +59,9 @@ class Surface : public Parcelable { // of the full parceling to happen on its native side. status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead); - private: + std::string toString() const; +private: static String16 readMaybeEmptyString16(const Parcel* parcel); }; diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 1b216e9063..f07747f32f 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -12,6 +12,34 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +aidl_interface { + name: "libgui_test_server_aidl", + unstable: true, + srcs: ["testserver/aidl/**/*.aidl"], + local_include_dir: "testserver/aidl", + include_dirs: [ + "frameworks/native/aidl/gui", + ], + backend: { + cpp: { + enabled: true, + additional_shared_libraries: [ + "libgui", + "libui", + ], + }, + java: { + enabled: false, + }, + ndk: { + enabled: false, + }, + rust: { + enabled: false, + }, + }, +} + cc_test { name: "libgui_test", test_suites: ["device-tests"], @@ -30,7 +58,6 @@ cc_test { ], srcs: [ - "LibGuiMain.cpp", // Custom gtest entrypoint "BLASTBufferQueue_test.cpp", "BufferItemConsumer_test.cpp", "BufferQueue_test.cpp", @@ -38,24 +65,29 @@ cc_test { "Choreographer_test.cpp", "CompositorTiming_test.cpp", "CpuConsumer_test.cpp", - "EndToEndNativeInputTest.cpp", - "FrameRateUtilsTest.cpp", - "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", + "DisplayInfo_test.cpp", + "EndToEndNativeInputTest.cpp", "FillBuffer.cpp", + "FrameRateUtilsTest.cpp", "GLTest.cpp", "IGraphicBufferProducer_test.cpp", + "LibGuiMain.cpp", // Custom gtest entrypoint "Malicious.cpp", "MultiTextureConsumer_test.cpp", "RegionSampling_test.cpp", "StreamSplitter_test.cpp", + "Surface_test.cpp", "SurfaceTextureClient_test.cpp", "SurfaceTextureFBO_test.cpp", + "SurfaceTextureGL_test.cpp", "SurfaceTextureGLThreadToGL_test.cpp", "SurfaceTextureGLToGL_test.cpp", - "SurfaceTextureGL_test.cpp", "SurfaceTextureMultiContextGL_test.cpp", - "Surface_test.cpp", + "TestServer_test.cpp", + "testserver/TestServer.cpp", + "testserver/TestServerClient.cpp", + "testserver/TestServerHost.cpp", "TextureRenderer.cpp", "VsyncEventData_test.cpp", "WindowInfo_test.cpp", @@ -66,10 +98,17 @@ cc_test { "android.hardware.configstore-utils", "libSurfaceFlingerProp", "libGLESv1_CM", + "libgui_test_server_aidl-cpp", "libinput", "libnativedisplay", ], + // This needs to get copied over for the test since it's not part of the + // platform. + data_libs: [ + "libgui_test_server_aidl-cpp", + ], + static_libs: [ "libgmock", ], diff --git a/libs/gui/tests/LibGuiMain.cpp b/libs/gui/tests/LibGuiMain.cpp index 10f7207588..7c7c2cc30f 100644 --- a/libs/gui/tests/LibGuiMain.cpp +++ b/libs/gui/tests/LibGuiMain.cpp @@ -14,8 +14,15 @@ * limitations under the License. */ -#include "gtest/gtest.h" -#include "log/log.h" +#include <android-base/unique_fd.h> +#include <gtest/gtest.h> +#include <log/log.h> + +#include "testserver/TestServer.h" +#include "testserver/TestServerClient.h" +#include "testserver/TestServerHost.h" + +using namespace android; namespace { @@ -32,7 +39,34 @@ class TestCaseLogger : public ::testing::EmptyTestEventListener { } // namespace int main(int argc, char** argv) { + // There are three modes that we can run in to support the libgui TestServer: + // + // - libgui_test : normal mode, runs tests and fork/execs the testserver host process + // - libgui_test --test-server-host $recvPipeFd $sendPipeFd : TestServerHost mode, listens on + // $recvPipeFd for commands and sends responses over $sendPipeFd + // - libgui_test --test-server $name : TestServer mode, starts a ITestService binder service + // under $name + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + if (arg == "--test-server-host") { + LOG_ALWAYS_FATAL_IF(argc < (i + 2), "--test-server-host requires two pipe fds"); + // Note that the send/recv are from our perspective. + base::unique_fd recvPipeFd = base::unique_fd(atoi(argv[i + 1])); + base::unique_fd sendPipeFd = base::unique_fd(atoi(argv[i + 2])); + return TestServerHostMain(argv[0], std::move(sendPipeFd), std::move(recvPipeFd)); + } + if (arg == "--test-server") { + LOG_ALWAYS_FATAL_IF(argc < (i + 1), "--test-server requires a name"); + return TestServerMain(argv[i + 1]); + } + } testing::InitGoogleTest(&argc, argv); testing::UnitTest::GetInstance()->listeners().Append(new TestCaseLogger()); + + // This has to be run *before* any test initialization, because it fork/execs a TestServerHost, + // which will later create new binder service. You can't do that in a forked thread after you've + // initialized any binder stuff, which some tests do. + TestServerClient::InitializeOrDie(argv[0]); + return RUN_ALL_TESTS(); }
\ No newline at end of file diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 8ab8783c4c..4232443308 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "gui/view/Surface.h" #include "Constants.h" #include "MockConsumer.h" @@ -53,6 +54,8 @@ #include <limits> #include <thread> +#include "testserver/TestServerClient.h" + namespace android { using namespace std::chrono_literals; @@ -2363,6 +2366,14 @@ TEST_F(SurfaceTest, QueueAcquireReleaseDequeue_CalledInStack_DoesNotDeadlock) { EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU)); } + +TEST_F(SurfaceTest, ViewSurface_toString) { + view::Surface surface{}; + EXPECT_EQ("", surface.toString()); + + surface.name = String16("name"); + EXPECT_EQ("name", surface.toString()); +} #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) } // namespace android diff --git a/libs/gui/tests/TestServer_test.cpp b/libs/gui/tests/TestServer_test.cpp new file mode 100644 index 0000000000..8712988e52 --- /dev/null +++ b/libs/gui/tests/TestServer_test.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> + +#include <SurfaceFlingerProperties.h> +#include <android/gui/IDisplayEventConnection.h> +#include <android/gui/ISurfaceComposer.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <android/hardware_buffer.h> +#include <binder/ProcessState.h> +#include <com_android_graphics_libgui_flags.h> +#include <configstore/Utils.h> +#include <gui/AidlStatusUtil.h> +#include <gui/BufferItemConsumer.h> +#include <gui/BufferQueue.h> +#include <gui/CpuConsumer.h> +#include <gui/IConsumerListener.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/ISurfaceComposer.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/SyncScreenCaptureListener.h> +#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> +#include <sys/types.h> +#include <system/window.h> +#include <ui/BufferQueueDefs.h> +#include <ui/DisplayMode.h> +#include <ui/GraphicBuffer.h> +#include <ui/Rect.h> +#include <utils/Errors.h> +#include <utils/String8.h> + +#include <cstddef> +#include <limits> +#include <thread> + +#include "binder/IInterface.h" +#include "testserver/TestServerClient.h" + +namespace android { + +namespace { + +class TestServerTest : public ::testing::Test { +protected: + TestServerTest() { ProcessState::self()->startThreadPool(); } +}; + +} // namespace + +TEST_F(TestServerTest, Create) { + EXPECT_NE(nullptr, TestServerClient::Create()); +} + +TEST_F(TestServerTest, CreateProducer) { + sp<TestServerClient> client = TestServerClient::Create(); + EXPECT_NE(nullptr, client->CreateProducer()); +} + +TEST_F(TestServerTest, KillServer) { + class DeathWaiter : public IBinder::DeathRecipient { + public: + virtual void binderDied(const wp<IBinder>&) override { mPromise.set_value(true); } + std::future<bool> getFuture() { return mPromise.get_future(); } + + std::promise<bool> mPromise; + }; + + sp<TestServerClient> client = TestServerClient::Create(); + sp<IGraphicBufferProducer> producer = client->CreateProducer(); + EXPECT_NE(nullptr, producer); + + sp<DeathWaiter> deathWaiter = sp<DeathWaiter>::make(); + EXPECT_EQ(OK, IInterface::asBinder(producer)->linkToDeath(deathWaiter)); + + auto deathWaiterFuture = deathWaiter->getFuture(); + EXPECT_EQ(OK, client->Kill()); + EXPECT_EQ(nullptr, client->CreateProducer()); + + EXPECT_TRUE(deathWaiterFuture.get()); +} + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServer.cpp b/libs/gui/tests/testserver/TestServer.cpp new file mode 100644 index 0000000000..cd8824e355 --- /dev/null +++ b/libs/gui/tests/testserver/TestServer.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "TestServer" + +#include <android-base/stringprintf.h> +#include <binder/IInterface.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <binder/Status.h> +#include <gui/BufferQueue.h> +#include <gui/IConsumerListener.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/view/Surface.h> +#include <libgui_test_server/BnTestServer.h> +#include <log/log.h> +#include <utils/Errors.h> + +#include <cstdint> +#include <cstdlib> +#include <memory> +#include <mutex> +#include <vector> + +#include <fcntl.h> +#include <unistd.h> + +#include "TestServer.h" + +namespace android { + +namespace { +class TestConsumerListener : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem&) override {} + virtual void onBuffersReleased() override {} + virtual void onSidebandStreamChanged() override {} +}; + +class TestServiceImpl : public libgui_test_server::BnTestServer { +public: + TestServiceImpl(const char* name) : mName(name) {} + + virtual binder::Status createProducer(view::Surface* out) override { + std::lock_guard<std::mutex> lock(mMutex); + + BufferQueueHolder bq; + BufferQueue::createBufferQueue(&bq.producer, &bq.consumer); + sp<TestConsumerListener> listener = sp<TestConsumerListener>::make(); + bq.consumer->consumerConnect(listener, /*controlledByApp*/ true); + + uint64_t id = 0; + bq.producer->getUniqueId(&id); + std::string name = base::StringPrintf("%s-%" PRIu64, mName, id); + + out->name = String16(name.c_str()); + out->graphicBufferProducer = bq.producer; + mBqs.push_back(std::move(bq)); + + return binder::Status::ok(); + } + + virtual binder::Status killNow() override { + ALOGE("LibGUI Test Service %s dying in response to killNow", mName); + _exit(0); + // Not reached: + return binder::Status::ok(); + } + +private: + std::mutex mMutex; + const char* mName; + + struct BufferQueueHolder { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + }; + + std::vector<BufferQueueHolder> mBqs; +}; +} // namespace + +int TestServerMain(const char* name) { + ProcessState::self()->startThreadPool(); + + sp<TestServiceImpl> testService = sp<TestServiceImpl>::make(name); + ALOGE("service"); + sp<IServiceManager> serviceManager(defaultServiceManager()); + LOG_ALWAYS_FATAL_IF(OK != serviceManager->addService(String16(name), testService)); + + ALOGD("LibGUI Test Service %s STARTED", name); + + IPCThreadState::self()->joinThreadPool(); + + ALOGW("LibGUI Test Service %s DIED", name); + + return 0; +} + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServer.h b/libs/gui/tests/testserver/TestServer.h new file mode 100644 index 0000000000..4226f1bb09 --- /dev/null +++ b/libs/gui/tests/testserver/TestServer.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace android { + +/* + * Main method for a libgui ITestServer server. + * + * This must be called without any binder setup having been done, because you can't fork and do + * binder things once ProcessState is set up. + * @param name The service name of the test server to start. + * @return retcode + */ +int TestServerMain(const char* name); + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerClient.cpp b/libs/gui/tests/testserver/TestServerClient.cpp new file mode 100644 index 0000000000..e388074675 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerClient.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/wait.h> +#include <cerrno> +#define LOG_TAG "TestServerClient" + +#include <android-base/stringprintf.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <libgui_test_server/ITestServer.h> +#include <log/log.h> +#include <utils/Errors.h> + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <unistd.h> + +#include <atomic> +#include <csignal> +#include <cstdlib> +#include <mutex> +#include <string> + +#include "TestServerClient.h" +#include "TestServerCommon.h" + +namespace android { + +namespace { + +std::string GetUniqueServiceName() { + static std::atomic<int> uniqueId = 1; + + pid_t pid = getpid(); + int id = uniqueId++; + return base::StringPrintf("Libgui-TestServer-%d-%d", pid, id); +} + +struct RemoteTestServerHostHolder { + RemoteTestServerHostHolder(pid_t pid, int sendFd, int recvFd) + : mPid(pid), mSendFd(sendFd), mRecvFd(recvFd) {} + ~RemoteTestServerHostHolder() { + std::lock_guard lock(mMutex); + + kill(mPid, SIGKILL); + close(mSendFd); + close(mRecvFd); + } + + pid_t CreateTestServerOrDie(std::string name) { + std::lock_guard lock(mMutex); + + CreateServerRequest request; + strlcpy(request.name, name.c_str(), sizeof(request.name) / sizeof(request.name[0])); + + ssize_t bytes = write(mSendFd, &request, sizeof(request)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(request)); + + CreateServerResponse response; + bytes = read(mRecvFd, &response, sizeof(response)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(response)); + + return response.pid; + } + +private: + std::mutex mMutex; + + pid_t mPid; + int mSendFd; + int mRecvFd; +}; + +std::unique_ptr<RemoteTestServerHostHolder> g_remoteTestServerHostHolder = nullptr; + +} // namespace + +void TestServerClient::InitializeOrDie(const char* filename) { + int sendPipeFds[2]; + int ret = pipe(sendPipeFds); + LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess send pipe"); + + int recvPipeFds[2]; + ret = pipe(recvPipeFds); + LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess recv pipe"); + + pid_t childPid = fork(); + LOG_ALWAYS_FATAL_IF(childPid < 0, "Unable to fork child process"); + + if (childPid == 0) { + // We forked! + close(sendPipeFds[1]); + close(recvPipeFds[0]); + + // We'll be reading from the parent's "send" and writing to the parent's "recv". + std::string sendPipe = std::to_string(sendPipeFds[0]); + std::string recvPipe = std::to_string(recvPipeFds[1]); + char* args[] = { + const_cast<char*>(filename), + const_cast<char*>("--test-server-host"), + const_cast<char*>(sendPipe.c_str()), + const_cast<char*>(recvPipe.c_str()), + nullptr, + }; + + ret = execv(filename, args); + ALOGE("Failed to exec libguiTestServer. ret=%d errno=%d (%s)", ret, errno, strerror(errno)); + status_t status = -errno; + write(recvPipeFds[1], &status, sizeof(status)); + _exit(EXIT_FAILURE); + } + + close(sendPipeFds[0]); + close(recvPipeFds[1]); + + // Check for an OK status that the host started. If so, we're good to go. + status_t status; + ret = read(recvPipeFds[0], &status, sizeof(status)); + LOG_ALWAYS_FATAL_IF(ret != sizeof(status), "Unable to read from pipe: %d", ret); + LOG_ALWAYS_FATAL_IF(OK != status, "Pipe returned failed status: %d", status); + + g_remoteTestServerHostHolder = + std::make_unique<RemoteTestServerHostHolder>(childPid, sendPipeFds[1], recvPipeFds[0]); +} + +sp<TestServerClient> TestServerClient::Create() { + std::string serviceName = GetUniqueServiceName(); + + pid_t childPid = g_remoteTestServerHostHolder->CreateTestServerOrDie(serviceName); + ALOGD("Created child server %s with pid %d", serviceName.c_str(), childPid); + + sp<libgui_test_server::ITestServer> server = + waitForService<libgui_test_server::ITestServer>(String16(serviceName.c_str())); + LOG_ALWAYS_FATAL_IF(server == nullptr); + ALOGD("Created connected to child server %s", serviceName.c_str()); + + return sp<TestServerClient>::make(server); +} + +TestServerClient::TestServerClient(const sp<libgui_test_server::ITestServer>& server) + : mServer(server) {} + +TestServerClient::~TestServerClient() { + Kill(); +} + +sp<IGraphicBufferProducer> TestServerClient::CreateProducer() { + std::lock_guard<std::mutex> lock(mMutex); + + if (!mIsAlive) { + return nullptr; + } + + view::Surface surface; + binder::Status status = mServer->createProducer(&surface); + + if (!status.isOk()) { + ALOGE("Failed to create remote producer. Error: %s", status.exceptionMessage().c_str()); + return nullptr; + } + + if (!surface.graphicBufferProducer) { + ALOGE("Remote producer returned no IGBP."); + return nullptr; + } + + return surface.graphicBufferProducer; +} + +status_t TestServerClient::Kill() { + std::lock_guard<std::mutex> lock(mMutex); + if (!mIsAlive) { + return DEAD_OBJECT; + } + + mServer->killNow(); + mServer = nullptr; + mIsAlive = false; + + return OK; +} + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerClient.h b/libs/gui/tests/testserver/TestServerClient.h new file mode 100644 index 0000000000..53296344a3 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerClient.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <libgui_test_server/ITestServer.h> +#include <utils/RefBase.h> + +namespace android { + +class TestServerClient : public RefBase { +public: + static void InitializeOrDie(const char* filename); + static sp<TestServerClient> Create(); + + TestServerClient(const sp<libgui_test_server::ITestServer>& server); + virtual ~TestServerClient() override; + + sp<IGraphicBufferProducer> CreateProducer(); + status_t Kill(); + +private: + std::mutex mMutex; + + sp<libgui_test_server::ITestServer> mServer; + bool mIsAlive = true; +}; + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerCommon.h b/libs/gui/tests/testserver/TestServerCommon.h new file mode 100644 index 0000000000..7370f20ef8 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerCommon.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <fcntl.h> + +namespace android { + +/* + * Test -> TestServerHost Request to create a new ITestServer fork. + */ +struct CreateServerRequest { + /* + * Service name for new ITestServer. + */ + char name[128]; +}; + +/* + * TestServerHost -> Test Response for creating an ITestServer fork. + */ +struct CreateServerResponse { + /* + * pid of new ITestServer. + */ + pid_t pid; +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServerHost.cpp b/libs/gui/tests/testserver/TestServerHost.cpp new file mode 100644 index 0000000000..696c3b9817 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerHost.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "TestServerHost" + +#include <android-base/unique_fd.h> +#include <binder/IInterface.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <binder/Status.h> +#include <gui/BufferQueue.h> +#include <gui/IConsumerListener.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <libgui_test_server/BnTestServer.h> +#include <log/log.h> +#include <utils/Errors.h> + +#include <memory> +#include <vector> + +#include <fcntl.h> +#include <unistd.h> +#include <cstddef> +#include <cstdlib> + +#include "TestServerCommon.h" +#include "TestServerHost.h" + +namespace android { + +namespace { + +pid_t ForkTestServer(const char* filename, char* name) { + pid_t childPid = fork(); + LOG_ALWAYS_FATAL_IF(childPid == -1); + + if (childPid != 0) { + return childPid; + } + + // We forked! + const char* test_server_flag = "--test-server"; + char* args[] = { + const_cast<char*>(filename), + const_cast<char*>(test_server_flag), + name, + nullptr, + }; + + int ret = execv(filename, args); + ALOGE("Failed to exec libgui_test as a TestServer. ret=%d errno=%d (%s)", ret, errno, + strerror(errno)); + _exit(EXIT_FAILURE); +} + +} // namespace + +int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd, + base::unique_fd recvPipeFd) { + status_t status = OK; + LOG_ALWAYS_FATAL_IF(sizeof(status) != write(sendPipeFd.get(), &status, sizeof(status))); + + ALOGE("Launched TestServerHost"); + + while (true) { + CreateServerRequest request = {}; + ssize_t bytes = read(recvPipeFd.get(), &request, sizeof(request)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(request)); + pid_t childPid = ForkTestServer(filename, request.name); + + CreateServerResponse response = {}; + response.pid = childPid; + bytes = write(sendPipeFd.get(), &response, sizeof(response)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(response)); + } + + return 0; +} + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServerHost.h b/libs/gui/tests/testserver/TestServerHost.h new file mode 100644 index 0000000000..df22c0c3fe --- /dev/null +++ b/libs/gui/tests/testserver/TestServerHost.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android-base/unique_fd.h> + +#include <string> + +namespace android { + +/* + * Main method for a host process for TestServers. + * + * This must be called without any binder setup having been done, because you can't fork and do + * binder things once ProcessState is set up. + * @param filename File name of this binary / the binary to execve into + * @param sendPipeFd Pipe FD to send data to. + * @param recvPipeFd Pipe FD to receive data from. + * @return retcode + */ +int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd, + base::unique_fd recvPipeFd); + +} // namespace android diff --git a/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl new file mode 100644 index 0000000000..c939ea00c1 --- /dev/null +++ b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl @@ -0,0 +1,12 @@ +package libgui_test_server; + +import android.view.Surface; + +// Test server for libgui_test +interface ITestServer { + // Create a new producer. The server will have connected to the consumer. + Surface createProducer(); + + // Kills the server immediately. + void killNow(); +} diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index 7c15e7cf92..84c2a6ac71 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -121,5 +121,11 @@ String16 Surface::readMaybeEmptyString16(const Parcel* parcel) { return str.value_or(String16()); } +std::string Surface::toString() const { + std::stringstream out; + out << name; + return out.str(); +} + } // namespace view } // namespace android |