Snap for 5381581 from 52caef057413dca49b49c243ca9f6c9db5123673 to qt-release

Change-Id: I13d34321d91b1df0dd3634575954055db9c143bd
diff --git a/1.0/SecureElement.cpp b/1.0/SecureElement.cpp
index 2ca4e7f..6a38a25 100755
--- a/1.0/SecureElement.cpp
+++ b/1.0/SecureElement.cpp
@@ -32,6 +32,10 @@
 
 sp<V1_0::ISecureElementHalCallback> SecureElement::mCallbackV1_0 = nullptr;
 
+static void onLSCompleted(bool result, std::string reason, void* arg) {
+  ((SecureElement*)arg)->onStateChange(result, reason);
+}
+
 SecureElement::SecureElement()
     : mOpenedchannelCount(0),
       mOpenedChannels{false, false, false, false} {}
@@ -61,7 +65,7 @@
     return Void();
   }
 
-  LSCSTATUS lsStatus = LSC_doDownload(clientCallback);
+  LSCSTATUS lsStatus = LSC_doDownload(onLSCompleted, (void*)this);
   /*
    * LSC_doDownload returns LSCSTATUS_FAILED in case thread creation fails.
    * So return callback as false.
@@ -439,6 +443,11 @@
   return sestatus;
 }
 
+void SecureElement::onStateChange(bool result, std::string reason) {
+  ALOGD("%s: result: %d, reaon= %s", __func__, result, reason.c_str());
+  mCallbackV1_0->onStateChange(result);
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace secure_element
diff --git a/1.0/SecureElement.h b/1.0/SecureElement.h
index 6e5c4a7..a15028a 100755
--- a/1.0/SecureElement.h
+++ b/1.0/SecureElement.h
@@ -21,6 +21,8 @@
 #include <android/hardware/secure_element/1.0/ISecureElement.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
+#include <string>
+
 #include "phNxpEse_Api.h"
 
 namespace android {
@@ -61,6 +63,7 @@
   Return<::android::hardware::secure_element::V1_0::SecureElementStatus>
   closeChannel(uint8_t channelNumber) override;
   void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) override;
+  void onStateChange(bool result, std::string reason);
 
  private:
   uint8_t mOpenedchannelCount = 0;
diff --git a/1.1/NxpEseService.cpp b/1.1/NxpEseService.cpp
new file mode 100755
index 0000000..595f11e
--- /dev/null
+++ b/1.1/NxpEseService.cpp
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 NXP
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#define LOG_TAG "nxpese@1.0-service"
+#include <android/hardware/secure_element/1.1/ISecureElement.h>
+#include <hidl/LegacySupport.h>
+#include <log/log.h>
+#include <vendor/nxp/nxpese/1.0/INxpEse.h>
+
+#include "NxpEse.h"
+#include "SecureElement.h"
+
+// Generated HIDL files
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::secure_element::V1_1::ISecureElement;
+using android::hardware::secure_element::V1_1::implementation::SecureElement;
+using vendor::nxp::nxpese::V1_0::INxpEse;
+using vendor::nxp::nxpese::V1_0::implementation::NxpEse;
+
+int main() {
+  ALOGD("Secure Element HAL Service 1.1 is starting.");
+  sp<ISecureElement> se_service = new SecureElement();
+  configureRpcThreadpool(1, true /*callerWillJoin*/);
+  status_t status = se_service->registerAsService("eSE1");
+  if (status != OK) {
+    LOG_ALWAYS_FATAL(
+        "Could not register service for Secure Element HAL Iface (%d).",
+        status);
+    return -1;
+  }
+  sp<INxpEse> nxp_se_service = new NxpEse();
+  status = nxp_se_service->registerAsService();
+  if (status != OK) {
+    LOG_ALWAYS_FATAL(
+        "Could not register service for Power Secure Element Extn Iface (%d).",
+        status);
+    return -1;
+  }
+  ALOGD("Secure Element Service is ready");
+  joinRpcThreadpool();
+  return 1;
+}
diff --git a/1.1/SecureElement.cpp b/1.1/SecureElement.cpp
new file mode 100755
index 0000000..e04b8ba
--- /dev/null
+++ b/1.1/SecureElement.cpp
@@ -0,0 +1,503 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 NXP
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#define LOG_TAG "NxpEseHal"
+#include <log/log.h>
+
+#include "LsClient.h"
+#include "SecureElement.h"
+#include "phNxpEse_Api.h"
+
+extern bool ese_debug_enabled;
+
+namespace android {
+namespace hardware {
+namespace secure_element {
+namespace V1_1 {
+namespace implementation {
+
+sp<V1_0::ISecureElementHalCallback> SecureElement::mCallbackV1_0 = nullptr;
+sp<V1_1::ISecureElementHalCallback> SecureElement::mCallbackV1_1 = nullptr;
+
+static void onLSCompleted(bool result, std::string reason, void* arg) {
+  ((SecureElement*)arg)->onStateChange(result, reason);
+}
+
+SecureElement::SecureElement()
+    : mOpenedchannelCount(0), mOpenedChannels{false, false, false, false} {}
+
+Return<void> SecureElement::init(
+    const sp<V1_0::ISecureElementHalCallback>& clientCallback) {
+  ESESTATUS status = ESESTATUS_SUCCESS;
+
+  if (clientCallback == nullptr) {
+    return Void();
+  } else {
+    mCallbackV1_0 = clientCallback;
+    mCallbackV1_1 = nullptr;
+    if (!mCallbackV1_0->linkToDeath(this, 0 /*cookie*/)) {
+      ALOGE("%s: Failed to register death notification", __func__);
+    }
+  }
+  if (isSeInitialized()) {
+    clientCallback->onStateChange(true);
+    return Void();
+  }
+
+  status = seHalInit();
+  if (status != ESESTATUS_SUCCESS) {
+    clientCallback->onStateChange(false);
+    return Void();
+  }
+
+  LSCSTATUS lsStatus = LSC_doDownload(onLSCompleted, (void*)this);
+  /*
+   * LSC_doDownload returns LSCSTATUS_FAILED in case thread creation fails.
+   * So return callback as false.
+   * Otherwise callback will be called in LSDownload module.
+   */
+  if (lsStatus != LSCSTATUS_SUCCESS) {
+    ALOGE("%s: LSDownload thread creation failed!!!", __func__);
+    SecureElementStatus sestatus = seHalDeInit();
+    if (sestatus != SecureElementStatus::SUCCESS) {
+      ALOGE("%s: seHalDeInit failed!!!", __func__);
+    }
+    clientCallback->onStateChange(false);
+  }
+  return Void();
+}
+
+Return<void> SecureElement::init_1_1(
+    const sp<V1_1::ISecureElementHalCallback>& clientCallback) {
+  ESESTATUS status = ESESTATUS_SUCCESS;
+
+  if (clientCallback == nullptr) {
+    return Void();
+  } else {
+    mCallbackV1_1 = clientCallback;
+    mCallbackV1_0 = nullptr;
+    if (!mCallbackV1_1->linkToDeath(this, 0 /*cookie*/)) {
+      ALOGE("%s: Failed to register death notification", __func__);
+    }
+  }
+  if (isSeInitialized()) {
+    clientCallback->onStateChange_1_1(true, "NXP SE HAL init ok");
+    return Void();
+  }
+
+  status = seHalInit();
+  if (status != ESESTATUS_SUCCESS) {
+    clientCallback->onStateChange_1_1(false, "NXP SE HAL init failed");
+    return Void();
+  }
+
+  LSCSTATUS lsStatus = LSC_doDownload(onLSCompleted, (void*)this);
+  /*
+   * LSC_doDownload returns LSCSTATUS_FAILED in case thread creation fails.
+   * So return callback as false.
+   * Otherwise callback will be called in LSDownload module.
+   */
+  if (lsStatus != LSCSTATUS_SUCCESS) {
+    ALOGE("%s: LSDownload thread creation failed!!!", __func__);
+    SecureElementStatus sestatus = seHalDeInit();
+    if (sestatus != SecureElementStatus::SUCCESS) {
+      ALOGE("%s: seHalDeInit failed!!!", __func__);
+    }
+    clientCallback->onStateChange_1_1(false,
+                                      "Failed to create LS download thread");
+  }
+  return Void();
+}
+
+Return<void> SecureElement::getAtr(getAtr_cb _hidl_cb) {
+  hidl_vec<uint8_t> response;
+  _hidl_cb(response);
+  return Void();
+}
+
+Return<bool> SecureElement::isCardPresent() { return true; }
+
+Return<void> SecureElement::transmit(const hidl_vec<uint8_t>& data,
+                                     transmit_cb _hidl_cb) {
+  ESESTATUS status = ESESTATUS_FAILED;
+  phNxpEse_data cmdApdu;
+  phNxpEse_data rspApdu;
+  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
+  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
+
+  cmdApdu.len = data.size();
+  if (cmdApdu.len >= MIN_APDU_LENGTH) {
+    cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(data.size() * sizeof(uint8_t));
+    memcpy(cmdApdu.p_data, data.data(), cmdApdu.len);
+    status = phNxpEse_Transceive(&cmdApdu, &rspApdu);
+  }
+
+  hidl_vec<uint8_t> result;
+  if (status != ESESTATUS_SUCCESS) {
+    ALOGE("%s: transmit failed!!!", __func__);
+  } else {
+    result.resize(rspApdu.len);
+    memcpy(&result[0], rspApdu.p_data, rspApdu.len);
+  }
+  _hidl_cb(result);
+  phNxpEse_free(cmdApdu.p_data);
+  phNxpEse_free(rspApdu.p_data);
+  return Void();
+}
+
+Return<void> SecureElement::openLogicalChannel(const hidl_vec<uint8_t>& aid,
+                                               uint8_t p2,
+                                               openLogicalChannel_cb _hidl_cb) {
+  hidl_vec<uint8_t> manageChannelCommand = {0x00, 0x70, 0x00, 0x00, 0x01};
+
+  LogicalChannelResponse resApduBuff;
+  resApduBuff.channelNumber = 0xff;
+  memset(&resApduBuff, 0x00, sizeof(resApduBuff));
+
+  if (!isSeInitialized()) {
+    ESESTATUS status = seHalInit();
+    if (status != ESESTATUS_SUCCESS) {
+      ALOGE("%s: seHalInit Failed!!!", __func__);
+      _hidl_cb(resApduBuff, SecureElementStatus::IOERROR);
+      return Void();
+    }
+  }
+
+  SecureElementStatus sestatus = SecureElementStatus::IOERROR;
+  ESESTATUS status = ESESTATUS_FAILED;
+  phNxpEse_data cmdApdu;
+  phNxpEse_data rspApdu;
+
+  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
+  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
+
+  cmdApdu.len = manageChannelCommand.size();
+  cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(manageChannelCommand.size() *
+                                               sizeof(uint8_t));
+  if (cmdApdu.p_data != NULL) {
+    memcpy(cmdApdu.p_data, manageChannelCommand.data(), cmdApdu.len);
+    status = phNxpEse_Transceive(&cmdApdu, &rspApdu);
+  }
+  if (status != ESESTATUS_SUCCESS) {
+    /*Transceive failed*/
+    sestatus = SecureElementStatus::IOERROR;
+  } else if (rspApdu.p_data[rspApdu.len - 2] == 0x90 &&
+             rspApdu.p_data[rspApdu.len - 1] == 0x00) {
+    /*ManageChannel successful*/
+    resApduBuff.channelNumber = rspApdu.p_data[0];
+    mOpenedchannelCount++;
+    mOpenedChannels[resApduBuff.channelNumber] = true;
+    sestatus = SecureElementStatus::SUCCESS;
+  } else if (rspApdu.p_data[rspApdu.len - 2] == 0x6A &&
+             rspApdu.p_data[rspApdu.len - 1] == 0x81) {
+    sestatus = SecureElementStatus::CHANNEL_NOT_AVAILABLE;
+  } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x6E) ||
+              (rspApdu.p_data[rspApdu.len - 2] == 0x6D)) &&
+             rspApdu.p_data[rspApdu.len - 1] == 0x00) {
+    sestatus = SecureElementStatus::UNSUPPORTED_OPERATION;
+  }
+
+  /*Free the allocations*/
+  phNxpEse_free(cmdApdu.p_data);
+  phNxpEse_free(rspApdu.p_data);
+
+  if (sestatus != SecureElementStatus::SUCCESS) {
+    /*If first logical channel open fails, DeInit SE*/
+    if (isSeInitialized() && (mOpenedchannelCount == 0)) {
+      SecureElementStatus deInitStatus = seHalDeInit();
+      if (deInitStatus != SecureElementStatus::SUCCESS) {
+        ALOGE("%s: seDeInit Failed", __func__);
+      }
+    }
+    /*If manageChanle is failed in any of above cases
+    send the callback and return*/
+    _hidl_cb(resApduBuff, sestatus);
+    return Void();
+  }
+
+  ALOGD_IF(ese_debug_enabled, "%s: Sending selectApdu", __func__);
+  /*Reset variables if manageChannel is success*/
+  sestatus = SecureElementStatus::IOERROR;
+  status = ESESTATUS_FAILED;
+
+  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
+  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
+
+  cmdApdu.len = (int32_t)(5 + aid.size());
+  cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
+  if (cmdApdu.p_data != NULL) {
+    uint8_t xx = 0;
+    cmdApdu.p_data[xx++] = resApduBuff.channelNumber;
+    cmdApdu.p_data[xx++] = 0xA4;        // INS
+    cmdApdu.p_data[xx++] = 0x04;        // P1
+    cmdApdu.p_data[xx++] = p2;          // P2
+    cmdApdu.p_data[xx++] = aid.size();  // Lc
+    memcpy(&cmdApdu.p_data[xx], aid.data(), aid.size());
+
+    status = phNxpEse_Transceive(&cmdApdu, &rspApdu);
+  }
+
+  if (status != ESESTATUS_SUCCESS) {
+    /*Transceive failed*/
+    sestatus = SecureElementStatus::IOERROR;
+  } else {
+    uint8_t sw1 = rspApdu.p_data[rspApdu.len - 2];
+    uint8_t sw2 = rspApdu.p_data[rspApdu.len - 1];
+    /*Return response on success, empty vector on failure*/
+    /*Status is success*/
+    if (sw1 == 0x90 && sw2 == 0x00) {
+      /*Copy the response including status word*/
+      resApduBuff.selectResponse.resize(rspApdu.len);
+      memcpy(&resApduBuff.selectResponse[0], rspApdu.p_data, rspApdu.len);
+      sestatus = SecureElementStatus::SUCCESS;
+    }
+    /*AID provided doesn't match any applet on the secure element*/
+    else if (sw1 == 0x6A && sw2 == 0x82) {
+      sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR;
+    }
+    /*Operation provided by the P2 parameter is not permitted by the applet.*/
+    else if (sw1 == 0x6A && sw2 == 0x86) {
+      sestatus = SecureElementStatus::UNSUPPORTED_OPERATION;
+    }
+  }
+
+  if (sestatus != SecureElementStatus::SUCCESS) {
+    SecureElementStatus closeChannelStatus =
+        closeChannel(resApduBuff.channelNumber);
+    if (closeChannelStatus != SecureElementStatus::SUCCESS) {
+      ALOGE("%s: closeChannel Failed", __func__);
+    } else {
+      resApduBuff.channelNumber = 0xff;
+    }
+  }
+  _hidl_cb(resApduBuff, sestatus);
+  phNxpEse_free(cmdApdu.p_data);
+  phNxpEse_free(rspApdu.p_data);
+
+  return Void();
+}
+
+Return<void> SecureElement::openBasicChannel(const hidl_vec<uint8_t>& aid,
+                                             uint8_t p2,
+                                             openBasicChannel_cb _hidl_cb) {
+  hidl_vec<uint8_t> result;
+
+  if (!isSeInitialized()) {
+    ESESTATUS status = seHalInit();
+    if (status != ESESTATUS_SUCCESS) {
+      ALOGE("%s: seHalInit Failed!!!", __func__);
+      _hidl_cb(result, SecureElementStatus::IOERROR);
+      return Void();
+    }
+  }
+
+  SecureElementStatus sestatus = SecureElementStatus::IOERROR;
+  ESESTATUS status = ESESTATUS_FAILED;
+  phNxpEse_data cmdApdu;
+  phNxpEse_data rspApdu;
+
+  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
+  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
+
+  cmdApdu.len = (int32_t)(5 + aid.size());
+  cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
+  if (cmdApdu.p_data != NULL) {
+    uint8_t xx = 0;
+    cmdApdu.p_data[xx++] = 0x00;        // basic channel
+    cmdApdu.p_data[xx++] = 0xA4;        // INS
+    cmdApdu.p_data[xx++] = 0x04;        // P1
+    cmdApdu.p_data[xx++] = p2;          // P2
+    cmdApdu.p_data[xx++] = aid.size();  // Lc
+    memcpy(&cmdApdu.p_data[xx], aid.data(), aid.size());
+
+    status = phNxpEse_Transceive(&cmdApdu, &rspApdu);
+  }
+
+  if (status != ESESTATUS_SUCCESS) {
+    /* Transceive failed */
+    sestatus = SecureElementStatus::IOERROR;
+  } else {
+    uint8_t sw1 = rspApdu.p_data[rspApdu.len - 2];
+    uint8_t sw2 = rspApdu.p_data[rspApdu.len - 1];
+    /*Return response on success, empty vector on failure*/
+    /*Status is success*/
+    if ((sw1 == 0x90) && (sw2 == 0x00)) {
+      /*Copy the response including status word*/
+      result.resize(rspApdu.len);
+      memcpy(&result[0], rspApdu.p_data, rspApdu.len);
+      /*Set basic channel reference if it is not set */
+      if (!mOpenedChannels[0]) {
+        mOpenedChannels[0] = true;
+        mOpenedchannelCount++;
+      }
+      sestatus = SecureElementStatus::SUCCESS;
+    }
+    /*AID provided doesn't match any applet on the secure element*/
+    else if (sw1 == 0x6A && sw2 == 0x82) {
+      sestatus = SecureElementStatus::NO_SUCH_ELEMENT_ERROR;
+    }
+    /*Operation provided by the P2 parameter is not permitted by the applet.*/
+    else if (sw1 == 0x6A && sw2 == 0x86) {
+      sestatus = SecureElementStatus::UNSUPPORTED_OPERATION;
+    }
+  }
+
+  if (sestatus != SecureElementStatus::SUCCESS) {
+    SecureElementStatus closeStatus = SecureElementStatus::IOERROR;
+    /*If first basic channel open fails, DeInit SE*/
+    if ((mOpenedChannels[DEFAULT_BASIC_CHANNEL] == false) &&
+        (mOpenedchannelCount == 0)) {
+      closeStatus = seHalDeInit();
+    } else {
+      closeStatus = closeChannel(DEFAULT_BASIC_CHANNEL);
+    }
+    if (closeStatus != SecureElementStatus::SUCCESS) {
+      ALOGE("%s: close Failed", __func__);
+    }
+  }
+  _hidl_cb(result, sestatus);
+  phNxpEse_free(cmdApdu.p_data);
+  phNxpEse_free(rspApdu.p_data);
+  return Void();
+}
+
+Return<SecureElementStatus> SecureElement::closeChannel(uint8_t channelNumber) {
+  ESESTATUS status = ESESTATUS_FAILED;
+  SecureElementStatus sestatus = SecureElementStatus::FAILED;
+
+  phNxpEse_data cmdApdu;
+  phNxpEse_data rspApdu;
+
+  if ((channelNumber < DEFAULT_BASIC_CHANNEL) ||
+      (channelNumber >= MAX_LOGICAL_CHANNELS) ||
+      (mOpenedChannels[channelNumber] == false)) {
+    ALOGE("%s: invalid channel!!!", __func__);
+    sestatus = SecureElementStatus::FAILED;
+  } else if (channelNumber > DEFAULT_BASIC_CHANNEL) {
+    phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
+    phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
+    cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(5 * sizeof(uint8_t));
+    if (cmdApdu.p_data != NULL) {
+      uint8_t xx = 0;
+
+      cmdApdu.p_data[xx++] = channelNumber;
+      cmdApdu.p_data[xx++] = 0x70;           // INS
+      cmdApdu.p_data[xx++] = 0x80;           // P1
+      cmdApdu.p_data[xx++] = channelNumber;  // P2
+      cmdApdu.p_data[xx++] = 0x00;           // Lc
+      cmdApdu.len = xx;
+
+      status = phNxpEse_Transceive(&cmdApdu, &rspApdu);
+    }
+    if (status != ESESTATUS_SUCCESS) {
+      sestatus = SecureElementStatus::FAILED;
+    } else if ((rspApdu.p_data[rspApdu.len - 2] == 0x90) &&
+               (rspApdu.p_data[rspApdu.len - 1] == 0x00)) {
+      sestatus = SecureElementStatus::SUCCESS;
+    } else {
+      sestatus = SecureElementStatus::FAILED;
+    }
+    phNxpEse_free(cmdApdu.p_data);
+    phNxpEse_free(rspApdu.p_data);
+  }
+
+  if ((channelNumber == DEFAULT_BASIC_CHANNEL) ||
+      (sestatus == SecureElementStatus::SUCCESS)) {
+    if (mOpenedChannels[channelNumber] != false) mOpenedchannelCount--;
+    mOpenedChannels[channelNumber] = false;
+    /*If there are no channels remaining close secureElement*/
+    if (mOpenedchannelCount == 0) {
+      sestatus = seHalDeInit();
+    } else {
+      sestatus = SecureElementStatus::SUCCESS;
+    }
+  }
+  return sestatus;
+}
+
+void SecureElement::serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) {
+  ALOGE("%s: SecureElement serviceDied!!!", __func__);
+  SecureElementStatus sestatus = seHalDeInit();
+  if (sestatus != SecureElementStatus::SUCCESS) {
+    ALOGE("%s: seHalDeInit Faliled!!!", __func__);
+  }
+  if (mCallbackV1_0 != nullptr) {
+    mCallbackV1_0->unlinkToDeath(this);
+    mCallbackV1_0 = nullptr;
+  }
+  if (mCallbackV1_1 != nullptr) {
+    mCallbackV1_1->unlinkToDeath(this);
+    mCallbackV1_1 = nullptr;
+  }
+}
+
+bool SecureElement::isSeInitialized() { return phNxpEse_isOpen(); }
+
+ESESTATUS SecureElement::seHalInit() {
+  ESESTATUS status = ESESTATUS_SUCCESS;
+  phNxpEse_initParams initParams;
+  memset(&initParams, 0x00, sizeof(phNxpEse_initParams));
+  initParams.initMode = ESE_MODE_NORMAL;
+
+  status = phNxpEse_open(initParams);
+  if (status != ESESTATUS_SUCCESS) {
+    ALOGE("%s: SecureElement open failed!!!", __func__);
+  } else {
+    status = phNxpEse_init(initParams);
+    if (status != ESESTATUS_SUCCESS) {
+      ALOGE("%s: SecureElement init failed!!!", __func__);
+    }
+  }
+  return status;
+}
+
+Return<SecureElementStatus> SecureElement::seHalDeInit() {
+  ESESTATUS status = ESESTATUS_SUCCESS;
+  SecureElementStatus sestatus = SecureElementStatus::FAILED;
+  status = phNxpEse_deInit();
+  if (status != ESESTATUS_SUCCESS) {
+    sestatus = SecureElementStatus::FAILED;
+  } else {
+    status = phNxpEse_close();
+    if (status != ESESTATUS_SUCCESS) {
+      sestatus = SecureElementStatus::FAILED;
+    } else {
+      sestatus = SecureElementStatus::SUCCESS;
+
+      for (uint8_t xx = 0; xx < MAX_LOGICAL_CHANNELS; xx++) {
+        mOpenedChannels[xx] = false;
+      }
+      mOpenedchannelCount = 0;
+    }
+  }
+  return sestatus;
+}
+
+void SecureElement::onStateChange(bool result, std::string reason) {
+  ALOGD("%s: result: %d, reaon= %s", __func__, result, reason.c_str());
+  if (mCallbackV1_1 != nullptr) {
+    mCallbackV1_1->onStateChange_1_1(result, reason);
+  } else if (mCallbackV1_0 != nullptr) {
+    mCallbackV1_0->onStateChange(result);
+  }
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace secure_element
+}  // namespace hardware
+}  // namespace android
diff --git a/1.1/SecureElement.h b/1.1/SecureElement.h
new file mode 100755
index 0000000..d36b03f
--- /dev/null
+++ b/1.1/SecureElement.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ *  Copyright 2018 NXP
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H
+#define ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H
+
+#include <android/hardware/secure_element/1.0/types.h>
+#include <android/hardware/secure_element/1.1/ISecureElement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <string>
+
+#include "phNxpEse_Api.h"
+
+namespace android {
+namespace hardware {
+namespace secure_element {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::secure_element::V1_0::LogicalChannelResponse;
+using ::android::hardware::secure_element::V1_0::SecureElementStatus;
+using ::android::hardware::secure_element::V1_1::ISecureElement;
+using ::android::hidl::base::V1_0::IBase;
+
+#ifndef MAX_LOGICAL_CHANNELS
+#define MAX_LOGICAL_CHANNELS 0x04
+#endif
+#ifndef MIN_APDU_LENGTH
+#define MIN_APDU_LENGTH 0x04
+#endif
+#ifndef DEFAULT_BASIC_CHANNEL
+#define DEFAULT_BASIC_CHANNEL 0x00
+#endif
+
+struct SecureElement : public V1_1::ISecureElement,
+                       public hidl_death_recipient {
+  SecureElement();
+  Return<void> init(
+      const sp<V1_0::ISecureElementHalCallback>& clientCallback) override;
+  Return<void> init_1_1(
+      const sp<V1_1::ISecureElementHalCallback>& clientCallback) override;
+  Return<void> getAtr(getAtr_cb _hidl_cb) override;
+  Return<bool> isCardPresent() override;
+  Return<void> transmit(const hidl_vec<uint8_t>& data,
+                        transmit_cb _hidl_cb) override;
+  Return<void> openLogicalChannel(const hidl_vec<uint8_t>& aid, uint8_t p2,
+                                  openLogicalChannel_cb _hidl_cb) override;
+  Return<void> openBasicChannel(const hidl_vec<uint8_t>& aid, uint8_t p2,
+                                openBasicChannel_cb _hidl_cb) override;
+  Return<SecureElementStatus> closeChannel(uint8_t channelNumber) override;
+  void serviceDied(uint64_t /*cookie*/, const wp<IBase>& /*who*/) override;
+  void onStateChange(bool result, std::string reason);
+
+ private:
+  uint8_t mOpenedchannelCount = 0;
+  bool mOpenedChannels[MAX_LOGICAL_CHANNELS];
+  static sp<V1_0::ISecureElementHalCallback> mCallbackV1_0;
+  static sp<V1_1::ISecureElementHalCallback> mCallbackV1_1;
+  Return<SecureElementStatus> seHalDeInit();
+  ESESTATUS seHalInit();
+  bool isSeInitialized();
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace secure_element
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SECURE_ELEMENT_V1_1_SECUREELEMENT_H
diff --git a/1.1/android.hardware.secure_element@1.1-service-disabled.rc b/1.1/android.hardware.secure_element@1.1-service-disabled.rc
new file mode 100644
index 0000000..d17201f
--- /dev/null
+++ b/1.1/android.hardware.secure_element@1.1-service-disabled.rc
@@ -0,0 +1,5 @@
+service vendor.secure_element_hal_service_1_1 /vendor/bin/hw/android.hardware.secure_element@1.1-service-disabled
+    disabled
+    interface android.hardware.secure_element@1.1::ISecureElement eSE1
+    user secure_element
+    group secure_element
diff --git a/1.1/android.hardware.secure_element@1.1-service.rc b/1.1/android.hardware.secure_element@1.1-service.rc
new file mode 100644
index 0000000..388fffd
--- /dev/null
+++ b/1.1/android.hardware.secure_element@1.1-service.rc
@@ -0,0 +1,5 @@
+service vendor.secure_element_hal_service_1_1 /vendor/bin/hw/android.hardware.secure_element@1.1-service
+    class hal
+    interface android.hardware.secure_element@1.1::ISecureElement eSE1
+    user secure_element
+    group secure_element
diff --git a/Android.bp b/Android.bp
index e76951c..e29b2b9 100755
--- a/Android.bp
+++ b/Android.bp
@@ -42,7 +42,6 @@
     shared_libs: [
         "android.hardware.nfc@1.0",
         "android.hardware.nfc@1.1",
-        "android.hardware.secure_element@1.0",
         "libcutils",
         "libhardware",
         "libhidlbase",
@@ -70,7 +69,6 @@
 
     shared_libs: [
         "ese_spi_nxp",
-        "android.hardware.secure_element@1.0",
         "libcutils",
         "liblog",
         "libhidlbase",
@@ -81,6 +79,35 @@
 }
 
 cc_defaults {
+    name: "android.hardware.secure_element@1.1_defaults",
+    relative_install_path: "hw",
+    proprietary: true,
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "1.1/NxpEseService.cpp",
+        "1.1/SecureElement.cpp",
+        "extns/impl/NxpEse.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.secure_element@1.0",
+        "android.hardware.secure_element@1.1",
+        "ese_spi_nxp",
+        "libbase",
+        "ls_client",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "vendor.nxp.nxpese@1.0",
+        "vendor.nxp.nxpnfc@1.0",
+    ],
+}
+
+cc_defaults {
     name: "android.hardware.secure_element@1.0_defaults",
     relative_install_path: "hw",
     proprietary: true,
@@ -119,3 +146,15 @@
     init_rc: ["1.0/android.hardware.secure_element@1.0-service-disabled.rc"],
     defaults: ["android.hardware.secure_element@1.0_defaults"],
 }
+
+cc_binary {
+    name: "android.hardware.secure_element@1.1-service",
+    init_rc: ["1.1/android.hardware.secure_element@1.1-service.rc"],
+    defaults: ["android.hardware.secure_element@1.1_defaults"],
+}
+
+cc_binary {
+    name: "android.hardware.secure_element@1.1-service-disabled",
+    init_rc: ["1.1/android.hardware.secure_element@1.1-service-disabled.rc"],
+    defaults: ["android.hardware.secure_element@1.1_defaults"],
+}
diff --git a/ls_client/inc/LsClient.h b/ls_client/inc/LsClient.h
index 01facdb..b4fa43e 100755
--- a/ls_client/inc/LsClient.h
+++ b/ls_client/inc/LsClient.h
@@ -19,7 +19,7 @@
 #ifndef LSCLIENT_H_
 #define LSCLIENT_H_
 
-#include <android/hardware/secure_element/1.0/ISecureElementHalCallback.h>
+#include <string>
 
 typedef enum {
   LSCSTATUS_SUCCESS = (0x0000),
@@ -29,18 +29,25 @@
   LSCSTATUS_HASH_SLOT_INVALID = (0x0007)
 } LSCSTATUS;
 
-using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback;
-
 /*******************************************************************************
 **
-** Function:        LSC_doDownload
+** Function:        LSC_onCompletedCallback
 **
-** Description:     Perform LS during hal init
-**
-** Returns:         SUCCESS of ok
+** Description:     callback function when Loader Service Scripts thread is done
 **
 *******************************************************************************/
-LSCSTATUS LSC_doDownload(
-    const android::sp<ISecureElementHalCallback>& clientCallback);
+typedef void (*LSC_onCompletedCallback)(bool result, std::string reason,
+                                        void* args);
+
+/*******************************************************************************
+ **
+ ** Function:        LSC_doDownload
+ **
+ ** Description:     Start LS download process
+ **
+ ** Returns:         SUCCESS if ok
+ **
+ *******************************************************************************/
+LSCSTATUS LSC_doDownload(LSC_onCompletedCallback callback, void* arg);
 
 #endif /* LSCLIENT_H_ */
diff --git a/ls_client/inc/LsLib.h b/ls_client/inc/LsLib.h
index 1bb9214..b5002cc 100755
--- a/ls_client/inc/LsLib.h
+++ b/ls_client/inc/LsLib.h
@@ -510,6 +510,17 @@
 
 /*******************************************************************************
 **
+** Function:        LSC_ReadLscInfo
+**
+** Description:     Read the info of LS applet
+**
+** Returns:         SUCCESS/FAILURE
+**
+*******************************************************************************/
+LSCSTATUS LSC_ReadLscInfo(uint8_t* state, uint16_t* version);
+
+/*******************************************************************************
+**
 ** Function:        Numof_lengthbytes
 **
 ** Description:     Checks the number of length bytes and assigns
diff --git a/ls_client/src/LsClient.cpp b/ls_client/src/LsClient.cpp
index 05a24ba..f7a78de 100755
--- a/ls_client/src/LsClient.cpp
+++ b/ls_client/src/LsClient.cpp
@@ -16,14 +16,19 @@
  *
  ******************************************************************************/
 #define LOG_TAG "LSClient"
-#include "LsClient.h"
+
 #include <cutils/properties.h>
 #include <dirent.h>
+#include <errno.h>
 #include <log/log.h>
 #include <openssl/evp.h>
 #include <pthread.h>
 #include <stdlib.h>
+#include <iomanip>
+#include <sstream>
 #include <string>
+
+#include "LsClient.h"
 #include "LsLib.h"
 
 uint8_t datahex(char c);
@@ -41,9 +46,78 @@
 const uint8_t LS_DOWNLOAD_SUCCESS = 0x00;
 const uint8_t LS_DOWNLOAD_FAILED = 0x01;
 
-static android::sp<ISecureElementHalCallback> cCallback;
+class LSInfo {
+ public:
+  uint8_t m_status;
+  uint8_t m_version;
+  uint8_t m_mode;
+  uint8_t m_slot1_status;
+  uint8_t m_slot1_hash;
+  uint8_t m_slot2_status;
+  uint8_t m_slot2_hash;
+};
+
+static LSC_onCompletedCallback mCallback = nullptr;
+static void* mCallbackParams = NULL;
+
 void* performLSDownload_thread(void* data);
 static void getLSScriptSourcePrefix(std::string& prefix);
+static int compareLSHash(uint8_t* hash, uint8_t length);
+static std::string printLSStatus(int status);
+static std::string dumpLsInfo(LSInfo* info);
+
+static int compareLSHash(uint8_t* hash, uint8_t length) {
+  uint8_t ls253UpdaterScriptHash[HASH_DATA_LENGTH - 1] = {
+      0x65, 0x80, 0xFB, 0xA0, 0xCA, 0x59, 0xAE, 0x6C, 0x71, 0x6B,
+      0x15, 0xB1, 0xBD, 0xB1, 0x2C, 0x04, 0x29, 0x14, 0x8A, 0x8F};
+  uint8_t ls253AppletScriptHash[HASH_DATA_LENGTH - 1] = {
+      0x71, 0x7B, 0x8D, 0x0C, 0xEA, 0xE7, 0xEC, 0xC1, 0xCF, 0x47,
+      0x33, 0x10, 0xFE, 0x8E, 0x52, 0x5D, 0xB1, 0x43, 0x9B, 0xDE};
+  uint8_t lsFactoryScript1Hash[HASH_DATA_LENGTH - 1] = {
+      0x4A, 0xD0, 0x37, 0xD0, 0x44, 0x5B, 0x78, 0x55, 0x17, 0x5E,
+      0xFD, 0x87, 0x9C, 0xF1, 0x74, 0xBA, 0x77, 0xAD, 0x03, 0x62};
+  uint8_t lsFactoryScript2Hash[HASH_DATA_LENGTH - 1] = {
+      0xA9, 0xDB, 0x03, 0x53, 0xC2, 0xD7, 0xF8, 0xFC, 0x84, 0x37,
+      0xAF, 0xB9, 0x53, 0x06, 0x27, 0x9D, 0xE9, 0x68, 0x45, 0xEF};
+  uint8_t lsFactoryScript3Hash[HASH_DATA_LENGTH - 1] = {
+      0xA9, 0xAE, 0x5E, 0x66, 0x92, 0x8F, 0x70, 0xBD, 0x0A, 0xC7,
+      0x20, 0x8A, 0x6A, 0xBB, 0x63, 0xB3, 0xCA, 0x05, 0x58, 0xC1};
+  uint8_t lsFactoryScript4Hash[HASH_DATA_LENGTH - 1] = {
+      0x64, 0x73, 0x56, 0xAE, 0x58, 0x27, 0x6C, 0x07, 0x4B, 0xBA,
+      0x64, 0x7E, 0x6E, 0xC1, 0x97, 0xC8, 0x57, 0x17, 0x6E, 0x2D};
+  uint8_t* hashList[6] = {lsFactoryScript1Hash,   lsFactoryScript2Hash,
+                          lsFactoryScript3Hash,   lsFactoryScript4Hash,
+                          ls253UpdaterScriptHash, ls253AppletScriptHash};
+
+  if (length != HASH_DATA_LENGTH - 1) {
+    return 0xFF;
+  }
+  for (int i = 0; i < 6; i++) {
+    if (0 == memcmp(hash, hashList[i], length)) {
+      return i + 1;
+    }
+  }
+  return 0xFF;
+}
+
+static std::string dumpLsInfo(LSInfo* info) {
+  std::stringstream buff;
+  buff << std::setw(2) << std::setfill('0') << std::hex
+       << (int)(info->m_status);
+  buff << std::setw(2) << std::setfill('0') << std::hex
+       << (int)(info->m_version);
+  buff << std::setw(2) << std::setfill('0') << std::hex
+       << (int)(info->m_mode);
+  buff << std::setw(2) << std::setfill('0') << std::hex
+       << (int)(info->m_slot1_status);
+  buff << std::setw(2) << std::setfill('0') << std::hex
+       << (int)(info->m_slot1_hash);
+  buff << std::setw(2) << std::setfill('0') << std::hex
+       << (int)(info->m_slot2_status);
+  buff << std::setw(2) << std::setfill('0') << std::hex
+       << (int)(info->m_slot2_hash);
+  return buff.str();
+}
 
 void getLSScriptSourcePrefix(std::string& prefix) {
   char source_path[PROPERTY_VALUE_MAX] = {0};
@@ -92,20 +166,22 @@
 **
 ** Function:        LSC_doDownload
 **
-** Description:     Start LS download process by creating thread
+** Description:     Start LS download process
 **
-** Returns:         SUCCESS of ok
+** Returns:         SUCCESS if ok
 **
 *******************************************************************************/
-LSCSTATUS LSC_doDownload(
-    const android::sp<ISecureElementHalCallback>& clientCallback) {
+LSCSTATUS LSC_doDownload(LSC_onCompletedCallback callback, void* args) {
   static const char fn[] = "LSC_doDownload";
+
+  mCallback = callback;
+  mCallbackParams = args;
+
   LSCSTATUS status;
   pthread_t thread;
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  cCallback = clientCallback;
   if (pthread_create(&thread, &attr, &performLSDownload_thread, NULL) < 0) {
     ALOGE("%s: Thread creation failed", fn);
     status = LSCSTATUS_FAILED;
@@ -118,6 +194,98 @@
 
 /*******************************************************************************
 **
+** Function:        printLSStatus
+**
+** Description:     print LS applet state and Slot 1 & 2 data
+**
+** Returns:         LS status log
+**
+*******************************************************************************/
+std::string printLSStatus(int lsStatus) {
+  ALOGD_IF(ese_debug_enabled, "%s enter  ", __func__);
+
+  uint8_t slotHashBuffer[HASH_DATA_LENGTH] = {0};
+  uint16_t length = 0;
+  uint16_t lsVersion = 0;
+  uint8_t lsMode = 0;
+  std::stringstream outStream;
+  std::stringstream outHash;
+
+  LSInfo lsInfo;
+  memset(&lsInfo, 0xFF, sizeof(LSInfo));
+  lsInfo.m_status = lsStatus;
+
+  outStream << "\nCurrent LS info:";
+  /*Read LS applet mode*/
+  LSCSTATUS status = LSC_ReadLscInfo(&lsMode, &lsVersion);
+  if (status != LSCSTATUS_SUCCESS) {
+    outStream << dumpLsInfo(&lsInfo);
+    outStream << "\nFailed to access LS applet!\n";
+    return outStream.str();
+  }
+
+  ALOGI_IF(ese_debug_enabled, "LS applet version is %d.%d", (lsVersion >> 8),
+           (lsVersion & 0xFF));
+  if (lsMode == 2) {
+    ALOGI_IF(ese_debug_enabled, "LS is in UPDATE mode!");
+  }
+  lsInfo.m_version = lsVersion & 0xFF;
+  lsInfo.m_mode = lsMode;
+
+  /*Read the hash from slot 1*/
+  status = LSC_ReadLsHash(slotHashBuffer, &length, 1);
+  if (status != LSCSTATUS_SUCCESS) {
+    ALOGI_IF(ese_debug_enabled, "Failed to read Hash value from slot 1.");
+    outStream << dumpLsInfo(&lsInfo);
+    return outStream.str();
+  }
+  if (slotHashBuffer[HASH_DATA_LENGTH - 1] == LS_DOWNLOAD_SUCCESS) {
+    ALOGI_IF(ese_debug_enabled, "LS Slot 1 passed.");
+    lsInfo.m_slot1_status = LS_DOWNLOAD_SUCCESS;
+  } else {
+    ALOGI_IF(ese_debug_enabled, "LS Slot 1 failed.");
+    lsInfo.m_slot1_status = LS_DOWNLOAD_FAILED;
+  }
+  lsInfo.m_slot1_hash = compareLSHash(slotHashBuffer, HASH_DATA_LENGTH - 1);
+  if (lsInfo.m_slot1_hash == 0xFF) {
+    outHash << "\n slot 1 hash:\n";
+    for (int i = 0; i < HASH_DATA_LENGTH - 1; i++) {
+      outHash << std::setw(2) << std::setfill('0') << std::hex
+              << (int)slotHashBuffer[i];
+    }
+  }
+
+  /*Read the hash from slot 2*/
+  status = LSC_ReadLsHash(slotHashBuffer, &length, 2);
+  if (status != LSCSTATUS_SUCCESS) {
+    ALOGI_IF(ese_debug_enabled, "Failed to read Hash value from slot 1.");
+    outStream << dumpLsInfo(&lsInfo);
+    return outStream.str();
+  }
+  if (slotHashBuffer[HASH_DATA_LENGTH - 1] == LS_DOWNLOAD_SUCCESS) {
+    ALOGI_IF(ese_debug_enabled, "LS Slot 2 passed.");
+    lsInfo.m_slot2_status = LS_DOWNLOAD_SUCCESS;
+  } else {
+    ALOGI_IF(ese_debug_enabled, "LS Slot 2 failed.");
+    lsInfo.m_slot2_status = LS_DOWNLOAD_FAILED;
+  }
+  lsInfo.m_slot2_hash = compareLSHash(slotHashBuffer, HASH_DATA_LENGTH - 1);
+  if (lsInfo.m_slot2_hash == 0xFF) {
+    outHash << "\n slot 2 hash:\n";
+    for (int i = 0; i < HASH_DATA_LENGTH - 1; i++) {
+      outHash << std::setw(2) << std::setfill('0') << std::hex
+              << (int)slotHashBuffer[i];
+    }
+  }
+
+  outStream << dumpLsInfo(&lsInfo) << outHash.str();
+
+  ALOGD_IF(ese_debug_enabled, "%s exit\n", __func__);
+  return outStream.str();
+}
+
+/*******************************************************************************
+**
 ** Function:        performLSDownload_thread
 **
 ** Description:     Perform LS during hal init
@@ -154,8 +322,8 @@
     sourcePath += ls_script_source_suffix;
     FILE* fIn = fopen(sourcePath.c_str(), "rb");
     if (fIn == NULL) {
-      ALOGE("%s Cannot open LS script file %s\n", __func__, sourcePath.c_str());
-      ALOGE("%s Error : %s", __func__, strerror(errno));
+      ALOGE("%s Cannot open LS script file %s, Error: %s\n", __func__,
+            sourcePath.c_str(), strerror(errno));
       break;
     }
     ALOGD_IF(ese_debug_enabled, "%s File opened %s\n", __func__,
@@ -236,8 +404,11 @@
       } else {
         ALOGE("%s: Ese_deInit failed", __func__);
       }
-      cCallback->onStateChange(false);
-      break;
+
+      if (mCallback != nullptr) {
+        (mCallback)(false, printLSStatus(LS_DOWNLOAD_FAILED), mCallbackParams);
+        break;
+      }
     } else {
       /*If current script execution is succes, update the status along with the
        * hash to the applet*/
@@ -253,7 +424,9 @@
   phNxpEse_free(lsHashInfo.readBuffHash);
 
   if (status == LSCSTATUS_SUCCESS) {
-    cCallback->onStateChange(true);
+    if (mCallback != nullptr) {
+      (mCallback)(true, printLSStatus(LS_DOWNLOAD_SUCCESS), mCallbackParams);
+    }
   }
   pthread_exit(NULL);
   ALOGD_IF(ese_debug_enabled, "%s pthread_exit\n", __func__);
diff --git a/ls_client/src/LsLib.cpp b/ls_client/src/LsLib.cpp
index 9dac201..82f64f0 100755
--- a/ls_client/src/LsLib.cpp
+++ b/ls_client/src/LsLib.cpp
@@ -2130,3 +2130,57 @@
   phNxpEse_free(rspApdu.p_data);
   return lsStatus;
 }
+
+/*******************************************************************************
+**
+** Function:        LSC_ReadLscInfo
+**
+** Description:     Read the state of LS applet
+**
+** Returns:         SUCCESS/FAILURE
+**
+*******************************************************************************/
+LSCSTATUS LSC_ReadLscInfo(uint8_t* state, uint16_t* version) {
+  static const char fn[] = "LSC_ReadLscInfo";
+  phNxpEse_data cmdApdu;
+  phNxpEse_data rspApdu;
+  LSCSTATUS status = LSCSTATUS_FAILED;
+  ALOGD_IF(ese_debug_enabled, "%s: Enter ", __func__);
+
+  phNxpEse_memset(&cmdApdu, 0x00, sizeof(phNxpEse_data));
+  phNxpEse_memset(&rspApdu, 0x00, sizeof(phNxpEse_data));
+
+  /*p_data will have channel_id (1 byte) + SelectLsc APDU*/
+  cmdApdu.len = (int32_t)(sizeof(SelectLsc) + 1);
+  cmdApdu.p_data = (uint8_t*)phNxpEse_memalloc(cmdApdu.len * sizeof(uint8_t));
+  cmdApdu.p_data[0] = 0x00;  // fchannel 0
+
+  memcpy(&(cmdApdu.p_data[1]), SelectLsc, sizeof(SelectLsc));
+
+  ALOGD_IF(ese_debug_enabled, "%s: Selecting Loader service applet", fn);
+
+  ESESTATUS eseStat = phNxpEse_Transceive(&cmdApdu, &rspApdu);
+
+  if (eseStat != ESESTATUS_SUCCESS && (rspApdu.len == 0x00)) {
+    status = LSCSTATUS_FAILED;
+    ALOGE("%s: SE transceive failed status = 0x%X", fn, status);
+  } else if (((rspApdu.p_data[rspApdu.len - 2] == 0x90) &&
+              (rspApdu.p_data[rspApdu.len - 1] == 0x00))) {
+    status = Process_SelectRsp(rspApdu.p_data, (rspApdu.len - 2));
+    if (status != LSCSTATUS_SUCCESS) {
+      ALOGE("%s: Select Lsc Rsp doesnt have a valid key; status = 0x%X", fn,
+            status);
+    } else {
+      *state = rspApdu.p_data[18];
+      *version = (rspApdu.p_data[22] << 8) | rspApdu.p_data[23];
+    }
+  } else if (rspApdu.p_data[rspApdu.len - 2] != 0x90) {
+    ALOGE("%s: Selecting Loader service applet failed", fn);
+    status = LSCSTATUS_FAILED;
+  }
+
+  ALOGD_IF(ese_debug_enabled, "%s: Exit ", __func__);
+  phNxpEse_free(cmdApdu.p_data);
+  phNxpEse_free(rspApdu.p_data);
+  return status;
+}