Bug 850140 - B2G MMS: implement MmsService.handleDeliveryIndication() to handle delivery report (part 1, provide and correct DB functions). r=vicamo a=koi+
authorGene Lian <clian@mozilla.com>
Wed, 31 Jul 2013 15:23:37 +0800
changeset 153375 0b43cdc937648c234d2ea06944869d41b21bd724
parent 153374 743d9b24e3c40d6c2a4c351af1fd396fb4b64889
child 153376 c95c169d959e94cd91e5c5128b36680c38f8c6e0
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvicamo, koi
bugs850140
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 850140 - B2G MMS: implement MmsService.handleDeliveryIndication() to handle delivery report (part 1, provide and correct DB functions). r=vicamo a=koi+
dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl
dom/mobilemessage/src/gonk/MmsService.js
dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
dom/system/gonk/RadioInterfaceLayer.js
--- a/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl
+++ b/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl
@@ -20,17 +20,17 @@ interface nsIRilMobileMessageDatabaseRec
 {
   /**
    * |aMessageRecord| Object: the mobile-message database record
    * |aDomMessage|: the nsIDOMMoz{Mms,Sms}Message. Noted, this value might be null.
    */
   void notify(in nsresult aRv, in jsval aMessageRecord, in nsISupports aDomMessage);
 };
 
