Merge "No double encryption on FDE+FBE SD cards"
diff --git a/Android.bp b/Android.bp
index 5941cd9..aca6493 100644
--- a/Android.bp
+++ b/Android.bp
@@ -50,7 +50,6 @@
         "libhardware_legacy",
         "libhidlbase",
         "libhwbinder",
-        "libkeystore_binder",
         "libkeyutils",
         "liblog",
         "liblogwrap",
@@ -65,9 +64,7 @@
     defaults: ["vold_default_flags"],
 
     srcs: [
-        "binder/android/os/IVold.aidl",
-        "binder/android/os/IVoldListener.aidl",
-        "binder/android/os/IVoldTaskListener.aidl",
+        ":vold_aidl",
     ],
     shared_libs: [
         "libbinder",
@@ -80,6 +77,11 @@
     },
 }
 
+cc_library_headers {
+    name: "libvold_headers",
+    export_include_dirs: ["."],
+}
+
 // Static library factored out to support testing
 cc_library_static {
     name: "libvold",
@@ -111,6 +113,7 @@
         "VoldNativeService.cpp",
         "VoldUtil.cpp",
         "VolumeManager.cpp",
+        "authorization_set.cpp",
         "cryptfs.cpp",
         "fs/Ext4.cpp",
         "fs/F2fs.cpp",
@@ -123,6 +126,16 @@
         "model/VolumeBase.cpp",
         "secontext.cpp",
     ],
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "model/ObbVolume.cpp",
+            ],
+            static_libs: [
+                "libarcobbvolume",
+            ],
+        },
+    },
 }
 
 cc_binary {
@@ -134,6 +147,13 @@
 
     srcs: ["main.cpp"],
     static_libs: ["libvold"],
+    product_variables: {
+        arc: {
+            static_libs: [
+                "libarcobbvolume",
+            ]
+        },
+    },
     init_rc: ["vold.rc"],
 
     required: [
@@ -187,4 +207,13 @@
     ],
 }
 
+filegroup {
+    name: "vold_aidl",
+    srcs: [
+        "binder/android/os/IVold.aidl",
+        "binder/android/os/IVoldListener.aidl",
+        "binder/android/os/IVoldTaskListener.aidl",
+    ],
+}
+
 subdirs = ["tests"]
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index be43b33..2f6aa1a 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -41,14 +41,15 @@
 
 #include <hardware/hw_auth_token.h>
 
-#include <keystore/authorization_set.h>
-#include <keystore/keystore_hidl_support.h>
 
 extern "C" {
 
 #include "crypto_scrypt.h"
 }
 
+#include "authorization_set.h"
+#include "keystore_hidl_support.h"
+
 namespace android {
 namespace vold {
 using namespace keystore;
diff --git a/Keymaster.cpp b/Keymaster.cpp
index 4d055c2..e32d598 100644
--- a/Keymaster.cpp
+++ b/Keymaster.cpp
@@ -17,9 +17,10 @@
 #include "Keymaster.h"
 
 #include <android-base/logging.h>
-#include <keystore/keymaster_tags.h>
-#include <keystore/authorization_set.h>
-#include <keystore/keystore_hidl_support.h>
+
+#include "authorization_set.h"
+#include "keymaster_tags.h"
+#include "keystore_hidl_support.h"
 
 using namespace ::keystore;
 using android::hardware::hidl_string;
diff --git a/Keymaster.h b/Keymaster.h
index 6eec6e9..6ed5276 100644
--- a/Keymaster.h
+++ b/Keymaster.h
@@ -25,7 +25,8 @@
 
 #include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
 #include <android-base/macros.h>
-#include <keystore/authorization_set.h>
+
+#include "authorization_set.h"
 
 namespace android {
 namespace vold {
diff --git a/MoveStorage.cpp b/MoveStorage.cpp
index 4f5ebe8..4624026 100644
--- a/MoveStorage.cpp
+++ b/MoveStorage.cpp
@@ -18,10 +18,11 @@
 #include "Utils.h"
 #include "VolumeManager.h"
 
-#include <android-base/stringprintf.h>
 #include <android-base/logging.h>
-#include <private/android_filesystem_config.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <hardware_legacy/power.h>
+#include <private/android_filesystem_config.h>
 
 #include <thread>
 
@@ -30,7 +31,7 @@
 
 #define CONSTRAIN(amount, low, high) ((amount) < (low) ? (low) : ((amount) > (high) ? (high) : (amount)))
 
-#define EXEC_BLOCKING 0
+static const char* kPropBlockingExec = "persist.sys.blocking_exec";
 
 using android::base::StringPrintf;
 
@@ -93,9 +94,10 @@
         return OK;
     }
 
-#if EXEC_BLOCKING
-    return ForkExecvp(cmd);
-#else
+    if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
+        return ForkExecvp(cmd);
+    }
+
     pid_t pid = ForkExecvpAsync(cmd);
     if (pid == -1) return -1;
 
@@ -116,7 +118,6 @@
                 ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
     }
     return -1;
-#endif
 }
 
 static status_t execCp(const std::string& fromPath, const std::string& toPath, int startProgress,
@@ -144,9 +145,10 @@
     }
     cmd.push_back(toPath.c_str());
 
-#if EXEC_BLOCKING
-    return ForkExecvp(cmd);
-#else
+    if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
+        return ForkExecvp(cmd);
+    }
+
     pid_t pid = ForkExecvpAsync(cmd);
     if (pid == -1) return -1;
 
@@ -167,7 +169,6 @@
                 ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
     }
     return -1;
