summaryrefslogtreecommitdiffstats
path: root/voip/java
diff options
context:
space:
mode:
authorChung-yih Wang <cywang@google.com>2011-03-10 11:33:39 +0800
committerrepo sync <cywang@google.com>2011-06-09 18:19:07 +0800
commitbb0a989c17cd6135c8d9c8566507521d4d927fe0 (patch)
treed6ade1871b2506ffc8ece9baa88fe85cc7417baa /voip/java
parent2db439bdd819c99a0c96c8c60ff49be5727d9471 (diff)
downloadframeworks_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.java125
-rw-r--r--voip/java/com/android/server/sip/SipSessionGroup.java3
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();