-[scriptable, uuid(0ead3154-542d-4e2c-a624-9e3cec504758)]
+[scriptable, uuid(f6cd671e-f9af-11e2-b64b-1fb87e9c217c)]
 interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
 {
   /**
    * |aMessage| Object: should contain the following properties for internal use:
    *   - |type| DOMString: "sms" or "mms"
    *   - |sender| DOMString: the phone number of sender
    *   - |timestamp| Number: the timestamp of received message
    *
@@ -38,17 +38,17 @@ interface nsIRilMobileMessageDatabaseSer
    *     - |messageClass| DOMString: the message class of received message
    *     - |receiver| DOMString: the phone number of receiver
    *
    *   - If |type| == "mms", we also need:
    *     - |delivery| DOMString: the delivery state of received message
    *     - |deliveryStatus| DOMString Array: the delivery status of received message
    *     - |receivers| DOMString Array: the phone numbers of receivers
    *     - |msisdn| DOMString: [optional] my own phone number.
-   *     - |transactionId| DOMString: the transaction ID from MMS pdu header.
+   *     - |transactionId| DOMString: the transaction ID from MMS PDU header.
    *
    * Note: |deliveryStatus| should only contain single string to specify
    *       the delivery status of MMS message for the phone owner self.
    */
   long saveReceivedMessage(in jsval aMessage,
                 [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
 
   /**
@@ -67,32 +67,47 @@ interface nsIRilMobileMessageDatabaseSer
   long saveSendingMessage(in jsval aMessage,
                [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
 
   /**
    * |aMessageId| Number: the message's DB record ID.
    * |aReceiver| DOMString: the phone number of receiver (for MMS; can be null).
    * |aDelivery| DOMString: the new delivery value to update (can be null).
    * |aDeliveryStatus| DOMString: the new delivery status to update (can be null).
+   * |aEnvelopeId| DOMString: the "message-id" specified in the MMS PDU headers.
    * |aCallback| nsIRilMobileMessageDatabaseCallback: an optional callback.
    */
-  void setMessageDelivery(in long aMessageId,
-                          in DOMString aReceiver,
-                          in DOMString aDelivery,
-                          in DOMString aDeliveryStatus,
-               [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
+  void setMessageDeliveryByMessageId(in long aMessageId,
+                                     in DOMString aReceiver,
+                                     in DOMString aDelivery,
+                                     in DOMString aDeliveryStatus,
+                                     in DOMString aEnvelopeId,
+                          [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
+
+  /**
+   * |aEnvelopeId| DOMString: the "message-id" specified in the MMS PDU headers.
+   * |aReceiver| DOMString: the phone number of receiver (for MMS; can be null).
+   * |aDelivery| DOMString: the new delivery value to update (can be null).
+   * |aDeliveryStatus| DOMString: the new delivery status to update (can be null).
+   * |aCallback| nsIRilMobileMessageDatabaseCallback: an optional callback.
+   */
+  void setMessageDeliveryByEnvelopeId(in DOMString aEnvelopeId,
+                                      in DOMString aReceiver,
+                                      in DOMString aDelivery,
+                                      in DOMString aDeliveryStatus,
+                           [optional] in nsIRilMobileMessageDatabaseCallback aCallback);
 
   /**
    * |aMessageId| Number: the message's DB record ID.
-   * |aCallback| nsIRilMobileMessageDatabaseCallback: a callback which takes
-   *   result flag, message record and domMessage as parameters.
+   * |aCallback| nsIRilMobileMessageDatabaseRecordCallback: a callback which
+   *   takes result flag, message record and domMessage as parameters.
    */
   void getMessageRecordById(in long aMessageId,
                             in nsIRilMobileMessageDatabaseRecordCallback aCallback);
 
   /**
-   * |aTransactionId| DOMString: the transaction ID of MMS pdu.
-   * |aCallback| nsIRilMobileMessageDatabaseCallback: a callback which takes
-   *   result flag and message record as parameters.
+   * |aTransactionId| DOMString: the transaction ID of MMS PDU.
+   * |aCallback| nsIRilMobileMessageDatabaseRecordCallback: a callback which
+   *   takes result flag and message record as parameters.
    */
   void getMessageRecordByTransactionId(in DOMString aTransactionId,
                                        in nsIRilMobileMessageDatabaseRecordCallback aCallback);
 };
--- a/dom/mobilemessage/src/gonk/MmsService.js
+++ b/dom/mobilemessage/src/gonk/MmsService.js
@@ -1391,21 +1391,23 @@ MmsService.prototype = {
     // retrieving failed. The end user has to retrieve the MMS again.
     if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
       let transaction = new NotifyResponseTransaction(transactionId,
                                                       mmsStatus,
                                                       reportAllowed);
       transaction.run();
       // Retrieved fail after retry, so we update the delivery status in DB and
       // notify this domMessage that error happen.
-      gMobileMessageDatabaseService.setMessageDelivery(id,
-                                                       null,
-                                                       null,
-                                                       DELIVERY_STATUS_ERROR,
-                                                       (function (rv, domMessage) {
+      gMobileMessageDatabaseService
+        .setMessageDeliveryByMessageId(id,
+                                       null,
+                                       null,
+                                       DELIVERY_STATUS_ERROR,
+                                       null,
+                                       (function (rv, domMessage) {
         this.broadcastReceivedMessageEvent(domMessage);
       }).bind(this));
       return;
     }
 
     savableMessage = this.mergeRetrievalConfirmation(retrievedMessage,
                                                      savableMessage);
 
@@ -1723,21 +1725,22 @@ MmsService.prototype = {
       if (aErrorCode == Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR) {
         aRequest.notifySendMessageFailed(aErrorCode);
         Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
         return;
       }
 
       let isSentSuccess = (aErrorCode == Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR);
       gMobileMessageDatabaseService
-        .setMessageDelivery(aDomMessage.id,
-                            null,
-                            isSentSuccess ? DELIVERY_SENT : DELIVERY_ERROR,
-                            isSentSuccess ? null : DELIVERY_STATUS_ERROR,
-                            function notifySetDeliveryResult(aRv, aDomMessage) {
+        .setMessageDeliveryByMessageId(aDomMessage.id,
+                                       null,
+                                       isSentSuccess ? DELIVERY_SENT : DELIVERY_ERROR,
+                                       isSentSuccess ? null : DELIVERY_STATUS_ERROR,
+                                       null,
+                                       function notifySetDeliveryResult(aRv, aDomMessage) {
         if (DEBUG) debug("Marking the delivery state/staus is done. Notify sent or failed.");
         // TODO bug 832140 handle !Components.isSuccessCode(aRv)
         if (!isSentSuccess) {
           if (DEBUG) debug("Sending MMS failed.");
           aRequest.notifySendMessageFailed(aErrorCode);
           Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
           return;
         }
@@ -1869,21 +1872,23 @@ MmsService.prototype = {
           return;
         }
 
         // If the mmsStatus is still MMS_PDU_STATUS_DEFERRED after retry,
         // we should not store it into database and update its delivery
         // status to 'error'.
         if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
           if (DEBUG) debug("RetrieveMessage fail after retry.");
-          gMobileMessageDatabaseService.setMessageDelivery(aMessageId,
-                                                           null,
-                                                           null,
-                                                           DELIVERY_STATUS_ERROR,
-                                                           function () {
+          gMobileMessageDatabaseService
+            .setMessageDeliveryByMessageId(aMessageId,
+                                           null,
+                                           null,
+                                           DELIVERY_STATUS_ERROR,
+                                           null,
+                                           function () {
             aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
           });
           return;
         }
         // In OMA-TS-MMS_ENC-V1_3, Table 5 in page 25. This header field
         // (x-mms-transaction-id) SHALL be present when the MMS Proxy relay
         // seeks an acknowledgement for the MM delivered though M-Retrieve.conf
         // PDU during deferred retrieval. This transaction ID is used by the MMS
@@ -1927,23 +1932,24 @@ MmsService.prototype = {
           // the specific MMS Client. The M-Acknowledge.ind PDU confirms
           // successful message retrieval to the MMS Proxy Relay.
           let transaction = new AcknowledgeTransaction(transactionId, reportAllowed);
           transaction.run();
         }).bind(this));
       };
       // Update the delivery status to pending in DB.
       gMobileMessageDatabaseService
-        .setMessageDelivery(aMessageId,
-                            null,
-                            null,
-                            DELIVERY_STATUS_PENDING,
-                            this.retrieveMessage(url,
-                                                 responseNotify.bind(this),
-                                                 aDomMessage));
+        .setMessageDeliveryByMessageId(aMessageId,
+                                       null,
+                                       null,
+                                       DELIVERY_STATUS_PENDING,
+                                       null,
+                                       this.retrieveMessage(url,
+                                                            responseNotify.bind(this),
+                                                            aDomMessage));
     }).bind(this));
   },
 
   // nsIWapPushApplication
 
   receiveWapPush: function receiveWapPush(array, length, offset, options) {
     let data = {array: array, offset: offset};
     let msg = MMS.PduHelper.parse(data, null);
--- a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
+++ b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
@@ -19,17 +19,17 @@ const RIL_GETMESSAGESCURSOR_CID =
 const RIL_GETTHREADSCURSOR_CID =
   Components.ID("{95ee7c3e-d6f2-4ec4-ade5-0c453c036d35}");
 
 const DEBUG = false;
 const DISABLE_MMS_GROUPING_FOR_RECEIVING = true;
 
 
 const DB_NAME = "sms";
-const DB_VERSION = 11;
+const DB_VERSION = 12;
 const MESSAGE_STORE_NAME = "sms";
 const THREAD_STORE_NAME = "thread";
 const PARTICIPANT_STORE_NAME = "participant";
 const MOST_RECENT_STORE_NAME = "most-recent";
 
 const DELIVERY_SENDING = "sending";
 const DELIVERY_SENT = "sent";
 const DELIVERY_RECEIVED = "received";
@@ -216,20 +216,24 @@ MobileMessageDatabaseService.prototype =
           case 9:
             if (DEBUG) debug("Upgrade to version 10. Upgrade type if it's not existing.");
             self.upgradeSchema9(event.target.transaction, next);
             break;
           case 10:
             if (DEBUG) debug("Upgrade to version 11. Add last message type into threadRecord.");
             self.upgradeSchema10(event.target.transaction, next);
             break;
-	  case 11:
-	    // This will need to be moved for each new version
-	    if (DEBUG) debug("Upgrade finished.");
-	    break;
+          case 11:
+            if (DEBUG) debug("Upgrade to version 12. Add envelopeId index for outgoing MMS.");
+            self.upgradeSchema11(event.target.transaction, next);
+            break;
+          case 12:
+            // This will need to be moved for each new version
+            if (DEBUG) debug("Upgrade finished.");
+            break;
           default:
             event.target.transaction.abort();
             callback("Old database version: " + event.oldVersion, null);
             break;
         }
       }
 
       update(currentVersion);
@@ -760,16 +764,48 @@ MobileMessageDatabaseService.prototype =
             debug("Caught error on transaction", event.target.errorCode);
           }
         }
         cursor.continue();
       };
     };
   },
 
+  /**
+   * Add envelopeId index for MMS.
+   */
+  upgradeSchema11: function upgradeSchema11(transaction, next) {
+    let messageStore = transaction.objectStore(MESSAGE_STORE_NAME);
+
+    // Delete "envelopeId" index.
+    if (messageStore.indexNames.contains("envelopeId")) {
+      messageStore.deleteIndex("envelopeId");
+    }
+
+    // Create new "envelopeId" indexes.
+    messageStore.createIndex("envelopeId", "envelopeIdIndex", { unique: true });
+
+    // Populate new "envelopeIdIndex" attributes.
+    messageStore.openCursor().onsuccess = function(event) {
+      let cursor = event.target.result;
+      if (!cursor) {
+        next();
+        return;
+      }
+
+      let messageRecord = cursor.value;
+      if (messageRecord.type == "mms" &&
+          messageRecord.delivery == DELIVERY_SENT) {
+        messageRecord.envelopeIdIndex = messageRecord.headers["message-id"];
+        cursor.update(messageRecord);
+      }
+      cursor.continue();
+    };
+  },
+
   createDomMessageFromRecord: function createDomMessageFromRecord(aMessageRecord) {
     if (DEBUG) {
       debug("createDomMessageFromRecord: " + JSON.stringify(aMessageRecord));
     }
     if (aMessageRecord.type == "sms") {
       return gMobileMessageService.createSmsMessage(aMessageRecord.id,
                                                     aMessageRecord.threadId,
                                                     aMessageRecord.delivery,
@@ -1147,16 +1183,172 @@ MobileMessageDatabaseService.prototype =
           insertMessageRecord(threadId);
         };
       });
     }, [MESSAGE_STORE_NAME, PARTICIPANT_STORE_NAME, THREAD_STORE_NAME]);
     // We return the key that we expect to store in the db
     return aMessageRecord.id;
   },
 
