blob: e43ee5fcf5f3ad8f2d81428613a22ae85dcf0075 [file] [log] [blame]
/*
* 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 "../Utils.h"
#include <sys/prctl.h>
#include <thread>
using namespace android;
const String16 kServerName = String16("binderClearBuf");
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();
}
*outBuffer = android::HexString(lastReply, lastReplySize);
return result;
}
};
TEST(BinderClearBuf, ClearKernelBuffer) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
sp<IBinder> binder = defaultServiceManager()->getService(kServerName);
#pragma clang diagnostic pop
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();
}