blob: 60b3c94f5eb52396a6a0d39f704343e6b335de55 [file] [log] [blame]
Steven Moreland042ae822020-05-27 17:45:17 +00001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <android-base/logging.h>
Devin Moore2a49be62022-05-26 22:04:21 +000018#include <binder/Binder.h>
Steven Moreland042ae822020-05-27 17:45:17 +000019#include <binder/IServiceManager.h>
Devin Moore2a49be62022-05-26 22:04:21 +000020#include <binder/Parcel.h>
21#include <binder/RpcServer.h>
22#include <binder/RpcSession.h>
Steven Moreland042ae822020-05-27 17:45:17 +000023#include <gtest/gtest.h>
24#include <utils/CallStack.h>
25
26#include <malloc.h>
27#include <functional>
28#include <vector>
29
30struct DestructionAction {
31 DestructionAction(std::function<void()> f) : mF(std::move(f)) {}
32 ~DestructionAction() { mF(); };
33private:
34 std::function<void()> mF;
35};
36
37// Group of hooks
38struct MallocHooks {
39 decltype(__malloc_hook) malloc_hook;
40 decltype(__realloc_hook) realloc_hook;
41
42 static MallocHooks save() {
43 return {
44 .malloc_hook = __malloc_hook,
45 .realloc_hook = __realloc_hook,
46 };
47 }
48
49 void overwrite() const {
50 __malloc_hook = malloc_hook;
51 __realloc_hook = realloc_hook;
52 }
53};
54
55static const MallocHooks orig_malloc_hooks = MallocHooks::save();
56
57// When malloc is hit, executes lambda.
58namespace LambdaHooks {
59 using AllocationHook = std::function<void(size_t)>;
60 static std::vector<AllocationHook> lambdas = {};
61
62 static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg);
63 static void* lambda_malloc_hook(size_t bytes, const void* arg);
64
65 static const MallocHooks lambda_malloc_hooks = {
66 .malloc_hook = lambda_malloc_hook,
67 .realloc_hook = lambda_realloc_hook,
68 };
69
70 static void* lambda_malloc_hook(size_t bytes, const void* arg) {
71 {
72 orig_malloc_hooks.overwrite();
73 lambdas.at(lambdas.size() - 1)(bytes);
74 lambda_malloc_hooks.overwrite();
75 }
76 return orig_malloc_hooks.malloc_hook(bytes, arg);
77 }
78
79 static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg) {
80 {
81 orig_malloc_hooks.overwrite();
82 lambdas.at(lambdas.size() - 1)(bytes);
83 lambda_malloc_hooks.overwrite();
84 }
85 return orig_malloc_hooks.realloc_hook(ptr, bytes, arg);
86 }
87
88}
89
90// Action to execute when malloc is hit. Supports nesting. Malloc is not
91// restricted when the allocation hook is being processed.
92__attribute__((warn_unused_result))
93DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
94 MallocHooks before = MallocHooks::save();
95 LambdaHooks::lambdas.emplace_back(std::move(f));
96 LambdaHooks::lambda_malloc_hooks.overwrite();
97 return DestructionAction([before]() {
98 before.overwrite();
99 LambdaHooks::lambdas.pop_back();
100 });
101}
102
103// exported symbol, to force compiler not to optimize away pointers we set here
104const void* imaginary_use;
105
106TEST(TestTheTest, OnMalloc) {
107 size_t mallocs = 0;
108 {
109 const auto on_malloc = OnMalloc([&](size_t bytes) {
110 mallocs++;
111 EXPECT_EQ(bytes, 40);
112 });
113
114 imaginary_use = new int[10];
115 }
116 EXPECT_EQ(mallocs, 1);
117}
118
119
120__attribute__((warn_unused_result))
121DestructionAction ScopeDisallowMalloc() {
122 return OnMalloc([&](size_t bytes) {
123 ADD_FAILURE() << "Unexpected allocation: " << bytes;
124 using android::CallStack;
125 std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get())
126 << std::endl;
127 });
128}
129
Devin Moore2a49be62022-05-26 22:04:21 +0000130using android::BBinder;
Steven Moreland042ae822020-05-27 17:45:17 +0000131using android::defaultServiceManager;
Devin Moore2a49be62022-05-26 22:04:21 +0000132using android::IBinder;
Steven Moreland042ae822020-05-27 17:45:17 +0000133using android::IServiceManager;
Devin Moore2a49be62022-05-26 22:04:21 +0000134using android::OK;
135using android::Parcel;
136using android::RpcServer;
137using android::RpcSession;
138using android::sp;
139using android::status_t;
140using android::statusToString;
141using android::String16;
Steven Moreland042ae822020-05-27 17:45:17 +0000142
143static sp<IBinder> GetRemoteBinder() {
144 // This gets binder representing the service manager
145 // the current IServiceManager API doesn't expose the binder, and
146 // I want to avoid adding usages of the AIDL generated interface it
147 // is using underneath, so to avoid people copying it.
148 sp<IBinder> binder = defaultServiceManager()->checkService(String16("manager"));
149 EXPECT_NE(nullptr, binder);
150 return binder;
151}
152
153TEST(BinderAllocation, ParcelOnStack) {
154 const auto m = ScopeDisallowMalloc();
155 Parcel p;
156 imaginary_use = p.data();
157}
158
159TEST(BinderAllocation, GetServiceManager) {
160 defaultServiceManager(); // first call may alloc
161 const auto m = ScopeDisallowMalloc();
162 defaultServiceManager();
163}
164
165// note, ping does not include interface descriptor
166TEST(BinderAllocation, PingTransaction) {
167 sp<IBinder> a_binder = GetRemoteBinder();
168 const auto m = ScopeDisallowMalloc();
169 a_binder->pingBinder();
170}
171
172TEST(BinderAllocation, SmallTransaction) {
173 String16 empty_descriptor = String16("");
174 sp<IServiceManager> manager = defaultServiceManager();
175
176 size_t mallocs = 0;
177 const auto on_malloc = OnMalloc([&](size_t bytes) {
178 mallocs++;
179 // Parcel should allocate a small amount by default
180 EXPECT_EQ(bytes, 128);
181 });
182 manager->checkService(empty_descriptor);
183
184 EXPECT_EQ(mallocs, 1);
185}
186
Devin Moore2a49be62022-05-26 22:04:21 +0000187TEST(RpcBinderAllocation, SetupRpcServer) {
188 std::string tmp = getenv("TMPDIR") ?: "/tmp";
189 std::string addr = tmp + "/binderRpcBenchmark";
190 (void)unlink(addr.c_str());
191 auto server = RpcServer::make();
192 server->setRootObject(sp<BBinder>::make());
193
194 CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
195
196 std::thread([server]() { server->join(); }).detach();
197
198 status_t status;
199 auto session = RpcSession::make();
200 status = session->setupUnixDomainClient(addr.c_str());
201 CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
202
203 auto remoteBinder = session->getRootObject();
204
205 size_t mallocs = 0, totalBytes = 0;
Frederick Mayle68aa3bc2022-06-07 15:51:31 +0000206 {
207 const auto on_malloc = OnMalloc([&](size_t bytes) {
208 mallocs++;
209 totalBytes += bytes;
210 });
211 CHECK_EQ(OK, remoteBinder->pingBinder());
212 }
Frederick Mayleb86cda42022-06-09 23:17:45 +0000213 EXPECT_EQ(mallocs, 1);
214 EXPECT_EQ(totalBytes, 40);
Devin Moore2a49be62022-05-26 22:04:21 +0000215}
216
Steven Moreland042ae822020-05-27 17:45:17 +0000217int main(int argc, char** argv) {
218 if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
219 CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
220 execv(argv[0], argv);
221 return 1;
222 }
223 ::testing::InitGoogleTest(&argc, argv);
224 return RUN_ALL_TESTS();
225}