Merge changes I49b222b9,I96bdda45,I7a75ef4e,I50f3f1ba,Ica4a9a21

* changes:
  Assign inode values properly in AuthFS
  Various renames in authfs
  Remove unnecessary local ID in authfs
  authfs: support remote output directory
  Workaround a quirk in the OpenOptions unix impl
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 69f5518..b07dc3b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -8,9 +8,7 @@
     },
     {
       "name": "VirtualizationTestCases"
-    }
-  ],
-  "postsubmit": [
+    },
     {
       "name": "MicrodroidTestApp"
     }
diff --git a/apex/Android.bp b/apex/Android.bp
index af65e79..9d4cfdf 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -39,6 +39,7 @@
                 "microdroid_boot-5.10",
                 "microdroid_vendor_boot-5.10",
                 "microdroid_vbmeta",
+                "microdroid_vbmeta_bootconfig",
             ],
         },
     },
diff --git a/demo/java/com/android/microdroid/demo/MainActivity.java b/demo/java/com/android/microdroid/demo/MainActivity.java
index 60e50bb..15d9046 100644
--- a/demo/java/com/android/microdroid/demo/MainActivity.java
+++ b/demo/java/com/android/microdroid/demo/MainActivity.java
@@ -285,7 +285,7 @@
                     mVirtualMachine = vmm.create("demo_vm", config);
                 }
                 mVirtualMachine.run();
-                mVirtualMachine.setCallback(callback);
+                mVirtualMachine.setCallback(Executors.newSingleThreadExecutor(), callback);
                 mStatus.postValue(mVirtualMachine.getStatus());
 
                 InputStream console = mVirtualMachine.getConsoleOutputStream();
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index 63c9288..6556b87 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -19,6 +19,7 @@
 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -42,6 +43,7 @@
 import java.nio.file.FileAlreadyExistsException;
 import java.nio.file.Files;
 import java.util.Optional;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -110,6 +112,9 @@
     /** The registered callback */
     private @Nullable VirtualMachineCallback mCallback;
 
+    /** The executor on which the callback will be executed */
+    private @NonNull Executor mCallbackExecutor;
+
     private @Nullable ParcelFileDescriptor mConsoleReader;
     private @Nullable ParcelFileDescriptor mConsoleWriter;
 
@@ -263,7 +268,10 @@
      * Registers the callback object to get events from the virtual machine. If a callback was
      * already registered, it is replaced with the new one.
      */
-    public void setCallback(@Nullable VirtualMachineCallback callback) {
+    public void setCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable VirtualMachineCallback callback) {
+        mCallbackExecutor = executor;
         mCallback = callback;
     }
 
@@ -328,7 +336,8 @@
                             if (cb == null) {
                                 return;
                             }
-                            cb.onPayloadStarted(VirtualMachine.this, stream);
+                            mCallbackExecutor.execute(
+                                    () -> cb.onPayloadStarted(VirtualMachine.this, stream));
                         }
 
                         @Override
@@ -337,7 +346,7 @@
                             if (cb == null) {
                                 return;
                             }
-                            cb.onPayloadReady(VirtualMachine.this);
+                            mCallbackExecutor.execute(() -> cb.onPayloadReady(VirtualMachine.this));
                         }
 
                         @Override
@@ -346,7 +355,8 @@
                             if (cb == null) {
                                 return;
                             }
-                            cb.onPayloadFinished(VirtualMachine.this, exitCode);
+                            mCallbackExecutor.execute(
+                                    () -> cb.onPayloadFinished(VirtualMachine.this, exitCode));
                         }
 
                         @Override
@@ -355,7 +365,7 @@
                             if (cb == null) {
                                 return;
                             }
-                            cb.onDied(VirtualMachine.this);
+                            mCallbackExecutor.execute(() -> cb.onDied(VirtualMachine.this));
                         }
                     });
             service.asBinder()
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 274b7ed..44b547e 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -335,25 +335,93 @@
     cmd: "cat $(in) > $(out)",
 }
 
+vbmeta {
+    name: "microdroid_vbmeta_bootconfig",
+    partition_name: "vbmeta",
+    private_key: ":avb_testkey_rsa4096",
+    chained_partitions: [
+        {
+            name: "bootconfig",
+            private_key: ":avb_testkey_rsa4096",
+        },
+    ],
+}
+
+// See external/avb/avbtool.py
+// MAX_VBMETA_SIZE=64KB, MAX_FOOTER_SIZE=4KB
+avb_hash_footer_kb = "68"
+
 // TODO(b/203031847) sign these bootconfig images using avb
 prebuilt_etc {
     name: "microdroid_bootconfig_normal",
-    src: "bootconfig.normal",
+    src: ":microdroid_bootconfig_normal_gen",
     filename: "microdroid_bootconfig.normal",
 }
 
 prebuilt_etc {
     name: "microdroid_bootconfig_app_debuggable",
-    src: "bootconfig.app_debuggable",
+    src: ":microdroid_bootconfig_app_debuggable_gen",
     filename: "microdroid_bootconfig.app_debuggable",
 }
 
 prebuilt_etc {
     name: "microdroid_bootconfig_full_debuggable",
-    src: "bootconfig.full_debuggable",
+    src: ":microdroid_bootconfig_full_debuggable_gen",
     filename: "microdroid_bootconfig.full_debuggable",
 }
 
