Bug 731786 - B2G RIL: Support SIM cards that require PIN codes. r=philikon sr=sicking
authorYoshi Huang <yhuang@mozilla.com>
Thu, 12 Apr 2012 12:01:49 +0800
changeset 98580 fe33852b68c79df21be7cb3fb92f170609a8c701
parent 98579 68e2fd6845edbcf7476e788b1cb5e9edcae2c933
child 98581 925c8302f34a85ce1064406289e93dbbad7c4888
push id1116
push userlsblakk@mozilla.com
push dateMon, 16 Jul 2012 19:38:18 +0000
treeherdermozilla-beta@95f959a8b4dc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilikon, sicking
bugs731786
milestone15.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 731786 - B2G RIL: Support SIM cards that require PIN codes. r=philikon sr=sicking
dom/base/DOMRequestHelper.jsm
dom/network/interfaces/nsIDOMMobileConnection.idl
dom/network/interfaces/nsIMobileConnectionProvider.idl
dom/network/src/MobileConnection.cpp
dom/system/gonk/RILContentHelper.js
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/ril_consts.js
dom/system/gonk/ril_worker.js
--- a/dom/base/DOMRequestHelper.jsm
+++ b/dom/base/DOMRequestHelper.jsm
@@ -52,33 +52,46 @@ DOMRequestIpcHelper.prototype = {
   },
 
   observe: function(aSubject, aTopic, aData) {
     let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
     if (wId == this.innerWindowID) {
       Services.obs.removeObserver(this, "inner-window-destroyed");
       this._requests = [];
       this._window = null;
-      this._messages.forEach((function(msgName) {
-        cpmm.removeMessageListener(msgName, this);
-      }).bind(this));
+      this.removeMessageListener();
       if(this.uninit)
         this.uninit();
     }
   },
 
-  initHelper: function(aWindow, aMessages) {
+  initRequests: function initRequests() {
+    this._requests = [];
+  },
+
+  initMessageListener: function initMessageListener(aMessages) {
     this._messages = aMessages;
-    this._requests = [];
+    this._messages.forEach((function(msgName) {
+      cpmm.addMessageListener(msgName, this);
+    }).bind(this));
+  },
+  
+  initHelper: function(aWindow, aMessages) {
+    this.initMessageListener(aMessages);
+    this.initRequests();
+    this._id = this._getRandomId();
+    Services.obs.addObserver(this, "inner-window-destroyed", false);
     this._window = aWindow;
     let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     this.innerWindowID = util.currentInnerWindowID;
-    this._id = this._getRandomId();
-    Services.obs.addObserver(this, "inner-window-destroyed", false);
+  },
+
+  removeMessageListener: function removeMessageListener() {
     this._messages.forEach((function(msgName) {
-      cpmm.addMessageListener(msgName, this);
-    }).bind(this));
+        cpmm.removeMessageListener(msgName, this);
+      }).bind(this));
+    this._messages = null;
   },
 
   createRequest: function() {
     return Services.DOMRequest.createRequest(this._window);
   }
 }
--- a/dom/network/interfaces/nsIDOMMobileConnection.idl
+++ b/dom/network/interfaces/nsIDOMMobileConnection.idl
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMEventListener;
 interface nsIDOMDOMRequest;
 interface nsIDOMMozMobileConnectionInfo;
 
