Use target.linux for all linux kernel based targets
am: 8fb8549537

Change-Id: Ieae9c387493f60ea8ad5086efddbdeb0e4378988
diff --git a/apps/weaver/card/src/com/android/weaver/Consts.java b/apps/weaver/card/src/com/android/weaver/Consts.java
index 22df865..6fd4c62 100644
--- a/apps/weaver/card/src/com/android/weaver/Consts.java
+++ b/apps/weaver/card/src/com/android/weaver/Consts.java
@@ -34,5 +34,6 @@
     public static final byte INS_GET_NUM_SLOTS = 0x02;
     public static final byte INS_WRITE = 0x4;
     public static final byte INS_READ = 0x6;
-    public static final byte INS_ERASE_ALL = 0x8;
+    public static final byte INS_ERASE_VALUE = 0x8;
+    public static final byte INS_ERASE_ALL = 0xa;
 }
diff --git a/apps/weaver/card/src/com/android/weaver/Slots.java b/apps/weaver/card/src/com/android/weaver/Slots.java
index 6f316ad..d9ecf8e 100644
--- a/apps/weaver/card/src/com/android/weaver/Slots.java
+++ b/apps/weaver/card/src/com/android/weaver/Slots.java
@@ -45,6 +45,16 @@
      */
     byte read(short slotId, byte[] key, short keyOffset, byte[] value, short valueOffset);
 
-    /** Erases the contents of all slots. */
+    /**
+     * Set the value of the identified slot to all zeros whilst leaving the key untouched.
+     *
+     * This is used to destroy the secret stored in the slot but retain the ability to authenticate
+     * by comparing a challenege with the slot's key.
+     *
+     * @param slotId ID of the slot of which to erase the value.
+     */
+    void eraseValue(short slotId);
+
+    /** Erases the key and value of all slots. */
     void eraseAll();
 }
diff --git a/apps/weaver/card/src/com/android/weaver/Weaver.java b/apps/weaver/card/src/com/android/weaver/Weaver.java
index 7bb3738..0839c5f 100644
--- a/apps/weaver/card/src/com/android/weaver/Weaver.java
+++ b/apps/weaver/card/src/com/android/weaver/Weaver.java
@@ -113,6 +113,10 @@
                 read(apdu);
                 return;
 
+            case Consts.INS_ERASE_VALUE:
+                eraseValue(apdu);
+                return;
+
             case Consts.INS_ERASE_ALL:
                 eraseAll(apdu);
                 return;
@@ -202,6 +206,25 @@
         }
     }
 
+    public static final short ERASE_VALUE_BYTES = Consts.SLOT_ID_BYTES;
+    private static final byte ERASE_VALUE_SLOT_ID_OFFSET = ISO7816.OFFSET_CDATA;
+
+    /**
+     * Erase the value of a slot.
+     *
+     * p1: 0
+     * p2: 0
+     * data: [slot ID]
+     */
+    private void eraseValue(APDU apdu) {
+        p1p2Unused(apdu);
+        receiveData(apdu, ERASE_VALUE_BYTES);
+
+        final byte buffer[] = apdu.getBuffer();
+        final short slotId = getSlotId(buffer, READ_DATA_SLOT_ID_OFFSET);
+        mSlots.eraseValue(slotId);
+    }
+
     /**
      * Erase all slots.
      *
diff --git a/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java b/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java
index c81ea0d..2eb1caa 100644
--- a/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java
+++ b/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java
@@ -64,6 +64,12 @@
     }
 
     @Override
+    public void eraseValue(short rawSlotId) {
+        final short slotId = validateSlotId(rawSlotId);
+        mSlots[slotId].eraseValue();
+    }
+
+    @Override
     public void eraseAll() {
         for (short i = 0; i < NUM_SLOTS; ++i) {
             mSlots[i].erase();
@@ -108,6 +114,14 @@
         }
 
         /**
+         * Clear the slot's value.
+         */
+        public void eraseValue() {
+            // This is intended to be destructive so a partial update is not a problem
+            Util.arrayFillNonAtomic(mValue, (short) 0, Consts.SLOT_VALUE_BYTES, (byte) 0);
+        }
+
+        /**
          * Transactionally clear the slot.
          */
         public void erase() {
@@ -170,7 +184,7 @@
         }
 
         /**
-         * 3.0.3 does not offset Util.arrayFill
+         * 3.0.3 does not offer Util.arrayFill
          */
         private static void arrayFill(byte[] bArray, short bOff, short bLen, byte bValue) {
             for (short i = 0; i < bLen; ++i) {
diff --git a/apps/weaver/include/ese/app/weaver.h b/apps/weaver/include/ese/app/weaver.h
index 67bea4b..7c8adad 100644
--- a/apps/weaver/include/ese/app/weaver.h
+++ b/apps/weaver/include/ese/app/weaver.h
@@ -114,6 +114,13 @@
 EseAppResult ese_weaver_read(struct EseWeaverSession *session, uint32_t slotId,
                              const uint8_t *key, uint8_t *value, uint32_t *timeout);
 
+/**
+ * Erase the value of a slot whilst maintaining the same key.
+ *
+ * @returns ESE_APP_RESULT_OK on success.
+ */
+EseAppResult ese_weaver_erase_value(struct EseWeaverSession *session, uint32_t slotId);
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
diff --git a/apps/weaver/tests/weaver_test.cpp b/apps/weaver/tests/weaver_test.cpp
index a2700e1..c8ae1ac 100644
--- a/apps/weaver/tests/weaver_test.cpp
+++ b/apps/weaver/tests/weaver_test.cpp
@@ -80,3 +80,18 @@
   ASSERT_NE(0, memcmp(VALUE, readValue, kEseWeaverValueSize));
   ASSERT_EQ(uint32_t{0}, timeout); // First timeout is 0
 }
+
+TEST_F(WeaverTest, writeAndEraseValue) {
+  const uint32_t slotId = 0;
+  ASSERT_EQ(ese_weaver_write(&mSession, slotId, KEY, VALUE), ESE_APP_RESULT_OK);
+  ASSERT_EQ(ese_weaver_erase_value(&mSession, slotId), ESE_APP_RESULT_OK);
+
+  // The read should be successful as the key is unchanged but the value should
+  // be all zeros
+  uint8_t readValue[kEseWeaverValueSize];
+  uint32_t timeout;
+  ASSERT_EQ(ESE_APP_RESULT_OK, ese_weaver_read(&mSession, slotId, KEY, readValue, &timeout));
+
+  const uint8_t expectedValue[kEseWeaverValueSize] = {0};
+  ASSERT_EQ(0, memcmp(readValue, expectedValue, kEseWeaverValueSize));
+}
diff --git a/apps/weaver/weaver.c b/apps/weaver/weaver.c
index 8f3caf8..6672246 100644
--- a/apps/weaver/weaver.c
+++ b/apps/weaver/weaver.c
@@ -31,7 +31,8 @@
                               kEseWeaverValueSize}; // slotid + key + value
 const uint8_t kRead[] = {0x80, 0x06, 0x00, 0x00,
                          4 + kEseWeaverKeySize}; // slotid + key
