Don't corrupt ssd when encrypting and power fails

Stop encryption when battery is low, mark position, and continue on reboot.

Note - support for multiple encrypted volumes removed as no devices seem
to exist with an fstab that uses this feature. If you want support for such
a device, contact me and we will re-add it with appropriate testing.

Bug: 13284213
Change-Id: I1f7178e4f7dd8ea816cbc03ab5c4f6543e98acaa
diff --git a/cryptfs.c b/cryptfs.c
index f8d14cf..30e13a3 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -35,7 +35,6 @@
 #include <string.h>
 #include <sys/mount.h>
 #include <openssl/evp.h>
-#include <openssl/sha.h>
 #include <errno.h>
 #include <ext4.h>
 #include <linux/kdev_t.h>
@@ -51,6 +50,7 @@
 #include "VoldUtil.h"
 #include "crypto_scrypt.h"
 #include "ext4_utils.h"
+#include "CheckBattery.h"
 
 #define UNUSED __attribute__((unused))
 
@@ -87,13 +87,23 @@
 
 extern struct fstab *fstab;
 
-static void cryptfs_reboot(int recovery)
+enum RebootType {reboot, recovery, shutdown};
+static void cryptfs_reboot(enum RebootType rt)
 {
-    if (recovery) {
-        property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
-    } else {
-        property_set(ANDROID_RB_PROPERTY, "reboot");
+  switch(rt) {
+      case reboot:
+          property_set(ANDROID_RB_PROPERTY, "reboot");
+          break;
+
+      case recovery:
+          property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
+          break;
+
+      case shutdown:
+          property_set(ANDROID_RB_PROPERTY, "shutdown");
+          break;
     }
+
     sleep(20);
 
     /* Shouldn't get here, reboot should happen before sleep times out */
@@ -1615,7 +1625,8 @@
 }
 
 #define CRYPT_INPLACE_BUFSIZE 4096
-#define CRYPT_SECTORS_PER_BUFSIZE (CRYPT_INPLACE_BUFSIZE / 512)
+#define CRYPT_SECTORS_PER_BUFSIZE (CRYPT_INPLACE_BUFSIZE / CRYPT_SECTOR_SIZE)
+#define CRYPT_SECTOR_SIZE 512
 
 /* aligned 32K writes tends to make flash happy.
  * SD card association recommends it.
@@ -1633,6 +1644,8 @@
     int count;
     off64_t offset;
     char* buffer;
+    off64_t last_written_sector;
+    int completed;
 };
 
 static void update_progress(struct encryptGroupsData* data)
@@ -1669,9 +1682,14 @@
         SLOGE("Error writing crypto_blkdev %s for inplace encrypt",
               data->crypto_blkdev);
         return -1;
+    } else {
+        SLOGI("Encrypted %d blocks at sector %lld",
+              data->count, data->offset / info.block_size * CRYPT_SECTOR_SIZE);
     }
 
     data->count = 0;
+    data->last_written_sector = (data->offset + data->count)
+                                / info.block_size * CRYPT_SECTOR_SIZE - 1;
     return 0;
 }
 
@@ -1737,12 +1755,20 @@
                     goto errout;
                 }
             }
+
+            if (!is_battery_ok()) {
+                SLOGE("Stopping encryption due to low battery");
+                rc = 0;
+                goto errout;
+            }
+
         }
         if (flush_outstanding_data(data)) {
             goto errout;
         }
     }
 
+    data->completed = 1;
     rc = 0;
 
 errout:
@@ -1755,12 +1781,18 @@
                                        char *real_blkdev,
                                        off64_t size,
                                        off64_t *size_already_done,
-                                       off64_t tot_size)
+                                       off64_t tot_size,
+                                       off64_t previously_encrypted_upto)
 {
     int i;
     struct encryptGroupsData data;
     int rc = -1;
 
+    if (previously_encrypted_upto > *size_already_done) {
+        SLOGD("Not fast encrypting since resuming part way through");
+        return -1;
+    }
+
     memset(&data, 0, sizeof(data));
     data.real_blkdev = real_blkdev;
     data.crypto_blkdev = crypto_blkdev;
@@ -1802,7 +1834,7 @@
         goto errout;
     }
 
-    *size_already_done += size;
+    *size_already_done += data.completed ? size : data.last_written_sector;
     rc = 0;
 
 errout:
@@ -1814,7 +1846,8 @@
 
 static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
                                        off64_t size, off64_t *size_already_done,
-                                       off64_t tot_size)
+                                       off64_t tot_size,
+                                       off64_t previously_encrypted_upto)
 {
     int realfd, cryptofd;
     char *buf[CRYPT_INPLACE_BUFSIZE];
@@ -1846,10 +1879,37 @@
 
     SLOGE("Encrypting filesystem in place...");
 
+    i = previously_encrypted_upto + 1 - *size_already_done;
+
+    if (lseek64(realfd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
+        SLOGE("Cannot seek to previously encrypted point on %s", real_blkdev);
+        goto errout;
+    }
+
+    if (lseek64(cryptofd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
+        SLOGE("Cannot seek to previously encrypted point on %s", crypto_blkdev);
+        goto errout;
+    }
+
+    for (;i < size && i % CRYPT_SECTORS_PER_BUFSIZE != 0; ++i) {
+        if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) {
+            SLOGE("Error reading initial sectors from real_blkdev %s for "
+                  "inplace encrypt\n", crypto_blkdev);
+            goto errout;
+        }
+        if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) {
+            SLOGE("Error writing initial sectors to crypto_blkdev %s for "
+                  "inplace encrypt\n", crypto_blkdev);
+            goto errout;
+        } else {
+            SLOGI("Encrypted 1 block at %lld", i);
+        }
+    }
+
     one_pct = tot_numblocks / 100;
     cur_pct = 0;
     /* process the majority of the filesystem in blocks */
-    for (i=0; i<numblocks; i++) {
+    for (i/=CRYPT_SECTORS_PER_BUFSIZE; i<numblocks; i++) {
         new_pct = (i + blocks_already_done) / one_pct;
         if (new_pct > cur_pct) {
             char buf[8];
@@ -1859,24 +1919,37 @@
             property_set("vold.encrypt_progress", buf);
         }
         if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
-            SLOGE("Error reading real_blkdev %s for inplace encrypt\n", crypto_blkdev);
+            SLOGE("Error reading real_blkdev %s for inplace encrypt", crypto_blkdev);
             goto errout;
         }
         if (unix_write(cryptofd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
-            SLOGE("Error writing crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
+            SLOGE("Error writing crypto_blkdev %s for inplace encrypt", crypto_blkdev);
+            goto errout;
+        } else {
+            SLOGD("Encrypted %d block at %lld",
+                  CRYPT_SECTORS_PER_BUFSIZE,
+                  i * CRYPT_SECTORS_PER_BUFSIZE);
+        }
+
+       if (!is_battery_ok()) {
+            SLOGE("Stopping encryption due to low battery");
+            *size_already_done += (i + 1) * CRYPT_SECTORS_PER_BUFSIZE - 1;
+            rc = 0;
             goto errout;
         }
     }
 
     /* Do any remaining sectors */
     for (i=0; i<remainder; i++) {
-        if (unix_read(realfd, buf, 512) <= 0) {
-            SLOGE("Error reading rival sectors from real_blkdev %s for inplace encrypt\n", crypto_blkdev);
+        if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) {
+            SLOGE("Error reading final sectors from real_blkdev %s for inplace encrypt", crypto_blkdev);
             goto errout;
         }
-        if (unix_write(cryptofd, buf, 512) <= 0) {
-            SLOGE("Error writing final sectors to crypto_blkdev %s for inplace encrypt\n", crypto_blkdev);
+        if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) {
+            SLOGE("Error writing final sectors to crypto_blkdev %s for inplace encrypt", crypto_blkdev);
             goto errout;
+        } else {
+            SLOGI("Encrypted 1 block at next location");
         }
     }
 
@@ -1892,15 +1965,27 @@
 
 static int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev,
                                   off64_t size, off64_t *size_already_done,
-                                  off64_t tot_size)
+                                  off64_t tot_size,
+                                  off64_t previously_encrypted_upto)
 {
+    if (previously_encrypted_upto) {
+        SLOGD("Continuing encryption from %lld", previously_encrypted_upto);
+    }
+
+    if (*size_already_done + size < previously_encrypted_upto) {
+        *size_already_done += size;
+        return 0;
+    }
+
     if (cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev,
-                                    size, size_already_done, tot_size) == 0) {
+                                    size, size_already_done,
+                                    tot_size, previously_encrypted_upto) == 0) {
         return 0;
     }
 
     return cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev,