-[scriptable, uuid(ba2be619-fed6-4652-865a-c61f88ffeaa8)]
+[scriptable, uuid(962298cd-3443-423e-9e47-f22e24ad850b)]
 interface nsIDOMMozMobileConnection : nsIDOMEventTarget
 {
   /**
    * Indicates the state of the device's ICC card.
    *
    * Possible values: null, 'absent', 'pinRequired', 'pukRequired',
    * 'networkLocked', 'ready'.
    */
@@ -49,16 +49,121 @@ interface nsIDOMMozMobileConnection : ns
   attribute nsIDOMEventListener onvoicechange;
 
   /**
    * The 'datachange' event is notified whenever the data connection object
    * changes values.
    */
   attribute nsIDOMEventListener ondatachange;
 
+  /**
+   * Find out about the status of an ICC lock (e.g. the PIN lock).
+   *
+   * @param lockType
+   *        Identifies the lock type, e.g. "pin" for the PIN lock.
+   *
+   * @return a DOM Request.
+   *         The request's result will be an object containing 
+   *         information about the specified lock's status,
+   *         e.g. {lockType: "pin", enabled: true}.
+   */
+  nsIDOMDOMRequest getCardLock(in DOMString lockType);
+
+  /**
+   * Unlock a card lock.
+   *
+   * @param info
+   *        An object containing the information necessary to unlock
+   *        the given lock. At a minimum, this object must have a
+   *        "lockType" attribute which specifies the type of lock, e.g.
+   *        "pin" for the PIN lock. Other attributes are dependent on
+   *        the lock type.
+   *
+   * Examples:
+   *
+   * (1) Unlocking the PIN:
+   *
+   *   unlockCardLock({lockType: "pin",
+   *                   pin: "..."});
+   *
+   * (2) Unlocking the PUK and supplying a new PIN:
+   *
+   *   unlockCardLock({lockType: "puk",
+   *                   puk: "...",
+   *                   newPin: "..."});
+   *
+   * @return a nsIDOMDOMRequest.
+   *         The request's result will be an object containing 
+   *         information about the unlock operation.
+   *
+   * Examples:
+   *
+   * (1) Unlocking failed:
+   *
+   *     {
+   *       lockType:   "pin",
+   *       result:     false,
+   *       retryCount: 2
+   *     }
+   *
+   * (2) Unlocking succeeded:
+   *
+   *     {
+   *       lockType:  "pin",
+   *       result:    true
+   *     }
+   */
+  nsIDOMDOMRequest unlockCardLock(in jsval info);
+
+  /**
+   * Modify the state of a card lock.
+   *
+   * @param info
+   *        An object containing information about the lock and
+   *        how to modify its state. At a minimum, this object
+   *        must have a "lockType" attribute which specifies the
+   *        type of lock, e.g. "pin" for the PIN lock. Other
+   *        attributes are dependent on the lock type.
+   *
+   * Examples:
+   *
+   * (1) Disabling the PIN lock:
+   *
+   *   setCardLock({lockType: "pin",
+   *                pin: "...",
+   *                enabled: false});
+   *
+   * (2) Changing the PIN:
+   *
+   *   setCardLock({lockType: "pin",
+   *                pin: "...",
+   *                newPin: "..."});
+   *
+   * @return a nsIDOMDOMRequest.
+   *         The request's result will be an object containing 
+   *         information about the operation.
+   *
+   * Examples:
+   *
+   * (1) Enabling/Disabling card lock failed or change card lock failed.
+   *
+   *     {
+   *       lockType: "pin",
+   *       result: false,
+   *       retryCount: 2
+   *     }
+   *
+   * (2) Enabling/Disabling card lock succeed or change card lock succeed.
+   *
+   *     {
+   *       lockType: "pin",
+   *       result: true
+   *     }
+   */
+  nsIDOMDOMRequest setCardLock(in jsval info);
 };
 
 [scriptable, uuid(f3bb0611-5e4a-46f1-a8f5-cf592b37596e)]
 interface nsIDOMMozMobileConnectionInfo : nsISupports
 {
   /**
    * Indicates whether the device is connected to a mobile network.
    */
--- a/dom/network/interfaces/nsIMobileConnectionProvider.idl
+++ b/dom/network/interfaces/nsIMobileConnectionProvider.idl
@@ -7,17 +7,20 @@
 interface nsIDOMMozMobileConnectionInfo;
 interface nsIDOMDOMRequest;
 interface nsIDOMWindow;
 
 /**
  * XPCOM component (in the content process) that provides the mobile
  * network information.
  */
-[scriptable, uuid(1ecd19eb-15d4-47c0-a2cf-80cfa3b94eeb)]
+[scriptable, uuid(93202514-9ae9-482e-95bc-9c6ed62aea99)]
 interface nsIMobileConnectionProvider : nsISupports
 {
   readonly attribute DOMString cardState;
   readonly attribute nsIDOMMozMobileConnectionInfo voiceConnectionInfo;
   readonly attribute nsIDOMMozMobileConnectionInfo dataConnectionInfo;
 
   nsIDOMDOMRequest getNetworks(in nsIDOMWindow window);
+  nsIDOMDOMRequest getCardLock(in nsIDOMWindow window, in DOMString lockType);
+  nsIDOMDOMRequest unlockCardLock(in nsIDOMWindow window, in jsval info);
+  nsIDOMDOMRequest setCardLock(in nsIDOMWindow window, in jsval info);
 };
--- a/dom/network/src/MobileConnection.cpp
+++ b/dom/network/src/MobileConnection.cpp
@@ -157,16 +157,52 @@ MobileConnection::GetNetworks(nsIDOMDOMR
 
   if (!mProvider) {
     return NS_ERROR_FAILURE;
   }
 
   return mProvider->GetNetworks(GetOwner(), request);
 }
 
+NS_IMETHODIMP
+MobileConnection::GetCardLock(const nsAString& aLockType, nsIDOMDOMRequest** aDomRequest)
+{
+  *aDomRequest = nsnull;
+
+  if (!mProvider) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return mProvider->GetCardLock(GetOwner(), aLockType, aDomRequest);
+}
+
+NS_IMETHODIMP
+MobileConnection::UnlockCardLock(const jsval& aInfo, nsIDOMDOMRequest** aDomRequest)
+{
+  *aDomRequest = nsnull;
+
+  if (!mProvider) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return mProvider->UnlockCardLock(GetOwner(), aInfo, aDomRequest);
+}
+
+NS_IMETHODIMP
+MobileConnection::SetCardLock(const jsval& aInfo, nsIDOMDOMRequest** aDomRequest)
+{
+  *aDomRequest = nsnull;
+
+  if (!mProvider) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return mProvider->SetCardLock(GetOwner(), aInfo, aDomRequest);
+}
+
 nsresult
 MobileConnection::InternalDispatchEvent(const nsAString& aType)
 {
   nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
   nsresult rv = event->InitEvent(aType, false, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = event->SetTrusted(true);
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
 var RIL = {};
 Cu.import("resource://gre/modules/ril_consts.js", RIL);
 
 const DEBUG = false; // set to true to see debug messages
 
 const RILCONTENTHELPER_CID =
   Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
@@ -21,16 +22,22 @@ const MOBILECONNECTIONINFO_CID =
 
 const RIL_IPC_MSG_NAMES = [
   "RIL:CardStateChanged",
   "RIL:VoiceInfoChanged",
   "RIL:DataInfoChanged",
   "RIL:EnumerateCalls",
   "RIL:CallStateChanged",
   "RIL:CallError",
+  "RIL:GetCardLock:Return:OK",
+  "RIL:GetCardLock:Return:KO",
+  "RIL:SetCardLock:Return:OK",
+  "RIL:SetCardLock:Return:KO",
+  "RIL:UnlockCardLock:Return:OK",
+  "RIL:UnlockCardLock:Return:KO",
 ];
 
 const kVoiceChangedTopic     = "mobile-connection-voice-changed";
 const kDataChangedTopic      = "mobile-connection-data-changed";
 const kCardStateChangedTopic = "mobile-connection-cardstate-changed";
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
@@ -58,19 +65,18 @@ MobileConnectionInfo.prototype = {
   relSignalStrength: null
 };
 
 
 function RILContentHelper() {
   this.voiceConnectionInfo = new MobileConnectionInfo();
   this.dataConnectionInfo = new MobileConnectionInfo();
 
-  for each (let msgname in RIL_IPC_MSG_NAMES) {
-    cpmm.addMessageListener(msgname, this);
-  }
+  this.initRequests();
+  this.initMessageListener(RIL_IPC_MSG_NAMES);
   Services.obs.addObserver(this, "xpcom-shutdown", false);
 
   // Request initial state.
   let radioState = cpmm.QueryInterface(Ci.nsISyncMessageSender)
                        .sendSyncMessage("RIL:GetRadioState")[0];
   if (!radioState) {
     debug("Received null radioState from chrome process.");
     return;
@@ -79,16 +85,18 @@ function RILContentHelper() {
   for (let key in radioState.voice) {
     this.voiceConnectionInfo[key] = radioState.voice[key];
   }
   for (let key in radioState.data) {
     this.dataConnectionInfo[key] = radioState.data[key];
   }
 }
 RILContentHelper.prototype = {
+  __proto__: DOMRequestIpcHelper.prototype,
+
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMobileConnectionProvider,
                                          Ci.nsIRILContentHelper,
                                          Ci.nsIObserver]),
   classID:   RILCONTENTHELPER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
                                     classDescription: "RILContentHelper",
                                     interfaces: [Ci.nsIMobileConnectionProvider,
                                                  Ci.nsIRILContentHelper]}),
@@ -99,16 +107,49 @@ RILContentHelper.prototype = {
   voiceConnectionInfo: null,
   dataConnectionInfo:  null,
 
   getNetworks: function getNetworks(window) {
     //TODO bug 744344
     throw Components.Exception("Not implemented", Cr.NS_ERROR_NOT_IMPLEMENTED);
   },
 
+  getCardLock: function getCardLock(window, lockType) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = this.getRequestId(request);
+    cpmm.sendAsyncMessage("RIL:GetCardLock", {lockType: lockType, requestId: requestId});
+    return request;
+  },
+
+  unlockCardLock: function unlockCardLock(window, info) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    info.requestId = this.getRequestId(request);
+    cpmm.sendAsyncMessage("RIL:UnlockCardLock", info);
+    return request;
+  },
+
+  setCardLock: function setCardLock(window, info) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    info.requestId = this.getRequestId(request);
+    cpmm.sendAsyncMessage("RIL:SetCardLock", info);
+    return request;
+  },
+
   _telephonyCallbacks: null,
   _enumerationTelephonyCallbacks: null,
 
   registerTelephonyCallback: function registerTelephonyCallback(callback) {
     if (this._telephonyCallbacks) {
       if (this._telephonyCallbacks.indexOf(callback) != -1) {
         throw new Error("Already registered this callback!");
       }
@@ -190,27 +231,26 @@ RILContentHelper.prototype = {
   set speakerEnabled(value) {
     cpmm.sendAsyncMessage("RIL:SetSpeakerEnabled", value);
   },
 
   // nsIObserver
 
   observe: function observe(subject, topic, data) {
     if (topic == "xpcom-shutdown") {
-      for each (let msgname in RIL_IPC_MSG_NAMES) {
-        cpmm.removeMessageListener(msgname, this);
-      }
+      this.removeMessageListener();
       Services.obs.removeObserver(this, "xpcom-shutdown");
       cpmm = null;
     }
   },
 
   // nsIFrameMessageListener
 
   receiveMessage: function receiveMessage(msg) {
+    let request;
     debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json));
     switch (msg.name) {
       case "RIL:CardStateChanged":
         if (this.cardState != msg.json.cardState) {
           this.cardState = msg.json.cardState;
           Services.obs.notifyObservers(null, kCardStateChangedTopic, null);
         }
         break;
@@ -234,16 +274,32 @@ RILContentHelper.prototype = {
                                        [msg.json.callIndex, msg.json.state,
                                         msg.json.number, msg.json.isActive]);
         break;
       case "RIL:CallError":
         this._deliverTelephonyCallback("notifyError",
                                         [msg.json.callIndex, 
                                          msg.json.error]);    	  
     	break;
+      case "RIL:GetCardLock:Return:OK":
+      case "RIL:SetCardLock:Return:OK":
+      case "RIL:UnlockCardLock:Return:OK":
+        request = this.getRequest(msg.json.requestId);
+        if (request) {
+          Services.DOMRequest.fireSuccess(request, msg.json);
+        }
+        break;
+      case "RIL:GetCardLock:Return:KO":
+      case "RIL:SetCardLock:Return:KO":
+      case "RIL:UnlockCardLock:Return:KO":
+        request = this.getRequest(msg.json.requestId);
+        if (request) {
+          Services.DOMRequest.fireError(request, msg.json.errorMsg);
+        }
+        break;
     }
   },
 
   handleEnumerateCalls: function handleEnumerateCalls(calls) {
     debug("handleEnumerateCalls: " + JSON.stringify(calls));
     let callback = this._enumerationTelephonyCallbacks.shift();
     for (let i in calls) {
       let call = calls[i];
@@ -279,17 +335,16 @@ RILContentHelper.prototype = {
       }
       try {
         handler.apply(callback, args);
       } catch (e) {
         debug("callback handler for " + name + " threw an exception: " + e);
       }
     }
   },
-
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("-*- RILContentHelper: " + s + "\n");
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -39,16 +39,19 @@ const RIL_IPC_MSG_NAMES = [
   "RIL:StartTone",
   "RIL:StopTone",
   "RIL:Dial",
   "RIL:HangUp",
   "RIL:AnswerCall",
   "RIL:RejectCall",
   "RIL:HoldCall",
   "RIL:ResumeCall",
+  "RIL:GetCardLock",
+  "RIL:UnlockCardLock",
+  "RIL:SetCardLock"
 ];
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
                                    "@mozilla.org/sms/smsservice;1",
                                    "nsISmsService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsRequestManager",
                                    "@mozilla.org/sms/smsrequestmanager;1",
@@ -216,16 +219,25 @@ RadioInterfaceLayer.prototype = {
         this.rejectCall(msg.json);
         break;
       case "RIL:HoldCall":
         this.holdCall(msg.json);
         break;
       case "RIL:ResumeCall":
         this.resumeCall(msg.json);
         break;
+      case "RIL:GetCardLock":
+        this.getCardLock(msg.json);
+        break;
+      case "RIL:UnlockCardLock":
+        this.unlockCardLock(msg.json);
+        break;
+      case "RIL:SetCardLock":
+        this.setCardLock(msg.json);
+        break;
     }
   },
 
   onerror: function onerror(event) {
     debug("Got an error: " + event.filename + ":" +
           event.lineno + ": " + event.message + "\n");
     event.preventDefault();
   },