-#endif
 }
 
 static void bringOffline(const std::shared_ptr<VolumeBase>& vol) {
diff --git a/Process.cpp b/Process.cpp
index 042ba2d..9038af2 100644
--- a/Process.cpp
+++ b/Process.cpp
@@ -52,7 +52,7 @@
         std::string::size_type pos = line.find('/');
         if (pos != std::string::npos) {
             line = line.substr(pos);
-            if (android::base::StartsWith(line, prefix.c_str())) {
+            if (android::base::StartsWith(line, prefix)) {
                 LOG(WARNING) << "Found map " << path << " referencing " << line;
                 found = true;
             }
@@ -64,7 +64,7 @@
 static bool checkSymlink(const std::string& path, const std::string& prefix) {
     std::string res;
     if (android::base::Readlink(path, &res)) {
-        if (android::base::StartsWith(res, prefix.c_str())) {
+        if (android::base::StartsWith(res, prefix)) {
             LOG(WARNING) << "Found symlink " << path << " referencing " << res;
             return true;
         }
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index e8e151f..f7637fd 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -285,6 +285,13 @@
     return translate(VolumeManager::Instance()->onUserStopped(userId));
 }
 
+binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) {
+    ENFORCE_UID(AID_SYSTEM);
+    ACQUIRE_LOCK;
+
+    return translate(VolumeManager::Instance()->onSecureKeyguardStateChanged(isShowing));
+}
+
 binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType,
         int32_t ratio) {
     ENFORCE_UID(AID_SYSTEM);
@@ -547,22 +554,12 @@
         int32_t encryptionFlags) {
     bool noUi = (encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_NO_UI) != 0;
 
-    std::string how;
-    if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_IN_PLACE) != 0) {
-        how = "inplace";
-    } else if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_WIPE) != 0) {
-        how = "wipe";
-    } else {
-        LOG(ERROR) << "Missing encryption flag";
-        return -1;
-    }
-
     for (int tries = 0; tries < 2; ++tries) {
         int rc;
         if (passwordType == VoldNativeService::PASSWORD_TYPE_DEFAULT) {
-            rc = cryptfs_enable_default(how.c_str(), noUi);
+            rc = cryptfs_enable_default(noUi);
         } else {
-            rc = cryptfs_enable(how.c_str(), passwordType, password.c_str(), noUi);
+            rc = cryptfs_enable(passwordType, password.c_str(), noUi);
         }
 
         if (rc == 0) {
@@ -584,9 +581,6 @@
         if (passwordType != PASSWORD_TYPE_DEFAULT) {
             return error("Unexpected password type");
         }
-        if (encryptionFlags != (ENCRYPTION_FLAG_IN_PLACE | ENCRYPTION_FLAG_NO_UI)) {
-            return error("Unexpected flags");
-        }
         return translateBool(e4crypt_enable_crypto());
     }
 
diff --git a/VoldNativeService.h b/VoldNativeService.h
index d107138..1359d90 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -43,6 +43,8 @@
     binder::Status onUserStarted(int32_t userId);
     binder::Status onUserStopped(int32_t userId);
 
+    binder::Status onSecureKeyguardStateChanged(bool isShowing);
+
     binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio);
     binder::Status forgetPartition(const std::string& partGuid, const std::string& fsUuid);
 
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index e078c0d..5e6e74f 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -90,6 +90,9 @@
 VolumeManager::VolumeManager() {
     mDebug = false;
     mNextObbId = 0;
+    // For security reasons, assume that a secure keyguard is
+    // showing until we hear otherwise
+    mSecureKeyguardShowing = true;
 }
 
 VolumeManager::~VolumeManager() {
@@ -116,23 +119,13 @@
 
             auto disk = new android::vold::Disk("virtual", buf.st_rdev, "virtual",
                     android::vold::Disk::Flags::kAdoptable | android::vold::Disk::Flags::kSd);
-            disk->create();
             mVirtualDisk = std::shared_ptr<android::vold::Disk>(disk);
-            mDisks.push_back(mVirtualDisk);
+            handleDiskAdded(mVirtualDisk);
         }
     } else {
         if (mVirtualDisk != nullptr) {
             dev_t device = mVirtualDisk->getDevice();
-
-            auto i = mDisks.begin();
-            while (i != mDisks.end()) {
-                if ((*i)->getDevice() == device) {
-                    (*i)->destroy();
-                    i = mDisks.erase(i);
-                } else {
-                    ++i;
-                }
-            }
+            handleDiskRemoved(device);
 
             Loop::destroyByDevice(mVirtualDiskPath.c_str());
             mVirtualDisk = nullptr;
@@ -217,8 +210,7 @@
 
                 auto disk = new android::vold::Disk(eventPath, device,
                         source->getNickname(), flags);
-                disk->create();
-                mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));
+                handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));
                 break;
             }
         }
@@ -226,24 +218,11 @@
     }
     case NetlinkEvent::Action::kChange: {
         LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
-        for (const auto& disk : mDisks) {
-            if (disk->getDevice() == device) {
-                disk->readMetadata();
-                disk->readPartitions();
-            }
-        }
+        handleDiskChanged(device);
         break;
     }
     case NetlinkEvent::Action::kRemove: {
-        auto i = mDisks.begin();
-        while (i != mDisks.end()) {
-            if ((*i)->getDevice() == device) {
-                (*i)->destroy();
-                i = mDisks.erase(i);
-            } else {
-                ++i;
-            }
-        }
+        handleDiskRemoved(device);
         break;
     }
     default: {
@@ -253,6 +232,51 @@
     }
 }
 
+void VolumeManager::handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk) {
+    // For security reasons, if secure keyguard is showing, wait
+    // until the user unlocks the device to actually touch it
+    if (mSecureKeyguardShowing) {
+        LOG(INFO) << "Found disk at " << disk->getEventPath()
+                << " but delaying scan due to secure keyguard";
+        mPendingDisks.push_back(disk);
+    } else {
+        disk->create();
+        mDisks.push_back(disk);
+    }
+}
+
+void VolumeManager::handleDiskChanged(dev_t device) {
+    for (const auto& disk : mDisks) {
+        if (disk->getDevice() == device) {
+            disk->readMetadata();
+            disk->readPartitions();
+        }
+    }
+
+    // For security reasons, we ignore all pending disks, since
+    // we'll scan them once the device is unlocked
+}
+
+void VolumeManager::handleDiskRemoved(dev_t device) {
+    auto i = mDisks.begin();
+    while (i != mDisks.end()) {
+        if ((*i)->getDevice() == device) {
+            (*i)->destroy();
+            i = mDisks.erase(i);
+        } else {
+            ++i;
+        }
+    }
+    auto j = mPendingDisks.begin();
+    while (j != mPendingDisks.end()) {
+        if ((*j)->getDevice() == device) {
+            j = mPendingDisks.erase(j);
+        } else {
+            ++j;
+        }
+    }
+}
+
 void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
     std::lock_guard<std::mutex> lock(mLock);
     mDiskSources.push_back(diskSource);
@@ -367,6 +391,20 @@
     return 0;
 }
 
+int VolumeManager::onSecureKeyguardStateChanged(bool isShowing) {
+    mSecureKeyguardShowing = isShowing;
+    if (!mSecureKeyguardShowing) {
+        // Now that secure keyguard has been dismissed, process
+        // any pending disks
+        for (const auto& disk : mPendingDisks) {
+            disk->create();
+            mDisks.push_back(disk);
+        }
+        mPendingDisks.clear();
+    }
+    return 0;
+}
+
 int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) {
     mPrimary = vol;
     for (userid_t userId : mStartedUsers) {
@@ -388,7 +426,7 @@
     mntent* mentry;
     while ((mentry = getmntent(fp)) != NULL) {
         auto test = std::string(mentry->mnt_dir) + "/";
-        if (android::base::StartsWith(test, prefix.c_str())) {
+        if (android::base::StartsWith(test, prefix)) {
             toUnmount.push_front(test);
         }
     }
@@ -554,6 +592,7 @@
         disk->destroy();
     }
     mDisks.clear();
+    mPendingDisks.clear();
     android::vold::sSleepOnUnmount = true;
     return 0;
 }
diff --git a/VolumeManager.h b/VolumeManager.h
index 5baa7ce..fb455d8 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -94,6 +94,8 @@
     int onUserStarted(userid_t userId);
     int onUserStopped(userid_t userId);
 
+    int onSecureKeyguardStateChanged(bool isShowing);
+
     int setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol);
 
     int remountUid(uid_t uid, const std::string& mode);
@@ -132,6 +134,10 @@
 
     int linkPrimary(userid_t userId);
 
+    void handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk);
+    void handleDiskChanged(dev_t device);
+    void handleDiskRemoved(dev_t device);
+
     std::mutex mLock;
     std::mutex mCryptLock;
 
@@ -139,6 +145,7 @@
 
     std::list<std::shared_ptr<DiskSource>> mDiskSources;
     std::list<std::shared_ptr<android::vold::Disk>> mDisks;
+    std::list<std::shared_ptr<android::vold::Disk>> mPendingDisks;
     std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
 
     std::unordered_map<userid_t, int> mAddedUsers;
@@ -150,6 +157,7 @@
     std::shared_ptr<android::vold::VolumeBase> mPrimary;
 
     int mNextObbId;
+    bool mSecureKeyguardShowing;
 };
 
 #endif
