Merge "ttyd uses client cert" into main
diff --git a/android/LinuxInstaller/java/com/android/virtualization/linuxinstaller/MainActivity.java b/android/LinuxInstaller/java/com/android/virtualization/linuxinstaller/MainActivity.java
index 0351f97..9b0ec97 100644
--- a/android/LinuxInstaller/java/com/android/virtualization/linuxinstaller/MainActivity.java
+++ b/android/LinuxInstaller/java/com/android/virtualization/linuxinstaller/MainActivity.java
@@ -18,11 +18,6 @@
 
 import android.annotation.WorkerThread;
 import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.SystemProperties;
@@ -65,12 +60,6 @@
     }
 
     private void installLinuxImage() {
-        ComponentName vmTerminalComponent = resolve(getPackageManager(), ACTION_VM_TERMINAL);
-        if (vmTerminalComponent == null) {
-            updateStatus("Failed to resolve VM terminal");
-            return;
-        }
-
         if (!hasLocalAssets()) {
             updateStatus("No local assets");
             return;
@@ -81,12 +70,6 @@
             Log.e(TAG, "failed to update image", e);
             return;
         }
-        updateStatus("Enabling terminal app...");
-        getPackageManager()
-                .setComponentEnabledSetting(
-                        vmTerminalComponent,
-                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
-                        PackageManager.DONT_KILL_APP);
         updateStatus("Done.");
     }
 
@@ -190,18 +173,4 @@
                     statusView.append(line + "\n");
                 });
     }
-
-    private ComponentName resolve(PackageManager pm, String action) {
-        Intent intent = new Intent(action);
-        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, PackageManager.MATCH_ALL);
-        if (resolveInfos.size() != 1) {
-            Log.w(
-                    TAG,
-                    "Failed to resolve activity, action=" + action + ", resolved=" + resolveInfos);
-            return null;
-        }
-        ActivityInfo activityInfo = resolveInfos.getFirst().activityInfo;
-        // MainActivityAlias shows in Launcher
-        return new ComponentName(activityInfo.packageName, activityInfo.name + "Alias");
-    }
 }
diff --git a/android/TerminalApp/AndroidManifest.xml b/android/TerminalApp/AndroidManifest.xml
index f09412e..bd1395a 100644
--- a/android/TerminalApp/AndroidManifest.xml
+++ b/android/TerminalApp/AndroidManifest.xml
@@ -12,15 +12,18 @@
     <uses-feature android:name="android.software.virtualization_framework" android:required="true" />
 
     <application
-	android:label="@string/app_name"
+        android:label="@string/app_name"
         android:icon="@mipmap/ic_launcher"
         android:theme="@style/Theme.Material3.DayNight.NoActionBar"
-        android:usesCleartextTraffic="true">
+        android:usesCleartextTraffic="true"
+        android:enabled="false">
         <activity android:name=".MainActivity"
                   android:configChanges="orientation|screenSize|keyboard|keyboardHidden|navigation|uiMode|screenLayout|smallestScreenSize"
                   android:exported="true">
             <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.virtualization.VM_TERMINAL" />
+                <category android:name="android.intent.category.LAUNCHER" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
@@ -44,20 +47,9 @@
                 android:name="${applicationId}.SplitInitializer"
                 android:value="androidx.startup" />
         </provider>
-        <activity-alias
-            android:name=".MainActivityAlias"
-            android:targetActivity="com.android.virtualization.terminal.MainActivity"
-            android:exported="true"
-            android:enabled="false" >
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity-alias>
 
         <service
             android:name="com.android.virtualization.vmlauncher.VmLauncherService"
-            android:enabled="true"
             android:exported="false"
             android:foregroundServiceType="specialUse">
             <property
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index 821a2ef..6ae5b7b 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -16,25 +16,45 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name">Terminal</string>
-    <string name="vm_creation_message">Preparing terminal.</string>
-    <string name="vm_stop_message">Stopping terminal.</string>
-    <string name="vm_error_message">Terminal crashed.</string>
 
+    <!-- Application name of this terminal app shown in the launcher. This app provides computer terminal to connect to virtual machine. [CHAR LIMIT=16] -->
+    <string name="app_name">Terminal</string>
+
+    <!-- Toast message to notify that preparing terminal to start [CHAR LIMIT=none] -->
+    <string name="vm_creation_message">Preparing terminal</string>
+    <!-- Toast message to notify that terminal is stopping [CHAR LIMIT=none] -->
+    <string name="vm_stop_message">Stopping terminal</string>
+    <!-- Toast message to notify that terminal is crashed [CHAR LIMIT=none] -->
+    <string name="vm_error_message">Terminal crashed</string>
+
+    <!-- Settings memu title for resizing disk of the virtual machine. [CHAR LIMIT=none] -->
     <string name="settings_disk_resize_title">Disk Resize</string>
