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