You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
839 lines
34 KiB
839 lines
34 KiB
/*
|
|
* Copyright 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 <binder/SafeInterface.h>
|
|
|
|
#include <binder/IInterface.h>
|
|
#include <binder/IPCThreadState.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <binder/Parcel.h>
|
|
#include <binder/Parcelable.h>
|
|
#include <binder/ProcessState.h>
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Weverything"
|
|
#include <gtest/gtest.h>
|
|
#pragma clang diagnostic pop
|
|
|
|
#include <utils/LightRefBase.h>
|
|
#include <utils/NativeHandle.h>
|
|
|
|
#include <cutils/native_handle.h>
|
|
|
|
#include <optional>
|
|
|
|
#include <sys/eventfd.h>
|
|
#include <sys/prctl.h>
|
|
|
|
using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
|
|
|
|
namespace android {
|
|
namespace tests {
|
|
|
|
static const String16 kServiceName("SafeInterfaceTest");
|
|
|
|
enum class TestEnum : uint32_t {
|
|
INVALID = 0,
|
|
INITIAL = 1,
|
|
FINAL = 2,
|
|
};
|
|
|
|
// This class serves two purposes:
|
|
// 1) It ensures that the implementation doesn't require copying or moving the data (for
|
|
// efficiency purposes)
|
|
// 2) It tests that Parcelables can be passed correctly
|
|
class NoCopyNoMove : public Parcelable {
|
|
public:
|
|
NoCopyNoMove() = default;
|
|
explicit NoCopyNoMove(int32_t value) : mValue(value) {}
|
|
~NoCopyNoMove() override = default;
|
|
|
|
// Not copyable
|
|
NoCopyNoMove(const NoCopyNoMove&) = delete;
|
|
NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
|
|
|
|
// Not movable
|
|
NoCopyNoMove(NoCopyNoMove&&) = delete;
|
|
NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;
|
|
|
|
// Parcelable interface
|
|
status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
|
|
status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
|
|
|
|
int32_t getValue() const { return mValue; }
|
|
void setValue(int32_t value) { mValue = value; }
|
|
|
|
private:
|
|
int32_t mValue = 0;
|
|
__attribute__((unused)) uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded
|
|
};
|
|
|
|
struct TestFlattenable : Flattenable<TestFlattenable> {
|
|
TestFlattenable() = default;
|
|
explicit TestFlattenable(int32_t v) : value(v) {}
|
|
|
|
// Flattenable protocol
|
|
size_t getFlattenedSize() const { return sizeof(value); }
|
|
size_t getFdCount() const { return 0; }
|
|
status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
|
|
FlattenableUtils::write(buffer, size, value);
|
|
return NO_ERROR;
|
|
}
|
|
status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
|
|
FlattenableUtils::read(buffer, size, value);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int32_t value = 0;
|
|
};
|
|
|
|
struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> {
|
|
TestLightFlattenable() = default;
|
|
explicit TestLightFlattenable(int32_t v) : value(v) {}
|
|
int32_t value = 0;
|
|
};
|
|
|
|
// It seems like this should be able to inherit from TestFlattenable (to avoid duplicating code),
|
|
// but the SafeInterface logic can't easily be extended to find an indirect Flattenable<T>
|
|
// base class
|
|
class TestLightRefBaseFlattenable : public Flattenable<TestLightRefBaseFlattenable>,
|
|
public LightRefBase<TestLightRefBaseFlattenable> {
|
|
public:
|
|
TestLightRefBaseFlattenable() = default;
|
|
explicit TestLightRefBaseFlattenable(int32_t v) : value(v) {}
|
|
|
|
// Flattenable protocol
|
|
size_t getFlattenedSize() const { return sizeof(value); }
|
|
size_t getFdCount() const { return 0; }
|
|
status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
|
|
FlattenableUtils::write(buffer, size, value);
|
|
return NO_ERROR;
|
|
}
|
|
status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
|
|
FlattenableUtils::read(buffer, size, value);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
int32_t value = 0;
|
|
};
|
|
|
|
class TestParcelable : public Parcelable {
|
|
public:
|
|
TestParcelable() = default;
|
|
explicit TestParcelable(int32_t value) : mValue(value) {}
|
|
TestParcelable(const TestParcelable& other) : TestParcelable(other.mValue) {}
|
|
TestParcelable(TestParcelable&& other) : TestParcelable(other.mValue) {}
|
|
|
|
// Parcelable interface
|
|
status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
|
|
status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
|
|
|
|
int32_t getValue() const { return mValue; }
|
|
void setValue(int32_t value) { mValue = value; }
|
|
|
|
private:
|
|
int32_t mValue = 0;
|
|
};
|
|
|
|
class ExitOnDeath : public IBinder::DeathRecipient {
|
|
public:
|
|
~ExitOnDeath() override = default;
|
|
|
|
void binderDied(const wp<IBinder>& /*who*/) override {
|
|
ALOG(LOG_INFO, "ExitOnDeath", "Exiting");
|
|
exit(0);
|
|
}
|
|
};
|
|
|
|
// This callback class is used to test both one-way transactions and that sp<IInterface> can be
|
|
// passed correctly
|
|
class ICallback : public IInterface {
|
|
public:
|
|
DECLARE_META_INTERFACE(Callback)
|
|
|
|
enum class Tag : uint32_t {
|
|
OnCallback = IBinder::FIRST_CALL_TRANSACTION,
|
|
Last,
|
|
};
|
|
|
|
virtual void onCallback(int32_t aPlusOne) = 0;
|
|
};
|
|
|
|
class BpCallback : public SafeBpInterface<ICallback> {
|
|
public:
|
|
explicit BpCallback(const sp<IBinder>& impl) : SafeBpInterface<ICallback>(impl, getLogTag()) {}
|
|
|
|
void onCallback(int32_t aPlusOne) override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemoteAsync<decltype(&ICallback::onCallback)>(Tag::OnCallback, aPlusOne);
|
|
}
|
|
|
|
private:
|
|
static constexpr const char* getLogTag() { return "BpCallback"; }
|
|
};
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
|
IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback")
|
|
#pragma clang diagnostic pop
|
|
|
|
class BnCallback : public SafeBnInterface<ICallback> {
|
|
public:
|
|
BnCallback() : SafeBnInterface("BnCallback") {}
|
|
|
|
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
|
|
uint32_t /*flags*/) override {
|
|
EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
|
|
EXPECT_LT(code, static_cast<uint32_t>(ICallback::Tag::Last));
|
|
ICallback::Tag tag = static_cast<ICallback::Tag>(code);
|
|
switch (tag) {
|
|
case ICallback::Tag::OnCallback: {
|
|
return callLocalAsync(data, reply, &ICallback::onCallback);
|
|
}
|
|
case ICallback::Tag::Last:
|
|
// Should not be possible because of the asserts at the beginning of the method
|
|
[&]() { FAIL(); }();
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
};
|
|
|
|
class ISafeInterfaceTest : public IInterface {
|
|
public:
|
|
DECLARE_META_INTERFACE(SafeInterfaceTest)
|
|
|
|
enum class Tag : uint32_t {
|
|
SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
|
|
ReturnsNoMemory,
|
|
LogicalNot,
|
|
ModifyEnum,
|
|
IncrementFlattenable,
|
|
IncrementLightFlattenable,
|
|
IncrementLightRefBaseFlattenable,
|
|
IncrementNativeHandle,
|
|
IncrementNoCopyNoMove,
|
|
IncrementParcelableVector,
|
|
DoubleString,
|
|
CallMeBack,
|
|
IncrementInt32,
|
|
IncrementUint32,
|
|
IncrementInt64,
|
|
IncrementUint64,
|
|
IncrementFloat,
|
|
IncrementTwo,
|
|
Last,
|
|
};
|
|
|
|
// This is primarily so that the remote service dies when the test does, but it also serves to
|
|
// test the handling of sp<IBinder> and non-const methods
|
|
virtual status_t setDeathToken(const sp<IBinder>& token) = 0;
|
|
|
|
// This is the most basic test since it doesn't require parceling any arguments
|
|
virtual status_t returnsNoMemory() const = 0;
|
|
|
|
// These are ordered according to their corresponding methods in SafeInterface::ParcelHandler
|
|
virtual status_t logicalNot(bool a, bool* notA) const = 0;
|
|
virtual status_t modifyEnum(TestEnum a, TestEnum* b) const = 0;
|
|
virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0;
|
|
virtual status_t increment(const TestLightFlattenable& a,
|
|
TestLightFlattenable* aPlusOne) const = 0;
|
|
virtual status_t increment(const sp<TestLightRefBaseFlattenable>& a,
|
|
sp<TestLightRefBaseFlattenable>* aPlusOne) const = 0;
|
|
virtual status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const = 0;
|
|
virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
|
|
virtual status_t increment(const std::vector<TestParcelable>& a,
|
|
std::vector<TestParcelable>* aPlusOne) const = 0;
|
|
virtual status_t doubleString(const String8& str, String8* doubleStr) const = 0;
|
|
// As mentioned above, sp<IBinder> is already tested by setDeathToken
|
|
virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
|
|
virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
|
|
virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
|
|
virtual status_t increment(int64_t a, int64_t* aPlusOne) const = 0;
|
|
virtual status_t increment(uint64_t a, uint64_t* aPlusOne) const = 0;
|
|
virtual status_t increment(float a, float* aPlusOne) const = 0;
|
|
|
|
// This tests that input/output parameter interleaving works correctly
|
|
virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
|
|
int32_t* bPlusOne) const = 0;
|
|
};
|
|
|
|
class BpSafeInterfaceTest : public SafeBpInterface<ISafeInterfaceTest> {
|
|
public:
|
|
explicit BpSafeInterfaceTest(const sp<IBinder>& impl)
|
|
: SafeBpInterface<ISafeInterfaceTest>(impl, getLogTag()) {}
|
|
|
|
status_t setDeathToken(const sp<IBinder>& token) override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemote<decltype(&ISafeInterfaceTest::setDeathToken)>(Tag::SetDeathToken, token);
|
|
}
|
|
status_t returnsNoMemory() const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemote<decltype(&ISafeInterfaceTest::returnsNoMemory)>(Tag::ReturnsNoMemory);
|
|
}
|
|
status_t logicalNot(bool a, bool* notA) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA);
|
|
}
|
|
status_t modifyEnum(TestEnum a, TestEnum* b) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemote<decltype(&ISafeInterfaceTest::modifyEnum)>(Tag::ModifyEnum, a, b);
|
|
}
|
|
status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
|
|
using Signature =
|
|
status_t (ISafeInterfaceTest::*)(const TestFlattenable&, TestFlattenable*) const;
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemote<Signature>(Tag::IncrementFlattenable, a, aPlusOne);
|
|
}
|
|
status_t increment(const TestLightFlattenable& a,
|
|
TestLightFlattenable* aPlusOne) const override {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(const TestLightFlattenable&,
|
|
TestLightFlattenable*) const;
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
|
|
}
|
|
status_t increment(const sp<TestLightRefBaseFlattenable>& a,
|
|
sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
|
|
sp<TestLightRefBaseFlattenable>*) const;
|
|
return callRemote<Signature>(Tag::IncrementLightRefBaseFlattenable, a, aPlusOne);
|
|
}
|
|
status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature =
|
|
status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&, sp<NativeHandle>*) const;
|
|
return callRemote<Signature>(Tag::IncrementNativeHandle, a, aPlusOne);
|
|
}
|
|
status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
|
|
NoCopyNoMove* aPlusOne) const;
|
|
return callRemote<Signature>(Tag::IncrementNoCopyNoMove, a, aPlusOne);
|
|
}
|
|
status_t increment(const std::vector<TestParcelable>& a,
|
|
std::vector<TestParcelable>* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature = status_t (ISafeInterfaceTest::*)(const std::vector<TestParcelable>&,
|
|
std::vector<TestParcelable>*);
|
|
return callRemote<Signature>(Tag::IncrementParcelableVector, a, aPlusOne);
|
|
}
|
|
status_t doubleString(const String8& str, String8* doubleStr) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemote<decltype(&ISafeInterfaceTest::doubleString)>(Tag::DoubleString, str,
|
|
doubleStr);
|
|
}
|
|
void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return callRemoteAsync<decltype(&ISafeInterfaceTest::callMeBack)>(Tag::CallMeBack, callback,
|
|
a);
|
|
}
|
|
status_t increment(int32_t a, int32_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
|
|
return callRemote<Signature>(Tag::IncrementInt32, a, aPlusOne);
|
|
}
|
|
status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
|
|
return callRemote<Signature>(Tag::IncrementUint32, a, aPlusOne);
|
|
}
|
|
status_t increment(int64_t a, int64_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature = status_t (ISafeInterfaceTest::*)(int64_t, int64_t*) const;
|
|
return callRemote<Signature>(Tag::IncrementInt64, a, aPlusOne);
|
|
}
|
|
status_t increment(uint64_t a, uint64_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
|
|
return callRemote<Signature>(Tag::IncrementUint64, a, aPlusOne);
|
|
}
|
|
status_t increment(float a, float* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
|
|
return callRemote<Signature>(Tag::IncrementFloat, a, aPlusOne);
|
|
}
|
|
status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
using Signature =
|
|
status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t, int32_t*) const;
|
|
return callRemote<Signature>(Tag::IncrementTwo, a, aPlusOne, b, bPlusOne);
|
|
}
|
|
|
|
private:
|
|
static constexpr const char* getLogTag() { return "BpSafeInterfaceTest"; }
|
|
};
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
|
IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest")
|
|
|
|
static sp<IBinder::DeathRecipient> getDeathRecipient() {
|
|
static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath;
|
|
return recipient;
|
|
}
|
|
#pragma clang diagnostic pop
|
|
|
|
class BnSafeInterfaceTest : public SafeBnInterface<ISafeInterfaceTest> {
|
|
public:
|
|
BnSafeInterfaceTest() : SafeBnInterface(getLogTag()) {}
|
|
|
|
status_t setDeathToken(const sp<IBinder>& token) override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
token->linkToDeath(getDeathRecipient());
|
|
return NO_ERROR;
|
|
}
|
|
status_t returnsNoMemory() const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
return NO_MEMORY;
|
|
}
|
|
status_t logicalNot(bool a, bool* notA) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*notA = !a;
|
|
return NO_ERROR;
|
|
}
|
|
status_t modifyEnum(TestEnum a, TestEnum* b) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*b = (a == TestEnum::INITIAL) ? TestEnum::FINAL : TestEnum::INVALID;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
aPlusOne->value = a.value + 1;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(const TestLightFlattenable& a,
|
|
TestLightFlattenable* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
aPlusOne->value = a.value + 1;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(const sp<TestLightRefBaseFlattenable>& a,
|
|
sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*aPlusOne = new TestLightRefBaseFlattenable(a->value + 1);
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
native_handle* rawHandle = native_handle_create(1 /*numFds*/, 1 /*numInts*/);
|
|
if (rawHandle == nullptr) return NO_MEMORY;
|
|
|
|
// Copy the fd over directly
|
|
rawHandle->data[0] = dup(a->handle()->data[0]);
|
|
|
|
// Increment the int
|
|
rawHandle->data[1] = a->handle()->data[1] + 1;
|
|
|
|
// This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing
|
|
// the native_handle when it goes out of scope
|
|
*aPlusOne = NativeHandle::create(rawHandle, true);
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
aPlusOne->setValue(a.getValue() + 1);
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(const std::vector<TestParcelable>& a,
|
|
std::vector<TestParcelable>* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
aPlusOne->resize(a.size());
|
|
for (size_t i = 0; i < a.size(); ++i) {
|
|
(*aPlusOne)[i].setValue(a[i].getValue() + 1);
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
status_t doubleString(const String8& str, String8* doubleStr) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*doubleStr = str + str;
|
|
return NO_ERROR;
|
|
}
|
|
void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
callback->onCallback(a + 1);
|
|
}
|
|
status_t increment(int32_t a, int32_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*aPlusOne = a + 1;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*aPlusOne = a + 1;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(int64_t a, int64_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*aPlusOne = a + 1;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(uint64_t a, uint64_t* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*aPlusOne = a + 1;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(float a, float* aPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*aPlusOne = a + 1.0f;
|
|
return NO_ERROR;
|
|
}
|
|
status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
|
|
ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
|
|
*aPlusOne = a + 1;
|
|
*bPlusOne = b + 1;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// BnInterface
|
|
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
|
|
uint32_t /*flags*/) override {
|
|
EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
|
|
EXPECT_LT(code, static_cast<uint32_t>(Tag::Last));
|
|
ISafeInterfaceTest::Tag tag = static_cast<ISafeInterfaceTest::Tag>(code);
|
|
switch (tag) {
|
|
case ISafeInterfaceTest::Tag::SetDeathToken: {
|
|
return callLocal(data, reply, &ISafeInterfaceTest::setDeathToken);
|
|
}
|
|
case ISafeInterfaceTest::Tag::ReturnsNoMemory: {
|
|
return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory);
|
|
}
|
|
case ISafeInterfaceTest::Tag::LogicalNot: {
|
|
return callLocal(data, reply, &ISafeInterfaceTest::logicalNot);
|
|
}
|
|
case ISafeInterfaceTest::Tag::ModifyEnum: {
|
|
return callLocal(data, reply, &ISafeInterfaceTest::modifyEnum);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementFlattenable: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(const TestFlattenable& a,
|
|
TestFlattenable* aPlusOne) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementLightFlattenable: {
|
|
using Signature =
|
|
status_t (ISafeInterfaceTest::*)(const TestLightFlattenable& a,
|
|
TestLightFlattenable* aPlusOne) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementLightRefBaseFlattenable: {
|
|
using Signature =
|
|
status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
|
|
sp<TestLightRefBaseFlattenable>*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementNativeHandle: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&,
|
|
sp<NativeHandle>*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
|
|
NoCopyNoMove* aPlusOne) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementParcelableVector: {
|
|
using Signature =
|
|
status_t (ISafeInterfaceTest::*)(const std::vector<TestParcelable>&,
|
|
std::vector<TestParcelable>*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::DoubleString: {
|
|
return callLocal(data, reply, &ISafeInterfaceTest::doubleString);
|
|
}
|
|
case ISafeInterfaceTest::Tag::CallMeBack: {
|
|
return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementInt32: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementUint32: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementInt64: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(int64_t, int64_t*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementUint64: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(uint64_t, uint64_t*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementFloat: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(float, float*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::IncrementTwo: {
|
|
using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
|
|
int32_t*) const;
|
|
return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
|
|
}
|
|
case ISafeInterfaceTest::Tag::Last:
|
|
// Should not be possible because of the asserts at the beginning of the method
|
|
[&]() { FAIL(); }();
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
|
|
private:
|
|
static constexpr const char* getLogTag() { return "BnSafeInterfaceTest"; }
|
|
};
|
|
|
|
class SafeInterfaceTest : public ::testing::Test {
|
|
public:
|
|
SafeInterfaceTest() : mSafeInterfaceTest(getRemoteService()) {
|
|
ProcessState::self()->startThreadPool();
|
|
}
|
|
~SafeInterfaceTest() override = default;
|
|
|
|
protected:
|
|
sp<ISafeInterfaceTest> mSafeInterfaceTest;
|
|
|
|
private:
|
|
static constexpr const char* getLogTag() { return "SafeInterfaceTest"; }
|
|
|
|
sp<ISafeInterfaceTest> getRemoteService() {
|
|
sp<IBinder> binder = defaultServiceManager()->getService(kServiceName);
|
|
sp<ISafeInterfaceTest> iface = interface_cast<ISafeInterfaceTest>(binder);
|
|
EXPECT_TRUE(iface != nullptr);
|
|
|
|
iface->setDeathToken(new BBinder);
|
|
|
|
return iface;
|
|
}
|
|
};
|
|
|
|
TEST_F(SafeInterfaceTest, TestReturnsNoMemory) {
|
|
status_t result = mSafeInterfaceTest->returnsNoMemory();
|
|
ASSERT_EQ(NO_MEMORY, result);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestLogicalNot) {
|
|
const bool a = true;
|
|
bool notA = true;
|
|
status_t result = mSafeInterfaceTest->logicalNot(a, ¬A);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(!a, notA);
|
|
// Test both since we don't want to accidentally catch a default false somewhere
|
|
const bool b = false;
|
|
bool notB = false;
|
|
result = mSafeInterfaceTest->logicalNot(b, ¬B);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(!b, notB);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestModifyEnum) {
|
|
const TestEnum a = TestEnum::INITIAL;
|
|
TestEnum b = TestEnum::INVALID;
|
|
status_t result = mSafeInterfaceTest->modifyEnum(a, &b);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(TestEnum::FINAL, b);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementFlattenable) {
|
|
const TestFlattenable a{1};
|
|
TestFlattenable aPlusOne{0};
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a.value + 1, aPlusOne.value);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) {
|
|
const TestLightFlattenable a{1};
|
|
TestLightFlattenable aPlusOne{0};
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a.value + 1, aPlusOne.value);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementLightRefBaseFlattenable) {
|
|
sp<TestLightRefBaseFlattenable> a = new TestLightRefBaseFlattenable{1};
|
|
sp<TestLightRefBaseFlattenable> aPlusOne;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_NE(nullptr, aPlusOne.get());
|
|
ASSERT_EQ(a->value + 1, aPlusOne->value);
|
|
}
|
|
|
|
namespace { // Anonymous namespace
|
|
|
|
bool fdsAreEquivalent(int a, int b) {
|
|
struct stat statA {};
|
|
struct stat statB {};
|
|
if (fstat(a, &statA) != 0) return false;
|
|
if (fstat(b, &statB) != 0) return false;
|
|
return (statA.st_dev == statB.st_dev) && (statA.st_ino == statB.st_ino);
|
|
}
|
|
|
|
} // Anonymous namespace
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementNativeHandle) {
|
|
// Create an fd we can use to send and receive from the remote process
|
|
base::unique_fd eventFd{eventfd(0 /*initval*/, 0 /*flags*/)};
|
|
ASSERT_NE(-1, eventFd);
|
|
|
|
// Determine the maximum number of fds this process can have open
|
|
struct rlimit limit {};
|
|
ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &limit));
|
|
uint32_t maxFds = static_cast<uint32_t>(limit.rlim_cur);
|
|
|
|
// Perform this test enough times to rule out fd leaks
|
|
for (uint32_t iter = 0; iter < (2 * maxFds); ++iter) {
|
|
native_handle* handle = native_handle_create(1 /*numFds*/, 1 /*numInts*/);
|
|
ASSERT_NE(nullptr, handle);
|
|
handle->data[0] = dup(eventFd.get());
|
|
handle->data[1] = 1;
|
|
|
|
// This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing
|
|
// the native_handle when it goes out of scope
|
|
sp<NativeHandle> a = NativeHandle::create(handle, true);
|
|
|
|
sp<NativeHandle> aPlusOne;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_TRUE(fdsAreEquivalent(a->handle()->data[0], aPlusOne->handle()->data[0]));
|
|
ASSERT_EQ(a->handle()->data[1] + 1, aPlusOne->handle()->data[1]);
|
|
}
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
|
|
const NoCopyNoMove a{1};
|
|
NoCopyNoMove aPlusOne{0};
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a.getValue() + 1, aPlusOne.getValue());
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncremementParcelableVector) {
|
|
const std::vector<TestParcelable> a{TestParcelable{1}, TestParcelable{2}};
|
|
std::vector<TestParcelable> aPlusOne;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a.size(), aPlusOne.size());
|
|
for (size_t i = 0; i < a.size(); ++i) {
|
|
ASSERT_EQ(a[i].getValue() + 1, aPlusOne[i].getValue());
|
|
}
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestDoubleString) {
|
|
const String8 str{"asdf"};
|
|
String8 doubleStr;
|
|
status_t result = mSafeInterfaceTest->doubleString(str, &doubleStr);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_TRUE(doubleStr == String8{"asdfasdf"});
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestCallMeBack) {
|
|
class CallbackReceiver : public BnCallback {
|
|
public:
|
|
void onCallback(int32_t aPlusOne) override {
|
|
ALOG(LOG_INFO, "CallbackReceiver", "%s", __PRETTY_FUNCTION__);
|
|
std::unique_lock<decltype(mMutex)> lock(mMutex);
|
|
mValue = aPlusOne;
|
|
mCondition.notify_one();
|
|
}
|
|
|
|
std::optional<int32_t> waitForCallback() {
|
|
std::unique_lock<decltype(mMutex)> lock(mMutex);
|
|
bool success =
|
|
mCondition.wait_for(lock, 100ms, [&]() { return static_cast<bool>(mValue); });
|
|
return success ? mValue : std::nullopt;
|
|
}
|
|
|
|
private:
|
|
std::mutex mMutex;
|
|
std::condition_variable mCondition;
|
|
std::optional<int32_t> mValue;
|
|
};
|
|
|
|
sp<CallbackReceiver> receiver = new CallbackReceiver;
|
|
const int32_t a = 1;
|
|
mSafeInterfaceTest->callMeBack(receiver, a);
|
|
auto result = receiver->waitForCallback();
|
|
ASSERT_TRUE(result);
|
|
ASSERT_EQ(a + 1, *result);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementInt32) {
|
|
const int32_t a = 1;
|
|
int32_t aPlusOne = 0;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a + 1, aPlusOne);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementUint32) {
|
|
const uint32_t a = 1;
|
|
uint32_t aPlusOne = 0;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a + 1, aPlusOne);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementInt64) {
|
|
const int64_t a = 1;
|
|
int64_t aPlusOne = 0;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a + 1, aPlusOne);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementUint64) {
|
|
const uint64_t a = 1;
|
|
uint64_t aPlusOne = 0;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a + 1, aPlusOne);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementFloat) {
|
|
const float a = 1.0f;
|
|
float aPlusOne = 0.0f;
|
|
status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a + 1.0f, aPlusOne);
|
|
}
|
|
|
|
TEST_F(SafeInterfaceTest, TestIncrementTwo) {
|
|
const int32_t a = 1;
|
|
int32_t aPlusOne = 0;
|
|
const int32_t b = 2;
|
|
int32_t bPlusOne = 0;
|
|
status_t result = mSafeInterfaceTest->increment(1, &aPlusOne, 2, &bPlusOne);
|
|
ASSERT_EQ(NO_ERROR, result);
|
|
ASSERT_EQ(a + 1, aPlusOne);
|
|
ASSERT_EQ(b + 1, bPlusOne);
|
|
}
|
|
|
|
extern "C" int main(int argc, char **argv) {
|
|
testing::InitGoogleTest(&argc, argv);
|
|
|
|
if (fork() == 0) {
|
|
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
|
sp<BnSafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
|
|
status_t status = defaultServiceManager()->addService(kServiceName, nativeService);
|
|
if (status != OK) {
|
|
ALOG(LOG_INFO, "SafeInterfaceServer", "could not register");
|
|
return EXIT_FAILURE;
|
|
}
|
|
IPCThreadState::self()->joinThreadPool();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return RUN_ALL_TESTS();
|
|
}
|
|
|
|
} // namespace tests
|
|
} // namespace android
|