diff --git a/authorization_set.cpp b/authorization_set.cpp
new file mode 100644
index 0000000..e7a3401
--- /dev/null
+++ b/authorization_set.cpp
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2014 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 "authorization_set.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <istream>
+#include <limits>
+#include <ostream>
+
+#include <new>
+
+namespace keystore {
+
+inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) return a.tag < b.tag;
+    int retval;
+    switch (typeFromTag(a.tag)) {
+        case TagType::INVALID:
+        case TagType::BOOL:
+            return false;
+        case TagType::ENUM:
+        case TagType::ENUM_REP:
+        case TagType::UINT:
+        case TagType::UINT_REP:
+            return a.f.integer < b.f.integer;
+        case TagType::ULONG:
+        case TagType::ULONG_REP:
+            return a.f.longInteger < b.f.longInteger;
+        case TagType::DATE:
+            return a.f.dateTime < b.f.dateTime;
+        case TagType::BIGNUM:
+        case TagType::BYTES:
+            // Handle the empty cases.
+            if (a.blob.size() == 0) return b.blob.size() != 0;
+            if (b.blob.size() == 0) return false;
+
+            retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+            // if one is the prefix of the other the longer wins
+            if (retval == 0) return a.blob.size() < b.blob.size();
+            // Otherwise a is less if a is less.
+            else
+                return retval < 0;
+    }
+    return false;
+}
+
+inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) return false;
+
+    switch (typeFromTag(a.tag)) {
+        case TagType::INVALID:
+        case TagType::BOOL:
+            return true;
+        case TagType::ENUM:
+        case TagType::ENUM_REP:
+        case TagType::UINT:
+        case TagType::UINT_REP:
+            return a.f.integer == b.f.integer;
+        case TagType::ULONG:
+        case TagType::ULONG_REP:
+            return a.f.longInteger == b.f.longInteger;
+        case TagType::DATE:
+            return a.f.dateTime == b.f.dateTime;
+        case TagType::BIGNUM:
+        case TagType::BYTES:
+            if (a.blob.size() != b.blob.size()) return false;
+            return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
+    }
+    return false;
+}
+
+void AuthorizationSet::Sort() {
+    std::sort(data_.begin(), data_.end(), keyParamLess);
+}
+
+void AuthorizationSet::Deduplicate() {
+    if (data_.empty()) return;
+
+    Sort();
+    std::vector<KeyParameter> result;
+
+    auto curr = data_.begin();
+    auto prev = curr++;
+    for (; curr != data_.end(); ++prev, ++curr) {
+        if (prev->tag == Tag::INVALID) continue;
+
+        if (!keyParamEqual(*prev, *curr)) {
+            result.emplace_back(std::move(*prev));
+        }
+    }
+    result.emplace_back(std::move(*prev));
+
+    std::swap(data_, result);
+}
+
+void AuthorizationSet::Union(const AuthorizationSet& other) {
+    data_.insert(data_.end(), other.data_.begin(), other.data_.end());
+    Deduplicate();
+}
+
+void AuthorizationSet::Subtract(const AuthorizationSet& other) {
+    Deduplicate();
+
+    auto i = other.begin();
+    while (i != other.end()) {
+        int pos = -1;
+        do {
+            pos = find(i->tag, pos);
+            if (pos != -1 && keyParamEqual(*i, data_[pos])) {
+                data_.erase(data_.begin() + pos);
+                break;
+            }
+        } while (pos != -1);
+        ++i;
+    }
+}
+
+int AuthorizationSet::find(Tag tag, int begin) const {
+    auto iter = data_.begin() + (1 + begin);
+
+    while (iter != data_.end() && iter->tag != tag) ++iter;
+
+    if (iter != data_.end()) return iter - data_.begin();
+    return -1;
+}
+
+bool AuthorizationSet::erase(int index) {
+    auto pos = data_.begin() + index;
+    if (pos != data_.end()) {
+        data_.erase(pos);
+        return true;
+    }
+    return false;
+}
+
+KeyParameter& AuthorizationSet::operator[](int at) {
+    return data_[at];
+}
+
+const KeyParameter& AuthorizationSet::operator[](int at) const {
+    return data_[at];
+}
+
+void AuthorizationSet::Clear() {
+    data_.clear();
+}
+
+size_t AuthorizationSet::GetTagCount(Tag tag) const {
+    size_t count = 0;
+    for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count;
+    return count;
+}
+
+NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
+    int pos = find(tag);
+    if (pos == -1) return {};
+    return data_[pos];
+}
+
+/**
+ * Persistent format is:
+ * | 32 bit indirect_size         |
+ * --------------------------------
+ * | indirect_size bytes of data  | this is where the blob data is stored
+ * --------------------------------
+ * | 32 bit element_count         | number of entries
+ * | 32 bit elements_size         | total bytes used by entries (entries have variable length)
+ * --------------------------------
+ * | elementes_size bytes of data | where the elements are stored
+ */
+
+/**
+ * Persistent format of blobs and bignums:
+ * | 32 bit tag             |
+ * | 32 bit blob_length     |
+ * | 32 bit indirect_offset |
+ */
+
+struct OutStreams {
+    std::ostream& indirect;
+    std::ostream& elements;
+};
+
+OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
+    uint32_t buffer;
+
+    // write blob_length
+    auto blob_length = blob.size();
+    if (blob_length > std::numeric_limits<uint32_t>::max()) {
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = blob_length;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write indirect_offset
+    auto offset = out.indirect.tellp();
+    if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
+        uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) {  // overflow check
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = offset;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write blob to indirect stream
+    if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
+
+    return out;
+}
+
+template <typename T>
+OutStreams& serializeParamValue(OutStreams& out, const T& value) {
+    out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
+    return out;
+}
+
+OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
+    // skip invalid entries.
+    return out;
+}
+template <typename T>
+OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
+    out.elements.write(reinterpret_cast<const char*>(&param.tag), sizeof(int32_t));
+    return serializeParamValue(out, accessTagValue(ttag, param));
+}
+
+template <typename... T>
+struct choose_serializer;
+template <typename... Tags>
+struct choose_serializer<MetaList<Tags...>> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        return choose_serializer<Tags...>::serialize(out, param);
+    }
+};
+template <>
+struct choose_serializer<> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        if (param.tag == tag) {
+            return keystore::serialize(TypedTag<tag_type, tag>(), out, param);
+        } else {
+            return choose_serializer<Tail...>::serialize(out, param);
+        }
+    }
+};
+
+OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+    return choose_serializer<all_tags_t>::serialize(out, param);
+}
+
+std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
+    std::stringstream indirect;
+    std::stringstream elements;
+    OutStreams streams = {indirect, elements};
+    for (const auto& param : params) {
+        serialize(streams, param);
+    }
+    if (indirect.bad() || elements.bad()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    auto pos = indirect.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t indirect_size = pos;
+    pos = elements.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t elements_size = pos;
+    uint32_t element_count = params.size();
+
+    out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (indirect_size) out << indirect.rdbuf();
+    assert(out.tellp() - pos == indirect_size);
+
+    out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
+    out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (elements_size) out << elements.rdbuf();
+    assert(out.tellp() - pos == elements_size);
+
+    return out;
+}
+
+struct InStreams {
+    std::istream& indirect;
+    std::istream& elements;
+};
+
+InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
+    uint32_t blob_length = 0;
+    uint32_t offset = 0;
+    in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
+    blob->resize(blob_length);
+    in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
+    in.indirect.seekg(offset);
+    in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
+    return in;
+}
+
+template <typename T>
+InStreams& deserializeParamValue(InStreams& in, T* value) {
+    in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
+    return in;
+}
+
+InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
+    // there should be no invalid KeyParamaters but if handle them as zero sized.
+    return in;
+}
+
+template <typename T>
+InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
+    return deserializeParamValue(in, &accessTagValue(ttag, *param));
+}
+
+template <typename... T>
+struct choose_deserializer;
+template <typename... Tags>
+struct choose_deserializer<MetaList<Tags...>> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        return choose_deserializer<Tags...>::deserialize(in, param);
+    }
+};
+template <>
+struct choose_deserializer<> {
+    static InStreams& deserialize(InStreams& in, KeyParameter*) {
+        // encountered an unknown tag -> fail parsing
+        in.elements.setstate(std::ios_base::badbit);
+        return in;
+    }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        if (param->tag == tag) {
+            return keystore::deserialize(TypedTag<tag_type, tag>(), in, param);
+        } else {
+            return choose_deserializer<Tail...>::deserialize(in, param);
+        }
+    }
+};
+
+InStreams& deserialize(InStreams& in, KeyParameter* param) {
+    in.elements.read(reinterpret_cast<char*>(&param->tag), sizeof(Tag));
+    return choose_deserializer<all_tags_t>::deserialize(in, param);
+}
+
+std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
+    uint32_t indirect_size = 0;
+    in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
+    std::string indirect_buffer(indirect_size, '\0');
+    if (indirect_buffer.size() != indirect_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&indirect_buffer[0], indirect_buffer.size());
+
+    uint32_t element_count = 0;
+    in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
+    uint32_t elements_size = 0;
+    in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
+
+    std::string elements_buffer(elements_size, '\0');
+    if (elements_buffer.size() != elements_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&elements_buffer[0], elements_buffer.size());
+
+    if (in.bad()) return in;
+
+    // TODO write one-shot stream buffer to avoid copying here
+    std::stringstream indirect(indirect_buffer);
+    std::stringstream elements(elements_buffer);
+    InStreams streams = {indirect, elements};
+
+    params->resize(element_count);
+
+    for (uint32_t i = 0; i < element_count; ++i) {
+        deserialize(streams, &(*params)[i]);
+    }
+    return in;
+}
+void AuthorizationSet::Serialize(std::ostream* out) const {
+    serialize(*out, data_);
+}
+void AuthorizationSet::Deserialize(std::istream* in) {
+    deserialize(*in, &data_);
+}
+
+}  // namespace keystore
diff --git a/authorization_set.h b/authorization_set.h
new file mode 100644
index 0000000..8f68bb0
--- /dev/null
+++ b/authorization_set.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2014 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 SYSTEM_VOLD_AUTHORIZATION_SET_H_
+#define SYSTEM_VOLD_AUTHORIZATION_SET_H_
+
+#include <vector>
+
+#include "keymaster_tags.h"
+
+namespace keystore {
+
+class AuthorizationSetBuilder;
+
+/**
+ * An ordered collection of KeyParameters. It provides memory ownership and some convenient
+ * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters.
+ * For serialization, wrap the backing store of this structure in a hidl_vec<KeyParameter>.
+ */
+class AuthorizationSet {
+  public:
+    /**
+     * Construct an empty, dynamically-allocated, growable AuthorizationSet.
+     */
+    AuthorizationSet(){};
+
+    // Copy constructor.
+    AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
+
+    // Move constructor.
+    AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {}
+
+    // Constructor from hidl_vec<KeyParameter>
+    AuthorizationSet(const hidl_vec<KeyParameter>& other) { *this = other; }
+
+    // Copy assignment.
+    AuthorizationSet& operator=(const AuthorizationSet& other) {
+        data_ = other.data_;
+        return *this;
+    }
+
+    // Move assignment.
+    AuthorizationSet& operator=(AuthorizationSet&& other) {
+        data_ = std::move(other.data_);
+        return *this;
+    }
+
+    AuthorizationSet& operator=(const hidl_vec<KeyParameter>& other) {
+        if (other.size() > 0) {
+            data_.resize(other.size());
+            for (size_t i = 0; i < data_.size(); ++i) {
+                /* This makes a deep copy even of embedded blobs.
+                 * See assignment operator/copy constructor of hidl_vec.*/
+                data_[i] = other[i];
+            }
+        }
+        return *this;
+    }
+
+    /**
+     * Clear existing authorization set data
+     */
+    void Clear();
+
+    ~AuthorizationSet() = default;
+
+    /**
+     * Returns the size of the set.
+     */
+    size_t size() const { return data_.size(); }
+
+    /**
+     * Returns true if the set is empty.
+     */
+    bool empty() const { return size() == 0; }
+
+    /**
+     * Returns the data in the set, directly. Be careful with this.
+     */
+    const KeyParameter* data() const { return data_.data(); }
+
+    /**
+     * Sorts the set
+     */
+    void Sort();
+
+    /**
+     * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+     * AuthorizationSetBuilder).
+     */
+    void Deduplicate();
+
+    /**
+     * Adds all elements from \p set that are not already present in this AuthorizationSet.  As a
+     * side-effect, if \p set is not null this AuthorizationSet will end up sorted.
+     */
+    void Union(const AuthorizationSet& set);
+
+    /**
+     * Removes all elements in \p set from this AuthorizationSet.
+     */
+    void Subtract(const AuthorizationSet& set);
+
+    /**
+     * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+     * begin.  If not found, returns -1.
+     */
+    int find(Tag tag, int begin = -1) const;
+
+    /**
+     * Removes the entry at the specified index. Returns true if successful, false if the index was
+     * out of bounds.
+     */
+    bool erase(int index);
+
+    /**
+     * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); }
+
+    /**
+     * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
+
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    KeyParameter& operator[](int n);
+
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    const KeyParameter& operator[](int n) const;
+
+    /**
+     * Returns true if the set contains at least one instance of \p tag
+     */
+    bool Contains(Tag tag) const { return find(tag) != -1; }
+
+    template <TagType tag_type, Tag tag, typename ValueT>
+    bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
+        for (const auto& param : data_) {
+            auto entry = authorizationValue(ttag, param);
+            if (entry.isOk() && entry.value() == value) return true;
+        }
+        return false;
+    }
+    /**
+     * Returns the number of \p tag entries.
+     */
+    size_t GetTagCount(Tag tag) const;
+
+    template <typename T>
+    inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
+        auto entry = GetEntry(tag);
+        if (entry.isOk()) return authorizationValue(tag, entry.value());
+        return {};
+    }
+
+    void push_back(const KeyParameter& param) { data_.push_back(param); }
+    void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
+
+    /**
+     * Append the tag and enumerated value to the set.
+     * "val" may be exactly one parameter unless a boolean parameter is added.
+     * In this case "val" is omitted. This condition is checked at compile time by Authorization()
+     */
+    template <typename TypedTagT, typename... Value>
+    void push_back(TypedTagT tag, Value&&... val) {
+        push_back(Authorization(tag, std::forward<Value>(val)...));
+    }
+
+    template <typename Iterator>
+    void append(Iterator begin, Iterator end) {
+        while (begin != end) {
+            push_back(*begin);
+            ++begin;
+        }
+    }
+
+    hidl_vec<KeyParameter> hidl_data() const {
+        hidl_vec<KeyParameter> result;
+        result.setToExternal(const_cast<KeyParameter*>(data()), size());
+        return result;
+    }
+
+    void Serialize(std::ostream* out) const;
+    void Deserialize(std::istream* in);
+
+  private:
+    NullOr<const KeyParameter&> GetEntry(Tag tag) const;
+
+    std::vector<KeyParameter> data_;
+};
+
+class AuthorizationSetBuilder : public AuthorizationSet {
+  public:
+    template <typename TagType, typename... ValueType>
+    AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
+        push_back(ttag, std::forward<ValueType>(value)...);
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data,
+                                           size_t data_length) {
+        hidl_vec<uint8_t> new_blob;
+        new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
+        push_back(ttag, std::move(new_blob));
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data,
+                                           size_t data_length) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
+    AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+    AuthorizationSetBuilder& AesKey(uint32_t key_size);
+    AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+    AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& SigningKey();
+    AuthorizationSetBuilder& EncryptionKey();
+    AuthorizationSetBuilder& NoDigestOrPadding();
+    AuthorizationSetBuilder& EcbMode();
+
+    AuthorizationSetBuilder& Digest(Digest digest) { return Authorization(TAG_DIGEST, digest); }
+
+    AuthorizationSetBuilder& Padding(PaddingMode padding) {
+        return Authorization(TAG_PADDING, padding);
+    }
+};
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+                                                                uint64_t public_exponent) {
+    Authorization(TAG_ALGORITHM, Algorithm::RSA);
+    Authorization(TAG_KEY_SIZE, key_size);
+    Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::EC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return *this;
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::AES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::HMAC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+                                                                       uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size,
+                                                                          uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+    EcdsaKey(key_size);
+    return SigningKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+    AesKey(key_size);
+    return EncryptionKey();
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
+    return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT);
+    return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+    Authorization(TAG_DIGEST, Digest::NONE);
+    return Authorization(TAG_PADDING, PaddingMode::NONE);
+}
+
+inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+    return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
+}
+
+}  // namespace keystore
+
+#endif  // SYSTEM_VOLD_AUTHORIZATION_SET_H_
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index c3f5029..9facaf7 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -33,6 +33,8 @@
     void onUserStarted(int userId);
     void onUserStopped(int userId);
 
