Add userdata partition to microdroid

Many programs need /data (especially /data/local/tmp) to properly work.
This change adds a basic unencrypted ext4 userdata partition to
microdroid. Eventually microdroid will support userdata encryption so
only VM can access /data.

Bug: 185767624
Test: atest MicrodroidHostTestCases
Test: log in to microdroid and test writing to /data
Change-Id: I115a8083ad6741fea9dedd61eca7194b1b5e5712
diff --git a/apex/Android.bp b/apex/Android.bp
index 8af22ff..91df00c 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -56,6 +56,7 @@
         "com.android.virt.init.rc",
         "microdroid_cdisk.json",
         "microdroid_cdisk_env.json",
+        "microdroid_cdisk_userdata.json",
         "microdroid_payload.json",
         "microdroid_uboot_env",
         "microdroid_bootloader",
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 2522679..5cffdb4 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -18,6 +18,7 @@
     "vendor",
     "debug_ramdisk",
     "mnt",
+    "data",
 
     "apex",
     "linkerconfig",
@@ -105,6 +106,7 @@
     name: "microdroid_vendor",
     use_avb: true,
     deps: [
+        "microdroid_fstab",
         "microdroid_plat_sepolicy_vers.txt",
         "microdroid_precompiled_sepolicy",
         "microdroid_precompiled_sepolicy.plat_sepolicy_and_mapping.sha256",
@@ -385,6 +387,11 @@
 }
 
 prebuilt_etc {
+    name: "microdroid_cdisk_userdata.json",
+    src: "microdroid_cdisk_userdata.json",
+}
+
+prebuilt_etc {
     name: "microdroid_payload.json",
     src: "microdroid_payload.json",
 }
diff --git a/microdroid/README.md b/microdroid/README.md
index 4ce74a5..4adf60d 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -34,10 +34,13 @@
 $ adb shell 'cp /apex/com.android.virt/etc/fs/*.img /data/local/tmp'
 $ adb shell 'cp /apex/com.android.virt/etc/uboot_env.img /data/local/tmp'
 $ adb shell 'dd if=/dev/zero of=/data/local/tmp/misc.img bs=4k count=256'
+$ adb shell 'dd if=/dev/zero of=/data/local/tmp/userdata.img bs=4k count=25600'
+$ adb shell 'mkfs.ext4 /data/local/tmp/userdata.img'
 $ adb shell 'cd /data/local/tmp; /apex/com.android.virt/bin/mk_cdisk /apex/com.android.virt/etc/microdroid_cdisk.json os_composite.img'
 $ adb shell 'cd /data/local/tmp; /apex/com.android.virt/bin/mk_cdisk /apex/com.android.virt/etc/microdroid_cdisk_env.json env_composite.img'
+$ adb shell 'cd /data/local/tmp; /apex/com.android.virt/bin/mk_cdisk /apex/com.android.virt/etc/microdroid_cdisk_userdata.json userdata_composite.img'
 $ adb shell 'cd /data/local/tmp; /apex/com.android.virt/bin/mk_payload /apex/com.android.virt/etc/microdroid_payload.json payload.img'