+  updateMessageDeliveryById: function updateMessageDeliveryById(
+      id, type, receiver, delivery, deliveryStatus, envelopeId, callback) {
+    if (DEBUG) {
+      debug("Setting message's delivery by " + type + " = "+ id
+            + " receiver: " + receiver
+            + " delivery: " + delivery
+            + " deliveryStatus: " + deliveryStatus
+            + " envelopeId: " + envelopeId);
+    }
+
+    let self = this;
+    let messageRecord;
+    function notifyResult(rv) {
+      if (!callback) {
+        return;
+      }
+      let domMessage = self.createDomMessageFromRecord(messageRecord);
+      callback.notify(rv, domMessage);
+    }
+
+    this.newTxn(READ_WRITE, function (error, txn, messageStore) {
+      if (error) {
+        // TODO bug 832140 check event.target.errorCode
+        notifyResult(Cr.NS_ERROR_FAILURE);
+        return;
+      }
+      txn.oncomplete = function oncomplete(event) {
+        notifyResult(Cr.NS_OK);
+      };
+      txn.onabort = function onabort(event) {
+        // TODO bug 832140 check event.target.errorCode
+        notifyResult(Cr.NS_ERROR_FAILURE);
+      };
+
+      let getRequest;
+      if (type === "messageId") {
+        getRequest = messageStore.get(id);
+      } else if (type === "envelopeId") {
+        getRequest = messageStore.index("envelopeId").get(id);
+      }
+
+      getRequest.onsuccess = function onsuccess(event) {
+        messageRecord = event.target.result;
+        if (!messageRecord) {
+          if (DEBUG) debug("type = " + id + " is not found");
+          return;
+        }
+
+        let isRecordUpdated = false;
+
+        // Update |messageRecord.delivery| if needed.
+        if (delivery && messageRecord.delivery != delivery) {
+          messageRecord.delivery = delivery;
+          messageRecord.deliveryIndex = [delivery, messageRecord.timestamp];
+          isRecordUpdated = true;
+        }
+
+        // Update |messageRecord.deliveryStatus| if needed.
+        if (deliveryStatus) {
+          if (messageRecord.type == "sms") {
+            if (messageRecord.deliveryStatus != deliveryStatus) {
+              messageRecord.deliveryStatus = deliveryStatus;
+              isRecordUpdated = true;
+            }
+          } else if (messageRecord.type == "mms") {
+            if (!receiver) {
+              for (let i = 0; i < messageRecord.deliveryStatus.length; i++) {
+                if (messageRecord.deliveryStatus[i] != deliveryStatus) {
+                  messageRecord.deliveryStatus[i] = deliveryStatus;
+                  isRecordUpdated = true;
+                }
+              }
+            } else {
+              let normReceiver = PhoneNumberUtils.normalize(receiver, false);
+              if (!normReceiver) {
+                if (DEBUG) {
+                  debug("Normalized receiver is not valid. Fail to update.");
+                }
+                return;
+              }
+
+              let parsedReveiver = PhoneNumberUtils.parseWithMCC(normReceiver, null);
+
+              let found = false;
+              for (let i = 0; i < messageRecord.receivers.length; i++) {
+                let storedReceiver = messageRecord.receivers[i];
+                let normStoreReceiver =
+                  PhoneNumberUtils.normalize(storedReceiver, false);
+                if (!normStoreReceiver) {
+                  if (DEBUG) {
+                    debug("Normalized stored receiver is not valid. Skipping.");
+                  }
+                  continue;
+                }
+
+                let match = (normReceiver === normStoreReceiver);
+                if (!match) {
+                  if (parsedReveiver) {
+                    if (normStoreReceiver.endsWith(parsedReveiver.nationalNumber)) {
+                      match = true;
+                    }
+                  } else {
+                    let parsedStoreReceiver =
+                      PhoneNumberUtils.parseWithMCC(normStoreReceiver, null);
+                    if (parsedStoreReceiver &&
+                        normReceiver.endsWith(parsedStoreReceiver.nationalNumber)) {
+                      match = true;
+                    }
+                  }
+                }
+                if (!match) {
+                  if (DEBUG) debug("Stored receiver is not matched. Skipping.");
+                  continue;
+                }
+
+                found = true;
+                if (messageRecord.deliveryStatus[i] != deliveryStatus) {
+                  messageRecord.deliveryStatus[i] = deliveryStatus;
+                  isRecordUpdated = true;
+                }
+              }
+
+              if (!found) {
+                if (DEBUG) {
+                  debug("Cannot find the receiver. Fail to set delivery status.");
+                }
+                return;
+              }
+            }
+          }
+        }
+
+        // Update |messageRecord.envelopeIdIndex| if needed.
+        if (envelopeId) {
+          if (messageRecord.envelopeIdIndex != envelopeId) {
+            messageRecord.envelopeIdIndex = envelopeId;
+            isRecordUpdated = true;
+          }
+        }
+
+        if (!isRecordUpdated) {
+          if (DEBUG) {
+            debug("The values of delivery, deliveryStatus and envelopeId " +
+                  "don't need to be updated.");
+          }
+          return;
+        }
+
+        if (DEBUG) {
+          debug("The delivery, deliveryStatus or envelopeId are updated.");
+        }
+        messageStore.put(messageRecord);
+      };
+    });
+  },
+
   /**
    * nsIRilMobileMessageDatabaseService API
    */
 
   saveReceivedMessage: function saveReceivedMessage(aMessage, aCallback) {
     if ((aMessage.type != "sms" && aMessage.type != "mms") ||
         (aMessage.type == "sms" && aMessage.messageClass == undefined) ||
         (aMessage.type == "mms" && (aMessage.delivery == undefined ||
@@ -1278,117 +1470,30 @@ MobileMessageDatabaseService.prototype =
     if (aMessage.type == "sms") {
       addresses = [aMessage.receiver];
     } else if (aMessage.type == "mms") {
       addresses = aMessage.receivers;
     }
     return this.saveRecord(aMessage, addresses, aCallback);
   },
 
-  setMessageDelivery: function setMessageDelivery(
-      messageId, receiver, delivery, deliveryStatus, callback) {
-    if (DEBUG) {
-      debug("Setting message " + messageId + " delivery to " + delivery
-            + ", and deliveryStatus to " + deliveryStatus);
-    }
-
-    let self = this;
-    let messageRecord;
-    function notifyResult(rv) {
-      if (!callback) {
-        return;
-      }
-      let domMessage = self.createDomMessageFromRecord(messageRecord);
-      callback.notify(rv, domMessage);
-    }
-
-    this.newTxn(READ_WRITE, function (error, txn, messageStore) {
-      if (error) {
-        // TODO bug 832140 check event.target.errorCode
-        notifyResult(Cr.NS_ERROR_FAILURE);
-        return;
-      }
-      txn.oncomplete = function oncomplete(event) {
-        notifyResult(Cr.NS_OK);
-      };
-      txn.onabort = function onabort(event) {
-        // TODO bug 832140 check event.target.errorCode
-        notifyResult(Cr.NS_ERROR_FAILURE);
-      };
-
-      let getRequest = messageStore.get(messageId);
-      getRequest.onsuccess = function onsuccess(event) {
-        messageRecord = event.target.result;
-        if (!messageRecord) {
-          if (DEBUG) debug("Message ID " + messageId + " not found");
-          return;
-        }
-        if (messageRecord.id != messageId) {
-          if (DEBUG) {
-            debug("Retrieve message ID (" + messageId + ") is " +
-                  "different from the one we got");
-          }
-          return;
-        }
-
-        let isRecordUpdated = false;
+  setMessageDeliveryByMessageId: function setMessageDeliveryByMessageId(
+      messageId, receiver, delivery, deliveryStatus, envelopeId, callback) {
+    this.updateMessageDeliveryById(messageId, "messageId",
+                                   receiver, delivery, deliveryStatus,
+                                   envelopeId, callback);
 
-        // Update |messageRecord.delivery| if needed.
-        if (delivery && messageRecord.delivery != delivery) {
-          messageRecord.delivery = delivery;
-          messageRecord.deliveryIndex = [delivery, messageRecord.timestamp];
-          isRecordUpdated = true;
-        }
+  },
 
-        // Update |messageRecord.deliveryStatus| if needed.
-        if (deliveryStatus) {
-          if (messageRecord.type == "sms") {
-            if (messageRecord.deliveryStatus != deliveryStatus) {
-              messageRecord.deliveryStatus = deliveryStatus;
-              isRecordUpdated = true;
-            }
-          } else if (messageRecord.type == "mms") {
-            if (!receiver) {
-              for (let i = 0; i < messageRecord.deliveryStatus.length; i++) {
-                if (messageRecord.deliveryStatus[i] != deliveryStatus) {
-                  messageRecord.deliveryStatus[i] = deliveryStatus;
-                  isRecordUpdated = true;
-                }
-              }
-            } else {
-              let index = messageRecord.receivers.indexOf(receiver);
-              if (index == -1) {
-                if (DEBUG) {
-                  debug("Cannot find the receiver. Fail to set delivery status.");
-                }
-                return;
-              }
-              if (messageRecord.deliveryStatus[index] != deliveryStatus) {
-                messageRecord.deliveryStatus[index] = deliveryStatus;
-                isRecordUpdated = true;
-              }
-            }
-          }
-        }
+  setMessageDeliveryByEnvelopeId: function setMessageDeliveryByEnvelopeId(
+      envelopeId, receiver, delivery, deliveryStatus, callback) {
+    this.updateMessageDeliveryById(envelopeId, "envelopeId",
+                                   receiver, delivery, deliveryStatus,
+                                   null, callback);
 
-        // Only updates messages that have different delivery or deliveryStatus.
-        if (!isRecordUpdated) {
-          if (DEBUG) {
-            debug("The values of attribute delivery and deliveryStatus are the"
-                  + " the same with given parameters.");
-          }
-          return;
-        }
-
-        if (DEBUG) {
-          debug("The record's delivery and/or deliveryStatus are updated.");
-        }
-        messageStore.put(messageRecord);
-      };
-    });
   },
 
   getMessageRecordByTransactionId: function getMessageRecordByTransactionId(aTransactionId, aCallback) {
     if (DEBUG) debug("Retrieving message with transaction ID " + aTransactionId);
     let self = this;
     this.newTxn(READ_ONLY, function (error, txn, messageStore) {
       if (error) {
         if (DEBUG) debug(error);
@@ -1408,18 +1513,19 @@ MobileMessageDatabaseService.prototype =
         // In this case, we don't need a dom message. Just pass null to the
         // third argument.
         aCallback.notify(Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR,
                          messageRecord, null);
       };
 
       txn.onerror = function onerror(event) {
         if (DEBUG) {
-          if (event.target)
+          if (event.target) {
             debug("Caught error on transaction", event.target.errorCode);
+          }
         }
         aCallback.notify(Ci.nsIMobileMessageCallback.INTERNAL_ERROR, null, null);
       };
     });
   },
 
   getMessageRecordById: function getMessageRecordById(aMessageId, aCallback) {
     if (DEBUG) debug("Retrieving message with ID " + aMessageId);
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -2027,21 +2027,23 @@ RadioInterface.prototype = {
                                                sms.receiver,
                                                sms.body,
                                                sms.messageClass,
                                                sms.timestamp,
                                                sms.read));
       return;
     }
 
-    gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
-                                                     null,
-                                                     DOM_MOBILE_MESSAGE_DELIVERY_SENT,
-                                                     options.sms.deliveryStatus,
-                                                     function notifyResult(rv, domMessage) {
+    gMobileMessageDatabaseService
+      .setMessageDeliveryByMessageId(options.sms.id,
+                                     null,
+                                     DOM_MOBILE_MESSAGE_DELIVERY_SENT,
+                                     options.sms.deliveryStatus,
+                                     null,
+                                     function notifyResult(rv, domMessage) {
       // TODO bug 832140 handle !Components.isSuccessCode(rv)
       this.broadcastSmsSystemMessage("sms-sent", domMessage);
 
       if (!options.requestStatusReport) {
         // No more used if STATUS-REPORT not requested.
         delete this._sentSmsEnvelopes[message.envelopeId];
       } else {
         options.sms = domMessage;
@@ -2060,21 +2062,23 @@ RadioInterface.prototype = {
       return;
     }
     delete this._sentSmsEnvelopes[message.envelopeId];
 
     if (options.silent) {
       return;
     }
 
-    gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
-                                                     null,
-                                                     options.sms.delivery,
-                                                     message.deliveryStatus,
-                                                     function notifyResult(rv, domMessage) {
+    gMobileMessageDatabaseService
+      .setMessageDeliveryByMessageId(options.sms.id,
+                                     null,
+                                     options.sms.delivery,
+                                     message.deliveryStatus,
+                                     null,
+                                     function notifyResult(rv, domMessage) {
       // TODO bug 832140 handle !Components.isSuccessCode(rv)
       let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
                   ? kSmsDeliverySuccessObserverTopic
                   : kSmsDeliveryErrorObserverTopic;
       Services.obs.notifyObservers(domMessage, topic, null);
     }.bind(this));
   },
 
@@ -2094,21 +2098,23 @@ RadioInterface.prototype = {
         break;
     }
 
     if (options.silent) {
       options.request.notifySendMessageFailed(error);
       return;
     }
 
-    gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
-                                                     null,
-                                                     DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
-                                                     RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
-                                                     function notifyResult(rv, domMessage) {
+    gMobileMessageDatabaseService
+      .setMessageDeliveryByMessageId(options.sms.id,
+                                     null,
+                                     DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
+                                     RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
+                                     null,
+                                     function notifyResult(rv, domMessage) {
       // TODO bug 832140 handle !Components.isSuccessCode(rv)
       options.request.notifySendMessageFailed(error);
       Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
     }.bind(this));
   },
 
   /**
    * Handle data call state changes.
@@ -3270,21 +3276,22 @@ RadioInterface.prototype = {
       }
       if (errorCode) {
         if (silent) {
           request.notifySendMessageFailed(errorCode);
           return;
         }
 
         gMobileMessageDatabaseService
-          .setMessageDelivery(domMessage.id,
-                              null,
-                              DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
-                              RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
-                              function notifyResult(rv, domMessage) {
+          .setMessageDeliveryByMessageId(domMessage.id,
+                                         null,
+                                         DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
+                                         RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
+                                         null,
+                                         function notifyResult(rv, domMessage) {
           // TODO bug 832140 handle !Components.isSuccessCode(rv)
           request.notifySendMessageFailed(errorCode);
           Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
         });
         return;
       }
 
       // Keep current SMS message info for sent/delivered notifications