mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1152730 - Part 1: Update retry logic in SmsService and remove the retry in ril_worker. r=btseng
This commit is contained in:
parent
d1ea8c75ab
commit
bda8330654
@ -32,6 +32,7 @@ const kSmsSentObserverTopic = "sms-sent";
|
||||
const kSmsFailedObserverTopic = "sms-failed";
|
||||
const kSmsDeliverySuccessObserverTopic = "sms-delivery-success";
|
||||
const kSmsDeliveryErrorObserverTopic = "sms-delivery-error";
|
||||
const kSmsDeletedObserverTopic = "sms-deleted";
|
||||
|
||||
const DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED = "received";
|
||||
const DOM_MOBILE_MESSAGE_DELIVERY_SENDING = "sending";
|
||||
@ -75,6 +76,21 @@ XPCOMUtils.defineLazyGetter(this, "gWAP", function() {
|
||||
return ns;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gSmsSendingSchedulars", function() {
|
||||
return {
|
||||
_schedulars: [],
|
||||
getSchedularByServiceId: function(aServiceId) {
|
||||
let schedular = this._schedulars[aServiceId];
|
||||
if (!schedular) {
|
||||
schedular = this._schedulars[aServiceId] =
|
||||
new SmsSendingSchedular(aServiceId);
|
||||
}
|
||||
|
||||
return schedular;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
|
||||
"@mozilla.org/cellbroadcast/cellbroadcastservice;1",
|
||||
"nsIGonkCellBroadcastService");
|
||||
@ -273,11 +289,82 @@ SmsService.prototype = {
|
||||
return index;
|
||||
},
|
||||
|
||||
_notifySendingError: function(aErrorCode, aSendingMessage, aSilent, aRequest) {
|
||||
if (aSilent || aErrorCode === Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR) {
|
||||
// There is no way to modify nsIDOMMozSmsMessage attributes as they
|
||||
// are read only so we just create a new sms instance to send along
|
||||
// with the notification.
|
||||
aRequest.notifySendMessageFailed(aErrorCode,
|
||||
gMobileMessageService.createSmsMessage(aSendingMessage.id,
|
||||
aSendingMessage.threadId,
|
||||
aSendingMessage.iccId,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
aSendingMessage.sender,
|
||||
aSendingMessage.receiver,
|
||||
aSendingMessage.body,
|
||||
aSendingMessage.messageClass,
|
||||
aSendingMessage.timestamp,
|
||||
0,
|
||||
0,
|
||||
aSendingMessage.read));
|
||||
|
||||
if (!aSilent) {
|
||||
Services.obs.notifyObservers(aSendingMessage, kSmsFailedObserverTopic, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(aSendingMessage.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
(aRv, aDomMessage) => {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
|
||||
this._broadcastSmsSystemMessage(
|
||||
Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, aDomMessage);
|
||||
aRequest.notifySendMessageFailed(aErrorCode, aDomMessage);
|
||||
Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule the sending request.
|
||||
*/
|
||||
_scheduleSending: function(aServiceId, aDomMessage, aSilent, aOptions, aRequest) {
|
||||
gSmsSendingSchedulars.getSchedularByServiceId(aServiceId)
|
||||
.schedule({
|
||||
messageId: aDomMessage.id,
|
||||
onSend: () => {
|
||||
if (DEBUG) debug("onSend: " + aDomMessage.id);
|
||||
this._sendToTheAir(aServiceId,
|
||||
aDomMessage,
|
||||
aSilent,
|
||||
aOptions,
|
||||
aRequest);
|
||||
},
|
||||
onCancel: (aErrorCode) => {
|
||||
if (DEBUG) debug("onCancel: " + aErrorCode);
|
||||
this._notifySendingError(aErrorCode, aDomMessage, aSilent, aRequest);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a SMS message to the modem.
|
||||
*/
|
||||
_sendToTheAir: function(aServiceId, aDomMessage, aSilent, aOptions, aRequest) {
|
||||
// Keep current SMS message info for sent/delivered notifications
|
||||
let sentMessage = aDomMessage;
|
||||
let requestStatusReport = aOptions.requestStatusReport;
|
||||
|
||||
// Retry count for GECKO_ERROR_SMS_SEND_FAIL_RETRY
|
||||
if (!aOptions.retryCount) {
|
||||
aOptions.retryCount = 0;
|
||||
}
|
||||
|
||||
gRadioInterfaces[aServiceId].sendWorkerMessage("sendSMS",
|
||||
aOptions,
|
||||
(aResponse) => {
|
||||
@ -288,43 +375,18 @@ SmsService.prototype = {
|
||||
error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR;
|
||||
} else if (aResponse.errorMsg === RIL.GECKO_ERROR_FDN_CHECK_FAILURE) {
|
||||
error = Ci.nsIMobileMessageCallback.FDN_CHECK_ERROR;
|
||||
} else if (aResponse.errorMsg === RIL.GECKO_ERROR_SMS_SEND_FAIL_RETRY &&
|
||||
aOptions.retryCount < RIL.SMS_RETRY_MAX) {
|
||||
aOptions.retryCount++;
|
||||
this._scheduleSending(aServiceId,
|
||||
aDomMessage,
|
||||
aSilent,
|
||||
aOptions,
|
||||
aRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSilent) {
|
||||
// There is no way to modify nsIDOMMozSmsMessage attributes as they
|
||||
// are read only so we just create a new sms instance to send along
|
||||
// with the notification.
|
||||
aRequest.notifySendMessageFailed(
|
||||
error,
|
||||
gMobileMessageService.createSmsMessage(sentMessage.id,
|
||||
sentMessage.threadId,
|
||||
sentMessage.iccId,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
sentMessage.sender,
|
||||
sentMessage.receiver,
|
||||
sentMessage.body,
|
||||
sentMessage.messageClass,
|
||||
sentMessage.timestamp,
|
||||
0,
|
||||
0,
|
||||
sentMessage.read));
|
||||
return false;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(aDomMessage.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
(aRv, aDomMessage) => {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
|
||||
this._broadcastSmsSystemMessage(
|
||||
Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, aDomMessage);
|
||||
aRequest.notifySendMessageFailed(error, aDomMessage);
|
||||
Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
this._notifySendingError(error, sentMessage, aSilent, aRequest);
|
||||
return false;
|
||||
} // End of send failure.
|
||||
|
||||
@ -906,28 +968,12 @@ SmsService.prototype = {
|
||||
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
|
||||
}
|
||||
if (errorCode) {
|
||||
if (aSilent) {
|
||||
aRequest.notifySendMessageFailed(errorCode, aSendingMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(aSendingMessage.id,
|
||||
null,
|
||||
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
|
||||
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
(aRv, aDomMessage) => {
|
||||
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
|
||||
this._broadcastSmsSystemMessage(
|
||||
Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, aDomMessage);
|
||||
aRequest.notifySendMessageFailed(errorCode, aDomMessage);
|
||||
Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
|
||||
});
|
||||
this._notifySendingError(errorCode, aSendingMessage, aSilent, aRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
this._sendToTheAir(aServiceId, aSendingMessage, aSilent, options, aRequest);
|
||||
this._scheduleSending(aServiceId, aSendingMessage, aSilent, options,
|
||||
aRequest);
|
||||
}; // End of |saveSendingMessageCallback|.
|
||||
|
||||
// Don't save message into DB for silent SMS.
|
||||
@ -1147,4 +1193,171 @@ function getEnabledGsmTableTuplesFromMcc() {
|
||||
return tuples;
|
||||
};
|
||||
|
||||
function SmsSendingSchedular(aServiceId) {
|
||||
this._serviceId = aServiceId;
|
||||
this._queue = [];
|
||||
|
||||
Services.obs.addObserver(this, kSmsDeletedObserverTopic, false);
|
||||
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
||||
}
|
||||
SmsSendingSchedular.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionListener]),
|
||||
|
||||
_serviceId: 0,
|
||||
_isObservingMoboConn: false,
|
||||
_queue: null,
|
||||
|
||||
/**
|
||||
* Ensure the handler is listening on MobileConnection events.
|
||||
*/
|
||||
_ensureMoboConnObserverRegistration: function() {
|
||||
if (!this._isObservingMoboConn) {
|
||||
let connection =
|
||||
gMobileConnectionService.getItemByServiceId(this._serviceId);
|
||||
if (connection) {
|
||||
connection.registerListener(this);
|
||||
this._isObservingMoboConn = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure the handler is not listening on MobileConnection events.
|
||||
*/
|
||||
_ensureMoboConnObserverUnregistration: function() {
|
||||
if (this._isObservingMoboConn) {
|
||||
let connection =
|
||||
gMobileConnectionService.getItemByServiceId(this._serviceId);
|
||||
if (connection) {
|
||||
connection.unregisterListener(this);
|
||||
this._isObservingMoboConn = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a sending request.
|
||||
*
|
||||
* @param aSendingRequest
|
||||
* An object with the following properties:
|
||||
* - messageId
|
||||
* The messageId in MobileMessageDB.
|
||||
* - onSend
|
||||
* The callback to invoke to trigger a sending or retry.
|
||||
* - onCancel
|
||||
* The callback to invoke when the request is canceled and won't
|
||||
* retry.
|
||||
*/
|
||||
schedule: function(aSendingRequest) {
|
||||
if (aSendingRequest) {
|
||||
this._ensureMoboConnObserverRegistration();
|
||||
this._queue.push(aSendingRequest)
|
||||
|
||||
// Keep the queue in order to guarantee the sending order matches user
|
||||
// expectation.
|
||||
this._queue.sort(function(a, b) {
|
||||
return a.messageId - b.messageId;
|
||||
});
|
||||
}
|
||||
|
||||
this.send();
|
||||
},
|
||||
|
||||
/**
|
||||
* Send all requests in the queue if voice connection is available.
|
||||
*/
|
||||
send: function() {
|
||||
let connection =
|
||||
gMobileConnectionService.getItemByServiceId(this._servicdeId);
|
||||
|
||||
// If the voice connection is temporarily unavailable, pend the request.
|
||||
let voiceInfo = connection && connection.voice;
|
||||
let voiceConnected = voiceInfo && voiceInfo.connected;
|
||||
if (!voiceConnected) {
|
||||
if (DEBUG) {
|
||||
debug("Voice connection is temporarily unavailable. Skip sending.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let snapshot = this._queue;
|
||||
this._queue = [];
|
||||
let req;
|
||||
while ((req = snapshot.shift())) {
|
||||
req.onSend();
|
||||
}
|
||||
|
||||
// The sending / retry could fail and being re-scheduled immediately.
|
||||
// Only unregister listener when the queue is empty after retries.
|
||||
if (this._queue.length === 0) {
|
||||
this._ensureMoboConnObserverUnregistration();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIObserver interface.
|
||||
*/
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case kSmsDeletedObserverTopic:
|
||||
if (DEBUG) {
|
||||
debug("Observe " + kSmsDeletedObserverTopic + ": " +
|
||||
JSON.stringify(aSubject));
|
||||
}
|
||||
|
||||
if (aSubject && aSubject.deletedMessageIds) {
|
||||
for (let id of aSubject.deletedMessageIds) {
|
||||
for (let i = 0; i < this._queue.length; i++) {
|
||||
if (this._queue[i].messageId === id) {
|
||||
if (DEBUG) debug("Deleting message with id=" + id);
|
||||
this._queue.splice(i, 1)[0].onCancel(
|
||||
Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
|
||||
this._ensureMoboConnObserverUnregistration();
|
||||
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
Services.obs.removeObserver(this, kSmsDeletedObserverTopic);
|
||||
|
||||
// Cancel all pending requests and clear the queue.
|
||||
for (let req of this._queue) {
|
||||
req.onCancel(Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR);
|
||||
}
|
||||
this._queue = [];
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* nsIMobileConnectionListener implementation.
|
||||
*/
|
||||
notifyVoiceChanged: function() {
|
||||
let connection = gMobileConnectionService.getItemByServiceId(this._serviceId);
|
||||
let voiceInfo = connection && connection.voice;
|
||||
let voiceConnected = voiceInfo && voiceInfo.connected;
|
||||
if (voiceConnected) {
|
||||
if (DEBUG) {
|
||||
debug("Voice connected. Resend pending requests.");
|
||||
}
|
||||
|
||||
this.send();
|
||||
}
|
||||
},
|
||||
|
||||
// Unused nsIMobileConnectionListener methods.
|
||||
notifyDataChanged: function() {},
|
||||
notifyDataError: function(message) {},
|
||||
notifyCFStateChanged: function(action, reason, number, timeSeconds, serviceClass) {},
|
||||
notifyEmergencyCbModeChanged: function(active, timeoutMs) {},
|
||||
notifyOtaStatusChanged: function(status) {},
|
||||
notifyRadioStateChanged: function() {},
|
||||
notifyClirModeChanged: function(mode) {},
|
||||
notifyLastKnownNetworkChanged: function() {},
|
||||
notifyLastKnownHomeNetworkChanged: function() {},
|
||||
notifyNetworkSelectionModeChanged: function() {}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SmsService]);
|
||||
|
@ -1457,10 +1457,6 @@ RilObject.prototype = {
|
||||
options.langIndex = options.langIndex || PDU_NL_IDENTIFIER_DEFAULT;
|
||||
options.langShiftIndex = options.langShiftIndex || PDU_NL_IDENTIFIER_DEFAULT;
|
||||
|
||||
if (!options.retryCount) {
|
||||
options.retryCount = 0;
|
||||
}
|
||||
|
||||
if (!options.segmentSeq) {
|
||||
// Fist segment to send
|
||||
options.segmentSeq = 1;
|
||||
@ -4024,15 +4020,6 @@ RilObject.prototype = {
|
||||
options.errorMsg);
|
||||
}
|
||||
|
||||
if (options.errorMsg === GECKO_ERROR_SMS_SEND_FAIL_RETRY &&
|
||||
options.retryCount < SMS_RETRY_MAX) {
|
||||
options.retryCount++;
|
||||
// TODO: bug 736702 TP-MR, retry interval, retry timeout
|
||||
this.sendSMS(options);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to default error handling if it meets max retry count.
|
||||
this.sendChromeMessage({
|
||||
rilMessageType: options.rilMessageType,
|
||||
rilMessageToken: options.rilMessageToken,
|
||||
|
Loading…
Reference in New Issue
Block a user