+    void onSecureKeyguardStateChanged(boolean isShowing);
+
     void partition(@utf8InCpp String diskId, int partitionType, int ratio);
     void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid);
 
@@ -92,8 +94,6 @@
 
     void secdiscard(@utf8InCpp String path);
 
-    const int ENCRYPTION_FLAG_WIPE = 1;
-    const int ENCRYPTION_FLAG_IN_PLACE = 2;
     const int ENCRYPTION_FLAG_NO_UI = 4;
 
     const int ENCRYPTION_STATE_NONE = 1;
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 207f08c..aa60541 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -1937,73 +1937,6 @@
     return 0;
 }
 
-static int cryptfs_enable_wipe(char *crypto_blkdev, off64_t size, int type)
-{
-    const char *args[10];
-    char size_str[32]; /* Must be large enough to hold a %lld and null byte */
-    int num_args;
-    int status;
-    int tmp;
-    int rc = -1;
-
-    if (type == EXT4_FS) {
-        args[0] = "/system/bin/mke2fs";
-        args[1] = "-M";
-        args[2] = "/data";
-        args[3] = "-b";
-        args[4] = "4096";
-        args[5] = "-t";
-        args[6] = "ext4";
-        args[7] = crypto_blkdev;
-        snprintf(size_str, sizeof(size_str), "%" PRId64, size / (4096 / 512));
-        args[8] = size_str;
-        num_args = 9;
-        SLOGI("Making empty filesystem with command %s %s %s %s %s %s\n",
-              args[0], args[1], args[2], args[3], args[4], args[5]);
-    } else if (type == F2FS_FS) {
-        args[0] = "/system/bin/make_f2fs";
-        args[1] = "-f";
-        args[2] = "-d1";
-        args[3] = "-O";
-        args[4] = "encrypt";
-        args[5] = "-O";
-        args[6] = "quota";
-        args[7] = crypto_blkdev;
-        snprintf(size_str, sizeof(size_str), "%" PRId64, size);
-        args[8] = size_str;
-        num_args = 9;
-        SLOGI("Making empty filesystem with command %s %s %s %s %s %s %s %s %s\n",
-              args[0], args[1], args[2], args[3], args[4], args[5],
-              args[6], args[7], args[8]);
-    } else {
-        SLOGE("cryptfs_enable_wipe(): unknown filesystem type %d\n", type);
-        return -1;
-    }
-
-    tmp = android_fork_execvp(num_args, (char **)args, &status, false, true);
-
-    if (tmp != 0) {
-      SLOGE("Error creating empty filesystem on %s due to logwrap error\n", crypto_blkdev);
-    } else {
-        if (WIFEXITED(status)) {
-            if (WEXITSTATUS(status)) {
-                SLOGE("Error creating filesystem on %s, exit status %d ",
-                      crypto_blkdev, WEXITSTATUS(status));
-            } else {
-                SLOGD("Successfully created filesystem on %s\n", crypto_blkdev);
-                rc = 0;
-            }
-        } else {
-            SLOGE("Error creating filesystem on %s, did not exit normally\n", crypto_blkdev);
-       }
-    }
-
-    return rc;
-}
-
-#define CRYPTO_ENABLE_WIPE 1
-#define CRYPTO_ENABLE_INPLACE 2
-
 #define FRAMEWORK_BOOT_WAIT 60
 
 static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf)