@@ -304,16 +316,25 @@ RadioInterfaceLayer.prototype = {
         debug("nitzTime networkTime=" + message.networkTimeInSeconds +
               " timezone=" + message.networkTimeZoneInMinutes +
               " dst=" + message.dstFlag +
               " timestamp=" + message.localTimeStampInMS);
         break;
       case "iccinfochange":
         this.radioState.icc = message;
         break;
+      case "iccgetcardlock":
+        this.handleICCGetCardLock(message);
+        break;
+      case "iccsetcardlock":
+        this.handleICCSetCardLock(message);
+        break;
+      case "iccunlockcardlock":
+        this.handleICCUnlockCardLock(message);
+        break;
       default:
         throw new Error("Don't know about this message type: " + message.type);
     }
   },
 
   updateVoiceConnection: function updateVoiceConnection(state) {
     let voiceInfo = this.radioState.voice;
     voiceInfo.type = "gsm"; //TODO see bug 726098.
@@ -629,16 +650,28 @@ RadioInterfaceLayer.prototype = {
       RILNetworkInterface.disconnect();
     }
     if (setting.value && !RILNetworkInterface.connected) {
       debug("Data call settings connect data call.");
       RILNetworkInterface.connect();
     }
   },
 
+  handleICCGetCardLock: function handleICCGetCardLock(message) {
+    ppmm.sendAsyncMessage("RIL:GetCardLock:Return:OK", message);
+  },
+
+  handleICCSetCardLock: function handleICCSetCardLock(message) {
+    ppmm.sendAsyncMessage("RIL:SetCardLock:Return:OK", message);
+  },
+
+  handleICCUnlockCardLock: function handleICCUnlockCardLock(message) {
+    ppmm.sendAsyncMessage("RIL:UnlockCardLock:Return:OK", message);
+  },
+
   // nsIObserver
 
   observe: function observe(subject, topic, data) {
     switch (topic) {
       case kMozSettingsChangedObserverTopic:
         let setting = JSON.parse(data);
         this.handleMozSettingsChanged(setting);
         break;
@@ -1191,19 +1224,82 @@ RadioInterfaceLayer.prototype = {
                              cid: cid,
                              reason: reason});
   },
 
   getDataCallList: function getDataCallList() {
     this.worker.postMessage({type: "getDataCallList"});
   },
 