-$ adb shell 'cd /data/local/tmp; /apex/com.android.virt/bin/crosvm run --cid=5 --disable-sandbox --bios=bootloader --serial=type=stdout --disk=os_composite.img --disk=env_composite.img --disk=payload.img'
+$ adb shell 'cd /data/local/tmp; /apex/com.android.virt/bin/crosvm run --cid=5 --disable-sandbox --bios=bootloader --serial=type=stdout --disk=os_composite.img --disk=env_composite.img --disk=payload.img --rwdisk=userdata_composite.img'
 ```
 
 The CID in `--cid` parameter can be anything greater than 2 (`VMADDR_CID_HOST`).
diff --git a/microdroid/fstab b/microdroid/fstab
index 129718e..2f4e45f 100644
--- a/microdroid/fstab
+++ b/microdroid/fstab
@@ -1,2 +1,5 @@
 system /system ext4 noatime,ro,errors=panic wait,first_stage_mount,logical
 vendor /vendor ext4 noatime,ro,errors=panic wait,first_stage_mount,logical
+
+# TODO(b/185767624): turn on encryption
+/dev/block/by-name/userdata /data ext4 noatime,nosuid,nodev,errors=panic latemount,wait,check
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 61f9ae5..721ba93 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -78,6 +78,8 @@
     # some services can be started.
     trigger late-fs
 
+    trigger post-fs-data
+
     # Load persist properties and override properties (if enabled) from /data.
     trigger load_persist_props_action
 
@@ -109,6 +111,10 @@
 
     start adbd
 
+on post-fs-data
+    mount_all /vendor/etc/fstab --late
+    restorecon /data
+
 service ueventd /system/bin/ueventd
     class core
     critical
diff --git a/microdroid/microdroid_cdisk_userdata.json b/microdroid/microdroid_cdisk_userdata.json
new file mode 100644
index 0000000..04af3f2
--- /dev/null
+++ b/microdroid/microdroid_cdisk_userdata.json
@@ -0,0 +1,9 @@
+{
+  "partitions": [
+    {
+      "label": "userdata",
+      "path": "userdata.img",
+      "writable": true
+    }
+  ]
+}
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index aaa0457..5a104d1 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -30,6 +30,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -61,11 +64,13 @@
                                 + "cp %setc/microdroid_bootloader bootloader && "
                                 + "cp %setc/fs/*.img . && "
                                 + "cp %setc/uboot_env.img . && "
-                                + "dd if=/dev/zero of=misc.img bs=4k count=256",
+                                + "dd if=/dev/zero of=misc.img bs=4k count=256 && "
+                                + "dd if=/dev/zero of=userdata.img bs=4k count=25600 && "
+                                + "mkfs.ext4 userdata.img",
                         TEST_ROOT, TEST_ROOT, VIRT_APEX, VIRT_APEX, VIRT_APEX);
         getDevice().executeShellCommand(prepareImagesCmd);
 
-        // Create os_composite.img, env_composite.img, and payload.img
+        // Create os_composite.img, env_composite.img, userdata.img, and payload.img
         String makeOsCompositeCmd =
                 String.format(
                         "cd %s; %sbin/mk_cdisk %setc/microdroid_cdisk.json os_composite.img",
@@ -76,6 +81,12 @@
                         "cd %s; %sbin/mk_cdisk %setc/microdroid_cdisk_env.json env_composite.img",
                         TEST_ROOT, VIRT_APEX, VIRT_APEX);
         getDevice().executeShellCommand(makeEnvCompositeCmd);
+        String makeDataCompositeCmd =
+                String.format(
+                        "cd %s; %sbin/mk_cdisk %setc/microdroid_cdisk_userdata.json"
+                                + " userdata_composite.img",
+                        TEST_ROOT, VIRT_APEX, VIRT_APEX);
+        getDevice().executeShellCommand(makeDataCompositeCmd);
         String makePayloadCompositeCmd =
                 String.format(
                         "cd %s; %sbin/mk_payload %setc/microdroid_payload.json payload.img",
@@ -83,14 +94,15 @@
         getDevice().executeShellCommand(makePayloadCompositeCmd);
 
         // Make sure that the composite images are created
-        final String osCompositeImg = TEST_ROOT + "/os_composite.img";
-        final String envCompositeImg = TEST_ROOT + "/env_composite.img";
-        final String payloadCompositeImg = TEST_ROOT + "/payload.img";
+        final List<String> compositeImages =
+                new ArrayList<>(
+                        Arrays.asList(
+                                TEST_ROOT + "/os_composite.img",
+                                TEST_ROOT + "/env_composite.img",
+                                TEST_ROOT + "/userdata_composite.img",
+                                TEST_ROOT + "/payload.img"));
         CommandResult result =
-                getDevice().executeShellV2Command(
-                        "du -b " + osCompositeImg + " "
-                                 + envCompositeImg + " "
-                                 + payloadCompositeImg);
+                getDevice().executeShellV2Command("du -b " + String.join(" ", compositeImages));
         assertThat(result.getExitCode(), is(0));
         assertThat(result.getStdout(), is(not("")));
 
@@ -100,7 +112,8 @@
                 String.format(
                         "cd %s; %sbin/crosvm run --cid=%d --disable-sandbox --bios=bootloader"
                                 + " --serial=type=syslog --disk=os_composite.img"
-                                + " --disk=env_composite.img --disk=payload.img",
+                                + " --disk=env_composite.img --disk=payload.img"
+                                + " --rwdisk=userdata_composite.img",
                         TEST_ROOT, VIRT_APEX, TEST_VM_CID);
         executor.execute(
                 () -> {