Merge "Add KeepAlive Interval Measurement."

This commit is contained in:
Chung-yih Wang
2011-06-09 03:24:55 -07:00
committed by Android (Google) Code Review
2 changed files with 126 additions and 2 deletions

View File

@@ -82,6 +82,7 @@ public final class SipService extends ISipService.Stub {
private WifiScanProcess mWifiScanProcess;
private WifiManager.WifiLock mWifiLock;
private boolean mWifiOnly;
private IntervalMeasurementProcess mIntervalMeasurementProcess;
private MyExecutor mExecutor;
@@ -96,6 +97,7 @@ public final class SipService extends ISipService.Stub {
private ConnectivityReceiver mConnectivityReceiver;
private boolean mWifiEnabled;
private SipWakeLock mMyWakeLock;
private int mKeepAliveInterval;
/**
* Starts the SIP service. Do nothing if the SIP API is not supported on the
@@ -441,12 +443,14 @@ public final class SipService extends ISipService.Stub {
if (connected) {
mLocalIp = determineLocalIp();
mKeepAliveInterval = -1;
for (SipSessionGroupExt group : mSipGroups.values()) {
group.onConnectivityChanged(true);
}
if (isWifi && (mWifiLock != null)) stopWifiScanner();
} else {
mMyWakeLock.reset(); // in case there's a leak
stopPortMappingMeasurement();
if (isWifi && (mWifiLock != null)) startWifiScanner();
}
} catch (SipException e) {
@@ -454,6 +458,18 @@ public final class SipService extends ISipService.Stub {
}
}
private void stopPortMappingMeasurement() {
if (mIntervalMeasurementProcess != null) {
mIntervalMeasurementProcess.stop();
mIntervalMeasurementProcess = null;
}
}
private void startPortMappingLifetimeMeasurement(SipSessionGroup group) {
mIntervalMeasurementProcess = new IntervalMeasurementProcess(group);
mIntervalMeasurementProcess.start();
}
private synchronized void addPendingSession(ISipSession session) {
try {
cleanUpPendingSessions();
@@ -687,6 +703,93 @@ public final class SipService extends ISipService.Stub {
}
}
private class IntervalMeasurementProcess extends SipSessionAdapter
implements Runnable {
private static final String TAG = "\\INTERVAL/";
private static final int MAX_INTERVAL = 120; // seconds
private static final int MIN_INTERVAL = SHORT_EXPIRY_TIME;
private static final int PASS_THRESHOLD = 6;
private SipSessionGroupExt mGroup;
private SipSessionGroup.SipSessionImpl mSession;
private boolean mRunning;
private int mMinInterval = 10;
private int mMaxInterval = MAX_INTERVAL;
private int mInterval = MAX_INTERVAL / 2;
private int mPassCounter = 0;
private WakeupTimer mTimer = new WakeupTimer(mContext);
public IntervalMeasurementProcess(SipSessionGroup group) {
try {
mGroup = new SipSessionGroupExt(
group.getLocalProfile(), null, null);
mSession = (SipSessionGroup.SipSessionImpl)
mGroup.createSession(this);
} catch (Exception e) {
Log.w(TAG, "start interval measurement error: " + e);
}
}
public void start() {
if (mRunning) return;
mRunning = true;
mTimer.set(mInterval * 1000, this);
if (DEBUGV) Log.v(TAG, "start interval measurement");
run();
}
public void stop() {
mRunning = false;
mTimer.cancel(this);
}
private void restart() {
mTimer.cancel(this);
mTimer.set(mInterval * 1000, this);
}
private void calculateNewInterval() {
if (!mSession.isReRegisterRequired()) {
if (++mPassCounter != PASS_THRESHOLD) return;
// update the interval, since the current interval is good to
// keep the port mapping.
mKeepAliveInterval = mMinInterval = mInterval;
} else {
// Since the rport is changed, shorten the interval.
mSession.clearReRegisterRequired();
mMaxInterval = mInterval;
}
if ((mMaxInterval - mMinInterval) < MIN_INTERVAL) {
// update mKeepAliveInterval and stop measurement.
stop();
mKeepAliveInterval = mMinInterval;
if (DEBUGV) Log.v(TAG, "measured interval: " + mKeepAliveInterval);
} else {
// calculate the new interval and continue.
mInterval = (mMaxInterval + mMinInterval) / 2;
mPassCounter = 0;
if (DEBUGV) {
Log.v(TAG, " current interval: " + mKeepAliveInterval
+ "test new interval: " + mInterval);
}
restart();
}
}
public void run() {
synchronized (SipService.this) {
if (!mRunning) return;
try {
mSession.sendKeepAlive();
calculateNewInterval();
} catch (Throwable t) {
stop();
Log.w(TAG, "interval measurement error: " + t);
}
}
}
}
// KeepAliveProcess is controlled by AutoRegistrationProcess.
// All methods will be invoked in sync with SipService.this.
private class KeepAliveProcess implements Runnable {
@@ -694,6 +797,7 @@ public final class SipService extends ISipService.Stub {
private static final int INTERVAL = 10;
private SipSessionGroup.SipSessionImpl mSession;
private boolean mRunning = false;
private int mInterval = INTERVAL;
public KeepAliveProcess(SipSessionGroup.SipSessionImpl session) {
mSession = session;
@@ -705,6 +809,12 @@ public final class SipService extends ISipService.Stub {
mTimer.set(INTERVAL * 1000, this);
}
private void restart(int duration) {
if (DEBUG) Log.d(TAG, "Refresh NAT port mapping " + duration + "s later.");
mTimer.cancel(this);
mTimer.set(duration * 1000, this);
}
// timeout handler
public void run() {
synchronized (SipService.this) {
@@ -721,6 +831,10 @@ public final class SipService extends ISipService.Stub {
mMyWakeLock.acquire(mSession);
mSession.register(EXPIRY_TIME);
}
if (mKeepAliveInterval > mInterval) {
mInterval = mKeepAliveInterval;
restart(mInterval);
}
} catch (Throwable t) {
Log.w(TAG, "keepalive error: " + t);
}
@@ -761,6 +875,17 @@ public final class SipService extends ISipService.Stub {
// return right away if no active network connection.
if (mSession == null) return;
synchronized (SipService.this) {
if (isBehindNAT(mLocalIp)
&& (mIntervalMeasurementProcess == null)
&& (mKeepAliveInterval == -1)) {
// Start keep-alive interval measurement, here we allow
// the first profile only as the target service provider
// to measure the life time of NAT port mapping.
startPortMappingLifetimeMeasurement(group);
}
}
// start unregistration to clear up old registration at server
// TODO: when rfc5626 is deployed, use reg-id and sip.instance
// in registration to avoid adding duplicate entries to server

View File

@@ -397,7 +397,7 @@ class SipSessionGroup implements SipListener {
// for registration
boolean mReRegisterFlag = false;
int mRPort;
int mRPort = 0;
// lightweight timer
class SessionTimer {
@@ -447,7 +447,6 @@ class SipSessionGroup implements SipListener {
mState = SipSession.State.READY_TO_CALL;
mInviteReceived = null;
mPeerSessionDescription = null;
mRPort = 0;
mAuthenticationRetryCount = 0;
if (mDialog != null) mDialog.delete();