Auto-encrypt drive at startup

Modify fs_mgr to unmount encryptable drives after test mounting them and
then trigger an auto-encrypt via the init script

Needs matching vold changes from
 https://googleplex-android-review.googlesource.com/#/c/414200/

Feature is limited to list of serial numbers with this change

Bug: 11985952
Change-Id: I84f85a258b6a7e9809467c9149249302e203c41b
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index c4f27a0..9ac68cd 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -54,6 +54,32 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
+/**
+ * TODO - Remove to enable always on encryption for all devices
+ * This limits the machines on which this feature is enabled
+ * Remove call from fs_mgr_mount_all as well
+ */
+static const char* serial_numbers[] = {
+  "039b83b8437e9637",
+  0
+};
+
+static int serial_matches()
+{
+    char tmp[PROP_VALUE_MAX];
+    *tmp = 0;
+    __system_property_get("ro.serialno", tmp);
+
+    const char** i;
+    for (i = serial_numbers; *i; ++i) {
+        if (!strcmp(*i, tmp)) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 /*
  * gettime() - returns the time in seconds of the system's monotonic clock or
  * zero on error.
@@ -254,6 +280,22 @@
                        fstab->recs[i].fs_options);
 
         if (!mret) {
+            /* If this is encryptable, need to trigger encryption */
+            if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
+                if (serial_matches() && umount(fstab->recs[i].mount_point) == 0) {
+                    if (!encryptable) {
+                        encryptable = 2;
+                    } else {
+                        ERROR("Only one encryptable/encrypted partition supported");
+                        encryptable = 1;
+                    }
+                } else {
+                    INFO("Could not umount %s - allow continue unencrypted",
+                         fstab->recs[i].mount_point);
+                    continue;
+                }
+            }
+
             /* Success!  Go get the next one */
             continue;
         }
@@ -287,12 +329,8 @@
 
     if (error_count) {
         return -1;
-    }
-
-    if (encryptable) {
-        return 1;
     } else {
-        return 0;
+        return encryptable;
     }
 }
 
diff --git a/init/builtins.c b/init/builtins.c
index a168062..a857c98 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -501,8 +501,12 @@
         return -1;
     }
 
-    /* ret is 1 if the device appears encrypted, 0 if not, and -1 on error */
-    if (ret == 1) {
+    /* ret is 2 if device needs encrypted, 1 if the device appears encrypted,
+     * 0 if not, and -1 on error */
+    if (ret == 2) {
+        property_set("ro.crypto.state", "unencrypted");
+        property_set("vold.decrypt", "trigger_encryption");
+    } else if (ret == 1) {
         property_set("ro.crypto.state", "encrypted");
         property_set("vold.decrypt", "trigger_default_encryption");
     } else if (ret == 0) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 5675cac..f63b332 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -399,6 +399,11 @@
     start surfaceflinger
     start defaultcrypto
 
+on property:vold.decrypt=trigger_encryption
+    start surfaceflinger
+    start encrypt
+    class_start main
+
 on charger
     class_start charger
 
@@ -554,6 +559,13 @@
     # vold will set vold.decrypt to trigger_restart_framework (default
     # encryption) or trigger_restart_min_framework (other encryption)
 
+# One shot invocation to encrypt unencrypted volumes
+service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace
+    disabled
+    oneshot
+    # vold will set vold.decrypt to trigger_restart_framework (default
+    # encryption)
+
 service bootanim /system/bin/bootanimation
     class main
     user graphics