+// TODO(jiyong): make a new module type that does the avb signing
+genrule {
+    name: "microdroid_bootconfig_normal_gen",
+    tools: ["avbtool"],
+    srcs: [
+        "bootconfig.normal",
+        ":avb_testkey_rsa4096",
+    ],
+    out: ["microdroid_bootconfig.normal"],
+    cmd: "cp $(location bootconfig.normal) $(out) && " +
+        "$(location avbtool) add_hash_footer " +
+        "--algorithm SHA256_RSA4096 " +
+        "--partition_name bootconfig " +
+        "--key $(location :avb_testkey_rsa4096) " +
+        "--partition_size $$(( " + avb_hash_footer_kb + " * 1024 + ( $$(stat --format=%s $(out)) + 4096 - 1 ) / 4096 * 4096 )) " +
+        "--image $(out)",
+}
+
+genrule {
+    name: "microdroid_bootconfig_app_debuggable_gen",
+    tools: ["avbtool"],
+    srcs: [
+        "bootconfig.app_debuggable",
+        ":avb_testkey_rsa4096",
+    ],
+    out: ["microdroid_bootconfig.app_debuggable"],
+    cmd: "cp $(location bootconfig.app_debuggable) $(out) && " +
+        "$(location avbtool) add_hash_footer " +
+        "--algorithm SHA256_RSA4096 " +
+        "--partition_name bootconfig " +
+        "--key $(location :avb_testkey_rsa4096) " +
+        "--partition_size $$(( " + avb_hash_footer_kb + " * 1024 + ( $$(stat --format=%s $(out)) + 4096 - 1 ) / 4096 * 4096 )) " +
+        "--image $(out)",
+}
+
+genrule {
+    name: "microdroid_bootconfig_full_debuggable_gen",
+    tools: ["avbtool"],
+    srcs: [
+        "bootconfig.full_debuggable",
+        ":avb_testkey_rsa4096",
+    ],
+    out: ["microdroid_bootconfig.full_debuggable"],
+    cmd: "cp $(location bootconfig.full_debuggable) $(out) && " +
+        "$(location avbtool) add_hash_footer " +
+        "--algorithm SHA256_RSA4096 " +
+        "--partition_name bootconfig " +
+        "--key $(location :avb_testkey_rsa4096) " +
+        "--partition_size $$(( " + avb_hash_footer_kb + " * 1024 + ( $$(stat --format=%s $(out)) + 4096 - 1 ) / 4096 * 4096 )) " +
+        "--image $(out)",
+}
+
 prebuilt_etc {
     name: "microdroid_fstab",
     src: "fstab.microdroid",
@@ -375,10 +443,6 @@
     filename: "microdroid_bootloader",
 }
 
