Merge "Make authfs start optional"
diff --git a/avmd/src/main.rs b/avmd/src/main.rs
index ca28f42..a3dee15 100644
--- a/avmd/src/main.rs
+++ b/avmd/src/main.rs
@@ -16,7 +16,7 @@
 
 use anyhow::{anyhow, bail, Result};
 use apexutil::get_payload_vbmeta_image_hash;
-use apkverify::pick_v4_apk_digest;
+use apkverify::get_apk_digest;
 use avmd::{ApkDescriptor, Avmd, Descriptor, ResourceIdentifier, VbMetaDescriptor};
 use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
 use serde::ser::Serialize;
@@ -74,7 +74,7 @@
     }
     for (i, namespace, name, file) in NamespaceNameFileIterator::new(args, "apk") {
         let file = File::open(file)?;
-        let (signature_algorithm_id, apk_digest) = pick_v4_apk_digest(file)?;
+        let (signature_algorithm_id, apk_digest) = get_apk_digest(file, /*verify=*/ false)?;
         descriptors.insert(
             i,
             Descriptor::Apk(ApkDescriptor {
diff --git a/compos/benchmark/src/java/com/android/compos/benchmark/ComposBenchmark.java b/compos/benchmark/src/java/com/android/compos/benchmark/ComposBenchmark.java
index 996d32a..dd113a6 100644
--- a/compos/benchmark/src/java/com/android/compos/benchmark/ComposBenchmark.java
+++ b/compos/benchmark/src/java/com/android/compos/benchmark/ComposBenchmark.java
@@ -23,7 +23,6 @@
 
 import android.app.Instrumentation;
 import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
 import com.android.microdroid.test.common.MetricsProcessor;
@@ -36,9 +35,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.sql.Timestamp;
 import java.text.DateFormat;
 import java.text.ParseException;
@@ -198,37 +195,8 @@
         processMemory.forEach((k, v) -> reportMetric(prefix + k, unit, v));
     }
 
-    private byte[] executeCommandBlocking(String command) {
-        try (InputStream is =
-                        new ParcelFileDescriptor.AutoCloseInputStream(
-                                mInstrumentation.getUiAutomation().executeShellCommand(command));
-                ByteArrayOutputStream out = new ByteArrayOutputStream()) {
-            byte[] buf = new byte[BUFFER_SIZE];
-            int length;
-            while ((length = is.read(buf)) >= 0) {
-                out.write(buf, 0, length);
-            }
-            return out.toByteArray();
-        } catch (IOException e) {
-            Log.e(TAG, "Error executing: " + command, e);
-            return null;
-        }
-    }
-
     private String executeCommand(String command) {
-        try {
-            byte[] output = executeCommandBlocking(command);
-
-            if (output == null) {
-                throw new RuntimeException("Failed to run the command.");
-            } else {
-                String stdout = new String(output, "UTF-8");
-                Log.i(TAG, "Get stdout : " + stdout);
-                return stdout;
-            }
-        } catch (Exception e) {
-            throw new RuntimeException("Error executing: " + command + " , Exception: " + e);
-        }
+        return runInShell(TAG, mInstrumentation.getUiAutomation(), command);
     }
 
     private class GetMetricsRunnable implements Runnable {
diff --git a/libs/apkverify/src/lib.rs b/libs/apkverify/src/lib.rs
index 92de9b0..1e0bd77 100644
--- a/libs/apkverify/src/lib.rs
+++ b/libs/apkverify/src/lib.rs
@@ -22,7 +22,9 @@
 #[allow(dead_code)]
 pub mod testing;
 mod v3;
+mod v4;
 mod ziputil;
 
 pub use algorithms::SignatureAlgorithmID;
-pub use v3::{get_public_key_der, pick_v4_apk_digest, verify};
+pub use v3::{get_public_key_der, verify};
+pub use v4::get_apk_digest;
diff --git a/libs/apkverify/src/v3.rs b/libs/apkverify/src/v3.rs
index 5272834..fac0a7f 100644
--- a/libs/apkverify/src/v3.rs
+++ b/libs/apkverify/src/v3.rs
@@ -38,7 +38,7 @@
 
 type Signers = LengthPrefixed<Vec<LengthPrefixed<Signer>>>;
 
-struct Signer {
+pub(crate) struct Signer {
     signed_data: LengthPrefixed<Bytes>, // not verified yet
     min_sdk: u32,
     max_sdk: u32,
@@ -105,15 +105,9 @@
     Ok(signer.public_key.public_key_to_der()?.into_boxed_slice())
 }
 
-/// Gets the v4 [apk_digest].
-///
-/// [apk_digest]: https://source.android.com/docs/security/apksigning/v4#apk-digest
-pub fn pick_v4_apk_digest<R: Read + Seek>(apk: R) -> Result<(SignatureAlgorithmID, Box<[u8]>)> {
-    let (signer, _) = extract_signer_and_apk_sections(apk)?;
-    signer.pick_v4_apk_digest()
-}
-
-fn extract_signer_and_apk_sections<R: Read + Seek>(apk: R) -> Result<(Signer, ApkSections<R>)> {
+pub(crate) fn extract_signer_and_apk_sections<R: Read + Seek>(
+    apk: R,
+) -> Result<(Signer, ApkSections<R>)> {
     let mut sections = ApkSections::new(apk)?;
     let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID).context(
         "Fallback to v2 when v3 block not found is not yet implemented. See b/197052981.",
@@ -144,7 +138,7 @@
             .context("No supported signatures found")?)
     }
 
-    fn pick_v4_apk_digest(&self) -> Result<(SignatureAlgorithmID, Box<[u8]>)> {
+    pub(crate) fn pick_v4_apk_digest(&self) -> Result<(SignatureAlgorithmID, Box<[u8]>)> {
         let strongest_algorithm_id = self
             .strongest_signature()?
             .signature_algorithm_id
diff --git a/libs/apkverify/src/v4.rs b/libs/apkverify/src/v4.rs
new file mode 100644
index 0000000..d0522a7
--- /dev/null
+++ b/libs/apkverify/src/v4.rs
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! API for APK Signature Scheme [v4].
+//!
+//! [v4]: https://source.android.com/security/apksigning/v4
+
+use anyhow::{ensure, Result};
+use std::io::{Read, Seek};
+
+use crate::algorithms::SignatureAlgorithmID;
+use crate::v3::extract_signer_and_apk_sections;
+
+/// Gets the v4 [apk_digest]. If `verify` is true, we verify that digest computed
+/// with the extracted algorithm is equal to the digest extracted directly from apk.
+/// Otherwise, the extracted digest will be returned directly.
+///
+/// [apk_digest]: https://source.android.com/docs/security/apksigning/v4#apk-digest
+pub fn get_apk_digest<R: Read + Seek>(
+    apk: R,
+    verify: bool,
+) -> Result<(SignatureAlgorithmID, Box<[u8]>)> {
+    let (signer, mut sections) = extract_signer_and_apk_sections(apk)?;
+    let (signature_algorithm_id, extracted_digest) = signer.pick_v4_apk_digest()?;
+    if verify {
+        let computed_digest = sections.compute_digest(signature_algorithm_id)?;
+        ensure!(
+            computed_digest == extracted_digest.as_ref(),
+            "Computed digest does not match the extracted digest."
+        );
+    }
+    Ok((signature_algorithm_id, extracted_digest))
+}
diff --git a/libs/apkverify/tests/apkverify_test.rs b/libs/apkverify/tests/apkverify_test.rs
index e17ba5c..047538c 100644
--- a/libs/apkverify/tests/apkverify_test.rs
+++ b/libs/apkverify/tests/apkverify_test.rs
@@ -15,7 +15,7 @@
  */
 
 use apkverify::{
-    get_public_key_der, pick_v4_apk_digest, testing::assert_contains, verify, SignatureAlgorithmID,
+    get_apk_digest, get_public_key_der, testing::assert_contains, verify, SignatureAlgorithmID,
 };
 use std::{fs, matches, path::Path};
 
@@ -221,16 +221,22 @@
 
 /// Validates that the following apk_digest are equal:
 /// * apk_digest directly extracted from apk without computation
+/// * computed apk_digest
 /// * expected apk digest from the corresponding .apk_digest file
 fn validate_apk_digest<P: AsRef<Path>>(apk_path: P, expected_algorithm_id: SignatureAlgorithmID) {
     let apk = fs::File::open(&apk_path).expect("Unabled to open apk file");
 
-    let (signature_algorithm_id, digest_from_apk) =
-        pick_v4_apk_digest(apk).expect("Error when extracting apk digest.");
+    let (verified_algorithm_id, verified_digest) = get_apk_digest(&apk, /*verify=*/ true)
+        .expect("Error when extracting apk digest with verification.");
 
-    assert_eq!(expected_algorithm_id, signature_algorithm_id);
+    assert_eq!(expected_algorithm_id, verified_algorithm_id);
     let expected_digest_path = format!("{}.apk_digest", apk_path.as_ref().to_str().unwrap());
-    assert_bytes_eq_to_data_in_file(&digest_from_apk, expected_digest_path);
+    assert_bytes_eq_to_data_in_file(&verified_digest, expected_digest_path);
+
+    let (unverified_algorithm_id, unverified_digest) = get_apk_digest(&apk, /*verify=*/ false)
+        .expect("Error when extracting apk digest without verification.");
+    assert_eq!(expected_algorithm_id, unverified_algorithm_id);
+    assert_eq!(verified_digest, unverified_digest);
 }
 
 fn assert_bytes_eq_to_data_in_file<P: AsRef<Path> + std::fmt::Display>(
diff --git a/libs/idsig/src/apksigv4.rs b/libs/idsig/src/apksigv4.rs
index 434a429..29def3b 100644
--- a/libs/idsig/src/apksigv4.rs
+++ b/libs/idsig/src/apksigv4.rs
@@ -15,7 +15,7 @@
  */
 
 use anyhow::{anyhow, bail, Context, Result};
-use apkverify::{pick_v4_apk_digest, SignatureAlgorithmID};
+use apkverify::{get_apk_digest, SignatureAlgorithmID};
 use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 use num_derive::{FromPrimitive, ToPrimitive};
 use num_traits::{FromPrimitive, ToPrimitive};
@@ -158,7 +158,7 @@
         ret.hashing_info.log2_blocksize = log2(block_size);
 
         apk.seek(SeekFrom::Start(start))?;
-        let (signature_algorithm_id, apk_digest) = pick_v4_apk_digest(apk)?;
+        let (signature_algorithm_id, apk_digest) = get_apk_digest(apk, /*verify=*/ false)?;
         ret.signing_info.signature_algorithm_id = signature_algorithm_id;
         ret.signing_info.apk_digest = apk_digest;
         // TODO(jiyong): add a signature to the signing_info struct
diff --git a/microdroid/bootconfig.app_debuggable b/microdroid/bootconfig.app_debuggable
index 6e66371..529ed07 100644
--- a/microdroid/bootconfig.app_debuggable
+++ b/microdroid/bootconfig.app_debuggable
@@ -7,9 +7,8 @@
 androidboot.microdroid.debuggable=0
 
 # Console output is not redirect to the host-side.
-# TODO(b/219743539) This doesn't successfully disable the console
 kernel.printk.devkmsg=off
-kernel.console=null
+kernel.console=ttynull
 
 # ADB is supported but rooting is prohibited.
 androidboot.adb.enabled=1
diff --git a/microdroid/bootconfig.normal b/microdroid/bootconfig.normal
index ec85f0d..5cc553c 100644
--- a/microdroid/bootconfig.normal
+++ b/microdroid/bootconfig.normal
@@ -5,10 +5,8 @@
 androidboot.microdroid.debuggable=0
 
 # Console output is not redirect to the host-side.
-# TODO(b/219743539) This doesn't successfully disable the console
 kernel.printk.devkmsg=off
-# TODO(b/219743539) Setting this to null makes everything slow
-kernel.console=hvc0
+kernel.console=ttynull
 
 # ADB is not enabled.
 androidboot.adb.enabled=0
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index a07731e..fdc846e 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -19,6 +19,7 @@
 
 import static org.junit.Assume.assumeNoException;
 
+import android.app.UiAutomation;
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemProperties;
@@ -35,6 +36,8 @@
 import com.android.virt.VirtualizationTestHelper;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.OptionalLong;
@@ -334,4 +337,20 @@
                 listener.getInitStartedNanoTime(),
                 listener.getPayloadStartedNanoTime());
     }
+
+    /** Execute a command. Returns stdout. */
+    protected String runInShell(String tag, UiAutomation uiAutomation, String command) {
+        try (InputStream is =
+                        new ParcelFileDescriptor.AutoCloseInputStream(
+                                uiAutomation.executeShellCommand(command));
+                ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            is.transferTo(out);
+            String stdout = out.toString("UTF-8");
+            Log.i(tag, "Got stdout : " + stdout);
+            return stdout;
+        } catch (IOException e) {
+            Log.e(tag, "Error executing: " + command, e);
+            throw new RuntimeException("Failed to run the command.");
+        }
+    }
 }