1 /*
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 "perfetto/ext/base/unix_socket.h"
18 #include "perfetto/ext/base/unix_task_runner.h"
19 #include "perfetto/heap_profile.h"
20 #include "src/profiling/memory/heap_profile_internal.h"
21
22 #include "src/profiling/memory/client.h"
23 #include "src/profiling/memory/client_api_factory.h"
24 #include "src/profiling/memory/shared_ring_buffer.h"
25 #include "src/profiling/memory/wire_protocol.h"
26 #include "test/gtest_and_gmock.h"
27
28 #include <memory>
29
30 namespace perfetto {
31 namespace profiling {
32
33 namespace {
34
35 ClientConfiguration g_client_config;
36 int g_shmem_fd;
37
GlobalServerSocket()38 base::UnixSocketRaw& GlobalServerSocket() {
39 static base::UnixSocketRaw* srv_sock = new base::UnixSocketRaw;
40 return *srv_sock;
41 }
42
DisconnectGlobalServerSocket()43 void DisconnectGlobalServerSocket() {
44 base::UnixSocketRaw destroy;
45 std::swap(destroy, GlobalServerSocket());
46 }
47
48 } // namespace
49
50 // This is called by AHeapProfile_initSession (client_api.cc) to construct a
51 // client. The Client API requires to be linked against another compliation
52 // unit that provides this function. This way, it can be used in different
53 // circumstances (central heapprofd, fork heapprofd) and be agnostic about the
54 // details. This is is used to create a test Client here.
StartHeapprofdIfStatic()55 void StartHeapprofdIfStatic() {}
ConstructClient(UnhookedAllocator<perfetto::profiling::Client> unhooked_allocator)56 std::shared_ptr<Client> ConstructClient(
57 UnhookedAllocator<perfetto::profiling::Client> unhooked_allocator) {
58 base::UnixSocketRaw cli_sock;
59 base::UnixSocketRaw& srv_sock = GlobalServerSocket();
60 std::tie(cli_sock, srv_sock) = base::UnixSocketRaw::CreatePairPosix(
61 base::SockFamily::kUnix, base::SockType::kStream);
62 auto ringbuf = SharedRingBuffer::Create(8 * 1048576);
63 PERFETTO_CHECK(ringbuf);
64 PERFETTO_CHECK(cli_sock);
65 PERFETTO_CHECK(srv_sock);
66 g_shmem_fd = ringbuf->fd();
67 return std::allocate_shared<Client>(unhooked_allocator, std::move(cli_sock),
68 g_client_config, std::move(*ringbuf),
69 getpid(), GetMainThreadStackRange());
70 }
71
72 namespace {
73
TEST(ClientApiTest,NoClient)74 TEST(ClientApiTest, NoClient) {
75 uint32_t heap_id = AHeapProfile_registerHeap(AHeapInfo_create("NoClient"));
76 EXPECT_FALSE(AHeapProfile_reportAllocation(heap_id, 1, 1));
77 }
78
TEST(ClientApiTest,ClientEnabledHeap)79 TEST(ClientApiTest, ClientEnabledHeap) {
80 uint32_t heap_id =
81 AHeapProfile_registerHeap(AHeapInfo_create("ClientEnabledHeap"));
82 ClientConfiguration client_config{};
83 client_config.default_interval = 1;
84 strcpy(&client_config.heaps[0].name[0], "ClientEnabledHeap");
85 client_config.heaps[0].interval = 1;
86 client_config.num_heaps = 1;
87
88 g_client_config = client_config;
89
90 AHeapProfile_initSession(malloc, free);
91 PERFETTO_CHECK(g_shmem_fd);
92 auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd)));
93 g_shmem_fd = 0;
94 PERFETTO_CHECK(ringbuf);
95 EXPECT_TRUE(AHeapProfile_reportAllocation(heap_id, 1, 1));
96 // Check that the service received something on the shmem.
97 EXPECT_TRUE(ringbuf->BeginRead());
98 DisconnectGlobalServerSocket();
99 ringbuf->SetShuttingDown();
100 EXPECT_FALSE(AHeapProfile_reportAllocation(heap_id, 1, 1));
101 }
102
TEST(ClientApiTest,ClientAllHeaps)103 TEST(ClientApiTest, ClientAllHeaps) {
104 uint32_t heap_id =
105 AHeapProfile_registerHeap(AHeapInfo_create("ClientAllHeaps"));
106 ClientConfiguration client_config{};
107 client_config.default_interval = 1;
108 client_config.all_heaps = true;
109
110 g_client_config = client_config;
111
112 AHeapProfile_initSession(malloc, free);
113 PERFETTO_CHECK(g_shmem_fd);
114 auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd)));
115 g_shmem_fd = 0;
116 PERFETTO_CHECK(ringbuf);
117 EXPECT_TRUE(AHeapProfile_reportAllocation(heap_id, 1, 1));
118 // Check that the service received something on the shmem.
119 EXPECT_TRUE(ringbuf->BeginRead());
120 DisconnectGlobalServerSocket();
121 ringbuf->SetShuttingDown();
122 EXPECT_FALSE(AHeapProfile_reportAllocation(heap_id, 1, 1));
123 }
124
125 } // namespace
126
127 } // namespace profiling
128 } // namespace perfetto
129