-                                       size, size_already_done, tot_size);
+                                       size, size_already_done, tot_size,
+                                       previously_encrypted_upto);
 }
 
 #define CRYPTO_ENABLE_WIPE 1
@@ -1914,34 +1999,91 @@
             (VOL_ENCRYPTABLE | VOL_NONREMOVABLE);
 }
 
+static int cryptfs_SHA256_fileblock(const char* filename, __le8* buf)
+{
+    int fd = open(filename, O_RDONLY);
+    if (fd == -1) {
+        SLOGE("Error opening file %s", filename);
+        return -1;
+    }
+
+    char block[CRYPT_INPLACE_BUFSIZE];
+    memset(block, 0, sizeof(block));
+    if (unix_read(fd, block, sizeof(block)) < 0) {
+        SLOGE("Error reading file %s", filename);
+        close(fd);
+        return -1;
+    }
+
+    close(fd);
+
+    SHA256_CTX c;
+    SHA256_Init(&c);
+    SHA256_Update(&c, block, sizeof(block));
+    SHA256_Final(buf, &c);
+
+    return 0;
+}
+
+static int cryptfs_enable_all_volumes(struct crypt_mnt_ftr *crypt_ftr, int how,
+                                      char *crypto_blkdev, char *real_blkdev,
+                                      int previously_encrypted_upto)
+{
+    off64_t cur_encryption_done=0, tot_encryption_size=0;
+    int i, rc = -1;
+
+    if (!is_battery_ok()) {
+        SLOGE("Stopping encryption due to low battery");
+        return 0;
+    }
+
+    /* 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) {
+        rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr->fs_size, EXT4_FS);
+    } 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);
+
+        if (!rc && cur_encryption_done != (off64_t)crypt_ftr->fs_size) {
+            crypt_ftr->encrypted_upto = cur_encryption_done;
+        }
+
+        if (!rc && !crypt_ftr->encrypted_upto) {
+            /* 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;
+    }
+
+    return rc;
+}
+
 int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd,
                             int allow_reboot)
 {
     int how = 0;
-    char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN], sd_crypto_blkdev[MAXPATHLEN];
+    char crypto_blkdev[MAXPATHLEN], real_blkdev[MAXPATHLEN];
     unsigned long nr_sec;
     unsigned char decrypted_master_key[KEY_LEN_BYTES];
     int rc=-1, fd, i, ret;
-    struct crypt_mnt_ftr crypt_ftr, sd_crypt_ftr;;
+    struct crypt_mnt_ftr crypt_ftr;
     struct crypt_persist_data *pdata;
-    char tmpfs_options[PROPERTY_VALUE_MAX];
     char encrypted_state[PROPERTY_VALUE_MAX];
     char lockid[32] = { 0 };
     char key_loc[PROPERTY_VALUE_MAX];
     char fuse_sdcard[PROPERTY_VALUE_MAX];
     char *sd_mnt_point;
-    char sd_blk_dev[256] = { 0 };
     int num_vols;
     struct volume_info *vol_list = 0;
-    off64_t cur_encryption_done=0, tot_encryption_size=0;
-
-    property_get("ro.crypto.state", encrypted_state, "");
-    if (!strcmp(encrypted_state, "encrypted")) {
-        SLOGE("Device is already running encrypted, aborting");
-        goto error_unencrypted;
-    }
-
-    fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
+    off64_t previously_encrypted_upto = 0;
 
     if (!strcmp(howarg, "wipe")) {
       how = CRYPTO_ENABLE_WIPE;
@@ -1952,6 +2094,22 @@
       goto error_unencrypted;
     }
 
+    /* See if an encryption was underway and interrupted */
+    if (how == CRYPTO_ENABLE_INPLACE
+          && get_crypt_ftr_and_key(&crypt_ftr) == 0
+          && (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS)) {
+        previously_encrypted_upto = crypt_ftr.encrypted_upto;
+        crypt_ftr.encrypted_upto = 0;
+    }
+
+    property_get("ro.crypto.state", encrypted_state, "");
+    if (!strcmp(encrypted_state, "encrypted") && !previously_encrypted_upto) {
+        SLOGE("Device is already running encrypted, aborting");
+        goto error_unencrypted;
+    }
+
+    // TODO refactor fs_mgr_get_crypt_info to get both in one call
+    fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc));
     fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
 
     /* Get the size of the real block device */
