Changes to init to support encrypted filesystems.

These are the changes to init and init.rc necessary to
support booting with and encrypted /data filesystem.
A corresponding change to init.<device>.rc goes along
with this change.

Change-Id: I0c7e2cc39568358014a82e317735c0eae14dd683
diff --git a/init/builtins.c b/init/builtins.c
index 4326ebc..8b2e4aa 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -162,6 +162,12 @@
     return 0;
 }
 
+int do_class_reset(int nargs, char **args)
+{
+    service_for_each_class(args[1], service_reset);
+    return 0;
+}
+
 int do_domainname(int nargs, char **args)
 {
     return write_file("/proc/sys/kernel/domainname", args[1]);
@@ -269,6 +275,8 @@
     { 0,            0 },
 };
 
+#define DATA_MNT_POINT "/data"
+
 /* mount <type> <device> <path> <flags ...> <options> */
 int do_mount(int nargs, char **args)
 {
@@ -359,9 +367,51 @@
         if (wait)
             wait_for_file(source, COMMAND_RETRY_TIMEOUT);
         if (mount(source, target, system, flags, options) < 0) {
-            return -1;
+            /* If this fails, it may be an encrypted filesystem.
+             * We only support encrypting /data.  Check
+             * if we're trying to mount it, and if so,
+             * assume it's encrypted, mount a tmpfs instead.
+             * Then save the orig mount parms in properties
+             * for vold to query when it mounts the real
+             * encrypted /data.
+             */
+            if (!strcmp(target, DATA_MNT_POINT)) {
+                const char *tmpfs_options;
+
+                tmpfs_options = property_get("ro.crypto.tmpfs_options");
+
+                if (mount("tmpfs", target, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV,
+                    tmpfs_options) < 0) {
+                    return -1;
+                }
+
+                /* Set the property that triggers the framework to do a minimal
+                 * startup and ask the user for a password
+                 */
+                property_set("vold.decrypt", "1");
+            } else {
+                return -1;
+            }
+        } else {
+            if (!strcmp(target, DATA_MNT_POINT)) {
+                /* We succeeded in mounting /data, so it's not encrypted */
+                action_for_each_trigger("nonencrypted", action_add_queue_tail);
+            }
         }
 
+        if (!strcmp(target, DATA_MNT_POINT)) {
+            char fs_flags[32];
+
+            /* Save the original mount options */
+            property_set("ro.crypto.fs_type", system);
+            property_set("ro.crypto.fs_real_blkdev", source);
+            property_set("ro.crypto.fs_mnt_point", target);
+            if (options) {
+                property_set("ro.crypto.fs_options", options);
+            }
+            snprintf(fs_flags, sizeof(fs_flags), "0x%8.8x", flags);
+            property_set("ro.crypto.fs_flags", fs_flags);
+        }
         return 0;
     }
 }
diff --git a/init/init.c b/init/init.c
index 7aef387..e13d4b1 100755
--- a/init/init.c
+++ b/init/init.c
@@ -150,11 +150,11 @@
     int needs_console;
     int n;
 
-        /* starting a service removes it from the disabled
+        /* starting a service removes it from the disabled or reset
          * state and immediately takes it out of the restarting
          * state if it was in there
          */
-    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING));
+    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET));
     svc->time_started = 0;
     
         /* running processes require no additional work -- if
@@ -300,27 +300,42 @@
         notify_service_state(svc->name, "running");
 }
 
-void service_stop(struct service *svc)
+/* The how field should be either SVC_DISABLED or SVC_RESET */
+static void service_stop_or_reset(struct service *svc, int how)
 {
         /* we are no longer running, nor should we
          * attempt to restart
          */
     svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
 
+    if ((how != SVC_DISABLED) && (how != SVC_RESET)) {
+        /* Hrm, an illegal flag.  Default to SVC_DISABLED */
+        how = SVC_DISABLED;
+    }
         /* if the service has not yet started, prevent
          * it from auto-starting with its class
          */
-    svc->flags |= SVC_DISABLED;
+    svc->flags |= how;
 
     if (svc->pid) {
         NOTICE("service '%s' is being killed\n", svc->name);
-        kill(-svc->pid, SIGTERM);
+        kill(-svc->pid, SIGKILL);
         notify_service_state(svc->name, "stopping");
     } else {
         notify_service_state(svc->name, "stopped");
     }
 }
 