+    <!-- Settings memu subtitle for resizing disk of the virtual machine. [CHAR LIMIT=none] -->
     <string name="settings_disk_resize_sub_title">Resize / Rootfs</string>
+    <!-- Toast message after new disk size is set. [CHAR LIMIT=none] -->
     <string name="settings_disk_resize_resize_message">Disk size set</string>
+    <!-- Settings menu option description for the current disk size, followed by a text box with the actual number [CHAR LIMIT=none] -->
     <string name="settings_disk_resize_resize_gb_assigned">GB Assigned</string>
+    <!-- Settings menu option description for the maximum resizable disk size. [CHAR LIMIT=none] -->
     <string name="settings_disk_resize_resize_gb_total">256 GB total</string>
+    <!-- Settings menu button to cancel disk resize. [CHAR LIMIT=32] -->
     <string name="settings_disk_resize_resize_cancel">Cancel</string>
+    <!-- Settings menu button to apply change that requires to restart VM (abbrev of virtual machine). [CHAR LIMIT=64] -->
     <string name="settings_disk_resize_resize_restart_vm_to_apply">Restart VM to apply</string>
 
+    <!-- Settings menu title for 'port forwarding' [CHAR LIMIT=none] -->
     <string name="settings_port_forwarding_title">Port Forwarding</string>
+    <!-- Settings menu subtitle for 'port forwarding' [CHAR LIMIT=none] -->
     <string name="settings_port_forwarding_sub_title">Configure port forwarding</string>
 
+    <!-- Settings menu title for recoverying image [CHAR LIMIT=none] -->
     <string name="settings_recovery_title">Recovery</string>
+    <!-- Settings menu subtitle for recoverying image [CHAR LIMIT=none] -->
     <string name="settings_recovery_sub_title">Partition Recovery options</string>
+    <!-- Settings menu title for resetting the virtual machine image [CHAR LIMIT=none] -->
     <string name="settings_recovery_reset_title">Change to Initial version</string>
+    <!-- Settings menu subtitle for resetting the virtual machine image [CHAR LIMIT=none] -->
     <string name="settings_recovery_reset_sub_title">Remove all</string>
+    <!-- Toast message for reset is completed [CHAR LIMIT=none] -->
     <string name="settings_recovery_reset_message">VM reset</string>
 </resources>
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 97d9373..71a9d3b 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -103,6 +103,17 @@
 	wget -O - "${url}" | tar xz -C "${outdir}" --strip-components=1
 }
 
