• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 #define STATSD_DEBUG false  // STOPSHIP if true
18 #include "Log.h"
19 
20 #include <android/binder_ibinder.h>
21 #include <android/binder_ibinder_platform.h>
22 #include <android/binder_interface_utils.h>
23 #include <android/binder_manager.h>
24 #include <android/binder_process.h>
25 #include <stdio.h>
26 #include <sys/random.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <utils/Looper.h>
31 
32 #include "StatsService.h"
33 #include "flags/FlagProvider.h"
34 #include "packages/UidMap.h"
35 #include "socket/StatsSocketListener.h"
36 
37 using namespace android;
38 using namespace android::os::statsd;
39 using ::ndk::SharedRefBase;
40 using std::shared_ptr;
41 using std::make_shared;
42 
43 shared_ptr<StatsService> gStatsService = nullptr;
44 sp<StatsSocketListener> gSocketListener = nullptr;
45 int gCtrlPipe[2];
46 
signalHandler(int sig)47 void signalHandler(int sig) {
48     ALOGW("statsd terminated on receiving signal %d.", sig);
49     const char c = 'q';
50     write(gCtrlPipe[1], &c, 1);
51 }
52 
registerSignalHandlers()53 void registerSignalHandlers()
54 {
55     struct sigaction sa;
56     sigemptyset(&sa.sa_mask);
57     sa.sa_flags = 0;
58 
59     sa.sa_handler = SIG_IGN;
60     // ShellSubscriber uses SIGPIPE as a signal to detect the end of the
61     // client process. Don't prematurely exit(1) here. Instead, ignore the
62     // signal and allow the write call to return EPIPE.
63     sigaction(SIGPIPE, &sa, nullptr);
64 
65     pipe2(gCtrlPipe, O_CLOEXEC);
66     sa.sa_handler = signalHandler;
67     sigaction(SIGTERM, &sa, nullptr);
68 }
69 
initSeedRandom()70 void initSeedRandom() {
71     unsigned int seed = 0;
72     // getrandom() reads bytes from urandom source into buf. If getrandom()
73     // is unable to read from urandom source, then it returns -1 and we set
74     // out seed to be time(nullptr) as a fallback.
75     if (TEMP_FAILURE_RETRY(
76                 getrandom(static_cast<void*>(&seed), sizeof(unsigned int), GRND_NONBLOCK)) < 0) {
77         seed = time(nullptr);
78     }
79     srand(seed);
80 }
81 
main(int,char **)82 int main(int /*argc*/, char** /*argv*/) {
83     // Set up the looper
84     sp<Looper> looper(Looper::prepare(0 /* opts */));
85 
86     // Set up the binder
87     ABinderProcess_setThreadPoolMaxThreadCount(9);
88     ABinderProcess_startThreadPool();
89 
90     // Initialize boot flags
91     FlagProvider::getInstance().initBootFlags({});
92 
93     std::shared_ptr<LogEventQueue> eventQueue =
94             std::make_shared<LogEventQueue>(50000); /*buffer limit. Buffer is NOT pre-allocated*/
95 
96     sp<UidMap> uidMap = UidMap::getInstance();
97 
98     std::shared_ptr<LogEventFilter> logEventFilter = std::make_shared<LogEventFilter>();
99 
100     initSeedRandom();
101 
102     // Start reading events from the socket as early as possible.
103     // Processing from the queue is delayed until StatsService::startup to allow
104     // config initialization to occur before we start processing atoms.
105     gSocketListener = new StatsSocketListener(eventQueue, logEventFilter);
106 
107     ALOGI("Statsd starts to listen to socket.");
108     // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
109     if (gSocketListener->startListener(600)) {
110         exit(1);
111     }
112 
113     // Create the service
114     gStatsService = SharedRefBase::make<StatsService>(uidMap, eventQueue, logEventFilter);
115     auto binder = gStatsService->asBinder();
116 
117     // We want to be able to ask for the selinux context of callers:
118     if (__builtin_available(android __ANDROID_API_U__, *)) {
119         AIBinder_setRequestingSid(binder.get(), true);
120     }
121 
122     // TODO(b/149582373): Set DUMP_FLAG_PROTO once libbinder_ndk supports
123     // setting dumpsys priorities.
124     binder_status_t status = AServiceManager_addService(binder.get(), "stats");
125     if (status != STATUS_OK) {
126         ALOGE("Failed to add service as AIDL service");
127         return -1;
128     }
129 
130     gStatsService->sayHiToStatsCompanion();
131 
132     gStatsService->Startup();
133 
134     // Enable the filter now since configs are initialized.
135     logEventFilter->setFilteringEnabled(true);
136 
137     // Use self-pipe to notify this thread to gracefully quit
138     // when receiving SIGTERM
139     registerSignalHandlers();
140     std::thread([] {
141         while (true) {
142             char c;
143             int i = read(gCtrlPipe[0], &c, 1);
144             if (i < 0) {
145                 if (errno == EINTR) continue;
146             }
147             gSocketListener->stopListener();
148             gStatsService->Terminate();
149             // return the signal handler to its default disposition, then raise the signal again
150             signal(SIGTERM, SIG_DFL);
151             // this is a sync call which leads to immediate process termination and
152             // no destructors are called, semantically similar to call exit(1) here
153             raise(SIGTERM);
154         }
155     }).detach();
156 
157     // Loop forever -- the reports run on this thread in a handler, and the
158     // binder calls remain responsive in their pool of one thread.
159     while (true) {
160         looper->pollAll(-1 /* timeoutMillis */);
161     }
162     ALOGW("statsd escaped from its loop.");
163 
164     return 1;
165 }
166