/*
* 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