/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_COMMON_TIME_SERVER_H #define ANDROID_COMMON_TIME_SERVER_H #include <arpa/inet.h> #include <stdint.h> #include <sys/socket.h> #include <common_time/ICommonClock.h> #include <common_time/local_clock.h> #include <utils/String8.h> #include "clock_recovery.h" #include "common_clock.h" #include "common_time_server_packets.h" #include "utils.h" #define RTT_LOG_SIZE 30 namespace android { class CommonClockService; class CommonTimeConfigService; /***** time service implementation *****/ class CommonTimeServer : public Thread { public: CommonTimeServer(); ~CommonTimeServer(); bool startServices(); // Common Clock API methods CommonClock& getCommonClock() { return mCommonClock; } LocalClock& getLocalClock() { return mLocalClock; } uint64_t getTimelineID(); int32_t getEstimatedError(); ICommonClock::State getState(); status_t getMasterAddr(struct sockaddr_storage* addr); status_t isCommonTimeValid(bool* valid, uint32_t* timelineID); // Config API methods status_t getMasterElectionPriority(uint8_t *priority); status_t setMasterElectionPriority(uint8_t priority); status_t getMasterElectionEndpoint(struct sockaddr_storage *addr); status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr); status_t getMasterElectionGroupId(uint64_t *id); status_t setMasterElectionGroupId(uint64_t id); status_t getInterfaceBinding(String8& ifaceName); status_t setInterfaceBinding(const String8& ifaceName); status_t getMasterAnnounceInterval(int *interval); status_t setMasterAnnounceInterval(int interval); status_t getClientSyncInterval(int *interval); status_t setClientSyncInterval(int interval); status_t getPanicThreshold(int *threshold); status_t setPanicThreshold(int threshold); status_t getAutoDisable(bool *autoDisable); status_t setAutoDisable(bool autoDisable); status_t forceNetworklessMasterMode(); // Method used by the CommonClockService to notify the core service about // changes in the number of active common clock clients. void reevaluateAutoDisableState(bool commonClockHasClients); status_t dumpClockInterface(int fd, const Vector<String16>& args, size_t activeClients); status_t dumpConfigInterface(int fd, const Vector<String16>& args); private: class PacketRTTLog { public: PacketRTTLog() { resetLog(); } void resetLog() { wrPtr = 0; logFull = 0; } void logTX(int64_t txTime); void logRX(int64_t txTime, int64_t rxTime); void dumpLog(int fd, const CommonClock& cclk); private: uint32_t wrPtr; bool logFull; int64_t txTimes[RTT_LOG_SIZE]; int64_t rxTimes[RTT_LOG_SIZE]; }; bool threadLoop(); bool runStateMachine_l(); bool setupSocket_l(); void assignTimelineID(); bool assignDeviceID(); static bool arbitrateMaster(uint64_t deviceID1, uint8_t devicePrio1, uint64_t deviceID2, uint8_t devicePrio2); bool handlePacket(); bool handleWhoIsMasterRequest (const WhoIsMasterRequestPacket* request, const sockaddr_storage& srcAddr); bool handleWhoIsMasterResponse(const WhoIsMasterResponsePacket* response, const sockaddr_storage& srcAddr); bool handleSyncRequest (const SyncRequestPacket* request, const sockaddr_storage& srcAddr); bool handleSyncResponse (const SyncResponsePacket* response, const sockaddr_storage& srcAddr); bool handleMasterAnnouncement (const MasterAnnouncementPacket* packet, const sockaddr_storage& srcAddr); bool handleTimeout(); bool handleTimeoutInitial(); bool handleTimeoutClient(); bool handleTimeoutMaster(); bool handleTimeoutRonin(); bool handleTimeoutWaitForElection(); bool sendWhoIsMasterRequest(); bool sendSyncRequest(); bool sendMasterAnnouncement(); bool becomeClient(const sockaddr_storage& masterAddr, uint64_t masterDeviceID, uint8_t masterDevicePriority, uint64_t timelineID, const char* cause); bool becomeMaster(const char* cause); bool becomeRonin(const char* cause); bool becomeWaitForElection(const char* cause); bool becomeInitial(const char* cause); void notifyClockSync(); void notifyClockSyncLoss(); ICommonClock::State mState; void setState(ICommonClock::State s); void clearPendingWakeupEvents_l(); void wakeupThread_l(); void cleanupSocket_l(); void shutdownThread(); inline uint8_t effectivePriority() const { return (mMasterPriority & 0x7F) | (mForceLowPriority ? 0x00 : 0x80); } inline bool shouldAutoDisable() const { return (mAutoDisable && !mCommonClockHasClients); } inline void resetSyncStats() { mClient_SyncRequestPending = false; mClient_SyncRequestTimeouts = 0; mClient_SyncsSentToCurMaster = 0; mClient_SyncRespsRXedFromCurMaster = 0; mClient_ExpiredSyncRespsRXedFromCurMaster = 0; mClient_FirstSyncTX = 0; mClient_LastGoodSyncRX = 0; mClient_PacketRTTLog.resetLog(); } bool shouldPanicNotGettingGoodData(); // Helper to keep track of the state machine's current timeout Timeout mCurTimeout; // common clock, local clock abstraction, and clock recovery loop CommonClock mCommonClock; LocalClock mLocalClock; ClockRecoveryLoop mClockRecovery; // implementation of ICommonClock sp<CommonClockService> mICommonClock; // implementation of ICommonTimeConfig sp<CommonTimeConfigService> mICommonTimeConfig; // UDP socket for the time sync protocol int mSocket; // eventfd used to wakeup the work thread in response to configuration // changes. int mWakeupThreadFD; // timestamp captured when a packet is received int64_t mLastPacketRxLocalTime; // ID of the timeline that this device is following uint64_t mTimelineID; // flag for whether the clock has been synced to a timeline bool mClockSynced; // flag used to indicate that clients should be considered to be lower // priority than all of their peers during elections. This flag is set and // cleared by the state machine. It is set when the client joins a new // network. If the client had been a master in the old network (or an // isolated master with no network connectivity) it should defer to any // masters which may already be on the network. It will be cleared whenever // the state machine transitions to the master state. bool mForceLowPriority; inline void setForceLowPriority(bool val) { mForceLowPriority = val; if (mState == ICommonClock::STATE_MASTER) mClient_MasterDevicePriority = effectivePriority(); } // Lock to synchronize access to internal state and configuration. Mutex mLock; // Flag updated by the common clock service to indicate that it does or does // not currently have registered clients. When the the auto disable flag is // cleared on the common time service, the service will participate in // network synchronization whenever it has a valid network interface to bind // to. When the auto disable flag is set on the common time service, it // will only participate in network synchronization when it has both a valid // interface AND currently active common clock clients. bool mCommonClockHasClients; // Internal logs used for dumpsys. LogRing mStateChangeLog; LogRing mElectionLog; LogRing mBadPktLog; // Configuration info struct sockaddr_storage mMasterElectionEP; // Endpoint over which we conduct master election String8 mBindIface; // Endpoint for the service to bind to. bool mBindIfaceValid; // whether or not the bind Iface is valid. bool mBindIfaceDirty; // whether or not the bind Iface is valid. struct sockaddr_storage mMasterEP; // Endpoint of our current master (if any) bool mMasterEPValid; uint64_t mDeviceID; // unique ID of this device uint64_t mSyncGroupID; // synchronization group ID of this device. uint8_t mMasterPriority; // Priority of this device in master election. uint32_t mMasterAnnounceIntervalMs; uint32_t mSyncRequestIntervalMs; uint32_t mPanicThresholdUsec; bool mAutoDisable; // Config defaults. static const char* kDefaultMasterElectionAddr; static const uint16_t kDefaultMasterElectionPort; static const uint64_t kDefaultSyncGroupID; static const uint8_t kDefaultMasterPriority; static const uint32_t kDefaultMasterAnnounceIntervalMs; static const uint32_t kDefaultSyncRequestIntervalMs; static const uint32_t kDefaultPanicThresholdUsec; static const bool kDefaultAutoDisable; // Priority mask and shift fields. static const uint64_t kDeviceIDMask; static const uint8_t kDevicePriorityMask; static const uint8_t kDevicePriorityHiLowBit; static const uint32_t kDevicePriorityShift; // Unconfgurable constants static const int kSetupRetryTimeoutMs; static const int64_t kNoGoodDataPanicThresholdUsec; static const uint32_t kRTTDiscardPanicThreshMultiplier; /*** status while in the Initial state ***/ int mInitial_WhoIsMasterRequestTimeouts; static const int kInitial_NumWhoIsMasterRetries; static const int kInitial_WhoIsMasterTimeoutMs; /*** status while in the Client state ***/ uint64_t mClient_MasterDeviceID; uint8_t mClient_MasterDevicePriority; bool mClient_SyncRequestPending; int mClient_SyncRequestTimeouts; uint32_t mClient_SyncsSentToCurMaster; uint32_t mClient_SyncRespsRXedFromCurMaster; uint32_t mClient_ExpiredSyncRespsRXedFromCurMaster; int64_t mClient_FirstSyncTX; int64_t mClient_LastGoodSyncRX; PacketRTTLog mClient_PacketRTTLog; static const int kClient_NumSyncRequestRetries; /*** status while in the Master state ***/ static const uint32_t kDefaultMaster_AnnouncementIntervalMs; /*** status while in the Ronin state ***/ int mRonin_WhoIsMasterRequestTimeouts; static const int kRonin_NumWhoIsMasterRetries; static const int kRonin_WhoIsMasterTimeoutMs; /*** status while in the WaitForElection state ***/ static const int kWaitForElection_TimeoutMs; static const int kInfiniteTimeout; static const char* stateToString(ICommonClock::State s); static void sockaddrToString(const sockaddr_storage& addr, bool addrValid, char* buf, size_t bufLen); static bool sockaddrMatch(const sockaddr_storage& a1, const sockaddr_storage& a2, bool matchAddressOnly); }; } // namespace android #endif // ANDROID_COMMON_TIME_SERVER_H