summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/DataCallManager.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/gonk/DataCallManager.js')
-rw-r--r--dom/system/gonk/DataCallManager.js1726
1 files changed, 0 insertions, 1726 deletions
diff --git a/dom/system/gonk/DataCallManager.js b/dom/system/gonk/DataCallManager.js
deleted file mode 100644
index 5411987cd..000000000
--- a/dom/system/gonk/DataCallManager.js
+++ /dev/null
@@ -1,1726 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/systemlibs.js");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
- "@mozilla.org/settingsService;1",
- "nsISettingsService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
- "@mozilla.org/network/manager;1",
- "nsINetworkManager");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
- "@mozilla.org/mobileconnection/mobileconnectionservice;1",
- "nsIMobileConnectionService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
- "@mozilla.org/icc/iccservice;1",
- "nsIIccService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gDataCallInterfaceService",
- "@mozilla.org/datacall/interfaceservice;1",
- "nsIDataCallInterfaceService");
-
-XPCOMUtils.defineLazyGetter(this, "RIL", function() {
- let obj = {};
- Cu.import("resource://gre/modules/ril_consts.js", obj);
- return obj;
-});
-
-// Ril quirk to attach data registration on demand.
-var RILQUIRKS_DATA_REGISTRATION_ON_DEMAND =
- libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true";
-
-// Ril quirk to control the uicc/data subscription.
-var RILQUIRKS_SUBSCRIPTION_CONTROL =
- libcutils.property_get("ro.moz.ril.subscription_control", "false") == "true";
-
-// Ril quirk to enable IPv6 protocol/roaming protocol in APN settings.
-var RILQUIRKS_HAVE_IPV6 =
- libcutils.property_get("ro.moz.ril.ipv6", "false") == "true";
-
-const DATACALLMANAGER_CID =
- Components.ID("{35b9efa2-e42c-45ce-8210-0a13e6f4aadc}");
-const DATACALLHANDLER_CID =
- Components.ID("{132b650f-c4d8-4731-96c5-83785cb31dee}");
-const RILNETWORKINTERFACE_CID =
- Components.ID("{9574ee84-5d0d-4814-b9e6-8b279e03dcf4}");
-const RILNETWORKINFO_CID =
- Components.ID("{dd6cf2f0-f0e3-449f-a69e-7c34fdcb8d4b}");
-
-const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
-const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed";
-const TOPIC_PREF_CHANGED = "nsPref:changed";
-const TOPIC_DATA_CALL_ERROR = "data-call-error";
-const PREF_RIL_DEBUG_ENABLED = "ril.debugging.enabled";
-
-const NETWORK_TYPE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_TYPE_UNKNOWN;
-const NETWORK_TYPE_WIFI = Ci.nsINetworkInfo.NETWORK_TYPE_WIFI;
-const NETWORK_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE;
-const NETWORK_TYPE_MOBILE_MMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS;
-const NETWORK_TYPE_MOBILE_SUPL = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL;
-const NETWORK_TYPE_MOBILE_IMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS;
-const NETWORK_TYPE_MOBILE_DUN = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN;
-const NETWORK_TYPE_MOBILE_FOTA = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA;
-
-const NETWORK_STATE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_STATE_UNKNOWN;
-const NETWORK_STATE_CONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTING;
-const NETWORK_STATE_CONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED;
-const NETWORK_STATE_DISCONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTING;
-const NETWORK_STATE_DISCONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED;
-
-const INT32_MAX = 2147483647;
-
-// set to true in ril_consts.js to see debug messages
-var DEBUG = RIL.DEBUG_RIL;
-
-function updateDebugFlag() {
- // Read debug setting from pref
- let debugPref;
- try {
- debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED);
- } catch (e) {
- debugPref = false;
- }
- DEBUG = debugPref || RIL.DEBUG_RIL;
-}
-updateDebugFlag();
-
-function DataCallManager() {
- this._connectionHandlers = [];
-
- let numRadioInterfaces = gMobileConnectionService.numItems;
- for (let clientId = 0; clientId < numRadioInterfaces; clientId++) {
- this._connectionHandlers.push(new DataCallHandler(clientId));
- }
-
- let lock = gSettingsService.createLock();
- // Read the APN data from the settings DB.
- lock.get("ril.data.apnSettings", this);
- // Read the data enabled setting from DB.
- lock.get("ril.data.enabled", this);
- lock.get("ril.data.roaming_enabled", this);
- // Read the default client id for data call.
- lock.get("ril.data.defaultServiceId", this);
-
- Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
- Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false);
- Services.prefs.addObserver(PREF_RIL_DEBUG_ENABLED, this, false);
-}
-DataCallManager.prototype = {
- classID: DATACALLMANAGER_CID,
- classInfo: XPCOMUtils.generateCI({classID: DATACALLMANAGER_CID,
- classDescription: "Data Call Manager",
- interfaces: [Ci.nsIDataCallManager]}),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallManager,
- Ci.nsIObserver,
- Ci.nsISettingsServiceCallback]),
-
- _connectionHandlers: null,
-
- // Flag to determine the data state to start with when we boot up. It
- // corresponds to the 'ril.data.enabled' setting from the UI.
- _dataEnabled: false,
-
- // Flag to record the default client id for data call. It corresponds to
- // the 'ril.data.defaultServiceId' setting from the UI.
- _dataDefaultClientId: -1,
-
- // Flag to record the current default client id for data call.
- // It differs from _dataDefaultClientId in that it is set only when
- // the switch of client id process is done.
- _currentDataClientId: -1,
-
- // Pending function to execute when we are notified that another data call has
- // been disconnected.
- _pendingDataCallRequest: null,
-
- debug: function(aMsg) {
- dump("-*- DataCallManager: " + aMsg + "\n");
- },
-
- get dataDefaultServiceId() {
- return this._dataDefaultClientId;
- },
-
- getDataCallHandler: function(aClientId) {
- let handler = this._connectionHandlers[aClientId]
- if (!handler) {
- throw Cr.NS_ERROR_UNEXPECTED;
- }
-
- return handler;
- },
-
- _setDataRegistration: function(aDataCallInterface, aAttach) {
- return new Promise(function(aResolve, aReject) {
- let callback = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]),
- notifySuccess: function() {
- aResolve();
- },
- notifyError: function(aErrorMsg) {
- aReject(aErrorMsg);
- }
- };
-
- aDataCallInterface.setDataRegistration(aAttach, callback);
- });
- },
-
- _handleDataClientIdChange: function(aNewClientId) {
- if (this._dataDefaultClientId === aNewClientId) {
- return;
- }
- this._dataDefaultClientId = aNewClientId;
-
- // This is to handle boot up stage.
- if (this._currentDataClientId == -1) {
- this._currentDataClientId = this._dataDefaultClientId;
- let connHandler = this._connectionHandlers[this._currentDataClientId];
- let dcInterface = connHandler.dataCallInterface;
- if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND ||
- RILQUIRKS_SUBSCRIPTION_CONTROL) {
- this._setDataRegistration(dcInterface, true);
- }
- if (this._dataEnabled) {
- let settings = connHandler.dataCallSettings;
- settings.oldEnabled = settings.enabled;
- settings.enabled = true;
- connHandler.updateRILNetworkInterface();
- }
- return;
- }
-
- let oldConnHandler = this._connectionHandlers[this._currentDataClientId];
- let oldIface = oldConnHandler.dataCallInterface;
- let oldSettings = oldConnHandler.dataCallSettings;
- let newConnHandler = this._connectionHandlers[this._dataDefaultClientId];
- let newIface = newConnHandler.dataCallInterface;
- let newSettings = newConnHandler.dataCallSettings;
-
- let applyPendingDataSettings = () => {
- if (DEBUG) {
- this.debug("Apply pending data registration and settings.");
- }
-
- if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND ||
- RILQUIRKS_SUBSCRIPTION_CONTROL) {
- this._setDataRegistration(oldIface, false).then(() => {
- if (this._dataEnabled) {
- newSettings.oldEnabled = newSettings.enabled;
- newSettings.enabled = true;
- }
- this._currentDataClientId = this._dataDefaultClientId;
-
- this._setDataRegistration(newIface, true).then(() => {
- newConnHandler.updateRILNetworkInterface();
- });
- });
- return;
- }
-
- if (this._dataEnabled) {
- newSettings.oldEnabled = newSettings.enabled;
- newSettings.enabled = true;
- }
-
- this._currentDataClientId = this._dataDefaultClientId;
- newConnHandler.updateRILNetworkInterface();
- };
-
- if (this._dataEnabled) {
- oldSettings.oldEnabled = oldSettings.enabled;
- oldSettings.enabled = false;
- }
-
- oldConnHandler.deactivateDataCallsAndWait().then(() => {
- applyPendingDataSettings();
- });
- },
-
- _shutdown: function() {
- for (let handler of this._connectionHandlers) {
- handler.shutdown();
- }
- this._connectionHandlers = null;
- Services.prefs.removeObserver(PREF_RIL_DEBUG_ENABLED, this);
- Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
- Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED);
- },
-
- /**
- * nsISettingsServiceCallback
- */
- handle: function(aName, aResult) {
- switch (aName) {
- case "ril.data.apnSettings":
- if (DEBUG) {
- this.debug("'ril.data.apnSettings' is now " +
- JSON.stringify(aResult));
- }
- if (!aResult) {
- break;
- }
- for (let clientId in this._connectionHandlers) {
- let handler = this._connectionHandlers[clientId];
- let apnSetting = aResult[clientId];
- if (handler && apnSetting) {
- handler.updateApnSettings(apnSetting);
- }
- }
- break;
- case "ril.data.enabled":
- if (DEBUG) {
- this.debug("'ril.data.enabled' is now " + aResult);
- }
- if (this._dataEnabled === aResult) {
- break;
- }
- this._dataEnabled = aResult;
-
- if (DEBUG) {
- this.debug("Default id for data call: " + this._dataDefaultClientId);
- }
- if (this._dataDefaultClientId === -1) {
- // We haven't got the default id for data from db.
- break;
- }
-
- let connHandler = this._connectionHandlers[this._dataDefaultClientId];
- let settings = connHandler.dataCallSettings;
- settings.oldEnabled = settings.enabled;
- settings.enabled = aResult;
- connHandler.updateRILNetworkInterface();
- break;
- case "ril.data.roaming_enabled":
- if (DEBUG) {
- this.debug("'ril.data.roaming_enabled' is now " + aResult);
- this.debug("Default id for data call: " + this._dataDefaultClientId);
- }
- for (let clientId = 0; clientId < this._connectionHandlers.length; clientId++) {
- let connHandler = this._connectionHandlers[clientId];
- let settings = connHandler.dataCallSettings;
- settings.roamingEnabled = Array.isArray(aResult) ? aResult[clientId]
- : aResult;
- }
- if (this._dataDefaultClientId === -1) {
- // We haven't got the default id for data from db.
- break;
- }
- this._connectionHandlers[this._dataDefaultClientId].updateRILNetworkInterface();
- break;
- case "ril.data.defaultServiceId":
- aResult = aResult || 0;
- if (DEBUG) {
- this.debug("'ril.data.defaultServiceId' is now " + aResult);
- }
- this._handleDataClientIdChange(aResult);
- break;
- }
- },
-
- handleError: function(aErrorMessage) {
- if (DEBUG) {
- this.debug("There was an error while reading RIL settings.");
- }
- },
-
- /**
- * nsIObserver interface methods.
- */
- observe: function(aSubject, aTopic, aData) {
- switch (aTopic) {
- case TOPIC_MOZSETTINGS_CHANGED:
- if ("wrappedJSObject" in aSubject) {
- aSubject = aSubject.wrappedJSObject;
- }
- this.handle(aSubject.key, aSubject.value);
- break;
- case TOPIC_PREF_CHANGED:
- if (aData === PREF_RIL_DEBUG_ENABLED) {
- updateDebugFlag();
- }
- break;
- case TOPIC_XPCOM_SHUTDOWN:
- this._shutdown();
- break;
- }
- },
-};
-
-function DataCallHandler(aClientId) {
- // Initial owning attributes.
- this.clientId = aClientId;
- this.dataCallSettings = {
- oldEnabled: false,
- enabled: false,
- roamingEnabled: false
- };
- this._dataCalls = [];
- this._listeners = [];
-
- // This map is used to collect all the apn types and its corresponding
- // RILNetworkInterface.
- this.dataNetworkInterfaces = new Map();
-
- this.dataCallInterface = gDataCallInterfaceService.getDataCallInterface(aClientId);
- this.dataCallInterface.registerListener(this);
-
- let mobileConnection = gMobileConnectionService.getItemByServiceId(aClientId);
- mobileConnection.registerListener(this);
-
- this._dataInfo = {
- state: mobileConnection.data.state,
- type: mobileConnection.data.type,
- roaming: mobileConnection.data.roaming
- }
-}
-DataCallHandler.prototype = {
- classID: DATACALLHANDLER_CID,
- classInfo: XPCOMUtils.generateCI({classID: DATACALLHANDLER_CID,
- classDescription: "Data Call Handler",
- interfaces: [Ci.nsIDataCallHandler]}),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallHandler,
- Ci.nsIDataCallInterfaceListener,
- Ci.nsIMobileConnectionListener]),
-
- clientId: 0,
- dataCallInterface: null,
- dataCallSettings: null,
- dataNetworkInterfaces: null,
- _dataCalls: null,
- _dataInfo: null,
-
- // Apn settings to be setup after data call are cleared.
- _pendingApnSettings: null,
-
- debug: function(aMsg) {
- dump("-*- DataCallHandler[" + this.clientId + "]: " + aMsg + "\n");
- },
-
- shutdown: function() {
- // Shutdown all RIL network interfaces
- this.dataNetworkInterfaces.forEach(function(networkInterface) {
- gNetworkManager.unregisterNetworkInterface(networkInterface);
- networkInterface.shutdown();
- networkInterface = null;
- });
- this.dataNetworkInterfaces.clear();
- this._dataCalls = [];
- this.clientId = null;
-
- this.dataCallInterface.unregisterListener(this);
- this.dataCallInterface = null;
-
- let mobileConnection =
- gMobileConnectionService.getItemByServiceId(this.clientId);
- mobileConnection.unregisterListener(this);
- },
-
- /**
- * Check if we get all necessary APN data.
- */
- _validateApnSetting: function(aApnSetting) {
- return (aApnSetting &&
- aApnSetting.apn &&
- aApnSetting.types &&
- aApnSetting.types.length);
- },
-
- _convertApnType: function(aApnType) {
- switch (aApnType) {
- case "default":
- return NETWORK_TYPE_MOBILE;
- case "mms":
- return NETWORK_TYPE_MOBILE_MMS;
- case "supl":
- return NETWORK_TYPE_MOBILE_SUPL;
- case "ims":
- return NETWORK_TYPE_MOBILE_IMS;
- case "dun":
- return NETWORK_TYPE_MOBILE_DUN;
- case "fota":
- return NETWORK_TYPE_MOBILE_FOTA;
- default:
- return NETWORK_TYPE_UNKNOWN;
- }
- },
-
- _compareDataCallOptions: function(aDataCall, aNewDataCall) {
- return aDataCall.apnProfile.apn == aNewDataCall.apnProfile.apn &&
- aDataCall.apnProfile.user == aNewDataCall.apnProfile.user &&
- aDataCall.apnProfile.password == aNewDataCall.apnProfile.passwd &&
- aDataCall.apnProfile.authType == aNewDataCall.apnProfile.authType &&
- aDataCall.apnProfile.protocol == aNewDataCall.apnProfile.protocol &&
- aDataCall.apnProfile.roaming_protocol == aNewDataCall.apnProfile.roaming_protocol;
- },
-
- /**
- * This function will do the following steps:
- * 1. Clear the cached APN settings in the RIL.
- * 2. Combine APN, user name, and password as the key of |byApn| object to
- * refer to the corresponding APN setting.
- * 3. Use APN type as the index of |byType| object to refer to the
- * corresponding APN setting.
- * 4. Create RilNetworkInterface for each APN setting created at step 2.
- */
- _setupApnSettings: function(aNewApnSettings) {
- if (!aNewApnSettings) {
- return;
- }
- if (DEBUG) this.debug("setupApnSettings: " + JSON.stringify(aNewApnSettings));
-
- // Shutdown all network interfaces and clear data calls.
- this.dataNetworkInterfaces.forEach(function(networkInterface) {
- gNetworkManager.unregisterNetworkInterface(networkInterface);
- networkInterface.shutdown();
- networkInterface = null;
- });
- this.dataNetworkInterfaces.clear();
- this._dataCalls = [];
-
- // Cache the APN settings by APNs and by types in the RIL.
- for (let inputApnSetting of aNewApnSettings) {
- if (!this._validateApnSetting(inputApnSetting)) {
- continue;
- }
-
- // Use APN type as the key of dataNetworkInterfaces to refer to the
- // corresponding RILNetworkInterface.
- for (let i = 0; i < inputApnSetting.types.length; i++) {
- let apnType = inputApnSetting.types[i];
- let networkType = this._convertApnType(apnType);
- if (networkType === NETWORK_TYPE_UNKNOWN) {
- if (DEBUG) this.debug("Invalid apn type: " + apnType);
- continue;
- }
-
- if (DEBUG) this.debug("Preparing RILNetworkInterface for type: " + apnType);
- // Create DataCall for RILNetworkInterface or reuse one that is shareable.
- let dataCall;
- for (let i = 0; i < this._dataCalls.length; i++) {
- if (this._dataCalls[i].canHandleApn(inputApnSetting)) {
- if (DEBUG) this.debug("Found shareable DataCall, reusing it.");
- dataCall = this._dataCalls[i];
- break;
- }
- }
-
- if (!dataCall) {
- if (DEBUG) this.debug("No shareable DataCall found, creating one.");
- dataCall = new DataCall(this.clientId, inputApnSetting, this);
- this._dataCalls.push(dataCall);
- }
-
- try {
- let networkInterface = new RILNetworkInterface(this, networkType,
- inputApnSetting,
- dataCall);
- gNetworkManager.registerNetworkInterface(networkInterface);
- this.dataNetworkInterfaces.set(networkType, networkInterface);
- } catch (e) {
- if (DEBUG) {
- this.debug("Error setting up RILNetworkInterface for type " +
- apnType + ": " + e);
- }
- }
- }
- }
- },
-
- /**
- * Check if all data is disconnected.
- */
- allDataDisconnected: function() {
- for (let i = 0; i < this._dataCalls.length; i++) {
- let dataCall = this._dataCalls[i];
- if (dataCall.state != NETWORK_STATE_UNKNOWN &&
- dataCall.state != NETWORK_STATE_DISCONNECTED) {
- return false;
- }
- }
- return true;
- },
-
- deactivateDataCallsAndWait: function() {
- return new Promise((aResolve, aReject) => {
- this.deactivateDataCalls({
- notifyDataCallsDisconnected: function() {
- aResolve();
- }
- });
- });
- },
-
- updateApnSettings: function(aNewApnSettings) {
- if (!aNewApnSettings) {
- return;
- }
- if (this._pendingApnSettings) {
- // Change of apn settings in process, just update to the newest.
- this._pengingApnSettings = aNewApnSettings;
- return;
- }
-
- this._pendingApnSettings = aNewApnSettings;
- this.deactivateDataCallsAndWait().then(() => {
- this._setupApnSettings(this._pendingApnSettings);
- this._pendingApnSettings = null;
- this.updateRILNetworkInterface();
- });
- },
-
- updateRILNetworkInterface: function() {
- let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE);
- if (!networkInterface) {
- if (DEBUG) {
- this.debug("No network interface for default data.");
- }
- return;
- }
-
- let connection =
- gMobileConnectionService.getItemByServiceId(this.clientId);
-
- // This check avoids data call connection if the radio is not ready
- // yet after toggling off airplane mode.
- let radioState = connection && connection.radioState;
- if (radioState != Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) {
- if (DEBUG) {
- this.debug("RIL is not ready for data connection: radio's not ready");
- }
- return;
- }
-
- // We only watch at "ril.data.enabled" flag changes for connecting or
- // disconnecting the data call. If the value of "ril.data.enabled" is
- // true and any of the remaining flags change the setting application
- // should turn this flag to false and then to true in order to reload
- // the new values and reconnect the data call.
- if (this.dataCallSettings.oldEnabled === this.dataCallSettings.enabled) {
- if (DEBUG) {
- this.debug("No changes for ril.data.enabled flag. Nothing to do.");
- }
- return;
- }
-
- let dataInfo = connection && connection.data;
- let isRegistered =
- dataInfo &&
- dataInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED;
- let haveDataConnection =
- dataInfo &&
- dataInfo.type != RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN;
- if (!isRegistered || !haveDataConnection) {
- if (DEBUG) {
- this.debug("RIL is not ready for data connection: Phone's not " +
- "registered or doesn't have data connection.");
- }
- return;
- }
- let wifi_active = false;
- if (gNetworkManager.activeNetworkInfo &&
- gNetworkManager.activeNetworkInfo.type == NETWORK_TYPE_WIFI) {
- wifi_active = true;
- }
-
- let defaultDataCallConnected = networkInterface.connected;
-
- // We have moved part of the decision making into DataCall, the rest will be
- // moved after Bug 904514 - [meta] NetworkManager enhancement.
- if (networkInterface.enabled &&
- (!this.dataCallSettings.enabled ||
- (dataInfo.roaming && !this.dataCallSettings.roamingEnabled))) {
- if (DEBUG) {
- this.debug("Data call settings: disconnect data call.");
- }
- networkInterface.disconnect();
- return;
- }
-
- if (networkInterface.enabled && wifi_active) {
- if (DEBUG) {
- this.debug("Disconnect data call when Wifi is connected.");
- }
- networkInterface.disconnect();
- return;
- }
-
- if (!this.dataCallSettings.enabled || defaultDataCallConnected) {
- if (DEBUG) {
- this.debug("Data call settings: nothing to do.");
- }
- return;
- }
- if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) {
- if (DEBUG) {
- this.debug("We're roaming, but data roaming is disabled.");
- }
- return;
- }
- if (wifi_active) {
- if (DEBUG) {
- this.debug("Don't connect data call when Wifi is connected.");
- }
- return;
- }
- if (this._pendingApnSettings) {
- if (DEBUG) this.debug("We're changing apn settings, ignore any changes.");
- return;
- }
-
- if (this._deactivatingDataCalls) {
- if (DEBUG) this.debug("We're deactivating all data calls, ignore any changes.");
- return;
- }
-
- if (DEBUG) {
- this.debug("Data call settings: connect data call.");
- }
- networkInterface.connect();
- },
-
- _isMobileNetworkType: function(aNetworkType) {
- if (aNetworkType === NETWORK_TYPE_MOBILE ||
- aNetworkType === NETWORK_TYPE_MOBILE_MMS ||
- aNetworkType === NETWORK_TYPE_MOBILE_SUPL ||
- aNetworkType === NETWORK_TYPE_MOBILE_IMS ||
- aNetworkType === NETWORK_TYPE_MOBILE_DUN ||
- aNetworkType === NETWORK_TYPE_MOBILE_FOTA) {
- return true;
- }
-
- return false;
- },
-
- getDataCallStateByType: function(aNetworkType) {
- if (!this._isMobileNetworkType(aNetworkType)) {
- if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!");
- throw Cr.NS_ERROR_INVALID_ARG;
- }
-
- let networkInterface = this.dataNetworkInterfaces.get(aNetworkType);
- if (!networkInterface) {
- return NETWORK_STATE_UNKNOWN;
- }
- return networkInterface.info.state;
- },
-
- setupDataCallByType: function(aNetworkType) {
- if (DEBUG) {
- this.debug("setupDataCallByType: " + aNetworkType);
- }
-
- if (!this._isMobileNetworkType(aNetworkType)) {
- if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!");
- throw Cr.NS_ERROR_INVALID_ARG;
- }
-
- let networkInterface = this.dataNetworkInterfaces.get(aNetworkType);
- if (!networkInterface) {
- if (DEBUG) {
- this.debug("No network interface for type: " + aNetworkType);
- }
- return;
- }
-
- networkInterface.connect();
- },
-
- deactivateDataCallByType: function(aNetworkType) {
- if (DEBUG) {
- this.debug("deactivateDataCallByType: " + aNetworkType);
- }
-
- if (!this._isMobileNetworkType(aNetworkType)) {
- if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!");
- throw Cr.NS_ERROR_INVALID_ARG;
- }
-
- let networkInterface = this.dataNetworkInterfaces.get(aNetworkType);
- if (!networkInterface) {
- if (DEBUG) {
- this.debug("No network interface for type: " + aNetworkType);
- }
- return;
- }
-
- networkInterface.disconnect();
- },
-
- _deactivatingDataCalls: false,
-
- deactivateDataCalls: function(aCallback) {
- let dataDisconnecting = false;
- this.dataNetworkInterfaces.forEach(function(networkInterface) {
- if (networkInterface.enabled) {
- if (networkInterface.info.state != NETWORK_STATE_UNKNOWN &&
- networkInterface.info.state != NETWORK_STATE_DISCONNECTED) {
- dataDisconnecting = true;
- }
- networkInterface.disconnect();
- }
- });
-
- this._deactivatingDataCalls = dataDisconnecting;
- if (!dataDisconnecting) {
- aCallback.notifyDataCallsDisconnected();
- return;
- }
-
- let callback = {
- notifyAllDataDisconnected: () => {
- this._unregisterListener(callback);
- aCallback.notifyDataCallsDisconnected();
- }
- };
- this._registerListener(callback);
- },
-
- _listeners: null,
-
- _notifyListeners: function(aMethodName, aArgs) {
- let listeners = this._listeners.slice();
- for (let listener of listeners) {
- if (this._listeners.indexOf(listener) == -1) {
- // Listener has been unregistered in previous run.
- continue;
- }
-
- let handler = listener[aMethodName];
- try {
- handler.apply(listener, aArgs);
- } catch (e) {
- this.debug("listener for " + aMethodName + " threw an exception: " + e);
- }
- }
- },
-
- _registerListener: function(aListener) {
- if (this._listeners.indexOf(aListener) >= 0) {
- return;
- }
-
- this._listeners.push(aListener);
- },
-
- _unregisterListener: function(aListener) {
- let index = this._listeners.indexOf(aListener);
- if (index >= 0) {
- this._listeners.splice(index, 1);
- }
- },
-
- _findDataCallByCid: function(aCid) {
- if (aCid === undefined || aCid < 0) {
- return -1;
- }
-
- for (let i = 0; i < this._dataCalls.length; i++) {
- let datacall = this._dataCalls[i];
- if (datacall.linkInfo.cid != null &&
- datacall.linkInfo.cid == aCid) {
- return i;
- }
- }
-
- return -1;
- },
-
- /**
- * Notify about data call setup error, called from DataCall.
- */
- notifyDataCallError: function(aDataCall, aErrorMsg) {
- // Notify data call error only for data APN
- let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE);
- if (networkInterface && networkInterface.enabled) {
- let dataCall = networkInterface.dataCall;
- if (this._compareDataCallOptions(dataCall, aDataCall)) {
- Services.obs.notifyObservers(networkInterface.info,
- TOPIC_DATA_CALL_ERROR, aErrorMsg);
- }
- }
- },
-
- /**
- * Notify about data call changed, called from DataCall.
- */
- notifyDataCallChanged: function(aUpdatedDataCall) {
- // Process pending radio power off request after all data calls
- // are disconnected.
- if (aUpdatedDataCall.state == NETWORK_STATE_DISCONNECTED ||
- aUpdatedDataCall.state == NETWORK_STATE_UNKNOWN &&
- this.allDataDisconnected() && this._deactivatingDataCalls) {
- this._deactivatingDataCalls = false;
- this._notifyListeners("notifyAllDataDisconnected", {
- clientId: this.clientId
- });
- }
- },
-
- // nsIDataCallInterfaceListener
-
- notifyDataCallListChanged: function(aCount, aDataCallList) {
- let currentDataCalls = this._dataCalls.slice();
- for (let i = 0; i < aDataCallList.length; i++) {
- let dataCall = aDataCallList[i];
- let index = this._findDataCallByCid(dataCall.cid);
- if (index == -1) {
- if (DEBUG) {
- this.debug("Unexpected new data call: " + JSON.stringify(dataCall));
- }
- continue;
- }
- currentDataCalls[index].onDataCallChanged(dataCall);
- currentDataCalls[index] = null;
- }
-
- // If there is any CONNECTED DataCall left in currentDataCalls, means that
- // it is missing in dataCallList, we should send a DISCONNECTED event to
- // notify about this.
- for (let i = 0; i < currentDataCalls.length; i++) {
- let currentDataCall = currentDataCalls[i];
- if (currentDataCall && currentDataCall.linkInfo.cid != null &&
- currentDataCall.state == NETWORK_STATE_CONNECTED) {
- if (DEBUG) {
- this.debug("Expected data call missing: " + JSON.stringify(
- currentDataCall.apnProfile) + ", must have been DISCONNECTED.");
- }
- currentDataCall.onDataCallChanged({
- state: NETWORK_STATE_DISCONNECTED
- });
- }
- }
- },
-
- // nsIMobileConnectionListener
-
- notifyVoiceChanged: function() {},
-
- notifyDataChanged: function () {
- let connection = gMobileConnectionService.getItemByServiceId(this.clientId);
- let newDataInfo = connection.data;
-
- if (this._dataInfo.state == newDataInfo.state &&
- this._dataInfo.type == newDataInfo.type &&
- this._dataInfo.roaming == newDataInfo.roaming) {
- return;
- }
-
- this._dataInfo.state = newDataInfo.state;
- this._dataInfo.type = newDataInfo.type;
- this._dataInfo.roaming = newDataInfo.roaming;
- this.updateRILNetworkInterface();
- },
-
- notifyDataError: function (aMessage) {},
-
- notifyCFStateChanged: function(aAction, aReason, aNumber, aTimeSeconds, aServiceClass) {},
-
- notifyEmergencyCbModeChanged: function(aActive, aTimeoutMs) {},
-
- notifyOtaStatusChanged: function(aStatus) {},
-
- notifyRadioStateChanged: function() {},
-
- notifyClirModeChanged: function(aMode) {},
-
- notifyLastKnownNetworkChanged: function() {},
-
- notifyLastKnownHomeNetworkChanged: function() {},
-
- notifyNetworkSelectionModeChanged: function() {},
-
- notifyDeviceIdentitiesChanged: function() {}
-};
-
-function DataCall(aClientId, aApnSetting, aDataCallHandler) {
- this.clientId = aClientId;
- this.dataCallHandler = aDataCallHandler;
- this.apnProfile = {
- apn: aApnSetting.apn,
- user: aApnSetting.user,
- password: aApnSetting.password,
- authType: aApnSetting.authtype,
- protocol: aApnSetting.protocol,
- roaming_protocol: aApnSetting.roaming_protocol
- };
- this.linkInfo = {
- cid: null,
- ifname: null,
- addresses: [],
- dnses: [],
- gateways: [],
- pcscf: [],
- mtu: null
- };
- this.state = NETWORK_STATE_UNKNOWN;
- this.requestedNetworkIfaces = [];
-}
-DataCall.prototype = {
- /**
- * Standard values for the APN connection retry process
- * Retry funcion: time(secs) = A * numer_of_retries^2 + B
- */
- NETWORK_APNRETRY_FACTOR: 8,
- NETWORK_APNRETRY_ORIGIN: 3,
- NETWORK_APNRETRY_MAXRETRIES: 10,
-
- dataCallHandler: null,
-
- // Event timer for connection retries
- timer: null,
-
- // APN failed connections. Retry counter
- apnRetryCounter: 0,
-
- // Array to hold RILNetworkInterfaces that requested this DataCall.
- requestedNetworkIfaces: null,
-
- /**
- * @return "deactivate" if <ifname> changes or one of the aCurrentDataCall
- * addresses is missing in updatedDataCall, or "identical" if no
- * changes found, or "changed" otherwise.
- */
- _compareDataCallLink: function(aUpdatedDataCall, aCurrentDataCall) {
- // If network interface is changed, report as "deactivate".
- if (aUpdatedDataCall.ifname != aCurrentDataCall.ifname) {
- return "deactivate";
- }
-
- // If any existing address is missing, report as "deactivate".
- for (let i = 0; i < aCurrentDataCall.addresses.length; i++) {
- let address = aCurrentDataCall.addresses[i];
- if (aUpdatedDataCall.addresses.indexOf(address) < 0) {
- return "deactivate";
- }
- }
-
- if (aCurrentDataCall.addresses.length != aUpdatedDataCall.addresses.length) {
- // Since now all |aCurrentDataCall.addresses| are found in
- // |aUpdatedDataCall.addresses|, this means one or more new addresses are
- // reported.
- return "changed";
- }
-
- let fields = ["gateways", "dnses"];
- for (let i = 0; i < fields.length; i++) {
- // Compare <datacall>.<field>.
- let field = fields[i];
- let lhs = aUpdatedDataCall[field], rhs = aCurrentDataCall[field];
- if (lhs.length != rhs.length) {
- return "changed";
- }
- for (let i = 0; i < lhs.length; i++) {
- if (lhs[i] != rhs[i]) {
- return "changed";
- }
- }
- }
-
- if (aCurrentDataCall.mtu != aUpdatedDataCall.mtu) {
- return "changed";
- }
-
- return "identical";
- },
-
- _getGeckoDataCallState:function (aDataCall) {
- if (aDataCall.active == Ci.nsIDataCallInterface.DATACALL_STATE_ACTIVE_UP ||
- aDataCall.active == Ci.nsIDataCallInterface.DATACALL_STATE_ACTIVE_DOWN) {
- return NETWORK_STATE_CONNECTED;
- }
-
- return NETWORK_STATE_DISCONNECTED;
- },
-
- onSetupDataCallResult: function(aDataCall) {
- this.debug("onSetupDataCallResult: " + JSON.stringify(aDataCall));
- let errorMsg = aDataCall.errorMsg;
- if (aDataCall.failCause &&
- aDataCall.failCause != Ci.nsIDataCallInterface.DATACALL_FAIL_NONE) {
- errorMsg =
- RIL.RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[aDataCall.failCause];
- }
-
- if (errorMsg) {
- if (DEBUG) {
- this.debug("SetupDataCall error for apn " + this.apnProfile.apn + ": " +
- errorMsg + " (" + aDataCall.failCause + "), retry time: " +
- aDataCall.suggestedRetryTime);
- }
-
- this.state = NETWORK_STATE_DISCONNECTED;
-
- if (this.requestedNetworkIfaces.length === 0) {
- if (DEBUG) this.debug("This DataCall is not requested anymore.");
- return;
- }
-
- // Let DataCallHandler notify MobileConnectionService
- this.dataCallHandler.notifyDataCallError(this, errorMsg);
-
- // For suggestedRetryTime, the value of INT32_MAX(0x7fffffff) means no retry.
- if (aDataCall.suggestedRetryTime === INT32_MAX ||
- this.isPermanentFail(aDataCall.failCause, errorMsg)) {
- if (DEBUG) this.debug("Data call error: no retry needed.");
- return;
- }
-
- this.retry(aDataCall.suggestedRetryTime);
- return;
- }
-
- this.apnRetryCounter = 0;
- this.linkInfo.cid = aDataCall.cid;
-
- if (this.requestedNetworkIfaces.length === 0) {
- if (DEBUG) {
- this.debug("State is connected, but no network interface requested" +
- " this DataCall");
- }
- this.deactivate();
- return;
- }
-
- this.linkInfo.ifname = aDataCall.ifname;
- this.linkInfo.addresses = aDataCall.addresses ? aDataCall.addresses.split(" ") : [];
- this.linkInfo.gateways = aDataCall.gateways ? aDataCall.gateways.split(" ") : [];
- this.linkInfo.dnses = aDataCall.dnses ? aDataCall.dnses.split(" ") : [];
- this.linkInfo.pcscf = aDataCall.pcscf ? aDataCall.pcscf.split(" ") : [];
- this.linkInfo.mtu = aDataCall.mtu > 0 ? aDataCall.mtu : 0;
- this.state = this._getGeckoDataCallState(aDataCall);
-
- // Notify DataCallHandler about data call connected.
- this.dataCallHandler.notifyDataCallChanged(this);
-
- for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
- this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
- }
- },
-
- onDeactivateDataCallResult: function() {
- if (DEBUG) this.debug("onDeactivateDataCallResult");
-
- this.reset();
-
- if (this.requestedNetworkIfaces.length > 0) {
- if (DEBUG) {
- this.debug("State is disconnected/unknown, but this DataCall is" +
- " requested.");
- }
- this.setup();
- return;
- }
-
- // Notify DataCallHandler about data call disconnected.
- this.dataCallHandler.notifyDataCallChanged(this);
- },
-
- onDataCallChanged: function(aUpdatedDataCall) {
- if (DEBUG) {
- this.debug("onDataCallChanged: " + JSON.stringify(aUpdatedDataCall));
- }
-
- if (this.state == NETWORK_STATE_CONNECTING ||
- this.state == NETWORK_STATE_DISCONNECTING) {
- if (DEBUG) {
- this.debug("We are in connecting/disconnecting state, ignore any " +
- "unsolicited event for now.");
- }
- return;
- }
-
- let dataCallState = this._getGeckoDataCallState(aUpdatedDataCall);
- if (this.state == dataCallState &&
- dataCallState != NETWORK_STATE_CONNECTED) {
- return;
- }
-
- let newLinkInfo = {
- ifname: aUpdatedDataCall.ifname,
- addresses: aUpdatedDataCall.addresses ? aUpdatedDataCall.addresses.split(" ") : [],
- dnses: aUpdatedDataCall.dnses ? aUpdatedDataCall.dnses.split(" ") : [],
- gateways: aUpdatedDataCall.gateways ? aUpdatedDataCall.gateways.split(" ") : [],
- pcscf: aUpdatedDataCall.pcscf ? aUpdatedDataCall.pcscf.split(" ") : [],
- mtu: aUpdatedDataCall.mtu > 0 ? aUpdatedDataCall.mtu : 0
- };
-
- switch (dataCallState) {
- case NETWORK_STATE_CONNECTED:
- if (this.state == NETWORK_STATE_CONNECTED) {
- let result =
- this._compareDataCallLink(newLinkInfo, this.linkInfo);
-
- if (result == "identical") {
- if (DEBUG) this.debug("No changes in data call.");
- return;
- }
- if (result == "deactivate") {
- if (DEBUG) this.debug("Data link changed, cleanup.");
- this.deactivate();
- return;
- }
- // Minor change, just update and notify.
- if (DEBUG) {
- this.debug("Data link minor change, just update and notify.");
- }
-
- this.linkInfo.addresses = newLinkInfo.addresses.slice();
- this.linkInfo.gateways = newLinkInfo.gateways.slice();
- this.linkInfo.dnses = newLinkInfo.dnses.slice();
- this.linkInfo.pcscf = newLinkInfo.pcscf.slice();
- this.linkInfo.mtu = newLinkInfo.mtu;
- }
- break;
- case NETWORK_STATE_DISCONNECTED:
- case NETWORK_STATE_UNKNOWN:
- if (this.state == NETWORK_STATE_CONNECTED) {
- // Notify first on unexpected data call disconnection.
- this.state = dataCallState;
- for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
- this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
- }
- }
- this.reset();
-
- if (this.requestedNetworkIfaces.length > 0) {
- if (DEBUG) {
- this.debug("State is disconnected/unknown, but this DataCall is" +
- " requested.");
- }
- this.setup();
- return;
- }
- break;
- }
-
- this.state = dataCallState;
-
- // Notify DataCallHandler about data call changed.
- this.dataCallHandler.notifyDataCallChanged(this);
-
- for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
- this.requestedNetworkIfaces[i].notifyRILNetworkInterface();
- }
- },
-
- // Helpers
-
- debug: function(aMsg) {
- dump("-*- DataCall[" + this.clientId + ":" + this.apnProfile.apn + "]: " +
- aMsg + "\n");
- },
-
- get connected() {
- return this.state == NETWORK_STATE_CONNECTED;
- },
-
- isPermanentFail: function(aDataFailCause, aErrorMsg) {
- // Check ril.h for 'no retry' data call fail causes.
- if (aErrorMsg === RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE ||
- aErrorMsg === RIL.GECKO_ERROR_INVALID_PARAMETER ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_OPERATOR_BARRED ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_MISSING_UKNOWN_APN ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_USER_AUTHENTICATION ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ACTIVATION_REJECT_GGSN ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_NSAPI_IN_USE ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ONLY_IPV4_ALLOWED ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ONLY_IPV6_ALLOWED ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_PROTOCOL_ERRORS ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_RADIO_POWER_OFF ||
- aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_TETHERED_CALL_ACTIVE) {
- return true;
- }
-
- return false;
- },
-
- inRequestedTypes: function(aType) {
- for (let i = 0; i < this.requestedNetworkIfaces.length; i++) {
- if (this.requestedNetworkIfaces[i].info.type == aType) {
- return true;
- }
- }
- return false;
- },
-
- canHandleApn: function(aApnSetting) {
- let isIdentical = this.apnProfile.apn == aApnSetting.apn &&
- (this.apnProfile.user || '') == (aApnSetting.user || '') &&
- (this.apnProfile.password || '') == (aApnSetting.password || '') &&
- (this.apnProfile.authType || '') == (aApnSetting.authtype || '');
-
- if (RILQUIRKS_HAVE_IPV6) {
- isIdentical = isIdentical &&
- (this.apnProfile.protocol || '') == (aApnSetting.protocol || '') &&
- (this.apnProfile.roaming_protocol || '') == (aApnSetting.roaming_protocol || '');
- }
-
- return isIdentical;
- },
-
- resetLinkInfo: function() {
- this.linkInfo.cid = null;
- this.linkInfo.ifname = null;
- this.linkInfo.addresses = [];
- this.linkInfo.dnses = [];
- this.linkInfo.gateways = [];
- this.linkInfo.pcscf = [];
- this.linkInfo.mtu = null;
- },
-
- reset: function() {
- this.resetLinkInfo();
-
- this.state = NETWORK_STATE_UNKNOWN;
- },
-
- connect: function(aNetworkInterface) {
- if (DEBUG) this.debug("connect: " + aNetworkInterface.info.type);
-
- if (this.requestedNetworkIfaces.indexOf(aNetworkInterface) == -1) {
- this.requestedNetworkIfaces.push(aNetworkInterface);
- }
-
- if (this.state == NETWORK_STATE_CONNECTING ||
- this.state == NETWORK_STATE_DISCONNECTING) {
- return;
- }
- if (this.state == NETWORK_STATE_CONNECTED) {
- // This needs to run asynchronously, to behave the same way as the case of
- // non-shared apn, see bug 1059110.
- Services.tm.currentThread.dispatch(() => {
- // Do not notify if state changed while this event was being dispatched,
- // the state probably was notified already or need not to be notified.
- if (aNetworkInterface.info.state == RIL.GECKO_NETWORK_STATE_CONNECTED) {
- aNetworkInterface.notifyRILNetworkInterface();
- }
- }, Ci.nsIEventTarget.DISPATCH_NORMAL);
- return;
- }
-
- // If retry mechanism is running on background, stop it since we are going
- // to setup data call now.
- if (this.timer) {
- this.timer.cancel();
- }
-
- this.setup();
- },
-
- setup: function() {
- if (DEBUG) {
- this.debug("Going to set up data connection with APN " +
- this.apnProfile.apn);
- }
-
- let connection =
- gMobileConnectionService.getItemByServiceId(this.clientId);
- let dataInfo = connection && connection.data;
- if (dataInfo == null ||
- dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED ||
- dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) {
- return;
- }
-
- let radioTechType = dataInfo.type;
- let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType);
- let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnProfile.authType);
- // Use the default authType if the value in database is invalid.
- // For the case that user might not select the authentication type.
- if (authType == -1) {
- if (DEBUG) {
- this.debug("Invalid authType '" + this.apnProfile.authtype +
- "', using '" + RIL.GECKO_DATACALL_AUTH_DEFAULT + "'");
- }
- authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT);
- }
-
- let pdpType = Ci.nsIDataCallInterface.DATACALL_PDP_TYPE_IPV4;
- if (RILQUIRKS_HAVE_IPV6) {
- pdpType = !dataInfo.roaming
- ? RIL.RIL_DATACALL_PDP_TYPES.indexOf(this.apnProfile.protocol)
- : RIL.RIL_DATACALL_PDP_TYPES.indexOf(this.apnProfile.roaming_protocol);
- if (pdpType == -1) {
- if (DEBUG) {
- this.debug("Invalid pdpType '" + (!dataInfo.roaming
- ? this.apnProfile.protocol
- : this.apnProfile.roaming_protocol) +
- "', using '" + RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT + "'");
- }
- pdpType = RIL.RIL_DATACALL_PDP_TYPES.indexOf(RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT);
- }
- }
-
- let dcInterface = this.dataCallHandler.dataCallInterface;
- dcInterface.setupDataCall(
- this.apnProfile.apn, this.apnProfile.user, this.apnProfile.password,
- authType, pdpType, {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]),
- notifySetupDataCallSuccess: (aDataCall) => {
- this.onSetupDataCallResult(aDataCall);
- },
- notifyError: (aErrorMsg) => {
- this.onSetupDataCallResult({errorMsg: aErrorMsg});
- }
- });
- this.state = NETWORK_STATE_CONNECTING;
- },
-
- retry: function(aSuggestedRetryTime) {
- let apnRetryTimer;
-
- // We will retry the connection in increasing times
- // based on the function: time = A * numer_of_retries^2 + B
- if (this.apnRetryCounter >= this.NETWORK_APNRETRY_MAXRETRIES) {
- this.apnRetryCounter = 0;
- this.timer = null;
- if (DEBUG) this.debug("Too many APN Connection retries - STOP retrying");
- return;
- }
-
- // If there is a valid aSuggestedRetryTime, override the retry timer.
- if (aSuggestedRetryTime !== undefined && aSuggestedRetryTime >= 0) {
- apnRetryTimer = aSuggestedRetryTime / 1000;
- } else {
- apnRetryTimer = this.NETWORK_APNRETRY_FACTOR *
- (this.apnRetryCounter * this.apnRetryCounter) +
- this.NETWORK_APNRETRY_ORIGIN;
- }
- this.apnRetryCounter++;
- if (DEBUG) {
- this.debug("Data call - APN Connection Retry Timer (secs-counter): " +
- apnRetryTimer + "-" + this.apnRetryCounter);
- }
-
- if (this.timer == null) {
- // Event timer for connection retries
- this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- }
- this.timer.initWithCallback(this, apnRetryTimer * 1000,
- Ci.nsITimer.TYPE_ONE_SHOT);
- },
-
- disconnect: function(aNetworkInterface) {
- if (DEBUG) this.debug("disconnect: " + aNetworkInterface.info.type);
-
- let index = this.requestedNetworkIfaces.indexOf(aNetworkInterface);
- if (index != -1) {
- this.requestedNetworkIfaces.splice(index, 1);
-
- if (this.state == NETWORK_STATE_DISCONNECTED ||
- this.state == NETWORK_STATE_UNKNOWN) {
- if (this.timer) {
- this.timer.cancel();
- }
- this.reset();
- return;
- }
-
- // Notify the DISCONNECTED event immediately after network interface is
- // removed from requestedNetworkIfaces, to make the DataCall, shared or
- // not, to have the same behavior.
- Services.tm.currentThread.dispatch(() => {
- // Do not notify if state changed while this event was being dispatched,
- // the state probably was notified already or need not to be notified.
- if (aNetworkInterface.info.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) {
- aNetworkInterface.notifyRILNetworkInterface();
-
- // Clear link info after notifying NetworkManager.
- if (this.requestedNetworkIfaces.length === 0) {
- this.resetLinkInfo();
- }
- }
- }, Ci.nsIEventTarget.DISPATCH_NORMAL);
- }
-
- // Only deactivate data call if no more network interface needs this
- // DataCall and if state is CONNECTED, for other states, we simply remove
- // the network interface from requestedNetworkIfaces.
- if (this.requestedNetworkIfaces.length > 0 ||
- this.state != NETWORK_STATE_CONNECTED) {
- return;
- }
-
- this.deactivate();
- },
-
- deactivate: function() {
- let reason = Ci.nsIDataCallInterface.DATACALL_DEACTIVATE_NO_REASON;
- if (DEBUG) {
- this.debug("Going to disconnect data connection cid " + this.linkInfo.cid);
- }
-
- let dcInterface = this.dataCallHandler.dataCallInterface;
- dcInterface.deactivateDataCall(this.linkInfo.cid, reason, {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]),
- notifySuccess: () => {
- this.onDeactivateDataCallResult();
- },
- notifyError: (aErrorMsg) => {
- this.onDeactivateDataCallResult();
- }
- });
-
- this.state = NETWORK_STATE_DISCONNECTING;
- },
-
- // Entry method for timer events. Used to reconnect to a failed APN
- notify: function(aTimer) {
- this.setup();
- },
-
- shutdown: function() {
- if (this.timer) {
- this.timer.cancel();
- this.timer = null;
- }
- }
-};
-
-function RILNetworkInfo(aClientId, aType, aNetworkInterface)
-{
- this.serviceId = aClientId;
- this.type = aType;
-
- this.networkInterface = aNetworkInterface;
-}
-RILNetworkInfo.prototype = {
- classID: RILNETWORKINFO_CID,
- classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINFO_CID,
- classDescription: "RILNetworkInfo",
- interfaces: [Ci.nsINetworkInfo,
- Ci.nsIRilNetworkInfo]}),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo,
- Ci.nsIRilNetworkInfo]),
-
- networkInterface: null,
-
- getDataCall: function() {
- return this.networkInterface.dataCall;
- },
-
- getApnSetting: function() {
- return this.networkInterface.apnSetting;
- },
-
- debug: function(aMsg) {
- dump("-*- RILNetworkInfo[" + this.serviceId + ":" + this.type + "]: " +
- aMsg + "\n");
- },
-
- /**
- * nsINetworkInfo Implementation
- */
- get state() {
- let dataCall = this.getDataCall();
- if (!dataCall.inRequestedTypes(this.type)) {
- return NETWORK_STATE_DISCONNECTED;
- }
- return dataCall.state;
- },
-
- type: null,
-
- get name() {
- return this.getDataCall().linkInfo.ifname;
- },
-
- getAddresses: function(aIps, aPrefixLengths) {
- let addresses = this.getDataCall().linkInfo.addresses;
-
- let ips = [];
- let prefixLengths = [];
- for (let i = 0; i < addresses.length; i++) {
- let [ip, prefixLength] = addresses[i].split("/");
- ips.push(ip);
- prefixLengths.push(prefixLength);
- }
-
- aIps.value = ips.slice();
- aPrefixLengths.value = prefixLengths.slice();
-
- return ips.length;
- },
-
- getGateways: function(aCount) {
- let linkInfo = this.getDataCall().linkInfo;
-
- if (aCount) {
- aCount.value = linkInfo.gateways.length;
- }
-
- return linkInfo.gateways.slice();
- },
-
- getDnses: function(aCount) {
- let linkInfo = this.getDataCall().linkInfo;
-
- if (aCount) {
- aCount.value = linkInfo.dnses.length;
- }
-
- return linkInfo.dnses.slice();
- },
-
- /**
- * nsIRilNetworkInfo Implementation
- */
-
- serviceId: 0,
-
- get iccId() {
- let icc = gIccService.getIccByServiceId(this.serviceId);
- let iccInfo = icc && icc.iccInfo;
-
- return iccInfo && iccInfo.iccid;
- },
-
- get mmsc() {
- if (this.type != NETWORK_TYPE_MOBILE_MMS) {
- if (DEBUG) this.debug("Error! Only MMS network can get MMSC.");
- throw Cr.NS_ERROR_UNEXPECTED;
- }
-
- return this.getApnSetting().mmsc || "";
- },
-
- get mmsProxy() {
- if (this.type != NETWORK_TYPE_MOBILE_MMS) {
- if (DEBUG) this.debug("Error! Only MMS network can get MMS proxy.");
- throw Cr.NS_ERROR_UNEXPECTED;
- }
-
- return this.getApnSetting().mmsproxy || "";
- },
-
- get mmsPort() {
- if (this.type != NETWORK_TYPE_MOBILE_MMS) {
- if (DEBUG) this.debug("Error! Only MMS network can get MMS port.");
- throw Cr.NS_ERROR_UNEXPECTED;
- }
-
- // Note: Port 0 is reserved, so we treat it as invalid as well.
- // See http://www.iana.org/assignments/port-numbers
- return this.getApnSetting().mmsport || -1;
- },
-
- getPcscf: function(aCount) {
- if (this.type != NETWORK_TYPE_MOBILE_IMS) {
- if (DEBUG) this.debug("Error! Only IMS network can get pcscf.");
- throw Cr.NS_ERROR_UNEXPECTED;
- }
-
- let linkInfo = this.getDataCall().linkInfo;
-
- if (aCount) {
- aCount.value = linkInfo.pcscf.length;
- }
- return linkInfo.pcscf.slice();
- },
-};
-
-function RILNetworkInterface(aDataCallHandler, aType, aApnSetting, aDataCall) {
- if (!aDataCall) {
- throw new Error("No dataCall for RILNetworkInterface: " + type);
- }
-
- this.dataCallHandler = aDataCallHandler;
- this.enabled = false;
- this.dataCall = aDataCall;
- this.apnSetting = aApnSetting;
-
- this.info = new RILNetworkInfo(aDataCallHandler.clientId, aType, this);
-}
-
-RILNetworkInterface.prototype = {
- classID: RILNETWORKINTERFACE_CID,
- classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID,
- classDescription: "RILNetworkInterface",
- interfaces: [Ci.nsINetworkInterface]}),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]),
-
- // If this RILNetworkInterface type is enabled or not.
- enabled: null,
-
- apnSetting: null,
-
- dataCall: null,
-
- /**
- * nsINetworkInterface Implementation
- */
-
- info: null,
-
- get httpProxyHost() {
- return this.apnSetting.proxy || "";
- },
-
- get httpProxyPort() {
- return this.apnSetting.port || "";
- },
-
- get mtu() {
- // Value provided by network has higher priority than apn settings.
- return this.dataCall.linkInfo.mtu || this.apnSetting.mtu || -1;
- },
-
- // Helpers
-
- debug: function(aMsg) {
- dump("-*- RILNetworkInterface[" + this.dataCallHandler.clientId + ":" +
- this.info.type + "]: " + aMsg + "\n");
- },
-
- get connected() {
- return this.info.state == NETWORK_STATE_CONNECTED;
- },
-
- notifyRILNetworkInterface: function() {
- if (DEBUG) {
- this.debug("notifyRILNetworkInterface type: " + this.info.type +
- ", state: " + this.info.state);
- }
-
- gNetworkManager.updateNetworkInterface(this);
- },
-
- connect: function() {
- this.enabled = true;
-
- this.dataCall.connect(this);
- },
-
- disconnect: function() {
- if (!this.enabled) {
- return;
- }
- this.enabled = false;
-
- this.dataCall.disconnect(this);
- },
-
- shutdown: function() {
- this.dataCall.shutdown();
- this.dataCall = null;
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataCallManager]); \ No newline at end of file