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/*
18 * A service that exchanges time synchronization information between
19 * a master that defines a timeline and clients that follow the timeline.
20 */
21
22#define LOG_TAG "common_time"
23#include <utils/Log.h>
24
25#include <binder/IServiceManager.h>
26#include <binder/IPCThreadState.h>
27
28#include "common_time_server.h"
29
30#include <inttypes.h>
31
32namespace android {
33
34//
35// Clock API
36//
37uint64_t CommonTimeServer::getTimelineID() {
38    AutoMutex _lock(&mLock);
39    return mTimelineID;
40}
41
42ICommonClock::State CommonTimeServer::getState() {
43    AutoMutex _lock(&mLock);
44    return mState;
45}
46
47status_t CommonTimeServer::getMasterAddr(struct sockaddr_storage* addr) {
48    AutoMutex _lock(&mLock);
49    if (mMasterEPValid) {
50        memcpy(addr, &mMasterEP, sizeof(*addr));
51        return OK;
52    }
53
54    return UNKNOWN_ERROR;
55}
56
57int32_t CommonTimeServer::getEstimatedError() {
58    AutoMutex _lock(&mLock);
59
60    if (ICommonClock::STATE_MASTER == mState)
61        return 0;
62
63    if (!mClockSynced)
64        return ICommonClock::kErrorEstimateUnknown;
65
66    return mClockRecovery.getLastErrorEstimate();
67}
68
69status_t CommonTimeServer::isCommonTimeValid(bool* valid,
70                                             uint32_t* timelineID) {
71    AutoMutex _lock(&mLock);
72    *valid = mCommonClock.isValid();
73    *timelineID = mTimelineID;
74    return OK;
75}
76
77//
78// Config API
79//
80status_t CommonTimeServer::getMasterElectionPriority(uint8_t *priority) {
81    AutoMutex _lock(&mLock);
82    *priority = mMasterPriority;
83    return OK;
84}
85
86status_t CommonTimeServer::setMasterElectionPriority(uint8_t priority) {
87    AutoMutex _lock(&mLock);
88
89    if (priority > 0x7F)
90        return BAD_VALUE;
91
92    mMasterPriority = priority;
93    return OK;
94}
95
96status_t CommonTimeServer::getMasterElectionEndpoint(
97        struct sockaddr_storage *addr) {
98    AutoMutex _lock(&mLock);
99    memcpy(addr, &mMasterElectionEP, sizeof(*addr));
100    return OK;
101}
102
103status_t CommonTimeServer::setMasterElectionEndpoint(
104        const struct sockaddr_storage *addr) {
105    AutoMutex _lock(&mLock);
106
107    if (!addr)
108        return BAD_VALUE;
109
110    // TODO: add proper support for IPv6
111    if (addr->ss_family != AF_INET)
112        return BAD_VALUE;
113
114    // Only multicast and broadcast endpoints with explicit ports are allowed.
115    uint16_t ipv4Port = ntohs(
116        reinterpret_cast<const struct sockaddr_in*>(addr)->sin_port);
117    if (!ipv4Port)
118        return BAD_VALUE;
119
120    uint32_t ipv4Addr = ntohl(
121        reinterpret_cast<const struct sockaddr_in*>(addr)->sin_addr.s_addr);
122    if ((ipv4Addr != 0xFFFFFFFF) && (0xE0000000 != (ipv4Addr & 0xF0000000)))
123        return BAD_VALUE;
124
125    memcpy(&mMasterElectionEP, addr, sizeof(mMasterElectionEP));
126
127    // Force a rebind in order to change election enpoints.
128    mBindIfaceDirty = true;
129    wakeupThread_l();
130    return OK;
131}
132
133status_t CommonTimeServer::getMasterElectionGroupId(uint64_t *id) {
134    AutoMutex _lock(&mLock);
135    *id = mSyncGroupID;
136    return OK;
137}
138
139status_t CommonTimeServer::setMasterElectionGroupId(uint64_t id) {
140    AutoMutex _lock(&mLock);
141    mSyncGroupID = id;
142    return OK;
143}
144
145status_t CommonTimeServer::getInterfaceBinding(String8& ifaceName) {
146    AutoMutex _lock(&mLock);
147    if (!mBindIfaceValid)
148        return INVALID_OPERATION;
149    ifaceName = mBindIface;
150    return OK;
151}
152
153status_t CommonTimeServer::setInterfaceBinding(const String8& ifaceName) {
154    AutoMutex _lock(&mLock);
155
156    mBindIfaceDirty = true;
157    if (ifaceName.size()) {
158        mBindIfaceValid = true;
159        mBindIface = ifaceName;
160    } else {
161        mBindIfaceValid = false;
162        mBindIface.clear();
163    }
164
165    wakeupThread_l();
166    return OK;
167}
168
169status_t CommonTimeServer::getMasterAnnounceInterval(int *interval) {
170    AutoMutex _lock(&mLock);
171    *interval = mMasterAnnounceIntervalMs;
172    return OK;
173}
174
175status_t CommonTimeServer::setMasterAnnounceInterval(int interval) {
176    AutoMutex _lock(&mLock);
177
178    if (interval > (6 *3600000)) // Max interval is once every 6 hrs
179        return BAD_VALUE;
180
181    if (interval < 500) // Min interval is once per 0.5 seconds
182        return BAD_VALUE;
183
184    mMasterAnnounceIntervalMs = interval;
185    if (ICommonClock::STATE_MASTER == mState) {
186        int pendingTimeout = mCurTimeout.msecTillTimeout();
187        if ((kInfiniteTimeout == pendingTimeout) ||
188            (pendingTimeout > interval)) {
189            mCurTimeout.setTimeout(mMasterAnnounceIntervalMs);
190            wakeupThread_l();
191        }
192    }
193
194    return OK;
195}
196
197status_t CommonTimeServer::getClientSyncInterval(int *interval) {
198    AutoMutex _lock(&mLock);
199    *interval = mSyncRequestIntervalMs;
200    return OK;
201}
202
203status_t CommonTimeServer::setClientSyncInterval(int interval) {
204    AutoMutex _lock(&mLock);
205
206    if (interval > (3600000)) // Max interval is once every 60 min
207        return BAD_VALUE;
208
209    if (interval < 250) // Min interval is once per 0.25 seconds
210        return BAD_VALUE;
211
212    mSyncRequestIntervalMs = interval;
213    if (ICommonClock::STATE_CLIENT == mState) {
214        int pendingTimeout = mCurTimeout.msecTillTimeout();
215        if ((kInfiniteTimeout == pendingTimeout) ||
216            (pendingTimeout > interval)) {
217            mCurTimeout.setTimeout(mSyncRequestIntervalMs);
218            wakeupThread_l();
219        }
220    }
221
222    return OK;
223}
224
225status_t CommonTimeServer::getPanicThreshold(int *threshold) {
226    AutoMutex _lock(&mLock);
227    *threshold = mPanicThresholdUsec;
228    return OK;
229}
230
231status_t CommonTimeServer::setPanicThreshold(int threshold) {
232    AutoMutex _lock(&mLock);
233
234    if (threshold < 1000) // Min threshold is 1mSec
235        return BAD_VALUE;
236
237    mPanicThresholdUsec = threshold;
238    return OK;
239}
240
241status_t CommonTimeServer::getAutoDisable(bool *autoDisable) {
242    AutoMutex _lock(&mLock);
243    *autoDisable = mAutoDisable;
244    return OK;
245}
246
247status_t CommonTimeServer::setAutoDisable(bool autoDisable) {
248    AutoMutex _lock(&mLock);
249    mAutoDisable = autoDisable;
250    wakeupThread_l();
251    return OK;
252}
253
254status_t CommonTimeServer::forceNetworklessMasterMode() {
255    AutoMutex _lock(&mLock);
256
257    // Can't force networkless master mode if we are currently bound to a
258    // network.
259    if (mSocket >= 0)
260        return INVALID_OPERATION;
261
262    becomeMaster("force networkless");
263
264    return OK;
265}
266
267void CommonTimeServer::reevaluateAutoDisableState(bool commonClockHasClients) {
268    AutoMutex _lock(&mLock);
269    bool needWakeup = (mAutoDisable && mMasterEPValid &&
270                      (commonClockHasClients != mCommonClockHasClients));
271
272    mCommonClockHasClients = commonClockHasClients;
273
274    if (needWakeup) {
275        ALOGI("Waking up service, auto-disable is engaged and service now has%s"
276             " clients", mCommonClockHasClients ? "" : " no");
277        wakeupThread_l();
278    }
279}
280
281#define dump_printf(a, b...) do {                 \
282    int res;                                      \
283    res = snprintf(buffer, sizeof(buffer), a, b); \
284    buffer[sizeof(buffer) - 1] = 0;               \
285    if (res > 0)                                  \
286        write(fd, buffer, res);                   \
287} while (0)
288#define checked_percentage(a, b) ((0 == (b)) ? 0.0f : ((100.0f * (a)) / (b)))
289
290status_t CommonTimeServer::dumpClockInterface(int fd,
291                                              const Vector<String16>& /* args */,
292                                              size_t activeClients) {
293    AutoMutex _lock(&mLock);
294    const size_t SIZE = 256;
295    char buffer[SIZE];
296
297    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
298        snprintf(buffer, SIZE, "Permission Denial: "
299                 "can't dump CommonClockService from pid=%d, uid=%d\n",
300                 IPCThreadState::self()->getCallingPid(),
301                 IPCThreadState::self()->getCallingUid());
302        write(fd, buffer, strlen(buffer));
303    } else {
304        int64_t commonTime;
305        int64_t localTime;
306        bool    synced;
307        char maStr[64];
308
309        localTime  = mLocalClock.getLocalTime();
310        synced     = (OK == mCommonClock.localToCommon(localTime, &commonTime));
311        sockaddrToString(mMasterEP, mMasterEPValid, maStr, sizeof(maStr));
312
313        dump_printf("Common Clock Service Status\nLocal time     : %" PRId64 "\n",
314                    localTime);
315
316        if (synced)
317            dump_printf("Common time    : %" PRId64 "\n", commonTime);
318        else
319            dump_printf("Common time    : %s\n", "not synced");
320
321        dump_printf("Timeline ID    : %016" PRIu64 "\n", mTimelineID);
322        dump_printf("State          : %s\n", stateToString(mState));
323        dump_printf("Master Addr    : %s\n", maStr);
324
325
326        if (synced) {
327            int32_t est = (ICommonClock::STATE_MASTER != mState)
328                        ? mClockRecovery.getLastErrorEstimate()
329                        : 0;
330            dump_printf("Error Est.     : %.3f msec\n",
331                        static_cast<float>(est) / 1000.0);
332        } else {
333            dump_printf("Error Est.     : %s\n", "unknown");
334        }
335
336        dump_printf("Syncs TXes     : %u\n", mClient_SyncsSentToCurMaster);
337        dump_printf("Syncs RXes     : %u (%.2f%%)\n",
338                    mClient_SyncRespsRXedFromCurMaster,
339                    checked_percentage(
340                        mClient_SyncRespsRXedFromCurMaster,
341                        mClient_SyncsSentToCurMaster));
342        dump_printf("RXs Expired    : %u (%.2f%%)\n",
343                    mClient_ExpiredSyncRespsRXedFromCurMaster,
344                    checked_percentage(
345                        mClient_ExpiredSyncRespsRXedFromCurMaster,
346                        mClient_SyncsSentToCurMaster));
347
348        if (!mClient_LastGoodSyncRX) {
349            dump_printf("Last Good RX   : %s\n", "unknown");
350        } else {
351            int64_t localDelta, usecDelta;
352            localDelta = localTime - mClient_LastGoodSyncRX;
353            usecDelta  = mCommonClock.localDurationToCommonDuration(localDelta);
354            dump_printf("Last Good RX   : %" PRId64 " uSec ago\n", usecDelta);
355        }
356
357        dump_printf("Active Clients : %zu\n", activeClients);
358        mClient_PacketRTTLog.dumpLog(fd, mCommonClock);
359        mStateChangeLog.dumpLog(fd);
360        mElectionLog.dumpLog(fd);
361        mBadPktLog.dumpLog(fd);
362    }
363
364    return NO_ERROR;
365}
366
367status_t CommonTimeServer::dumpConfigInterface(int fd,
368                                               const Vector<String16>& /* args */) {
369    AutoMutex _lock(&mLock);
370    const size_t SIZE = 256;
371    char buffer[SIZE];
372
373    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
374        snprintf(buffer, SIZE, "Permission Denial: "
375                 "can't dump CommonTimeConfigService from pid=%d, uid=%d\n",
376                 IPCThreadState::self()->getCallingPid(),
377                 IPCThreadState::self()->getCallingUid());
378        write(fd, buffer, strlen(buffer));
379    } else {
380        char meStr[64];
381
382        sockaddrToString(mMasterElectionEP, true, meStr, sizeof(meStr));
383
384        dump_printf("Common Time Config Service Status\n"
385                    "Bound Interface           : %s\n",
386                    mBindIfaceValid ? mBindIface.string() : "<unbound>");
387        dump_printf("Master Election Endpoint  : %s\n", meStr);
388        dump_printf("Master Election Group ID  : %016" PRIu64 "\n", mSyncGroupID);
389        dump_printf("Master Announce Interval  : %d mSec\n",
390                    mMasterAnnounceIntervalMs);
391        dump_printf("Client Sync Interval      : %d mSec\n",
392                    mSyncRequestIntervalMs);
393        dump_printf("Panic Threshold           : %d uSec\n",
394                    mPanicThresholdUsec);
395        dump_printf("Base ME Prio              : 0x%02x\n",
396                    static_cast<uint32_t>(mMasterPriority));
397        dump_printf("Effective ME Prio         : 0x%02x\n",
398                    static_cast<uint32_t>(effectivePriority()));
399        dump_printf("Auto Disable Allowed      : %s\n",
400                    mAutoDisable ? "yes" : "no");
401        dump_printf("Auto Disable Engaged      : %s\n",
402                    shouldAutoDisable() ? "yes" : "no");
403    }
404
405    return NO_ERROR;
406}
407
408void CommonTimeServer::PacketRTTLog::dumpLog(int fd, const CommonClock& cclk) {
409    const size_t SIZE = 256;
410    char buffer[SIZE];
411    uint32_t avail = !logFull ? wrPtr : RTT_LOG_SIZE;
412
413    if (!avail)
414        return;
415
416    dump_printf("\nPacket Log (%d entries)\n", avail);
417
418    uint32_t ndx = 0;
419    uint32_t i = logFull ? wrPtr : 0;
420    do {
421        if (rxTimes[i]) {
422            int64_t delta = rxTimes[i] - txTimes[i];
423            int64_t deltaUsec = cclk.localDurationToCommonDuration(delta);
424            dump_printf("pkt[%2d] : localTX %12" PRId64 " localRX %12" PRId64 " "
425                        "(%.3f msec RTT)\n",
426                        ndx, txTimes[i], rxTimes[i],
427                        static_cast<float>(deltaUsec) / 1000.0);
428        } else {
429            dump_printf("pkt[%2d] : localTX %12" PRId64 " localRX never\n",
430                        ndx, txTimes[i]);
431        }
432        i = (i + 1) % RTT_LOG_SIZE;
433        ndx++;
434    } while (i != wrPtr);
435}
436
437#undef dump_printf
438#undef checked_percentage
439
440}  // namespace android
441