Bug 783392 - RadioInterfaceLayer broadcasts radio-state information to all content processes. r=marshall_law

This commit is contained in:
Hsin-Yi Tsai 2012-10-09 18:07:11 +08:00
parent af3f4360b3
commit 06749ee6db
7 changed files with 200 additions and 23 deletions

View File

@ -14,9 +14,19 @@ interface nsIDOMWindow;
* XPCOM component (in the content process) that provides the mobile
* network information.
*/
[scriptable, uuid(bc1a82aa-2a1f-4a27-a5e7-614d06b72e0a)]
[scriptable, uuid(3db24bfe-abc4-43a3-9183-07e516a33af9)]
interface nsIMobileConnectionProvider : nsISupports
{
/**
* Called when a content process registers receiving unsolicited messages from
* RadioInterfaceLayer in the chrome process. Only a content granted
* mobileconnection permission is allowed to register. Note that a content
* doesn't need to unregister because the chrome process will remove it from
* the registration list once the chrome receives a 'child-process-shutdown'
* message.
*/
void registerMobileConnectionMsg();
readonly attribute DOMString cardState;
readonly attribute nsIDOMMozMobileICCInfo iccInfo;
readonly attribute nsIDOMMozMobileConnectionInfo voiceConnectionInfo;

View File

@ -82,6 +82,8 @@ MobileConnection::MobileConnection()
// for it explicitly below.
if (!mProvider) {
NS_WARNING("Could not acquire nsIMobileConnectionProvider!");
} else {
mProvider->RegisterMobileConnectionMsg();
}
}

View File