@@ -1967,7 +2125,7 @@
         unsigned int fs_size_sec, max_fs_size_sec;
 
         fs_size_sec = get_fs_size(real_blkdev);
-        max_fs_size_sec = nr_sec - (CRYPT_FOOTER_OFFSET / 512);
+        max_fs_size_sec = nr_sec - (CRYPT_FOOTER_OFFSET / CRYPT_SECTOR_SIZE);
 
         if (fs_size_sec > max_fs_size_sec) {
             SLOGE("Orig filesystem overlaps crypto footer region.  Cannot encrypt in place.");
@@ -1991,26 +2149,19 @@
         sd_mnt_point = "/mnt/sdcard";
     }
 
+    /* TODO
+     * Currently do not have test devices with multiple encryptable volumes.
+     * When we acquire some, re-add support.
+     */
     num_vols=vold_getNumDirectVolumes();
     vol_list = malloc(sizeof(struct volume_info) * num_vols);
     vold_getDirectVolumeList(vol_list);
 
     for (i=0; i<num_vols; i++) {
         if (should_encrypt(&vol_list[i])) {
-            fd = open(vol_list[i].blk_dev, O_RDONLY);
-            if ( (vol_list[i].size = get_blkdev_size(fd)) == 0) {
-                SLOGE("Cannot get size of block device %s\n", vol_list[i].blk_dev);
-                goto error_unencrypted;
-            }
-            close(fd);
-
-            ret=vold_disableVol(vol_list[i].label);
-            if ((ret < 0) && (ret != UNMOUNT_NOT_MOUNTED_ERR)) {
-                /* -2 is returned when the device exists but is not currently mounted.
-                 * ignore the error and continue. */
-                SLOGE("Failed to unmount volume %s\n", vol_list[i].label);
-                goto error_unencrypted;
-            }
+            SLOGE("Cannot encrypt if there are multiple encryptable volumes"
+                  "%s\n", vol_list[i].label);
+            goto error_unencrypted;
         }
     }
 
