Add binderAllocationsLimit test for binder call with string vec
We have one allocation for writing the interface token, one for resizing
the output vector, and the rest of the allocations come from reading the
reply parcel into the output vector.
Flag: EXEMPT test only
Test: atest binderAllocationLimits
Bug: none
Change-Id: Icfb26fa4a8b93962ae97c8ff7286e3a50770fd78
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index 9414c37..9da9f0a 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -15,6 +15,7 @@
*/
#include <android-base/logging.h>
+#include <android/os/IServiceManager.h>
#include <binder/Binder.h>
#include <binder/Functional.h>
#include <binder/IServiceManager.h>
@@ -243,6 +244,45 @@
a_binder->pingBinder();
}
+// Return the max size of a string that will get the Small String Optimization
+// and avoid a heap allocation
+static size_t getSSOMaxSize() {
+ size_t mallocs = 0;
+ const auto on_malloc = OnMalloc([&](size_t /* bytes */) { mallocs++; });
+ for (int i = 1; true; i++) {
+ std::string s(i, 'a');
+ if (mallocs) return i - 1;
+ }
+}
+
+TEST(BinderAllocation, GetListOfStrings) {
+ sp<android::os::IServiceManager> sm =
+ android::interface_cast<android::os::IServiceManager>(GetRemoteBinder());
+ // 128 bytes Parcel::writeInterfaceToken -> writeInt32 (why 128 bytes?)
+ // 9480 Parcel::readUtf8VectorFromUtf16Vector -> readData -> c->resize(9480)
+ // then it's all readUtf8FromUtf16 calls from readUtf8VectorFromUtf16Vector
+ // Parcel::readUtf8VectorFromUtf16Vector -> readData -> readUtf8FromUtf16
+ const size_t numExtraMallocs = 2;
+ size_t mallocs = 0;
+ // Could save a single malloc by starting with a large enough vector,
+ // not worth doing without knowing the number of services.
+ std::vector<std::string> ret;
+ size_t maxSSOSize = getSSOMaxSize();
+
+ const auto on_malloc = OnMalloc([&](size_t /* bytes */) { mallocs++; });
+
+ ASSERT_TRUE(sm->listServices(android::IServiceManager::DUMP_FLAG_PRIORITY_ALL, &ret).isOk());
+ ASSERT_GT(ret.size(), 0u);
+
+ size_t numStringAllocations = std::ranges::count_if(ret, [maxSSOSize](const std::string& s) {
+ // In readUtf8FromUtf16 we resize with num chars + 1
+ return s.size() + 1 > maxSSOSize;
+ });
+
+ EXPECT_EQ(mallocs, numStringAllocations + numExtraMallocs)
+ << "Expecting " << numStringAllocations << " string allocs";
+}
+
TEST(BinderAllocation, MakeScopeGuard) {
const auto m = ScopeDisallowMalloc();
{