+build_rust_binary_and_copy() {
+	pushd "$(dirname "$0")/../../guest/$1" > /dev/null
+	RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
+		--target "${arch}-unknown-linux-gnu" \
+		--target-dir "${workdir}/$1"
+	mkdir -p "${dst}/files/usr/local/bin/$1"
+	cp "${workdir}/$1/${arch}-unknown-linux-gnu/debug/$1" "${dst}/files/usr/local/bin/$1/AVF"
+	chmod 777 "${dst}/files/usr/local/bin/$1/AVF"
+	popd > /dev/null
+}
+
 copy_android_config() {
 	local src="$(dirname "$0")/fai_config"
 	local dst="${config_space}"
@@ -116,23 +127,9 @@
 	wget "${url}" -O "${dst}/files/usr/local/bin/ttyd/AVF"
 	chmod 777 "${dst}/files/usr/local/bin/ttyd/AVF"
 
-	pushd "$(dirname "$0")/../../guest/forwarder_guest" > /dev/null
-	RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
-		--target "${arch}-unknown-linux-gnu" \
-		--target-dir "${workdir}/forwarder_guest"
-	mkdir -p "${dst}/files/usr/local/bin/forwarder_guest"
-	cp "${workdir}/forwarder_guest/${arch}-unknown-linux-gnu/debug/forwarder_guest" "${dst}/files/usr/local/bin/forwarder_guest/AVF"
-	chmod 777 "${dst}/files/usr/local/bin/forwarder_guest/AVF"
-	popd > /dev/null
-
-	pushd $(dirname $0)/../../guest/ip_addr_reporter > /dev/null
-	RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc" cargo build \
-		--target aarch64-unknown-linux-gnu \
-		--target-dir ${workdir}/ip_addr_reporter
-	mkdir -p ${dst}/files/usr/local/bin/ip_addr_reporter
-	cp ${workdir}/ip_addr_reporter/aarch64-unknown-linux-gnu/debug/ip_addr_reporter ${dst}/files/usr/local/bin/ip_addr_reporter/AVF
-	chmod 777 ${dst}/files/usr/local/bin/ip_addr_reporter/AVF
-	popd > /dev/null
+	build_rust_binary_and_copy forwarder_guest
+	build_rust_binary_and_copy forwarder_guest_launcher
+	build_rust_binary_and_copy ip_addr_reporter
 }
 
 run_fai() {
diff --git a/build/debian/fai_config/scripts/AVF/10-systemd b/build/debian/fai_config/scripts/AVF/10-systemd
index 09d1bd1..6a106c6 100755
--- a/build/debian/fai_config/scripts/AVF/10-systemd
+++ b/build/debian/fai_config/scripts/AVF/10-systemd
@@ -1,7 +1,8 @@
 #!/bin/bash
 
 chmod +x $target/usr/local/bin/forwarder_guest
+chmod +x $target/usr/local/bin/forwarder_guest_launcher
 chmod +x $target/usr/local/bin/ip_addr_reporter
 chmod +x $target/usr/local/bin/ttyd
 ln -s /etc/systemd/system/ttyd.service $target/etc/systemd/system/multi-user.target.wants/ttyd.service
-ln -s /etc/systemd/system/ip_addr_reporter.service $target/etc/systemd/system/multi-user.target.wants/ip_addr_reporter.service
\ No newline at end of file
+ln -s /etc/systemd/system/ip_addr_reporter.service $target/etc/systemd/system/multi-user.target.wants/ip_addr_reporter.service
diff --git a/build/debian/fai_config/scripts/AVF/20-useradd b/build/debian/fai_config/scripts/AVF/20-useradd
index b5887c5..9fbcd43 100755
--- a/build/debian/fai_config/scripts/AVF/20-useradd
+++ b/build/debian/fai_config/scripts/AVF/20-useradd
@@ -1,4 +1,4 @@
 #!/bin/bash
 
-$ROOTCMD useradd -m -u 1000 -g 1000 -N -G sudo droid
+$ROOTCMD useradd -m -u 1000 -N -G sudo droid
 $ROOTCMD echo 'droid ALL=(ALL) NOPASSWD:ALL' >> $target/etc/sudoers
\ No newline at end of file
diff --git a/docs/vm_remote_attestation.md b/docs/vm_remote_attestation.md
index ee20591..2ee0fae 100644
--- a/docs/vm_remote_attestation.md
+++ b/docs/vm_remote_attestation.md
@@ -126,7 +126,7 @@
 
 To support VM remote attestation, vendors must include an RKP VM marker in their
 DICE certificates. This marker should be present from the early boot stage
-within the TEE and continue through to the last DICE certificate before
+within the TEE and continue through to the leaf DICE certificate before
 [pvmfw][pvmfw] takes over.
 
 ![RKP VM DICE chain][rkpvm-dice-chain]
@@ -140,6 +140,20 @@
 server because it will lack the RKP VM marker that pvmfw would have added in a
 genuine RKP VM boot process.
 
+### Testing
+
+To ensure the correct implementation and usage of RKP VM markers, we've
+incorporated comprehensive checks into various xTS tests (e.g.,
+`VtsHalRemotelyProvisionedComponentTargetTest`).
+
+These tests validate the following conditions:
+
+- The RKP VM DICE chain must have a continuous presence of at least two RKP VM
+  markers, extending to the leaf DICE certificate.
+- Non-RKP VM DICE chains must not have a continuous presence of two or more RKP
+  VM markers, preventing non-RKP VM chains from being incorrectly identified as
+  RKP VM chains.
+
 [pvmfw]: ../guest/pvmfw/README.md
 [rkpvm-dice-chain]: img/rkpvm-dice-chain.png
 
diff --git a/guest/forwarder_guest_launcher/Cargo.toml b/guest/forwarder_guest_launcher/Cargo.toml
new file mode 100644
index 0000000..bf0c0ed
--- /dev/null
+++ b/guest/forwarder_guest_launcher/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "forwarder_guest_launcher"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+clap = { version = "4.5.20", features = ["derive"] }
+prost = "0.13.3"
+tokio = { version = "1.40.0", features = ["rt-multi-thread"] }
+tonic = "0.12.3"
+
+[build-dependencies]
+tonic-build = "0.12.3"
diff --git a/guest/forwarder_guest_launcher/build.rs b/guest/forwarder_guest_launcher/build.rs
new file mode 100644
index 0000000..c923747
--- /dev/null
+++ b/guest/forwarder_guest_launcher/build.rs
@@ -0,0 +1,18 @@
+// Copyright 2024 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.
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    tonic_build::compile_protos("../../libs/debian_service/proto/DebianService.proto")?;
+    Ok(())
+}
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
new file mode 100644
index 0000000..4042fe5
--- /dev/null
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -0,0 +1,50 @@
+// Copyright 2024 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.
+
+//! Launcher of forwarder_guest
+
+use clap::Parser;
+use debian_service::debian_service_client::DebianServiceClient;
+use debian_service::Empty;
+use tonic::transport::Endpoint;
+use tonic::Request;
+
+mod debian_service {
+    tonic::include_proto!("com.android.virtualization.vmlauncher.proto");
+}
+
+#[derive(Parser)]
+/// Flags for running command
+pub struct Args {
+    /// Host IP address
+    #[arg(long)]
+    #[arg(alias = "host")]
+    host_addr: String,
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    let args = Args::parse();
+    let addr = format!("https://{}:12000", args.host_addr);
+
+    let channel = Endpoint::from_shared(addr)?.connect().await?;
+    let mut client = DebianServiceClient::new(channel);
+    let mut res_stream =
+        client.open_forwarding_request_queue(Request::new(Empty {})).await?.into_inner();
+
+    while let Some(response) = res_stream.message().await? {
+        println!("Response from the host: {:?}", response);
+    }
+    Ok(())
+}
diff --git a/guest/microdroid_manager/Android.bp b/guest/microdroid_manager/Android.bp
index 9c9a3d0..1824c20 100644
--- a/guest/microdroid_manager/Android.bp
+++ b/guest/microdroid_manager/Android.bp
@@ -43,7 +43,6 @@
         "libmicrodroid_payload_config",
         "libmicrodroid_uids",
         "libnix",