+  getCardLock: function getCardLock(message) {
+    // Currently only support pin.
+    switch (message.lockType) {
+      case "pin" :
+        message.type = "getICCPinLock";
+        break;
+      default:
+        ppmm.sendAsyncMessage("RIL:GetCardLock:Return:KO",
+                              {errorMsg: "Unsupported Card Lock.",
+                               requestId: message.requestId});
+        return;
+    }
+    this.worker.postMessage(message);
+  },
+
+  unlockCardLock: function unlockCardLock(message) {
+    switch (message.lockType) {
+      case "pin":
+        message.type = "enterICCPIN";
+        break;
+      case "pin2":
+        message.type = "enterICCPIN2";
+        break;
+      case "puk":
+        message.type = "enterICCPUK";
+        break;
+      case "puk2":
+        message.type = "enterICCPUK2";
+        break;
+      default:
+        ppmm.sendAsyncMessage("RIL:UnlockCardLock:Return:KO",
+                              {errorMsg: "Unsupported Card Lock.",
+                               requestId: message.requestId});
+        return;
+    }
+    this.worker.postMessage(message);
+  },
+
+  setCardLock: function setCardLock(message) {
+    // Change pin.
+    if (message.newPin !== undefined) {
+      switch (message.lockType) {
+        case "pin":
+          message.type = "changeICCPIN";
+          break;
+        case "pin2":
+          message.type = "changeICCPIN2";
+          break;
+        default:
+          ppmm.sendAsyncMessage("RIL:SetCardLock:Return:KO",
+                                {errorMsg: "Unsupported Card Lock.",
+                                 requestId: message.requestId});
+          return;
+      }
+    } else { // Enable/Disable pin lock.
+      if (message.lockType != "pin") {
+          ppmm.sendAsyncMessage("RIL:SetCardLock:Return:KO",
+                                {errorMsg: "Unsupported Card Lock.",
+                                 requestId: message.requestId});
+      }
+      message.type = "setICCPinLock";
+    }
+    this.worker.postMessage(message);
+  }
 };
 
