diff options
author | Chung-yih Wang <cywang@google.com> | 2011-03-10 11:33:39 +0800 |
---|---|---|
committer | repo sync <cywang@google.com> | 2011-06-09 18:19:07 +0800 |
commit | bb0a989c17cd6135c8d9c8566507521d4d927fe0 (patch) | |
tree | d6ade1871b2506ffc8ece9baa88fe85cc7417baa /voip/java | |
parent | 2db439bdd819c99a0c96c8c60ff49be5727d9471 (diff) | |
download | frameworks_base-bb0a989c17cd6135c8d9c8566507521d4d927fe0.zip frameworks_base-bb0a989c17cd6135c8d9c8566507521d4d927fe0.tar.gz frameworks_base-bb0a989c17cd6135c8d9c8566507521d4d927fe0.tar.bz2 |
Add KeepAlive Interval Measurement.
Change-Id: Id5ea2fcfa0bcd45198e773a5842d39eacc8ae400
Diffstat (limited to 'voip/java')
-rw-r--r-- | voip/java/com/android/server/sip/SipService.java | 125 | ||||
-rw-r--r-- | voip/java/com/android/server/sip/SipSessionGroup.java | 3 |
2 files changed, 126 insertions, 2 deletions
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java index dc66989..afa696c 100644 --- a/voip/java/com/android/server/sip/SipService.java +++ b/voip/java/com/android/server/sip/SipService.java @@ -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 diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index aa616a9..b5f1a17 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -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(); |