/** * Disconnect from IMS network interface * * @throws PayloadException * @throws NetworkException * @throws ContactManagerException */ private void disconnectFromIms() throws PayloadException, NetworkException, ContactManagerException { // Stop the IMS connection stopImsConnection(TerminationReason.TERMINATION_BY_CONNECTION_LOST); // Registration terminated mCurrentNetworkInterface.registrationTerminated(); // Disconnect from the network access mCurrentNetworkInterface.getNetworkAccess().disconnect(); }
/** * Connect to IMS network interface * * @param ipAddr IP address * @throws CertificateException * @throws IOException */ private void connectToIms(String ipAddr) throws CertificateException, IOException { // Connected to the network access mCurrentNetworkInterface.getNetworkAccess().connect(ipAddr); // Start the IMS connection startImsConnection(); }
/** Load the user profile associated to the network interface */ private void loadUserProfile() { ImsModule.setImsUserProfile(mCurrentNetworkInterface.getUserProfile()); RtpSource.setCname(ImsModule.getImsUserProfile().getPublicUri()); if (sLogger.isActivated()) { sLogger.debug("User profile has been reloaded"); } }
/** * Terminate the connection manager * * @throws PayloadException * @throws NetworkException * @throws ContactManagerException */ public void terminate() throws PayloadException, NetworkException, ContactManagerException { if (sLogger.isActivated()) { sLogger.info("Terminate the IMS connection manager"); } if (mBatteryLevelListener != null) { mCtx.unregisterReceiver(mBatteryLevelListener); mBatteryLevelListener = null; } if (mNetworkStateListener != null) { mCtx.unregisterReceiver(mNetworkStateListener); mNetworkStateListener = null; } stopImsConnection(TerminationReason.TERMINATION_BY_SYSTEM); mCurrentNetworkInterface.unregister(); if (sLogger.isActivated()) { sLogger.info("IMS connection manager has been terminated"); } }
@Override // @FIXME: This run method needs to be refactored as the current logic of polling is bit too // complex and can be made much more simpler. public void run() { try { if (sLogger.isActivated()) { sLogger.debug("Start polling of the IMS connection"); } long servicePollingPeriod = mRcsSettings.getImsServicePollingPeriod(); long regBaseTime = mRcsSettings.getRegisterRetryBaseTime(); long regMaxTime = mRcsSettings.getRegisterRetryMaxTime(); Random random = new Random(); int nbFailures = 0; while (mImsPollingThreadId == Thread.currentThread().getId()) { if (sLogger.isActivated()) { sLogger.debug("Polling: check IMS connection"); } // Connection management try { // Test IMS registration if (!mCurrentNetworkInterface.isRegistered()) { if (sLogger.isActivated()) { sLogger.debug("Not yet registered to IMS: try registration"); } // Try to register to IMS mCurrentNetworkInterface.register(mDnsResolvedFields); // InterruptedException thrown by stopImsConnection() may be caught by one // of the methods used in currentNetworkInterface.register() above if (mImsPollingThreadId != Thread.currentThread().getId()) { if (sLogger.isActivated()) { sLogger.debug("IMS connection polling thread race condition"); } break; } if (mImsModule.isInitializationFinished() && !mImsServicesStarted) { if (sLogger.isActivated()) { sLogger.debug("Registered to the IMS with success: start IMS services"); } mImsModule.startImsServices(); mImsServicesStarted = true; } // Reset number of failures nbFailures = 0; } else { if (mImsModule.isInitializationFinished()) { if (!mImsServicesStarted) { if (sLogger.isActivated()) { sLogger.debug("Already registered to IMS: start IMS services"); } mImsModule.startImsServices(); mImsServicesStarted = true; } else { if (sLogger.isActivated()) { sLogger.debug("Already registered to IMS: check IMS services"); } mImsModule.checkImsServices(); } } else { if (sLogger.isActivated()) { sLogger.debug("Already registered to IMS: IMS services not yet started"); } } } } catch (ContactManagerException e) { sLogger.error("Can't register to the IMS!", e); mCurrentNetworkInterface.getSipManager().closeStack(); /* Increment number of failures */ nbFailures++; /* Force to perform a new DNS lookup */ mDnsResolvedFields = null; } catch (PayloadException e) { sLogger.error("Can't register to the IMS!", e); mCurrentNetworkInterface.getSipManager().closeStack(); /* Increment number of failures */ nbFailures++; /* Force to perform a new DNS lookup */ mDnsResolvedFields = null; } catch (NetworkException e) { if (sLogger.isActivated()) { sLogger.debug(e.getMessage()); } mCurrentNetworkInterface.getSipManager().closeStack(); /* Increment number of failures */ nbFailures++; /* Force to perform a new DNS lookup */ mDnsResolvedFields = null; } // InterruptedException thrown by stopImsConnection() may be caught by one // of the methods used in currentNetworkInterface.register() above if (mImsPollingThreadId != Thread.currentThread().getId()) { sLogger.debug("IMS connection polling thread race condition"); break; } // Make a pause before the next polling try { if (!mCurrentNetworkInterface.isRegistered()) { final long retryAfterHeaderDuration = mCurrentNetworkInterface.getRetryAfterHeaderDuration(); if (retryAfterHeaderDuration > 0) { Thread.sleep(retryAfterHeaderDuration); } else { // Pause before the next register attempt double w = Math.min(regMaxTime, (regBaseTime * Math.pow(2, nbFailures))); double coeff = (random.nextInt(51) + 50) / 100.0; // Coeff between 50% // and // 100% long retryPeriod = (long) (coeff * w); if (sLogger.isActivated()) { sLogger.debug( new StringBuilder("Wait ") .append(retryPeriod) .append("ms before retry registration (failures=") .append(nbFailures) .append(", coeff=") .append(coeff) .append(')') .toString()); } Thread.sleep(retryPeriod); } } else if (!mImsServicesStarted) { if (sLogger.isActivated()) { sLogger.debug( new StringBuilder("Wait ") .append(DEFAULT_RETRY_PERIOD) .append("ms before retry to start services") .toString()); } Thread.sleep(DEFAULT_RETRY_PERIOD); } else { // Pause before the next service check Thread.sleep(servicePollingPeriod); } } catch (InterruptedException e) { if (sLogger.isActivated()) { sLogger.warn("IMS connection polling is interrupted", e); } break; } } if (sLogger.isActivated()) { sLogger.debug("IMS connection polling is terminated"); } } catch (RuntimeException e) { /* * Normally we are not allowed to catch runtime exceptions as these are genuine bugs * which should be handled/fixed within the code. However the cases when we are * executing operations on a thread unhandling such exceptions will eventually lead to * exit the system and thus can bring the whole system down, which is not intended. */ sLogger.error("Failed to poll for ims connection!", e); } }
// @FIXME: This method is doing so many things at this moment and has become too complex thus // needs a complete refactor, However at this moment due to other prior tasks the refactoring // task has been kept in backlog. private void connectionEvent(Intent intent) throws PayloadException, CertificateException, NetworkException, ContactManagerException { try { if (mDisconnectedByBattery) { return; } if (!intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { return; } boolean connectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); String reason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON); boolean failover = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false); if (sLogger.isActivated()) { sLogger.debug( "Connectivity event change: failover=" + failover + ", connectivity=" + !connectivity + ", reason=" + reason); } NetworkInfo networkInfo = mCnxManager.getActiveNetworkInfo(); if (networkInfo == null) { if (sLogger.isActivated()) { sLogger.debug("Disconnect from IMS: no network (e.g. air plane mode)"); } disconnectFromIms(); return; } if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { String lastUserAccount = LauncherUtils.getLastUserAccount(mCtx); String currentUserAccount = LauncherUtils.getCurrentUserAccount(mCtx); if (lastUserAccount != null) { if ((currentUserAccount == null) || !currentUserAccount.equalsIgnoreCase(lastUserAccount)) { mImsModule.getCoreListener().onSimChangeDetected(); return; } } } String localIpAddr = null; if (networkInfo.getType() != mCurrentNetworkInterface.getType()) { if (sLogger.isActivated()) { sLogger.info("Data connection state: NETWORK ACCESS CHANGED"); } if (sLogger.isActivated()) { sLogger.debug("Disconnect from IMS: network access has changed"); } disconnectFromIms(); if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { if (sLogger.isActivated()) { sLogger.debug("Change the network interface to mobile"); } mCurrentNetworkInterface = getMobileNetworkInterface(); } else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { if (sLogger.isActivated()) { sLogger.debug("Change the network interface to Wi-Fi"); } mCurrentNetworkInterface = getWifiNetworkInterface(); } loadUserProfile(); try { mDnsResolvedFields = mCurrentNetworkInterface.getDnsResolvedFields(); } catch (UnknownHostException e) { /* * Even if we are not able to resolve host name , we should still continue to * get local IP as this is a very obvious case, Specially for networks * supporting IPV4 protocol. */ if (sLogger.isActivated()) { sLogger.debug(e.getMessage()); } } localIpAddr = NetworkFactory.getFactory() .getLocalIpAddress(mDnsResolvedFields, networkInfo.getType()); } else { /* Check if the IP address has changed */ try { if (mDnsResolvedFields == null) { mDnsResolvedFields = mCurrentNetworkInterface.getDnsResolvedFields(); } } catch (UnknownHostException e) { /* * Even if we are not able to resolve host name , we should still continue to * get local IP as this is a very obvious case, Specially for networks * supporting IPV4 protocol. */ if (sLogger.isActivated()) { sLogger.debug(e.getMessage()); } } localIpAddr = NetworkFactory.getFactory() .getLocalIpAddress(mDnsResolvedFields, networkInfo.getType()); String lastIpAddr = mCurrentNetworkInterface.getNetworkAccess().getIpAddress(); if (!localIpAddr.equals(lastIpAddr)) { // Changed by Deutsche Telekom if (lastIpAddr != null) { if (sLogger.isActivated()) { sLogger.debug("Disconnect from IMS: IP address has changed"); } disconnectFromIms(); } else { if (sLogger.isActivated()) { sLogger.debug("IP address available (again)"); } } } else { // Changed by Deutsche Telekom if (sLogger.isActivated()) { sLogger.debug("Neither interface nor IP address has changed; nothing to do."); } return; } } if (networkInfo.isConnected()) { String remoteAddress; if (mDnsResolvedFields != null) { remoteAddress = mDnsResolvedFields.mIpAddress; } else { remoteAddress = new String("unresolved"); } if (sLogger.isActivated()) { sLogger.info( "Data connection state: CONNECTED to " + networkInfo.getTypeName() + " with local IP " + localIpAddr + " valid for " + remoteAddress); } if (!NetworkAccessType.ANY.equals(mNetwork) && (mNetwork.toInt() != networkInfo.getType())) { if (sLogger.isActivated()) { sLogger.warn("Network access " + networkInfo.getTypeName() + " is not authorized"); } return; } TelephonyManager tm = (TelephonyManager) mCtx.getSystemService(Context.TELEPHONY_SERVICE); String currentOpe = tm.getSimOperatorName(); if (mOperator != null && !currentOpe.equalsIgnoreCase(mOperator)) { if (sLogger.isActivated()) { sLogger.warn( "Operator not authorized current=" + currentOpe + " authorized=" + mOperator); } return; } if (!mCurrentNetworkInterface.isInterfaceConfigured()) { if (sLogger.isActivated()) { sLogger.warn("IMS network interface not well configured"); } return; } if (sLogger.isActivated()) { sLogger.debug("Connect to IMS"); } connectToIms(localIpAddr); } } catch (SocketException e) { if (sLogger.isActivated()) { sLogger.debug(e.getMessage()); } disconnectFromIms(); } catch (IOException e) { if (sLogger.isActivated()) { sLogger.debug(e.getMessage()); } disconnectFromIms(); } }