@ -514,6 +514,21 @@ RILContentHelper.prototype = {
this.unregisterCallback("_voicemailCallbacks", callback);
},
registerTelephonyMsg: function registerTelephonyMsg() {
debug("Registering for telephony-related messages");
cpmm.sendAsyncMessage("RIL:RegisterTelephonyMsg");
},
registerMobileConnectionMsg: function registerMobileConnectionMsg() {
debug("Registering for mobile connection-related messages");
cpmm.sendAsyncMessage("RIL:RegisterMobileConnectionMsg");
},
registerVoicemailMsg: function registerVoicemailMsg() {
debug("Registering for voicemail-related messages");
cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg");
},
enumerateCalls: function enumerateCalls(callback) {
debug("Requesting enumeration of calls for callback: " + callback);
// We need 'requestId' to meet the 'RILContentHelper <--> RadioInterfaceLayer'

View File

@ -59,6 +59,7 @@ const RIL_IPC_TELEPHONY_MSG_NAMES = [
"RIL:RejectCall",
"RIL:HoldCall",
"RIL:ResumeCall",
"RIL:RegisterTelephonyMsg"
];
const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
@ -74,6 +75,11 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
"RIL:SendStkResponse",
"RIL:SendStkMenuSelection",
"RIL:SendStkEventDownload",
"RIL:RegisterMobileConnectionMsg"
];
const RIL_IPC_VOICEMAIL_MSG_NAMES = [
"RIL:RegisterVoicemailMsg"
];
XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
@ -251,12 +257,20 @@ function RadioInterfaceLayer() {
this._messageManagerByRequest = {};
// Manage message targets in terms of permission. Only the authorized and
// registered contents can receive related messages.
this._messageManagerByPermission = {};
ppmm.addMessageListener("child-process-shutdown", this);
for (let msgname of RIL_IPC_TELEPHONY_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
Services.obs.addObserver(this, "xpcom-shutdown", false);
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
Services.obs.addObserver(this, kSysMsgListenerReadyObserverTopic, false);
@ -284,6 +298,16 @@ RadioInterfaceLayer.prototype = {
*/
receiveMessage: function receiveMessage(msg) {
debug("Received '" + msg.name + "' message from content process");
if (msg.name == "child-process-shutdown") {
// By the time we receive child-process-shutdown, the child process has
// already forgotten its permissions so we need to unregister for both
// telephony and mobile connection messages.
this.unregisterTelephonyTarget(msg.target);
this.unregisterMobileConnectionTarget(msg.target);
this.unregisterVoicemailTarget(msg.target);
return;
}
if (RIL_IPC_TELEPHONY_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("telephony")) {
debug("Telephony message " + msg.name +
@ -296,6 +320,12 @@ RadioInterfaceLayer.prototype = {
" from a content process with no 'mobileconnection' privileges.");
return null;
}
} else if (RIL_IPC_VOICEMAIL_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("voicemail")) {
debug("Voicemail message " + msg.name +
" from a content process with no 'voicemail' privileges.");
return null;
}
} else {
debug("Ignoring unknown message type: " + msg.name);
return null;
@ -348,6 +378,9 @@ RadioInterfaceLayer.prototype = {
case "RIL:ResumeCall":
this.resumeCall(msg.json);
break;
case "RIL:RegisterTelephonyMsg":
this.registerTelephonyTarget(msg.target);
break;
case "RIL:GetAvailableNetworks":
this.saveRequestTarget(msg);
this.getAvailableNetworks(msg.json.requestId);
@ -359,6 +392,7 @@ RadioInterfaceLayer.prototype = {
case "RIL:SelectNetworkAuto":
this.saveRequestTarget(msg);
this.selectNetworkAuto(msg.json.requestId);
break;
case "RIL:GetCardLock":
this.saveRequestTarget(msg);
this.getCardLock(msg.json);
@ -388,6 +422,12 @@ RadioInterfaceLayer.prototype = {
case "RIL:SendStkEventDownload":
this.sendStkEventDownload(msg.json);
break;
case "RIL:RegisterMobileConnectionMsg":
this.registerMobileConnectionTarget(msg.target);
break;
case "RIL:RegisterVoicemailMsg":
this.registerVoicemailTarget(msg.target);
break;
}
},
@ -458,7 +498,7 @@ RadioInterfaceLayer.prototype = {
break;
case "cardstatechange":
this.rilContext.cardState = message.cardState;
ppmm.broadcastAsyncMessage("RIL:CardStateChanged", message);
this._sendMobileConnectionMessage("RIL:CardStateChanged", message);
break;
case "setCallWaiting":
this.handleCallWaitingStatusChange(message);
@ -505,7 +545,7 @@ RadioInterfaceLayer.prototype = {
}
break;
case "iccmbdn":
ppmm.broadcastAsyncMessage("RIL:VoicemailNumberChanged", message);
this._sendVoicemailMessage("RIL:VoicemailNumberChanged", message);
break;
case "USSDReceived":
debug("USSDReceived " + JSON.stringify(message));
@ -523,7 +563,7 @@ RadioInterfaceLayer.prototype = {
this.handleStkProactiveCommand(message);
break;
case "stksessionend":
ppmm.broadcastAsyncMessage("RIL:StkSessionEnd", null);
this._sendMobileConnectionMessage("RIL:StkSessionEnd", null);
break;
case "setPreferredNetworkType":
this.handleSetPreferredNetworkType(message);
@ -564,6 +604,86 @@ RadioInterfaceLayer.prototype = {
target.sendAsyncMessage(requestType, options);
},
_messageManagerByPermission: null,
registerMessageTarget: function registerMessageTarget(permission, target) {
let targets = this._messageManagerByPermission[permission];
if (!targets) {
targets = this._messageManagerByPermission[permission] = [];
}
if (targets.indexOf(target) != -1) {
debug("Already registered this target!");
return;
}
targets.push(target);
debug("Registered " + permission + " target: " + target);
},
unregisterMessageTarget: function unregisterMessageTarget(permission, target) {
let targets = this._messageManagerByPermission[permission];
if (!targets) {
return;
}
let index = targets.indexOf(target);
if (index != -1) {
targets.splice(index, 1);
debug("Unregistered " + permission + " target: " + target);
}
},
registerTelephonyTarget: function registerTelephonyTarget(target) {
this.registerMessageTarget("telephony", target);
},
registerMobileConnectionTarget: function registerMobileConnectionTarget(target) {
this.registerMessageTarget("mobileconnection", target);
},
registerVoicemailTarget: function registerVoicemailTarget(target) {
this.registerMessageTarget("voicemail", target);
},
unregisterTelephonyTarget: function unregisterTelephonyTarget(target) {
this.unregisterMessageTarget("telephony", target);
},
unregisterMobileConnectionTarget: function unregisterMobileConnectionTarget(target) {
this.unregisterMessageTarget("mobileconnection", target);
},
unregisterVoicemailTarget: function unregisterVoicemailTarget(target) {
this.unregisterMessageTarget("voicemail", target);
},
_sendTargetMessage: function _sendTargetMessage(permission, message, options) {
let thisTargets = this._messageManagerByPermission[permission];
if (!thisTargets) {
return;
}
let targets = thisTargets.slice();
for each (let target in targets) {
if (thisTargets.indexOf(target) == -1) {
continue;
}
target.sendAsyncMessage(message, options);
}
},
_sendTelephonyMessage: function sendTelephonyMessage(message, options) {
this._sendTargetMessage("telephony", message, options);
},
_sendMobileConnectionMessage: function sendMobileConnectionMessage(message, options) {
this._sendTargetMessage("mobileconnection", message, options);
},
_sendVoicemailMessage: function sendVoicemailMessage(message, options) {
this._sendTargetMessage("voicemail", message, options);
},
updateNetworkInfo: function updateNetworkInfo(message) {
let voiceMessage = message[RIL.NETWORK_INFO_VOICE_REGISTRATION_STATE];
let dataMessage = message[RIL.NETWORK_INFO_DATA_REGISTRATION_STATE];
@ -597,10 +717,10 @@ RadioInterfaceLayer.prototype = {
this.checkRoamingBetweenOperators(data);
if (voiceMessage || operatorMessage) {
ppmm.broadcastAsyncMessage("RIL:VoiceInfoChanged", voice);
this._sendMobileConnectionMessage("RIL:VoiceInfoChanged", voice);
}
if (dataMessage || operatorMessage) {
ppmm.broadcastAsyncMessage("RIL:DataInfoChanged", data);
this._sendMobileConnectionMessage("RIL:DataInfoChanged", data);
}
if (selectionMessage) {
@ -674,7 +794,7 @@ RadioInterfaceLayer.prototype = {
}
if (!newInfo.batch) {
ppmm.broadcastAsyncMessage("RIL:VoiceInfoChanged", voiceInfo);
this._sendMobileConnectionMessage("RIL:VoiceInfoChanged", voiceInfo);
}
},
@ -704,7 +824,7 @@ RadioInterfaceLayer.prototype = {
}
if (!newInfo.batch) {
ppmm.broadcastAsyncMessage("RIL:DataInfoChanged", dataInfo);
this._sendMobileConnectionMessage("RIL:DataInfoChanged", dataInfo);
}
this.updateRILNetworkInterface();
},
@ -715,7 +835,7 @@ RadioInterfaceLayer.prototype = {
handleDataCallError: function handleDataCallError(message) {
// Notify data call error only for data APN
if (message.apn == this.dataCallSettings["apn"]) {
ppmm.broadcastAsyncMessage("RIL:DataError", message);
this._sendMobileConnectionMessage("RIL:DataError", message);
}
this._deliverDataCallCallback("dataCallError", [message]);
@ -761,7 +881,7 @@ RadioInterfaceLayer.prototype = {
voiceInfo.relSignalStrength != message.gsmRelative) {
voiceInfo.signalStrength = message.gsmDBM;
voiceInfo.relSignalStrength = message.gsmRelative;
ppmm.broadcastAsyncMessage("RIL:VoiceInfoChanged", voiceInfo);
this._sendMobileConnectionMessage("RIL:VoiceInfoChanged", voiceInfo);
}
let dataInfo = this.rilContext.data;
@ -769,7 +889,7 @@ RadioInterfaceLayer.prototype = {
dataInfo.relSignalStrength != message.gsmRelative) {
dataInfo.signalStrength = message.gsmDBM;
dataInfo.relSignalStrength = message.gsmRelative;
ppmm.broadcastAsyncMessage("RIL:DataInfoChanged", dataInfo);
this._sendMobileConnectionMessage("RIL:DataInfoChanged", dataInfo);
}
},
@ -787,12 +907,12 @@ RadioInterfaceLayer.prototype = {
if (this.networkChanged(message, voice.network)) {
voice.network = message;
ppmm.broadcastAsyncMessage("RIL:VoiceInfoChanged", voice);
this._sendMobileConnectionMessage("RIL:VoiceInfoChanged", voice);
}
if (this.networkChanged(message, data.network)) {
data.network = message;
ppmm.broadcastAsyncMessage("RIL:DataInfoChanged", data);
this._sendMobileConnectionMessage("RIL:DataInfoChanged", data);
}
},
@ -989,7 +1109,7 @@ RadioInterfaceLayer.prototype = {
this._activeCall = null;
}
this.updateCallAudioState();
ppmm.broadcastAsyncMessage("RIL:CallStateChanged", call);
this._sendTelephonyMessage("RIL:CallStateChanged", call);
},
/**
@ -1002,7 +1122,7 @@ RadioInterfaceLayer.prototype = {
}
this.updateCallAudioState();
call.state = nsIRadioInterfaceLayer.CALL_STATE_DISCONNECTED;
ppmm.broadcastAsyncMessage("RIL:CallStateChanged", call);
this._sendTelephonyMessage("RIL:CallStateChanged", call);
},
/**
@ -1030,7 +1150,7 @@ RadioInterfaceLayer.prototype = {
*/
updateNetworkSelectionMode: function updateNetworkSelectionMode(message) {
debug("updateNetworkSelectionMode: " + JSON.stringify(message));
ppmm.broadcastAsyncMessage("RIL:NetworkSelectionModeChanged", message);
this._sendMobileConnectionMessage("RIL:NetworkSelectionModeChanged", message);
},
/**
@ -1053,7 +1173,7 @@ RadioInterfaceLayer.prototype = {
* Handle call error.
*/
handleCallError: function handleCallError(message) {
ppmm.broadcastAsyncMessage("RIL:CallError", message);
this._sendTelephonyMessage("RIL:CallError", message);
},
/**
@ -1114,7 +1234,7 @@ RadioInterfaceLayer.prototype = {
if (mwi) {
mwi.returnNumber = message.sender || null;
mwi.returnMessage = message.fullBody || null;
ppmm.broadcastAsyncMessage("RIL:VoicemailNotification", mwi);
this._sendVoicemailMessage("RIL:VoicemailNotification", mwi);
return;
}
@ -1230,7 +1350,7 @@ RadioInterfaceLayer.prototype = {
if (datacall.ifname &&
datacall.apn == this.dataCallSettings["apn"]) {
data.connected = (datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED);
ppmm.broadcastAsyncMessage("RIL:DataInfoChanged", data);
this._sendMobileConnectionMessage("RIL:DataInfoChanged", data);
}
this._deliverDataCallCallback("dataCallStateChanged",
@ -1287,7 +1407,7 @@ RadioInterfaceLayer.prototype = {
}
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
// when the MCC or MNC codes have changed.
ppmm.broadcastAsyncMessage("RIL:IccInfoChanged", message);
this._sendMobileConnectionMessage("RIL:IccInfoChanged", message);
},
handleICCCardLockResult: function handleICCCardLockResult(message) {
@ -1296,7 +1416,7 @@ RadioInterfaceLayer.prototype = {
handleUSSDReceived: function handleUSSDReceived(ussd) {
debug("handleUSSDReceived " + JSON.stringify(ussd));
ppmm.broadcastAsyncMessage("RIL:USSDReceived", ussd);
this._sendMobileConnectionMessage("RIL:UssdReceived", ussd);
},
handleSendMMI: function handleSendMMI(message) {
@ -1316,7 +1436,7 @@ RadioInterfaceLayer.prototype = {
handleStkProactiveCommand: function handleStkProactiveCommand(message) {
debug("handleStkProactiveCommand " + JSON.stringify(message));
gSystemMessenger.broadcastMessage("icc-stkcommand", message);
ppmm.broadcastAsyncMessage("RIL:StkCommand", message);
this._sendMobileConnectionMessage("RIL:StkCommand", message);
},
// nsIObserver
@ -1333,12 +1453,16 @@ RadioInterfaceLayer.prototype = {
this.handle(setting.key, setting.value);
break;
case "xpcom-shutdown":
ppmm.removeMessageListener("child-process-shutdown", this);
for (let msgname of RIL_IPC_TELEPHONY_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_MOBILECONNECTION_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
for (let msgname of RIL_IPC_VOICEMAIL_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
// Shutdown all RIL network interfaces
this.dataNetworkInterface.shutdown();
this.mmsNetworkInterface.shutdown();

View File

@ -139,7 +139,7 @@ interface nsIRILContactCallback : nsISupports
* Helper that runs in the content process and exposes information
* to the DOM.
*/
[scriptable, uuid(31ea634b-e710-49ce-bb7d-bfcbaa40fb00)]
[scriptable, uuid(2abe554b-e07c-44b0-9719-02190460188d)]
interface nsIRILContentHelper : nsIMobileConnectionProvider
{
void registerTelephonyCallback(in nsIRILTelephonyCallback callback);
@ -148,6 +148,24 @@ interface nsIRILContentHelper : nsIMobileConnectionProvider
void registerVoicemailCallback(in nsIRILVoicemailCallback callback);
void unregisterVoicemailCallback(in nsIRILVoicemailCallback callback);
/**
* Called when a content process registers receiving unsolicited messages from
* RadioInterfaceLayer in the chrome process. Only content granted telephony
* permission is allowed to register. Note that a content doesn't need to
* unregister because the chrome process will remove it from the registration
* list once the chrome receives a 'child-process-shutdown' message.
*/
void registerTelephonyMsg();
/**
* Called when a content process registers receiving unsolicited messages from
* RadioInterfaceLayer in the chrome process. Only a content granted voice
* mail permission is allowed to register. Note that a content doesn't need to
* unregister because the chrome process will remove it from the registration
* list once the chrome receives a 'child-process-shutdown' message.
*/
void registerVoicemailMsg();
/**
* Will continue calling callback.enumerateCallState until the callback
* returns false.

View File

@ -94,6 +94,9 @@ Telephony::Create(nsPIDOMWindow* aOwner, nsIRILContentHelper* aRIL)
rv = aRIL->RegisterTelephonyCallback(telephony->mRILTelephonyCallback);
NS_ENSURE_SUCCESS(rv, nullptr);
rv = aRIL->RegisterTelephonyMsg();
NS_ENSURE_SUCCESS(rv, nullptr);
return telephony.forget();
}

View File

@ -50,6 +50,11 @@ Voicemail::Voicemail(nsPIDOMWindow* aWindow, nsIRILContentHelper* aRIL)
if (NS_FAILED(rv)) {
NS_WARNING("Failed registering voicemail callback with RIL");
}
rv = aRIL->RegisterVoicemailMsg();
if (NS_FAILED(rv)) {
NS_WARNING("Failed registering voicemail messages with RIL");
}
}
Voicemail::~Voicemail()