• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "libstatspull_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_pull_atom_callback.h"
27 
28 // This file provides a lazy interface to libstatspull.so to address early boot dependencies.
29 // Specifically bootanimation, surfaceflinger, and lmkd run before the statsd APEX is loaded and
30 // libstatspull.so is in the statsd APEX.
31 
32 // Method pointers to libstatspull methods are held in an array which simplifies checking
33 // all pointers are initialized.
34 enum MethodIndex {
35     // PullAtomMetadata APIs in stats_pull_atom_callback.h.
36     k_AStatsManager_PullAtomMetadata_obtain,
37     k_AStatsManager_PullAtomMetadata_release,
38     k_AStatsManager_PullAtomMetadata_setCoolDownMillis,
39     k_AStatsManager_PullAtomMetadata_getCoolDownMillis,
40     k_AStatsManager_PullAtomMetadata_setTimeoutMillis,
41     k_AStatsManager_PullAtomMetadata_getTimeoutMillis,
42     k_AStatsManager_PullAtomMetadata_setAdditiveFields,
43     k_AStatsManager_PullAtomMetadata_getNumAdditiveFields,
44     k_AStatsManager_PullAtomMetadata_getAdditiveFields,
45 
46     // AStatsEventList APIs in stats_pull_atom_callback.h
47     k_AStatsEventList_addStatsEvent,
48 
49     // PullAtomCallback APIs in stats_pull_atom_callback.h
50     k_AStatsManager_setPullAtomCallback,
51     k_AStatsManager_clearPullAtomCallback,
52 
53     // Marker for count of methods
54     k_MethodCount
55 };
56 
57 // Table of methods pointers in libstatspull APIs.
58 static void* g_Methods[k_MethodCount];
59 
60 //
61 // Libstatspull lazy loading.
62 //
63 
64 static atomic_bool gPreventLibstatspullLoading = false;  // Allows tests to block loading.
65 
PreventLibstatspullLazyLoadingForTests()66 void PreventLibstatspullLazyLoadingForTests() {
67     gPreventLibstatspullLoading.store(true);
68 }
69 
LoadLibstatspull(int dlopen_flags)70 static void* LoadLibstatspull(int dlopen_flags) {
71     if (gPreventLibstatspullLoading.load()) {
72         return nullptr;
73     }
74     return dlopen("libstatspull.so", dlopen_flags);
75 }
76 
77 //
78 // Initialization and symbol binding.
79 
BindSymbol(void * handle,const char * name,enum MethodIndex index)80 static void BindSymbol(void* handle, const char* name, enum MethodIndex index) {
81     void* symbol = dlsym(handle, name);
82     LOG_ALWAYS_FATAL_IF(symbol == nullptr, "Failed to find symbol '%s' in libstatspull.so: %s",
83                         name, dlerror());
84     g_Methods[index] = symbol;
85 }
86 
InitializeOnce()87 static void InitializeOnce() {
88     void* handle = LoadLibstatspull(RTLD_NOW);
89     LOG_ALWAYS_FATAL_IF(handle == nullptr, "Failed to load libstatspull.so: %s", dlerror());
90 
91 #undef BIND_SYMBOL
92 #define BIND_SYMBOL(name) BindSymbol(handle, #name, k_##name);
93     // PullAtomMetadata APIs in stats_pull_atom_callback.h.
94     BIND_SYMBOL(AStatsManager_PullAtomMetadata_obtain);
95     BIND_SYMBOL(AStatsManager_PullAtomMetadata_release);
96     BIND_SYMBOL(AStatsManager_PullAtomMetadata_setCoolDownMillis);
97     BIND_SYMBOL(AStatsManager_PullAtomMetadata_getCoolDownMillis);
98     BIND_SYMBOL(AStatsManager_PullAtomMetadata_setTimeoutMillis);
99     BIND_SYMBOL(AStatsManager_PullAtomMetadata_getTimeoutMillis);
100     BIND_SYMBOL(AStatsManager_PullAtomMetadata_setAdditiveFields);
101     BIND_SYMBOL(AStatsManager_PullAtomMetadata_getNumAdditiveFields);
102     BIND_SYMBOL(AStatsManager_PullAtomMetadata_getAdditiveFields);
103 
104     // AStatsEventList APIs in stats_pull_atom_callback.h
105     BIND_SYMBOL(AStatsEventList_addStatsEvent);
106 
107     // PullAtomCallback APIs in stats_pull_atom_callback.h
108     BIND_SYMBOL(AStatsManager_setPullAtomCallback);
109     BIND_SYMBOL(AStatsManager_clearPullAtomCallback);
110 
111 #undef BIND_SYMBOL
112 
113     // Check every symbol is bound.
114     for (int i = 0; i < k_MethodCount; ++i) {
115         LOG_ALWAYS_FATAL_IF(g_Methods[i] == nullptr,
116                             "Uninitialized method in libstatspull_lazy at index: %d", i);
117     }
118 }
119 
EnsureInitialized()120 static void EnsureInitialized() {
121     static std::once_flag initialize_flag;
122     std::call_once(initialize_flag, InitializeOnce);
123 }
124 
125 #define INVOKE_METHOD(name, args...)                            \
126     do {                                                        \
127         EnsureInitialized();                                    \
128         void* method = g_Methods[k_##name];                     \
129         return reinterpret_cast<decltype(&name)>(method)(args); \
130     } while (0)
131 
132 //
133 // Forwarding for methods in stats_pull_atom_callback.h.
134 //
135 
AStatsManager_PullAtomMetadata_obtain()136 AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
137     INVOKE_METHOD(AStatsManager_PullAtomMetadata_obtain);
138 }
139 
AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata * metadata)140 void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
141     INVOKE_METHOD(AStatsManager_PullAtomMetadata_release, metadata);
142 }
143 
AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata * metadata,int64_t cool_down_millis)144 void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
145                                                       int64_t cool_down_millis) {
146     INVOKE_METHOD(AStatsManager_PullAtomMetadata_setCoolDownMillis, metadata, cool_down_millis);
147 }
148 
AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata * metadata)149 int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata) {
150     INVOKE_METHOD(AStatsManager_PullAtomMetadata_getCoolDownMillis, metadata);
151 }
152 
AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata * metadata,int64_t timeout_millis)153 void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
154                                                      int64_t timeout_millis) {
155     INVOKE_METHOD(AStatsManager_PullAtomMetadata_setTimeoutMillis, metadata, timeout_millis);
156 }
157 
AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata * metadata)158 int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata) {
159     INVOKE_METHOD(AStatsManager_PullAtomMetadata_getTimeoutMillis, metadata);
160 }
161 
AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata * metadata,int32_t * additive_fields,int32_t num_fields)162 void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
163                                                       int32_t* additive_fields,
164                                                       int32_t num_fields) {
165     INVOKE_METHOD(AStatsManager_PullAtomMetadata_setAdditiveFields, metadata, additive_fields,
166                   num_fields);
167 }
168 
AStatsManager_PullAtomMetadata_getNumAdditiveFields(AStatsManager_PullAtomMetadata * metadata)169 int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
170         AStatsManager_PullAtomMetadata* metadata) {
171     INVOKE_METHOD(AStatsManager_PullAtomMetadata_getNumAdditiveFields, metadata);
172 }
173 
AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata * metadata,int32_t * fields)174 void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
175                                                       int32_t* fields) {
176     INVOKE_METHOD(AStatsManager_PullAtomMetadata_getAdditiveFields, metadata, fields);
177 }
178 
AStatsEventList_addStatsEvent(AStatsEventList * pull_data)179 AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
180     INVOKE_METHOD(AStatsEventList_addStatsEvent, pull_data);
181 }
182 
AStatsManager_setPullAtomCallback(int32_t atom_tag,AStatsManager_PullAtomMetadata * metadata,AStatsManager_PullAtomCallback callback,void * cookie)183 void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
184                                        AStatsManager_PullAtomCallback callback, void* cookie) {
185     INVOKE_METHOD(AStatsManager_setPullAtomCallback, atom_tag, metadata, callback, cookie);
186 }
187 
AStatsManager_clearPullAtomCallback(int32_t atom_tag)188 void AStatsManager_clearPullAtomCallback(int32_t atom_tag) {
189     INVOKE_METHOD(AStatsManager_clearPullAtomCallback, atom_tag);
190 }
191