Bug 838467 3/5: IPC. r=sicking,bent, a=leo+
authorVicamo Yang <vyang@mozilla.com>
Thu, 18 Apr 2013 09:09:36 +0800
changeset 119093 2d48112638590417e72a220c2420c30a13599508
parent 119092 4d817bfa3c73e36523b285213b10b87ceb17ab86
child 119094 a60ba4e8f79d3191db7905276025f30dedc513e5
push id680
push uservyang@mozilla.com
push dateThu, 18 Apr 2013 01:11:41 +0000
reviewerssicking, bent, leo
bugs838467
milestone18.0
Bug 838467 3/5: IPC. r=sicking,bent, a=leo+
dom/mobilemessage/src/ipc/SmsChild.cpp
dom/mobilemessage/src/ipc/SmsChild.h
dom/mobilemessage/src/ipc/SmsIPCService.cpp
dom/mobilemessage/src/ipc/SmsIPCService.h
dom/mobilemessage/src/ipc/SmsParent.cpp
dom/mobilemessage/src/ipc/SmsParent.h
dom/mobilemessage/src/ipc/ipdl.mk
--- a/dom/mobilemessage/src/ipc/SmsChild.cpp
+++ b/dom/mobilemessage/src/ipc/SmsChild.cpp
@@ -30,26 +30,16 @@ NotifyObserversWithSmsMessage(const char
 }
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
-SmsChild::SmsChild()
-{
-  MOZ_COUNT_CTOR(SmsChild);
-}
-
-SmsChild::~SmsChild()
-{
-  MOZ_COUNT_DTOR(SmsChild);
-}
-
 void
 SmsChild::ActorDestroy(ActorDestroyReason aWhy)
 {
 }
 
 bool
 SmsChild::RecvNotifyReceivedMessage(const SmsMessageData& aMessageData)
 {
@@ -101,32 +91,43 @@ SmsChild::AllocPSmsRequest(const IPCSmsR
 
 bool
 SmsChild::DeallocPSmsRequest(PSmsRequestChild* aActor)
 {
   delete aActor;
   return true;
 }
 
+PMobileMessageCursorChild*
+SmsChild::AllocPMobileMessageCursor(const CreateMessageCursorRequest& aRequest)
+{
+  MOZ_NOT_REACHED("Caller is supposed to manually construct a cursor!");
+  return nullptr;
+}
+
+bool
+SmsChild::DeallocPMobileMessageCursor(PMobileMessageCursorChild* aActor)
+{
+  // MobileMessageCursorChild is refcounted, must not be freed manually.
+  // Originally AddRefed in SendCursorRequest() in SmsIPCService.cpp.
+  static_cast<MobileMessageCursorChild*>(aActor)->Release();
+  return true;
+}
+
 /*******************************************************************************
  * SmsRequestChild
  ******************************************************************************/
 
 SmsRequestChild::SmsRequestChild(nsIMobileMessageCallback* aReplyRequest)
-: mReplyRequest(aReplyRequest)
+  : mReplyRequest(aReplyRequest)
 {
   MOZ_COUNT_CTOR(SmsRequestChild);
   MOZ_ASSERT(aReplyRequest);
 }
 
-SmsRequestChild::~SmsRequestChild()
-{
-  MOZ_COUNT_DTOR(SmsRequestChild);
-}
-
 void
 SmsRequestChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   // Nothing needed here.
 }
 
 bool
 SmsRequestChild::Recv__delete__(const MessageReply& aReply)
@@ -150,31 +151,16 @@ SmsRequestChild::Recv__delete__(const Me
       mReplyRequest->NotifyGetMessageFailed(aReply.get_ReplyGetMessageFail().error());
       break;
     case MessageReply::TReplyMessageDelete:
       mReplyRequest->NotifyMessageDeleted(aReply.get_ReplyMessageDelete().deleted());
       break;
     case MessageReply::TReplyMessageDeleteFail:
       mReplyRequest->NotifyMessageDeleted(aReply.get_ReplyMessageDeleteFail().error());
       break;
-    case MessageReply::TReplyNoMessageInList:
-      mReplyRequest->NotifyNoMessageInList();
-      break;
-    case MessageReply::TReplyCreateMessageList:
-      message = new SmsMessage(aReply.get_ReplyCreateMessageList().messageData());
-      mReplyRequest->NotifyMessageListCreated(aReply.get_ReplyCreateMessageList().listId(), 
-                                              message);
-      break;
-    case MessageReply::TReplyCreateMessageListFail:
-      mReplyRequest->NotifyReadMessageListFailed(aReply.get_ReplyCreateMessageListFail().error());
-      break;
-    case MessageReply::TReplyGetNextMessage:
-      message = new SmsMessage(aReply.get_ReplyGetNextMessage().messageData());
-      mReplyRequest->NotifyNextMessageInListGot(message);
-      break;
     case MessageReply::TReplyMarkeMessageRead:
       mReplyRequest->NotifyMessageMarkedRead(aReply.get_ReplyMarkeMessageRead().read());
       break;
     case MessageReply::TReplyMarkeMessageReadFail:
       mReplyRequest->NotifyMarkMessageReadFailed(aReply.get_ReplyMarkeMessageReadFail().error());
       break;
     case MessageReply::TReplyThreadList: {
       SmsRequestForwarder* forwarder = static_cast<SmsRequestForwarder*>(mReplyRequest.get());
@@ -187,11 +173,66 @@ SmsRequestChild::Recv__delete__(const Me
     default:
       MOZ_NOT_REACHED("Received invalid response parameters!");
       return false;
   }
 
   return true;
 }
 
+/*******************************************************************************
+ * MobileMessageCursorChild
+ ******************************************************************************/
+
+NS_IMPL_ISUPPORTS1(MobileMessageCursorChild, nsICursorContinueCallback)
+
+MobileMessageCursorChild::MobileMessageCursorChild(nsIMobileMessageCursorCallback* aCallback)
+  : mCursorCallback(aCallback)
+{
+  MOZ_COUNT_CTOR(MobileMessageCursorChild);
+  MOZ_ASSERT(aCallback);
+}
+
+void
+MobileMessageCursorChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  // Nothing needed here.
+}
+
+bool
+MobileMessageCursorChild::RecvNotifyResult(const SmsMessageData& aMessageData)
+{
+  MOZ_ASSERT(mCursorCallback);
+
+  nsCOMPtr<nsISupports> result = new SmsMessage(aMessageData);
+  mCursorCallback->NotifyCursorResult(result);
+  return true;
+}
+
+bool
+MobileMessageCursorChild::Recv__delete__(const int32_t& aError)
+{
+  MOZ_ASSERT(mCursorCallback);
+
+  if (aError != nsIMobileMessageCallback::SUCCESS_NO_ERROR) {
+    mCursorCallback->NotifyCursorError(aError);
+  } else {
+    mCursorCallback->NotifyCursorDone();
+  }
+  mCursorCallback = nullptr;
+
+  return true;
+}
+
+// nsICursorContinueCallback
+
+NS_IMETHODIMP
+MobileMessageCursorChild::HandleContinue()
+{
+  MOZ_ASSERT(mCursorCallback);
+
+  SendContinue();
+  return NS_OK;
+}
+
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/src/ipc/SmsChild.h
+++ b/dom/mobilemessage/src/ipc/SmsChild.h
@@ -3,30 +3,38 @@
  * 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/. */
 
 #ifndef mozilla_dom_mobilemessage_SmsChild_h
 #define mozilla_dom_mobilemessage_SmsChild_h
 
 #include "mozilla/dom/mobilemessage/PSmsChild.h"
 #include "mozilla/dom/mobilemessage/PSmsRequestChild.h"
-
-class nsIMobileMessageCallback;
+#include "mozilla/dom/mobilemessage/PMobileMessageCursorChild.h"
+#include "nsIDOMDOMCursor.h"
+#include "nsIMobileMessageCallback.h"
+#include "nsIMobileMessageCursorCallback.h"
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 class SmsChild : public PSmsChild
 {
 public:
-  SmsChild();
+  SmsChild()
+  {
+    MOZ_COUNT_CTOR(SmsChild);
+  }
 
 protected:
-  virtual ~SmsChild();
+  virtual ~SmsChild()
+  {
+    MOZ_COUNT_DTOR(SmsChild);
+  }
 
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyReceivedMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual bool
@@ -44,34 +52,72 @@ protected:
   virtual bool
   RecvNotifyDeliveryErrorMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual PSmsRequestChild*
   AllocPSmsRequest(const IPCSmsRequest& aRequest) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPSmsRequest(PSmsRequestChild* aActor) MOZ_OVERRIDE;
+
+  virtual PMobileMessageCursorChild*
+  AllocPMobileMessageCursor(const CreateMessageCursorRequest& aRequest) MOZ_OVERRIDE;
+
+  virtual bool
+  DeallocPMobileMessageCursor(PMobileMessageCursorChild* aActor) MOZ_OVERRIDE;
 };
 
 class SmsRequestChild : public PSmsRequestChild
 {
   friend class SmsChild;
 
   nsCOMPtr<nsIMobileMessageCallback> mReplyRequest;
 
 public:
   SmsRequestChild(nsIMobileMessageCallback* aReplyRequest);
 
 protected:
-  virtual ~SmsRequestChild();
+  virtual ~SmsRequestChild()
+  {
+    MOZ_COUNT_DTOR(SmsRequestChild);
+  }
 
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool
   Recv__delete__(const MessageReply& aReply) MOZ_OVERRIDE;
 };
 
+class MobileMessageCursorChild : public PMobileMessageCursorChild
+                               , public nsICursorContinueCallback
+{
+  friend class SmsChild;
+
+  nsCOMPtr<nsIMobileMessageCursorCallback> mCursorCallback;
+
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICURSORCONTINUECALLBACK
+
+  MobileMessageCursorChild(nsIMobileMessageCursorCallback* aCallback);
+
+protected:
+  virtual ~MobileMessageCursorChild()
+  {
+    MOZ_COUNT_DTOR(MobileMessageCursorChild);
+  }
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvNotifyResult(const SmsMessageData& aMessageData) MOZ_OVERRIDE;
+
+  virtual bool
+  Recv__delete__(const int32_t& aError) MOZ_OVERRIDE;
+};
+
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobilemessage_SmsChild_h
--- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp
@@ -8,137 +8,153 @@
 #include "nsXULAppAPI.h"
 #include "jsapi.h"
 #include "mozilla/dom/mobilemessage/SmsChild.h"
 #include "SmsMessage.h"
 #include "SmsFilter.h"
 #include "SmsRequest.h"
 #include "SmsSegmentInfo.h"
 
-namespace mozilla {
-namespace dom {
-namespace mobilemessage {
+using namespace mozilla::dom;
+using namespace mozilla::dom::mobilemessage;
 
+namespace {
+
+// TODO: Bug 767082 - WebSMS: sSmsChild leaks at shutdown
 PSmsChild* gSmsChild;
 
-NS_IMPL_ISUPPORTS2(SmsIPCService, nsISmsService, nsIMobileMessageDatabaseService)
-
-void
-SendRequest(const IPCSmsRequest& aRequest, nsIMobileMessageCallback* aRequestReply)
+PSmsChild*
+GetSmsChild()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  NS_WARN_IF_FALSE(gSmsChild,
-                   "Calling methods on SmsIPCService during "
-                   "shutdown!");
-
-  if (gSmsChild) {
-    SmsRequestChild* actor = new SmsRequestChild(aRequestReply);
-    gSmsChild->SendPSmsRequestConstructor(actor, aRequest);
-  }
-}
-
-PSmsChild*
-SmsIPCService::GetSmsChild()
-{
   if (!gSmsChild) {
     gSmsChild = ContentChild::GetSingleton()->SendPSmsConstructor();
+
+    NS_WARN_IF_FALSE(gSmsChild,
+                     "Calling methods on SmsIPCService during shutdown!");
   }
 
   return gSmsChild;
 }
 
+nsresult
+SendRequest(const IPCSmsRequest& aRequest,
+            nsIMobileMessageCallback* aRequestReply)
+{
+  PSmsChild* smsChild = GetSmsChild();
+  NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE);
+
+  SmsRequestChild* actor = new SmsRequestChild(aRequestReply);
+  smsChild->SendPSmsRequestConstructor(actor, aRequest);
+
+  return NS_OK;
+}
+
+nsresult
+SendCursorRequest(const CreateMessageCursorRequest& aRequest,
+                  nsIMobileMessageCursorCallback* aRequestReply,
+                  nsICursorContinueCallback** aResult)
+{
+  PSmsChild* smsChild = GetSmsChild();
+  NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE);
+
+  nsRefPtr<MobileMessageCursorChild> actor =
+    new MobileMessageCursorChild(aRequestReply);
+
+  // Add an extra ref for IPDL. Will be released in
+  // SmsChild::DeallocPMobileMessageCursor().
+  actor->AddRef();
+
+  smsChild->SendPMobileMessageCursorConstructor(actor, aRequest);
+
+  actor.forget(aResult);
+  return NS_OK;
+}
+
+} // anonymous namespace
+
+NS_IMPL_ISUPPORTS2(SmsIPCService,
+                   nsISmsService,
+                   nsIMobileMessageDatabaseService);
+
 /*
  * Implementation of nsISmsService.
  */
 NS_IMETHODIMP
 SmsIPCService::HasSupport(bool* aHasSupport)
 {
-  GetSmsChild()->SendHasSupport(aHasSupport);
+  PSmsChild* smsChild = GetSmsChild();
+  NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE);
+
+  smsChild->SendHasSupport(aHasSupport);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsIPCService::GetSegmentInfoForText(const nsAString & aText,
                                      nsIDOMMozSmsSegmentInfo** aResult)
 {
+  PSmsChild* smsChild = GetSmsChild();
+  NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE);
+
   SmsSegmentInfoData data;
-  bool ok = GetSmsChild()->SendGetSegmentInfoForText(nsString(aText), &data);
+  bool ok = smsChild->SendGetSegmentInfoForText(nsString(aText), &data);
   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
   info.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsIPCService::Send(const nsAString& aNumber,
                     const nsAString& aMessage,
                     nsIMobileMessageCallback* aRequest)
 {
-  SendRequest(SendMessageRequest(nsString(aNumber), nsString(aMessage)), aRequest);
-  return NS_OK;
+  return SendRequest(SendMessageRequest(nsString(aNumber), nsString(aMessage)),
+                     aRequest);
 }
 
 /*
  * Implementation of nsIMobileMessageDatabaseService.
  */
 NS_IMETHODIMP
 SmsIPCService::GetMessageMoz(int32_t aMessageId,
                              nsIMobileMessageCallback* aRequest)
 {
-  SendRequest(GetMessageRequest(aMessageId), aRequest);
-  return NS_OK;
+  return SendRequest(GetMessageRequest(aMessageId), aRequest);
 }
 
 NS_IMETHODIMP
 SmsIPCService::DeleteMessage(int32_t aMessageId,
                              nsIMobileMessageCallback* aRequest)
 {
-  SendRequest(DeleteMessageRequest(aMessageId), aRequest);
-  return NS_OK;
+  return SendRequest(DeleteMessageRequest(aMessageId), aRequest);
 }
 
 NS_IMETHODIMP
-SmsIPCService::CreateMessageList(nsIDOMMozSmsFilter* aFilter,
-                                 bool aReverse,
-                                 nsIMobileMessageCallback* aRequest)
+SmsIPCService::CreateMessageCursor(nsIDOMMozSmsFilter* aFilter,
+                                   bool aReverse,
+                                   nsIMobileMessageCursorCallback* aCursorCallback,
+                                   nsICursorContinueCallback** aResult)
 {
-  SmsFilterData data = SmsFilterData(static_cast<SmsFilter*>(aFilter)->GetData());
-  SendRequest(CreateMessageListRequest(data, aReverse), aRequest);
-  return NS_OK;
-}
+  const SmsFilterData& data =
+    SmsFilterData(static_cast<SmsFilter*>(aFilter)->GetData());
 
-NS_IMETHODIMP
-SmsIPCService::GetNextMessageInList(int32_t aListId,
-                                    nsIMobileMessageCallback* aRequest)
-{
-  SendRequest(GetNextMessageInListRequest(aListId), aRequest);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-SmsIPCService::ClearMessageList(int32_t aListId)
-{
-  GetSmsChild()->SendClearMessageList(aListId);
-  return NS_OK;
+  return SendCursorRequest(CreateMessageCursorRequest(data, aReverse),
+                           aCursorCallback, aResult);
 }
 
 NS_IMETHODIMP
 SmsIPCService::MarkMessageRead(int32_t aMessageId,
                                bool aValue,
                                nsIMobileMessageCallback* aRequest)
 {
-  SendRequest(MarkMessageReadRequest(aMessageId, aValue), aRequest);
-  return NS_OK;
+  return SendRequest(MarkMessageReadRequest(aMessageId, aValue), aRequest);
 }
 
 NS_IMETHODIMP
 SmsIPCService::GetThreadList(nsIMobileMessageCallback* aRequest)
 {
-  SendRequest(GetThreadListRequest(), aRequest);
-  return NS_OK;
+  return SendRequest(GetThreadListRequest(), aRequest);
 }
-
-} // namespace mobilemessage
-} // namespace dom
-} // namespace mozilla
--- a/dom/mobilemessage/src/ipc/SmsIPCService.h
+++ b/dom/mobilemessage/src/ipc/SmsIPCService.h
@@ -18,18 +18,15 @@ class PSmsChild;
 
 class SmsIPCService MOZ_FINAL : public nsISmsService
                               , public nsIMobileMessageDatabaseService
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISMSSERVICE
   NS_DECL_NSIMOBILEMESSAGEDATABASESERVICE
