diff options
Diffstat (limited to 'libmemunreachable/tests/Binder_test.cpp')
-rw-r--r-- | libmemunreachable/tests/Binder_test.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/libmemunreachable/tests/Binder_test.cpp b/libmemunreachable/tests/Binder_test.cpp new file mode 100644 index 000000000..6e85d5ab3 --- /dev/null +++ b/libmemunreachable/tests/Binder_test.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 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 <signal.h> +#include <sys/types.h> +#include <unistd.h> + +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> + +#include <gtest/gtest.h> + +#include "Allocator.h" +#include "Binder.h" + +namespace android { + +static const String16 service_name("test.libmemunreachable_binder"); + +class BinderService : public BBinder { + public: + BinderService() = default; + virtual ~BinderService() = default; + + virtual status_t onTransact(uint32_t /*code*/, const Parcel& data, Parcel* reply, + uint32_t /*flags*/ = 0) { + reply->writeStrongBinder(ref); + ref = data.readStrongBinder(); + return 0; + } + + private: + sp<IBinder> ref; +}; + +class BinderObject : public BBinder { + public: + BinderObject() = default; + ~BinderObject() = default; +}; + +class ServiceProcess { + public: + ServiceProcess() : child_(0) {} + ~ServiceProcess() { Stop(); } + + bool Run() { + pid_t ret = fork(); + if (ret < 0) { + return false; + } else if (ret == 0) { + // child + _exit(Service()); + } else { + // parent + child_ = ret; + return true; + } + } + + bool Stop() { + if (child_ > 0) { + if (kill(child_, SIGTERM)) { + return false; + } + int status = 0; + if (TEMP_FAILURE_RETRY(waitpid(child_, &status, 0)) != child_) { + return false; + } + child_ = 0; + return WIFEXITED(status) && WEXITSTATUS(status) == 0; + } + + return true; + } + + int Service() { + sp<ProcessState> proc{ProcessState::self()}; + sp<IServiceManager> sm = defaultServiceManager(); + if (sm == nullptr) { + fprintf(stderr, "Failed to get service manager\n"); + return 1; + } + if (sm->addService(service_name, new BinderService()) != OK) { + fprintf(stderr, "Failed to add test service\n"); + return 1; + } + proc->startThreadPool(); + pause(); + return 0; + } + + private: + pid_t child_; +}; + +class BinderTest : public ::testing::Test { + protected: + ServiceProcess service_process_; +}; + +TEST_F(BinderTest, binder) { + ServiceProcess service_process; + ASSERT_TRUE(service_process.Run()); + + sp<IServiceManager> sm = defaultServiceManager(); + ASSERT_TRUE(sm != nullptr); + + // A small sleep allows the service to start, which + // prevents a longer sleep in getService. + usleep(100000); + + sp<IBinder> service = sm->getService(service_name); + ASSERT_TRUE(service != nullptr); + + sp<IBinder> binder{new BinderObject()}; + + Parcel send; + Parcel reply; + + send.writeStrongBinder(binder); + status_t rv = service->transact(0, send, &reply); + ASSERT_EQ(static_cast<status_t>(OK), rv); + + Heap heap; + allocator::vector<uintptr_t> refs{heap}; + + ASSERT_TRUE(BinderReferences(refs)); + + bool found_ref = false; + for (auto ref : refs) { + if (ref == reinterpret_cast<uintptr_t>(binder.get())) { + found_ref = true; + } + } + + ASSERT_TRUE(found_ref); +} + +} // namespace android |