-        "libonce_cell",
         "libopenssl",
         "libprotobuf",
         "librpcbinder_rs",
diff --git a/guest/pvmfw/Android.bp b/guest/pvmfw/Android.bp
index d0d309b..bcd3e42 100644
--- a/guest/pvmfw/Android.bp
+++ b/guest/pvmfw/Android.bp
@@ -21,7 +21,6 @@
         "libfdtpci",
         "liblibfdt_nostd",
         "liblog_rust_nostd",
-        "libonce_cell_nostd",
         "libpvmfw_avb_nostd",
         "libpvmfw_embedded_key",
         "libpvmfw_fdt_template",
diff --git a/libs/debian_service/proto/DebianService.proto b/libs/debian_service/proto/DebianService.proto
index 5adf615..5e3286a 100644
--- a/libs/debian_service/proto/DebianService.proto
+++ b/libs/debian_service/proto/DebianService.proto
@@ -23,12 +23,20 @@
 
 service DebianService {
   rpc ReportVmIpAddr (IpAddr) returns (ReportVmIpAddrResponse) {}
+  rpc OpenForwardingRequestQueue (Empty) returns (stream ForwardingRequestItem) {}
 }
 
+message Empty {}
+
 message IpAddr {
   string addr = 1;
 }
 
 message ReportVmIpAddrResponse {
-    bool success = 1;
-}
\ No newline at end of file
+  bool success = 1;
+}
+
+message ForwardingRequestItem {
+  int32 guest_tcp_port = 1;
+  int32 vsock_port = 2;
+}
diff --git a/libs/dice/driver/Android.bp b/libs/dice/driver/Android.bp
index c93bd7d..baed21d 100644
--- a/libs/dice/driver/Android.bp
+++ b/libs/dice/driver/Android.bp
@@ -22,7 +22,6 @@
         "liblibc",
         "liblog_rust",
         "libnix",
-        "libonce_cell",
         "libopenssl",
         "libthiserror",
         "libserde_cbor",
diff --git a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
index 2f7666a..ccc0ed6 100644
--- a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
+++ b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
@@ -19,6 +19,8 @@
 import android.util.Log;
 
 import com.android.virtualization.vmlauncher.proto.DebianServiceGrpc;
+import com.android.virtualization.vmlauncher.proto.Empty;
+import com.android.virtualization.vmlauncher.proto.ForwardingRequestItem;
 import com.android.virtualization.vmlauncher.proto.IpAddr;
 import com.android.virtualization.vmlauncher.proto.ReportVmIpAddrResponse;
 
@@ -43,6 +45,16 @@
         responseObserver.onCompleted();
     }
 
+    @Override
+    public void openForwardingRequestQueue(
+            Empty request, StreamObserver<ForwardingRequestItem> responseObserver) {
+        Log.d(DebianServiceImpl.TAG, "OpenForwardingRequestQueue");
+
+        // TODO(b/340126051): Bring information from forwarder_host.
+
+        responseObserver.onCompleted();
+    }
+
     protected interface DebianServiceCallback {
         void onIpAddressAvailable(String ipAddr);
     }