1//
2// Copyright (C) 2012 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 "shill/net/shill_time.h"
18
19#include <string.h>
20#include <time.h>
21
22#include <base/format_macros.h>
23#include <base/strings/stringprintf.h>
24
25using std::string;
26
27namespace shill {
28
29namespace {
30
31// As Time may be instantiated by MemoryLogMessage during a callback of
32// AtExitManager, it needs to be a leaky singleton to avoid
33// AtExitManager::RegisterCallback() from potentially being called within a
34// callback of AtExitManager, which will lead to a crash. Making Time leaky is
35// fine as it does not need to clean up or release any resource at destruction.
36base::LazyInstance<Time>::Leaky g_time = LAZY_INSTANCE_INITIALIZER;
37
38}  // namespace
39
40Time::Time() { }
41
42Time::~Time() { }
43
44Time* Time::GetInstance() {
45  return g_time.Pointer();
46}
47
48bool Time::GetSecondsMonotonic(time_t* seconds) {
49  struct timeval now;
50  if (GetTimeMonotonic(&now) < 0) {
51    return false;
52  } else {
53    *seconds = now.tv_sec;
54    return true;
55  }
56}
57
58bool Time::GetSecondsBoottime(time_t* seconds) {
59  struct timeval now;
60  if (GetTimeBoottime(&now) < 0) {
61    return false;
62  } else {
63    *seconds = now.tv_sec;
64    return true;
65  }
66}
67
68int Time::GetTimeMonotonic(struct timeval* tv) {
69  struct timespec ts;
70  if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
71    return -1;
72  }
73
74  tv->tv_sec = ts.tv_sec;
75  tv->tv_usec = ts.tv_nsec / 1000;
76  return 0;
77}
78
79int Time::GetTimeBoottime(struct timeval* tv) {
80  struct timespec ts;
81  if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) {
82    return -1;
83  }
84
85  tv->tv_sec = ts.tv_sec;
86  tv->tv_usec = ts.tv_nsec / 1000;
87  return 0;
88}
89
90int Time::GetTimeOfDay(struct timeval* tv, struct timezone* tz) {
91  return gettimeofday(tv, tz);
92}
93
94Timestamp Time::GetNow() {
95  struct timeval now_monotonic = {};
96  struct timeval now_boottime = {};
97  struct timeval now_wall_clock = {};
98  struct tm local_time = {};
99  string wall_clock_string;
100
101  GetTimeMonotonic(&now_monotonic);
102  GetTimeBoottime(&now_boottime);
103  GetTimeOfDay(&now_wall_clock, nullptr);
104  localtime_r(&now_wall_clock.tv_sec, &local_time);
105  wall_clock_string = FormatTime(local_time, now_wall_clock.tv_usec);
106
107  return Timestamp(now_monotonic, now_boottime, wall_clock_string);
108}
109
110// static
111string Time::FormatTime(const struct tm& date_time, suseconds_t usec) {
112  char date_time_string[64];
113  size_t date_time_length;
114  date_time_length = strftime(date_time_string, sizeof(date_time_string),
115                              "%Y-%m-%dT%H:%M:%S %z", &date_time);
116
117  // Stitch in the microseconds, to provider finer resolution than
118  // strftime allows.
119  string full_string = "<unknown>";
120  char* split_pos = static_cast<char*>(
121      memchr(date_time_string, ' ', sizeof(date_time_string)));
122  if (date_time_length && date_time_length < sizeof(date_time_string) &&
123      split_pos) {
124    *split_pos = '\0';
125    full_string =
126        base::StringPrintf("%s.%06" PRIu64 "%s", date_time_string,
127                           static_cast<uint64_t>(usec), split_pos + 1);
128  }
129
130  return full_string;
131}
132
133time_t Time::GetSecondsSinceEpoch() const {
134  return time(nullptr);
135}
136
137}  // namespace shill
138