+void service_reset(struct service *svc)
+{
+    service_stop_or_reset(svc, SVC_RESET);
+}
+
+void service_stop(struct service *svc)
+{
+    service_stop_or_reset(svc, SVC_DISABLED);
+}
+
 void property_changed(const char *name, const char *value)
 {
     if (property_triggers_enabled)
@@ -725,6 +740,7 @@
     action_for_each_trigger("early-fs", action_add_queue_tail);
     action_for_each_trigger("fs", action_add_queue_tail);
     action_for_each_trigger("post-fs", action_add_queue_tail);
+    action_for_each_trigger("post-fs-data", action_add_queue_tail);
 
     queue_builtin_action(property_service_init_action, "property_service_init");
     queue_builtin_action(signal_init_action, "signal_init");
diff --git a/init/init.h b/init/init.h
index 8691335..05cdfaa 100644
--- a/init/init.h
+++ b/init/init.h
@@ -69,6 +69,8 @@
 #define SVC_RESTARTING  0x08  /* waiting to restart */
 #define SVC_CONSOLE     0x10  /* requires console */
 #define SVC_CRITICAL    0x20  /* will reboot into recovery if keeps crashing */
+#define SVC_RESET       0x40  /* Use when stopping a process, but not disabling
+                                 so it can be restarted with its class */
 
 #define NR_SVC_SUPP_GIDS 12    /* twelve supplementary groups */
 
@@ -121,6 +123,7 @@
 void service_for_each_flags(unsigned matchflags,
                             void (*func)(struct service *svc));
 void service_stop(struct service *svc);
+void service_reset(struct service *svc);
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
diff --git a/init/init_parser.c b/init/init_parser.c
index d136c28..7ac1a1e 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -82,6 +82,7 @@
         if (!strcmp(s, "lass")) return K_class;
         if (!strcmp(s, "lass_start")) return K_class_start;
         if (!strcmp(s, "lass_stop")) return K_class_stop;
+        if (!strcmp(s, "lass_reset")) return K_class_reset;
         if (!strcmp(s, "onsole")) return K_console;
         if (!strcmp(s, "hown")) return K_chown;
         if (!strcmp(s, "hmod")) return K_chmod;
diff --git a/init/keywords.h b/init/keywords.h
index 25315d8..d15ad49 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -4,6 +4,7 @@
 int do_chdir(int nargs, char **args);
 int do_class_start(int nargs, char **args);
 int do_class_stop(int nargs, char **args);
+int do_class_reset(int nargs, char **args);
 int do_domainname(int nargs, char **args);
 int do_exec(int nargs, char **args);
 int do_export(int nargs, char **args);
@@ -39,6 +40,7 @@
     KEYWORD(class,       OPTION,  0, 0)
     KEYWORD(class_start, COMMAND, 1, do_class_start)
     KEYWORD(class_stop,  COMMAND, 1, do_class_stop)
+    KEYWORD(class_reset, COMMAND, 1, do_class_reset)
     KEYWORD(console,     OPTION,  0, 0)
     KEYWORD(critical,    OPTION,  0, 0)
     KEYWORD(disabled,    OPTION,  0, 0)
diff --git a/init/signal_handler.c b/init/signal_handler.c
index 3e5d136..833e59d 100644
--- a/init/signal_handler.c
+++ b/init/signal_handler.c
@@ -83,8 +83,8 @@
         svc->flags |= SVC_DISABLED;
     }
 