@@ -2087,102 +2238,78 @@
 
     /* Start the actual work of making an encrypted filesystem */
     /* Initialize a crypt_mnt_ftr for the partition */
-    cryptfs_init_crypt_mnt_ftr(&crypt_ftr);
+    if (previously_encrypted_upto == 0) {
+        cryptfs_init_crypt_mnt_ftr(&crypt_ftr);
 
-    if (!strcmp(key_loc, KEY_IN_FOOTER)) {
-        crypt_ftr.fs_size = nr_sec - (CRYPT_FOOTER_OFFSET / 512);
-    } else {
-        crypt_ftr.fs_size = nr_sec;
-    }
-    crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
-    crypt_ftr.crypt_type = crypt_type;
-    strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
+        if (!strcmp(key_loc, KEY_IN_FOOTER)) {
+            crypt_ftr.fs_size = nr_sec
+              - (CRYPT_FOOTER_OFFSET / CRYPT_SECTOR_SIZE);
+        } else {
+            crypt_ftr.fs_size = nr_sec;
+        }
+        crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
+        crypt_ftr.crypt_type = crypt_type;
+        strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
 
-    /* Make an encrypted master key */
-    if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt, &crypt_ftr)) {
-        SLOGE("Cannot create encrypted master key\n");
-        goto error_shutting_down;
-    }
+        /* Make an encrypted master key */
+        if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt, &crypt_ftr)) {
+            SLOGE("Cannot create encrypted master key\n");
+            goto error_shutting_down;
+        }
 
-    /* Write the key to the end of the partition */
-    put_crypt_ftr_and_key(&crypt_ftr);
+        /* Write the key to the end of the partition */
+        put_crypt_ftr_and_key(&crypt_ftr);
 
-    /* If any persistent data has been remembered, save it.
-     * If none, create a valid empty table and save that.
-     */
-    if (!persist_data) {
-       pdata = malloc(CRYPT_PERSIST_DATA_SIZE);
-       if (pdata) {
-           init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE);
-           persist_data = pdata;
-       }
-    }
-    if (persist_data) {
-        save_persistent_data();
+        /* If any persistent data has been remembered, save it.
+         * If none, create a valid empty table and save that.
+         */
+        if (!persist_data) {
+           pdata = malloc(CRYPT_PERSIST_DATA_SIZE);
+           if (pdata) {
+               init_empty_persist_data(pdata, CRYPT_PERSIST_DATA_SIZE);
+               persist_data = pdata;
+           }
+        }
+        if (persist_data) {
+            save_persistent_data();
+        }
     }
 
     decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr);
     create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev,
                           "userdata");
 
