libgui: Add a test server utility for unit tests.

This is being added to make it possible to test linkToDeath callbacks,
but may serve to be generally useful.

This is a complicated little thing. But it has to be this way.

Most of the complication comes from the fact that we want ephemeral
Binder services that we can kill at will on a per-test basis. Binder
doesn't let you do any binder stuff after you've forked, however, so we
needed an intermediary, non-binder process to kick off the binder
processes that actually run the test server.

The way this works is:

- libgui_test defaults to being a normal test, and intializes a
  `TestServerHost` via fork/exec of the libgui_test binary
- The first fork runs TestServerHostMain and waits on a pipe for
  commands to create servers, at which point it will fork/exec
- Each forked server creates a new ITestService service, which the
  original test connects to.

BYPASS_IGBP_IGBC_API_REASON=warren buffers

Bug: 340933794
Flag: EXEMPT test
Test: test library
Change-Id: I37ee51b13a895a8b3387b7f2db92e5069158ff46
diff --git a/libs/gui/tests/testserver/TestServer.cpp b/libs/gui/tests/testserver/TestServer.cpp
new file mode 100644
index 0000000..cd8824e
--- /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 0000000..4226f1b
--- /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 0000000..e388074
--- /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 0000000..5329634
--- /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 0000000..7370f20
--- /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 0000000..696c3b9
--- /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 0000000..df22c0c
--- /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 0000000..c939ea0
--- /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();
+}