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