Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f11c43f authored by Devin Moore's avatar Devin Moore Committed by Gerrit Code Review
Browse files

Merge "Add simple AccessorProvider case to binderAllocationLimits" into main

parents 92af73a6 b616049f
Loading
Loading
Loading
Loading
+118 −4
Original line number Diff line number Diff line
@@ -22,17 +22,33 @@
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
#include <cutils/trace.h>
#include <gtest/gtest-spi.h>
#include <gtest/gtest.h>
#include <utils/CallStack.h>

#include <malloc.h>
#include <atomic>
#include <functional>
#include <numeric>
#include <vector>

using namespace android::binder::impl;

static android::String8 gEmpty(""); // make sure first allocation from optimization runs

struct State {
    State(std::vector<size_t>&& expectedMallocs) : expectedMallocs(std::move(expectedMallocs)) {}
    ~State() {
        size_t num = numMallocs.load();
        if (expectedMallocs.size() != num) {
            ADD_FAILURE() << "Expected " << expectedMallocs.size() << " allocations, but got "
                          << num;
        }
    }
    const std::vector<size_t> expectedMallocs;
    std::atomic<size_t> numMallocs;
};

struct DestructionAction {
    DestructionAction(std::function<void()> f) : mF(std::move(f)) {}
    ~DestructionAction() { mF(); };
@@ -95,8 +111,7 @@ namespace LambdaHooks {

// Action to execute when malloc is hit. Supports nesting. Malloc is not
// restricted when the allocation hook is being processed.
__attribute__((warn_unused_result))
DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
__attribute__((warn_unused_result)) DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
    MallocHooks before = MallocHooks::save();
    LambdaHooks::lambdas.emplace_back(std::move(f));
    LambdaHooks::lambda_malloc_hooks.overwrite();
@@ -106,6 +121,22 @@ DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
    });
}

DestructionAction setExpectedMallocs(std::vector<size_t>&& expected) {
    auto state = std::make_shared<State>(std::move(expected));
    return OnMalloc([state = state](size_t bytes) {
        size_t num = state->numMallocs.fetch_add(1);
        if (num >= state->expectedMallocs.size() || state->expectedMallocs[num] != bytes) {
            ADD_FAILURE() << "Unexpected allocation number " << num << " of size " << bytes
                          << " bytes" << std::endl
                          << android::CallStack::stackToString("UNEXPECTED ALLOCATION",
                                                               android::CallStack::getCurrent(
                                                                       4 /*ignoreDepth*/)
                                                                       .get())
                          << std::endl;
        }
    });
}

// exported symbol, to force compiler not to optimize away pointers we set here
const void* imaginary_use;

@@ -119,16 +150,53 @@ TEST(TestTheTest, OnMalloc) {

        imaginary_use = new int[10];
    }
    delete[] reinterpret_cast<const int*>(imaginary_use);
    EXPECT_EQ(mallocs, 1u);
}

TEST(TestTheTest, OnMallocWithExpectedMallocs) {
    std::vector<size_t> expectedMallocs = {
            4,
            16,
            8,
    };
    {
        const auto on_malloc = setExpectedMallocs(std::move(expectedMallocs));
        imaginary_use = new int32_t[1];
        delete[] reinterpret_cast<const int*>(imaginary_use);
        imaginary_use = new int32_t[4];
        delete[] reinterpret_cast<const int*>(imaginary_use);
        imaginary_use = new int32_t[2];
        delete[] reinterpret_cast<const int*>(imaginary_use);
    }
}

TEST(TestTheTest, OnMallocWithExpectedMallocsWrongSize) {
    std::vector<size_t> expectedMallocs = {
            4,
            16,
            100000,
    };
    EXPECT_NONFATAL_FAILURE(
            {
                const auto on_malloc = setExpectedMallocs(std::move(expectedMallocs));
                imaginary_use = new int32_t[1];
                delete[] reinterpret_cast<const int*>(imaginary_use);
                imaginary_use = new int32_t[4];
                delete[] reinterpret_cast<const int*>(imaginary_use);
                imaginary_use = new int32_t[2];
                delete[] reinterpret_cast<const int*>(imaginary_use);
            },
            "Unexpected allocation number 2 of size 8 bytes");
}

__attribute__((warn_unused_result))
DestructionAction ScopeDisallowMalloc() {
    return OnMalloc([&](size_t bytes) {
        ADD_FAILURE() << "Unexpected allocation: " << bytes;
        FAIL() << "Unexpected allocation: " << bytes;
        using android::CallStack;
        std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get())
        std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION",
                                              CallStack::getCurrent(4 /*ignoreDepth*/).get())
                  << std::endl;
    });
}
@@ -224,6 +292,51 @@ TEST(BinderAllocation, SmallTransaction) {
    EXPECT_EQ(mallocs, 1u);
}

TEST(BinderAccessorAllocation, AddAccessorCheckService) {
    // Need to call defaultServiceManager() before checking malloc because it
    // will allocate an instance in the call_once
    const auto sm = defaultServiceManager();
    const std::string kInstanceName1 = "foo.bar.IFoo/default";
    const std::string kInstanceName2 = "foo.bar.IFoo2/default";
    const String16 kInstanceName16(kInstanceName1.c_str());
    std::vector<size_t> expectedMallocs = {
            // addAccessorProvider
            112, // new AccessorProvider
            16,  // new AccessorProviderEntry
            // checkService
            45,  // String8 from String16 in CppShim::checkService
            128, // writeInterfaceToken
            16,  // getInjectedAccessor, new AccessorProviderEntry
            66,  // getInjectedAccessor, String16
            45,  // String8 from String16 in AccessorProvider::provide
    };
    std::set<std::string> supportedInstances = {kInstanceName1, kInstanceName2};
    auto onMalloc = setExpectedMallocs(std::move(expectedMallocs));

    auto receipt =
            android::addAccessorProvider(std::move(supportedInstances),
                                         [&](const String16&) -> sp<IBinder> { return nullptr; });
    EXPECT_FALSE(receipt.expired());

    sp<IBinder> binder = sm->checkService(kInstanceName16);

    status_t status = android::removeAccessorProvider(receipt);
}

TEST(BinderAccessorAllocation, AddAccessorEmpty) {
    std::vector<size_t> expectedMallocs = {
            48, // From ALOGE with empty set of instances
    };
    std::set<std::string> supportedInstances = {};
    auto onMalloc = setExpectedMallocs(std::move(expectedMallocs));

    auto receipt =
            android::addAccessorProvider(std::move(supportedInstances),
                                         [&](const String16&) -> sp<IBinder> { return nullptr; });

    EXPECT_TRUE(receipt.expired());
}

TEST(RpcBinderAllocation, SetupRpcServer) {
    std::string tmp = getenv("TMPDIR") ?: "/tmp";
    std::string addr = tmp + "/binderRpcBenchmark";
@@ -255,6 +368,7 @@ TEST(RpcBinderAllocation, SetupRpcServer) {
}

int main(int argc, char** argv) {
    LOG(INFO) << "Priming static log variables for binderAllocationLimits.";
    if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
        CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
        execv(argv[0], argv);