1 /*
2 * Copyright (C) 2021 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 "libstatssocket_lazy.h"
18
19 #include <mutex>
20
21 #include <dlfcn.h>
22 #include <stdatomic.h>
23
24 #include "log/log.h"
25
26 #include <stats_event.h>
27 #include <stats_socket.h>
28
29 #include "statssocket_lazy.h"
30
31 // This file provides a lazy interface to libstatssocket.so to address early boot dependencies.
32 // Specifically bootanimation, surfaceflinger, and lmkd run before the statsd APEX is loaded and
33 // libstatssocket.so is in the statsd APEX.
34
35 // Method pointers to libstatssocket methods are held in an array which simplifies checking
36 // all pointers are initialized.
37 enum MethodIndex {
38 // Stats Event APIs in stats_event.h.
39 k_AStatsEvent_obtain,
40 k_AStatsEvent_build,
41 k_AStatsEvent_write,
42 k_AStatsEvent_release,
43 k_AStatsEvent_setAtomId,
44 k_AStatsEvent_writeInt32,
45 k_AStatsEvent_writeInt64,
46 k_AStatsEvent_writeFloat,
47 k_AStatsEvent_writeBool,
48 k_AStatsEvent_writeByteArray,
49 k_AStatsEvent_writeString,
50 k_AStatsEvent_writeStringArray,
51 k_AStatsEvent_writeAttributionChain,
52 k_AStatsEvent_addBoolAnnotation,
53 k_AStatsEvent_addInt32Annotation,
54
55 // Stats Socket APIs in stats_socket.h.
56 k_AStatsSocket_close,
57
58 // Marker for count of methods
59 k_MethodCount
60 };
61
62 // Table of methods pointers in libstatssocket APIs.
63 static void* g_Methods[k_MethodCount];
64
65 //
66 // Libstatssocket lazy loading.
67 //
68
69 static atomic_bool gPreventLibstatssocketLoading = false; // Allows tests to block loading.
70
PreventLibstatssocketLazyLoadingForTests()71 void PreventLibstatssocketLazyLoadingForTests() {
72 gPreventLibstatssocketLoading.store(true);
73 }
74
LoadLibstatssocket(int dlopen_flags)75 static void* LoadLibstatssocket(int dlopen_flags) {
76 if (gPreventLibstatssocketLoading.load()) {
77 return nullptr;
78 }
79 return dlopen("libstatssocket.so", dlopen_flags);
80 }
81
82 namespace android::statssocket::lazy {
IsAvailable()83 bool IsAvailable() {
84 static const void* handle = LoadLibstatssocket(RTLD_NOW);
85 return handle != nullptr;
86 }
87 } // namespace android::statssocket::lazy
88
89 //
90 // Initialization and symbol binding.
91
BindSymbol(void * handle,const char * name,enum MethodIndex index)92 static void BindSymbol(void* handle, const char* name, enum MethodIndex index) {
93 void* symbol = dlsym(handle, name);
94 LOG_ALWAYS_FATAL_IF(symbol == nullptr, "Failed to find symbol '%s' in libstatssocket.so: %s",
95 name, dlerror());
96 g_Methods[index] = symbol;
97 }
98
InitializeOnce()99 static void InitializeOnce() {
100 void* handle = LoadLibstatssocket(RTLD_NOW);
101 LOG_ALWAYS_FATAL_IF(handle == nullptr, "Failed to load libstatssocket.so: %s", dlerror());
102
103 #undef BIND_SYMBOL
104 #define BIND_SYMBOL(name) BindSymbol(handle, #name, k_##name);
105 // Methods in stats_event.h.
106 BIND_SYMBOL(AStatsEvent_obtain);
107 BIND_SYMBOL(AStatsEvent_build);
108 BIND_SYMBOL(AStatsEvent_write);
109 BIND_SYMBOL(AStatsEvent_release);
110 BIND_SYMBOL(AStatsEvent_setAtomId);
111 BIND_SYMBOL(AStatsEvent_writeInt32);
112 BIND_SYMBOL(AStatsEvent_writeInt64);
113 BIND_SYMBOL(AStatsEvent_writeFloat);
114 BIND_SYMBOL(AStatsEvent_writeBool);
115 BIND_SYMBOL(AStatsEvent_writeByteArray);
116 BIND_SYMBOL(AStatsEvent_writeString);
117 BIND_SYMBOL(AStatsEvent_writeStringArray);
118 BIND_SYMBOL(AStatsEvent_writeAttributionChain);
119 BIND_SYMBOL(AStatsEvent_addBoolAnnotation);
120 BIND_SYMBOL(AStatsEvent_addInt32Annotation);
121
122 // Methods in stats_socket.h.
123 BIND_SYMBOL(AStatsSocket_close);
124 #undef BIND_SYMBOL
125
126 // Check every symbol is bound.
127 for (int i = 0; i < k_MethodCount; ++i) {
128 LOG_ALWAYS_FATAL_IF(g_Methods[i] == nullptr,
129 "Uninitialized method in libstatssocket_lazy at index: %d", i);
130 }
131 }
132
EnsureInitialized()133 static void EnsureInitialized() {
134 static std::once_flag initialize_flag;
135 std::call_once(initialize_flag, InitializeOnce);
136 }
137
138 #define INVOKE_METHOD(name, args...) \
139 do { \
140 EnsureInitialized(); \
141 void* method = g_Methods[k_##name]; \
142 return reinterpret_cast<decltype(&name)>(method)(args); \
143 } while (0)
144
145 //
146 // Forwarding for methods in stats_event.h.
147 //
148
AStatsEvent_obtain()149 AStatsEvent* AStatsEvent_obtain() {
150 INVOKE_METHOD(AStatsEvent_obtain);
151 }
152
AStatsEvent_build(AStatsEvent * event)153 void AStatsEvent_build(AStatsEvent* event) {
154 INVOKE_METHOD(AStatsEvent_build, event);
155 }
156
AStatsEvent_write(AStatsEvent * event)157 int AStatsEvent_write(AStatsEvent* event) {
158 INVOKE_METHOD(AStatsEvent_write, event);
159 }
160
AStatsEvent_release(AStatsEvent * event)161 void AStatsEvent_release(AStatsEvent* event) {
162 INVOKE_METHOD(AStatsEvent_release, event);
163 }
164
AStatsEvent_setAtomId(AStatsEvent * event,uint32_t atomId)165 void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
166 INVOKE_METHOD(AStatsEvent_setAtomId, event, atomId);
167 }
168
AStatsEvent_writeInt32(AStatsEvent * event,int32_t value)169 void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value) {
170 INVOKE_METHOD(AStatsEvent_writeInt32, event, value);
171 }
172
AStatsEvent_writeInt64(AStatsEvent * event,int64_t value)173 void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value) {
174 INVOKE_METHOD(AStatsEvent_writeInt64, event, value);
175 }
176
AStatsEvent_writeFloat(AStatsEvent * event,float value)177 void AStatsEvent_writeFloat(AStatsEvent* event, float value) {
178 INVOKE_METHOD(AStatsEvent_writeFloat, event, value);
179 }
180
AStatsEvent_writeBool(AStatsEvent * event,bool value)181 void AStatsEvent_writeBool(AStatsEvent* event, bool value) {
182 INVOKE_METHOD(AStatsEvent_writeBool, event, value);
183 }
184
AStatsEvent_writeByteArray(AStatsEvent * event,const uint8_t * buf,size_t numBytes)185 void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes) {
186 INVOKE_METHOD(AStatsEvent_writeByteArray, event, buf, numBytes);
187 }
188
AStatsEvent_writeString(AStatsEvent * event,const char * value)189 void AStatsEvent_writeString(AStatsEvent* event, const char* value) {
190 INVOKE_METHOD(AStatsEvent_writeString, event, value);
191 }
192
AStatsEvent_writeStringArray(AStatsEvent * event,const char * const * elements,size_t numElements)193 void AStatsEvent_writeStringArray(AStatsEvent* event, const char* const* elements,
194 size_t numElements) {
195 INVOKE_METHOD(AStatsEvent_writeStringArray, event, elements, numElements);
196 }
197
AStatsEvent_writeAttributionChain(AStatsEvent * event,const uint32_t * uids,const char * const * tags,uint8_t numNodes)198 void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
199 const char* const* tags, uint8_t numNodes) {
200 INVOKE_METHOD(AStatsEvent_writeAttributionChain, event, uids, tags, numNodes);
201 }
202
AStatsEvent_addBoolAnnotation(AStatsEvent * event,uint8_t annotationId,bool value)203 void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value) {
204 INVOKE_METHOD(AStatsEvent_addBoolAnnotation, event, annotationId, value);
205 }
206
AStatsEvent_addInt32Annotation(AStatsEvent * event,uint8_t annotationId,int32_t value)207 void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value) {
208 INVOKE_METHOD(AStatsEvent_addInt32Annotation, event, annotationId, value);
209 }
210
211 //
212 // Forwarding for methods in stats_socket.h.
213 //
214
AStatsSocket_close()215 void AStatsSocket_close() {
216 INVOKE_METHOD(AStatsSocket_close);
217 }
218