@@ -2032,60 +1965,31 @@
     return 0;
 }
 
-static int get_fs_type(struct fstab_rec *rec)
-{
-    if (!strcmp(rec->fs_type, "ext4")) {
-        return EXT4_FS;
-    } else if (!strcmp(rec->fs_type, "f2fs")) {
-        return F2FS_FS;
-    } else {
-        return -1;
-    }
-}
-
-static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how,
-                                      char *crypto_blkdev, char *real_blkdev,
-                                      int previously_encrypted_upto)
-{
+static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr* crypt_ftr, char* crypto_blkdev,
+                                      char* real_blkdev, int previously_encrypted_upto) {
     off64_t cur_encryption_done=0, tot_encryption_size=0;
     int rc = -1;
 
     /* The size of the userdata partition, and add in the vold volumes below */
     tot_encryption_size = crypt_ftr->fs_size;
 
-    if (how == CRYPTO_ENABLE_WIPE) {
-        struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT);
-        int fs_type = get_fs_type(rec);
-        if (fs_type < 0) {
-            SLOGE("cryptfs_enable: unsupported fs type %s\n", rec->fs_type);
-            return -1;
-        }
-        rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr->fs_size, fs_type);
-    } else if (how == CRYPTO_ENABLE_INPLACE) {
-        rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev,
-                                    crypt_ftr->fs_size, &cur_encryption_done,
-                                    tot_encryption_size,
-                                    previously_encrypted_upto);
+    rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, crypt_ftr->fs_size, &cur_encryption_done,
+                                tot_encryption_size, previously_encrypted_upto);
 
-        if (rc == ENABLE_INPLACE_ERR_DEV) {
-            /* Hack for b/17898962 */
-            SLOGE("cryptfs_enable: crypto block dev failure. Must reboot...\n");
-            cryptfs_reboot(RebootType::reboot);
-        }
+    if (rc == ENABLE_INPLACE_ERR_DEV) {
+        /* Hack for b/17898962 */
+        SLOGE("cryptfs_enable: crypto block dev failure. Must reboot...\n");
+        cryptfs_reboot(RebootType::reboot);
+    }
 
-        if (!rc) {
-            crypt_ftr->encrypted_upto = cur_encryption_done;
-        }
+    if (!rc) {
+        crypt_ftr->encrypted_upto = cur_encryption_done;
+    }
 
-        if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) {
-            /* The inplace routine never actually sets the progress to 100% due
-             * to the round down nature of integer division, so set it here */
-            property_set("vold.encrypt_progress", "100");
-        }
-    } else {
-        /* Shouldn't happen */
-        SLOGE("cryptfs_enable: internal error, unknown option\n");
-        rc = -1;
+    if (!rc && crypt_ftr->encrypted_upto == crypt_ftr->fs_size) {
+        /* The inplace routine never actually sets the progress to 100% due
+         * to the round down nature of integer division, so set it here */
+        property_set("vold.encrypt_progress", "100");
     }
 
     return rc;
@@ -2096,10 +2000,7 @@
     return vm->unmountAll();
 }
 
-int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *passwd,
-                            int no_ui)
-{
-    int how = 0;
+int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) {
     char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN];
     unsigned char decrypted_master_key[KEY_LEN_BYTES];
     int rc=-1, i;
@@ -2114,17 +2015,7 @@
     bool onlyCreateHeader = false;
     int fd = -1;
 
