summaryrefslogtreecommitdiff
path: root/libs/gui
diff options
context:
space:
mode:
author Jim Shargo <jshargo@google.com> 2024-08-15 16:54:39 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-08-15 16:54:39 +0000
commit93555841df70bd9ee2d5fae79d98c8d4bd6918e0 (patch)
tree64ac3e9d6c6bb51b3c7c09a0cdcb2a83b3664b2d /libs/gui
parentcb0f460a55de131d12c14199a0e3cf1ada8ce7e4 (diff)
parent550dbaa588e02bfb2f356a73967e0615471a787a (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.h2
-rw-r--r--libs/gui/include/gui/IGraphicBufferProducer.h2
-rw-r--r--libs/gui/include/gui/Surface.h15
-rw-r--r--libs/gui/include/gui/view/Surface.h3
-rw-r--r--libs/gui/tests/Android.bp51
-rw-r--r--libs/gui/tests/LibGuiMain.cpp38
-rw-r--r--libs/gui/tests/Surface_test.cpp11
-rw-r--r--libs/gui/tests/TestServer_test.cpp99
-rw-r--r--libs/gui/tests/testserver/TestServer.cpp114
-rw-r--r--libs/gui/tests/testserver/TestServer.h31
-rw-r--r--libs/gui/tests/testserver/TestServerClient.cpp199
-rw-r--r--libs/gui/tests/testserver/TestServerClient.h42
-rw-r--r--libs/gui/tests/testserver/TestServerCommon.h43
-rw-r--r--libs/gui/tests/testserver/TestServerHost.cpp95
-rw-r--r--libs/gui/tests/testserver/TestServerHost.h38
-rw-r--r--libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl12
-rw-r--r--libs/gui/view/Surface.cpp6
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