-// See external/avb/avbtool.py
-// MAX_VBMETA_SIZE=64KB, MAX_FOOTER_SIZE=4KB
-avb_hash_footer_kb = "68"
-
 // TODO(b/193504286) remove this when prebuilt bootloader exposes pubkey as well.
 genrule {
     name: "microdroid_bootloader_gen",
diff --git a/microdroid/bootconfig.x86_64 b/microdroid/bootconfig.x86_64
index 2977ee3..6076889 100644
--- a/microdroid/bootconfig.x86_64
+++ b/microdroid/bootconfig.x86_64
@@ -1 +1 @@
-androidboot.boot_devices = pci0000:00/0000:00:03.0,pci0000:00/0000:00:04.0,pci0000:00/0000:00:05.0
+androidboot.boot_devices = pci0000:00/0000:00:04.0,pci0000:00/0000:00:05.0,pci0000:00/0000:00:06.0
diff --git a/microdroid/init.rc b/microdroid/init.rc
index ad551cc..664402f 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -195,7 +195,7 @@
     seclabel u:r:shell:s0
     setenv HOSTNAME console
 
-service seriallogging /system/bin/logcat -b all -v threadtime -f /dev/hvc1 *:V
+service seriallogging /system/bin/logcat -b all -v threadtime -f /dev/hvc2 *:V
     disabled
     user logd
     group root logd
diff --git a/microdroid/ueventd.rc b/microdroid/ueventd.rc
index 85f2f9d..037b8fc 100644
--- a/microdroid/ueventd.rc
+++ b/microdroid/ueventd.rc
@@ -26,4 +26,4 @@
 /dev/tty0                 0660   root       system
 
 # Virtual console for logcat
-/dev/hvc1                 0660   logd       logd
+/dev/hvc2                 0660   logd       logd
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 8ff2127..e0d6cc1 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -19,8 +19,6 @@
 import static org.junit.Assume.assumeNoException;
 
 import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.system.virtualmachine.VirtualMachine;
 import android.system.virtualmachine.VirtualMachineCallback;
@@ -38,6 +36,10 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
 @RunWith(JUnit4.class)
 public class MicrodroidTests {
     @Rule public Timeout globalTimeout = Timeout.seconds(300);
@@ -81,57 +83,24 @@
     }
 
     private abstract static class VmEventListener implements VirtualMachineCallback {
-        private final Handler mHandler;
+        private ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
 
-        VmEventListener() {
-            Looper.prepare();
-            mHandler = new Handler(Looper.myLooper());
-        }
-
-        void runToFinish(VirtualMachine vm) throws VirtualMachineException {
-            vm.setCallback(mCallback);
+        void runToFinish(VirtualMachine vm) throws VirtualMachineException, InterruptedException {
+            vm.setCallback(mExecutorService, this);
             vm.run();
-            Looper.loop();
+            mExecutorService.awaitTermination(300, TimeUnit.SECONDS);
         }
 
         void forceStop(VirtualMachine vm) {
             try {
                 vm.stop();
+                this.onDied(vm);
+                mExecutorService.shutdown();
             } catch (VirtualMachineException e) {
                 throw new RuntimeException(e);
             }
         }
 
-        // This is the actual listener that is registered. Since the listener is executed in another
-        // thread, post a runnable to the current thread to call the corresponding mHandler method
-        // in the current thread.
-        private final VirtualMachineCallback mCallback =
-                new VirtualMachineCallback() {
-                    @Override
-                    public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
-                        mHandler.post(() -> VmEventListener.this.onPayloadStarted(vm, stream));
-                    }
-
-                    @Override
-                    public void onPayloadReady(VirtualMachine vm) {
-                        mHandler.post(() -> VmEventListener.this.onPayloadReady(vm));
-                    }
-
-                    @Override
-                    public void onPayloadFinished(VirtualMachine vm, int exitCode) {
-                        mHandler.post(() -> VmEventListener.this.onPayloadFinished(vm, exitCode));
-                    }
-
-                    @Override
-                    public void onDied(VirtualMachine vm) {
-                        mHandler.post(
-                                () -> {
-                                    VmEventListener.this.onDied(vm);
-                                    Looper.myLooper().quitSafely();
-                                });
-                    }
-                };
-
         @Override
         public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {}
 
@@ -158,13 +127,13 @@
                     private boolean mPayloadStartedCalled = false;
 
                     @Override
-                    public void onPayloadReady(VirtualMachine vm) {
-                        mPayloadReadyCalled = true;
+                    public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
+                        mPayloadStartedCalled = true;
                     }
 
                     @Override
-                    public void onPayloadStarted(VirtualMachine vm, ParcelFileDescriptor stream) {
-                        mPayloadStartedCalled = true;
+                    public void onPayloadReady(VirtualMachine vm) {
+                        mPayloadReadyCalled = true;
                         forceStop(vm);
                     }
 
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 08be052..bf1ff0c 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -251,8 +251,9 @@
 
     // Setup the serial devices.
     // 1. uart device: used as the output device by bootloaders and as early console by linux
-    // 2. virtio-console device: used as the console device
-    // 3. virtio-console device: used as the logcat output
+    // 2. virtio-console device: used as the console device where kmsg is redirected to
+    // 3. virtio-console device: used as the androidboot.console device (not used currently)
+    // 4. virtio-console device: used as the logcat output
     //
     // When [console|log]_fd is not specified, the devices are attached to sink, which means what's
     // written there is discarded.
@@ -273,8 +274,10 @@
     command.arg(format!("--serial={},hardware=serial", &console_arg));
     // /dev/hvc0
     command.arg(format!("--serial={},hardware=virtio-console,num=1", &console_arg));
-    // /dev/hvc1
-    command.arg(format!("--serial={},hardware=virtio-console,num=2", &log_arg));
+    // /dev/hvc1 (not used currently)
+    command.arg("--serial=type=sink,hardware=virtio-console,num=2");
+    // /dev/hvc2
+    command.arg(format!("--serial={},hardware=virtio-console,num=3", &log_arg));
 
     if let Some(bootloader) = &config.bootloader {
         command.arg("--bios").arg(add_preserved_fd(&mut preserved_fds, bootloader));
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index bc184ec..ac8eec7 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -296,6 +296,14 @@
         temporary_directory,
     )?);
 
+    vm_config.disks[1].partitions.push(Partition {
+        label: "vbmeta".to_owned(),
+        image: Some(open_parcel_file(
+            Path::new("/apex/com.android.virt/etc/fs/microdroid_vbmeta_bootconfig.img"),
+            false,
+        )?),
+        writable: false,
+    });
     let bootconfig_image = "/apex/com.android.virt/etc/microdroid_bootconfig.".to_owned()
         + match config.debugLevel {
             DebugLevel::NONE => "normal",