-    if (!strcmp(howarg, "wipe")) {
-      how = CRYPTO_ENABLE_WIPE;
-    } else if (! strcmp(howarg, "inplace")) {
-      how = CRYPTO_ENABLE_INPLACE;
-    } else {
-      /* Shouldn't happen, as CommandListener vets the args */
-      goto error_unencrypted;
-    }
-
-    if (how == CRYPTO_ENABLE_INPLACE
-          && get_crypt_ftr_and_key(&crypt_ftr) == 0) {
+    if (get_crypt_ftr_and_key(&crypt_ftr) == 0) {
         if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) {
             /* An encryption was underway and was interrupted */
             previously_encrypted_upto = crypt_ftr.encrypted_upto;
@@ -2177,7 +2068,7 @@
     close(fd);
 
     /* If doing inplace encryption, make sure the orig fs doesn't include the crypto footer */
-    if ((how == CRYPTO_ENABLE_INPLACE) && (!strcmp(key_loc, KEY_IN_FOOTER))) {
+    if (!strcmp(key_loc, KEY_IN_FOOTER)) {
         unsigned int fs_size_sec, max_fs_size_sec;
         fs_size_sec = get_fs_size(real_blkdev);
         if (fs_size_sec == 0)
@@ -2224,7 +2115,7 @@
     }
 
     /* Do extra work for a better UX when doing the long inplace encryption */
-    if (how == CRYPTO_ENABLE_INPLACE && !onlyCreateHeader) {
+    if (!onlyCreateHeader) {
         /* Now that /data is unmounted, we need to mount a tmpfs
          * /data, set a property saying we're doing inplace encryption,
          * and restart the framework.
@@ -2311,7 +2202,7 @@
         cryptfs_reboot(RebootType::reboot);
     }
 
-    if (how == CRYPTO_ENABLE_INPLACE && (!no_ui || rebootEncryption)) {
+    if (!no_ui || rebootEncryption) {
         /* startup service classes main and late_start */
         property_set("vold.decrypt", "trigger_restart_min_framework");
         SLOGD("Just triggered restart_min_framework\n");
@@ -2341,14 +2232,12 @@
     }
 
     if (!rc) {
-        rc = cryptfs_enable_all_volumes(&crypt_ftr, how,
-                                        crypto_blkdev, real_blkdev,
+        rc = cryptfs_enable_all_volumes(&crypt_ftr, crypto_blkdev, real_blkdev,
                                         previously_encrypted_upto);
     }
 
     /* Calculate checksum if we are not finished */
-    if (!rc && how == CRYPTO_ENABLE_INPLACE
-            && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
+    if (!rc && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
         rc = cryptfs_SHA256_fileblock(crypto_blkdev,
                                       crypt_ftr.hash_first_block);
         if (rc) {
@@ -2364,8 +2253,7 @@
         /* Success */
         crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE;
 
-        if (how == CRYPTO_ENABLE_INPLACE
-              && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
+        if (crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
             SLOGD("Encrypted up to sector %lld - will continue after reboot",
                   crypt_ftr.encrypted_upto);
             crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
@@ -2373,30 +2261,29 @@
 
         put_crypt_ftr_and_key(&crypt_ftr);
 
-        if (how == CRYPTO_ENABLE_WIPE
-              || crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
-          char value[PROPERTY_VALUE_MAX];
-          property_get("ro.crypto.state", value, "");
-          if (!strcmp(value, "")) {
-            /* default encryption - continue first boot sequence */
-            property_set("ro.crypto.state", "encrypted");
-            property_set("ro.crypto.type", "block");
-            release_wake_lock(lockid);
-            if (rebootEncryption && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
-                // Bring up cryptkeeper that will check the password and set it
-                property_set("vold.decrypt", "trigger_shutdown_framework");
-                sleep(2);
-                property_set("vold.encrypt_progress", "");
-                cryptfs_trigger_restart_min_framework();
+        if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
+            char value[PROPERTY_VALUE_MAX];
+            property_get("ro.crypto.state", value, "");
+            if (!strcmp(value, "")) {
+                /* default encryption - continue first boot sequence */
+                property_set("ro.crypto.state", "encrypted");
+                property_set("ro.crypto.type", "block");
+                release_wake_lock(lockid);
+                if (rebootEncryption && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) {
+                    // Bring up cryptkeeper that will check the password and set it
+                    property_set("vold.decrypt", "trigger_shutdown_framework");
+                    sleep(2);
+                    property_set("vold.encrypt_progress", "");
+                    cryptfs_trigger_restart_min_framework();
+                } else {
+                    cryptfs_check_passwd(DEFAULT_PASSWORD);
+                    cryptfs_restart_internal(1);
+                }
+                return 0;
             } else {
-                cryptfs_check_passwd(DEFAULT_PASSWORD);
-                cryptfs_restart_internal(1);
+                sleep(2); /* Give the UI a chance to show 100% progress */
+                cryptfs_reboot(RebootType::reboot);
             }
-            return 0;
-          } else {
-            sleep(2); /* Give the UI a chance to show 100% progress */
-            cryptfs_reboot(RebootType::reboot);
-          }
         } else {
             sleep(2); /* Partially encrypted, ensure writes flushed to ssd */
             cryptfs_reboot(RebootType::shutdown);
@@ -2455,15 +2342,12 @@
     return -1;
 }
 
-int cryptfs_enable(const char *howarg, int type, const char *passwd, int no_ui)
-{
-    return cryptfs_enable_internal(howarg, type, passwd, no_ui);
+int cryptfs_enable(int type, const char* passwd, int no_ui) {
+    return cryptfs_enable_internal(type, passwd, no_ui);
 }
 
-int cryptfs_enable_default(const char *howarg, int no_ui)
-{
-    return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT,
-                          DEFAULT_PASSWORD, no_ui);
+int cryptfs_enable_default(int no_ui) {
+    return cryptfs_enable_internal(CRYPT_TYPE_DEFAULT, DEFAULT_PASSWORD, no_ui);
 }
 
 int cryptfs_changepw(int crypt_type, const char *newpw)
diff --git a/cryptfs.h b/cryptfs.h
index 767270f..bf4b405 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -231,9 +231,9 @@
 int cryptfs_check_passwd(const char* pw);
 int cryptfs_verify_passwd(const char* pw);
 int cryptfs_restart(void);
-int cryptfs_enable(const char* flag, int type, const char* passwd, int no_ui);
+int cryptfs_enable(int type, const char* passwd, int no_ui);
 int cryptfs_changepw(int type, const char* newpw);
-int cryptfs_enable_default(const char* flag, int no_ui);
+int cryptfs_enable_default(int no_ui);
 int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const unsigned char* key,
                              int keysize, char* out_crypto_blkdev);
 int cryptfs_revert_ext_volume(const char* label);
diff --git a/keymaster_tags.h b/keymaster_tags.h
new file mode 100644
index 0000000..c89354d
--- /dev/null
+++ b/keymaster_tags.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2014 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 SYSTEM_VOLD_KEYMASTER_TAGS_H_
+#define SYSTEM_VOLD_KEYMASTER_TAGS_H_
+
+/**
+ * This header contains various definitions that make working with keymaster tags safer and easier.
+ *
+ * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose
+ * of making it impossible to make certain classes of mistakes when operating on keymaster
+ * authorizations.  For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE
+ * and then to assign Algorithm::RSA to algorithm element of its union. But because the user
+ * must choose the union field, there could be a mismatch which the compiler has now way to
+ * diagnose.
+ *
+ * The machinery in this header solves these problems by describing which union field corresponds
+ * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a
+ * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG,
+ * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal.
+ *
+ * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance
+ * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag
+ * to its value c++ type and the correct union element of KeyParameter. This is done by means of
+ * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping
+ * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a
+ * reference to the correct element of KeyParameter.
+ * E.g.:
+ *      given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)"
+ *      yields a reference to param.f.purpose
+ * If used in an assignment the compiler can now check the compatibility of the assigned value.
+ *
+ * For convenience we also provide the constructor like function Authorization().
+ * Authorization takes a typed tag and a value and checks at compile time whether the value given
+ * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the
+ * given tag and value and returns it by value.
+ *
+ * The second convenience function, authorizationValue, allows access to the KeyParameter value in
+ * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped
+ * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped
+ * reference.
+ * E.g.:
+ *      auto param = Authorization(TAG_ALGORITM, Algorithm::RSA);
+ *      auto value1 = authorizationValue(TAG_PURPOSE, param);
+ *      auto value2 = authorizationValue(TAG_ALGORITM, param);
+ * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access.
+ */
+
+#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
+#include <hardware/hw_auth_token.h>
+#include <type_traits>
+
+namespace keystore {
+
+using ::android::hardware::keymaster::V3_0::Algorithm;
+using ::android::hardware::keymaster::V3_0::BlockMode;
+using ::android::hardware::keymaster::V3_0::Digest;
+using ::android::hardware::keymaster::V3_0::EcCurve;
+using ::android::hardware::keymaster::V3_0::ErrorCode;
+using ::android::hardware::keymaster::V3_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType;
+using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements;
+using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
+using ::android::hardware::keymaster::V3_0::KeyDerivationFunction;
+using ::android::hardware::keymaster::V3_0::KeyFormat;
+using ::android::hardware::keymaster::V3_0::KeyOrigin;
+using ::android::hardware::keymaster::V3_0::KeyParameter;
+using ::android::hardware::keymaster::V3_0::KeyPurpose;
+using ::android::hardware::keymaster::V3_0::PaddingMode;
+using ::android::hardware::keymaster::V3_0::Tag;
+using ::android::hardware::keymaster::V3_0::TagType;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have.  We
+// need these old values to be able to support old keys that use them.
+static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
+static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
+
+constexpr TagType typeFromTag(Tag tag) {
+    return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
+}
+
+/**
+ * TypedTag is a templatized version of Tag, which provides compile-time checking of
+ * keymaster tag types. Instances are convertible to Tag, so they can be used wherever
+ * Tag is expected, and because they encode the tag type it's possible to create
+ * function overloads that only operate on tags with a particular type.
+ */
+template <TagType tag_type, Tag tag>
+struct TypedTag {
+    inline TypedTag() {
+        // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+        // 'tag_type'.  Attempting to instantiate a tag with the wrong type will result in a compile
+        // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+        static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
+    }
+    operator Tag() const { return tag; }
+};
+
+template <Tag tag>
+struct Tag2TypedTag {
+    typedef TypedTag<typeFromTag(tag), tag> type;
+};
+
+template <Tag tag>
+struct Tag2String;
+
+#define _TAGS_STRINGIFY(x) #x
+#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x)
+
+#define DECLARE_TYPED_TAG(name)                                             \
+    typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t;          \
+    extern TAG_##name##_t TAG_##name;                                       \
+    template <>                                                             \
+    struct Tag2String<Tag::name> {                                          \
+        static const char* value() { return "Tag::" TAGS_STRINGIFY(name); } \
+    }
+
+DECLARE_TYPED_TAG(INVALID);
+DECLARE_TYPED_TAG(KEY_SIZE);
+DECLARE_TYPED_TAG(MAC_LENGTH);
+DECLARE_TYPED_TAG(CALLER_NONCE);
+DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
+DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
+DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE);
+DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
+DECLARE_TYPED_TAG(ACTIVE_DATETIME);
+DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
+DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
+DECLARE_TYPED_TAG(ALL_USERS);
+DECLARE_TYPED_TAG(USER_ID);
+DECLARE_TYPED_TAG(USER_SECURE_ID);
+DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
+DECLARE_TYPED_TAG(AUTH_TIMEOUT);
+DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
+DECLARE_TYPED_TAG(ALL_APPLICATIONS);
+DECLARE_TYPED_TAG(APPLICATION_ID);
+DECLARE_TYPED_TAG(APPLICATION_DATA);
+DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(ROLLBACK_RESISTANT);
+DECLARE_TYPED_TAG(ROOT_OF_TRUST);
+DECLARE_TYPED_TAG(ASSOCIATED_DATA);
+DECLARE_TYPED_TAG(NONCE);
+DECLARE_TYPED_TAG(AUTH_TOKEN);
+DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
+DECLARE_TYPED_TAG(OS_VERSION);
+DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
+DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
+DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
+
+DECLARE_TYPED_TAG(PURPOSE);
+DECLARE_TYPED_TAG(ALGORITHM);
+DECLARE_TYPED_TAG(BLOCK_MODE);
+DECLARE_TYPED_TAG(DIGEST);
+DECLARE_TYPED_TAG(PADDING);
+DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
+DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(KDF);
+DECLARE_TYPED_TAG(EC_CURVE);
+
+template <typename... Elems>
+struct MetaList {};
+
+using all_tags_t = MetaList<
+    TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
+    TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t,
+    TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
+    TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t,
+    TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t,
+    TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t,
+    TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t,
+    TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
+    TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
+    TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
+    TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>;
+
+/* implementation in keystore_utils.cpp */
+extern const char* stringifyTag(Tag tag);
+
+template <typename TypedTagType>
+struct TypedTag2ValueType;
+
+#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name)                              \
+    template <Tag tag>                                                             \
+    struct TypedTag2ValueType<TypedTag<tag_type, tag>> {                           \
+        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type;    \
+    };                                                                             \
+    template <Tag tag>                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \
+        ->const decltype(param.field_name)& {                                      \
+        return param.field_name;                                                   \
+    }                                                                              \
+    template <Tag tag>                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param)       \
+        ->decltype(param.field_name)& {                                            \
+        return param.field_name;                                                   \
+    }
+
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
+
+#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name)                     \
+    template <>                                                                 \
+    struct TypedTag2ValueType<decltype(typed_tag)> {                            \
+        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \
+    };                                                                          \
+    inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param)  \
+        ->const decltype(param.field_name)& {                                   \
+        return param.field_name;                                                \
+    }                                                                           \
+    inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)        \
+        ->decltype(param.field_name)& {                                         \
+        return param.field_name;                                                \
+    }
+
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType)
+
+template <TagType tag_type, Tag tag, typename ValueT>
+inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
+    KeyParameter param;
+    param.tag = tag;
+    param.f.longInteger = 0;
+    accessTagValue(ttag, param) = std::forward<ValueT>(value);
+    return param;
+}
+
+// the boolean case
+template <Tag tag>
+inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
+    KeyParameter param;
+    param.tag = tag;
+    param.f.boolValue = true;
+    return param;
+}
+
+template <typename... Pack>
+struct FirstOrNoneHelper;
+template <typename First>
+struct FirstOrNoneHelper<First> {
+    typedef First type;
+};
+template <>
+struct FirstOrNoneHelper<> {
+    struct type {};
+};
+
+template <typename... Pack>
+using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;
+
+template <TagType tag_type, Tag tag, typename... Args>
+inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
+    static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
+                  "TagType::BOOL Authorizations do not take parameters. Presence is truth.");
+    static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
+                  "Authorization other then TagType::BOOL take exactly one parameter.");
+    static_assert(
+        tag_type == TagType::BOOL ||
+            std::is_convertible<std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
+                                typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
+        "Invalid argument type for given tag.");
+
+    return makeKeyParameter(ttag, std::forward<Args>(args)...);
+}
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ */
+template <typename ValueT>
+class NullOr {
+    template <typename T>
+    struct reference_initializer {
+        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
+    };
+    template <typename T>
+    struct pointer_initializer {
+        static T init() { return nullptr; }
+    };
+    template <typename T>
+    struct value_initializer {
+        static T init() { return T(); }
+    };
+    template <typename T>
+    using initializer_t = std::conditional_t<
+        std::is_lvalue_reference<T>::value, reference_initializer<T>,
+        std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>, value_initializer<T>>>;
+
+  public:
+    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
+    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+
+    bool isOk() const { return !null_; }
+
+    const ValueT& value() const & { return value_; }
+    ValueT& value() & { return value_; }
+    ValueT&& value() && { return std::move(value_); }
+
+  private:
+    ValueT value_;
+    bool null_;
+};
+
+template <typename T>
+std::remove_reference_t<T> NullOrOr(T&& v) {
+    if (v.isOk()) return v;
+    return {};
+}
+
+template <typename Head, typename... Tail>
+std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
+    if (head.isOk()) return head;
+    return NullOrOr(std::forward<Tail>(tail)...);
+}
+
+template <typename Default, typename Wrapped>
+std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
+    static_assert(
+        std::is_convertible<std::remove_reference_t<Default>, std::remove_reference_t<Wrapped>>::value,
+        "Type of default value must match the type wrapped by NullOr");
+    if (optional.isOk()) return optional.value();
+    return def;
+}
+
+template <TagType tag_type, Tag tag>
+inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue(
+    TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
+    if (tag != param.tag) return {};
+    return accessTagValue(ttag, param);
+}
+
+}  // namespace keystore
+
+#endif  // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
diff --git a/keystore_hidl_support.h b/keystore_hidl_support.h
new file mode 100644
index 0000000..d21e02a
--- /dev/null
+++ b/keystore_hidl_support.h
@@ -0,0 +1,108 @@
+/*
+ **
+ ** Copyright 2016, 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 SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_
+#define SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_
+
+#include <ostream>
+#include <sstream>
+#include <string>
+
+#include <hidl/Status.h>
+
+#include "keymaster_tags.h"
+
+namespace keystore {
+
+inline static std::ostream& formatArgs(std::ostream& out) {
+    return out;
+}
+
+template <typename First, typename... Args>
+inline static std::ostream& formatArgs(std::ostream& out, First&& first, Args&&... args) {
+    out << first;
+    return formatArgs(out, args...);
+}
+
+template <typename... Args>
+inline static std::string argsToString(Args&&... args) {
+    std::stringstream s;
+    formatArgs(s, args...);
+    return s.str();
+}
+
+template <typename... Msgs>
+inline static ErrorCode ksHandleHidlError(const Return<ErrorCode>& error, Msgs&&... msgs) {
+    if (!error.isOk()) {
+        ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
+              argsToString(msgs...).c_str());
+        return ErrorCode::UNKNOWN_ERROR;
+    }
+    return ErrorCode(error);
+}
+template <typename... Msgs>
+inline static ErrorCode ksHandleHidlError(const Return<void>& error, Msgs&&... msgs) {
+    if (!error.isOk()) {
+        ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
+              argsToString(msgs...).c_str());
+        return ErrorCode::UNKNOWN_ERROR;
+    }
+    return ErrorCode::OK;
+}
+
+#define KS_HANDLE_HIDL_ERROR(rc) \
+    ::keystore::ksHandleHidlError(rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__)
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
+                                             bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    if (inPlace)
+        result.setToExternal(const_cast<unsigned char*>(data), length);
+    else {
+        result.resize(length);
+        memcpy(&result[0], data, length);
+    }
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(
+        reinterpret_cast<uint8_t*>(const_cast<std::string::value_type*>(value.data())),
+        static_cast<size_t>(value.size()));
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size()));
+    return result;
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+    const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+    return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+inline std::string hidlVec2String(const hidl_vec<uint8_t>& value) {
+    return std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size());
+}
+
+}  // namespace keystore
+
+#endif  // SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_
diff --git a/main.cpp b/main.cpp
index 01a2168..62ea6b7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -41,7 +41,8 @@
 #include <dirent.h>
 #include <fs_mgr.h>
 
-static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota);
+static int process_config(VolumeManager* vm, bool* has_adoptable, bool* has_quota,
+                          bool* has_reserved);
 static void coldboot(const char *path);
 static void parse_args(int argc, char** argv);
 
@@ -99,8 +100,9 @@
 
     bool has_adoptable;
     bool has_quota;
+    bool has_reserved;
 
-    if (process_config(vm, &has_adoptable, &has_quota)) {
+    if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) {
         PLOG(ERROR) << "Error reading configuration... continuing anyways";
     }
 
@@ -122,6 +124,7 @@
     // a deadlock between vold and init (see b/34278978 for details)
     android::base::SetProperty("vold.has_adoptable", has_adoptable ? "1" : "0");
     android::base::SetProperty("vold.has_quota", has_quota ? "1" : "0");
+    android::base::SetProperty("vold.has_reserved", has_reserved ? "1" : "0");
 
     // Do coldboot here so it won't block booting,
     // also the cold boot is needed in case we have flash drive
@@ -204,7 +207,8 @@
     }
 }
 
-static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) {
+static int process_config(VolumeManager* vm, bool* has_adoptable, bool* has_quota,
+                          bool* has_reserved) {
     ATRACE_NAME("process_config");
 
     fstab_default = fs_mgr_read_fstab_default();
@@ -216,11 +220,15 @@
     /* Loop through entries looking for ones that vold manages */
     *has_adoptable = false;
     *has_quota = false;
