Merge "Add tap and settings intent for the terminal notification" into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
index 7256015..95bcbbc 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
@@ -15,18 +15,49 @@
*/
package com.android.virtualization.terminal
+import android.content.Intent
import android.os.Bundle
-import android.widget.Toast
+import android.util.Log
import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
+import com.android.virtualization.vmlauncher.InstallUtils
import com.google.android.material.card.MaterialCardView
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import java.io.IOException
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+const val TAG: String = "VmTerminalApp"
class SettingsRecoveryActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.settings_recovery)
val resetCard = findViewById<MaterialCardView>(R.id.settings_recovery_reset_card)
+ val dialog = MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.settings_recovery_reset_dialog_title)
+ .setMessage(R.string.settings_recovery_reset_dialog_message)
+ .setPositiveButton(R.string.settings_recovery_reset_dialog_confirm) { _, _ ->
+ // This coroutine will be killed when the activity is killed. The behavior is both acceptable
+ // either removing is done or not
+ lifecycleScope.launch(Dispatchers.IO) {
+ try {
+ InstallUtils.unInstall(this@SettingsRecoveryActivity)
+ // Restart terminal
+ val intent =
+ baseContext.packageManager.getLaunchIntentForPackage(baseContext.packageName)
+ intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ finish()
+ startActivity(intent)
+ } catch (e: IOException) {
+ Log.e(TAG, "VM image reset failed.")
+ }
+ }
+ }
+ .setNegativeButton(R.string.settings_recovery_reset_dialog_cancel) { dialog, _ -> dialog.dismiss() }
+ .create()
resetCard.setOnClickListener {
- Toast.makeText(this@SettingsRecoveryActivity, R.string.settings_recovery_reset_message, Toast.LENGTH_SHORT).show()
+ dialog.show()
}
}
}
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index 070807c..ca803ec 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -87,8 +87,14 @@
<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>
+ <!-- Dialog title for restarting the terminal [CHAR LIMIT=none] -->
+ <string name="settings_recovery_reset_dialog_title">Reset the virtual machine</string>
+ <!-- Dialog message for restarting the terminal [CHAR LIMIT=none] -->
+ <string name="settings_recovery_reset_dialog_message">Data will be deleted.</string>
+ <!-- Dialog button confirm for restarting the terminal [CHAR LIMIT=16] -->
+ <string name="settings_recovery_reset_dialog_confirm">Confirm</string>
+ <!-- Dialog button cancel for restarting the terminal [CHAR LIMIT=16] -->
+ <string name="settings_recovery_reset_dialog_cancel">Cancel</string>
<!-- Notification action button for settings [CHAR LIMIT=none] -->
<string name="service_notification_settings">Settings</string>
diff --git a/build/debian/build.sh b/build/debian/build.sh
index 5829ecc..b4436c1 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -104,6 +104,7 @@
source "$HOME"/.cargo/env
rustup target add "${arch}"-unknown-linux-gnu
+ cargo install cargo-license
}
download_debian_cloud_image() {
@@ -124,6 +125,9 @@
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"
+
+ mkdir -p "${dst}/files/usr/share/doc/$1"
+ cargo license > "${dst}/files/usr/share/doc/$1/copyright"
popd > /dev/null
}
@@ -140,6 +144,8 @@
mkdir -p "${dst}/files/usr/local/bin/ttyd"
cp /tmp/stage/${arch}-linux-musl/bin/ttyd "${dst}/files/usr/local/bin/ttyd/AVF"
chmod 777 "${dst}/files/usr/local/bin/ttyd/AVF"
+ mkdir -p "${dst}/files/usr/share/doc/ttyd"
+ cp LICENSE "${dst}/files/usr/share/doc/ttyd/copyright"
popd > /dev/null
popd > /dev/null
}
diff --git a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF b/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
index 251f88c..4c1b2f5 100644
--- a/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
+++ b/build/debian/fai_config/files/etc/systemd/system/forwarder_guest_launcher.service/AVF
@@ -2,8 +2,9 @@
Description=Port forwarding service in guest VM
After=syslog.target
After=network.target
+After=virtiofs_internal.service
[Service]
-ExecStart=/usr/local/bin/forwarder_guest_launcher --host 192.168.0.1
+ExecStart=/usr/local/bin/forwarder_guest_launcher --host 192.168.0.1 --grpc_port $(cat /mnt/internal/debian_service_port)
Type=simple
Restart=on-failure
RestartSec=1
diff --git a/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF b/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF
index 7d163fb..81347a7 100644
--- a/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF
+++ b/build/debian/fai_config/files/etc/systemd/system/ip_addr_reporter.service/AVF
@@ -3,8 +3,9 @@
After=syslog.target
After=network.target
Requires=ttyd.service
+After=virtiofs_internal.service
[Service]
-ExecStart=/usr/local/bin/ip_addr_reporter
+ExecStart=/usr/local/bin/ip_addr_reporter --grpc_port $(cat /mnt/internal/debian_service_port)
Type=simple
Restart=on-failure
User=root
diff --git a/guest/forwarder_guest/Cargo.toml b/guest/forwarder_guest/Cargo.toml
index 65f57cf..ce50e4c 100644
--- a/guest/forwarder_guest/Cargo.toml
+++ b/guest/forwarder_guest/Cargo.toml
@@ -2,6 +2,7 @@
name = "forwarder_guest"
version = "0.1.0"
edition = "2021"
+license = "Apache-2.0"
[dependencies]
clap = { version = "4.5.19", features = ["derive"] }
diff --git a/guest/forwarder_guest_launcher/Cargo.toml b/guest/forwarder_guest_launcher/Cargo.toml
index 03d3f7f..b7f9eaf 100644
--- a/guest/forwarder_guest_launcher/Cargo.toml
+++ b/guest/forwarder_guest_launcher/Cargo.toml
@@ -2,6 +2,7 @@
name = "forwarder_guest_launcher"
version = "0.1.0"
edition = "2021"
+license = "Apache-2.0"
[dependencies]
anyhow = "1.0.91"
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
index 59ee8c6..d753d19 100644
--- a/guest/forwarder_guest_launcher/src/main.rs
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -33,13 +33,17 @@
#[arg(long)]
#[arg(alias = "host")]
host_addr: String,
+ /// grpc port number
+ #[arg(long)]
+ #[arg(alias = "grpc_port")]
+ grpc_port: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Starting forwarder_guest_launcher");
let args = Args::parse();
- let addr = format!("https://{}:12000", args.host_addr);
+ let addr = format!("https://{}:{}", args.host_addr, args.grpc_port);
let channel = Endpoint::from_shared(addr)?.connect().await?;
let mut client = DebianServiceClient::new(channel);
diff --git a/guest/ip_addr_reporter/Cargo.toml b/guest/ip_addr_reporter/Cargo.toml
index e255eaf..7592e3f 100644
--- a/guest/ip_addr_reporter/Cargo.toml
+++ b/guest/ip_addr_reporter/Cargo.toml
@@ -2,8 +2,10 @@
name = "ip_addr_reporter"
version = "0.1.0"
edition = "2021"
+license = "Apache-2.0"
[dependencies]
+clap = { version = "4.5.20", features = ["derive"] }
netdev = "0.31.0"
prost = "0.13.3"
tokio = { version = "1.40.0", features = ["rt-multi-thread"] }
diff --git a/guest/ip_addr_reporter/src/main.rs b/guest/ip_addr_reporter/src/main.rs
index 5784a83..2c782d3 100644
--- a/guest/ip_addr_reporter/src/main.rs
+++ b/guest/ip_addr_reporter/src/main.rs
@@ -1,17 +1,27 @@
use api::debian_service_client::DebianServiceClient;
use api::IpAddr;
+use clap::Parser;
pub mod api {
tonic::include_proto!("com.android.virtualization.vmlauncher.proto");
}
+#[derive(Parser)]
+/// Flags for running command
+pub struct Args {
+ /// grpc port number
+ #[arg(long)]
+ #[arg(alias = "grpc_port")]
+ grpc_port: String,
+}
+
#[tokio::main]
async fn main() -> Result<(), String> {
+ let args = Args::parse();
let gateway_ip_addr = netdev::get_default_gateway()?.ipv4[0];
let ip_addr = netdev::get_default_interface()?.ipv4[0].addr();
- const PORT: i32 = 12000;
- let server_addr = format!("http://{}:{}", gateway_ip_addr.to_string(), PORT);
+ let server_addr = format!("http://{}:{}", gateway_ip_addr.to_string(), args.grpc_port);
println!("local ip addr: {}", ip_addr.to_string());
println!("coonect to grpc server {}", server_addr);
diff --git a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java
index 1febe27..53dd677 100644
--- a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java
+++ b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/InstallUtils.java
@@ -49,6 +49,10 @@
return Files.exists(getInstallationCompletedPath(context));
}
+ public static void unInstall(Context context) throws IOException {
+ Files.delete(getInstallationCompletedPath(context));
+ }
+
public static boolean createInstalledMarker(Context context) {
try {
File file = new File(getInstallationCompletedPath(context).toString());
diff --git a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java
index 5cd7b92..f672b7b 100644
--- a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java
+++ b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java
@@ -27,11 +27,20 @@
import android.system.virtualmachine.VirtualMachineException;
import android.util.Log;
+import io.grpc.Grpc;
import io.grpc.InsecureServerCredentials;
+import io.grpc.Metadata;
import io.grpc.Server;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+import io.grpc.Status;
import io.grpc.okhttp.OkHttpServerBuilder;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
@@ -137,19 +146,54 @@
}
private void startDebianServer() {
+ ServerInterceptor interceptor =
+ new ServerInterceptor() {
+ @Override
+ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
+ ServerCall<ReqT, RespT> call,
+ Metadata headers,
+ ServerCallHandler<ReqT, RespT> next) {
+ // Refer to VirtualizationSystemService.TetheringService
+ final String VM_STATIC_IP_ADDR = "192.168.0.2";
+ InetSocketAddress remoteAddr =
+ (InetSocketAddress)
+ call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
+
+ if (remoteAddr != null
+ && Objects.equals(
+ remoteAddr.getAddress().getHostAddress(),
+ VM_STATIC_IP_ADDR)) {
+ // Allow the request only if it is from VM
+ return next.startCall(call, headers);
+ }
+ Log.d(TAG, "blocked grpc request from " + remoteAddr);
+ call.close(Status.Code.PERMISSION_DENIED.toStatus(), new Metadata());
+ return new ServerCall.Listener<ReqT>() {};
+ }
+ };
new Thread(
() -> {
- // TODO(b/372666638): gRPC for java doesn't support vsock for now.
- // In addition, let's consider using a dynamic port and SSL(and client
- // certificate)
- int port = 12000;
try {
+ // TODO(b/372666638): gRPC for java doesn't support vsock for now.
+ int port = 0;
mServer =
OkHttpServerBuilder.forPort(
port, InsecureServerCredentials.create())
+ .intercept(interceptor)
.addService(new DebianServiceImpl(this))
.build()
.start();
+
+ // TODO(b/373533555): we can use mDNS for that.
+ String debianServicePortFileName = "debian_service_port";
+ File debianServicePortFile =
+ new File(getFilesDir(), debianServicePortFileName);
+ try (FileOutputStream writer =
+ new FileOutputStream(debianServicePortFile)) {
+ writer.write(String.valueOf(mServer.getPort()).getBytes());
+ } catch (IOException e) {
+ Log.d(TAG, "cannot write grpc port number", e);
+ }
} catch (IOException e) {
Log.d(TAG, "grpc server error", e);
}