-const uint8_t kEraseAll[] = {0x80, 0x08, 0x00, 0x00};
+const uint8_t kEraseValue[] = {0x80, 0x08, 0x00, 0x00, 4}; // slotid
+const uint8_t kEraseAll[] = {0x80, 0x0a, 0x00, 0x00};
 
 // Build 32-bit int from big endian bytes
 static uint32_t get_uint32(uint8_t buf[4]) {
@@ -359,4 +360,48 @@
   return ESE_APP_RESULT_OK;
 }
 
+ESE_API EseAppResult ese_weaver_erase_value(struct EseWeaverSession *session,
+                                            uint32_t slotId) {
+  if (!session || !session->ese || !session->active) {
+    return ESE_APP_RESULT_ERROR_ARGUMENTS;
+  }
+  if (!session->active || session->channel_id == 0) {
+    return ESE_APP_RESULT_ERROR_ARGUMENTS;
+  }
+
+  // Prepare data to send
+  struct EseSgBuffer tx[3];
+  uint8_t chan = kEraseValue[0] | session->channel_id;
+  tx[0].base = &chan;
+  tx[0].len = 1;
+  tx[1].base = (uint8_t *)&kEraseValue[1];
+  tx[1].len = sizeof(kEraseValue) - 1;
+
+  // Slot ID in big endian
+  uint8_t slot_id[4];
+  put_uint32(slot_id, slotId);
+  tx[2].base = slot_id;
+  tx[2].len = sizeof(slot_id);
+
+  // Prepare buffer for result
+  struct EseSgBuffer rx;
+  uint8_t rx_buf[2];
+  rx.base = rx_buf;
+  rx.len = sizeof(rx_buf);
+
+  // Send the command
+  const int rx_len = ese_transceive_sg(session->ese, tx, 3, &rx, 1);
+
+  // Check for errors
+  if (rx_len < 2 || ese_error(session->ese)) {
+    ALOGE("Failed to write to slot");
+    return ESE_APP_RESULT_ERROR_COMM_FAILED;
+  }
+  if (rx_len > 2) {
+    ALOGE("Unexpected response from Weaver applet");
+    return ESE_APP_RESULT_ERROR_COMM_FAILED;
+  }
+  return check_apdu_status(rx_buf);
+}
+
 // TODO: erase all, not currently used
