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