diff options
| author | 2021-01-12 17:45:09 +0000 | |
|---|---|---|
| committer | 2021-01-12 17:45:09 +0000 | |
| commit | c3aa2ad4150aaa773c698aa3bfeeedd5c11dcd6f (patch) | |
| tree | 4d0350eac40f0aca968da2826064cbcfc870f133 /libs | |
| parent | 38effc4ffd41ebd939ec290cba98fd3b4b34e963 (diff) | |
| parent | f23dae2d0a098dc67211a320713bd3ddb86a4cba (diff) | |
Merge "Check FLAG_CLEAR_BUF behavior."
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/binder/TEST_MAPPING | 3 | ||||
| -rw-r--r-- | libs/binder/tests/Android.bp | 18 | ||||
| -rw-r--r-- | libs/binder/tests/binderClearBufTest.cpp | 131 |
3 files changed, 152 insertions, 0 deletions
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 97e282e783..00a14f408d 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -10,6 +10,9 @@ "name": "binderAllocationLimits" }, { + "name": "binderClearBufTest" + }, + { "name": "binderDriverInterfaceTest" }, { diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 87f1d45350..988f7f3c6d 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -157,6 +157,24 @@ cc_test { require_root: true, } +cc_test { + name: "binderClearBufTest", + defaults: ["binder_test_defaults"], + srcs: [ + "binderClearBufTest.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder", + "liblog", + "libutils", + ], + + test_suites: ["general-tests"], + require_root: true, +} + aidl_interface { name: "binderStabilityTestIface", unstable: true, diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp new file mode 100644 index 0000000000..a565e72091 --- /dev/null +++ b/libs/binder/tests/binderClearBufTest.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2020 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 <android-base/logging.h> +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/Stability.h> +#include <gtest/gtest.h> + +#include <sys/prctl.h> +#include <thread> + +using namespace android; + +const String16 kServerName = String16("binderClearBuf"); + +std::string hexString(const void* bytes, size_t len) { + if (bytes == nullptr) return "<null>"; + + const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes); + char chars[] = "0123456789abcdef"; + std::string result; + result.resize(len * 2); + + for (size_t i = 0; i < len; i++) { + result[2 * i] = chars[bytes8[i] >> 4]; + result[2 * i + 1] = chars[bytes8[i] & 0xf]; + } + + return result; +} + +class FooBar : public BBinder { + public: + enum { + TRANSACTION_REPEAT_STRING = IBinder::FIRST_CALL_TRANSACTION, + }; + + std::mutex foo; + std::string last; + + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + // not checking data, since there is no hook at the time this test is + // written to check values there are set to zero. Instead, we only check + // the reply parcel. + + switch (code) { + case TRANSACTION_REPEAT_STRING: { + const char* str = data.readCString(); + return reply->writeCString(str == nullptr ? "<null>" : str); + } + } + return BBinder::onTransact(code, data, reply, flags); + } + static std::string RepeatString(const sp<IBinder> binder, + const std::string& repeat, + std::string* outBuffer) { + Parcel data; + data.writeCString(repeat.c_str()); + std::string result; + const uint8_t* lastReply; + size_t lastReplySize; + { + Parcel reply; + binder->transact(TRANSACTION_REPEAT_STRING, data, &reply, FLAG_CLEAR_BUF); + result = reply.readCString(); + lastReply = reply.data(); + lastReplySize = reply.dataSize(); + } + IPCThreadState::self()->flushCommands(); + *outBuffer = hexString(lastReply, lastReplySize); + return result; + } +}; + +TEST(BinderClearBuf, ClearKernelBuffer) { + sp<IBinder> binder = defaultServiceManager()->getService(kServerName); + ASSERT_NE(nullptr, binder); + + std::string replyBuffer; + std::string result = FooBar::RepeatString(binder, "foo", &replyBuffer); + EXPECT_EQ("foo", result); + + // the buffer must have at least some length for the string, but we will + // just check it has some length, to avoid assuming anything about the + // format + EXPECT_GT(replyBuffer.size(), 0); + + for (size_t i = 0; i < replyBuffer.size(); i++) { + EXPECT_EQ(replyBuffer[i], '0') << "reply buffer at " << i; + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + + sp<IBinder> server = new FooBar; + android::defaultServiceManager()->addService(kServerName, server); + + IPCThreadState::self()->joinThreadPool(true); + exit(1); // should not reach + } + + // This is not racey. Just giving these services some time to register before we call + // getService which sleeps for much longer. One alternative would be to + // start a threadpool + use waitForService, but we want to have as few + // binder things going on in this test as possible, since we are checking + // memory is zero'd which the kernel has a right to change. + usleep(100000); + + return RUN_ALL_TESTS(); +} |