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#define LOG_TAG "common_time"
18#include <utils/Log.h>
19
20#include "utils.h"
21
22namespace android {
23
24void Timeout::setTimeout(int msec) {
25    if (msec < 0) {
26        mSystemEndTime = 0;
27        return;
28    }
29
30    mSystemEndTime = systemTime() + (static_cast<nsecs_t>(msec) * 1000000);
31}
32
33int Timeout::msecTillTimeout(nsecs_t nowTime) {
34    if (!mSystemEndTime) {
35        return -1;
36    }
37
38    if (mSystemEndTime < nowTime) {
39        return 0;
40    }
41
42    nsecs_t delta = mSystemEndTime - nowTime;
43    delta += 999999;
44    delta /= 1000000;
45    if (delta > 0x7FFFFFFF) {
46        return 0x7FFFFFFF;
47    }
48
49    return static_cast<int>(delta);
50}
51
52LogRing::LogRing(const char* header, size_t entries)
53    : mSize(entries)
54    , mWr(0)
55    , mIsFull(false)
56    , mHeader(header) {
57    mRingBuffer = new Entry[mSize];
58    if (NULL == mRingBuffer)
59        ALOGE("Failed to allocate log ring with %u entries.", mSize);
60}
61
62LogRing::~LogRing() {
63    if (NULL != mRingBuffer)
64        delete[] mRingBuffer;
65}
66
67void LogRing::log(int prio, const char* tag, const char* fmt, ...) {
68    va_list argp;
69    va_start(argp, fmt);
70    internalLog(prio, tag, fmt, argp);
71    va_end(argp);
72}
73
74void LogRing::log(const char* fmt, ...) {
75    va_list argp;
76    va_start(argp, fmt);
77    internalLog(0, NULL, fmt, argp);
78    va_end(argp);
79}
80
81void LogRing::internalLog(int prio,
82                          const char* tag,
83                          const char* fmt,
84                          va_list argp) {
85    if (NULL != mRingBuffer) {
86        Mutex::Autolock lock(&mLock);
87        String8 s(String8::formatV(fmt, argp));
88        Entry* last = NULL;
89
90        if (mIsFull || mWr)
91            last = &(mRingBuffer[(mWr + mSize - 1) % mSize]);
92
93
94        if ((NULL != last) && !last->s.compare(s)) {
95            gettimeofday(&(last->last_ts), NULL);
96            ++last->count;
97        } else {
98            gettimeofday(&mRingBuffer[mWr].first_ts, NULL);
99            mRingBuffer[mWr].last_ts = mRingBuffer[mWr].first_ts;
100            mRingBuffer[mWr].count = 1;
101            mRingBuffer[mWr].s.setTo(s);
102
103            mWr = (mWr + 1) % mSize;
104            if (!mWr)
105                mIsFull = true;
106        }
107    }
108
109    if (NULL != tag)
110        LOG_PRI_VA(prio, tag, fmt, argp);
111}
112
113void LogRing::dumpLog(int fd) {
114    if (NULL == mRingBuffer)
115        return;
116
117    Mutex::Autolock lock(&mLock);
118
119    if (!mWr && !mIsFull)
120        return;
121
122    char buf[1024];
123    int res;
124    size_t start = mIsFull ? mWr : 0;
125    size_t count = mIsFull ? mSize : mWr;
126    static const char* kTimeFmt = "%a %b %d %Y %H:%M:%S";
127
128    res = snprintf(buf, sizeof(buf), "\n%s\n", mHeader);
129    if (res > 0)
130        write(fd, buf, res);
131
132    for (size_t i = 0; i < count; ++i) {
133        struct tm t;
134        char timebuf[64];
135        char repbuf[96];
136        size_t ndx = (start + i) % mSize;
137
138        if (1 != mRingBuffer[ndx].count) {
139            localtime_r(&mRingBuffer[ndx].last_ts.tv_sec, &t);
140            strftime(timebuf, sizeof(timebuf), kTimeFmt, &t);
141            snprintf(repbuf, sizeof(repbuf),
142                    " (repeated %d times, last was %s.%03ld)",
143                     mRingBuffer[ndx].count,
144                     timebuf,
145                     mRingBuffer[ndx].last_ts.tv_usec / 1000);
146            repbuf[sizeof(repbuf) - 1] = 0;
147        } else {
148            repbuf[0] = 0;
149        }
150
151        localtime_r(&mRingBuffer[ndx].first_ts.tv_sec, &t);
152        strftime(timebuf, sizeof(timebuf), kTimeFmt, &t);
153        res = snprintf(buf, sizeof(buf), "[%2d] %s.%03ld :: %s%s\n",
154                       i, timebuf,
155                       mRingBuffer[ndx].first_ts.tv_usec / 1000,
156                       mRingBuffer[ndx].s.string(),
157                       repbuf);
158
159        if (res > 0)
160            write(fd, buf, res);
161    }
162}
163
164}  // namespace android
165