Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff90f107 authored by Chung-yih Wang's avatar Chung-yih Wang Committed by Android (Google) Code Review
Browse files

Merge "Add KeepAlive Interval Measurement."

parents d4f1bacc bb0a989c
Loading
Loading
Loading
Loading
+125 −0
Original line number Diff line number Diff line
@@ -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
+1 −2
Original line number Diff line number Diff line
@@ -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();