+    *has_reserved = false;
     for (int i = 0; i < fstab_default->num_entries; i++) {
         auto rec = &fstab_default->recs[i];
         if (fs_mgr_is_quota(rec)) {
             *has_quota = true;
         }
+        if (rec->reserved_size > 0) {
+            *has_reserved = true;
+        }
 
         if (fs_mgr_is_voldmanaged(rec)) {
             if (fs_mgr_is_nonremovable(rec)) {
diff --git a/model/Disk.cpp b/model/Disk.cpp
index b42f215..9b772e4 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -455,12 +455,6 @@
 status_t Disk::partitionMixed(int8_t ratio) {
     int res;
 
-    if (e4crypt_is_native()
-            && !android::base::GetBoolProperty("persist.sys.adoptable_fbe", false)) {
-        LOG(ERROR) << "Private volumes not yet supported on FBE devices";
-        return -EINVAL;
-    }
-
     destroyAllVolumes();
     mJustPartitioned = true;
 
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index d40cf3f..7f5c4ff 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -86,6 +86,7 @@
                 "-m",
                 "-w",
                 "-G",
+                "-i",
                 mRawPath.c_str(),
                 label.c_str(),
                 NULL)) {
diff --git a/vdc.cpp b/vdc.cpp
index 19eb379..5ae4cd9 100644
--- a/vdc.cpp
+++ b/vdc.cpp
@@ -93,8 +93,7 @@
         checkStatus(vold->initUser0());
     } else if (args[0] == "cryptfs" && args[1] == "enablecrypto") {
         int passwordType = android::os::IVold::PASSWORD_TYPE_DEFAULT;
-        int encryptionFlags = android::os::IVold::ENCRYPTION_FLAG_IN_PLACE
-                | android::os::IVold::ENCRYPTION_FLAG_NO_UI;
+        int encryptionFlags = android::os::IVold::ENCRYPTION_FLAG_NO_UI;
         checkStatus(vold->fdeEnable(passwordType, "", encryptionFlags));
     } else if (args[0] == "cryptfs" && args[1] == "mountdefaultencrypted") {
         checkStatus(vold->mountDefaultEncrypted());
diff --git a/vdc.rc b/vdc.rc
index 4d51ced..f2a8076 100644
--- a/vdc.rc
+++ b/vdc.rc
@@ -7,6 +7,6 @@
 # One shot invocation to encrypt unencrypted volumes
 on encrypt
     start surfaceflinger
-    exec - root -- /system/bin/vdc --wait cryptfs enablecrypto inplace default noui
+    exec - root -- /system/bin/vdc --wait cryptfs enablecrypto
     # vold will set vold.decrypt to trigger_restart_framework (default
     # encryption)
diff --git a/vold.rc b/vold.rc
index c27aeda..7d14453 100644
--- a/vold.rc
+++ b/vold.rc
@@ -5,3 +5,4 @@
     ioprio be 2
     writepid /dev/cpuset/foreground/tasks
     shutdown critical
+    group reserved_disk