-        /* disabled processes do not get restarted automatically */
-    if (svc->flags & SVC_DISABLED) {
+        /* disabled and reset processes do not get restarted automatically */
+    if (svc->flags & (SVC_DISABLED | SVC_RESET) )  {
         notify_service_state(svc->name, "stopped");
         return 0;
     }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d252d71..9f3020f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -96,6 +96,32 @@
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
 
+    # We chown/chmod /cache again so because mount is run as root + defaults
+    chown system cache /cache
+    chmod 0770 /cache
+
+    # This may have been created by the recovery system with odd permissions
+    chown system cache /cache/recovery
+    chmod 0770 /cache/recovery
+
+    #change permissions on vmallocinfo so we can grab it from bugreports
+    chown root log /proc/vmallocinfo
+    chmod 0440 /proc/vmallocinfo
+
+    #change permissions on kmsg & sysrq-trigger so bugreports can grab kthread stacks
+    chown root system /proc/kmsg
+    chmod 0440 /proc/kmsg
+    chown root system /proc/sysrq-trigger
+    chmod 0220 /proc/sysrq-trigger
+
+    # create the lost+found directories, so as to enforce our permissions
+    mkdir /cache/lost+found 0770
+
+    # double check the perms, in case lost+found already exists, and set owner
+    chown root root /cache/lost+found
+    chmod 0770 /cache/lost+found
+
+on post-fs-data
     # We chown/chmod /data again so because mount is run as root + defaults
     chown system system /data
     chmod 0771 /data
@@ -119,25 +145,7 @@
 
     write /proc/apanic_console 1
 
-    # Same reason as /data above
-    chown system cache /cache
-    chmod 0770 /cache
-
-    # This may have been created by the recovery system with odd permissions
-    chown system cache /cache/recovery
-    chmod 0770 /cache/recovery
-
-    #change permissions on vmallocinfo so we can grab it from bugreports
-    chown root log /proc/vmallocinfo
-    chmod 0440 /proc/vmallocinfo
-
-    #change permissions on kmsg & sysrq-trigger so bugreports can grab kthread stacks
-    chown root system /proc/kmsg
-    chmod 0440 /proc/kmsg
-    chown root system /proc/sysrq-trigger
-    chmod 0220 /proc/sysrq-trigger
-
-# create basic filesystem structure
+    # create basic filesystem structure
     mkdir /data/misc 01771 system misc
     mkdir /data/misc/bluetoothd 0770 bluetooth bluetooth
     mkdir /data/misc/bluetooth 0770 system system
@@ -163,19 +171,22 @@
 
     # create the lost+found directories, so as to enforce our permissions
     mkdir /data/lost+found 0770
-    mkdir /cache/lost+found 0770
 
     # double check the perms, in case lost+found already exists, and set owner
     chown root root /data/lost+found
     chmod 0770 /data/lost+found
-    chown root root /cache/lost+found
-    chmod 0770 /cache/lost+found
 
     # create directory for DRM plug-ins
     mkdir /data/drm 0774 drm drm
     mkdir /data/drm/plugins 0774 drm drm
     mkdir /data/drm/plugins/native 0774 drm drm
 
+    # If there is no fs-post-data action in the init.<device>.rc file, you
+    # must uncomment this line, otherwise encrypted filesystems
+    # won't work.
+    # Set indication (checked by vold) that we have finished this action
+    #setprop vold.post_fs_data_done 1
+
 on boot
 # basic network init
     ifup lo
@@ -273,14 +284,34 @@
     setprop net.tcp.buffersize.edge    4093,26280,35040,4096,16384,35040
     setprop net.tcp.buffersize.gprs    4092,8760,11680,4096,8760,11680
 
-    class_start default
+    class_start core
+    class_start main
+
+on nonencrypted
+    class_start late_start
+
+on property:vold.decrypt=trigger_reset_main
+    class_reset main
+
+on property:vold.decrypt=trigger_post_fs_data
+    trigger post-fs-data
+
+on property:vold.decrypt=trigger_restart_framework
+    class_start main
+    class_start late_start
+
+on property:vold.decrypt=trigger_shutdown_framework
+    class_reset late_start
+    class_reset main
 
 ## Daemon processes to be run by init.
 ##
 service ueventd /sbin/ueventd
+    class core
     critical
 
 service console /system/bin/sh
+    class core
     console
     disabled
     user shell
@@ -291,6 +322,7 @@
 
 # adbd is controlled by the persist.service.adb.enable system property
 service adbd /sbin/adbd
+    class core
     disabled
 
 # adbd on at boot in emulator
@@ -304,6 +336,7 @@
     stop adbd
 
 service servicemanager /system/bin/servicemanager
+    class core
     user system
     group system
     critical
@@ -311,22 +344,27 @@
     onrestart restart media
 
 service vold /system/bin/vold
+    class core
     socket vold stream 0660 root mount
     ioprio be 2
 
 service netd /system/bin/netd
+    class main
     socket netd stream 0660 root system
     socket dnsproxyd stream 0660 root inet
 
 service debuggerd /system/bin/debuggerd
+    class main
 
 service ril-daemon /system/bin/rild
+    class main
     socket rild stream 660 root radio
     socket rild-debug stream 660 radio system
     user root
     group radio cache inet misc audio sdcard_rw
 
 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
+    class main
     socket zygote stream 666
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
@@ -334,30 +372,36 @@
     onrestart restart netd
 
 service drm /system/bin/drmserver
+    class main
     user drm
     group system root inet
 
 service drmio /system/bin/drmioserver
+    class main
     user drmio
     group drmio
 
 service media /system/bin/mediaserver
+    class main
     user media
     group system audio camera graphics inet net_bt net_bt_admin net_raw
     ioprio rt 4
 
 service bootanim /system/bin/bootanimation
+    class main
     user graphics
     group graphics
     disabled
     oneshot
 
 service dbus /system/bin/dbus-daemon --system --nofork
+    class main
     socket dbus stream 660 bluetooth bluetooth
     user bluetooth
     group bluetooth net_bt_admin
 
 service bluetoothd /system/bin/bluetoothd -n
+    class main
     socket bluetooth stream 660 bluetooth bluetooth
     socket dbus_bluetooth stream 660 bluetooth bluetooth
     # init.rc does not yet support applying capabilities, so run as root and
@@ -366,12 +410,15 @@
     disabled
 
 service installd /system/bin/installd
+    class main
     socket installd stream 600 system system
 
 service flash_recovery /system/etc/install-recovery.sh
+    class main
     oneshot
 
 service racoon /system/bin/racoon
+    class main
     socket racoon stream 600 system system
     # racoon will setuid to vpn after getting necessary resources.
     group net_admin
@@ -379,6 +426,7 @@
     oneshot
 
 service mtpd /system/bin/mtpd
+    class main
     socket mtpd stream 600 system system
     user vpn
     group vpn net_admin net_raw
@@ -386,11 +434,13 @@
     oneshot
 
 service keystore /system/bin/keystore /data/misc/keystore
+    class main
     user keystore
     group keystore
     socket keystore stream 666
 
 service dumpstate /system/bin/dumpstate -s
+    class main
     socket dumpstate stream 0660 shell log
     disabled
     oneshot