-    /* The size of the userdata partition, and add in the vold volumes below */
-    tot_encryption_size = crypt_ftr.fs_size;
+    /* If we are continuing, check checksums match */
+    rc = 0;
+    if (previously_encrypted_upto) {
+        __le8 hash_first_block[SHA256_DIGEST_LENGTH];
+        rc = cryptfs_SHA256_fileblock(crypto_blkdev, hash_first_block);
 
-    /* setup crypto mapping for all encryptable volumes handled by vold */
-    for (i=0; i<num_vols; i++) {
-        if (should_encrypt(&vol_list[i])) {
-            vol_list[i].crypt_ftr = crypt_ftr; /* gotta love struct assign */
-            vol_list[i].crypt_ftr.fs_size = vol_list[i].size;
-            create_crypto_blk_dev(&vol_list[i].crypt_ftr, decrypted_master_key,
-                                  vol_list[i].blk_dev, vol_list[i].crypto_blkdev,
-                                  vol_list[i].label);
-            tot_encryption_size += vol_list[i].size;
+        if (!rc && memcmp(hash_first_block, crypt_ftr.hash_first_block,
+                          sizeof(hash_first_block)) != 0) {
+            SLOGE("Checksums do not match - trigger wipe");
+            rc = -1;
         }
     }
 
-    if (how == CRYPTO_ENABLE_WIPE) {
-        rc = cryptfs_enable_wipe(crypto_blkdev, crypt_ftr.fs_size, EXT4_FS);
-        /* Encrypt all encryptable volumes handled by vold */
+    if (!rc) {
+        rc = cryptfs_enable_all_volumes(&crypt_ftr, how,
+                                        crypto_blkdev, real_blkdev,
+                                        previously_encrypted_upto);
+    }
+
+    /* Calculate checksum if we are not finished */
+    if (!rc && crypt_ftr.encrypted_upto) {
+        rc = cryptfs_SHA256_fileblock(crypto_blkdev,
+                                      crypt_ftr.hash_first_block);
         if (!rc) {
-            for (i=0; i<num_vols; i++) {
-                if (should_encrypt(&vol_list[i])) {
-                    rc = cryptfs_enable_wipe(vol_list[i].crypto_blkdev,
-                                             vol_list[i].crypt_ftr.fs_size, FAT_FS);
-                }
-            }
+            SLOGE("Error calculating checksum for continuing encryption");
+            rc = -1;
         }
-    } else if (how == CRYPTO_ENABLE_INPLACE) {
-        rc = cryptfs_enable_inplace(crypto_blkdev, real_blkdev, crypt_ftr.fs_size,
-                                    &cur_encryption_done, tot_encryption_size);
-        /* Encrypt all encryptable volumes handled by vold */
-        if (!rc) {
-            for (i=0; i<num_vols; i++) {
-                if (should_encrypt(&vol_list[i])) {
-                    rc = cryptfs_enable_inplace(vol_list[i].crypto_blkdev,
-                                                vol_list[i].blk_dev,
-                                                vol_list[i].crypt_ftr.fs_size,
-                                                &cur_encryption_done, tot_encryption_size);
-                }
-            }
-        }
-        if (!rc) {
-            /* 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");
-        goto error_shutting_down;
     }
 
     /* Undo the dm-crypt mapping whether we succeed or not */
     delete_crypto_blk_dev("userdata");
-    for (i=0; i<num_vols; i++) {
-        if (should_encrypt(&vol_list[i])) {
-            delete_crypto_blk_dev(vol_list[i].label);
-        }
-    }
 
     free(vol_list);
 
@@ -2190,11 +2317,22 @@
         /* Success */
 
         /* Clear the encryption in progres flag in the footer */
-        crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
+        if (!crypt_ftr.encrypted_upto) {
+            crypt_ftr.flags &= ~CRYPT_ENCRYPTION_IN_PROGRESS;
+        } else {
+            SLOGD("Encrypted up to sector %lld - will continue after reboot",
+                  crypt_ftr.encrypted_upto);
+        }
         put_crypt_ftr_and_key(&crypt_ftr);
 
         sleep(2); /* Give the UI a chance to show 100% progress */
-        cryptfs_reboot(0);
+                  /* Partially encrypted - ensure writes are flushed to ssd */
+
+        if (!crypt_ftr.encrypted_upto) {
+            cryptfs_reboot(reboot);
+        } else {
+            cryptfs_reboot(shutdown);
+        }
     } else {
         char value[PROPERTY_VALUE_MAX];
 
@@ -2210,7 +2348,7 @@
             } else {
                 SLOGE("could not open /cache/recovery/command\n");
             }
-            cryptfs_reboot(1);
+            cryptfs_reboot(recovery);
         } else {
             /* set property to trigger dialog */
             property_set("vold.encrypt_progress", "error_partially_encrypted");
@@ -2241,7 +2379,7 @@
      * vold to restart the system.
      */
     SLOGE("Error enabling encryption after framework is shutdown, no data changed, restarting system");
-    cryptfs_reboot(0);
+    cryptfs_reboot(reboot);
 
     /* shouldn't get here */
     property_set("vold.encrypt_progress", "error_shutting_down");