-
-private:
-  static PSmsChild* GetSmsChild();
 };
 
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobilemessage_SmsIPCService_h
--- a/dom/mobilemessage/src/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/src/ipc/SmsParent.cpp
@@ -33,21 +33,16 @@ SmsParent::SmsParent()
   obs->AddObserver(this, kSmsReceivedObserverTopic, false);
   obs->AddObserver(this, kSmsSendingObserverTopic, false);
   obs->AddObserver(this, kSmsSentObserverTopic, false);
   obs->AddObserver(this, kSmsFailedObserverTopic, false);
   obs->AddObserver(this, kSmsDeliverySuccessObserverTopic, false);
   obs->AddObserver(this, kSmsDeliveryErrorObserverTopic, false);
 }
 
-SmsParent::~SmsParent()
-{
-  MOZ_COUNT_DTOR(SmsParent);
-}
-
 void
 SmsParent::ActorDestroy(ActorDestroyReason why)
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     return;
   }
 
@@ -169,43 +164,28 @@ SmsParent::RecvGetSegmentInfoForText(con
 
   aResult->segments() = segments;
   aResult->charsPerSegment() = charsPerSegment;
   aResult->charsAvailableInLastSegment() = charsAvailableInLastSegment;
   return true;
 }
 
 bool
-SmsParent::RecvClearMessageList(const int32_t& aListId)
-{
-  nsCOMPtr<nsIMobileMessageDatabaseService> mobileMessageDBService =
-    do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(mobileMessageDBService, true);
-
-  mobileMessageDBService->ClearMessageList(aListId);
-  return true;
-}
-
-bool
 SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor,
                                       const IPCSmsRequest& aRequest)
 {
   SmsRequestParent* actor = static_cast<SmsRequestParent*>(aActor);
 
   switch (aRequest.type()) {
-    case IPCSmsRequest::TCreateMessageListRequest:
-      return actor->DoRequest(aRequest.get_CreateMessageListRequest());
     case IPCSmsRequest::TSendMessageRequest:
       return actor->DoRequest(aRequest.get_SendMessageRequest());
     case IPCSmsRequest::TGetMessageRequest:
       return actor->DoRequest(aRequest.get_GetMessageRequest());
     case IPCSmsRequest::TDeleteMessageRequest:
       return actor->DoRequest(aRequest.get_DeleteMessageRequest());
-    case IPCSmsRequest::TGetNextMessageInListRequest:
-      return actor->DoRequest(aRequest.get_GetNextMessageInListRequest());
     case IPCSmsRequest::TMarkMessageReadRequest:
       return actor->DoRequest(aRequest.get_MarkMessageReadRequest());
     case IPCSmsRequest::TGetThreadListRequest:
       return actor->DoRequest(aRequest.get_GetThreadListRequest());
     default:
       MOZ_NOT_REACHED("Unknown type!");
       return false;
   }
@@ -222,20 +202,49 @@ SmsParent::AllocPSmsRequest(const IPCSms
 
 bool
 SmsParent::DeallocPSmsRequest(PSmsRequestParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+bool
+SmsParent::RecvPMobileMessageCursorConstructor(PMobileMessageCursorParent* aActor,
+                                               const CreateMessageCursorRequest& aRequest)
+{
+  MobileMessageCursorParent* actor =
+    static_cast<MobileMessageCursorParent*>(aActor);
+
+  return actor->DoRequest(aRequest);
+}
+
+PMobileMessageCursorParent*
+SmsParent::AllocPMobileMessageCursor(const CreateMessageCursorRequest& aRequest)
+{
+  MobileMessageCursorParent* actor = new MobileMessageCursorParent();
+  // Add an extra ref for IPDL. Will be released in
+  // SmsParent::DeallocPMobileMessageCursor().
+  actor->AddRef();
+
+  return actor;
+}
+
+bool
+SmsParent::DeallocPMobileMessageCursor(PMobileMessageCursorParent* aActor)
+{
+  // MobileMessageCursorParent is refcounted, must not be freed manually.
+  static_cast<MobileMessageCursorParent*>(aActor)->Release();
+  return true;
+}
 
 /*******************************************************************************
  * SmsRequestParent
  ******************************************************************************/
+
 SmsRequestParent::SmsRequestParent()
 {
   MOZ_COUNT_CTOR(SmsRequestParent);
 }
 
 SmsRequestParent::~SmsRequestParent()
 {
   MOZ_COUNT_DTOR(SmsRequestParent);
@@ -299,47 +308,16 @@ SmsRequestParent::DoRequest(const Delete
   nsCOMPtr<nsIMobileMessageCallback> forwarder = new SmsRequestForwarder(mSmsRequest);
   nsresult rv = mobileMessageDBService->DeleteMessage(aRequest.messageId(), forwarder);
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
 bool
-SmsRequestParent::DoRequest(const CreateMessageListRequest& aRequest)
-{
-  nsCOMPtr<nsIMobileMessageDatabaseService> mobileMessageDBService =
-    do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
-
-  NS_ENSURE_TRUE(mobileMessageDBService, true);
-  mSmsRequest = SmsRequest::Create(this);
-  nsCOMPtr<nsIMobileMessageCallback> forwarder = new SmsRequestForwarder(mSmsRequest);
-  SmsFilter *filter = new SmsFilter(aRequest.filter());
-  nsresult rv = mobileMessageDBService->CreateMessageList(filter, aRequest.reverse(), forwarder);
-  NS_ENSURE_SUCCESS(rv, false);
-
-  return true;
-}
-
-bool
-SmsRequestParent::DoRequest(const GetNextMessageInListRequest& aRequest)
-{
-  nsCOMPtr<nsIMobileMessageDatabaseService> mobileMessageDBService =
-    do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
-
-  NS_ENSURE_TRUE(mobileMessageDBService, true);
-  mSmsRequest = SmsRequest::Create(this);
-  nsCOMPtr<nsIMobileMessageCallback> forwarder = new SmsRequestForwarder(mSmsRequest);
-  nsresult rv = mobileMessageDBService->GetNextMessageInList(aRequest.aListId(), forwarder);
-  NS_ENSURE_SUCCESS(rv, false);
-
-  return true;
-}
-
-bool
 SmsRequestParent::DoRequest(const MarkMessageReadRequest& aRequest)
 {
   nsCOMPtr<nsIMobileMessageDatabaseService> mobileMessageDBService =
     do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
 
   NS_ENSURE_TRUE(mobileMessageDBService, true);
   mSmsRequest = SmsRequest::Create(this);
   nsCOMPtr<nsIMobileMessageCallback> forwarder = new SmsRequestForwarder(mSmsRequest);
@@ -359,11 +337,95 @@ SmsRequestParent::DoRequest(const GetThr
   mSmsRequest = SmsRequest::Create(this);
   nsCOMPtr<nsIMobileMessageCallback> forwarder = new SmsRequestForwarder(mSmsRequest);
   nsresult rv = mobileMessageDBService->GetThreadList(forwarder);
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
+/*******************************************************************************
+ * MobileMessageCursorParent
+ ******************************************************************************/
+
+NS_IMPL_ISUPPORTS1(MobileMessageCursorParent, nsIMobileMessageCursorCallback)
+
+void
+MobileMessageCursorParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  // Two possible scenarios here:
+  // 1) When parent fails to SendNotifyResult() in NotifyCursorResult(), it's
+  //    destroyed without nulling out mContinueCallback.
+  // 2) When parent dies normally, mContinueCallback should have been cleared in
+  //    NotifyCursorError(), but just ensure this again.
+  mContinueCallback = nullptr;
+}
+
+bool
+MobileMessageCursorParent::RecvContinue()
+{
+  MOZ_ASSERT(mContinueCallback);
+
+  if (NS_FAILED(mContinueCallback->HandleContinue())) {
+    return NS_SUCCEEDED(NotifyCursorError(nsIMobileMessageCallback::INTERNAL_ERROR));
+  }
+
+  return true;
+}
+
+bool
+MobileMessageCursorParent::DoRequest(const CreateMessageCursorRequest& aRequest)
+{
+  nsresult rv = NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIMobileMessageDatabaseService> dbService =
+    do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
+  if (dbService) {
+    nsCOMPtr<nsIDOMMozSmsFilter> filter = new SmsFilter(aRequest.filter());
+    bool reverse = aRequest.reverse();
+
+    rv = dbService->CreateMessageCursor(filter, reverse, this,
+                                        getter_AddRefs(mContinueCallback));
+  }
+
+  if (NS_FAILED(rv)) {
+    return NS_SUCCEEDED(NotifyCursorError(nsIMobileMessageCallback::INTERNAL_ERROR));
+  }
+
+  return true;
+}
+
+// nsIMobileMessageCursorCallback
+
+NS_IMETHODIMP
+MobileMessageCursorParent::NotifyCursorError(int32_t aError)
+{
+  // The child process could die before this asynchronous notification, in which
+  // case ActorDestroy() was called and mContinueCallback is now null. Return an
+  // error here to avoid sending a message to the dead process.
+  NS_ENSURE_TRUE(mContinueCallback, NS_ERROR_FAILURE);
+
+  mContinueCallback = nullptr;
+
+  return Send__delete__(this, aError) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileMessageCursorParent::NotifyCursorResult(nsISupports* aResult)
+{
+  // The child process could die before this asynchronous notification, in which
+  // case ActorDestroy() was called and mContinueCallback is now null. Return an
+  // error here to avoid sending a message to the dead process.
+  NS_ENSURE_TRUE(mContinueCallback, NS_ERROR_FAILURE);
+
+  SmsMessage* message = static_cast<SmsMessage*>(aResult);
+  return SendNotifyResult(message->GetData()) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileMessageCursorParent::NotifyCursorDone()
+{
+  return NotifyCursorError(nsIMobileMessageCallback::SUCCESS_NO_ERROR);
+}
+
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/src/ipc/SmsParent.h
+++ b/dom/mobilemessage/src/ipc/SmsParent.h
@@ -3,16 +3,19 @@
  * 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/. */
 
 #ifndef mozilla_dom_mobilemessage_SmsParent_h
 #define mozilla_dom_mobilemessage_SmsParent_h
 
 #include "mozilla/dom/mobilemessage/PSmsParent.h"
 #include "mozilla/dom/mobilemessage/PSmsRequestParent.h"
+#include "mozilla/dom/mobilemessage/PMobileMessageCursorParent.h"
+#include "nsIDOMDOMCursor.h"
+#include "nsIMobileMessageCursorCallback.h"
 #include "nsIObserver.h"
 
 namespace mozilla {
 namespace dom {
 
 class ContentParent;
 class SmsRequest;
 
@@ -29,34 +32,44 @@ public:
 
 protected:
   virtual bool
   RecvHasSupport(bool* aHasSupport) MOZ_OVERRIDE;
 
   virtual bool
   RecvGetSegmentInfoForText(const nsString& aText, SmsSegmentInfoData* aResult) MOZ_OVERRIDE;
 
-  virtual bool
-  RecvClearMessageList(const int32_t& aListId) MOZ_OVERRIDE;
-
   SmsParent();
-  virtual ~SmsParent();
+  virtual ~SmsParent()
+  {
+    MOZ_COUNT_DTOR(SmsParent);
+  }
 
   virtual void
   ActorDestroy(ActorDestroyReason why);
 
   virtual bool
   RecvPSmsRequestConstructor(PSmsRequestParent* aActor,
                              const IPCSmsRequest& aRequest) MOZ_OVERRIDE;
 
   virtual PSmsRequestParent*
   AllocPSmsRequest(const IPCSmsRequest& aRequest) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPSmsRequest(PSmsRequestParent* aActor) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvPMobileMessageCursorConstructor(PMobileMessageCursorParent* aActor,
+                                      const CreateMessageCursorRequest& aRequest) MOZ_OVERRIDE;
+
+  virtual PMobileMessageCursorParent*
+  AllocPMobileMessageCursor(const CreateMessageCursorRequest& aRequest) MOZ_OVERRIDE;
+
+  virtual bool
+  DeallocPMobileMessageCursor(PMobileMessageCursorParent* aActor) MOZ_OVERRIDE;
 };
 
 class SmsRequestParent : public PSmsRequestParent
 {
   friend class SmsParent;
 
   nsRefPtr<SmsRequest> mSmsRequest;
 
@@ -76,25 +89,51 @@ protected:
 
   bool
   DoRequest(const GetMessageRequest& aRequest);
 
   bool
   DoRequest(const DeleteMessageRequest& aRequest);
 
   bool
-  DoRequest(const CreateMessageListRequest& aRequest);
-
-  bool
-  DoRequest(const GetNextMessageInListRequest& aRequest);
-
-  bool
   DoRequest(const MarkMessageReadRequest& aRequest);
 
   bool
   DoRequest(const GetThreadListRequest& aRequest);
 };
 
+class MobileMessageCursorParent : public PMobileMessageCursorParent
+                                , public nsIMobileMessageCursorCallback
+{
+  friend class SmsParent;
+
+  nsCOMPtr<nsICursorContinueCallback> mContinueCallback;
+
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMOBILEMESSAGECURSORCALLBACK
+
+protected:
+  MobileMessageCursorParent()
+  {
+    MOZ_COUNT_CTOR(MobileMessageCursorParent);
+  }
+
+  virtual ~MobileMessageCursorParent()
+  {
+    MOZ_COUNT_DTOR(MobileMessageCursorParent);
+  }
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
+
+  virtual bool
+  RecvContinue() MOZ_OVERRIDE;
+
+  bool
+  DoRequest(const CreateMessageCursorRequest& aRequest);
+};
+
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobilemessage_SmsParent_h
--- a/dom/mobilemessage/src/ipc/ipdl.mk
+++ b/dom/mobilemessage/src/ipc/ipdl.mk
@@ -1,9 +1,10 @@
 # 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/.
 
 IPDLSRCS = \
   SmsTypes.ipdlh \
   PSms.ipdl \
   PSmsRequest.ipdl \
+  PMobileMessageCursor.ipdl \
   $(NULL)