diff --git a/esed/Android.bp b/esed/Android.bp
index 53e7da6..997329f 100644
--- a/esed/Android.bp
+++ b/esed/Android.bp
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 
+subdirs = ["tests"]
+
 cc_defaults {
     name: "esed_defaults",
     proprietary: true,
@@ -35,13 +37,17 @@
     name: "esed",
     srcs: [
         "esed.cpp",
+        "Weaver.cpp",
     ],
     init_rc = ["esed.rc"],
     defaults: ["esed_defaults"],
     shared_libs: [
+        "android.hardware.weaver@1.0",
         "libese",
         "libbase",
+        "libese-app-boot",
         "libese_cpp_nxp_pn80t_nq_nci",
+        "libese-app-weaver",
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
diff --git a/esed/OemLock.cpp b/esed/OemLock.cpp
new file mode 100644
index 0000000..4a7974d
--- /dev/null
+++ b/esed/OemLock.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "OemLock.h"
+
+#include <vector>
+
+#include <android-base/logging.h>
+#include "../apps/boot/include/ese/app/boot.h"
+#include "ScopedEseConnection.h"
+
+namespace android {
+namespace esed {
+
+// libhidl
+using ::android::hardware::Void;
+
+// Methods from ::android::hardware::oemlock::V1_0::IOemLock follow.
+Return<void> OemLock::getName(getName_cb _hidl_cb) {
+  _hidl_cb(OemLockStatus::OK, {"01"});
+  return Void();
+}
+
+Return<OemLockSecureStatus> OemLock::setOemUnlockAllowedByCarrier(
+        bool allowed, const hidl_vec<uint8_t>& signature) {
+    LOG(INFO) << "Running OemLock::setOemUnlockAllowedByCarrier: " << allowed;
+    ScopedEseConnection ese{mEse};
+    ese.init();
+    // In general, setting the carrier lock to locked is only done in factory,
+    // but there is no reason the HAL could not be used in factory to do it.
+    // As such, the signature would actually be a specially formatted string of
+    // identifiers.  Unlocking requires a signature packaged in a simple format
+    // as well.
+    //
+    // See ../apps/boot/README.md for details.
+    std::vector<uint8_t> data(signature);
+    // "allowed" == unlocked == 0.
+    uint8_t lock_byte = allowed ? 0 : 1;
+    // xset expects the lock value as the first byte.
+    data.insert(data.cbegin(), lock_byte);
+
+   // Open SE session for applet
+    EseBootSession session;
+    ese_boot_session_init(&session);
+    EseAppResult res = ese_boot_session_open(mEse.ese_interface(), &session);
+    if (res != ESE_APP_RESULT_OK) {
+        LOG(ERROR) << "Failed to open a boot session: " << res;
+        return OemLockSecureStatus::FAILED;
+    }
+    res = ese_boot_lock_xset(&session, kEseBootLockIdCarrier,
+                             data.data(), data.size());
+    if (res != ESE_APP_RESULT_OK) {
+        LOG(ERROR) << "Failed to change lock state (allowed="
+                   << allowed << "): " << res;
+    }
+
+    // Try and close the session without perturbing our result value.
+    if (ese_boot_session_close(&session) != ESE_APP_RESULT_OK) {
+        LOG(WARNING) << "Failed to close boot session";
+    }
+
+    if (EseAppResultValue(res) == ESE_APP_RESULT_ERROR_APPLET) {
+        // 0004 and 0005 are invalid signature and invalid nonce respectively.
+        return OemLockSecureStatus::INVALID_SIGNATURE;
+    } else if (res != ESE_APP_RESULT_OK) {
+        return OemLockSecureStatus::FAILED;
+    }
+    return OemLockSecureStatus::OK;
+}
+
+Return<void> OemLock::isOemUnlockAllowedByCarrier(isOemUnlockAllowedByCarrier_cb _hidl_cb) {
+    LOG(VERBOSE) << "Running OemLock::isOemUnlockAllowedByCarrier";
+    ScopedEseConnection ese{mEse};
+    ese.init();
+    // Open SE session for applet
+    EseBootSession session;
+    ese_boot_session_init(&session);
+    EseAppResult res = ese_boot_session_open(mEse.ese_interface(), &session);
+    if (res != ESE_APP_RESULT_OK) {
+        LOG(ERROR) << "Failed to open a boot session: " << res;
+        _hidl_cb(OemLockStatus::FAILED, false);
+        return Void();
+    }
+    std::vector<uint8_t> data;
+    data.resize(1024);
+    uint16_t actualData = 0;
+    res = ese_boot_lock_xget(&session, kEseBootLockIdCarrier,
+                             &data[0], data.size(),
+                             &actualData);
+    if (res != ESE_APP_RESULT_OK || actualData == 0) {
+        LOG(ERROR) << "Failed to get lock state: " << res;
+    }
+
+    // Try and close the session without perturbing our result value.
+    if (ese_boot_session_close(&session) != ESE_APP_RESULT_OK) {
+        LOG(WARNING) << "Failed to close boot session";
+    }
+
+    if (res != ESE_APP_RESULT_OK) {
+        // Fail closed.
+        _hidl_cb(OemLockStatus::FAILED, false);
+        return Void();
+    }
+    // if data[0] == 1, lock == true, so allowed == false.
+    _hidl_cb(OemLockStatus::OK, data[0] != 0 ? false : true);
+    return Void();
+}
+
+Return<OemLockStatus> OemLock::setOemUnlockAllowedByDevice(bool allowed) {
+    LOG(INFO) << "Running OemLock::setOemUnlockAllowedByDevice: " << allowed;
+    ScopedEseConnection ese{mEse};
+    ese.init();
+    // "allowed" == unlocked == 0.
+    uint8_t lock_byte = allowed ? 0 : 1;
+
+   // Open SE session for applet
+    EseBootSession session;
+    ese_boot_session_init(&session);
+    EseAppResult res = ese_boot_session_open(mEse.ese_interface(), &session);
+    if (res != ESE_APP_RESULT_OK) {
+        LOG(ERROR) << "Failed to open a boot session: " << res;
+        return OemLockStatus::FAILED;
+    }
+    res = ese_boot_lock_set(&session, kEseBootLockIdDevice, lock_byte);
+    if (res != ESE_APP_RESULT_OK) {
+        LOG(ERROR) << "Failed to change device lock state (allowed="
+                   << allowed << "): " << res;
+    }
+
+    // Try and close the session without perturbing our result value.
+    if (ese_boot_session_close(&session) != ESE_APP_RESULT_OK) {
+        LOG(WARNING) << "Failed to close boot session";
+    }
+
+    if (res != ESE_APP_RESULT_OK) {
+        return OemLockStatus::FAILED;
+    }
+    return OemLockStatus::OK;
+}
+
+Return<void> OemLock::isOemUnlockAllowedByDevice(isOemUnlockAllowedByDevice_cb _hidl_cb) {
+    LOG(VERBOSE) << "Running OemLock::isOemUnlockAllowedByDevice";
+    ScopedEseConnection ese{mEse};
+    ese.init();
+    // Open SE session for applet
+    EseBootSession session;
+    ese_boot_session_init(&session);
+    EseAppResult res = ese_boot_session_open(mEse.ese_interface(), &session);
+    if (res != ESE_APP_RESULT_OK) {
+        LOG(ERROR) << "Failed to open a boot session: " << res;
+        _hidl_cb(OemLockStatus::FAILED, false);
+        return Void();
+    }
+    uint8_t lock_byte = 0;
+    res = ese_boot_lock_get(&session, kEseBootLockIdDevice, &lock_byte);
+    if (res != ESE_APP_RESULT_OK) {
+        LOG(ERROR) << "Failed to get device lock state: " << res;
+    }
+
+    // Try and close the session without perturbing our result value.
+    if (ese_boot_session_close(&session) != ESE_APP_RESULT_OK) {
+        LOG(WARNING) << "Failed to close boot session";
+    }
+
+    if (res != ESE_APP_RESULT_OK) {
+        // Fail closed.
+        _hidl_cb(OemLockStatus::FAILED, false);
+        return Void();
+    }
+    // if data[0] == 1, lock == true, so allowed == false.
+    _hidl_cb(OemLockStatus::OK, lock_byte != 0 ? false : true);
+    return Void();
+}
+
+}  // namespace esed
+}  // namespace android
diff --git a/esed/OemLock.h b/esed/OemLock.h
new file mode 100644
index 0000000..3d8fc9d
--- /dev/null
+++ b/esed/OemLock.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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_ESED_OEMLOCK_H
+#define ANDROID_ESED_OEMLOCK_H
+
+#include <android/hardware/oemlock/1.0/IOemLock.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <esecpp/EseInterface.h>
+
+namespace android {
+namespace esed {
+
+using ::android::EseInterface;
+using ::android::hardware::oemlock::V1_0::IOemLock;
+using ::android::hardware::oemlock::V1_0::OemLockSecureStatus;
+using ::android::hardware::oemlock::V1_0::OemLockStatus;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+struct OemLock : public IOemLock {
+    OemLock(EseInterface& ese) : mEse(ese) {}
+
+    // Methods from ::android::hardware::oemlock::V1_0::IOemLock follow.
+    Return<void> getName(getName_cb _hidl_cb) override;
+
+    Return<OemLockSecureStatus> setOemUnlockAllowedByCarrier(
+            bool allowed, const hidl_vec<uint8_t>& signature) override;
+
+    Return<void> isOemUnlockAllowedByCarrier(isOemUnlockAllowedByCarrier_cb _hidl_cb) override;
+
+    Return<OemLockStatus> setOemUnlockAllowedByDevice(bool allowed) override;
+
+    Return<void> isOemUnlockAllowedByDevice(isOemUnlockAllowedByDevice_cb _hidl_cb) override;
+
+private:
+    EseInterface& mEse;
+};
+
+}  // namespace esed
+}  // namespace android
+
+#endif  // ANDROID_ESED_OEMLOCK_H
diff --git a/esed/ScopedEseConnection.h b/esed/ScopedEseConnection.h
new file mode 100644
index 0000000..d953f42
--- /dev/null
+++ b/esed/ScopedEseConnection.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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_ESED_SCOPED_ESE_CONNECTION_H
+#define ANDROID_ESED_SCOPED_ESE_CONNECTION_H
+
+#include <android-base/logging.h>
+#include <esecpp/EseInterface.h>
+
+namespace android {
+namespace esed {
+
+using ::android::EseInterface;
+
+class ScopedEseConnection {
+ public:
+  ScopedEseConnection(EseInterface& ese) : mEse_(ese) {}
+  ~ScopedEseConnection() { mEse_.close(); }
+
+  bool init() {
+    mEse_.init();
+    int res = mEse_.open();
+    if (res != 0) {
+      LOG(ERROR) << "Failed to open eSE connection: " << res;
+      return false;
+    }
+    return true;
+  }
+
+ private:
+  EseInterface& mEse_;
+};
+
+}  // namespace esed
+}  // namespace android
+
+#endif  // ANDROID_ESED_SCOPED_ESE_CONNECTION_H
diff --git a/esed/Weaver.cpp b/esed/Weaver.cpp
new file mode 100644
index 0000000..1101551
--- /dev/null
+++ b/esed/Weaver.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "Weaver.h"
+
+#include <algorithm>
+#include <tuple>
+
+#include <android-base/logging.h>
+
+#include "../apps/weaver/include/ese/app/weaver.h"
+#include "ScopedEseConnection.h"
+
+namespace android {
+namespace esed {
+
+// libhidl
+using ::android::hardware::Void;
+
+// HAL
+using ::android::hardware::weaver::V1_0::WeaverConfig;
+using ::android::hardware::weaver::V1_0::WeaverReadResponse;
+using ::android::hardware::weaver::V1_0::WeaverReadStatus;
+
+// Methods from ::android::hardware::weaver::V1_0::IWeaver follow.
+Return<void> Weaver::getConfig(getConfig_cb _hidl_cb) {
+    LOG(VERBOSE) << "Running Weaver::getNumSlots";
+    // Open SE session for applet
+    ScopedEseConnection ese{mEse};
+    ese.init();
+    EseWeaverSession ws;
+    ese_weaver_session_init(&ws);
+    EseAppResult res = ese_weaver_session_open(mEse.ese_interface(), &ws);
+    if (EseAppResultValue(res) == ESE_APP_RESULT_ERROR_OS) {
+        switch (EseAppResultAppValue(res)) {
+        case 0x6999: // SW_APPLET_SELECT_FAILED
+        case 0x6A82: // SW_FILE_NOT_FOUND
+            // No applet means no Weaver storage. Report no slots to prompt
+            // fallback to software mode.
+            _hidl_cb(WeaverStatus::OK, WeaverConfig{0, 0, 0});
+            return Void();
+        }
+    } else if (res != ESE_APP_RESULT_OK) {
+        // Transient error
+        _hidl_cb(WeaverStatus::FAILED, WeaverConfig{});
+        return Void();
+    }
+
+    // Call the applet
+    uint32_t numSlots;
+    if (ese_weaver_get_num_slots(&ws, &numSlots) != ESE_APP_RESULT_OK) {
+        _hidl_cb(WeaverStatus::FAILED, WeaverConfig{});
+        return Void();
+    }
+
+    // Try and close the session
+    if (ese_weaver_session_close(&ws) != ESE_APP_RESULT_OK) {
+        LOG(WARNING) << "Failed to close Weaver session";
+    }
+
+    _hidl_cb(WeaverStatus::OK, WeaverConfig{numSlots, kEseWeaverKeySize, kEseWeaverValueSize});
+    return Void();
+}
+
+Return<WeaverStatus> Weaver::write(uint32_t slotId, const hidl_vec<uint8_t>& key,
+                           const hidl_vec<uint8_t>& value) {
+    LOG(INFO) << "Running Weaver::write on slot " << slotId;
+    ScopedEseConnection ese{mEse};
+    ese.init();
+    // Validate the key and value sizes
+    if (key.size() != kEseWeaverKeySize) {
+        LOG(ERROR) << "Key size must be " << kEseWeaverKeySize << ", not" << key.size() << " bytes";
+        return WeaverStatus::FAILED;
+    }
+    if (value.size() != kEseWeaverValueSize) {
+        LOG(ERROR) << "Value size must be " << kEseWeaverValueSize << ", not" << value.size()
+                   << " bytes";
+        return WeaverStatus::FAILED;
+    }
+
+    // Open SE session for applet
+    EseWeaverSession ws;
+    ese_weaver_session_init(&ws);
+    if (ese_weaver_session_open(mEse.ese_interface(), &ws) != ESE_APP_RESULT_OK) {
+        return WeaverStatus::FAILED;
+    }
+
+    // Call the applet
+    if (ese_weaver_write(&ws, slotId, key.data(), value.data()) != ESE_APP_RESULT_OK) {
+        return WeaverStatus::FAILED;
+    }
+
+    // Try and close the session
+    if (ese_weaver_session_close(&ws) != ESE_APP_RESULT_OK) {
+        LOG(WARNING) << "Failed to close Weaver session";
+    }
+
+    return WeaverStatus::OK;
+}
+
+Return<void> Weaver::read(uint32_t slotId, const hidl_vec<uint8_t>& key, read_cb _hidl_cb) {
+    LOG(VERBOSE) << "Running Weaver::read on slot " << slotId;
+
+    // Validate the key size
+    if (key.size() != kEseWeaverKeySize) {
+        LOG(ERROR) << "Key size must be " << kEseWeaverKeySize << ", not" << key.size() << " bytes";
+        _hidl_cb(WeaverReadStatus::FAILED, WeaverReadResponse{});
+        return Void();
+    }
+
+    // Open SE session for applet
+    ScopedEseConnection ese{mEse};
+    ese.init();
+    EseWeaverSession ws;
+    ese_weaver_session_init(&ws);
+    if (ese_weaver_session_open(mEse.ese_interface(), &ws) != ESE_APP_RESULT_OK) {
+        _hidl_cb(WeaverReadStatus::FAILED, WeaverReadResponse{});
+        return Void();
+    }
+
+    // Call the applet
+    hidl_vec<uint8_t> value;
+    value.resize(kEseWeaverValueSize);
+    uint32_t timeout;
+    const int res = ese_weaver_read(&ws, slotId, key.data(), value.data(), &timeout);
+    WeaverReadStatus status;
+    switch (res) {
+        case ESE_APP_RESULT_OK:
+            status = WeaverReadStatus::OK;
+            timeout = 0;
+            break;
+        case ESE_WEAVER_READ_WRONG_KEY:
+            status = WeaverReadStatus::INCORRECT_KEY;
+            value.resize(0);
+            break;
+        case ESE_WEAVER_READ_TIMEOUT:
+            status = WeaverReadStatus::THROTTLE;
+            value.resize(0);
+            break;
+        default:
+            status = WeaverReadStatus::FAILED;
+            timeout = 0;
+            value.resize(0);
+            break;
+    }
+
+    // Try and close the session
+    if (ese_weaver_session_close(&ws) != ESE_APP_RESULT_OK) {
+        LOG(WARNING) << "Failed to close Weaver session";
+    }
+
+    _hidl_cb(status, WeaverReadResponse{timeout, value});
+    return Void();
+}
+
+}  // namespace esed
+}  // namespace android
diff --git a/esed/Weaver.h b/esed/Weaver.h
new file mode 100644
index 0000000..7b35ef5
--- /dev/null
+++ b/esed/Weaver.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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_ESED_WEAVER_H
+#define ANDROID_ESED_WEAVER_H
+
+#include <android/hardware/weaver/1.0/IWeaver.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <esecpp/EseInterface.h>
+
+namespace android {
+namespace esed {
+
+using ::android::EseInterface;
+using ::android::hardware::weaver::V1_0::IWeaver;
+using ::android::hardware::weaver::V1_0::WeaverStatus;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+struct Weaver : public IWeaver {
+    Weaver(EseInterface& ese) : mEse(ese) {};
+
+    // Methods from ::android::hardware::weaver::V1_0::IWeaver follow.
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<WeaverStatus> write(uint32_t slotId, const hidl_vec<uint8_t>& key,
+                               const hidl_vec<uint8_t>& value) override;
+    Return<void> read(uint32_t slotId, const hidl_vec<uint8_t>& key, read_cb _hidl_cb) override;
+
+private:
+    EseInterface& mEse;
+};
+
+}  // namespace esed
+}  // namespace android
+
+#endif  // ANDROID_ESED_WEAVER_H
diff --git a/esed/esed.cpp b/esed/esed.cpp
index 2bfb890..01e0eef 100644
--- a/esed/esed.cpp
+++ b/esed/esed.cpp
@@ -19,6 +19,7 @@
 #include <thread>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <hidl/HidlTransportSupport.h>
 #include <utils/StrongPointer.h>
 
@@ -26,6 +27,8 @@
 #include <esecpp/NxpPn80tNqNci.h>
 using EseInterfaceImpl = android::NxpPn80tNqNci;
 
+#include "Weaver.h"
+
 using android::OK;
 using android::sp;
 using android::status_t;
@@ -34,13 +37,18 @@
 
 using namespace std::chrono_literals;
 
+// HALs
+using android::esed::Weaver;
+
 int main(int /* argc */, char** /* argv */) {
+    LOG(INFO) << "Waiting for property...";
+    android::base::WaitForProperty("init.svc.ese_load", "stopped");
     LOG(INFO) << "Starting esed...";
 
     // Open connection to the eSE
+    EseInterfaceImpl ese;
     uint32_t failCount = 0;
     while (true) {
-        EseInterfaceImpl ese;
         ese.init();
         if (ese.open() < 0) {
             std::string errMsg = "Failed to open connection to eSE";
@@ -59,13 +67,22 @@
         LOG(INFO) << "Opened connection to the eSE";
         break;
     }
+    // Close it until use.
+    ese.close();
+
 
     // This will be a single threaded daemon. This is important as libese is not
     // thread safe so we use binder to synchronize requests for us.
     constexpr bool thisThreadWillJoinPool = true;
     configureRpcThreadpool(1, thisThreadWillJoinPool);
 
-    // -- Instantiate other applet HALs here --
+    // Create Weaver HAL instance
+    sp<Weaver> weaver = new Weaver{ese};
+    const status_t status = weaver->registerAsService();
+    if (status != OK) {
+        LOG(ERROR) << "Failed to register Weaver as a service (status: " << status << ")";
+    }
+
 
     joinRpcThreadpool();
     return -1; // Should never reach here
diff --git a/esed/esed.rc b/esed/esed.rc
index ce9c4ac..572254a 100644
--- a/esed/esed.rc
+++ b/esed/esed.rc
@@ -2,3 +2,15 @@
     class hal
     user ese
     group ese
+
+on post-fs-data
+    mkdir /data/vendor/ese 0761 ese ese
+    restorecon /data/vendor/ese
+    start ese_load
+
+service ese_load /vendor/bin/ese_load force
+    disabled
+    oneshot
+    user ese
+    group ese
+    ioprio idle 0
diff --git a/esed/tests/Android.bp b/esed/tests/Android.bp
new file mode 100644
index 0000000..b5f504e
--- /dev/null
+++ b/esed/tests/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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.
+//
+
+// TODO: move to a VTS test
+cc_test {
+    name: "esed_integration_tests",
+    proprietary: true,
+    srcs: [
+        "weaver_integration_tests.cpp",
+    ],
+    host_supported: false,
+    shared_libs: [
+        "android.hardware.weaver@1.0",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/esed/tests/oemlock_integration_tests.cpp b/esed/tests/oemlock_integration_tests.cpp
new file mode 100644
index 0000000..9f1b148
--- /dev/null
+++ b/esed/tests/oemlock_integration_tests.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android/hardware/oemlock/1.0/IOemLock.h>
+#include <hidl/Status.h>
+
+#include <gtest/gtest.h>
+
+using ::android::OK;
+using ::android::sp;
+using ::android::status_t;
+using ::android::hardware::oemlock::V1_0::IOemLock;
+using ::android::hardware::oemlock::V1_0::OemLockSecureStatus;
+using ::android::hardware::oemlock::V1_0::OemLockStatus;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::testing::Test;
+
+class OemLockClientTest : public virtual Test {
+ public:
+  OemLockClientTest() {
+  }
+  virtual ~OemLockClientTest() { }
+  virtual void SetUp() {
+    service_ = IOemLock::getService();
+    ASSERT_NE(service_, nullptr);
+  }
+  virtual void TearDown() { }
+  sp<IOemLock> service_;
+};
+
+TEST_F(OemLockClientTest, GetName) {
+  std::string name;
+  OemLockStatus status;
+  auto get_name_cb = [&status, &name](OemLockStatus cb_status, hidl_string cb_name) {
+    status = cb_status;
+    name = cb_name.c_str();
+  };
+  Return<void> ret = service_->getName(get_name_cb);
+
+  EXPECT_TRUE(ret.isOk());
+  EXPECT_EQ(status, OemLockStatus::OK);
+  EXPECT_STREQ(name.c_str(), "01");
+};
+
+TEST_F(OemLockClientTest, AllowedByDeviceToggle) {
+  // Should always work as it is independent of carrier and boot lock states.
+  bool allowed = true;
+  OemLockStatus status;
+  auto get_allowed_cb = [&status, &allowed](OemLockStatus cb_status, bool cb_allowed) {
+    status = cb_status;
+    allowed = cb_allowed;
+  };
+
+  Return<OemLockStatus> set_ret = service_->setOemUnlockAllowedByDevice(allowed);
+  EXPECT_EQ(set_ret, OemLockStatus::OK);
+  Return<void> get_ret = service_->isOemUnlockAllowedByDevice(get_allowed_cb);
+  EXPECT_EQ(status, OemLockStatus::OK);
+  EXPECT_EQ(true, allowed);
+
+  allowed = false;
+  set_ret = service_->setOemUnlockAllowedByDevice(allowed);
+  EXPECT_EQ(set_ret, OemLockStatus::OK);
+  get_ret = service_->isOemUnlockAllowedByDevice(get_allowed_cb);
+  EXPECT_EQ(status, OemLockStatus::OK);
+  EXPECT_EQ(false, allowed);
+};
+
+TEST_F(OemLockClientTest, GetAllowedByCarrierIsFalse) {
+  bool allowed = true;
+  OemLockStatus status;
+  auto get_allowed_cb = [&status, &allowed](OemLockStatus cb_status, bool cb_allowed) {
+    status = cb_status;
+    allowed = cb_allowed;
+  };
+
+  Return<void> ret = service_->isOemUnlockAllowedByCarrier(get_allowed_cb);
+  EXPECT_EQ(status, OemLockStatus::OK);
+  EXPECT_EQ(false, allowed);
+};
diff --git a/esed/tests/weaver_integration_tests.cpp b/esed/tests/weaver_integration_tests.cpp
new file mode 100644
index 0000000..747955c
--- /dev/null
+++ b/esed/tests/weaver_integration_tests.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android/hardware/weaver/1.0/IWeaver.h>
+#include <hidl/Status.h>
+
+#include <gtest/gtest.h>
+
+using ::android::OK;
+using ::android::sp;
+using ::android::status_t;
+using ::android::hardware::weaver::V1_0::IWeaver;
+using ::android::hardware::weaver::V1_0::WeaverConfig;
+using ::android::hardware::weaver::V1_0::WeaverReadResponse;
+using ::android::hardware::weaver::V1_0::WeaverReadStatus;
+using ::android::hardware::weaver::V1_0::WeaverStatus;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::testing::Test;
+
+const std::vector<uint8_t> KEY{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+const std::vector<uint8_t> WRONG_KEY{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+const std::vector<uint8_t> VALUE{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+
+struct WeaverClientTest : public Test {
+  sp<IWeaver> service;
+
+  WeaverClientTest() = default;
+  virtual ~WeaverClientTest() = default;
+  void SetUp() override {
+    service = IWeaver::getService();
+    ASSERT_NE(service, nullptr);
+  }
+  void TearDown() override {}
+};
+
+TEST_F(WeaverClientTest, getConfig) {
+  bool cbkCalled = false;
+  WeaverStatus status;
+  WeaverConfig config;
+  auto ret = service->getConfig([&](WeaverStatus s, WeaverConfig c) {
+    cbkCalled = true;
+    status = s;
+    config = c;
+  });
+
+  EXPECT_TRUE(cbkCalled);
+  EXPECT_TRUE(ret.isOk());
+  EXPECT_EQ(status, WeaverStatus::OK);
+  const WeaverConfig expectedConfig{64, 16, 16};
+  EXPECT_EQ(config, expectedConfig);
+}
+
+TEST_F(WeaverClientTest, writeAndReadBack) {
+  const uint32_t slotId = 3;
+  auto ret = service->write(slotId, KEY, VALUE);
+  EXPECT_TRUE(ret.isOk());
+  EXPECT_EQ(ret, WeaverStatus::OK);
+
+  bool cbkCalled = false;
+  WeaverReadStatus status;
+  std::vector<uint8_t> readValue;
+  uint32_t timeout;
+  auto readRet = service->read(slotId, KEY, [&](WeaverReadStatus s, WeaverReadResponse r) {
+    cbkCalled = true;
+    status = s;
+    readValue = r.value;
+    timeout = r.timeout;
+  });
+  EXPECT_TRUE(cbkCalled);
+  EXPECT_TRUE(readRet.isOk());
+  EXPECT_EQ(status, WeaverReadStatus::OK);
+  EXPECT_EQ(readValue, VALUE);
+}
+
+TEST_F(WeaverClientTest, writeAndReadWithWrongKey) {
+  const uint32_t slotId = 3;
+  auto ret = service->write(slotId, KEY, VALUE);
+  EXPECT_TRUE(ret.isOk());
+  EXPECT_EQ(ret, WeaverStatus::OK);
+
+  bool cbkCalled = false;
+  WeaverReadStatus status;
+  std::vector<uint8_t> readValue;
+  uint32_t timeout;
+  auto readRet = service->read(slotId, WRONG_KEY, [&](WeaverReadStatus s, WeaverReadResponse r) {
+    cbkCalled = true;
+    status = s;
+    readValue = r.value;
+    timeout = r.timeout;
+  });
+  EXPECT_TRUE(cbkCalled);
+  EXPECT_TRUE(readRet.isOk());
+  EXPECT_EQ(status, WeaverReadStatus::INCORRECT_KEY);
+  EXPECT_EQ(timeout, uint32_t{0}); // first timeout is 0
+}
diff --git a/libese-cpp/NxpPn80tNqNci.cpp b/libese-cpp/NxpPn80tNqNci.cpp
index 3cdcda0..8cbd3b1 100644
--- a/libese-cpp/NxpPn80tNqNci.cpp
+++ b/libese-cpp/NxpPn80tNqNci.cpp
@@ -20,7 +20,9 @@
 namespace android {
 
 void NxpPn80tNqNci::init() {
-    mEse = new ::EseInterface;
+    if (mEse == nullptr) {
+        mEse = new ::EseInterface;
+    }
     ese_init(mEse, ESE_HW_NXP_PN80T_NQ_NCI);
 }