-
 let RILNetworkInterface = {
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface,
                                          Ci.nsIRILDataCallback]),
 
   // nsINetworkInterface
 
   NETWORK_STATE_UNKNOWN:       Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN,
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -418,16 +418,33 @@ const EF_PATH_DF_GSM = "7f20";
 const ICC_STATUS_NORMAL_ENDING = 0x90;
 const ICC_STATUS_NORMAL_ENDING_WITH_EXTRA = 0x91;
 const ICC_STATUS_WITH_SIM_DATA = 0x9e;
 const ICC_STATUS_WITH_RESPONSE_DATA = 0x9f;
 const ICC_STATUS_ERROR_WRONG_LENGTH = 0x67;
 const ICC_STATUS_ERROR_COMMAND_NOT_ALLOWED = 0x69;
 const ICC_STATUS_ERROR_WRONG_PARAMETERS = 0x6a;
 
+// ICC call barring facility.
+// TS 27.007, clause 7.4, +CLCK
+const ICC_CB_FACILITY_SIM = "SC";
+
+// ICC service class
+// TS 27.007, clause 7.4, +CLCK
+const ICC_SERVICE_CLASS_NONE = 0; // no user input
+const ICC_SERVICE_CLASS_VOICE = (1 << 0);
+const ICC_SERVICE_CLASS_DATA = (1 << 1);
+const ICC_SERVICE_CLASS_FAX = (1 << 2);
+const ICC_SERVICE_CLASS_SMS = (1 << 3);
+const ICC_SERVICE_CLASS_DATA_SYNC = (1 << 4);
+const ICC_SERVICE_CLASS_DATA_ASYNC = (1 << 5);
+const ICC_SERVICE_CLASS_PACKET = (1 << 6);
+const ICC_SERVICE_CLASS_PAD = (1 << 7);
+const ICC_SERVICE_CLASS_MAX = (1 << 7); // Max ICC_SERVICE_CLASS value
+
 /**
  * GSM PDU constants
  */
 
 // PDU TYPE-OF-ADDRESS
 const PDU_TOA_UNKNOWN       = 0x80; // Unknown. This is used when the user or
                                     // network has no a priori information
                                     // about the numbering plan.
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -757,56 +757,177 @@ let RIL = {
 
   /**
    * Enter a PIN to unlock the ICC.
    *
    * @param pin
    *        String containing the PIN.
    */
   enterICCPIN: function enterICCPIN(options) {
-    Buf.newParcel(REQUEST_ENTER_SIM_PIN);
+    Buf.newParcel(REQUEST_ENTER_SIM_PIN, options);
+    Buf.writeUint32(1);
+    Buf.writeString(options.pin);
+    Buf.sendParcel();
+  },
+
+  /**
+   * Enter a PIN2 to unlock the ICC.
+   *
+   * @param pin
+   *        String containing the PIN2.
+   */
+  enterICCPIN2: function enterICCPIN2(options) {
+    Buf.newParcel(REQUEST_ENTER_SIM_PIN2, options);
     Buf.writeUint32(1);
     Buf.writeString(options.pin);
     Buf.sendParcel();
   },
 
   /**
-   * Change the current ICC PIN number
+   * Change the current ICC PIN number.
    *
-   * @param oldPin
+   * @param pin
    *        String containing the old PIN value
    * @param newPin
    *        String containing the new PIN value
    */
   changeICCPIN: function changeICCPIN(options) {
-    Buf.newParcel(REQUEST_CHANGE_SIM_PIN);
+    Buf.newParcel(REQUEST_CHANGE_SIM_PIN, options);
     Buf.writeUint32(2);
-    Buf.writeString(options.oldPin);
+    Buf.writeString(options.pin);
     Buf.writeString(options.newPin);
     Buf.sendParcel();
   },
 
   /**
-   * Supplies SIM PUK and a new PIN to unlock the ICC
+   * Change the current ICC PIN2 number.
+   *
+   * @param pin
+   *        String containing the old PIN2 value
+   * @param newPin
+   *        String containing the new PIN2 value
+   */
+  changeICCPIN2: function changeICCPIN2(options) {
+    Buf.newParcel(REQUEST_CHANGE_SIM_PIN2, options);
+    Buf.writeUint32(2);
+    Buf.writeString(options.pin);
+    Buf.writeString(options.newPin);
+    Buf.sendParcel();
+  },
+  /**
+   * Supplies ICC PUK and a new PIN to unlock the ICC.
    *
    * @param puk
    *        String containing the PUK value.
    * @param newPin
    *        String containing the new PIN value.
    *
    */
    enterICCPUK: function enterICCPUK(options) {
-     Buf.newParcel(REQUEST_ENTER_SIM_PUK);
+     Buf.newParcel(REQUEST_ENTER_SIM_PUK, options);
+     Buf.writeUint32(2);
+     Buf.writeString(options.puk);
+     Buf.writeString(options.newPin);
+     Buf.sendParcel();
+   },
+
+  /**
+   * Supplies ICC PUK2 and a new PIN2 to unlock the ICC.
+   *
+   * @param puk
+   *        String containing the PUK2 value.
+   * @param newPin
+   *        String containing the new PIN2 value.
+   *
+   */
+   enterICCPUK2: function enterICCPUK2(options) {
+     Buf.newParcel(REQUEST_ENTER_SIM_PUK2, options);
      Buf.writeUint32(2);
      Buf.writeString(options.puk);
      Buf.writeString(options.newPin);
      Buf.sendParcel();
    },
 
   /**
+   * Get ICC Pin lock. A wrapper call to queryICCFacilityLock.
+   *
+   * @param requestId
+   *        Request Id from RadioInterfaceLayer.
+   */
+  getICCPinLock: function getICCPinLock(options) {
+    options.facility = ICC_CB_FACILITY_SIM;
+    options.password = ""; // For query no need to provide pin.
+    options.serviceClass = ICC_SERVICE_CLASS_VOICE |
+                           ICC_SERVICE_CLASS_DATA  |
+                           ICC_SERVICE_CLASS_FAX,
+    this.queryICCFacilityLock(options);
+  },
+
+  /**
+   *  Query ICC facility lock.
+   *
+   *  @param facility
+   *         One of ICC_CB_FACILITY_*.
+   *  @param password
+   *         Password for the facility, or "" if not required.
+   *  @param serviceClass
+   *         One of ICC_SERVICE_CLASS_*.
+   */
+  queryICCFacilityLock: function queryICCFacilityLock(options) {
+    Buf.newParcel(REQUEST_QUERY_FACILITY_LOCK, options);
+    Buf.writeUint32(3);
+    Buf.writeString(options.facility);
+    Buf.writeString(options.password);
+    Buf.writeString(options.serviceClass.toString());
+    Buf.sendParcel();
+  },
+
+  /**
+   * Set ICC Pin lock. A wrapper call to setICCFacilityLock.
+   *
+   * @param enabled
+   *        true to enable, false to disable.
+   * @param pin
+   *        Pin code.
+   * @param requestId
+   *        Request Id from RadioInterfaceLayer.
+   */
+  setICCPinLock: function setICCPinLock(options) {
+    options.facility = ICC_CB_FACILITY_SIM;
+    options.enabled = options.enabled;
+    options.password = options.pin;
+    options.serviceClass = ICC_SERVICE_CLASS_VOICE |
+                           ICC_SERVICE_CLASS_DATA  |
+                           ICC_SERVICE_CLASS_FAX,
+    this.setICCFacilityLock(options);
+  },
+
+  /**
+   * Set ICC facility lock.
+   *
+   * @param facility
+   *        One of ICC_CB_FACILITY_*.
+   * @param enabled
+   *        true to enable, false to disable.
+   * @param password
+   *        Password for the facility, or "" if not required.
+   * @param serviceClass
+   *        One of ICC_SERVICE_CLASS_*.
+   */
+  setICCFacilityLock: function setICCFacilityLock(options) {
+    Buf.newParcel(REQUEST_SET_FACILITY_LOCK, options);
+    Buf.writeUint32(4);
+    Buf.writeString(options.facility);
+    Buf.writeString(options.enabled ? "1" : "0");
+    Buf.writeString(options.password);
+    Buf.writeString(options.serviceClass.toString());
+    Buf.sendParcel();
+  },
+
+  /**
    *  Request an ICC I/O operation.
    * 
    *  See TS 27.007 "restricted SIM" operation, "AT Command +CRSM".
    *  The sequence is in the same order as how libril reads this parcel,
    *  see the struct RIL_SIM_IO_v5 or RIL_SIM_IO_v6 defined in ril.h
    *
    *  @param command 
    *         The I/O command, one of the ICC_COMMAND_* constants.
@@ -2149,35 +2270,57 @@ RIL[REQUEST_GET_SIM_STATUS] = function R
       pin2:           Buf.readUint32()
     });
   }
 
   if (DEBUG) debug("iccStatus: " + JSON.stringify(iccStatus));
   this._processICCStatus(iccStatus);
 };
 RIL[REQUEST_ENTER_SIM_PIN] = function REQUEST_ENTER_SIM_PIN(length, options) {
-  if (options.rilRequestError) {
-    return;
-  }
-
-  let response = Buf.readUint32List();
-  if (DEBUG) debug("REQUEST_ENTER_SIM_PIN returned " + response);
+  this.sendDOMMessage({type: "iccunlockcardlock",
+                       lockType: "pin",
+                       result: options.rilRequestError == 0 ? true : false,
+                       retryCount: length ? Buf.readUint32List()[0] : -1,
+                       requestId: options.requestId});
 };
 RIL[REQUEST_ENTER_SIM_PUK] = function REQUEST_ENTER_SIM_PUK(length, options) {
-  if (options.rilRequestError) {
-    return;
-  }
-
-  let response = Buf.readUint32List();
-  if (DEBUG) debug("REQUEST_ENTER_SIM_PUK returned " + response);
+  this.sendDOMMessage({type: "iccunlockcardlock",
+                       lockType: "puk",
+                       result: options.rilRequestError == 0 ? true : false,
+                       retryCount: length ? Buf.readUint32List()[0] : -1,
+                       requestId: options.requestId});
+};
+RIL[REQUEST_ENTER_SIM_PIN2] = function REQUEST_ENTER_SIM_PIN2(length, options) {
+  this.sendDOMMessage({type: "iccunlockcardlock",
+                       lockType: "pin2",
+                       result: options.rilRequestError == 0 ? true : false,
+                       retryCount: length ? Buf.readUint32List()[0] : -1,
+                       requestId: options.requestId});
 };
-RIL[REQUEST_ENTER_SIM_PIN2] = null;
-RIL[REQUEST_ENTER_SIM_PUK2] = null;
-RIL[REQUEST_CHANGE_SIM_PIN] = null;
-RIL[REQUEST_CHANGE_SIM_PIN2] = null;
+RIL[REQUEST_ENTER_SIM_PUK2] = function REQUEST_ENTER_SIM_PUK(length, options) {
+  this.sendDOMMessage({type: "iccunlockcardlock",
+                       lockType: "puk2",
+                       result: options.rilRequestError == 0 ? true : false,
+                       retryCount: length ? Buf.readUint32List()[0] : -1,
+                       requestId: options.requestId});
+};
+RIL[REQUEST_CHANGE_SIM_PIN] = function REQUEST_CHANGE_SIM_PIN(length, options) {
+  this.sendDOMMessage({type: "iccsetcardlock",
+                       lockType: "pin",
+                       result: options.rilRequestError == 0 ? true : false,
+                       retryCount: length ? Buf.readUint32List()[0] : -1,
+                       requestId: options.requestId});
+};
+RIL[REQUEST_CHANGE_SIM_PIN2] = function REQUEST_CHANGE_SIM_PIN2(length, options) {
+  this.sendDOMMessage({type: "iccsetcardlock",
+                       lockType: "pin2",
+                       result: options.rilRequestError == 0 ? true : false,
+                       retryCount: length ? Buf.readUint32List()[0] : -1,
+                       requestId: options.requestId});
+};
 RIL[REQUEST_ENTER_NETWORK_DEPERSONALIZATION] = null;
 RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   this.initRILQuirks();
 
@@ -2529,18 +2672,34 @@ RIL[REQUEST_DEACTIVATE_DATA_CALL] = func
   }
 
   let datacall = this.currentDataCalls[options.cid];
   delete this.currentDataCalls[options.cid];
   datacall.state = GECKO_NETWORK_STATE_DISCONNECTED;
   this.sendDOMMessage({type: "datacallstatechange",
                        datacall: datacall});
 };
-RIL[REQUEST_QUERY_FACILITY_LOCK] = null;
-RIL[REQUEST_SET_FACILITY_LOCK] = null;
+RIL[REQUEST_QUERY_FACILITY_LOCK] = function REQUEST_QUERY_FACILITY_LOCK(length, options) {
+  if (options.rilRequestError) {
+    return;
+  }
+
+  let response = Buf.readUint32List()[0];
+  this.sendDOMMessage({type: "iccgetcardlock",
+                       lockType: "pin",
+                       enabled: response == 0 ? false : true,
+                       requestId: options.requestId});
+};
+RIL[REQUEST_SET_FACILITY_LOCK] = function REQUEST_SET_FACILITY_LOCK(length, options) {
+  this.sendDOMMessage({type: "iccsetcardlock",
+                       lockType: "pin",
+                       result: options.rilRequestError == 0 ? true : false,
+                       retryCount: length ? Buf.readUint32List()[0] : -1,
+                       requestId: options.requestId});
+};
 RIL[REQUEST_CHANGE_BARRING_PASSWORD] = null;
 RIL[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELECTION_MODE(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   let mode = Buf.readUint32List();
   this.networkSelectionMode = mode[0];