2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "common_time"
18 #include <utils/Log.h>
22 #include <linux/tcp.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
27 #include <utils/Errors.h>
28 #include <utils/misc.h>
30 #include <common_time/local_clock.h>
32 #include "common_clock.h"
33 #include "diag_thread.h"
36 #define kListenPort 9876
38 static bool setNonblocking(int fd) {
39 int flags = fcntl(fd, F_GETFL);
40 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
41 ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
49 static bool setNodelay(int fd) {
51 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)) < 0) {
52 ALOGE("Failed to set socket (%d) to no-delay mode (errno %d)",
62 DiagThread::DiagThread(CommonClock* common_clock, LocalClock* local_clock) {
63 common_clock_ = common_clock;
64 local_clock_ = local_clock;
67 kernel_logID_basis_known_ = false;
68 discipline_log_ID_ = 0;
71 DiagThread::~DiagThread() {
74 status_t DiagThread::startWorkThread() {
80 ALOGE("Failed to start work thread (res = %d)", res);
85 void DiagThread::stopWorkThread() {
87 res = requestExitAndWait(); // block until thread exit.
89 ALOGE("Failed to stop work thread (res = %d)", res);
92 bool DiagThread::openListenSocket() {
95 cleanupListenSocket();
97 if ((listen_fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
98 ALOGE("Socket failed.");
102 // Set non-blocking operation
103 if (!setNonblocking(listen_fd_))
106 struct sockaddr_in addr;
107 memset(&addr, 0, sizeof(addr));
108 addr.sin_family = AF_INET;
109 addr.sin_addr.s_addr = INADDR_ANY;
110 addr.sin_port = htons(kListenPort);
112 if (bind(listen_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
113 ALOGE("Bind failed.");
117 if (listen(listen_fd_, 1) < 0) {
118 ALOGE("Listen failed.");
125 cleanupListenSocket();
130 void DiagThread::cleanupListenSocket() {
131 if (listen_fd_ >= 0) {
138 setsockopt(listen_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
139 shutdown(listen_fd_, SHUT_RDWR);
145 void DiagThread::cleanupDataSocket() {
153 setsockopt(data_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
154 shutdown(data_fd_, SHUT_RDWR);
160 void DiagThread::resetLogIDs() {
161 // Drain and discard all of the events from the kernel
162 struct local_time_debug_event events[kMaxEvents];
163 while(local_clock_->getDebugLog(events, kMaxEvents) > 0)
167 Mutex::Autolock lock(&discipline_log_lock_);
168 discipline_log_.clear();
169 discipline_log_ID_ = 0;
172 kernel_logID_basis_known_ = false;
175 void DiagThread::pushDisciplineEvent(int64_t observed_local_time,
176 int64_t observed_common_time,
177 int64_t nominal_common_time,
178 int32_t total_correction,
180 Mutex::Autolock lock(&discipline_log_lock_);
182 DisciplineEventRecord evt;
184 evt.event_id = discipline_log_ID_++;
186 evt.action_local_time = local_clock_->getLocalTime();
187 common_clock_->localToCommon(evt.action_local_time,
188 &evt.action_common_time);
190 evt.observed_local_time = observed_local_time;
191 evt.observed_common_time = observed_common_time;
192 evt.nominal_common_time = nominal_common_time;
193 evt.total_correction = total_correction;
196 discipline_log_.push_back(evt);
197 while (discipline_log_.size() > kMaxDisciplineLogSize)
198 discipline_log_.erase(discipline_log_.begin());
201 bool DiagThread::threadLoop() {
202 struct pollfd poll_fds[1];
204 if (!openListenSocket()) {
205 ALOGE("Failed to open listen socket");
209 while (!exitPending()) {
210 memset(&poll_fds, 0, sizeof(poll_fds));
213 poll_fds[0].fd = listen_fd_;
214 poll_fds[0].events = POLLIN;
216 poll_fds[0].fd = data_fd_;
217 poll_fds[0].events = POLLRDHUP | POLLIN;
220 int poll_res = poll(poll_fds, NELEM(poll_fds), 50);
222 ALOGE("Fatal error (%d,%d) while waiting on events",
230 if (poll_fds[0].revents) {
231 if (poll_fds[0].fd == listen_fd_) {
232 data_fd_ = accept(listen_fd_, NULL, NULL);
235 ALOGW("Failed accept on socket %d with err %d",
238 if (!setNonblocking(data_fd_))
240 if (!setNodelay(data_fd_))
244 if (poll_fds[0].fd == data_fd_) {
245 if (poll_fds[0].revents & POLLRDHUP) {
246 // Connection hung up; time to clean up.
249 if (poll_fds[0].revents & POLLIN) {
251 if (read(data_fd_, &cmd, sizeof(cmd)) > 0) {
263 struct local_time_debug_event events[kMaxEvents];
264 int amt = local_clock_->getDebugLog(events, kMaxEvents);
267 for (int i = 0; i < amt; i++) {
268 struct local_time_debug_event& e = events[i];
270 if (!kernel_logID_basis_known_) {
271 kernel_logID_basis_ = e.local_timesync_event_id;
272 kernel_logID_basis_known_ = true;
277 status_t res = common_clock_->localToCommon(e.local_time,
279 snprintf(buf, sizeof(buf), "E,%lld,%lld,%lld,%d\n",
280 e.local_timesync_event_id - kernel_logID_basis_,
283 (OK == res) ? 1 : 0);
284 buf[sizeof(buf) - 1] = 0;
287 write(data_fd_, buf, strlen(buf));
291 { // scope for autolock pattern
292 Mutex::Autolock lock(&discipline_log_lock_);
294 while (discipline_log_.size() > 0) {
296 DisciplineEventRecord& e = *discipline_log_.begin();
297 snprintf(buf, sizeof(buf),
298 "D,%lld,%lld,%lld,%lld,%lld,%lld,%d,%d\n",
301 e.action_common_time,
302 e.observed_local_time,
303 e.observed_common_time,
304 e.nominal_common_time,
307 buf[sizeof(buf) - 1] = 0;
310 write(data_fd_, buf, strlen(buf));
312 discipline_log_.erase(discipline_log_.begin());
319 cleanupListenSocket();
323 } // namespace android