Merge "Annotate tests accordingly" into main
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.java
deleted file mode 100644
index aeae5dd..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.virtualization.terminal;
-
-import android.Manifest;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-public abstract class BaseActivity extends AppCompatActivity {
-    private static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        NotificationManager notificationManager = getSystemService(NotificationManager.class);
-        if (notificationManager.getNotificationChannel(this.getPackageName()) == null) {
-            NotificationChannel channel =
-                    new NotificationChannel(
-                            this.getPackageName(),
-                            getString(R.string.app_name),
-                            NotificationManager.IMPORTANCE_HIGH);
-            notificationManager.createNotificationChannel(channel);
-        }
-
-        if (!(this instanceof ErrorActivity)) {
-            Thread currentThread = Thread.currentThread();
-            if (!(currentThread.getUncaughtExceptionHandler()
-                    instanceof TerminalExceptionHandler)) {
-                currentThread.setUncaughtExceptionHandler(
-                        new TerminalExceptionHandler(getApplicationContext()));
-            }
-        }
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        if (getApplicationContext().checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)
-                != PackageManager.PERMISSION_GRANTED) {
-            requestPermissions(
-                    new String[] {Manifest.permission.POST_NOTIFICATIONS},
-                    POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE);
-        }
-    }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt
new file mode 100644
index 0000000..e7ac8d9
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/BaseActivity.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+package com.android.virtualization.terminal
+
+import android.Manifest
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.pm.PackageManager
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+
+abstract class BaseActivity : AppCompatActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        val notificationManager =
+            getSystemService<NotificationManager>(NotificationManager::class.java)
+        if (notificationManager.getNotificationChannel(this.packageName) == null) {
+            val channel =
+                NotificationChannel(
+                    this.packageName,
+                    getString(R.string.app_name),
+                    NotificationManager.IMPORTANCE_HIGH,
+                )
+            notificationManager.createNotificationChannel(channel)
+        }
+
+        if (this !is ErrorActivity) {
+            val currentThread = Thread.currentThread()
+            if (currentThread.uncaughtExceptionHandler !is TerminalExceptionHandler) {
+                currentThread.uncaughtExceptionHandler =
+                    TerminalExceptionHandler(applicationContext)
+            }
+        }
+    }
+
+    public override fun onResume() {
+        super.onResume()
+
+        if (
+            applicationContext.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) !=
+                PackageManager.PERMISSION_GRANTED
+        ) {
+            requestPermissions(
+                arrayOf<String>(Manifest.permission.POST_NOTIFICATIONS),
+                POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE,
+            )
+        }
+    }
+
+    companion object {
+        private const val POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101
+    }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.kt b/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.kt
index 53809e5..ee8a8f8 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/CertificateUtils.kt
@@ -39,7 +39,6 @@
 object CertificateUtils {
     private const val ALIAS = "ttyd"
 
-    @JvmStatic
     fun createOrGetKey(): KeyStore.PrivateKeyEntry {
         try {
             val ks = KeyStore.getInstance("AndroidKeyStore")
@@ -87,7 +86,6 @@
         kpg.generateKeyPair()
     }
 
-    @JvmStatic
     fun writeCertificateToFile(context: Context, cert: Certificate) {
         val certFile = File(context.getFilesDir(), "ca.crt")
         try {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
deleted file mode 100644
index a0fca82..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.virtualization.terminal;
-
-
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.Rect;
-import android.os.Environment;
-import android.system.virtualmachine.VirtualMachineConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.AudioConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.Disk;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.DisplayConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.GpuConfig;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.Partition;
-import android.system.virtualmachine.VirtualMachineCustomImageConfig.SharedPath;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-import android.view.WindowMetrics;
-
-import com.google.gson.Gson;
-import com.google.gson.annotations.SerializedName;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-/** This class and its inner classes model vm_config.json. */
-class ConfigJson {
-    private static final boolean DEBUG = true;
-
-    private ConfigJson() {}
-
-    @SerializedName("protected")
-    private boolean isProtected;
-
-    private String name;
-    private String cpu_topology;
-    private String platform_version;
-    private int memory_mib = 1024;
-    private String console_input_device;
-    private String bootloader;
-    private String kernel;
-    private String initrd;
-    private String params;
-    private boolean debuggable;
-    private boolean console_out;
-    private boolean connect_console;
-    private boolean network;
-    private InputJson input;
-    private AudioJson audio;
-    private DiskJson[] disks;
-    private SharedPathJson[] sharedPath;
-    private DisplayJson display;
-    private GpuJson gpu;
-    private boolean auto_memory_balloon;
-
-    /** Parses JSON file at jsonPath */
-    static ConfigJson from(Context context, Path jsonPath) {
-        try (FileReader fileReader = new FileReader(jsonPath.toFile())) {
-            String content = replaceKeywords(fileReader, context);
-            return new Gson().fromJson(content, ConfigJson.class);
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to parse " + jsonPath, e);
-        }
-    }
-
-    private static String replaceKeywords(Reader r, Context context) throws IOException {
-        Map<String, String> rules = new HashMap<>();
-        rules.put("\\$PAYLOAD_DIR", InstalledImage.getDefault(context).getInstallDir().toString());
-        rules.put("\\$USER_ID", String.valueOf(context.getUserId()));
-        rules.put("\\$PACKAGE_NAME", context.getPackageName());
-        rules.put("\\$APP_DATA_DIR", context.getDataDir().toString());
-
-        try (BufferedReader br = new BufferedReader(r)) {
-            return br.lines()
-                    .map(
-                            line -> {
-                                for (Map.Entry<String, String> rule : rules.entrySet()) {
-                                    line = line.replaceAll(rule.getKey(), rule.getValue());
-                                }
-                                return line;
-                            })
-                    .collect(Collectors.joining("\n"));
-        }
-    }
-
-    private int getCpuTopology() {
-        switch (cpu_topology) {
-            case "one_cpu":
-                return VirtualMachineConfig.CPU_TOPOLOGY_ONE_CPU;
-            case "match_host":
-                return VirtualMachineConfig.CPU_TOPOLOGY_MATCH_HOST;
-            default:
-                throw new RuntimeException("invalid cpu topology: " + cpu_topology);
-        }
-    }
-
-    private int getDebugLevel() {
-        return debuggable
-                ? VirtualMachineConfig.DEBUG_LEVEL_FULL
-                : VirtualMachineConfig.DEBUG_LEVEL_NONE;
-    }
-
-    /** Converts this parsed JSON into VirtualMachieConfig Builder */
-    VirtualMachineConfig.Builder toConfigBuilder(Context context) {
-        return new VirtualMachineConfig.Builder(context)
-                .setProtectedVm(isProtected)
-                .setMemoryBytes((long) memory_mib * 1024 * 1024)
-                .setConsoleInputDevice(console_input_device)
-                .setCpuTopology(getCpuTopology())
-                .setCustomImageConfig(toCustomImageConfigBuilder(context).build())
-                .setDebugLevel(getDebugLevel())
-                .setVmOutputCaptured(console_out)
-                .setConnectVmConsole(connect_console);
-    }
-
-    VirtualMachineCustomImageConfig.Builder toCustomImageConfigBuilder(Context context) {
-        VirtualMachineCustomImageConfig.Builder builder =
-                new VirtualMachineCustomImageConfig.Builder();
-
-        builder.setName(name)
-                .setBootloaderPath(bootloader)
-                .setKernelPath(kernel)
-                .setInitrdPath(initrd)
-                .useNetwork(network)
-                .useAutoMemoryBalloon(auto_memory_balloon);
-
-        if (input != null) {
-            builder.useTouch(input.touchscreen)
-                    .useKeyboard(input.keyboard)
-                    .useMouse(input.mouse)
-                    .useTrackpad(input.trackpad)
-                    .useSwitches(input.switches);
-        }
-
-        if (audio != null) {
-            builder.setAudioConfig(audio.toConfig());
-        }
-
-        if (display != null) {
-            builder.setDisplayConfig(display.toConfig(context));
-        }
-
-        if (gpu != null) {
-            builder.setGpuConfig(gpu.toConfig());
-        }
-
-        if (params != null) {
-            Arrays.stream(params.split(" ")).forEach(builder::addParam);
-        }
-
-        if (disks != null) {
-            Arrays.stream(disks).map(d -> d.toConfig()).forEach(builder::addDisk);
-        }
-
-        if (sharedPath != null) {
-            Arrays.stream(sharedPath)
-                    .map(d -> d.toConfig(context))
-                    .filter(Objects::nonNull)
-                    .forEach(builder::addSharedPath);
-        }
-        return builder;
-    }
-
-    private static class SharedPathJson {
-        private SharedPathJson() {}
-
-        private String sharedPath;
-        private static final int GUEST_UID = 1000;
-        private static final int GUEST_GID = 100;
-
-        private SharedPath toConfig(Context context) {
-            try {
-                int terminalUid = getTerminalUid(context);
-                if (sharedPath.contains("emulated")) {
-                    if (Environment.isExternalStorageManager()) {
-                        int currentUserId = context.getUserId();
-                        String path = sharedPath + "/" + currentUserId + "/Download";
-                        return new SharedPath(
-                                path,
-                                terminalUid,
-                                terminalUid,
-                                GUEST_UID,
-                                GUEST_GID,
-                                0007,
-                                "android",
-                                "android",
-                                false, /* app domain is set to false so that crosvm is spin up as child of virtmgr */
-                                "");
-                    }
-                    return null;
-                }
-                Path socketPath = context.getFilesDir().toPath().resolve("internal.virtiofs");
-                Files.deleteIfExists(socketPath);
-                return new SharedPath(
-                        sharedPath,
-                        terminalUid,
-                        terminalUid,
-                        0,
-                        0,
-                        0007,
-                        "internal",
-                        "internal",
-                        true, /* app domain is set to true so that crosvm is spin up from app context */
-                        socketPath.toString());
-            } catch (NameNotFoundException | IOException e) {
-                return null;
-            }
-        }
-
-        private int getTerminalUid(Context context) throws NameNotFoundException {
-            return context.getPackageManager()
-                    .getPackageUidAsUser(context.getPackageName(), context.getUserId());
-        }
-    }
-
-    private static class InputJson {
-        private InputJson() {}
-
-        private boolean touchscreen;
-        private boolean keyboard;
-        private boolean mouse;
-        private boolean switches;
-        private boolean trackpad;
-    }
-
-    private static class AudioJson {
-        private AudioJson() {}
-
-        private boolean microphone;
-        private boolean speaker;
-
-        private AudioConfig toConfig() {
-            return new AudioConfig.Builder()
-                    .setUseMicrophone(microphone)
-                    .setUseSpeaker(speaker)
-                    .build();
-        }
-    }
-
-    private static class DiskJson {
-        private DiskJson() {}
-
-        private boolean writable;
-        private String image;
-        private PartitionJson[] partitions;
-
-        private Disk toConfig() {
-            Disk d = writable ? Disk.RWDisk(image) : Disk.RODisk(image);
-            for (PartitionJson pj : partitions) {
-                boolean writable = this.writable && pj.writable;
-                d.addPartition(new Partition(pj.label, pj.path, writable, pj.guid));
-            }
-            return d;
-        }
-    }
-
-    private static class PartitionJson {
-        private PartitionJson() {}
-
-        private boolean writable;
-        private String label;
-        private String path;
-        private String guid;
-    }
-
-    private static class DisplayJson {
-        private DisplayJson() {}
-
-        private float scale;
-        private int refresh_rate;
-        private int width_pixels;
-        private int height_pixels;
-
-        private DisplayConfig toConfig(Context context) {
-            WindowManager wm = context.getSystemService(WindowManager.class);
-            WindowMetrics metrics = wm.getCurrentWindowMetrics();
-            Rect dispBounds = metrics.getBounds();
-
-            int width = width_pixels > 0 ? width_pixels : dispBounds.right;
-            int height = height_pixels > 0 ? height_pixels : dispBounds.bottom;
-
-            int dpi = (int) (DisplayMetrics.DENSITY_DEFAULT * metrics.getDensity());
-            if (scale > 0.0f) {
-                dpi = (int) (dpi * scale);
-            }
-
-            int refreshRate = (int) context.getDisplay().getRefreshRate();
-            if (this.refresh_rate != 0) {
-                refreshRate = this.refresh_rate;
-            }
-
-            return new DisplayConfig.Builder()
-                    .setWidth(width)
-                    .setHeight(height)
-                    .setHorizontalDpi(dpi)
-                    .setVerticalDpi(dpi)
-                    .setRefreshRate(refreshRate)
-                    .build();
-        }
-    }
-
-    private static class GpuJson {
-        private GpuJson() {}
-
-        private String backend;
-        private String pci_address;
-        private String renderer_features;
-        private boolean renderer_use_egl = true;
-        private boolean renderer_use_gles = true;
-        private boolean renderer_use_glx = false;
-        private boolean renderer_use_surfaceless = true;
-        private boolean renderer_use_vulkan = false;
-        private String[] context_types;
-
-        private GpuConfig toConfig() {
-            return new GpuConfig.Builder()
-                    .setBackend(backend)
-                    .setPciAddress(pci_address)
-                    .setRendererFeatures(renderer_features)
-                    .setRendererUseEgl(renderer_use_egl)
-                    .setRendererUseGles(renderer_use_gles)
-                    .setRendererUseGlx(renderer_use_glx)
-                    .setRendererUseSurfaceless(renderer_use_surfaceless)
-                    .setRendererUseVulkan(renderer_use_vulkan)
-                    .setContextTypes(context_types)
-                    .build();
-        }
-    }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.kt
new file mode 100644
index 0000000..1fd58cd
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.kt
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 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.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Environment
+import android.system.virtualmachine.VirtualMachineConfig
+import android.system.virtualmachine.VirtualMachineCustomImageConfig
+import android.util.DisplayMetrics
+import android.view.WindowManager
+import com.android.virtualization.terminal.ConfigJson.AudioJson
+import com.android.virtualization.terminal.ConfigJson.DiskJson
+import com.android.virtualization.terminal.ConfigJson.DisplayJson
+import com.android.virtualization.terminal.ConfigJson.GpuJson
+import com.android.virtualization.terminal.ConfigJson.InputJson
+import com.android.virtualization.terminal.ConfigJson.PartitionJson
+import com.android.virtualization.terminal.ConfigJson.SharedPathJson
+import com.android.virtualization.terminal.InstalledImage.Companion.getDefault
+import com.google.gson.Gson
+import com.google.gson.annotations.SerializedName
+import java.io.BufferedReader
+import java.io.FileReader
+import java.io.IOException
+import java.io.Reader
+import java.lang.Exception
+import java.lang.RuntimeException
+import java.nio.file.Files
+import java.nio.file.Path
+
+/** This class and its inner classes model vm_config.json. */
+internal data class ConfigJson(
+    @SerializedName("protected") private val isProtected: Boolean,
+    private val name: String?,
+    private val cpu_topology: String?,
+    private val platform_version: String?,
+    private val memory_mib: Int = 1024,
+    private val console_input_device: String?,
+    private val bootloader: String?,
+    private val kernel: String?,
+    private val initrd: String?,
+    private val params: String?,
+    private val debuggable: Boolean,
+    private val console_out: Boolean,
+    private val connect_console: Boolean,
+    private val network: Boolean,
+    private val input: InputJson?,
+    private val audio: AudioJson?,
+    private val disks: Array<DiskJson>?,
+    private val sharedPath: Array<SharedPathJson>?,
+    private val display: DisplayJson?,
+    private val gpu: GpuJson?,
+    private val auto_memory_balloon: Boolean,
+) {
+    private fun getCpuTopology(): Int {
+        return when (cpu_topology) {
+            "one_cpu" -> VirtualMachineConfig.CPU_TOPOLOGY_ONE_CPU
+            "match_host" -> VirtualMachineConfig.CPU_TOPOLOGY_MATCH_HOST
+            else -> throw RuntimeException("invalid cpu topology: $cpu_topology")
+        }
+    }
+
+    private fun getDebugLevel(): Int {
+        return if (debuggable) VirtualMachineConfig.DEBUG_LEVEL_FULL
+        else VirtualMachineConfig.DEBUG_LEVEL_NONE
+    }
+
+    /** Converts this parsed JSON into VirtualMachineConfig Builder */
+    fun toConfigBuilder(context: Context): VirtualMachineConfig.Builder {
+        return VirtualMachineConfig.Builder(context)
+            .setProtectedVm(isProtected)
+            .setMemoryBytes(memory_mib.toLong() * 1024 * 1024)
+            .setConsoleInputDevice(console_input_device)
+            .setCpuTopology(getCpuTopology())
+            .setCustomImageConfig(toCustomImageConfigBuilder(context).build())
+            .setDebugLevel(getDebugLevel())
+            .setVmOutputCaptured(console_out)
+            .setConnectVmConsole(connect_console)
+    }
+
+    fun toCustomImageConfigBuilder(context: Context): VirtualMachineCustomImageConfig.Builder {
+        val builder = VirtualMachineCustomImageConfig.Builder()
+
+        builder
+            .setName(name)
+            .setBootloaderPath(bootloader)
+            .setKernelPath(kernel)
+            .setInitrdPath(initrd)
+            .useNetwork(network)
+            .useAutoMemoryBalloon(auto_memory_balloon)
+
+        if (input != null) {
+            builder
+                .useTouch(input.touchscreen)
+                .useKeyboard(input.keyboard)
+                .useMouse(input.mouse)
+                .useTrackpad(input.trackpad)
+                .useSwitches(input.switches)
+        }
+
+        if (audio != null) {
+            builder.setAudioConfig(audio.toConfig())
+        }
+
+        if (display != null) {
+            builder.setDisplayConfig(display.toConfig(context))
+        }
+
+        if (gpu != null) {
+            builder.setGpuConfig(gpu.toConfig())
+        }
+
+        params?.split(" ".toRegex())?.filter { it.isNotEmpty() }?.forEach { builder.addParam(it) }
+
+        disks?.forEach { builder.addDisk(it.toConfig()) }
+
+        sharedPath?.mapNotNull { it.toConfig(context) }?.forEach { builder.addSharedPath(it) }
+
+        return builder
+    }
+
+    internal data class SharedPathJson(private val sharedPath: String?) {
+        fun toConfig(context: Context): VirtualMachineCustomImageConfig.SharedPath? {
+            try {
+                val terminalUid = getTerminalUid(context)
+                if (sharedPath?.contains("emulated") == true) {
+                    if (Environment.isExternalStorageManager()) {
+                        val currentUserId = context.userId
+                        val path = "$sharedPath/$currentUserId/Download"
+                        return VirtualMachineCustomImageConfig.SharedPath(
+                            path,
+                            terminalUid,
+                            terminalUid,
+                            GUEST_UID,
+                            GUEST_GID,
+                            7,
+                            "android",
+                            "android",
+                            false, /* app domain is set to false so that crosvm is spin up as child of virtmgr */
+                            "",
+                        )
+                    }
+                    return null
+                }
+                val socketPath = context.getFilesDir().toPath().resolve("internal.virtiofs")
+                Files.deleteIfExists(socketPath)
+                return VirtualMachineCustomImageConfig.SharedPath(
+                    sharedPath,
+                    terminalUid,
+                    terminalUid,
+                    0,
+                    0,
+                    7,
+                    "internal",
+                    "internal",
+                    true, /* app domain is set to true so that crosvm is spin up from app context */
+                    socketPath.toString(),
+                )
+            } catch (e: PackageManager.NameNotFoundException) {
+                return null
+            } catch (e: IOException) {
+                return null
+            }
+        }
+
+        @Throws(PackageManager.NameNotFoundException::class)
+        fun getTerminalUid(context: Context): Int {
+            return context
+                .getPackageManager()
+                .getPackageUidAsUser(context.getPackageName(), context.userId)
+        }
+
+        companion object {
+            private const val GUEST_UID = 1000
+            private const val GUEST_GID = 100
+        }
+    }
+
+    internal data class InputJson(
+        val touchscreen: Boolean,
+        val keyboard: Boolean,
+        val mouse: Boolean,
+        val switches: Boolean,
+        val trackpad: Boolean,
+    )
+
+    internal data class AudioJson(private val microphone: Boolean, private val speaker: Boolean) {
+
+        fun toConfig(): VirtualMachineCustomImageConfig.AudioConfig {
+            return VirtualMachineCustomImageConfig.AudioConfig.Builder()
+                .setUseMicrophone(microphone)
+                .setUseSpeaker(speaker)
+                .build()
+        }
+    }
+
+    internal data class DiskJson(
+        private val writable: Boolean,
+        private val image: String?,
+        private val partitions: Array<PartitionJson>?,
+    ) {
+        fun toConfig(): VirtualMachineCustomImageConfig.Disk {
+            val d =
+                if (writable) VirtualMachineCustomImageConfig.Disk.RWDisk(image)
+                else VirtualMachineCustomImageConfig.Disk.RODisk(image)
+            partitions?.forEach {
+                val writable = this.writable && it.writable
+                d.addPartition(
+                    VirtualMachineCustomImageConfig.Partition(it.label, it.path, writable, it.guid)
+                )
+            }
+            return d
+        }
+    }
+
+    internal data class PartitionJson(
+        val writable: Boolean,
+        val label: String?,
+        val path: String?,
+        val guid: String?,
+    )
+
+    internal data class DisplayJson(
+        private val scale: Float = 0f,
+        private val refresh_rate: Int = 0,
+        private val width_pixels: Int = 0,
+        private val height_pixels: Int = 0,
+    ) {
+        fun toConfig(context: Context): VirtualMachineCustomImageConfig.DisplayConfig {
+            val wm = context.getSystemService<WindowManager>(WindowManager::class.java)
+            val metrics = wm.currentWindowMetrics
+            val dispBounds = metrics.bounds
+
+            val width = if (width_pixels > 0) width_pixels else dispBounds.right
+            val height = if (height_pixels > 0) height_pixels else dispBounds.bottom
+
+            var dpi = (DisplayMetrics.DENSITY_DEFAULT * metrics.density).toInt()
+            if (scale > 0.0f) {
+                dpi = (dpi * scale).toInt()
+            }
+
+            var refreshRate = context.display.refreshRate.toInt()
+            if (this.refresh_rate != 0) {
+                refreshRate = this.refresh_rate
+            }
+
+            return VirtualMachineCustomImageConfig.DisplayConfig.Builder()
+                .setWidth(width)
+                .setHeight(height)
+                .setHorizontalDpi(dpi)
+                .setVerticalDpi(dpi)
+                .setRefreshRate(refreshRate)
+                .build()
+        }
+    }
+
+    internal data class GpuJson(
+        private val backend: String?,
+        private val pci_address: String?,
+        private val renderer_features: String?,
+        // TODO: GSON actaully ignores the default values
+        private val renderer_use_egl: Boolean = true,
+        private val renderer_use_gles: Boolean = true,
+        private val renderer_use_glx: Boolean = false,
+        private val renderer_use_surfaceless: Boolean = true,
+        private val renderer_use_vulkan: Boolean = false,
+        private val context_types: Array<String>?,
+    ) {
+        fun toConfig(): VirtualMachineCustomImageConfig.GpuConfig {
+            return VirtualMachineCustomImageConfig.GpuConfig.Builder()
+                .setBackend(backend)
+                .setPciAddress(pci_address)
+                .setRendererFeatures(renderer_features)
+                .setRendererUseEgl(renderer_use_egl)
+                .setRendererUseGles(renderer_use_gles)
+                .setRendererUseGlx(renderer_use_glx)
+                .setRendererUseSurfaceless(renderer_use_surfaceless)
+                .setRendererUseVulkan(renderer_use_vulkan)
+                .setContextTypes(context_types)
+                .build()
+        }
+    }
+
+    companion object {
+        private const val DEBUG = true
+
+        /** Parses JSON file at jsonPath */
+        fun from(context: Context, jsonPath: Path): ConfigJson {
+            try {
+                FileReader(jsonPath.toFile()).use { fileReader ->
+                    val content = replaceKeywords(fileReader, context)
+                    return Gson().fromJson<ConfigJson?>(content, ConfigJson::class.java)
+                }
+            } catch (e: Exception) {
+                throw RuntimeException("Failed to parse $jsonPath", e)
+            }
+        }
+
+        @Throws(IOException::class)
+        private fun replaceKeywords(r: Reader, context: Context): String {
+            val rules: Map<String, String> =
+                mapOf(
+                    "\\\$PAYLOAD_DIR" to getDefault(context).installDir.toString(),
+                    "\\\$USER_ID" to context.userId.toString(),
+                    "\\\$PACKAGE_NAME" to context.getPackageName(),
+                    "\\\$APP_DATA_DIR" to context.getDataDir().toString(),
+                )
+
+            return BufferedReader(r).useLines { lines ->
+                lines
+                    .map { line ->
+                        rules.entries.fold(line) { acc, rule ->
+                            acc.replace(rule.key.toRegex(), rule.value)
+                        }
+                    }
+                    .joinToString("\n")
+            }
+        }
+    }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java
deleted file mode 100644
index 147a7e5..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.Keep;
-
-import com.android.virtualization.terminal.proto.DebianServiceGrpc;
-import com.android.virtualization.terminal.proto.ForwardingRequestItem;
-import com.android.virtualization.terminal.proto.QueueOpeningRequest;
-import com.android.virtualization.terminal.proto.ReportVmActivePortsRequest;
-import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse;
-import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest;
-import com.android.virtualization.terminal.proto.ShutdownRequestItem;
-
-import io.grpc.stub.StreamObserver;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-
-final class DebianServiceImpl extends DebianServiceGrpc.DebianServiceImplBase {
-    private final Context mContext;
-    private final PortsStateManager mPortsStateManager;
-    private PortsStateManager.Listener mPortsStateListener;
-    private Runnable mShutdownRunnable;
-
-    static {
-        System.loadLibrary("forwarder_host_jni");
-    }
-
-    DebianServiceImpl(Context context) {
-        super();
-        mContext = context;
-        mPortsStateManager = PortsStateManager.getInstance(mContext);
-    }
-
-    @Override
-    public void reportVmActivePorts(
-            ReportVmActivePortsRequest request,
-            StreamObserver<ReportVmActivePortsResponse> responseObserver) {
-        Log.d(TAG, "reportVmActivePorts: " + request.toString());
-        mPortsStateManager.updateActivePorts(
-                request.getPortsList().stream()
-                        .map(activePort -> activePort.getPort())
-                        .collect(Collectors.toSet()));
-        ReportVmActivePortsResponse reply =
-                ReportVmActivePortsResponse.newBuilder().setSuccess(true).build();
-        responseObserver.onNext(reply);
-        responseObserver.onCompleted();
-    }
-
-    @Override
-    public void openForwardingRequestQueue(
-            QueueOpeningRequest request, StreamObserver<ForwardingRequestItem> responseObserver) {
-        Log.d(TAG, "OpenForwardingRequestQueue");
-        mPortsStateListener =
-                new PortsStateManager.Listener() {
-                    @Override
-                    public void onPortsStateUpdated(
-                            Set<Integer> oldActivePorts, Set<Integer> newActivePorts) {
-                        updateListeningPorts();
-                    }
-                };
-        mPortsStateManager.registerListener(mPortsStateListener);
-        updateListeningPorts();
-        runForwarderHost(request.getCid(), new ForwarderHostCallback(responseObserver));
-        responseObserver.onCompleted();
-    }
-
-    public boolean shutdownDebian() {
-        if (mShutdownRunnable == null) {
-            Log.d(TAG, "mShutdownRunnable is not ready.");
-            return false;
-        }
-        mShutdownRunnable.run();
-        return true;
-    }
-
-    @Override
-    public void openShutdownRequestQueue(
-            ShutdownQueueOpeningRequest request,
-            StreamObserver<ShutdownRequestItem> responseObserver) {
-        Log.d(TAG, "openShutdownRequestQueue");
-        mShutdownRunnable =
-                () -> {
-                    responseObserver.onNext(ShutdownRequestItem.newBuilder().build());
-                    responseObserver.onCompleted();
-                    mShutdownRunnable = null;
-                };
-    }
-
-    @Keep
-    private static class ForwarderHostCallback {
-        private StreamObserver<ForwardingRequestItem> mResponseObserver;
-
-        ForwarderHostCallback(StreamObserver<ForwardingRequestItem> responseObserver) {
-            mResponseObserver = responseObserver;
-        }
-
-        private void onForwardingRequestReceived(int guestTcpPort, int vsockPort) {
-            ForwardingRequestItem item =
-                    ForwardingRequestItem.newBuilder()
-                            .setGuestTcpPort(guestTcpPort)
-                            .setVsockPort(vsockPort)
-                            .build();
-            mResponseObserver.onNext(item);
-        }
-    }
-
-    private static native void runForwarderHost(int cid, ForwarderHostCallback callback);
-
-    private static native void terminateForwarderHost();
-
-    void killForwarderHost() {
-        Log.d(TAG, "Stopping port forwarding");
-        if (mPortsStateListener != null) {
-            mPortsStateManager.unregisterListener(mPortsStateListener);
-            mPortsStateListener = null;
-        }
-        terminateForwarderHost();
-    }
-
-    private static native void updateListeningPorts(int[] ports);
-
-    private void updateListeningPorts() {
-        Set<Integer> activePorts = mPortsStateManager.getActivePorts();
-        Set<Integer> enabledPorts = mPortsStateManager.getEnabledPorts();
-        updateListeningPorts(
-                activePorts.stream()
-                        .filter(port -> enabledPorts.contains(port))
-                        .mapToInt(Integer::intValue)
-                        .toArray());
-    }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
new file mode 100644
index 0000000..887ae02
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/DebianServiceImpl.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 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.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import android.util.Log
+import androidx.annotation.Keep
+import com.android.virtualization.terminal.DebianServiceImpl.ForwarderHostCallback
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import com.android.virtualization.terminal.PortsStateManager.Companion.getInstance
+import com.android.virtualization.terminal.proto.DebianServiceGrpc.DebianServiceImplBase
+import com.android.virtualization.terminal.proto.ForwardingRequestItem
+import com.android.virtualization.terminal.proto.QueueOpeningRequest
+import com.android.virtualization.terminal.proto.ReportVmActivePortsRequest
+import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse
+import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest
+import com.android.virtualization.terminal.proto.ShutdownRequestItem
+import io.grpc.stub.StreamObserver
+
+internal class DebianServiceImpl(context: Context) : DebianServiceImplBase() {
+    private val portsStateManager: PortsStateManager = getInstance(context)
+    private var portsStateListener: PortsStateManager.Listener? = null
+    private var shutdownRunnable: Runnable? = null
+
+    override fun reportVmActivePorts(
+        request: ReportVmActivePortsRequest,
+        responseObserver: StreamObserver<ReportVmActivePortsResponse?>,
+    ) {
+        portsStateManager.updateActivePorts(request.portsList)
+        Log.d(TAG, "reportVmActivePorts: " + portsStateManager.getActivePorts())
+        val reply = ReportVmActivePortsResponse.newBuilder().setSuccess(true).build()
+        responseObserver.onNext(reply)
+        responseObserver.onCompleted()
+    }
+
+    override fun openForwardingRequestQueue(
+        request: QueueOpeningRequest,
+        responseObserver: StreamObserver<ForwardingRequestItem?>,
+    ) {
+        Log.d(TAG, "OpenForwardingRequestQueue")
+        portsStateListener =
+            object : PortsStateManager.Listener {
+                override fun onPortsStateUpdated(
+                    oldActivePorts: Set<Int>,
+                    newActivePorts: Set<Int>,
+                ) {
+                    updateListeningPorts()
+                }
+            }
+        portsStateManager.registerListener(portsStateListener!!)
+        updateListeningPorts()
+        runForwarderHost(request.cid, ForwarderHostCallback(responseObserver))
+        responseObserver.onCompleted()
+    }
+
+    fun shutdownDebian(): Boolean {
+        if (shutdownRunnable == null) {
+            Log.d(TAG, "mShutdownRunnable is not ready.")
+            return false
+        }
+        shutdownRunnable!!.run()
+        return true
+    }
+
+    override fun openShutdownRequestQueue(
+        request: ShutdownQueueOpeningRequest?,
+        responseObserver: StreamObserver<ShutdownRequestItem?>,
+    ) {
+        Log.d(TAG, "openShutdownRequestQueue")
+        shutdownRunnable = Runnable {
+            responseObserver.onNext(ShutdownRequestItem.newBuilder().build())
+            responseObserver.onCompleted()
+            shutdownRunnable = null
+        }
+    }
+
+    @Keep
+    private class ForwarderHostCallback(
+        private val responseObserver: StreamObserver<ForwardingRequestItem?>
+    ) {
+
+        fun onForwardingRequestReceived(guestTcpPort: Int, vsockPort: Int) {
+            val item =
+                ForwardingRequestItem.newBuilder()
+                    .setGuestTcpPort(guestTcpPort)
+                    .setVsockPort(vsockPort)
+                    .build()
+            responseObserver.onNext(item)
+        }
+    }
+
+    fun killForwarderHost() {
+        Log.d(TAG, "Stopping port forwarding")
+        if (portsStateListener != null) {
+            portsStateManager.unregisterListener(portsStateListener!!)
+            portsStateListener = null
+        }
+        terminateForwarderHost()
+    }
+
+    private fun updateListeningPorts() {
+        val activePorts: Set<Int> = portsStateManager.getActivePorts()
+        val enabledPorts: Set<Int> = portsStateManager.getEnabledPorts()
+        updateListeningPorts(activePorts.filter { enabledPorts.contains(it) }.toIntArray())
+    }
+
+    companion object {
+        init {
+            System.loadLibrary("forwarder_host_jni")
+        }
+
+        @JvmStatic private external fun runForwarderHost(cid: Int, callback: ForwarderHostCallback?)
+
+        @JvmStatic private external fun terminateForwarderHost()
+
+        @JvmStatic private external fun updateListeningPorts(ports: IntArray?)
+    }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
index f253f86..0a1090d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ErrorActivity.kt
@@ -58,7 +58,6 @@
     companion object {
         private const val EXTRA_CAUSE = "cause"
 
-        @JvmStatic
         fun start(context: Context, e: Exception) {
             val intent = Intent(context, ErrorActivity::class.java)
             intent.putExtra(EXTRA_CAUSE, e)
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
index 31c9a91..017ff89 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.kt
@@ -18,7 +18,7 @@
 import android.os.Build
 import android.os.Environment
 import android.util.Log
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import java.io.BufferedInputStream
 import java.io.FileInputStream
 import java.io.IOException
@@ -141,7 +141,6 @@
         private const val BUILD_TAG = "latest" // TODO: use actual tag name
         private const val HOST_URL = "https://dl.google.com/android/ferrochrome/$BUILD_TAG"
 
-        @JvmStatic
         fun getSdcardPathForTesting(): Path {
             return Environment.getExternalStoragePublicDirectory(DIR_IN_SDCARD).toPath()
         }
@@ -149,7 +148,6 @@
         /**
          * Creates ImageArchive which is located in the sdcard. This archive is for testing only.
          */
-        @JvmStatic
         fun fromSdCard(): ImageArchive {
             return ImageArchive(getSdcardPathForTesting().resolve(ARCHIVE_NAME))
         }
@@ -157,7 +155,6 @@
         /**
          * Creates ImageArchive which is hosted in the Google server. This is the official archive.
          */
-        @JvmStatic
         fun fromInternet(): ImageArchive {
             val arch =
                 if (listOf<String?>(*Build.SUPPORTED_ABIS).contains("x86_64")) "x86_64"
@@ -174,7 +171,6 @@
          * Creates ImageArchive from either SdCard or Internet. SdCard is used only when the build
          * is debuggable and the file actually exists.
          */
-        @JvmStatic
         fun getDefault(): ImageArchive {
             val archive = fromSdCard()
             return if (Build.isDebuggable() && archive.exists()) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.kt
index e52f996..7acc5f3 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstalledImage.kt
@@ -20,7 +20,7 @@
 import android.system.ErrnoException
 import android.system.Os
 import android.util.Log
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import java.io.BufferedReader
 import java.io.FileReader
 import java.io.IOException
@@ -34,7 +34,7 @@
 import kotlin.math.ceil
 
 /** Collection of files that consist of a VM image. */
-internal class InstalledImage private constructor(val installDir: Path) {
+public class InstalledImage private constructor(val installDir: Path) {
     private val rootPartition: Path = installDir.resolve(ROOTFS_FILENAME)
     val backupFile: Path = installDir.resolve(BACKUP_FILENAME)
 
@@ -95,13 +95,20 @@
         runE2fsck(rootPartition)
         val p: String = rootPartition.toAbsolutePath().toString()
         val result = runCommand("/system/bin/resize2fs", "-P", p)
-        // The return value is the number of 4k block
-        return try {
-            roundUp(result.lines().first().substring(42).toLong() * 4 * 1024)
-        } catch (e: NumberFormatException) {
-            Log.e(TAG, "Failed to parse min size, p=$p, result=$result")
-            throw IOException(e)
+        val regex = "Estimated minimum size of the filesystem: ([0-9]+)".toRegex()
+        val matchResult = result.lines().firstNotNullOfOrNull { regex.find(it) }
+        if (matchResult != null) {
+            try {
+                val size = matchResult.groupValues[1].toLong()
+                // The return value is the number of 4k block
+                return roundUp(size * 4 * 1024)
+            } catch (e: NumberFormatException) {
+                // cannot happen
+            }
         }
+        val msg = "Failed to get min size, p=$p, result=$result"
+        Log.e(TAG, msg)
+        throw RuntimeException(msg)
     }
 
     @Throws(IOException::class)
@@ -132,7 +139,6 @@
         const val RESIZE_STEP_BYTES: Long = 4 shl 20 // 4 MiB
 
         /** Returns InstalledImage for a given app context */
-        @JvmStatic
         fun getDefault(context: Context): InstalledImage {
             val installDir = context.getFilesDir().toPath().resolve(INSTALL_DIRNAME)
             return InstalledImage(installDir)
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
deleted file mode 100644
index 1c62572..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.annotation.MainThread;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.FileUtils;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.text.format.Formatter;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.material.progressindicator.LinearProgressIndicator;
-import com.google.android.material.snackbar.Snackbar;
-
-import java.io.IOException;
-import java.lang.ref.WeakReference;
-
-public class InstallerActivity extends BaseActivity {
-    private static final long ESTIMATED_IMG_SIZE_BYTES = FileUtils.parseSize("550MB");
-
-    private CheckBox mWaitForWifiCheckbox;
-    private TextView mInstallButton;
-
-    private IInstallerService mService;
-    private ServiceConnection mInstallerServiceConnection;
-    private InstallProgressListener mInstallProgressListener;
-    private boolean mInstallRequested;
-    private ConditionVariable mInstallCompleted = new ConditionVariable();
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setResult(RESULT_CANCELED);
-
-        mInstallProgressListener = new InstallProgressListener(this);
-
-        setContentView(R.layout.activity_installer);
-        updateSizeEstimation(ESTIMATED_IMG_SIZE_BYTES);
-        measureImageSizeAndUpdateDescription();
-
-        mWaitForWifiCheckbox = (CheckBox) findViewById(R.id.installer_wait_for_wifi_checkbox);
-        mInstallButton = (TextView) findViewById(R.id.installer_install_button);
-
-        mInstallButton.setOnClickListener(
-                (event) -> {
-                    requestInstall();
-                });
-
-        Intent intent = new Intent(this, InstallerService.class);
-        mInstallerServiceConnection = new InstallerServiceConnection(this);
-        if (!bindService(intent, mInstallerServiceConnection, Context.BIND_AUTO_CREATE)) {
-            handleInternalError(new Exception("Failed to connect to installer service"));
-        }
-    }
-
-    private void updateSizeEstimation(long est) {
-        String desc =
-                getString(
-                        R.string.installer_desc_text_format,
-                        Formatter.formatShortFileSize(this, est));
-        runOnUiThread(
-                () -> {
-                    TextView view = (TextView) findViewById(R.id.installer_desc);
-                    view.setText(desc);
-                });
-    }
-
-    private void measureImageSizeAndUpdateDescription() {
-        new Thread(
-                        () -> {
-                            long est;
-                            try {
-                                est = ImageArchive.getDefault().getSize();
-                            } catch (IOException e) {
-                                Log.w(TAG, "Failed to measure image size.", e);
-                                return;
-                            }
-                            updateSizeEstimation(est);
-                        })
-                .start();
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        if (Build.isDebuggable() && ImageArchive.fromSdCard().exists()) {
-            showSnackbar("Auto installing", Snackbar.LENGTH_LONG);
-            requestInstall();
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        if (mInstallerServiceConnection != null) {
-            unbindService(mInstallerServiceConnection);
-            mInstallerServiceConnection = null;
-        }
-
-        super.onDestroy();
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BUTTON_START) {
-            requestInstall();
-            return true;
-        }
-        return super.onKeyUp(keyCode, event);
-    }
-
-    @VisibleForTesting
-    public boolean waitForInstallCompleted(long timeoutMillis) {
-        return mInstallCompleted.block(timeoutMillis);
-    }
-
-    private void showSnackbar(String message, int length) {
-        Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), message, length);
-        snackbar.setAnchorView(mWaitForWifiCheckbox);
-        snackbar.show();
-    }
-
-    public void handleInternalError(Exception e) {
-        if (Build.isDebuggable()) {
-            showSnackbar(
-                    e.getMessage() + ". File a bugreport to go/ferrochrome-bug",
-                    Snackbar.LENGTH_INDEFINITE);
-        }
-        Log.e(TAG, "Internal error", e);
-        finishWithResult(RESULT_CANCELED);
-    }
-
-    private void finishWithResult(int resultCode) {
-        if (resultCode == RESULT_OK) {
-            mInstallCompleted.open();
-        }
-        setResult(resultCode);
-        finish();
-    }
-
-    private void setInstallEnabled(boolean enable) {
-        mInstallButton.setEnabled(enable);
-        mWaitForWifiCheckbox.setEnabled(enable);
-        LinearProgressIndicator progressBar = findViewById(R.id.installer_progress);
-        if (enable) {
-            progressBar.setVisibility(View.INVISIBLE);
-        } else {
-            progressBar.setVisibility(View.VISIBLE);
-        }
-
-        int resId =
-                enable
-                        ? R.string.installer_install_button_enabled_text
-                        : R.string.installer_install_button_disabled_text;
-        mInstallButton.setText(getString(resId));
-    }
-
-    @MainThread
-    private void requestInstall() {
-        setInstallEnabled(/* enable= */ false);
-
-        if (mService != null) {
-            try {
-                mService.requestInstall(mWaitForWifiCheckbox.isChecked());
-            } catch (RemoteException e) {
-                handleInternalError(e);
-            }
-        } else {
-            Log.d(TAG, "requestInstall() is called, but not yet connected");
-            mInstallRequested = true;
-        }
-    }
-
-    @MainThread
-    public void handleInstallerServiceConnected() {
-        try {
-            mService.setProgressListener(mInstallProgressListener);
-            if (mService.isInstalled()) {
-                // Finishing this activity will trigger MainActivity::onResume(),
-                // and VM will be started from there.
-                finishWithResult(RESULT_OK);
-                return;
-            }
-
-            if (mInstallRequested) {
-                requestInstall();
-            } else if (mService.isInstalling()) {
-                setInstallEnabled(false);
-            }
-        } catch (RemoteException e) {
-            handleInternalError(e);
-        }
-    }
-
-    @MainThread
-    public void handleInstallerServiceDisconnected() {
-        handleInternalError(new Exception("InstallerService is destroyed while in use"));
-    }
-
-    @MainThread
-    private void handleInstallError(String displayText) {
-        showSnackbar(displayText, Snackbar.LENGTH_LONG);
-        setInstallEnabled(true);
-    }
-
-    private static class InstallProgressListener extends IInstallProgressListener.Stub {
-        private final WeakReference<InstallerActivity> mActivity;
-
-        InstallProgressListener(InstallerActivity activity) {
-            mActivity = new WeakReference<>(activity);
-        }
-
-        @Override
-        public void onCompleted() {
-            InstallerActivity activity = mActivity.get();
-            if (activity == null) {
-                // Ignore incoming connection or disconnection after activity is destroyed.
-                return;
-            }
-
-            // MainActivity will be resume and handle rest of progress.
-            activity.finishWithResult(RESULT_OK);
-        }
-
-        @Override
-        public void onError(String displayText) {
-            InstallerActivity context = mActivity.get();
-            if (context == null) {
-                // Ignore incoming connection or disconnection after activity is destroyed.
-                return;
-            }
-
-            context.runOnUiThread(
-                    () -> {
-                        InstallerActivity activity = mActivity.get();
-                        if (activity == null) {
-                            // Ignore incoming connection or disconnection after activity is
-                            // destroyed.
-                            return;
-                        }
-
-                        activity.handleInstallError(displayText);
-                    });
-        }
-    }
-
-    @MainThread
-    public static final class InstallerServiceConnection implements ServiceConnection {
-        private final WeakReference<InstallerActivity> mActivity;
-
-        InstallerServiceConnection(InstallerActivity activity) {
-            mActivity = new WeakReference<>(activity);
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            InstallerActivity activity = mActivity.get();
-            if (activity == null || activity.mInstallerServiceConnection == null) {
-                // Ignore incoming connection or disconnection after activity is destroyed.
-                return;
-            }
-            if (service == null) {
-                activity.handleInternalError(new Exception("service shouldn't be null"));
-            }
-
-            activity.mService = IInstallerService.Stub.asInterface(service);
-            activity.handleInstallerServiceConnected();
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            InstallerActivity activity = mActivity.get();
-            if (activity == null || activity.mInstallerServiceConnection == null) {
-                // Ignore incoming connection or disconnection after activity is destroyed.
-                return;
-            }
-
-            if (activity.mInstallerServiceConnection != null) {
-                activity.unbindService(activity.mInstallerServiceConnection);
-                activity.mInstallerServiceConnection = null;
-            }
-            activity.handleInstallerServiceDisconnected();
-        }
-    }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.kt
new file mode 100644
index 0000000..ec4a8c4
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.kt
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+package com.android.virtualization.terminal
+
+import android.annotation.MainThread
+import android.content.ComponentName
+import android.content.Intent
+import android.content.ServiceConnection
+import android.os.Build
+import android.os.Bundle
+import android.os.ConditionVariable
+import android.os.FileUtils
+import android.os.IBinder
+import android.os.RemoteException
+import android.text.format.Formatter
+import android.util.Log
+import android.view.KeyEvent
+import android.view.View
+import android.widget.CheckBox
+import android.widget.TextView
+import com.android.internal.annotations.VisibleForTesting
+import com.android.virtualization.terminal.ImageArchive.Companion.fromSdCard
+import com.android.virtualization.terminal.ImageArchive.Companion.getDefault
+import com.android.virtualization.terminal.InstallerActivity.InstallProgressListener
+import com.android.virtualization.terminal.InstallerActivity.InstallerServiceConnection
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import com.google.android.material.progressindicator.LinearProgressIndicator
+import com.google.android.material.snackbar.Snackbar
+import java.io.IOException
+import java.lang.Exception
+import java.lang.ref.WeakReference
+
+public class InstallerActivity : BaseActivity() {
+    private lateinit var waitForWifiCheckbox: CheckBox
+    private lateinit var installButton: TextView
+
+    private var service: IInstallerService? = null
+    private var installerServiceConnection: ServiceConnection? = null
+    private lateinit var installProgressListener: InstallProgressListener
+    private var installRequested = false
+    private val installCompleted = ConditionVariable()
+
+    public override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setResult(RESULT_CANCELED)
+
+        installProgressListener = InstallProgressListener(this)
+
+        setContentView(R.layout.activity_installer)
+        updateSizeEstimation(ESTIMATED_IMG_SIZE_BYTES)
+        measureImageSizeAndUpdateDescription()
+
+        waitForWifiCheckbox = findViewById<CheckBox>(R.id.installer_wait_for_wifi_checkbox)
+        installButton = findViewById<TextView>(R.id.installer_install_button)
+
+        installButton.setOnClickListener(View.OnClickListener { requestInstall() })
+
+        val intent = Intent(this, InstallerService::class.java)
+        installerServiceConnection = InstallerServiceConnection(this)
+        if (!bindService(intent, installerServiceConnection!!, BIND_AUTO_CREATE)) {
+            handleInternalError(Exception("Failed to connect to installer service"))
+        }
+    }
+
+    private fun updateSizeEstimation(est: Long) {
+        val desc =
+            getString(R.string.installer_desc_text_format, Formatter.formatShortFileSize(this, est))
+        runOnUiThread {
+            val view = findViewById<TextView>(R.id.installer_desc)
+            view.text = desc
+        }
+    }
+
+    private fun measureImageSizeAndUpdateDescription() {
+        Thread {
+                val est: Long =
+                    try {
+                        getDefault().getSize()
+                    } catch (e: IOException) {
+                        Log.w(TAG, "Failed to measure image size.", e)
+                        return@Thread
+                    }
+                updateSizeEstimation(est)
+            }
+            .start()
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        if (Build.isDebuggable() && fromSdCard().exists()) {
+            showSnackBar("Auto installing", Snackbar.LENGTH_LONG)
+            requestInstall()
+        }
+    }
+
+    public override fun onDestroy() {
+        if (installerServiceConnection != null) {
+            unbindService(installerServiceConnection!!)
+            installerServiceConnection = null
+        }
+
+        super.onDestroy()
+    }
+
+    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
+        if (keyCode == KeyEvent.KEYCODE_BUTTON_START) {
+            requestInstall()
+            return true
+        }
+        return super.onKeyUp(keyCode, event)
+    }
+
+    @VisibleForTesting
+    public fun waitForInstallCompleted(timeoutMillis: Long): Boolean {
+        return installCompleted.block(timeoutMillis)
+    }
+
+    private fun showSnackBar(message: String, length: Int) {
+        val snackBar = Snackbar.make(findViewById<View>(android.R.id.content), message, length)
+        snackBar.anchorView = waitForWifiCheckbox
+        snackBar.show()
+    }
+
+    fun handleInternalError(e: Exception) {
+        if (Build.isDebuggable()) {
+            showSnackBar(
+                e.message + ". File a bugreport to go/ferrochrome-bug",
+                Snackbar.LENGTH_INDEFINITE,
+            )
+        }
+        Log.e(TAG, "Internal error", e)
+        finishWithResult(RESULT_CANCELED)
+    }
+
+    private fun finishWithResult(resultCode: Int) {
+        if (resultCode == RESULT_OK) {
+            installCompleted.open()
+        }
+        setResult(resultCode)
+        finish()
+    }
+
+    private fun setInstallEnabled(enabled: Boolean) {
+        installButton.setEnabled(enabled)
+        waitForWifiCheckbox.setEnabled(enabled)
+        val progressBar = findViewById<LinearProgressIndicator>(R.id.installer_progress)
+        progressBar.visibility = if (enabled) View.INVISIBLE else View.VISIBLE
+
+        val resId =
+            if (enabled) R.string.installer_install_button_enabled_text
+            else R.string.installer_install_button_disabled_text
+        installButton.text = getString(resId)
+    }
+
+    @MainThread
+    private fun requestInstall() {
+        setInstallEnabled(/* enabled= */ false)
+
+        if (service != null) {
+            try {
+                service!!.requestInstall(waitForWifiCheckbox.isChecked)
+            } catch (e: RemoteException) {
+                handleInternalError(e)
+            }
+        } else {
+            Log.d(TAG, "requestInstall() is called, but not yet connected")
+            installRequested = true
+        }
+    }
+
+    @MainThread
+    fun handleInstallerServiceConnected() {
+        try {
+            service!!.setProgressListener(installProgressListener)
+            if (service!!.isInstalled()) {
+                // Finishing this activity will trigger MainActivity::onResume(),
+                // and VM will be started from there.
+                finishWithResult(RESULT_OK)
+                return
+            }
+
+            if (installRequested) {
+                requestInstall()
+            } else if (service!!.isInstalling()) {
+                setInstallEnabled(false)
+            }
+        } catch (e: RemoteException) {
+            handleInternalError(e)
+        }
+    }
+
+    @MainThread
+    fun handleInstallerServiceDisconnected() {
+        handleInternalError(Exception("InstallerService is destroyed while in use"))
+    }
+
+    @MainThread
+    private fun handleInstallError(displayText: String) {
+        showSnackBar(displayText, Snackbar.LENGTH_LONG)
+        setInstallEnabled(true)
+    }
+
+    private class InstallProgressListener(activity: InstallerActivity) :
+        IInstallProgressListener.Stub() {
+        private val activity: WeakReference<InstallerActivity> =
+            WeakReference<InstallerActivity>(activity)
+
+        override fun onCompleted() {
+            val activity = activity.get()
+            if (activity == null) {
+                // Ignore incoming connection or disconnection after activity is destroyed.
+                return
+            }
+
+            // MainActivity will be resume and handle rest of progress.
+            activity.finishWithResult(RESULT_OK)
+        }
+
+        override fun onError(displayText: String) {
+            val context = activity.get()
+            if (context == null) {
+                // Ignore incoming connection or disconnection after activity is destroyed.
+                return
+            }
+
+            context.runOnUiThread {
+                val activity = activity.get()
+                if (activity == null) {
+                    // Ignore incoming connection or disconnection after activity is
+                    // destroyed.
+                    return@runOnUiThread
+                }
+                activity.handleInstallError(displayText)
+            }
+        }
+    }
+
+    @MainThread
+    class InstallerServiceConnection internal constructor(activity: InstallerActivity) :
+        ServiceConnection {
+        private val activity: WeakReference<InstallerActivity> =
+            WeakReference<InstallerActivity>(activity)
+
+        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
+            val activity = activity.get()
+            if (activity == null || activity.installerServiceConnection == null) {
+                // Ignore incoming connection or disconnection after activity is destroyed.
+                return
+            }
+            if (service == null) {
+                activity.handleInternalError(Exception("service shouldn't be null"))
+            }
+
+            activity.service = IInstallerService.Stub.asInterface(service)
+            activity.handleInstallerServiceConnected()
+        }
+
+        override fun onServiceDisconnected(name: ComponentName?) {
+            val activity = activity.get()
+            if (activity == null || activity.installerServiceConnection == null) {
+                // Ignore incoming connection or disconnection after activity is destroyed.
+                return
+            }
+
+            activity.unbindService(activity.installerServiceConnection!!)
+            activity.installerServiceConnection = null
+            activity.handleInstallerServiceDisconnected()
+        }
+    }
+
+    companion object {
+        private val ESTIMATED_IMG_SIZE_BYTES = FileUtils.parseSize("550MB")
+    }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
deleted file mode 100644
index 66ab414..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.virtualization.terminal;
-
-import static com.android.virtualization.terminal.MainActivity.TAG;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.ServiceInfo;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.os.Build;
-import android.os.IBinder;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.ref.WeakReference;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.file.Path;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class InstallerService extends Service {
-    private static final int NOTIFICATION_ID = 1313; // any unique number among notifications
-
-    private final Object mLock = new Object();
-
-    private Notification mNotification;
-
-    @GuardedBy("mLock")
-    private boolean mIsInstalling;
-
-    @GuardedBy("mLock")
-    private boolean mHasWifi;
-
-    @GuardedBy("mLock")
-    private IInstallProgressListener mListener;
-
-    private ExecutorService mExecutorService;
-    private ConnectivityManager mConnectivityManager;
-    private MyNetworkCallback mNetworkCallback;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-
-        Intent intent = new Intent(this, MainActivity.class);
-        PendingIntent pendingIntent =
-                PendingIntent.getActivity(
-                        this, /* requestCode= */ 0, intent, PendingIntent.FLAG_IMMUTABLE);
-        mNotification =
-                new Notification.Builder(this, this.getPackageName())
-                        .setSilent(true)
-                        .setSmallIcon(R.drawable.ic_launcher_foreground)
-                        .setContentTitle(getString(R.string.installer_notif_title_text))
-                        .setContentText(getString(R.string.installer_notif_desc_text))
-                        .setOngoing(true)
-                        .setContentIntent(pendingIntent)
-                        .build();
-
-        mExecutorService =
-                Executors.newSingleThreadExecutor(
-                        new TerminalThreadFactory(getApplicationContext()));
-
-        mConnectivityManager = getSystemService(ConnectivityManager.class);
-        Network defaultNetwork = mConnectivityManager.getBoundNetworkForProcess();
-        if (defaultNetwork != null) {
-            NetworkCapabilities capability =
-                    mConnectivityManager.getNetworkCapabilities(defaultNetwork);
-            if (capability != null) {
-                mHasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
-            }
-        }
-        mNetworkCallback = new MyNetworkCallback();
-        mConnectivityManager.registerDefaultNetworkCallback(mNetworkCallback);
-    }
-
-    @Nullable
-    @Override
-    public IBinder onBind(Intent intent) {
-        return new InstallerServiceImpl(this);
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        super.onStartCommand(intent, flags, startId);
-
-        Log.d(TAG, "Starting service ...");
-
-        return START_STICKY;
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-
-        Log.d(TAG, "Service is destroyed");
-        if (mExecutorService != null) {
-            mExecutorService.shutdown();
-        }
-        mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
-    }
-
-    private void requestInstall(boolean isWifiOnly) {
-        synchronized (mLock) {
-            if (mIsInstalling) {
-                Log.i(TAG, "already installing..");
-                return;
-            } else {
-                Log.i(TAG, "installing..");
-                mIsInstalling = true;
-            }
-        }
-
-        // Make service to be long running, even after unbind() when InstallerActivity is destroyed
-        // The service will still be destroyed if task is remove.
-        startService(new Intent(this, InstallerService.class));
-        startForeground(
-                NOTIFICATION_ID, mNotification, ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
-
-        mExecutorService.execute(
-                () -> {
-                    boolean success = downloadFromSdcard() || downloadFromUrl(isWifiOnly);
-                    stopForeground(STOP_FOREGROUND_REMOVE);
-
-                    synchronized (mLock) {
-                        mIsInstalling = false;
-                    }
-                    if (success) {
-                        notifyCompleted();
-                    }
-                });
-    }
-
-    private boolean downloadFromSdcard() {
-        ImageArchive archive = ImageArchive.fromSdCard();
-
-        // Installing from sdcard is preferred, but only supported only in debuggable build.
-        if (Build.isDebuggable() && archive.exists()) {
-            Log.i(TAG, "trying to install /sdcard/linux/images.tar.gz");
-
-            Path dest = InstalledImage.getDefault(this).getInstallDir();
-            try {
-                archive.installTo(dest, null);
-                Log.i(TAG, "image is installed from /sdcard/linux/images.tar.gz");
-                return true;
-            } catch (IOException e) {
-                Log.i(TAG, "Failed to install /sdcard/linux/images.tar.gz", e);
-            }
-        } else {
-            Log.i(TAG, "Non-debuggable build doesn't support installation from /sdcard/linux");
-        }
-        return false;
-    }
-
-    private boolean checkForWifiOnly(boolean isWifiOnly) {
-        if (!isWifiOnly) {
-            return true;
-        }
-        synchronized (mLock) {
-            return mHasWifi;
-        }
-    }
-
-    // TODO(b/374015561): Support pause/resume download
-    private boolean downloadFromUrl(boolean isWifiOnly) {
-        if (!checkForWifiOnly(isWifiOnly)) {
-            Log.e(TAG, "Install isn't started because Wifi isn't available");
-            notifyError(getString(R.string.installer_error_no_wifi));
-            return false;
-        }
-
-        Path dest = InstalledImage.getDefault(this).getInstallDir();
-        try {
-            ImageArchive.fromInternet()
-                    .installTo(
-                            dest,
-                            is -> {
-                                WifiCheckInputStream filter = new WifiCheckInputStream(is);
-                                filter.setWifiOnly(isWifiOnly);
-                                return filter;
-                            });
-        } catch (WifiCheckInputStream.NoWifiException e) {
-            Log.e(TAG, "Install failed because of Wi-Fi is gone");
-            notifyError(getString(R.string.installer_error_no_wifi));
-            return false;
-        } catch (UnknownHostException | SocketException e) {
-            // Log.e() doesn't print stack trace for UnknownHostException
-            Log.e(TAG, "Install failed: " + e.getMessage(), e);
-            notifyError(getString(R.string.installer_error_network));
-            return false;
-        } catch (IOException e) {
-            Log.e(TAG, "Installation failed", e);
-            notifyError(getString(R.string.installer_error_unknown));
-            return false;
-        }
-        return true;
-    }
-
-    private void notifyError(String displayText) {
-        IInstallProgressListener listener;
-        synchronized (mLock) {
-            listener = mListener;
-        }
-
-        try {
-            listener.onError(displayText);
-        } catch (Exception e) {
-            // ignore. Activity may not exist.
-        }
-    }
-
-    private void notifyCompleted() {
-        IInstallProgressListener listener;
-        synchronized (mLock) {
-            listener = mListener;
-        }
-
-        try {
-            listener.onCompleted();
-        } catch (Exception e) {
-            // ignore. Activity may not exist.
-        }
-    }
-
-    private static final class InstallerServiceImpl extends IInstallerService.Stub {
-        // Holds weak reference to avoid Context leak
-        private final WeakReference<InstallerService> mService;
-
-        public InstallerServiceImpl(InstallerService service) {
-            mService = new WeakReference<>(service);
-        }
-
-        private InstallerService ensureServiceConnected() throws RuntimeException {
-            InstallerService service = mService.get();
-            if (service == null) {
-                throw new RuntimeException(
-                        "Internal error: Installer service is being accessed after destroyed");
-            }
-            return service;
-        }
-
-        @Override
-        public void requestInstall(boolean isWifiOnly) {
-            InstallerService service = ensureServiceConnected();
-            synchronized (service.mLock) {
-                service.requestInstall(isWifiOnly);
-            }
-        }
-
-        @Override
-        public void setProgressListener(IInstallProgressListener listener) {
-            InstallerService service = ensureServiceConnected();
-            synchronized (service.mLock) {
-                service.mListener = listener;
-            }
-        }
-
-        @Override
-        public boolean isInstalling() {
-            InstallerService service = ensureServiceConnected();
-            synchronized (service.mLock) {
-                return service.mIsInstalling;
-            }
-        }
-
-        @Override
-        public boolean isInstalled() {
-            InstallerService service = ensureServiceConnected();
-            synchronized (service.mLock) {
-                return !service.mIsInstalling && InstalledImage.getDefault(service).isInstalled();
-            }
-        }
-    }
-
-    private final class WifiCheckInputStream extends InputStream {
-        private static final int READ_BYTES = 1024;
-
-        private final InputStream mInputStream;
-        private boolean mIsWifiOnly;
-
-        public WifiCheckInputStream(InputStream is) {
-            super();
-            mInputStream = is;
-        }
-
-        public void setWifiOnly(boolean isWifiOnly) {
-            mIsWifiOnly = isWifiOnly;
-        }
-
-        @Override
-        public int read(byte[] buf, int offset, int numToRead) throws IOException {
-            int totalRead = 0;
-            while (numToRead > 0) {
-                if (!checkForWifiOnly(mIsWifiOnly)) {
-                    throw new NoWifiException();
-                }
-                int read =
-                        mInputStream.read(buf, offset + totalRead, Math.min(READ_BYTES, numToRead));
-                if (read <= 0) {
-                    break;
-                }
-                totalRead += read;
-                numToRead -= read;
-            }
-            return totalRead;
-        }
-
-        @Override
-        public int read() throws IOException {
-            if (!checkForWifiOnly(mIsWifiOnly)) {
-                throw new NoWifiException();
-            }
-            return mInputStream.read();
-        }
-
-        private static final class NoWifiException extends SocketException {
-            // empty
-        }
-    }
-
-    private final class MyNetworkCallback extends ConnectivityManager.NetworkCallback {
-        @Override
-        public void onCapabilitiesChanged(
-                @NonNull Network network, @NonNull NetworkCapabilities capability) {
-            synchronized (mLock) {
-                mHasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
-            }
-        }
-    }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
new file mode 100644
index 0000000..423d66b
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.kt
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Intent
+import android.content.pm.ServiceInfo
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.os.Build
+import android.os.IBinder
+import android.util.Log
+import com.android.internal.annotations.GuardedBy
+import com.android.virtualization.terminal.ImageArchive.Companion.fromInternet
+import com.android.virtualization.terminal.ImageArchive.Companion.fromSdCard
+import com.android.virtualization.terminal.InstalledImage.Companion.getDefault
+import com.android.virtualization.terminal.InstallerService.InstallerServiceImpl
+import com.android.virtualization.terminal.InstallerService.WifiCheckInputStream.NoWifiException
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
+import java.io.IOException
+import java.io.InputStream
+import java.lang.Exception
+import java.lang.RuntimeException
+import java.lang.ref.WeakReference
+import java.net.SocketException
+import java.net.UnknownHostException
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import kotlin.math.min
+
+class InstallerService : Service() {
+    private val lock = Any()
+
+    private lateinit var notification: Notification
+
+    @GuardedBy("lock") private var isInstalling = false
+
+    @GuardedBy("lock") private var hasWifi = false
+
+    @GuardedBy("lock") private var listener: IInstallProgressListener? = null
+
+    private lateinit var executorService: ExecutorService
+    private lateinit var connectivityManager: ConnectivityManager
+    private lateinit var networkCallback: MyNetworkCallback
+
+    override fun onCreate() {
+        super.onCreate()
+
+        val intent = Intent(this, MainActivity::class.java)
+        val pendingIntent =
+            PendingIntent.getActivity(
+                this,
+                /* requestCode= */ 0,
+                intent,
+                PendingIntent.FLAG_IMMUTABLE,
+            )
+        notification =
+            Notification.Builder(this, this.packageName)
+                .setSilent(true)
+                .setSmallIcon(R.drawable.ic_launcher_foreground)
+                .setContentTitle(getString(R.string.installer_notif_title_text))
+                .setContentText(getString(R.string.installer_notif_desc_text))
+                .setOngoing(true)
+                .setContentIntent(pendingIntent)
+                .build()
+
+        executorService =
+            Executors.newSingleThreadExecutor(TerminalThreadFactory(applicationContext))
+
+        connectivityManager = getSystemService<ConnectivityManager>(ConnectivityManager::class.java)
+        val defaultNetwork = connectivityManager.boundNetworkForProcess
+        if (defaultNetwork != null) {
+            val capability = connectivityManager.getNetworkCapabilities(defaultNetwork)
+            if (capability != null) {
+                hasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+            }
+        }
+        networkCallback = MyNetworkCallback()
+        connectivityManager.registerDefaultNetworkCallback(networkCallback)
+    }
+
+    override fun onBind(intent: Intent?): IBinder? {
+        return InstallerServiceImpl(this)
+    }
+
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        super.onStartCommand(intent, flags, startId)
+
+        Log.d(TAG, "Starting service ...")
+
+        return START_STICKY
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+
+        Log.d(TAG, "Service is destroyed")
+        executorService.shutdown()
+        connectivityManager.unregisterNetworkCallback(networkCallback)
+    }
+
+    private fun requestInstall(isWifiOnly: Boolean) {
+        synchronized(lock) {
+            if (isInstalling) {
+                Log.i(TAG, "already installing..")
+                return
+            } else {
+                Log.i(TAG, "installing..")
+                isInstalling = true
+            }
+        }
+
+        // Make service to be long running, even after unbind() when InstallerActivity is destroyed
+        // The service will still be destroyed if task is remove.
+        startService(Intent(this, InstallerService::class.java))
+        startForeground(
+            NOTIFICATION_ID,
+            notification,
+            ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE,
+        )
+
+        executorService.execute(
+            Runnable {
+                val success = downloadFromSdcard() || downloadFromUrl(isWifiOnly)
+                stopForeground(STOP_FOREGROUND_REMOVE)
+
+                synchronized(lock) { isInstalling = false }
+                if (success) {
+                    notifyCompleted()
+                }
+            }
+        )
+    }
+
+    private fun downloadFromSdcard(): Boolean {
+        val archive = fromSdCard()
+
+        // Installing from sdcard is preferred, but only supported only in debuggable build.
+        if (Build.isDebuggable() && archive.exists()) {
+            Log.i(TAG, "trying to install /sdcard/linux/images.tar.gz")
+
+            val dest = getDefault(this).installDir
+            try {
+                archive.installTo(dest, null)
+                Log.i(TAG, "image is installed from /sdcard/linux/images.tar.gz")
+                return true
+            } catch (e: IOException) {
+                Log.i(TAG, "Failed to install /sdcard/linux/images.tar.gz", e)
+            }
+        } else {
+            Log.i(TAG, "Non-debuggable build doesn't support installation from /sdcard/linux")
+        }
+        return false
+    }
+
+    private fun checkForWifiOnly(isWifiOnly: Boolean): Boolean {
+        if (!isWifiOnly) {
+            return true
+        }
+        synchronized(lock) {
+            return hasWifi
+        }
+    }
+
+    // TODO(b/374015561): Support pause/resume download
+    private fun downloadFromUrl(isWifiOnly: Boolean): Boolean {
+        if (!checkForWifiOnly(isWifiOnly)) {
+            Log.e(TAG, "Install isn't started because Wifi isn't available")
+            notifyError(getString(R.string.installer_error_no_wifi))
+            return false
+        }
+
+        val dest = getDefault(this).installDir
+        try {
+            fromInternet().installTo(dest) {
+                val filter = WifiCheckInputStream(it)
+                filter.setWifiOnly(isWifiOnly)
+                filter
+            }
+        } catch (e: NoWifiException) {
+            Log.e(TAG, "Install failed because of Wi-Fi is gone")
+            notifyError(getString(R.string.installer_error_no_wifi))
+            return false
+        } catch (e: UnknownHostException) {
+            // Log.e() doesn't print stack trace for UnknownHostException
+            Log.e(TAG, "Install failed: " + e.message, e)
+            notifyError(getString(R.string.installer_error_network))
+            return false
+        } catch (e: SocketException) {
+            Log.e(TAG, "Install failed: " + e.message, e)
+            notifyError(getString(R.string.installer_error_network))
+            return false
+        } catch (e: IOException) {
+            Log.e(TAG, "Installation failed", e)
+            notifyError(getString(R.string.installer_error_unknown))
+            return false
+        }
+        return true
+    }
+
+    private fun notifyError(displayText: String?) {
+        var listener: IInstallProgressListener
+        synchronized(lock) { listener = this@InstallerService.listener!! }
+
+        try {
+            listener.onError(displayText)
+        } catch (e: Exception) {
+            // ignore. Activity may not exist.
+        }
+    }
+
+    private fun notifyCompleted() {
+        var listener: IInstallProgressListener
+        synchronized(lock) { listener = this@InstallerService.listener!! }
+
+        try {
+            listener.onCompleted()
+        } catch (e: Exception) {
+            // ignore. Activity may not exist.
+        }
+    }
+
+    private class InstallerServiceImpl(service: InstallerService?) : IInstallerService.Stub() {
+        // Holds weak reference to avoid Context leak
+        private val mService: WeakReference<InstallerService> =
+            WeakReference<InstallerService>(service)
+
+        @Throws(RuntimeException::class)
+        fun ensureServiceConnected(): InstallerService {
+            val service: InstallerService? = mService.get()
+            if (service == null) {
+                throw RuntimeException(
+                    "Internal error: Installer service is being accessed after destroyed"
+                )
+            }
+            return service
+        }
+
+        override fun requestInstall(isWifiOnly: Boolean) {
+            val service = ensureServiceConnected()
+            synchronized(service.lock) { service.requestInstall(isWifiOnly) }
+        }
+
+        override fun setProgressListener(listener: IInstallProgressListener) {
+            val service = ensureServiceConnected()
+            synchronized(service.lock) { service.listener = listener }
+        }
+
+        override fun isInstalling(): Boolean {
+            val service = ensureServiceConnected()
+            synchronized(service.lock) {
+                return service.isInstalling
+            }
+        }
+
+        override fun isInstalled(): Boolean {
+            val service = ensureServiceConnected()
+            synchronized(service.lock) {
+                return !service.isInstalling && getDefault(service).isInstalled()
+            }
+        }
+    }
+
+    private inner class WifiCheckInputStream(private val inputStream: InputStream) : InputStream() {
+        private var isWifiOnly = false
+
+        fun setWifiOnly(isWifiOnly: Boolean) {
+            this@WifiCheckInputStream.isWifiOnly = isWifiOnly
+        }
+
+        @Throws(IOException::class)
+        override fun read(buf: ByteArray?, offset: Int, numToRead: Int): Int {
+            var remaining = numToRead
+            var totalRead = 0
+            while (remaining > 0) {
+                if (!checkForWifiOnly(isWifiOnly)) {
+                    throw NoWifiException()
+                }
+                val read =
+                    this@WifiCheckInputStream.inputStream.read(
+                        buf,
+                        offset + totalRead,
+                        min(READ_BYTES, remaining),
+                    )
+                if (read <= 0) {
+                    break
+                }
+                totalRead += read
+                remaining -= read
+            }
+            return totalRead
+        }
+
+        @Throws(IOException::class)
+        override fun read(): Int {
+            if (!checkForWifiOnly(isWifiOnly)) {
+                throw NoWifiException()
+            }
+            return this@WifiCheckInputStream.inputStream.read()
+        }
+
+        inner class NoWifiException : SocketException()
+    }
+
+    private inner class MyNetworkCallback : ConnectivityManager.NetworkCallback() {
+        override fun onCapabilitiesChanged(network: Network, capability: NetworkCapabilities) {
+            synchronized(lock) {
+                hasWifi = capability.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+            }
+        }
+    }
+
+    companion object {
+        private const val NOTIFICATION_ID = 1313 // any unique number among notifications
+        private const val READ_BYTES = 1024
+    }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
index 3a273ec..547f1a7 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Logger.kt
@@ -37,7 +37,6 @@
  * Forwards VM's console output to a file on the Android side, and VM's log output to Android logd.
  */
 internal object Logger {
-    @JvmStatic
     fun setup(vm: VirtualMachine, path: Path, executor: ExecutorService) {
         if (vm.config.debugLevel != VirtualMachineConfig.DEBUG_LEVEL_FULL) {
             return
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
deleted file mode 100644
index 4fddd14..0000000
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-package com.android.virtualization.terminal;
-
-import static android.webkit.WebSettings.LOAD_NO_CACHE;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.drawable.Icon;
-import android.graphics.fonts.FontStyle;
-import android.net.Uri;
-import android.net.http.SslError;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Environment;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.WindowInsets;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
-import android.webkit.ClientCertRequest;
-import android.webkit.SslErrorHandler;
-import android.webkit.WebChromeClient;
-import android.webkit.WebResourceError;
-import android.webkit.WebResourceRequest;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-import androidx.activity.result.ActivityResult;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.microdroid.test.common.DeviceProperties;
-
-import com.google.android.material.appbar.MaterialToolbar;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class MainActivity extends BaseActivity
-        implements VmLauncherService.VmLauncherServiceCallback, AccessibilityStateChangeListener {
-    static final String TAG = "VmTerminalApp";
-    static final String KEY_DISK_SIZE = "disk_size";
-    private static final int TERMINAL_CONNECTION_TIMEOUT_MS;
-    private static final int REQUEST_CODE_INSTALLER = 0x33;
-    private static final int FONT_SIZE_DEFAULT = 13;
-
-    static {
-        DeviceProperties prop = DeviceProperties.create(SystemProperties::get);
-        if (prop.isCuttlefish() || prop.isGoldfish()) {
-            TERMINAL_CONNECTION_TIMEOUT_MS = 180_000; // 3 minutes
-        } else {
-            TERMINAL_CONNECTION_TIMEOUT_MS = 20_000; // 20 sec
-        }
-    }
-
-    private ExecutorService mExecutorService;
-    private InstalledImage mImage;
-    private X509Certificate[] mCertificates;
-    private PrivateKey mPrivateKey;
-    private TerminalView mTerminalView;
-    private AccessibilityManager mAccessibilityManager;
-    private ConditionVariable mBootCompleted = new ConditionVariable();
-    private static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_CODE = 101;
-    private ActivityResultLauncher<Intent> mManageExternalStorageActivityResultLauncher;
-    private static final Map<Integer, Integer> BTN_KEY_CODE_MAP =
-            Map.ofEntries(
-                    Map.entry(R.id.btn_tab, KeyEvent.KEYCODE_TAB),
-                    // Alt key sends ESC keycode
-                    Map.entry(R.id.btn_alt, KeyEvent.KEYCODE_ESCAPE),
-                    Map.entry(R.id.btn_esc, KeyEvent.KEYCODE_ESCAPE),
-                    Map.entry(R.id.btn_left, KeyEvent.KEYCODE_DPAD_LEFT),
-                    Map.entry(R.id.btn_right, KeyEvent.KEYCODE_DPAD_RIGHT),
-                    Map.entry(R.id.btn_up, KeyEvent.KEYCODE_DPAD_UP),
-                    Map.entry(R.id.btn_down, KeyEvent.KEYCODE_DPAD_DOWN),
-                    Map.entry(R.id.btn_home, KeyEvent.KEYCODE_MOVE_HOME),
-                    Map.entry(R.id.btn_end, KeyEvent.KEYCODE_MOVE_END),
-                    Map.entry(R.id.btn_pgup, KeyEvent.KEYCODE_PAGE_UP),
-                    Map.entry(R.id.btn_pgdn, KeyEvent.KEYCODE_PAGE_DOWN));
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        lockOrientationIfNecessary();
-
-        mImage = InstalledImage.getDefault(this);
-
-        boolean launchInstaller = installIfNecessary();
-
-        setContentView(R.layout.activity_headless);
-
-        MaterialToolbar toolbar = (MaterialToolbar) findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
-        mTerminalView = (TerminalView) findViewById(R.id.webview);
-        mTerminalView.getSettings().setDatabaseEnabled(true);
-        mTerminalView.getSettings().setDomStorageEnabled(true);
-        mTerminalView.getSettings().setJavaScriptEnabled(true);
-        mTerminalView.getSettings().setCacheMode(LOAD_NO_CACHE);
-        mTerminalView.setWebChromeClient(new WebChromeClient());
-
-        setupModifierKeys();
-
-        mAccessibilityManager = getSystemService(AccessibilityManager.class);
-        mAccessibilityManager.addAccessibilityStateChangeListener(this);
-
-        readClientCertificate();
-
-        mManageExternalStorageActivityResultLauncher =
-                registerForActivityResult(
-                        new ActivityResultContracts.StartActivityForResult(),
-                        (ActivityResult result) -> {
-                            startVm();
-                        });
-        getWindow()
-                .getDecorView()
-                .getRootView()
-                .setOnApplyWindowInsetsListener(
-                        (v, insets) -> {
-                            updateModifierKeysVisibility();
-                            return insets;
-                        });
-
-        mExecutorService =
-                Executors.newSingleThreadExecutor(
-                        new TerminalThreadFactory(getApplicationContext()));
-
-        // if installer is launched, it will be handled in onActivityResult
-        if (!launchInstaller) {
-            if (!Environment.isExternalStorageManager()) {
-                requestStoragePermissions(this, mManageExternalStorageActivityResultLauncher);
-            } else {
-                startVm();
-            }
-        }
-    }
-
-    private void lockOrientationIfNecessary() {
-        boolean hasHwQwertyKeyboard =
-                getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY;
-        if (hasHwQwertyKeyboard) {
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-        } else if (getResources().getBoolean(R.bool.terminal_portrait_only)) {
-            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-        }
-    }
-
-    @Override
-    public void onConfigurationChanged(@NonNull Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        lockOrientationIfNecessary();
-        updateModifierKeysVisibility();
-    }
-
-    private void setupModifierKeys() {
-        // Only ctrl key is special, it communicates with xtermjs to modify key event with ctrl key
-        findViewById(R.id.btn_ctrl)
-                .setOnClickListener(
-                        (v) -> {
-                            mTerminalView.mapCtrlKey();
-                            mTerminalView.enableCtrlKey();
-                        });
-
-        View.OnClickListener modifierButtonClickListener =
-                v -> {
-                    if (BTN_KEY_CODE_MAP.containsKey(v.getId())) {
-                        int keyCode = BTN_KEY_CODE_MAP.get(v.getId());
-                        mTerminalView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
-                        mTerminalView.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
-                    }
-                };
-
-        for (int btn : BTN_KEY_CODE_MAP.keySet()) {
-            View v = findViewById(btn);
-            if (v != null) {
-                v.setOnClickListener(modifierButtonClickListener);
-            }
-        }
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (Build.isDebuggable() && event.getKeyCode() == KeyEvent.KEYCODE_UNKNOWN) {
-            if (event.getAction() == KeyEvent.ACTION_UP) {
-                ErrorActivity.start(this, new Exception("Debug: KeyEvent.KEYCODE_UNKNOWN"));
-            }
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
-    private void requestStoragePermissions(
-            Context context, ActivityResultLauncher<Intent> activityResultLauncher) {
-        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
-        Uri uri = Uri.fromParts("package", context.getPackageName(), null);
-        intent.setData(uri);
-        activityResultLauncher.launch(intent);
-    }
-
-    private URL getTerminalServiceUrl(String ipAddress, int port) {
-        Configuration config = getResources().getConfiguration();
-
-        String query =
-                "?fontSize="
-                        + (int) (config.fontScale * FONT_SIZE_DEFAULT)
-                        + "&fontWeight="
-                        + (FontStyle.FONT_WEIGHT_NORMAL + config.fontWeightAdjustment)
-                        + "&fontWeightBold="
-                        + (FontStyle.FONT_WEIGHT_BOLD + config.fontWeightAdjustment)
-                        + "&screenReaderMode="
-                        + mAccessibilityManager.isEnabled()
-                        + "&titleFixed="
-                        + getString(R.string.app_name);
-
-
-        try {
-            return new URL("https", ipAddress, port, "/" + query);
-        } catch (MalformedURLException e) {
-            // this cannot happen
-            return null;
-        }
-    }
-
-    private void readClientCertificate() {
-        KeyStore.PrivateKeyEntry pke = CertificateUtils.createOrGetKey();
-        CertificateUtils.writeCertificateToFile(this, pke.getCertificate());
-        mPrivateKey = pke.getPrivateKey();
-        mCertificates = new X509Certificate[1];
-        mCertificates[0] = (X509Certificate) pke.getCertificate();
-    }
-
-    private void connectToTerminalService() {
-        mTerminalView.setWebViewClient(
-                new WebViewClient() {
-                    private boolean mLoadFailed = false;
-                    private long mRequestId = 0;
-
-                    @Override
-                    public boolean shouldOverrideUrlLoading(
-                            WebView view, WebResourceRequest request) {
-                        return false;
-                    }
-
-                    @Override
-                    public void onPageStarted(WebView view, String url, Bitmap favicon) {
-                        mLoadFailed = false;
-                    }
-
-                    @Override
-                    public void onReceivedError(
-                            WebView view, WebResourceRequest request, WebResourceError error) {
-                        mLoadFailed = true;
-                        switch (error.getErrorCode()) {
-                            case WebViewClient.ERROR_CONNECT:
-                            case WebViewClient.ERROR_HOST_LOOKUP:
-                            case WebViewClient.ERROR_FAILED_SSL_HANDSHAKE:
-                            case WebViewClient.ERROR_TIMEOUT:
-                                view.reload();
-                                return;
-                            default:
-                                String url = request.getUrl().toString();
-                                CharSequence msg = error.getDescription();
-                                Log.e(TAG, "Failed to load " + url + ": " + msg);
-                        }
-                    }
-
-                    @Override
-                    public void onPageFinished(WebView view, String url) {
-                        if (mLoadFailed) {
-                            return;
-                        }
-
-                        mRequestId++;
-                        view.postVisualStateCallback(
-                                mRequestId,
-                                new WebView.VisualStateCallback() {
-                                    @Override
-                                    public void onComplete(long requestId) {
-                                        if (requestId == mRequestId) {
-                                            android.os.Trace.endAsyncSection("executeTerminal", 0);
-                                            findViewById(R.id.boot_progress)
-                                                    .setVisibility(View.GONE);
-                                            findViewById(R.id.webview_container)
-                                                    .setVisibility(View.VISIBLE);
-                                            mBootCompleted.open();
-                                            updateModifierKeysVisibility();
-                                            mTerminalView.mapTouchToMouseEvent();
-                                        }
-                                    }
-                                });
-                    }
-
-                    @Override
-                    public void onReceivedClientCertRequest(
-                            WebView view, ClientCertRequest request) {
-                        if (mPrivateKey != null && mCertificates != null) {
-                            request.proceed(mPrivateKey, mCertificates);
-                            return;
-                        }
-                        super.onReceivedClientCertRequest(view, request);
-                    }
-
-                    @Override
-                    public void onReceivedSslError(
-                            WebView view, SslErrorHandler handler, SslError error) {
-                        // ttyd uses self-signed certificate
-                        handler.proceed();
-                    }
-                });
-
-        // TODO: refactor this block as a method
-        NsdManager nsdManager = getSystemService(NsdManager.class);
-        NsdServiceInfo info = new NsdServiceInfo();
-        info.setServiceType("_http._tcp");
-        info.setServiceName("ttyd");
-        nsdManager.registerServiceInfoCallback(
-                info,
-                mExecutorService,
-                new NsdManager.ServiceInfoCallback() {
-                    @Override
-                    public void onServiceInfoCallbackRegistrationFailed(int errorCode) {}
-
-                    @Override
-                    public void onServiceInfoCallbackUnregistered() {}
-
-                    @Override
-                    public void onServiceLost() {}
-
-                    @Override
-                    public void onServiceUpdated(NsdServiceInfo info) {
-                        nsdManager.unregisterServiceInfoCallback(this);
-
-                        Log.i(TAG, "Service found: " + info.toString());
-                        String ipAddress = info.getHostAddresses().get(0).getHostAddress();
-                        int port = info.getPort();
-                        URL url = getTerminalServiceUrl(ipAddress, port);
-                        runOnUiThread(() -> mTerminalView.loadUrl(url.toString()));
-                    }
-                });
-    }
-
-    @Override
-    protected void onDestroy() {
-        if (mExecutorService != null) {
-            mExecutorService.shutdown();
-        }
-
-        getSystemService(AccessibilityManager.class).removeAccessibilityStateChangeListener(this);
-        VmLauncherService.stop(this);
-        super.onDestroy();
-    }
-
-    @Override
-    public void onVmStart() {
-        Log.i(TAG, "onVmStart()");
-    }
-
-    @Override
-    public void onVmStop() {
-        Log.i(TAG, "onVmStop()");
-        finish();
-    }
-
-    @Override
-    public void onVmError() {
-        Log.i(TAG, "onVmError()");
-        // TODO: error cause is too simple.
-        ErrorActivity.start(this, new Exception("onVmError"));
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.main_menu, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        int id = item.getItemId();
-        if (id == R.id.menu_item_settings) {
-            Intent intent = new Intent(this, SettingsActivity.class);
-            this.startActivity(intent);
-            return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
-    public void onAccessibilityStateChanged(boolean enabled) {
-        connectToTerminalService();
-    }
-
-    private void updateModifierKeysVisibility() {
-        boolean imeShown =
-                getWindow().getDecorView().getRootWindowInsets().isVisible(WindowInsets.Type.ime());
-        boolean hasHwQwertyKeyboard =
-                getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY;
-        boolean showModifierKeys = imeShown && !hasHwQwertyKeyboard;
-
-        View modifierKeys = findViewById(R.id.modifier_keys);
-        modifierKeys.setVisibility(showModifierKeys ? View.VISIBLE : View.GONE);
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        super.onActivityResult(requestCode, resultCode, data);
-
-        if (requestCode == REQUEST_CODE_INSTALLER) {
-            if (resultCode != RESULT_OK) {
-                Log.e(TAG, "Failed to start VM. Installer returned error.");
-                finish();
-            }
-            if (!Environment.isExternalStorageManager()) {
-                requestStoragePermissions(this, mManageExternalStorageActivityResultLauncher);
-            } else {
-                startVm();
-            }
-        }
-    }
-
-    private boolean installIfNecessary() {
-        // If payload from external storage exists(only for debuggable build) or there is no
-        // installed image, launch installer activity.
-        if (!mImage.isInstalled()) {
-            Intent intent = new Intent(this, InstallerActivity.class);
-            startActivityForResult(intent, REQUEST_CODE_INSTALLER);
-            return true;
-        }
-        return false;
-    }
-
-    private void startVm() {
-        InstalledImage image = InstalledImage.getDefault(this);
-        if (!image.isInstalled()) {
-            return;
-        }
-
-        resizeDiskIfNecessary(image);
-
-        Intent tapIntent = new Intent(this, MainActivity.class);
-        tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        PendingIntent tapPendingIntent =
-                PendingIntent.getActivity(this, 0, tapIntent, PendingIntent.FLAG_IMMUTABLE);
-
-        Intent settingsIntent = new Intent(this, SettingsActivity.class);
-        settingsIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        PendingIntent settingsPendingIntent = PendingIntent.getActivity(this, 0, settingsIntent,
-                PendingIntent.FLAG_IMMUTABLE);
-
-        Intent stopIntent = new Intent();
-        stopIntent.setClass(this, VmLauncherService.class);
-        stopIntent.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE);
-        PendingIntent stopPendingIntent =
-                PendingIntent.getService(
-                        this,
-                        0,
-                        stopIntent,
-                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-        Icon icon = Icon.createWithResource(getResources(), R.drawable.ic_launcher_foreground);
-        Notification notification =
-                new Notification.Builder(this, this.getPackageName())
-                        .setSilent(true)
-                        .setSmallIcon(R.drawable.ic_launcher_foreground)
-                        .setContentTitle(
-                                getResources().getString(R.string.service_notification_title))
-                        .setContentText(
-                                getResources().getString(R.string.service_notification_content))
-                        .setContentIntent(tapPendingIntent)
-                        .setOngoing(true)
-                        .addAction(
-                                new Notification.Action.Builder(
-                                                icon,
-                                                getResources()
-                                                        .getString(
-                                                                R.string
-                                                                        .service_notification_settings),
-                                                settingsPendingIntent)
-                                        .build())
-                        .addAction(
-                                new Notification.Action.Builder(
-                                                icon,
-                                                getResources()
-                                                        .getString(
-                                                                R.string
-                                                                        .service_notification_quit_action),
-                                                stopPendingIntent)
-                                        .build())
-                        .build();
-
-        android.os.Trace.beginAsyncSection("executeTerminal", 0);
-        VmLauncherService.run(this, this, notification);
-        connectToTerminalService();
-    }
-
-    @VisibleForTesting
-    public boolean waitForBootCompleted(long timeoutMillis) {
-        return mBootCompleted.block(timeoutMillis);
-    }
-
-    private void resizeDiskIfNecessary(InstalledImage image) {
-        try {
-            // TODO(b/382190982): Show snackbar message instead when it's recoverable.
-            image.resize(getIntent().getLongExtra(KEY_DISK_SIZE, image.getSize()));
-        } catch (IOException e) {
-            ErrorActivity.start(this, new Exception("Failed to resize disk", e));
-            return;
-        }
-    }
-}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
new file mode 100644
index 0000000..bf2f573
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.kt
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 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.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.graphics.fonts.FontStyle
+import android.net.Uri
+import android.net.http.SslError
+import android.net.nsd.NsdManager
+import android.net.nsd.NsdServiceInfo
+import android.os.Build
+import android.os.Bundle
+import android.os.ConditionVariable
+import android.os.Environment
+import android.os.SystemProperties
+import android.os.Trace
+import android.provider.Settings
+import android.util.Log
+import android.view.KeyEvent
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityManager
+import android.webkit.ClientCertRequest
+import android.webkit.SslErrorHandler
+import android.webkit.WebChromeClient
+import android.webkit.WebResourceError
+import android.webkit.WebResourceRequest
+import android.webkit.WebSettings
+import android.webkit.WebView
+import android.webkit.WebViewClient
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.ActivityResultCallback
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
+import com.android.internal.annotations.VisibleForTesting
+import com.android.microdroid.test.common.DeviceProperties
+import com.android.virtualization.terminal.CertificateUtils.createOrGetKey
+import com.android.virtualization.terminal.CertificateUtils.writeCertificateToFile
+import com.android.virtualization.terminal.ErrorActivity.Companion.start
+import com.android.virtualization.terminal.InstalledImage.Companion.getDefault
+import com.android.virtualization.terminal.VmLauncherService.Companion.run
+import com.android.virtualization.terminal.VmLauncherService.Companion.stop
+import com.android.virtualization.terminal.VmLauncherService.VmLauncherServiceCallback
+import com.google.android.material.appbar.MaterialToolbar
+import java.io.IOException
+import java.lang.Exception
+import java.net.MalformedURLException
+import java.net.URL
+import java.security.PrivateKey
+import java.security.cert.X509Certificate
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+public class MainActivity :
+    BaseActivity(),
+    VmLauncherServiceCallback,
+    AccessibilityManager.AccessibilityStateChangeListener {
+    private lateinit var executorService: ExecutorService
+    private lateinit var image: InstalledImage
+    private var certificates: Array<X509Certificate>? = null
+    private var privateKey: PrivateKey? = null
+    private lateinit var terminalContainer: ViewGroup
+    private lateinit var terminalView: TerminalView
+    private lateinit var accessibilityManager: AccessibilityManager
+    private val bootCompleted = ConditionVariable()
+    private lateinit var manageExternalStorageActivityResultLauncher: ActivityResultLauncher<Intent>
+    private lateinit var modifierKeysController: ModifierKeysController
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        lockOrientationIfNecessary()
+
+        image = getDefault(this)
+
+        val launchInstaller = installIfNecessary()
+
+        setContentView(R.layout.activity_headless)
+
+        val toolbar = findViewById<MaterialToolbar>(R.id.toolbar)
+        setSupportActionBar(toolbar)
+        terminalView = findViewById<TerminalView>(R.id.webview)
+        terminalView.getSettings().setDomStorageEnabled(true)
+        terminalView.getSettings().setJavaScriptEnabled(true)
+        terminalView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE)
+        terminalView.setWebChromeClient(WebChromeClient())
+
+        terminalContainer = terminalView.parent as ViewGroup
+
+        modifierKeysController = ModifierKeysController(this, terminalView, terminalContainer)
+
+        accessibilityManager =
+            getSystemService<AccessibilityManager>(AccessibilityManager::class.java)
+        accessibilityManager.addAccessibilityStateChangeListener(this)
+
+        readClientCertificate()
+
+        manageExternalStorageActivityResultLauncher =
+            registerForActivityResult<Intent, ActivityResult>(
+                StartActivityForResult(),
+                ActivityResultCallback { startVm() },
+            )
+        executorService =
+            Executors.newSingleThreadExecutor(TerminalThreadFactory(applicationContext))
+
+        // if installer is launched, it will be handled in onActivityResult
+        if (!launchInstaller) {
+            if (!Environment.isExternalStorageManager()) {
+                requestStoragePermissions(this, manageExternalStorageActivityResultLauncher)
+            } else {
+                startVm()
+            }
+        }
+    }
+
+    private fun lockOrientationIfNecessary() {
+        val hasHwQwertyKeyboard = resources.configuration.keyboard == Configuration.KEYBOARD_QWERTY
+        if (hasHwQwertyKeyboard) {
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
+        } else if (resources.getBoolean(R.bool.terminal_portrait_only)) {
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+        }
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        lockOrientationIfNecessary()
+        modifierKeysController.update()
+    }
+
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        if (Build.isDebuggable() && event.keyCode == KeyEvent.KEYCODE_UNKNOWN) {
+            if (event.action == KeyEvent.ACTION_UP) {
+                start(this, Exception("Debug: KeyEvent.KEYCODE_UNKNOWN"))
+            }
+            return true
+        }
+        return super.dispatchKeyEvent(event)
+    }
+
+    private fun requestStoragePermissions(
+        context: Context,
+        activityResultLauncher: ActivityResultLauncher<Intent>,
+    ) {
+        val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
+        val uri = Uri.fromParts("package", context.getPackageName(), null)
+        intent.setData(uri)
+        activityResultLauncher.launch(intent)
+    }
+
+    private fun getTerminalServiceUrl(ipAddress: String?, port: Int): URL? {
+        val config = resources.configuration
+
+        val query =
+            ("?fontSize=" +
+                (config.fontScale * FONT_SIZE_DEFAULT).toInt() +
+                "&fontWeight=" +
+                (FontStyle.FONT_WEIGHT_NORMAL + config.fontWeightAdjustment) +
+                "&fontWeightBold=" +
+                (FontStyle.FONT_WEIGHT_BOLD + config.fontWeightAdjustment) +
+                "&screenReaderMode=" +
+                accessibilityManager.isEnabled +
+                "&titleFixed=" +
+                getString(R.string.app_name))
+
+        try {
+            return URL("https", ipAddress, port, "/$query")
+        } catch (e: MalformedURLException) {
+            // this cannot happen
+            return null
+        }
+    }
+
+    private fun readClientCertificate() {
+        val pke = createOrGetKey()
+        writeCertificateToFile(this, pke.certificate)
+        privateKey = pke.privateKey
+        certificates = arrayOf<X509Certificate>(pke.certificate as X509Certificate)
+    }
+
+    private fun connectToTerminalService() {
+        terminalView.setWebViewClient(
+            object : WebViewClient() {
+                private var loadFailed = false
+                private var requestId: Long = 0
+
+                override fun shouldOverrideUrlLoading(
+                    view: WebView?,
+                    request: WebResourceRequest?,
+                ): Boolean {
+                    return false
+                }
+
+                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
+                    loadFailed = false
+                }
+
+                override fun onReceivedError(
+                    view: WebView,
+                    request: WebResourceRequest,
+                    error: WebResourceError,
+                ) {
+                    loadFailed = true
+                    when (error.getErrorCode()) {
+                        ERROR_CONNECT,
+                        ERROR_HOST_LOOKUP,
+                        ERROR_FAILED_SSL_HANDSHAKE,
+                        ERROR_TIMEOUT -> {
+                            view.reload()
+                            return
+                        }
+
+                        else -> {
+                            val url: String? = request.getUrl().toString()
+                            val msg = error.getDescription()
+                            Log.e(TAG, "Failed to load $url: $msg")
+                        }
+                    }
+                }
+
+                override fun onPageFinished(view: WebView, url: String?) {
+                    if (loadFailed) {
+                        return
+                    }
+
+                    requestId++
+                    view.postVisualStateCallback(
+                        requestId,
+                        object : WebView.VisualStateCallback() {
+                            override fun onComplete(completedRequestId: Long) {
+                                if (completedRequestId == requestId) {
+                                    Trace.endAsyncSection("executeTerminal", 0)
+                                    findViewById<View?>(R.id.boot_progress).visibility = View.GONE
+                                    terminalContainer.visibility = View.VISIBLE
+                                    bootCompleted.open()
+                                    modifierKeysController.update()
+                                    terminalView.mapTouchToMouseEvent()
+                                }
+                            }
+                        },
+                    )
+                }
+
+                override fun onReceivedClientCertRequest(
+                    view: WebView?,
+                    request: ClientCertRequest,
+                ) {
+                    if (privateKey != null && certificates != null) {
+                        request.proceed(privateKey, certificates)
+                        return
+                    }
+                    super.onReceivedClientCertRequest(view, request)
+                }
+
+                override fun onReceivedSslError(
+                    view: WebView?,
+                    handler: SslErrorHandler,
+                    error: SslError?,
+                ) {
+                    // ttyd uses self-signed certificate
+                    handler.proceed()
+                }
+            }
+        )
+
+        // TODO: refactor this block as a method
+        val nsdManager = getSystemService<NsdManager>(NsdManager::class.java)
+        val info = NsdServiceInfo()
+        info.serviceType = "_http._tcp"
+        info.serviceName = "ttyd"
+        nsdManager.registerServiceInfoCallback(
+            info,
+            executorService,
+            object : NsdManager.ServiceInfoCallback {
+                override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
+
+                override fun onServiceInfoCallbackUnregistered() {}
+
+                override fun onServiceLost() {}
+
+                override fun onServiceUpdated(info: NsdServiceInfo) {
+                    nsdManager.unregisterServiceInfoCallback(this)
+
+                    Log.i(TAG, "Service found: $info")
+                    val ipAddress = info.hostAddresses[0].hostAddress
+                    val port = info.port
+                    val url = getTerminalServiceUrl(ipAddress, port)
+                    runOnUiThread(Runnable { terminalView.loadUrl(url.toString()) })
+                }
+            },
+        )
+    }
+
+    override fun onDestroy() {
+        executorService.shutdown()
+        getSystemService<AccessibilityManager>(AccessibilityManager::class.java)
+            .removeAccessibilityStateChangeListener(this)
+        stop(this)
+        super.onDestroy()
+    }
+
+    override fun onVmStart() {
+        Log.i(TAG, "onVmStart()")
+    }
+
+    override fun onVmStop() {
+        Log.i(TAG, "onVmStop()")
+        finish()
+    }
+
+    override fun onVmError() {
+        Log.i(TAG, "onVmError()")
+        // TODO: error cause is too simple.
+        start(this, Exception("onVmError"))
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+        menuInflater.inflate(R.menu.main_menu, menu)
+        return true
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        val id = item.getItemId()
+        if (id == R.id.menu_item_settings) {
+            val intent = Intent(this, SettingsActivity::class.java)
+            this.startActivity(intent)
+            return true
+        }
+        return super.onOptionsItemSelected(item)
+    }
+
+    override fun onAccessibilityStateChanged(enabled: Boolean) {
+        connectToTerminalService()
+    }
+
+    private val installerLauncher =
+        registerForActivityResult(StartActivityForResult()) { result ->
+            val resultCode = result.resultCode
+            if (resultCode != RESULT_OK) {
+                Log.e(TAG, "Failed to start VM. Installer returned error.")
+                finish()
+            }
+            if (!Environment.isExternalStorageManager()) {
+                requestStoragePermissions(this, manageExternalStorageActivityResultLauncher)
+            } else {
+                startVm()
+            }
+        }
+
+    private fun installIfNecessary(): Boolean {
+        // If payload from external storage exists(only for debuggable build) or there is no
+        // installed image, launch installer activity.
+        if (!image.isInstalled()) {
+            val intent = Intent(this, InstallerActivity::class.java)
+            installerLauncher.launch(intent)
+            return true
+        }
+        return false
+    }
+
+    private fun startVm() {
+        val image = getDefault(this)
+        if (!image.isInstalled()) {
+            return
+        }
+
+        resizeDiskIfNecessary(image)
+
+        val tapIntent = Intent(this, MainActivity::class.java)
+        tapIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
+        val tapPendingIntent =
+            PendingIntent.getActivity(this, 0, tapIntent, PendingIntent.FLAG_IMMUTABLE)
+
+        val settingsIntent = Intent(this, SettingsActivity::class.java)
+        settingsIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
+        val settingsPendingIntent =
+            PendingIntent.getActivity(this, 0, settingsIntent, PendingIntent.FLAG_IMMUTABLE)
+
+        val stopIntent = Intent()
+        stopIntent.setClass(this, VmLauncherService::class.java)
+        stopIntent.setAction(VmLauncherService.ACTION_STOP_VM_LAUNCHER_SERVICE)
+        val stopPendingIntent =
+            PendingIntent.getService(
+                this,
+                0,
+                stopIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
+            )
+        val icon = Icon.createWithResource(resources, R.drawable.ic_launcher_foreground)
+        val notification: Notification =
+            Notification.Builder(this, this.packageName)
+                .setSilent(true)
+                .setSmallIcon(R.drawable.ic_launcher_foreground)
+                .setContentTitle(resources.getString(R.string.service_notification_title))
+                .setContentText(resources.getString(R.string.service_notification_content))
+                .setContentIntent(tapPendingIntent)
+                .setOngoing(true)
+                .addAction(
+                    Notification.Action.Builder(
+                            icon,
+                            resources.getString(R.string.service_notification_settings),
+                            settingsPendingIntent,
+                        )
+                        .build()
+                )
+                .addAction(
+                    Notification.Action.Builder(
+                            icon,
+                            resources.getString(R.string.service_notification_quit_action),
+                            stopPendingIntent,
+                        )
+                        .build()
+                )
+                .build()
+
+        Trace.beginAsyncSection("executeTerminal", 0)
+        run(this, this, notification)
+        connectToTerminalService()
+    }
+
+    @VisibleForTesting
+    public fun waitForBootCompleted(timeoutMillis: Long): Boolean {
+        return bootCompleted.block(timeoutMillis)
+    }
+
+    private fun resizeDiskIfNecessary(image: InstalledImage) {
+        try {
+            // TODO(b/382190982): Show snackbar message instead when it's recoverable.
+            image.resize(intent.getLongExtra(KEY_DISK_SIZE, image.getSize()))
+        } catch (e: IOException) {
+            start(this, Exception("Failed to resize disk", e))
+            return
+        }
+    }
+
+    companion object {
+        const val TAG: String = "VmTerminalApp"
+        const val KEY_DISK_SIZE: String = "disk_size"
+        private val TERMINAL_CONNECTION_TIMEOUT_MS: Int
+        private const val REQUEST_CODE_INSTALLER = 0x33
+        private const val FONT_SIZE_DEFAULT = 13
+
+        init {
+            val prop =
+                DeviceProperties.create(
+                    DeviceProperties.PropertyGetter { key: String -> SystemProperties.get(key) }
+                )
+            TERMINAL_CONNECTION_TIMEOUT_MS =
+                if (prop.isCuttlefish() || prop.isGoldfish()) {
+                    180000 // 3 minutes
+                } else {
+                    20000 // 20 sec
+                }
+        }
+
+        private val BTN_KEY_CODE_MAP =
+            mapOf(
+                R.id.btn_tab to KeyEvent.KEYCODE_TAB, // Alt key sends ESC keycode
+                R.id.btn_alt to KeyEvent.KEYCODE_ESCAPE,
+                R.id.btn_esc to KeyEvent.KEYCODE_ESCAPE,
+                R.id.btn_left to KeyEvent.KEYCODE_DPAD_LEFT,
+                R.id.btn_right to KeyEvent.KEYCODE_DPAD_RIGHT,
+                R.id.btn_up to KeyEvent.KEYCODE_DPAD_UP,
+                R.id.btn_down to KeyEvent.KEYCODE_DPAD_DOWN,
+                R.id.btn_home to KeyEvent.KEYCODE_MOVE_HOME,
+                R.id.btn_end to KeyEvent.KEYCODE_MOVE_END,
+                R.id.btn_pgup to KeyEvent.KEYCODE_PAGE_UP,
+                R.id.btn_pgdn to KeyEvent.KEYCODE_PAGE_DOWN,
+            )
+    }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt b/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt
new file mode 100644
index 0000000..f8f30f9
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ModifierKeysController.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Activity
+import android.content.res.Configuration
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowInsets
+
+class ModifierKeysController(
+    val activity: Activity,
+    val terminalView: TerminalView,
+    val parent: ViewGroup,
+) {
+    private val window = activity.window
+    private val keysSingleLine: View
+    private val keysDoubleLine: View
+
+    private var keysInSingleLine: Boolean = false
+
+    init {
+        // Prepare the two modifier keys layout, but don't add them yet because we don't know which
+        // layout will be needed.
+        val layout = LayoutInflater.from(activity)
+        keysSingleLine = layout.inflate(R.layout.modifier_keys_singleline, parent, false)
+        keysDoubleLine = layout.inflate(R.layout.modifier_keys_doubleline, parent, false)
+
+        addClickListeners(keysSingleLine)
+        addClickListeners(keysDoubleLine)
+
+        keysSingleLine.visibility = View.GONE
+        keysDoubleLine.visibility = View.GONE
+
+        // Setup for the update to be called when needed
+        window.decorView.rootView.setOnApplyWindowInsetsListener { _: View?, insets: WindowInsets ->
+            update()
+            insets
+        }
+
+        terminalView.setOnFocusChangeListener { _: View, _: Boolean -> update() }
+    }
+
+    private fun addClickListeners(keys: View) {
+        // Only ctrl key is special, it communicates with xtermjs to modify key event with ctrl key
+        keys
+            .findViewById<View>(R.id.btn_ctrl)
+            .setOnClickListener({
+                terminalView.mapCtrlKey()
+                terminalView.enableCtrlKey()
+            })
+
+        val listener =
+            View.OnClickListener { v: View ->
+                BTN_KEY_CODE_MAP[v.id]?.also { keyCode ->
+                    terminalView.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, keyCode))
+                    terminalView.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, keyCode))
+                }
+            }
+
+        for (btn in BTN_KEY_CODE_MAP.keys) {
+            keys.findViewById<View>(btn).setOnClickListener(listener)
+        }
+    }
+
+    fun update() {
+        // select single line or double line
+        val needSingleLine = needsKeysInSingleLine()
+        if (keysInSingleLine != needSingleLine) {
+            if (needSingleLine) {
+                parent.removeView(keysDoubleLine)
+                parent.addView(keysSingleLine)
+            } else {
+                parent.removeView(keysSingleLine)
+                parent.addView(keysDoubleLine)
+            }
+            keysInSingleLine = needSingleLine
+        }
+
+        // set visibility
+        val needShow = needToShowKeys()
+        val keys = if (keysInSingleLine) keysSingleLine else keysDoubleLine
+        keys.visibility = if (needShow) View.VISIBLE else View.GONE
+    }
+
+    // Modifier keys are required only when IME is shown and the HW qwerty keyboard is not present
+    private fun needToShowKeys(): Boolean {
+        val imeShown = activity.window.decorView.rootWindowInsets.isVisible(WindowInsets.Type.ime())
+        val hasFocus = terminalView.hasFocus()
+        val hasHwQwertyKeyboard =
+            activity.resources.configuration.keyboard == Configuration.KEYBOARD_QWERTY
+        return imeShown && hasFocus && !hasHwQwertyKeyboard
+    }
+
+    // If terminal's height is less than 30% of the screen height, we need to show modifier keys in
+    // a single line to save the vertical space
+    private fun needsKeysInSingleLine(): Boolean =
+        (terminalView.height / activity.window.decorView.height.toFloat()) < 0.3f
+
+    companion object {
+        private val BTN_KEY_CODE_MAP =
+            mapOf(
+                R.id.btn_tab to KeyEvent.KEYCODE_TAB, // Alt key sends ESC keycode
+                R.id.btn_alt to KeyEvent.KEYCODE_ESCAPE,
+                R.id.btn_esc to KeyEvent.KEYCODE_ESCAPE,
+                R.id.btn_left to KeyEvent.KEYCODE_DPAD_LEFT,
+                R.id.btn_right to KeyEvent.KEYCODE_DPAD_RIGHT,
+                R.id.btn_up to KeyEvent.KEYCODE_DPAD_UP,
+                R.id.btn_down to KeyEvent.KEYCODE_DPAD_DOWN,
+                R.id.btn_home to KeyEvent.KEYCODE_MOVE_HOME,
+                R.id.btn_end to KeyEvent.KEYCODE_MOVE_END,
+                R.id.btn_pgup to KeyEvent.KEYCODE_PAGE_UP,
+                R.id.btn_pgdn to KeyEvent.KEYCODE_PAGE_DOWN,
+            )
+    }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
index 7a07dfe..7c48303 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/PortNotifier.kt
@@ -23,7 +23,7 @@
 import android.content.Intent
 import android.content.IntentFilter
 import android.graphics.drawable.Icon
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import java.util.Locale
 
 /**
@@ -76,7 +76,11 @@
 
         val title = getString(R.string.settings_port_forwarding_notification_title)
         val content =
-            context.getString(R.string.settings_port_forwarding_notification_content, port)
+            context.getString(
+                R.string.settings_port_forwarding_notification_content,
+                port,
+                portsStateManager.getActivePortInfo(port)?.comm,
+            )
         val acceptText = getString(R.string.settings_port_forwarding_notification_accept)
         val denyText = getString(R.string.settings_port_forwarding_notification_deny)
         val icon = Icon.createWithResource(context, R.drawable.ic_launcher_foreground)
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.kt b/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.kt
index 317ca8e..20bccc2 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/PortsStateManager.kt
@@ -18,6 +18,7 @@
 import android.content.Context
 import android.content.SharedPreferences
 import com.android.internal.annotations.GuardedBy
+import com.android.virtualization.terminal.proto.ActivePort
 import java.util.HashSet
 
 /**
@@ -27,7 +28,7 @@
 class PortsStateManager private constructor(private val sharedPref: SharedPreferences) {
     private val lock = Any()
 
-    @GuardedBy("lock") private val activePorts: MutableSet<Int> = hashSetOf()
+    @GuardedBy("lock") private val activePorts: MutableMap<Int, ActivePort> = hashMapOf()
 
     @GuardedBy("lock")
     private val enabledPorts: MutableSet<Int> =
@@ -44,7 +45,13 @@
 
     fun getActivePorts(): Set<Int> {
         synchronized(lock) {
-            return HashSet<Int>(activePorts)
+            return HashSet<Int>(activePorts.keys)
+        }
+    }
+
+    fun getActivePortInfo(port: Int): ActivePort? {
+        synchronized(lock) {
+            return activePorts[port]
         }
     }
 
@@ -54,11 +61,11 @@
         }
     }
 
-    fun updateActivePorts(ports: Set<Int>) {
+    fun updateActivePorts(ports: List<ActivePort>) {
         val oldPorts = getActivePorts()
         synchronized(lock) {
             activePorts.clear()
-            activePorts.addAll(ports)
+            activePorts.putAll(ports.associateBy { it.port })
         }
         notifyPortsStateUpdated(oldPorts, getActivePorts())
     }
@@ -114,7 +121,6 @@
 
         private var instance: PortsStateManager? = null
 
-        @JvmStatic
         @Synchronized
         fun getInstance(context: Context): PortsStateManager {
             if (instance == null) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt b/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
index 897e182..6454cbd 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/Runner.kt
@@ -22,7 +22,7 @@
 import android.system.virtualmachine.VirtualMachineException
 import android.system.virtualmachine.VirtualMachineManager
 import android.util.Log
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import java.util.concurrent.CompletableFuture
 import java.util.concurrent.ForkJoinPool
 
@@ -59,7 +59,6 @@
 
     companion object {
         /** Create a virtual machine of the given config, under the given context. */
-        @JvmStatic
         @Throws(VirtualMachineException::class)
         fun create(context: Context, config: VirtualMachineConfig): Runner {
             // context may already be the app context, but calling this again is not harmful.
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
index 1bfa390..7076084 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActiveAdapter.kt
@@ -15,6 +15,7 @@
  */
 package com.android.virtualization.terminal
 
+import android.content.Context
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -22,12 +23,14 @@
 import androidx.recyclerview.widget.RecyclerView
 import com.google.android.material.materialswitch.MaterialSwitch
 
-class SettingsPortForwardingActiveAdapter(private val mPortsStateManager: PortsStateManager) :
-    SettingsPortForwardingBaseAdapter<SettingsPortForwardingActiveAdapter.ViewHolder>() {
+class SettingsPortForwardingActiveAdapter(
+    private val portsStateManager: PortsStateManager,
+    private val context: Context,
+) : SettingsPortForwardingBaseAdapter<SettingsPortForwardingActiveAdapter.ViewHolder>() {
 
     override fun getItems(): ArrayList<SettingsPortForwardingItem> {
-        val enabledPorts = mPortsStateManager.getEnabledPorts()
-        return mPortsStateManager
+        val enabledPorts = portsStateManager.getEnabledPorts()
+        return portsStateManager
             .getActivePorts()
             .map { SettingsPortForwardingItem(it, enabledPorts.contains(it)) }
             .toCollection(ArrayList())
@@ -47,13 +50,18 @@
     }
 
     override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
-        val port = mItems[position].port
-        viewHolder.port.text = port.toString()
+        val port = items[position].port
+        viewHolder.port.text =
+            context.getString(
+                R.string.settings_port_forwarding_active_ports_content,
+                port,
+                portsStateManager.getActivePortInfo(port)?.comm,
+            )
         viewHolder.enabledSwitch.contentDescription = viewHolder.port.text
         viewHolder.enabledSwitch.setOnCheckedChangeListener(null)
-        viewHolder.enabledSwitch.isChecked = mItems[position].enabled
+        viewHolder.enabledSwitch.isChecked = items[position].enabled
         viewHolder.enabledSwitch.setOnCheckedChangeListener { _, isChecked ->
-            mPortsStateManager.updateEnabledPort(port, isChecked)
+            portsStateManager.updateEnabledPort(port, isChecked)
         }
     }
 }
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
index b4ca77b..db3926d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
@@ -31,30 +31,30 @@
 private const val PORT_RANGE_MAX: Int = 65535
 
 class SettingsPortForwardingActivity : AppCompatActivity() {
-    private lateinit var mPortsStateManager: PortsStateManager
-    private lateinit var mPortsStateListener: Listener
-    private lateinit var mActivePortsAdapter: SettingsPortForwardingActiveAdapter
-    private lateinit var mInactivePortsAdapter: SettingsPortForwardingInactiveAdapter
+    private lateinit var portsStateManager: PortsStateManager
+    private lateinit var portsStateListener: Listener
+    private lateinit var activePortsAdapter: SettingsPortForwardingActiveAdapter
+    private lateinit var inactivePortsAdapter: SettingsPortForwardingInactiveAdapter
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.settings_port_forwarding)
 
-        mPortsStateManager = PortsStateManager.getInstance(this)
+        portsStateManager = PortsStateManager.getInstance(this)
 
-        mActivePortsAdapter = SettingsPortForwardingActiveAdapter(mPortsStateManager)
+        activePortsAdapter = SettingsPortForwardingActiveAdapter(portsStateManager, this)
         val activeRecyclerView: RecyclerView =
             findViewById(R.id.settings_port_forwarding_active_recycler_view)
         activeRecyclerView.layoutManager = LinearLayoutManager(this)
-        activeRecyclerView.adapter = mActivePortsAdapter
+        activeRecyclerView.adapter = activePortsAdapter
 
-        mInactivePortsAdapter = SettingsPortForwardingInactiveAdapter(mPortsStateManager, this)
+        inactivePortsAdapter = SettingsPortForwardingInactiveAdapter(portsStateManager, this)
         val inactiveRecyclerView: RecyclerView =
             findViewById(R.id.settings_port_forwarding_inactive_recycler_view)
         inactiveRecyclerView.layoutManager = LinearLayoutManager(this)
-        inactiveRecyclerView.adapter = mInactivePortsAdapter
+        inactiveRecyclerView.adapter = inactivePortsAdapter
 
-        mPortsStateListener = Listener()
+        portsStateListener = Listener()
 
         val addButton = findViewById<ImageButton>(R.id.settings_port_forwarding_inactive_add_button)
         addButton.setOnClickListener {
@@ -71,7 +71,7 @@
                                 R.id.settings_port_forwarding_inactive_add_dialog_text
                             )!!
                         val port = editText.text.toString().toInt()
-                        mPortsStateManager.updateEnabledPort(port, true)
+                        portsStateManager.updateEnabledPort(port, true)
                     }
                     .setNegativeButton(R.string.settings_port_forwarding_dialog_cancel, null)
                     .create()
@@ -121,8 +121,8 @@
                             )
                             positiveButton.setEnabled(false)
                         } else if (
-                            mPortsStateManager.getActivePorts().contains(port) ||
-                                mPortsStateManager.getEnabledPorts().contains(port)
+                            portsStateManager.getActivePorts().contains(port) ||
+                                portsStateManager.getEnabledPorts().contains(port)
                         ) {
                             editText.setError(
                                 getString(
@@ -141,19 +141,19 @@
 
     private fun refreshAdapters() {
         runOnUiThread {
-            mActivePortsAdapter.refreshItems()
-            mInactivePortsAdapter.refreshItems()
+            activePortsAdapter.refreshItems()
+            inactivePortsAdapter.refreshItems()
         }
     }
 
     override fun onResume() {
         super.onResume()
-        mPortsStateManager.registerListener(mPortsStateListener)
+        portsStateManager.registerListener(portsStateListener)
         refreshAdapters()
     }
 
     override fun onPause() {
-        mPortsStateManager.unregisterListener(mPortsStateListener)
+        portsStateManager.unregisterListener(portsStateListener)
         super.onPause()
     }
 
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
index 4595372..5b8d022 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingBaseAdapter.kt
@@ -21,10 +21,10 @@
 
 abstract class SettingsPortForwardingBaseAdapter<T : RecyclerView.ViewHolder>() :
     RecyclerView.Adapter<T>() {
-    var mItems: SortedList<SettingsPortForwardingItem>
+    var items: SortedList<SettingsPortForwardingItem>
 
     init {
-        mItems =
+        items =
             SortedList(
                 SettingsPortForwardingItem::class.java,
                 object : SortedListAdapterCallback<SettingsPortForwardingItem>(this) {
@@ -52,11 +52,11 @@
             )
     }
 
-    override fun getItemCount() = mItems.size()
+    override fun getItemCount() = items.size()
 
     abstract fun getItems(): ArrayList<SettingsPortForwardingItem>
 
     fun refreshItems() {
-        mItems.replaceAll(getItems())
+        items.replaceAll(getItems())
     }
 }
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
index d572129..e1fe468 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingInactiveAdapter.kt
@@ -24,14 +24,14 @@
 import androidx.recyclerview.widget.RecyclerView
 
 class SettingsPortForwardingInactiveAdapter(
-    private val mPortsStateManager: PortsStateManager,
-    private val mContext: Context,
+    private val portsStateManager: PortsStateManager,
+    private val context: Context,
 ) : SettingsPortForwardingBaseAdapter<SettingsPortForwardingInactiveAdapter.ViewHolder>() {
 
     override fun getItems(): ArrayList<SettingsPortForwardingItem> {
-        return mPortsStateManager
+        return portsStateManager
             .getEnabledPorts()
-            .subtract(mPortsStateManager.getActivePorts())
+            .subtract(portsStateManager.getActivePorts())
             .map { SettingsPortForwardingItem(it, true) }
             .toCollection(ArrayList())
     }
@@ -50,15 +50,15 @@
     }
 
     override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
-        val port = mItems[position].port
+        val port = items[position].port
         viewHolder.port.text = port.toString()
         viewHolder.closeButton.contentDescription =
-            mContext.getString(
+            context.getString(
                 R.string.settings_port_forwarding_other_enabled_port_close_button,
                 port,
             )
         viewHolder.closeButton.setOnClickListener { _ ->
-            mPortsStateManager.updateEnabledPort(port, false)
+            portsStateManager.updateEnabledPort(port, false)
         }
     }
 }
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
index a4d43b8..319a53b 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
@@ -22,7 +22,7 @@
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.view.isVisible
 import androidx.lifecycle.lifecycleScope
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import com.google.android.material.card.MaterialCardView
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.snackbar.Snackbar
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.kt b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.kt
index 18a39fa..4d9a89d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/TerminalView.kt
@@ -31,7 +31,7 @@
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.InputConnection
 import android.webkit.WebView
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import java.io.IOException
 
 class TerminalView(context: Context, attrs: AttributeSet?) :
@@ -94,7 +94,7 @@
     // AccessibilityDelegate to the parent view where the events are sent to. And to guarantee that
     // the parent view exists, wait until the WebView is attached to the window by when the parent
     // must exist.
-    private val mA11yEventFilter: AccessibilityDelegate =
+    private val a11yEventFilter: AccessibilityDelegate =
         object : AccessibilityDelegate() {
             override fun onRequestSendAccessibilityEvent(
                 host: ViewGroup,
@@ -122,11 +122,11 @@
         super.onAttachedToWindow()
         if (a11yManager.isEnabled) {
             val parent = getParent() as View
-            parent.setAccessibilityDelegate(mA11yEventFilter)
+            parent.setAccessibilityDelegate(a11yEventFilter)
         }
     }
 
-    private val mA11yNodeProvider: AccessibilityNodeProvider =
+    private val a11yNodeProvider: AccessibilityNodeProvider =
         object : AccessibilityNodeProvider() {
             /** Returns the original NodeProvider that WebView implements. */
             private fun getParent(): AccessibilityNodeProvider? {
@@ -262,7 +262,7 @@
     override fun getAccessibilityNodeProvider(): AccessibilityNodeProvider? {
         val p = super.getAccessibilityNodeProvider()
         if (p != null && a11yManager.isEnabled) {
-            return mA11yNodeProvider
+            return a11yNodeProvider
         }
         return p
     }
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
index 2796b86..8c0368d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/VmLauncherService.kt
@@ -36,7 +36,7 @@
 import android.system.virtualmachine.VirtualMachineException
 import android.util.Log
 import android.widget.Toast
-import com.android.virtualization.terminal.MainActivity.TAG
+import com.android.virtualization.terminal.MainActivity.Companion.TAG
 import com.android.virtualization.terminal.Runner.Companion.create
 import com.android.virtualization.terminal.VmLauncherService.VmLauncherServiceCallback
 import io.grpc.Grpc
@@ -60,12 +60,12 @@
 
 class VmLauncherService : Service() {
     // TODO: using lateinit for some fields to avoid null
-    private var mExecutorService: ExecutorService? = null
-    private var mVirtualMachine: VirtualMachine? = null
-    private var mResultReceiver: ResultReceiver? = null
-    private var mServer: Server? = null
-    private var mDebianService: DebianServiceImpl? = null
-    private var mPortNotifier: PortNotifier? = null
+    private var executorService: ExecutorService? = null
+    private var virtualMachine: VirtualMachine? = null
+    private var resultReceiver: ResultReceiver? = null
+    private var server: Server? = null
+    private var debianService: DebianServiceImpl? = null
+    private var portNotifier: PortNotifier? = null
 
     interface VmLauncherServiceCallback {
         fun onVmStart()
@@ -81,7 +81,7 @@
 
     override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
         if (intent.action == ACTION_STOP_VM_LAUNCHER_SERVICE) {
-            if (mDebianService != null && mDebianService!!.shutdownDebian()) {
+            if (debianService != null && debianService!!.shutdownDebian()) {
                 // During shutdown, change the notification content to indicate that it's closing
                 val notification = createNotificationForTerminalClose()
                 getSystemService<NotificationManager?>(NotificationManager::class.java)
@@ -92,11 +92,11 @@
             }
             return START_NOT_STICKY
         }
-        if (mVirtualMachine != null) {
+        if (virtualMachine != null) {
             Log.d(TAG, "VM instance is already started")
             return START_NOT_STICKY
         }
-        mExecutorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
+        executorService = Executors.newCachedThreadPool(TerminalThreadFactory(applicationContext))
 
         val image = InstalledImage.getDefault(this)
         val json = ConfigJson.from(this, image.configPath)
@@ -117,28 +117,28 @@
         Trace.endSection()
         Trace.beginAsyncSection("debianBoot", 0)
 
-        mVirtualMachine = runner.vm
-        mResultReceiver =
+        virtualMachine = runner.vm
+        resultReceiver =
             intent.getParcelableExtra<ResultReceiver?>(
                 Intent.EXTRA_RESULT_RECEIVER,
                 ResultReceiver::class.java,
             )
 
         runner.exitStatus.thenAcceptAsync { success: Boolean ->
-            mResultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
+            resultReceiver?.send(if (success) RESULT_STOP else RESULT_ERROR, null)
             stopSelf()
         }
-        val logPath = getFileStreamPath(mVirtualMachine!!.name + ".log").toPath()
-        Logger.setup(mVirtualMachine!!, logPath, mExecutorService!!)
+        val logPath = getFileStreamPath(virtualMachine!!.name + ".log").toPath()
+        Logger.setup(virtualMachine!!, logPath, executorService!!)
 
         val notification =
             intent.getParcelableExtra<Notification?>(EXTRA_NOTIFICATION, Notification::class.java)
 
         startForeground(this.hashCode(), notification)
 
-        mResultReceiver!!.send(RESULT_START, null)
+        resultReceiver!!.send(RESULT_START, null)
 
-        mPortNotifier = PortNotifier(this)
+        portNotifier = PortNotifier(this)
 
         // TODO: dedup this part
         val nsdManager = getSystemService<NsdManager?>(NsdManager::class.java)
@@ -147,7 +147,7 @@
         info.serviceName = "ttyd"
         nsdManager.registerServiceInfoCallback(
             info,
-            mExecutorService!!,
+            executorService!!,
             object : NsdManager.ServiceInfoCallback {
                 override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {}
 
@@ -245,11 +245,11 @@
         try {
             // TODO(b/372666638): gRPC for java doesn't support vsock for now.
             val port = 0
-            mDebianService = DebianServiceImpl(this)
-            mServer =
+            debianService = DebianServiceImpl(this)
+            server =
                 OkHttpServerBuilder.forPort(port, InsecureServerCredentials.create())
                     .intercept(interceptor)
-                    .addService(mDebianService)
+                    .addService(debianService)
                     .build()
                     .start()
         } catch (e: IOException) {
@@ -257,13 +257,13 @@
             return
         }
 
-        mExecutorService!!.execute(
+        executorService!!.execute(
             Runnable {
                 // TODO(b/373533555): we can use mDNS for that.
                 val debianServicePortFile = File(filesDir, "debian_service_port")
                 try {
                     FileOutputStream(debianServicePortFile).use { writer ->
-                        writer.write(mServer!!.port.toString().toByteArray())
+                        writer.write(server!!.port.toString().toByteArray())
                     }
                 } catch (e: IOException) {
                     Log.d(TAG, "cannot write grpc port number", e)
@@ -273,28 +273,28 @@
     }
 
     override fun onDestroy() {
-        mPortNotifier?.stop()
+        portNotifier?.stop()
         getSystemService<NotificationManager?>(NotificationManager::class.java).cancelAll()
         stopDebianServer()
-        if (mVirtualMachine != null) {
-            if (mVirtualMachine!!.getStatus() == VirtualMachine.STATUS_RUNNING) {
+        if (virtualMachine != null) {
+            if (virtualMachine!!.getStatus() == VirtualMachine.STATUS_RUNNING) {
                 try {
-                    mVirtualMachine!!.stop()
+                    virtualMachine!!.stop()
                     stopForeground(STOP_FOREGROUND_REMOVE)
                 } catch (e: VirtualMachineException) {
                     Log.e(TAG, "failed to stop a VM instance", e)
                 }
             }
-            mExecutorService?.shutdownNow()
-            mExecutorService = null
-            mVirtualMachine = null
+            executorService?.shutdownNow()
+            executorService = null
+            virtualMachine = null
         }
         super.onDestroy()
     }
 
     private fun stopDebianServer() {
-        mDebianService?.killForwarderHost()
-        mServer?.shutdown()
+        debianService?.killForwarderHost()
+        server?.shutdown()
     }
 
     companion object {
@@ -313,7 +313,6 @@
             return Intent(context.getApplicationContext(), VmLauncherService::class.java)
         }
 
-        @JvmStatic
         fun run(
             context: Context,
             callback: VmLauncherServiceCallback?,
@@ -345,7 +344,6 @@
             return ResultReceiver.CREATOR.createFromParcel(parcel).also { parcel.recycle() }
         }
 
-        @JvmStatic
         fun stop(context: Context) {
             val i = getMyIntent(context)
             i.setAction(ACTION_STOP_VM_LAUNCHER_SERVICE)
diff --git a/android/TerminalApp/res/layout/activity_error.xml b/android/TerminalApp/res/layout/activity_error.xml
index 054478f..c0409a7 100644
--- a/android/TerminalApp/res/layout/activity_error.xml
+++ b/android/TerminalApp/res/layout/activity_error.xml
@@ -51,7 +51,9 @@
         android:layout_marginTop="24dp"
         android:layout_marginHorizontal="60dp"
         android:layout_below="@id/desc"
-        android:textSize="14sp" />
+        android:textSize="14sp"
+        android:scrollbars="vertical|horizontal"
+        android:scrollHorizontally="true" />
 
     <Button
         android:id="@+id/recovery"
diff --git a/android/TerminalApp/res/layout/activity_headless.xml b/android/TerminalApp/res/layout/activity_headless.xml
index b4a65cc..e18aa5c 100644
--- a/android/TerminalApp/res/layout/activity_headless.xml
+++ b/android/TerminalApp/res/layout/activity_headless.xml
@@ -48,7 +48,6 @@
                 android:layout_height="wrap_content"/>
         </LinearLayout>
         <LinearLayout
-            android:id="@+id/webview_container"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_marginBottom="5dp"
@@ -59,7 +58,6 @@
                 android:layout_width="match_parent"
                 android:layout_height="0dp"
                 android:layout_weight="1" />
-            <include layout="@layout/layout_modifier_keys" />
         </LinearLayout>
     </FrameLayout>
 
diff --git a/android/TerminalApp/res/layout/layout_modifier_keys.xml b/android/TerminalApp/res/layout/modifier_keys_doubleline.xml
similarity index 100%
rename from android/TerminalApp/res/layout/layout_modifier_keys.xml
rename to android/TerminalApp/res/layout/modifier_keys_doubleline.xml
diff --git a/android/TerminalApp/res/layout/modifier_keys_singleline.xml b/android/TerminalApp/res/layout/modifier_keys_singleline.xml
new file mode 100644
index 0000000..6ccf48f
--- /dev/null
+++ b/android/TerminalApp/res/layout/modifier_keys_singleline.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 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.
+ -->
+<!--TODO(b/376813452): we might want tablet UI for that-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/modifier_keys"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal" >
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_esc"
+        android:textSize="10sp"
+        android:text="@string/btn_esc_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_tab"
+        android:textSize="10sp"
+        android:text="@string/btn_tab_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_ctrl"
+        android:textSize="10sp"
+        android:text="@string/btn_ctrl_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_alt"
+        android:textSize="10sp"
+        android:text="@string/btn_alt_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_home"
+        android:textSize="10sp"
+        android:text="@string/btn_home_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_end"
+        android:textSize="10sp"
+        android:text="@string/btn_end_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_left"
+        android:textSize="10sp"
+        android:text="@string/btn_left_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_down"
+        android:textSize="10sp"
+        android:text="@string/btn_down_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_up"
+        android:textSize="10sp"
+        android:text="@string/btn_up_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_right"
+        android:textSize="10sp"
+        android:text="@string/btn_right_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_pgdn"
+        android:textSize="10sp"
+        android:text="@string/btn_pgdn_text" />
+    <Button
+        style="@style/ModifierKeyStyle"
+        android:id="@+id/btn_pgup"
+        android:textSize="10sp"
+        android:text="@string/btn_pgup_text" />
+</LinearLayout>
diff --git a/android/TerminalApp/res/values-af/strings.xml b/android/TerminalApp/res/values-af/strings.xml
index 31046ae..eae5281 100644
--- a/android/TerminalApp/res/values-af/strings.xml
+++ b/android/TerminalApp/res/values-af/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Poortkontrole"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Laat luisterpoorte toe of weier hulle"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Luisterpoorte"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Het toegelate poorte gestoor"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Voeg by"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Vee <xliff:g id="PORT_NUMBER">%d</xliff:g> uit"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ongeldige poortnommer"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Poort bestaan reeds"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminaal probeer om ’n nuwe poort oop te maak"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Poort versoek: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aanvaar"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Weier"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Herwin"</string>
diff --git a/android/TerminalApp/res/values-am/strings.xml b/android/TerminalApp/res/values-am/strings.xml
index 8f7bd25..f76eab8 100644
--- a/android/TerminalApp/res/values-am/strings.xml
+++ b/android/TerminalApp/res/values-am/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"የወደብ ቁጥጥር"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"የማዳመጫ ወደቦችን ይፍቀዱ/ይከልክሉ"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"የማዳመጫ ወደቦች"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"የተቀመጡ የሚፈቀዱ ወደቦች"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"አክል"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>ን ሰርዝ"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ልክ ያልሆነ የወደብ ቁጥር"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ወደብ ቀድሞውኑ ይገኛል"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ተርሚናል አዲስ ወደብ ለመክፈት እየጠየቀ ነው"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"የተጠየቀ ወደብ፦ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ተቀበል"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ከልክል"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"መልሶ ማግኘት"</string>
diff --git a/android/TerminalApp/res/values-ar/strings.xml b/android/TerminalApp/res/values-ar/strings.xml
index 81dc053..c01460d 100644
--- a/android/TerminalApp/res/values-ar/strings.xml
+++ b/android/TerminalApp/res/values-ar/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"التحكّم في المنافذ"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"السماح بمنافذ الاستماع أو حظرها"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"منافذ الاستماع"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"المنافذ المسموح بها المحفوظة"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"إضافة"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"حذف <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"رقم المنفذ غير صالح"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"المنفذ متوفِّر حاليًا"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"تطلُب الوحدة الطرفية فتح منفذ جديد"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"المنفذ المطلوب: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"قبول"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"رفض"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"الاسترداد"</string>
diff --git a/android/TerminalApp/res/values-as/strings.xml b/android/TerminalApp/res/values-as/strings.xml
index 3f8d5f7..a773fad 100644
--- a/android/TerminalApp/res/values-as/strings.xml
+++ b/android/TerminalApp/res/values-as/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"প’ৰ্ট নিয়ন্ত্ৰণ"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"শুনা প’ৰ্টৰ অনুমতি দিয়ক/অস্বীকাৰ কৰক"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"শুনা প’ৰ্ট"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ছেভ কৰা অনুমোদিত প’ৰ্ট"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"যোগ দিয়ক"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> মচক"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"অমান্য প’ৰ্টৰ নম্বৰ"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"প’ৰ্ট ইতিমধ্যে আছে"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"টাৰ্মিনেলটোৱে এটা নতুন প’ৰ্ট খুলিবলৈ অনুৰোধ কৰি আছে"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"প\'ৰ্ট অনুৰোধ কৰা হৈছে: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"গ্ৰহণ কৰক"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"অস্বীকাৰ কৰক"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"পুনৰুদ্ধাৰ"</string>
diff --git a/android/TerminalApp/res/values-az/strings.xml b/android/TerminalApp/res/values-az/strings.xml
index 5870590..0e52500 100644
--- a/android/TerminalApp/res/values-az/strings.xml
+++ b/android/TerminalApp/res/values-az/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port nəzarəti"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dinləmə portlarına icazə verin/imtina edin"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Dinləmə portları"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Yadda saxlanılmış icazə verilən portlar"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Əlavə edin"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Silin: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Yanlış port nömrəsi"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port artıq mövcuddur"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal yeni port açmağı tələb edir"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port tələb edildi: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Qəbul edin"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rədd edin"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Bərpa"</string>
diff --git a/android/TerminalApp/res/values-b+sr+Latn/strings.xml b/android/TerminalApp/res/values-b+sr+Latn/strings.xml
index 9d46706..fdbd9c0 100644
--- a/android/TerminalApp/res/values-b+sr+Latn/strings.xml
+++ b/android/TerminalApp/res/values-b+sr+Latn/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrola porta"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dozvolite ili zabranite portove za slušanje"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portovi za slušanje"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Sačuvani dozvoljeni portovi"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Izbriši <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nevažeći broj porta"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port već postoji"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal traži da otvori novi port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Obavezan port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prihvati"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odbij"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Oporavak"</string>
diff --git a/android/TerminalApp/res/values-be/strings.xml b/android/TerminalApp/res/values-be/strings.xml
index 003e4f5..77a6538 100644
--- a/android/TerminalApp/res/values-be/strings.xml
+++ b/android/TerminalApp/res/values-be/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Кіраванне портам"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дазволіць (адмовіць) доступ да партоў праслухоўвання"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Парты праслухоўвання"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Захаваць дазволеныя парты"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Дадаць"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Выдаліць порт <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Няправільны нумар порта"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт ужо існуе"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Тэрмінал запытвае адкрыць новы порт"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Запытаны порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прыняць"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Адмовіць"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Аднаўленне"</string>
diff --git a/android/TerminalApp/res/values-bg/strings.xml b/android/TerminalApp/res/values-bg/strings.xml
index e55062c..d9c16df 100644
--- a/android/TerminalApp/res/values-bg/strings.xml
+++ b/android/TerminalApp/res/values-bg/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Контрол на портовете"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Разрешаване/отхвърляне на портовете за слушане"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Портове за слушане"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Запазени разрешени портове"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Добавяне"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Изтриване на <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Невалиден номер на порт"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Портът вече съществува"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминалът заявява отварянето на нов порт"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Заявен порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Приемам"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Отказ"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Възстановя­ване"</string>
diff --git a/android/TerminalApp/res/values-bn/strings.xml b/android/TerminalApp/res/values-bn/strings.xml
index 34f45a1..b25bc02 100644
--- a/android/TerminalApp/res/values-bn/strings.xml
+++ b/android/TerminalApp/res/values-bn/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"পোর্ট কন্ট্রোল"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"লিসিনিং পোর্টের অনুমতি দিন/অনুমতি দেবেন না"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"লিসিনিং পোর্ট"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"অনুমতি দেওয়া পোর্ট সেভ করা হয়েছে"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"যোগ করুন"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> মুছুন"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"পোর্ট নম্বর ভুল আছে"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"পোর্ট আগে থেকেই রয়েছে"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"টার্মিনাল নতুন পোর্ট খোলার অনুরোধ করছে"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"পোর্ট ফরওয়ার্ড করা সম্পর্কে অনুরোধ করা হয়েছে: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"সম্মতি দিন"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"বাতিল করুন"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"আগের অবস্থায় ফেরানো"</string>
diff --git a/android/TerminalApp/res/values-bs/strings.xml b/android/TerminalApp/res/values-bs/strings.xml
index 4ce1abd..8dcfe6f 100644
--- a/android/TerminalApp/res/values-bs/strings.xml
+++ b/android/TerminalApp/res/values-bs/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Upravljanje priključkom"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dozvoli/odbij priključke za slušanje"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Priključci za slušanje"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Sačuvani dozvoljeni priključci"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodavanje"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Brisanje priključka <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nevažeći broj priključka"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Priključak već postoji"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal zahtijeva otvaranje novog priključka"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Zatražen je priključak: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prihvati"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odbij"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Oporavak"</string>
diff --git a/android/TerminalApp/res/values-ca/strings.xml b/android/TerminalApp/res/values-ca/strings.xml
index cbb5b5b..0737ffe 100644
--- a/android/TerminalApp/res/values-ca/strings.xml
+++ b/android/TerminalApp/res/values-ca/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control de ports"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permet o denega els ports d\'escolta"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ports d\'escolta"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ports permesos desats"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Afegeix"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Suprimeix <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"El número de port no és vàlid"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"El port ja existeix"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"El terminal està sol·licitant obrir un port nou"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port sol·licitat: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepta"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Denega"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recuperació"</string>
diff --git a/android/TerminalApp/res/values-cs/strings.xml b/android/TerminalApp/res/values-cs/strings.xml
index 1206132..2ab202e 100644
--- a/android/TerminalApp/res/values-cs/strings.xml
+++ b/android/TerminalApp/res/values-cs/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ovládání portů"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Povolit/zakázat naslouchající porty"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Naslouchající porty"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Uložené povolené porty"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Přidat"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Smazat port <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Neplatné číslo portu"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port už existuje"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminál se pokouší otevřít nový port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Požadovaný port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Přijmout"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Zamítnout"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Obnovení"</string>
diff --git a/android/TerminalApp/res/values-da/strings.xml b/android/TerminalApp/res/values-da/strings.xml
index 8e8bc3f..6ef382f 100644
--- a/android/TerminalApp/res/values-da/strings.xml
+++ b/android/TerminalApp/res/values-da/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portstyring"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Tillad/afvis aktive porte"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Aktive porte"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gemte tilladte porte"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Tilføj"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Slet <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ugyldigt portnummer"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porten findes allerede"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalen anmoder om at åbne en ny port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port, der anmodes om: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Acceptér"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Afvis"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Gendannelse"</string>
diff --git a/android/TerminalApp/res/values-de/strings.xml b/android/TerminalApp/res/values-de/strings.xml
index 5d488c2..deb3db3 100644
--- a/android/TerminalApp/res/values-de/strings.xml
+++ b/android/TerminalApp/res/values-de/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portsteuerung"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Überwachungsports zulassen / ablehnen"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Überwachungsports"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gespeicherte zulässige Ports"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Hinzufügen"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"„<xliff:g id="PORT_NUMBER">%d</xliff:g>“ löschen"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ungültige Portnummer"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port ist bereits vorhanden"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal fordert an, einen neuen Port zu öffnen"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Angeforderter Port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Akzeptieren"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Ablehnen"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Wieder­herstellung"</string>
diff --git a/android/TerminalApp/res/values-el/strings.xml b/android/TerminalApp/res/values-el/strings.xml
index 15606c1..78cf235 100644
--- a/android/TerminalApp/res/values-el/strings.xml
+++ b/android/TerminalApp/res/values-el/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Έλεγχος θυρών"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Να επιτρέπονται/μην επιτρέπονται οι θύρες ακρόασης"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Θύρες ακρόασης"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Αποθηκευμένες επιτρεπόμενες θύρες"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Προσθήκη"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Διαγραφή θύρας <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Μη έγκυρος αριθμός θύρας"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Η θύρα υπάρχει ήδη"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Το τερματικό ζητά να ανοίξει μια νέα θύρα"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Ζητήθηκε θύρα: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Αποδοχή"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Απόρριψη"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Ανάκτηση"</string>
diff --git a/android/TerminalApp/res/values-en-rAU/strings.xml b/android/TerminalApp/res/values-en-rAU/strings.xml
index c02591c..805257f 100644
--- a/android/TerminalApp/res/values-en-rAU/strings.xml
+++ b/android/TerminalApp/res/values-en-rAU/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port requested: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
diff --git a/android/TerminalApp/res/values-en-rCA/strings.xml b/android/TerminalApp/res/values-en-rCA/strings.xml
index c02591c..f208e38 100644
--- a/android/TerminalApp/res/values-en-rCA/strings.xml
+++ b/android/TerminalApp/res/values-en-rCA/strings.xml
@@ -48,6 +48,7 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+    <string name="settings_port_forwarding_active_ports_content" msgid="1818090784030797758">"<xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +60,7 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port requested: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <string name="settings_port_forwarding_notification_content" msgid="779450349212040908">"Port requested: <xliff:g id="PORT_NUMBER">%1$d</xliff:g> (<xliff:g id="PROCESS_NAME">%2$s</xliff:g>)"</string>
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
diff --git a/android/TerminalApp/res/values-en-rGB/strings.xml b/android/TerminalApp/res/values-en-rGB/strings.xml
index c02591c..805257f 100644
--- a/android/TerminalApp/res/values-en-rGB/strings.xml
+++ b/android/TerminalApp/res/values-en-rGB/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port requested: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
diff --git a/android/TerminalApp/res/values-en-rIN/strings.xml b/android/TerminalApp/res/values-en-rIN/strings.xml
index c02591c..805257f 100644
--- a/android/TerminalApp/res/values-en-rIN/strings.xml
+++ b/android/TerminalApp/res/values-en-rIN/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Port control"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Allow/deny listening ports"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Listening ports"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saved allowed ports"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Add"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Delete <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid port number"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port already exists"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal is requesting to open a new port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port requested: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accept"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Deny"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recovery"</string>
diff --git a/android/TerminalApp/res/values-es-rUS/strings.xml b/android/TerminalApp/res/values-es-rUS/strings.xml
index 3aeb2f2..ba758ac 100644
--- a/android/TerminalApp/res/values-es-rUS/strings.xml
+++ b/android/TerminalApp/res/values-es-rUS/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control del puerto"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir o denegar los puertos de escucha"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Puertos de escucha"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Puertos permitidos guardados"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Agregar"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Borrar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"El número de puerto no es válido"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"El puerto ya existe"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"La terminal está solicitando abrir un puerto nuevo"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Puerto solicitado: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceptar"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rechazar"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recuperación"</string>
diff --git a/android/TerminalApp/res/values-es/strings.xml b/android/TerminalApp/res/values-es/strings.xml
index f7dfa95..5a2629c 100644
--- a/android/TerminalApp/res/values-es/strings.xml
+++ b/android/TerminalApp/res/values-es/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control de puerto"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir/Denegar puertos de escucha"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Puertos de escucha"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Puertos permitidos guardados"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Añadir"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eliminar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Número de puerto no válido"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"El puerto ya existe"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"El terminal está solicitando abrir un nuevo puerto"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Puerto solicitado: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceptar"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Denegar"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recuperación"</string>
diff --git a/android/TerminalApp/res/values-et/strings.xml b/android/TerminalApp/res/values-et/strings.xml
index affff44..e64729c 100644
--- a/android/TerminalApp/res/values-et/strings.xml
+++ b/android/TerminalApp/res/values-et/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portide haldamine"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Kuulamisportide lubamine/keelamine"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Kuulamispordid"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Salvestatud lubatud pordid"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Lisa"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Kustuta <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Sobimatu pordi number"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port on juba olemas"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal taotleb uue pordi avamist"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Taotletud port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Nõustu"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Keela"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Taastamine"</string>
diff --git a/android/TerminalApp/res/values-eu/strings.xml b/android/TerminalApp/res/values-eu/strings.xml
index e65c992..fde1d1d 100644
--- a/android/TerminalApp/res/values-eu/strings.xml
+++ b/android/TerminalApp/res/values-eu/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ataka kontrolatzeko aukerak"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Onartu/Baztertu ataka aktiboak"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ataka aktiboak"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gorde dira onartutako atakak"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Gehitu"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Ezabatu <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ataka-zenbakiak ez du balio"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Ataka jada badago"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalak beste ataka bat irekitzeko eskatu du"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Ataka hau eskatu da: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Onartu"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Ukatu"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Berreskuratzea"</string>
diff --git a/android/TerminalApp/res/values-fa/strings.xml b/android/TerminalApp/res/values-fa/strings.xml
index 7ce2713c9..b040c24 100644
--- a/android/TerminalApp/res/values-fa/strings.xml
+++ b/android/TerminalApp/res/values-fa/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"کنترل درگاه"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"مجاز/ رد کردن درگاه‌های گوش کردن"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"درگاه‌های گوش کردن"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"درگاه‌های مجاز ذخیره شدند"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"افزودن"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"حذف کردن <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"شماره درگاه نامعتبر است"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"درگاه ازقبل موجود است"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"پایانه می‌خواهد درگاه جدیدی باز کند"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"درگاه درخواست‌شده: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"پذیرفتن"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"رد کردن"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"بازیابی"</string>
diff --git a/android/TerminalApp/res/values-fi/strings.xml b/android/TerminalApp/res/values-fi/strings.xml
index 5d7a66b..5dcfadf 100644
--- a/android/TerminalApp/res/values-fi/strings.xml
+++ b/android/TerminalApp/res/values-fi/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Porttien ohjaus"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Salli/kiellä kuunteluportit"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Kuunteluportit"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Tallennetut sallitut portit"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Lisää"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Poista <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Virheellinen portin numero"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Portti on jo olemassa"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Pääte yrittää avata uuden portin"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Pyydetty portti: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Hyväksy"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Hylkää"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Palautus"</string>
diff --git a/android/TerminalApp/res/values-fr-rCA/strings.xml b/android/TerminalApp/res/values-fr-rCA/strings.xml
index 4a0a9c3..a320c62 100644
--- a/android/TerminalApp/res/values-fr-rCA/strings.xml
+++ b/android/TerminalApp/res/values-fr-rCA/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Contrôle du port"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Autoriser/Refuser les ports en mode Réception"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ports en mode Réception"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ports autorisés enregistrés"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ajouter"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Supprimer le port <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numéro de port incorrect"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Le port existe déjà"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Le terminal demande d\'ouvrir un nouveau port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port demandé : <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepter"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuser"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Récupération"</string>
diff --git a/android/TerminalApp/res/values-fr/strings.xml b/android/TerminalApp/res/values-fr/strings.xml
index f043582..edb91b4 100644
--- a/android/TerminalApp/res/values-fr/strings.xml
+++ b/android/TerminalApp/res/values-fr/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Contrôle de port"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Autoriser/refuser les ports d\'écoute"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ports d\'écoute"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ports autorisés enregistrés"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ajouter"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Supprimer <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numéro de port incorrect"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Le port existe déjà"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Le terminal demande l\'ouverture d\'un nouveau port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port demandé : <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepter"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuser"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Récupération"</string>
diff --git a/android/TerminalApp/res/values-gl/strings.xml b/android/TerminalApp/res/values-gl/strings.xml
index 6435389..c1d4f82 100644
--- a/android/TerminalApp/res/values-gl/strings.xml
+++ b/android/TerminalApp/res/values-gl/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Control de portos"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir ou rexeitar portos de escoita"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portos de escoita"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Gardáronse os portos permitidos"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Engadir"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eliminar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"O número de porto non é válido"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Xa existe o porto"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"O terminal está solicitando que se abra outro porto"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Porto solicitado: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceptar"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Denegar"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recuperación"</string>
diff --git a/android/TerminalApp/res/values-gu/strings.xml b/android/TerminalApp/res/values-gu/strings.xml
index c21c364..b1a452f 100644
--- a/android/TerminalApp/res/values-gu/strings.xml
+++ b/android/TerminalApp/res/values-gu/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"પોર્ટ નિયંત્રણ"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"સાંભળનાર પોર્ટને મંજૂરી આપો/નકારો"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"સાંભળનાર પોર્ટ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"સાચવેલા મંજૂરીપ્રાપ્ત પોર્ટ"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ઉમેરો"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ડિલીટ કરો"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"પોર્ટ નંબર અમાન્ય છે"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"પોર્ટ પહેલેથી અસ્તિત્વમાં છે"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ટર્મિનલ નવું પોર્ટ ખોલવા માટે વિનંતી કરી રહ્યું છે"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"પોર્ટની વિનંતી કરવામાં આવી: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"સ્વીકારો"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"નકારો"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"રિકવરી"</string>
diff --git a/android/TerminalApp/res/values-hi/strings.xml b/android/TerminalApp/res/values-hi/strings.xml
index e0242d3..af2ddaa 100644
--- a/android/TerminalApp/res/values-hi/strings.xml
+++ b/android/TerminalApp/res/values-hi/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"पोर्ट कंट्रोल"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"लिसनिंग पोर्ट को अनुमति दें या अनुमति न दें"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"लिसनिंग पोर्ट"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"अनुमति पा चुके सभी पोर्ट को सेव किया गया"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"जोड़ें"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> को मिटाएं"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"अमान्य पोर्ट संख्या"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"पोर्ट पहले से मौजूद है"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"टर्मिनल, एक नया पोर्ट खोलने का अनुरोध कर रहा है"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"पोर्ट खोलने का अनुरोध किया गया: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"स्वीकार करें"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"अस्वीकार करें"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"इमेज रिकवर करें"</string>
diff --git a/android/TerminalApp/res/values-hr/strings.xml b/android/TerminalApp/res/values-hr/strings.xml
index 7027632..87d4798 100644
--- a/android/TerminalApp/res/values-hr/strings.xml
+++ b/android/TerminalApp/res/values-hr/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrola priključka"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dopusti/odbij priključke za slušanje"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Priključci za slušanje"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Spremljeni dopušteni priključci"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Izbriši priključak <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nevažeći broj priključka"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Priključak već postoji"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal zahtijeva da se otvori novi priključak"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Zatraženi priključak: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prihvati"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odbij"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Oporavak"</string>
diff --git a/android/TerminalApp/res/values-hu/strings.xml b/android/TerminalApp/res/values-hu/strings.xml
index 8195547..e1b17e6 100644
--- a/android/TerminalApp/res/values-hu/strings.xml
+++ b/android/TerminalApp/res/values-hu/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portvezérlés"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Figyelő portok engedélyezése/letiltása"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Figyelő portok"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Mentett engedélyezett portok"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Hozzáadás"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> törlése"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Érvénytelen a portszám"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"A port már létezik"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"A terminál új port megnyitását kéri"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Kért port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Elfogadás"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Elutasítás"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Helyreállítás"</string>
diff --git a/android/TerminalApp/res/values-hy/strings.xml b/android/TerminalApp/res/values-hy/strings.xml
index ecf0cb9..06ae4cb 100644
--- a/android/TerminalApp/res/values-hy/strings.xml
+++ b/android/TerminalApp/res/values-hy/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Միացքների կառավարում"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Թույլատրել/մերժել ունկնդրման միացքները"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Ունկնդրման միացքներ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Պահված թույլատրված միացքներ"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ավելացնել"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Ջնջել <xliff:g id="PORT_NUMBER">%d</xliff:g> համարի միացքը"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Միացքի անվավեր համար"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Միացքն արդեն գոյություն ունի"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Տերմինալը խնդրում է նոր միացք բացել"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Հարցված միացքը՝ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Ընդունել"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Մերժել"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Վերականգ­նում"</string>
diff --git a/android/TerminalApp/res/values-in/strings.xml b/android/TerminalApp/res/values-in/strings.xml
index c8d16f3..1a844b1 100644
--- a/android/TerminalApp/res/values-in/strings.xml
+++ b/android/TerminalApp/res/values-in/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrol port"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Izinkan/tolak port yang sedang dalam proses"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Port yang sedang dalam proses"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Port yang diizinkan tersimpan"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Tambahkan"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Hapus <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nomor port tidak valid"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port sudah ada"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal meminta untuk membuka port baru"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port yang diminta: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Terima"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Tolak"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Pemulihan"</string>
diff --git a/android/TerminalApp/res/values-is/strings.xml b/android/TerminalApp/res/values-is/strings.xml
index 277e807..638da38 100644
--- a/android/TerminalApp/res/values-is/strings.xml
+++ b/android/TerminalApp/res/values-is/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Gáttarstýring"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Leyfa hlustunargáttir/hafna hlustunargáttum"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Hlustunargáttir"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Vistaðar leyfðar gáttir"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Bæta við"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eyða <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ógilt númer tengis"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Tengi er þegar til"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Útstöðin bað um að opna nýja gátt"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Beiðni um gátt: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Samþykkja"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Hafna"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Endurheimt"</string>
diff --git a/android/TerminalApp/res/values-it/strings.xml b/android/TerminalApp/res/values-it/strings.xml
index 8dfb347..5660cc3 100644
--- a/android/TerminalApp/res/values-it/strings.xml
+++ b/android/TerminalApp/res/values-it/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controllo porte"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Consenti/rifiuta porte di ascolto"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porte di ascolto"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Porte consentite salvate"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Aggiungi"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Elimina <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numero di porta non valido"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"La porta esiste già"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Il terminale sta chiedendo di aprire una nuova porta"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Porta richiesta: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accetta"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rifiuta"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Ripristino"</string>
diff --git a/android/TerminalApp/res/values-iw/strings.xml b/android/TerminalApp/res/values-iw/strings.xml
index 91e768e..3ea2227 100644
--- a/android/TerminalApp/res/values-iw/strings.xml
+++ b/android/TerminalApp/res/values-iw/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"בקרת יציאות"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"אישור או דחייה של יציאות להאזנה"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"יציאות להאזנה"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"יציאות מורשות שנשמרו"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"הוספה"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"מחיקה של <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"מספר היציאה לא תקין"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"היציאה כבר קיימת"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"הטרמינל מבקש לפתוח יציאה חדשה"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"נשלחה בקשה ליציאה: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"אישור"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"דחייה"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"שחזור"</string>
diff --git a/android/TerminalApp/res/values-ja/strings.xml b/android/TerminalApp/res/values-ja/strings.xml
index b4c1cd9..bcc3378 100644
--- a/android/TerminalApp/res/values-ja/strings.xml
+++ b/android/TerminalApp/res/values-ja/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ポートの管理"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"リスニング ポートの許可 / 拒否"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"リスニング ポート"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"保存済みの許可ポート"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"追加"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> を削除"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ポート番号が無効です"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ポートはすでに存在します"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ターミナルが新しいポートを開くリクエストをしました"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"移行リクエスト済み: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"許可する"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"許可しない"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"リカバリ"</string>
diff --git a/android/TerminalApp/res/values-ka/strings.xml b/android/TerminalApp/res/values-ka/strings.xml
index c2c500f..51960f6 100644
--- a/android/TerminalApp/res/values-ka/strings.xml
+++ b/android/TerminalApp/res/values-ka/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"პორტის მართვა"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"მოსმენის პორტების დაშვება/აკრძალვა"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"მოსმენის პორტები"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"შენახული დაშვებული პორტები"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"დამატება"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>-ის წაშლა"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"პორტის არასწორი ნომერი"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"პორტი უკვე არსებობს"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ტერმინალი ითხოვს ახალი პორტის გახსნას"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"მოთხოვნილი პორტი: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"დათანხმება"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"უარყოფა"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"აღდგენა"</string>
diff --git a/android/TerminalApp/res/values-kk/strings.xml b/android/TerminalApp/res/values-kk/strings.xml
index d8c49bd..ea12254 100644
--- a/android/TerminalApp/res/values-kk/strings.xml
+++ b/android/TerminalApp/res/values-kk/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Портты басқару"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Тыңдау порттарына рұқсат беру/тыйым салу"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Тыңдау порттары"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Рұқсат берілген порттар сақталды"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Қосу"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> портты жою"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Порт нөмірі жарамсыз."</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт бұрыннан бар."</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал жаңа порт ашуды сұрайды"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Қажетті порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Қабылдау"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Қабылдамау"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Қалпына келтіру"</string>
diff --git a/android/TerminalApp/res/values-km/strings.xml b/android/TerminalApp/res/values-km/strings.xml
index 28a1620..d85ead9 100644
--- a/android/TerminalApp/res/values-km/strings.xml
+++ b/android/TerminalApp/res/values-km/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ការគ្រប់គ្រងច្រក"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"អនុញ្ញាត/បដិសេធច្រកស្ដាប់"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ច្រកស្ដាប់"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"បានរក្សាទុកច្រកដែលត្រូវបានអនុញ្ញាត"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"បញ្ចូល"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"លុប <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"លេខច្រកមិនត្រឹមត្រូវ"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"មានច្រករួចហើយ"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ទែមីណាល់កំពុងស្នើសុំបើកច្រកថ្មី"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"បានស្នើសុំច្រក៖ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ទទួលយក"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"បដិសេធ"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"ស្ដារ"</string>
diff --git a/android/TerminalApp/res/values-kn/strings.xml b/android/TerminalApp/res/values-kn/strings.xml
index a17c185..8010e73 100644
--- a/android/TerminalApp/res/values-kn/strings.xml
+++ b/android/TerminalApp/res/values-kn/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ಪೋರ್ಟ್ ನಿಯಂತ್ರಣ"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ಆಲಿಸುವ ಪೋರ್ಟ್‌ಗಳನ್ನು ಅನುಮತಿಸಿ/ನಿರಾಕರಿಸಿ"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ಆಲಿಸುವ ಪೋರ್ಟ್‌ಗಳು"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ಅನುಮತಿಸಲಾದ ಪೋರ್ಟ್‌ಗಳನ್ನು ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ಸೇರಿಸಿ"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ಅನ್ನು ಅಳಿಸಿ"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ಅಮಾನ್ಯ ಪೋರ್ಟ್ ಸಂಖ್ಯೆ"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ಪೋರ್ಟ್ ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ಟರ್ಮಿನಲ್‌ ಹೊಸ ಪೋರ್ಟ್‌ ಅನ್ನು ತೆರೆಯಲು ವಿನಂತಿಸುತ್ತಿದೆ"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"ಪೋರ್ಟ್ ಅನ್ನು ವಿನಂತಿಸಲಾಗಿದೆ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ಸಮ್ಮತಿಸಿ"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ನಿರಾಕರಿಸಿ"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"ರಿಕವರಿ"</string>
diff --git a/android/TerminalApp/res/values-ko/strings.xml b/android/TerminalApp/res/values-ko/strings.xml
index 9ecaca7..173cade 100644
--- a/android/TerminalApp/res/values-ko/strings.xml
+++ b/android/TerminalApp/res/values-ko/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"포트 제어"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"리스닝 포트 허용/거부"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"리스닝 포트"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"저장된 허용 포트"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"추가"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> 삭제"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"포트 번호가 잘못되었습니다."</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"포트가 이미 존재합니다."</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"터미널에서 새 포트를 열려고 합니다"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"요청된 포트: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"수락"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"거부"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"복구"</string>
diff --git a/android/TerminalApp/res/values-ky/strings.xml b/android/TerminalApp/res/values-ky/strings.xml
index 9268dae..21d0e2a 100644
--- a/android/TerminalApp/res/values-ky/strings.xml
+++ b/android/TerminalApp/res/values-ky/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Портту көзөмөлдөө"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Угуу портторуна уруксат берүү/тыюу салуу"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Угуу порттору"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Уруксат берилген порттор сакталды"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Кошуу"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Өчүрүү: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Порттун номери жараксыз"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт бар"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал жаңы оюкчаны ачууну суранып жатат"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Оюкча суралды: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Кабыл алуу"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Четке кагуу"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Калыбына келтирүү"</string>
diff --git a/android/TerminalApp/res/values-lo/strings.xml b/android/TerminalApp/res/values-lo/strings.xml
index 7854f77..109a304 100644
--- a/android/TerminalApp/res/values-lo/strings.xml
+++ b/android/TerminalApp/res/values-lo/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ການຄວບຄຸມຜອດ"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ອະນຸຍາດ/ປະຕິເສດຜອດການຟັງ"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ຜອດການຟັງ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ຜອດທີ່ອະນຸຍາດເຊິ່ງບັນທຶກໄວ້"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ເພີ່ມ"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"ລຶບ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ໝາຍເລກຜອດບໍ່ຖືກຕ້ອງ"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ມີຜອດຢູ່ກ່ອນແລ້ວ"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ເທີມິນອນກຳລັງສົ່ງຄຳຮ້ອງຂໍໃຫ້ເປີດຜອດໃໝ່"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"ຜອດທີ່ຮ້ອງຂໍ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ຍອມຮັບ"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ປະຕິເສດ"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"ການກູ້ຄືນ"</string>
diff --git a/android/TerminalApp/res/values-lt/strings.xml b/android/TerminalApp/res/values-lt/strings.xml
index 919c4ef..beefadd 100644
--- a/android/TerminalApp/res/values-lt/strings.xml
+++ b/android/TerminalApp/res/values-lt/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Prievado valdymas"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Leisti klausymo prievadus / neleisti jų"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Klausymo prievadai"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Išsaugoti leidžiami prievadai"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Pridėti"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Ištrinti <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Netinkamas prievado numeris"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Prievadas jau yra"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalas bando atidaryti naują prievadą"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Prievadas, kurio užklausa pateikta: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Sutikti"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Atmesti"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Atkūrimas"</string>
diff --git a/android/TerminalApp/res/values-lv/strings.xml b/android/TerminalApp/res/values-lv/strings.xml
index b888f53..d45aeb3 100644
--- a/android/TerminalApp/res/values-lv/strings.xml
+++ b/android/TerminalApp/res/values-lv/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portu kontrole"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Atļaut/aizliegt klausīšanās portus"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Klausīšanās porti"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Saglabātie atļautie porti"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Pievienot"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Dzēst <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nederīgs porta numurs"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Ports jau pastāv"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminālis pieprasa jauna porta atvēršanu"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Pieprasītais ports: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Piekrist"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Noraidīt"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Atkopšana"</string>
@@ -77,7 +80,7 @@
     <string name="settings_recovery_remove_backup_title" msgid="1540850288876158899">"Dublējuma datu noņemšana"</string>
     <string name="settings_recovery_remove_backup_sub_title" msgid="7791375988320242059">"Datu noņemšana no ceļa <xliff:g id="PATH">/mnt/backup</xliff:g>"</string>
     <string name="error_title" msgid="405150657301906598">"Neatkopjama kļūda"</string>
-    <string name="error_desc" msgid="4588252235686826721">"Neizdevās veikt atkopšanu pēc kļūdas.\nVarat restartēt termināli vai izmēģināt kādu no atkopšanas opcijām.\nJa neviens mēģinājums neizdodas, notīriet visus datus, izstrādātāja opcijās ieslēdzot/izslēdzot Linux termināli."</string>
+    <string name="error_desc" msgid="4588252235686826721">"Neizdevās veikt atkopšanu pēc kļūdas.\nVarat restartēt termināli vai izmēģināt kādu no atkopšanas opcijām.\nJa neviens mēģinājums neizdodas, notīriet visus datus, izstrādātāju opcijās ieslēdzot/izslēdzot Linux termināli."</string>
     <string name="error_code" msgid="3585291676855383649">"Kļūdas kods: <xliff:g id="ERROR_CODE">%s</xliff:g>"</string>
     <string name="service_notification_settings" msgid="1437365721184401135">"Iestatījumi"</string>
     <string name="service_notification_title" msgid="2918088850910713393">"Terminālis darbojas"</string>
diff --git a/android/TerminalApp/res/values-mk/strings.xml b/android/TerminalApp/res/values-mk/strings.xml
index 123074c..99cc48c 100644
--- a/android/TerminalApp/res/values-mk/strings.xml
+++ b/android/TerminalApp/res/values-mk/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Контрола на портите"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дозволете/одбијте порти за примање барања"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Порти за примање барања"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Дозволените порти се зачувани"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Додај"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Избриши <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Неважечки број на порта"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Портата веќе постои"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминалот бара да отвори нова порта"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Побарана е порта: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прифати"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Одбиј"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Враќање"</string>
diff --git a/android/TerminalApp/res/values-ml/strings.xml b/android/TerminalApp/res/values-ml/strings.xml
index edf01b7..c2bab30 100644
--- a/android/TerminalApp/res/values-ml/strings.xml
+++ b/android/TerminalApp/res/values-ml/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"പോർട്ട് നിയന്ത്രണം"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ശ്രവണ പോർട്ടുകൾ അനുവദിക്കുക/നിരസിക്കുക"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ശ്രവണ പോർട്ടുകൾ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"സംരക്ഷിച്ച അനുവദനീയമായ പോർട്ടുകൾ"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ചേർക്കുക"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ഇല്ലാതാക്കുക"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"പോർട്ട് നമ്പർ അസാധുവാണ്"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"പോർട്ട് ഇതിനകം നിലവിലുണ്ട്"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ഒരു പുതിയ പോർട്ട് തുറക്കാൻ ടെർമിനൽ അഭ്യർത്ഥിക്കുന്നു"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"പോർട്ട് അഭ്യർത്ഥിച്ചു: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"അംഗീകരിക്കുക"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"നിരസിക്കുക"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"വീണ്ടെടുക്കുക"</string>
diff --git a/android/TerminalApp/res/values-mn/strings.xml b/android/TerminalApp/res/values-mn/strings.xml
index 20a5925..4849006 100644
--- a/android/TerminalApp/res/values-mn/strings.xml
+++ b/android/TerminalApp/res/values-mn/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Портын тохиргоо"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Сүлжээний хүсэлт хүлээж буй портуудыг зөвшөөрөх/татгалзах"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Сүлжээний хүсэлт хүлээж буй портууд"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Хадгалсан зөвшөөрөгдсөн портууд"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Нэмэх"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>-г устгах"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Портын дугаар буруу байна"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт аль хэдийн байна"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал шинэ порт нээхийг хүсэж байна"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Хүссэн порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Зөвшөөрөх"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Татгалзах"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Сэргээх"</string>
diff --git a/android/TerminalApp/res/values-mr/strings.xml b/android/TerminalApp/res/values-mr/strings.xml
index eb5e53c..70a093e 100644
--- a/android/TerminalApp/res/values-mr/strings.xml
+++ b/android/TerminalApp/res/values-mr/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"पोर्ट नियंत्रण"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ऐकण्याच्या पोर्टना अनुमती द्या/नाकारा"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ऐकण्याचे पोर्ट"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"सेव्ह केलेले व अनुमती असलेले पोर्ट"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"जोडा"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> हटवा"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"पोर्ट नंबर चुकीचा आहे"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"पोर्ट आधीपासून अस्तित्वात आहे"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"टर्मिनल नवीन पोर्ट उघडण्याची विनंती करत आहे"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"विनंती केलेला पोर्ट: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"स्वीकारा"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"नकार द्या"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"रिकव्हरी"</string>
diff --git a/android/TerminalApp/res/values-ms/strings.xml b/android/TerminalApp/res/values-ms/strings.xml
index 07d2221..a14d938 100644
--- a/android/TerminalApp/res/values-ms/strings.xml
+++ b/android/TerminalApp/res/values-ms/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kawalan port"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Benarkan/tolak port mendengar"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Port mendengar"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Port yang dibenarkan disimpan"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Tambah"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Padamkan <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nombor port tidak sah"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port sudah wujud"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal membuat permintaan untuk membuka port baharu"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port diminta: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Terima"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Tolak"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Pemulihan"</string>
diff --git a/android/TerminalApp/res/values-my/strings.xml b/android/TerminalApp/res/values-my/strings.xml
index 815dd19..eda6e90 100644
--- a/android/TerminalApp/res/values-my/strings.xml
+++ b/android/TerminalApp/res/values-my/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ပို့တ်ထိန်းချုပ်မှု"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"စောင့်နေသောပို့တ်များကို ခွင့်ပြုရန်/ငြင်းပယ်ရန်"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"စောင့်နေသောပို့တ်များ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ခွင့်ပြုထားသောပို့တ်များ သိမ်းပြီးပြီ"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ထည့်ရန်"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ကို ဖျက်ရန်"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ပို့တ်နံပါတ် မမှန်ပါ"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ပို့တ်ရှိပြီးသားဖြစ်သည်"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"တာမီနယ်က ပို့တ်အသစ်ဖွင့်ရန် တောင်းဆိုနေသည်"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"တောင်းဆိုထားသော ပို့တ်- <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"လက်ခံရန်"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ငြင်းပယ်ရန်"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"ပြန်လည်ရယူခြင်း"</string>
diff --git a/android/TerminalApp/res/values-nb/strings.xml b/android/TerminalApp/res/values-nb/strings.xml
index 1423e22..b2492db 100644
--- a/android/TerminalApp/res/values-nb/strings.xml
+++ b/android/TerminalApp/res/values-nb/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portkontroll"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Tillat/avslå lytteporter"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Lytteporter"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Lagrede tillatte porter"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Legg til"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Slett <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ugyldig portnummer"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porten finnes allerede"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalen prøver å åpne en ny port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Forespurt port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Godta"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Avvis"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Gjenoppretting"</string>
diff --git a/android/TerminalApp/res/values-ne/strings.xml b/android/TerminalApp/res/values-ne/strings.xml
index 025cfe5..714dcf3 100644
--- a/android/TerminalApp/res/values-ne/strings.xml
+++ b/android/TerminalApp/res/values-ne/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"पोर्टसम्बन्धी कन्ट्रोल"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"लिसनिङ पोर्टहरू हाल्ने अनुमति दिनुहोस्/नदिनुहोस्"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"लिसनिङ पोर्टहरू"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"सेभ गरिएका अनुमति दिइएका पोर्टहरू"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"हाल्नुहोस्"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> मेटाउनुहोस्"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"अवैध पोर्ट नम्बर"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"पोर्ट पहिल्यैदेखि छ"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"टर्मिनलले एउटा नयाँ पोर्ट खोल्न अनुरोध गरिरहेको छ"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"निम्न पोर्ट खोल्न अनुरोध गरिएको छ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"स्वीकार गर्नुहोस्"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"अस्वीकार गर्नुहोस्"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"रिकभरी"</string>
diff --git a/android/TerminalApp/res/values-nl/strings.xml b/android/TerminalApp/res/values-nl/strings.xml
index 8f68f11..6c1e42a 100644
--- a/android/TerminalApp/res/values-nl/strings.xml
+++ b/android/TerminalApp/res/values-nl/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Poortcontrole"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Luisterende poorten toestaan/weigeren"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Luisterende poorten"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Toegestane poorten opgeslagen"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Toevoegen"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> verwijderen"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ongeldig poortnummer"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Poort bestaat al"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal verzoekt om een nieuwe poort te openen"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Poort aangevraagd: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Accepteren"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Weigeren"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Herstel"</string>
diff --git a/android/TerminalApp/res/values-or/strings.xml b/android/TerminalApp/res/values-or/strings.xml
index c6a67ae..29855af 100644
--- a/android/TerminalApp/res/values-or/strings.xml
+++ b/android/TerminalApp/res/values-or/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ପୋର୍ଟ ନିୟନ୍ତ୍ରଣ"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ଶୁଣିବା ପୋର୍ଟଗୁଡ଼ିକୁ ଅନୁମତି ଦିଅନ୍ତୁ/ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ଶୁଣିବା ପୋର୍ଟ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ଅନୁମତି ଦିଆଯାଇଥିବା ପୋର୍ଟଗୁଡ଼ିକୁ ସେଭ କରାଯାଇଛି"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ଯୋଗ କରନ୍ତୁ"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>କୁ ଡିଲିଟ କରନ୍ତୁ"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ଅବୈଧ ପୋର୍ଟ ନମ୍ବର"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ପୋର୍ଟ ପୂର୍ବରୁ ଉପଲବ୍ଧ ଅଛି"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ଏକ ନୂଆ ପୋର୍ଟ ଖୋଲିବାକୁ ଟର୍ମିନାଲ ଅନୁରୋଧ କରୁଛି"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"ପୋର୍ଟ ପାଇଁ ଅନୁରୋଧ କରାଯାଇଛି: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ଗ୍ରହଣ କରନ୍ତୁ"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"ରିକଭରି"</string>
diff --git a/android/TerminalApp/res/values-pa/strings.xml b/android/TerminalApp/res/values-pa/strings.xml
index 3639329..a4279ce 100644
--- a/android/TerminalApp/res/values-pa/strings.xml
+++ b/android/TerminalApp/res/values-pa/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"ਪੋਰਟ ਕੰਟਰੋਲ"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"ਲਿਸਨਿੰਗ ਪੋਰਟਾਂ ਨੂੰ ਆਗਿਆ ਦਿਓ/ਅਸਵੀਕਾਰ ਕਰੋ"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"ਲਿਸਨਿੰਗ ਪੋਰਟ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"ਮਨਜ਼ੂਰਸ਼ੁਦਾ ਪੋਰਟ ਰੱਖਿਅਤ ਕੀਤੇ ਗਏ"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ਨੂੰ ਮਿਟਾਓ"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"ਅਵੈਧ ਪੋਰਟ ਨੰਬਰ"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"ਪੋਰਟ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ਟਰਮੀਨਲ ਇੱਕ ਨਵੇਂ ਪੋਰਟ ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਬੇਨਤੀ ਕਰ ਰਿਹਾ ਹੈ"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"ਪੋਰਟ ਸੰਬੰਧੀ ਬੇਨਤੀ ਕੀਤੀ ਗਈ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ਸਵੀਕਾਰ ਕਰੋ"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"ਰਿਕਵਰੀ"</string>
diff --git a/android/TerminalApp/res/values-pl/strings.xml b/android/TerminalApp/res/values-pl/strings.xml
index 485f7bb..924c14c 100644
--- a/android/TerminalApp/res/values-pl/strings.xml
+++ b/android/TerminalApp/res/values-pl/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrola portów"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Zezwalaj/odrzucaj porty nasłuchujące"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porty nasłuchujące"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Zapisane dozwolone porty"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Usuń port <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Nieprawidłowy numer portu"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port już istnieje"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal wysłał żądanie otwarcia nowego portu"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Żądany port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Zaakceptuj"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Odrzuć"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Odzyskiwanie"</string>
diff --git a/android/TerminalApp/res/values-pt-rPT/strings.xml b/android/TerminalApp/res/values-pt-rPT/strings.xml
index f98fa0d..3a57ba6 100644
--- a/android/TerminalApp/res/values-pt-rPT/strings.xml
+++ b/android/TerminalApp/res/values-pt-rPT/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controlo de portas"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir/negar portas de audição"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portas de audição"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Portas permitidas guardadas"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Adicionar"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Eliminar <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Número de porta inválido"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"A porta já existe"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"O terminal está a pedir para abrir uma nova porta"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Porta pedida: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceitar"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Recusar"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recuperação"</string>
diff --git a/android/TerminalApp/res/values-pt/strings.xml b/android/TerminalApp/res/values-pt/strings.xml
index 9365db7..9d6a16f 100644
--- a/android/TerminalApp/res/values-pt/strings.xml
+++ b/android/TerminalApp/res/values-pt/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controle de portas"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permitir/negar portas de detecção"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portas de detecção"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"As portas permitidas foram salvas"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Adicionar"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Excluir <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Número de porta inválido"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"A porta já existe"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"O terminal está pedindo para abrir uma nova porta"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Porta solicitada: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Aceitar"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Negar"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recuperação"</string>
diff --git a/android/TerminalApp/res/values-ro/strings.xml b/android/TerminalApp/res/values-ro/strings.xml
index 2931361..779277e 100644
--- a/android/TerminalApp/res/values-ro/strings.xml
+++ b/android/TerminalApp/res/values-ro/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Controlul porturilor"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Permite / refuză porturile active"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porturi active"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Porturi permise salvate"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Adaugă"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Șterge <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Număr de port nevalid"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Portul există deja"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalul solicită să deschidă un nou port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Portul solicitat: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Acceptă"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuză"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Recuperare"</string>
diff --git a/android/TerminalApp/res/values-ru/strings.xml b/android/TerminalApp/res/values-ru/strings.xml
index e1cc4b4..ffdcaf6 100644
--- a/android/TerminalApp/res/values-ru/strings.xml
+++ b/android/TerminalApp/res/values-ru/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Управление портами"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Открыть/закрыть доступ к портам прослушивания"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Порты прослушивания"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Сохраненные порты с открытым доступом"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Добавить"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Удалить <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Неверный номер порта."</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт уже существует."</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал просит открыть новый порт"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Запрашиваемый порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>."</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Разрешить"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Не разрешать"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Восста­но­вле­ние"</string>
diff --git a/android/TerminalApp/res/values-si/strings.xml b/android/TerminalApp/res/values-si/strings.xml
index d1bbd82..cc67088 100644
--- a/android/TerminalApp/res/values-si/strings.xml
+++ b/android/TerminalApp/res/values-si/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"පෝටය පාලනය"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"සවන්දීමේ පෝටයන්ට ඉඩ දෙන්න/ප්‍රතික්ෂේප කරන්න"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"සවන්දීමේ පෝටයන්"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"සුරකින ලද ඉඩ දුන් පෝටයන්"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"එක් කරන්න"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> මකන්න"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"වලංගු නොවන පෝට අංකය"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"පෝටය දැනටමත් පවතී"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ටර්මිනලය නව පෝටයක් විවෘත කිරීමට ඉල්ලීම් කරයි"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"පෝටය ඉල්ලා ඇත: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"පිළිගන්න"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ප්‍රතික්ෂේප කරන්න"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"ප්‍රතිසාධනය"</string>
diff --git a/android/TerminalApp/res/values-sk/strings.xml b/android/TerminalApp/res/values-sk/strings.xml
index 11d762c..64abba6 100644
--- a/android/TerminalApp/res/values-sk/strings.xml
+++ b/android/TerminalApp/res/values-sk/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ovládanie portov"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Povoliť alebo zakázať porty počúvania"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Porty počúvania"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Uložené povolené porty"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Pridať"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Odstrániť <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Neplatné číslo portu"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port už existuje"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminál požaduje otvoriť nový port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Požadovaný port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prijať"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Zamietnuť"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Obnovenie"</string>
diff --git a/android/TerminalApp/res/values-sl/strings.xml b/android/TerminalApp/res/values-sl/strings.xml
index ce1389f..8d8dc3a 100644
--- a/android/TerminalApp/res/values-sl/strings.xml
+++ b/android/TerminalApp/res/values-sl/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Nadzor vrat"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dovoli/zavrni vrata za poslušanje"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Vrata za poslušanje"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Shranjena dovoljena vrata"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Dodaj"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Izbriši <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Neveljavna številka vrat"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Vrata že obstajajo"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal zahteva odpiranje novih vrat"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Zahtevana vrata: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Sprejmi"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Zavrni"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Obnovitev"</string>
diff --git a/android/TerminalApp/res/values-sq/strings.xml b/android/TerminalApp/res/values-sq/strings.xml
index c687f2d..871671d 100644
--- a/android/TerminalApp/res/values-sq/strings.xml
+++ b/android/TerminalApp/res/values-sq/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrolli i portës"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Lejo/refuzo portat e dëgjimit"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Portat e dëgjimit"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Portat e lejuara të ruajtura"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Shto"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Fshi <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Numër i pavlefshëm i portës"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porta ekziston tashmë"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminali po përpiqet të hapë një portë të re"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Porta e kërkuar: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Prano"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Refuzo"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Rikuperimi"</string>
diff --git a/android/TerminalApp/res/values-sr/strings.xml b/android/TerminalApp/res/values-sr/strings.xml
index 37da000..76e790d 100644
--- a/android/TerminalApp/res/values-sr/strings.xml
+++ b/android/TerminalApp/res/values-sr/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Контрола порта"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дозволите или забраните портове за слушање"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Портови за слушање"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Сачувани дозвољени портови"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Додај"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Избриши <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Неважећи број порта"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт већ постоји"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Терминал тражи да отвори нови порт"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Обавезан порт: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прихвати"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Одбиј"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Опоравак"</string>
diff --git a/android/TerminalApp/res/values-sv/strings.xml b/android/TerminalApp/res/values-sv/strings.xml
index 9edc1b6..33b00d8 100644
--- a/android/TerminalApp/res/values-sv/strings.xml
+++ b/android/TerminalApp/res/values-sv/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portkontroll"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Tillåt/neka lyssningsportar"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Lyssningsportar"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Sparade tillåtna portar"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Lägg till"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Radera <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Ogiltigt portnummer"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Porten finns redan"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminalen begär att öppna en ny port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Port som begärs: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Godkänn"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Neka"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Återställning"</string>
diff --git a/android/TerminalApp/res/values-sw/strings.xml b/android/TerminalApp/res/values-sw/strings.xml
index 6d17d8d..2affb51 100644
--- a/android/TerminalApp/res/values-sw/strings.xml
+++ b/android/TerminalApp/res/values-sw/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Udhibiti wa mlango"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Ruhusu au kataa milango ya usikilizaji"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Milango ya usikilizaji"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Umehifadhi milango inayoruhusiwa"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Weka"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Futa <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Namba ya mlango si sahihi"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Tayari mlango upo"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Temino inatuma ombi la kufungua mlango mpya"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Ombi la mlango: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Kubali"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Kataa"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Kurejesha"</string>
diff --git a/android/TerminalApp/res/values-ta/strings.xml b/android/TerminalApp/res/values-ta/strings.xml
index 4b3d3f1..a0e56d5 100644
--- a/android/TerminalApp/res/values-ta/strings.xml
+++ b/android/TerminalApp/res/values-ta/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"போர்ட் கட்டுப்பாடு"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"லிஸனிங் போர்ட்டுகளை அனுமதித்தல்/நிராகரித்தல்"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"லிஸனிங் போர்ட்டுகள்"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"சேமித்த அனுமதிக்கப்பட்ட போர்ட்டுகள்"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"சேர்க்கும்"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> ஐ நீக்கும்"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"தவறான போர்ட் எண்"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"போர்ட் ஏற்கெனவே உள்ளது"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"டெர்மினல் புதிய போர்ட்டைத் திறக்குமாறு கேட்கிறது"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"போர்ட் கேட்கப்பட்டுள்ளது: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ஏற்கிறேன்"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"நிராகரி"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"மீட்டெடுத்தல்"</string>
diff --git a/android/TerminalApp/res/values-te/strings.xml b/android/TerminalApp/res/values-te/strings.xml
index da156e2..7eab5da 100644
--- a/android/TerminalApp/res/values-te/strings.xml
+++ b/android/TerminalApp/res/values-te/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"పోర్ట్ కంట్రోల్"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"వినే పోర్ట్‌లకు అనుమతినివ్వండి/తిరస్కరించండి"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"వినే పోర్ట్‌లు"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"సేవ్ చేసిన, అనుమతి ఉన్న పోర్ట్‌లు"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"జోడించండి"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g>‌ను తొలగించండి"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"చెల్లుబాటు కాని పోర్ట్ నంబర్"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"పోర్ట్ ఇప్పటికే ఉంది"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"టెర్మినల్ ఒక కొత్త పోర్ట్‌ను తెరవడానికి రిక్వెస్ట్ చేస్తోంది"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"పోర్ట్ రిక్వెస్ట్ చేయబడింది: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ఆమోదించండి"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"తిరస్కరించండి"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"రికవరీ"</string>
diff --git a/android/TerminalApp/res/values-th/strings.xml b/android/TerminalApp/res/values-th/strings.xml
index 4f52c3b..77e0e5f 100644
--- a/android/TerminalApp/res/values-th/strings.xml
+++ b/android/TerminalApp/res/values-th/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"การควบคุมพอร์ต"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"อนุญาต/ปฏิเสธพอร์ตที่กำลังรอการเชื่อมต่อ"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"พอร์ตที่กำลังรอการเชื่อมต่อ"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"บันทึกพอร์ตที่อนุญาตแล้ว"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"เพิ่ม"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"ลบ <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"หมายเลขพอร์ตไม่ถูกต้อง"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"มีพอร์ตอยู่แล้ว"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"เทอร์มินัลกำลังส่งคำขอเปิดพอร์ตใหม่"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"พอร์ตที่ขอ: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"ยอมรับ"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"ปฏิเสธ"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"การกู้คืน"</string>
diff --git a/android/TerminalApp/res/values-tl/strings.xml b/android/TerminalApp/res/values-tl/strings.xml
index f51582c..c11620e 100644
--- a/android/TerminalApp/res/values-tl/strings.xml
+++ b/android/TerminalApp/res/values-tl/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kontrol ng port"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Payagan/tanggihan ang mga port ng pakikinig"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Mga port sa pakikinig"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"I-save ang mga pinayagang port"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Magdagdag"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"I-delete ang <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Invalid na numero ng port"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Mayroon na ng port na ito"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Nag-request ang terminal na magbukas ng bagong port"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Ni-request na port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Tanggapin"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Tanggihan"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Pag-recover"</string>
diff --git a/android/TerminalApp/res/values-tr/strings.xml b/android/TerminalApp/res/values-tr/strings.xml
index c2abca0..3b2bf0b 100644
--- a/android/TerminalApp/res/values-tr/strings.xml
+++ b/android/TerminalApp/res/values-tr/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Bağlantı noktası kontrolü"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Dinelenen bağlantı noktalarına izin ver/izin verme"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Dinlenen bağlantı noktaları"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"İzin verilen kayıtlı bağlantı noktaları"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Ekle"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Sil: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Bağlantı noktası numarası geçersiz"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Bağlantı noktası zaten mevcut"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal yeni bir bağlantı noktası açmak istiyor"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"İstenilen bağlantı noktası: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Kabul et"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Reddet"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Kurtarma"</string>
diff --git a/android/TerminalApp/res/values-uk/strings.xml b/android/TerminalApp/res/values-uk/strings.xml
index 015704c..f3a4906 100644
--- a/android/TerminalApp/res/values-uk/strings.xml
+++ b/android/TerminalApp/res/values-uk/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Керування портами"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Дозволити/заборонити порти прослуховування"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Порти прослуховування"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Збережені дозволені порти"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Додати"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Видалити <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Недійсний номер порту"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Порт уже існує"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Термінал просить відкрити новий порт"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Порт, указаний у запиті: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Прийняти"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Відхилити"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Відновлення"</string>
diff --git a/android/TerminalApp/res/values-ur/strings.xml b/android/TerminalApp/res/values-ur/strings.xml
index 89e3c86..f0e5351 100644
--- a/android/TerminalApp/res/values-ur/strings.xml
+++ b/android/TerminalApp/res/values-ur/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"پورٹ کنٹرول"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"لسننگ پورٹس کو اجازت دیں/مسترد کریں"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"لسننگ پورٹس"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"اجازت یافتہ پورٹس کو محفوظ کیا گیا"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"شامل کریں"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> حذف کریں"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"غلط پورٹ نمبر"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"پورٹ پہلے سے موجود ہے"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"ٹرمینل ایک نیا پورٹ کھولنے کی درخواست کر رہا ہے"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"پورٹ کی درخواست کی گئی: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"قبول کریں"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"مسترد کریں"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"بازیابی"</string>
diff --git a/android/TerminalApp/res/values-uz/strings.xml b/android/TerminalApp/res/values-uz/strings.xml
index 35d274e..5c65633 100644
--- a/android/TerminalApp/res/values-uz/strings.xml
+++ b/android/TerminalApp/res/values-uz/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Portlar boshqaruvi"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Uzatish portlariga ruxsat berish/ularni taqiqlash"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Uzatish postlari"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Ruxsat etilgan portlar saqlandi"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Qoʻshish"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"<xliff:g id="PORT_NUMBER">%d</xliff:g> hisobini oʻchirish"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Port raqami yaroqsiz"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Port allaqachon mavjud"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Terminal yangi port ochishni talab qilmoqda"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Talab qilingan port: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Qabul qilish"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Rad etish"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Tiklash"</string>
diff --git a/android/TerminalApp/res/values-vi/strings.xml b/android/TerminalApp/res/values-vi/strings.xml
index da15be5..5013918 100644
--- a/android/TerminalApp/res/values-vi/strings.xml
+++ b/android/TerminalApp/res/values-vi/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Kiểm soát cổng"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Cho phép/từ chối cổng nghe"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Cổng nghe"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Đã lưu các cổng được cho phép"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Thêm"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Xoá <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Số cổng không hợp lệ"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Cổng đã tồn tại"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Ứng dụng Terminal đang yêu cầu mở một cổng mới"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Cổng được yêu cầu: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Chấp nhận"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Từ chối"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Khôi phục"</string>
diff --git a/android/TerminalApp/res/values-zh-rCN/strings.xml b/android/TerminalApp/res/values-zh-rCN/strings.xml
index 3da5f28..4d424ed 100644
--- a/android/TerminalApp/res/values-zh-rCN/strings.xml
+++ b/android/TerminalApp/res/values-zh-rCN/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"端口控制"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"允许/拒绝使用监听端口"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"监听端口"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"已保存的获准端口"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"添加"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"删除“<xliff:g id="PORT_NUMBER">%d</xliff:g>”"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"端口号无效"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"端口已存在"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"终端正在请求打开新端口"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"请求的端口:<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"接受"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"拒绝"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"恢复"</string>
diff --git a/android/TerminalApp/res/values-zh-rHK/strings.xml b/android/TerminalApp/res/values-zh-rHK/strings.xml
index 5de6319..317ec3a 100644
--- a/android/TerminalApp/res/values-zh-rHK/strings.xml
+++ b/android/TerminalApp/res/values-zh-rHK/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"連接埠控制項"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"允許/拒絕聆聽連接埠"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"聆聽連接埠"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"已儲存許可的連接埠"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"新增"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"刪除 <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"連接埠號碼無效"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"連接埠已存在"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"終端機正在要求開啟新的連接埠"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"已要求連接埠:<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"接受"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"拒絕"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"復原"</string>
diff --git a/android/TerminalApp/res/values-zh-rTW/strings.xml b/android/TerminalApp/res/values-zh-rTW/strings.xml
index 28a0ce2..d3576d5 100644
--- a/android/TerminalApp/res/values-zh-rTW/strings.xml
+++ b/android/TerminalApp/res/values-zh-rTW/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"通訊埠控制"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"允許/拒絕監聽通訊埠"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"監聽通訊埠"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"已儲存允許的通訊埠"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"新增"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"刪除 <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"通訊埠號碼無效"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"已有這個通訊埠"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"終端機正在要求開啟新的通訊埠"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"要求的通訊埠:<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"接受"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"拒絕"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"復原"</string>
diff --git a/android/TerminalApp/res/values-zu/strings.xml b/android/TerminalApp/res/values-zu/strings.xml
index 7f9a958..8b81522 100644
--- a/android/TerminalApp/res/values-zu/strings.xml
+++ b/android/TerminalApp/res/values-zu/strings.xml
@@ -48,6 +48,8 @@
     <string name="settings_port_forwarding_title" msgid="4971368519093858377">"Ulawulo lwembobo"</string>
     <string name="settings_port_forwarding_sub_title" msgid="6547942778715654953">"Vumela/nqabela izimbobo zokulalela"</string>
     <string name="settings_port_forwarding_active_ports_title" msgid="1841436780635889858">"Izimbobo zokulalela"</string>
+    <!-- no translation found for settings_port_forwarding_active_ports_content (1818090784030797758) -->
+    <skip />
     <string name="settings_port_forwarding_other_enabled_ports_title" msgid="2644381842623436676">"Izimbobo ezivunyelwe ezilondoloziwe"</string>
     <string name="settings_port_forwarding_other_enabled_port_add_button" msgid="4402301203801949152">"Engeza"</string>
     <string name="settings_port_forwarding_other_enabled_port_close_button" msgid="8475029060852721339">"Sula i-<xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
@@ -59,7 +61,8 @@
     <string name="settings_port_forwarding_dialog_error_invalid_port_range" msgid="6682935312557379651">"Inombolo engasebenzi yembobo"</string>
     <string name="settings_port_forwarding_dialog_error_existing_port" msgid="768426750758769928">"Imbobo isikhona"</string>
     <string name="settings_port_forwarding_notification_title" msgid="6950621555592547524">"Itheminali icela ukuvula imbobo entsha"</string>
-    <string name="settings_port_forwarding_notification_content" msgid="5072621159244211971">"Imbobo iceliwe: <xliff:g id="PORT_NUMBER">%d</xliff:g>"</string>
+    <!-- no translation found for settings_port_forwarding_notification_content (779450349212040908) -->
+    <skip />
     <string name="settings_port_forwarding_notification_accept" msgid="3571520986524038185">"Yamukela"</string>
     <string name="settings_port_forwarding_notification_deny" msgid="636848749634710403">"Yenqaba"</string>
     <string name="settings_recovery_title" msgid="6586840079226383285">"Ukuthola"</string>
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index 40c354e..d3440d3 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -87,6 +87,8 @@
     <string name="settings_port_forwarding_sub_title">Allow/deny listening ports</string>
     <!-- Title for active ports setting in port forwarding [CHAR LIMIT=none] -->
     <string name="settings_port_forwarding_active_ports_title">Listening ports</string>
+    <!-- Text content for active ports setting in port forwarding [CHAR LIMIT=none] -->
+    <string name="settings_port_forwarding_active_ports_content"><xliff:g id="port_number" example="8000">%1$d</xliff:g> (<xliff:g id="process_name" example="undefined">%2$s</xliff:g>)</string>
     <!-- Title for other enabled ports setting in port forwarding [CHAR LIMIT=none] -->
     <string name="settings_port_forwarding_other_enabled_ports_title">Saved allowed ports</string>
     <!-- Description of add button for other enabled ports. Used for talkback. [CHAR LIMIT=16] -->
@@ -112,7 +114,7 @@
     <!-- Notification title for a new active port [CHAR LIMIT=none] -->
     <string name="settings_port_forwarding_notification_title">Terminal is requesting to open a new port</string>
     <!-- Notification content for a new active port [CHAR LIMIT=none] -->
-    <string name="settings_port_forwarding_notification_content">Port requested: <xliff:g id="port_number" example="8080">%d</xliff:g></string>
+    <string name="settings_port_forwarding_notification_content">Port requested: <xliff:g id="port_number" example="8000">%1$d</xliff:g> (<xliff:g id="process_name" example="undefined">%2$s</xliff:g>)</string>
     <!-- Notification action accept [CHAR LIMIT=16] -->
     <string name="settings_port_forwarding_notification_accept">Accept</string>
     <!-- Notification action deny [CHAR LIMIT=16] -->
diff --git a/android/virtmgr/Android.bp b/android/virtmgr/Android.bp
index ad63995..c2d67cf 100644
--- a/android/virtmgr/Android.bp
+++ b/android/virtmgr/Android.bp
@@ -38,7 +38,6 @@
         "libcfg_if",
         "libclap",
         "libcrosvm_control_static",
-        "libcstr",
         "libcommand_fds",
         "libdisk",
         "libglob",
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index c71b5c5..5ad7ee1 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -68,7 +68,6 @@
     self, wait_for_interface, Accessor, BinderFeatures, ConnectionInfo, ExceptionCode, Interface, ParcelFileDescriptor,
     SpIBinder, Status, StatusCode, Strong, IntoBinderResult,
 };
-use cstr::cstr;
 use glob::glob;
 use libc::{AF_VSOCK, sa_family_t, sockaddr_vm};
 use log::{debug, error, info, warn};
@@ -976,7 +975,7 @@
             "Passing vendor hashtree digest to pvmfw. This will be rejected if it doesn't \
                 match the trusted digest in the pvmfw config, causing the VM to fail to start."
         );
-        vec![(cstr!("vendor_hashtree_descriptor_root_digest"), vendor_hashtree_digest.as_slice())]
+        vec![(c"vendor_hashtree_descriptor_root_digest", vendor_hashtree_digest.as_slice())]
     } else {
         vec![]
     };
@@ -984,18 +983,18 @@
     let key_material;
     let mut untrusted_props = Vec::with_capacity(2);
     if cfg!(llpvm_changes) {
-        untrusted_props.push((cstr!("instance-id"), &instance_id[..]));
+        untrusted_props.push((c"instance-id", &instance_id[..]));
         let want_updatable = extract_want_updatable(config);
         if want_updatable && is_secretkeeper_supported() {
             // Let guest know that it can defer rollback protection to Secretkeeper by setting
             // an empty property in untrusted node in DT. This enables Updatable VMs.
-            untrusted_props.push((cstr!("defer-rollback-protection"), &[]));
+            untrusted_props.push((c"defer-rollback-protection", &[]));
             let sk: Strong<dyn ISecretkeeper> =
                 binder::wait_for_interface(SECRETKEEPER_IDENTIFIER)?;
             if sk.getInterfaceVersion()? >= 2 {
                 let PublicKey { keyMaterial } = sk.getSecretkeeperIdentity()?;
                 key_material = keyMaterial;
-                trusted_props.push((cstr!("secretkeeper_public_key"), key_material.as_slice()));
+                trusted_props.push((c"secretkeeper_public_key", key_material.as_slice()));
             }
         }
     }
diff --git a/android/virtmgr/src/dt_overlay.rs b/android/virtmgr/src/dt_overlay.rs
index 108ed61..fe2a419 100644
--- a/android/virtmgr/src/dt_overlay.rs
+++ b/android/virtmgr/src/dt_overlay.rs
@@ -15,14 +15,13 @@
 //! This module support creating AFV related overlays, that can then be appended to DT by VM.
 
 use anyhow::{anyhow, Result};
-use cstr::cstr;
 use fsfdt::FsFdt;
 use libfdt::Fdt;
 use std::ffi::CStr;
 use std::path::Path;
 
-pub(crate) const AVF_NODE_NAME: &CStr = cstr!("avf");
-pub(crate) const UNTRUSTED_NODE_NAME: &CStr = cstr!("untrusted");
+pub(crate) const AVF_NODE_NAME: &CStr = c"avf";
+pub(crate) const UNTRUSTED_NODE_NAME: &CStr = c"untrusted";
 pub(crate) const VM_DT_OVERLAY_PATH: &str = "vm_dt_overlay.dtbo";
 pub(crate) const VM_DT_OVERLAY_MAX_SIZE: usize = 2000;
 
@@ -63,13 +62,13 @@
         Fdt::create_empty_tree(buffer).map_err(|e| anyhow!("Failed to create empty Fdt: {e:?}"))?;
     let mut fragment = fdt
         .root_mut()
-        .add_subnode(cstr!("fragment@0"))
+        .add_subnode(c"fragment@0")
         .map_err(|e| anyhow!("Failed to add fragment node: {e:?}"))?;
     fragment
-        .setprop(cstr!("target-path"), b"/\0")
+        .setprop(c"target-path", b"/\0")
         .map_err(|e| anyhow!("Failed to set target-path property: {e:?}"))?;
     let overlay = fragment
-        .add_subnode(cstr!("__overlay__"))
+        .add_subnode(c"__overlay__")
         .map_err(|e| anyhow!("Failed to add __overlay__ node: {e:?}"))?;
     let avf =
         overlay.add_subnode(AVF_NODE_NAME).map_err(|e| anyhow!("Failed to add avf node: {e:?}"))?;
@@ -87,12 +86,12 @@
 
     // Read dt_path from host DT and overlay onto fdt.
     if let Some(path) = dt_path {
-        fdt.overlay_onto(cstr!("/fragment@0/__overlay__"), path)?;
+        fdt.overlay_onto(c"/fragment@0/__overlay__", path)?;
     }
 
     if !trusted_props.is_empty() {
         let mut avf = fdt
-            .node_mut(cstr!("/fragment@0/__overlay__/avf"))
+            .node_mut(c"/fragment@0/__overlay__/avf")
             .map_err(|e| anyhow!("Failed to search avf node: {e:?}"))?
             .ok_or(anyhow!("Failed to get avf node"))?;
         for (name, value) in trusted_props {
@@ -120,14 +119,14 @@
     #[test]
     fn untrusted_prop_test() {
         let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
-        let prop_name = cstr!("XOXO");
+        let prop_name = c"XOXO";
         let prop_val_input = b"OXOX";
         let fdt =
             create_device_tree_overlay(&mut buffer, None, &[(prop_name, prop_val_input)], &[])
                 .unwrap();
 
         let prop_value_dt = fdt
-            .node(cstr!("/fragment@0/__overlay__/avf/untrusted"))
+            .node(c"/fragment@0/__overlay__/avf/untrusted")
             .unwrap()
             .expect("/avf/untrusted node doesn't exist")
             .getprop(prop_name)
@@ -139,14 +138,14 @@
     #[test]
     fn trusted_prop_test() {
         let mut buffer = vec![0_u8; VM_DT_OVERLAY_MAX_SIZE];
-        let prop_name = cstr!("XOXOXO");
+        let prop_name = c"XOXOXO";
         let prop_val_input = b"OXOXOX";
         let fdt =
             create_device_tree_overlay(&mut buffer, None, &[], &[(prop_name, prop_val_input)])
                 .unwrap();
 
         let prop_value_dt = fdt
-            .node(cstr!("/fragment@0/__overlay__/avf"))
+            .node(c"/fragment@0/__overlay__/avf")
             .unwrap()
             .expect("/avf node doesn't exist")
             .getprop(prop_name)
diff --git a/guest/derive_microdroid_vendor_dice_node/Android.bp b/guest/derive_microdroid_vendor_dice_node/Android.bp
index 8b79aad..7a3ccbe 100644
--- a/guest/derive_microdroid_vendor_dice_node/Android.bp
+++ b/guest/derive_microdroid_vendor_dice_node/Android.bp
@@ -10,7 +10,6 @@
     rustlibs: [
         "libanyhow",
         "libclap",
-        "libcstr",
         "libdice_driver",
         "libdiced_open_dice",
         "libdm_rust",
diff --git a/guest/derive_microdroid_vendor_dice_node/src/main.rs b/guest/derive_microdroid_vendor_dice_node/src/main.rs
index 0f0631e..4ec91ad 100644
--- a/guest/derive_microdroid_vendor_dice_node/src/main.rs
+++ b/guest/derive_microdroid_vendor_dice_node/src/main.rs
@@ -16,7 +16,6 @@
 
 use anyhow::{bail, Context, Result};
 use clap::Parser;
-use cstr::cstr;
 use dice_driver::DiceDriver;
 use diced_open_dice::{
     hash, retry_bcc_format_config_descriptor, DiceConfigValues, OwnedDiceArtifacts, HIDDEN_SIZE,
@@ -50,7 +49,7 @@
 // See dice_for_avf_guest.cddl for CDDL of Configuration Descriptor of VM components.
 fn build_descriptor(vbmeta: &VbMetaImage) -> Result<Vec<u8>> {
     let values = DiceConfigValues {
-        component_name: Some(cstr!("Microdroid vendor")),
+        component_name: Some(c"Microdroid vendor"),
         security_version: Some(vbmeta.rollback_index()),
         ..Default::default()
     };
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
index bed8965..963a531 100644
--- a/guest/forwarder_guest_launcher/src/main.rs
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -22,7 +22,7 @@
 use futures::stream::StreamExt;
 use log::{debug, error};
 use serde::Deserialize;
-use std::collections::HashSet;
+use std::collections::HashMap;
 use std::process::Stdio;
 use tokio::io::BufReader;
 use tokio::process::Command;
@@ -46,6 +46,8 @@
     ip: i8,
     lport: i32,
     rport: i32,
+    #[serde(alias = "C-COMM")]
+    c_comm: String,
     newstate: String,
 }
 
@@ -88,12 +90,12 @@
 }
 
 async fn send_active_ports_report(
-    listening_ports: HashSet<i32>,
+    listening_ports: HashMap<i32, ActivePort>,
     client: &mut DebianServiceClient<Channel>,
 ) -> Result<(), Box<dyn std::error::Error>> {
     let res = client
         .report_vm_active_ports(Request::new(ReportVmActivePortsRequest {
-            ports: listening_ports.into_iter().map(|port| ActivePort { port }).collect(),
+            ports: listening_ports.values().cloned().collect(),
         }))
         .await?
         .into_inner();
@@ -126,12 +128,16 @@
     // TODO(b/340126051): Consider using NETLINK_SOCK_DIAG for the optimization.
     let listeners = listeners::get_all()?;
     // TODO(b/340126051): Support distinguished port forwarding for ipv6 as well.
-    let mut listening_ports: HashSet<_> = listeners
+    let mut listening_ports: HashMap<_, _> = listeners
         .iter()
-        .map(|x| x.socket)
-        .filter(|x| x.is_ipv4())
-        .map(|x| x.port().into())
-        .filter(|x| is_forwardable_port(*x))
+        .filter(|x| x.socket.is_ipv4())
+        .map(|x| {
+            (
+                x.socket.port().into(),
+                ActivePort { port: x.socket.port().into(), comm: x.process.name.to_string() },
+            )
+        })
+        .filter(|(x, _)| is_forwardable_port(*x))
         .collect();
     send_active_ports_report(listening_ports.clone(), &mut client).await?;
 
@@ -149,7 +155,7 @@
         }
         match row.newstate.as_str() {
             TCPSTATES_STATE_LISTEN => {
-                listening_ports.insert(row.lport);
+                listening_ports.insert(row.lport, ActivePort { port: row.lport, comm: row.c_comm });
             }
             TCPSTATES_STATE_CLOSE => {
                 listening_ports.remove(&row.lport);
diff --git a/guest/pvmfw/Android.bp b/guest/pvmfw/Android.bp
index 793204d..da056d6 100644
--- a/guest/pvmfw/Android.bp
+++ b/guest/pvmfw/Android.bp
@@ -17,7 +17,6 @@
         "libciborium_nostd",
         "libciborium_io_nostd",
         "libcoset_nostd",
-        "libcstr",
         "libdiced_open_dice_nostd",
         "libhypervisor_backends",
         "liblibfdt_nostd",
@@ -52,9 +51,6 @@
         unit_test: true,
     },
     prefer_rlib: true,
-    rustlibs: [
-        "libcstr",
-    ],
 }
 
 rust_test {
diff --git a/guest/pvmfw/src/bootargs.rs b/guest/pvmfw/src/bootargs.rs
index aacd8e0..0a5697f 100644
--- a/guest/pvmfw/src/bootargs.rs
+++ b/guest/pvmfw/src/bootargs.rs
@@ -108,7 +108,6 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use cstr::cstr;
 
     fn check(raw: &CStr, expected: Result<&[(&str, Option<&str>)], ()>) {
         let actual = BootArgsIterator::new(raw);
@@ -136,35 +135,35 @@
 
     #[test]
     fn empty() {
-        check(cstr!(""), Ok(&[]));
-        check(cstr!("    "), Ok(&[]));
-        check(cstr!("  \n  "), Ok(&[]));
+        check(c"", Ok(&[]));
+        check(c"    ", Ok(&[]));
+        check(c"  \n  ", Ok(&[]));
     }
 
     #[test]
     fn single() {
-        check(cstr!("foo"), Ok(&[("foo", None)]));
-        check(cstr!("   foo"), Ok(&[("foo", None)]));
-        check(cstr!("foo   "), Ok(&[("foo", None)]));
-        check(cstr!("   foo   "), Ok(&[("foo", None)]));
+        check(c"foo", Ok(&[("foo", None)]));
+        check(c"   foo", Ok(&[("foo", None)]));
+        check(c"foo   ", Ok(&[("foo", None)]));
+        check(c"   foo   ", Ok(&[("foo", None)]));
     }
 
     #[test]
     fn single_with_value() {
-        check(cstr!("foo=bar"), Ok(&[("foo", Some("=bar"))]));
-        check(cstr!("   foo=bar"), Ok(&[("foo", Some("=bar"))]));
-        check(cstr!("foo=bar   "), Ok(&[("foo", Some("=bar"))]));
-        check(cstr!("   foo=bar   "), Ok(&[("foo", Some("=bar"))]));
+        check(c"foo=bar", Ok(&[("foo", Some("=bar"))]));
+        check(c"   foo=bar", Ok(&[("foo", Some("=bar"))]));
+        check(c"foo=bar   ", Ok(&[("foo", Some("=bar"))]));
+        check(c"   foo=bar   ", Ok(&[("foo", Some("=bar"))]));
 
-        check(cstr!("foo="), Ok(&[("foo", Some("="))]));
-        check(cstr!("   foo="), Ok(&[("foo", Some("="))]));
-        check(cstr!("foo=   "), Ok(&[("foo", Some("="))]));
-        check(cstr!("   foo=   "), Ok(&[("foo", Some("="))]));
+        check(c"foo=", Ok(&[("foo", Some("="))]));
+        check(c"   foo=", Ok(&[("foo", Some("="))]));
+        check(c"foo=   ", Ok(&[("foo", Some("="))]));
+        check(c"   foo=   ", Ok(&[("foo", Some("="))]));
     }
 
     #[test]
     fn single_with_quote() {
-        check(cstr!("foo=hello\" \"world"), Ok(&[("foo", Some("=hello\" \"world"))]));
+        check(c"foo=hello\" \"world", Ok(&[("foo", Some("=hello\" \"world"))]));
     }
 
     #[test]
@@ -175,32 +174,32 @@
     #[test]
     fn multiple() {
         check(
-            cstr!(" a=b   c=d   e=  f g  "),
+            c" a=b   c=d   e=  f g  ",
             Ok(&[("a", Some("=b")), ("c", Some("=d")), ("e", Some("=")), ("f", None), ("g", None)]),
         );
         check(
-            cstr!("   a=b  \n c=d      e=  f g"),
+            c"   a=b  \n c=d      e=  f g",
             Ok(&[("a", Some("=b")), ("c", Some("=d")), ("e", Some("=")), ("f", None), ("g", None)]),
         );
     }
 
     #[test]
     fn incomplete_quote() {
-        check(
-            cstr!("foo=incomplete\" quote bar=y"),
-            Ok(&[("foo", Some("=incomplete\" quote bar=y"))]),
-        );
+        check(c"foo=incomplete\" quote bar=y", Ok(&[("foo", Some("=incomplete\" quote bar=y"))]));
     }
 
     #[test]
     fn complex() {
-        check(cstr!("  a  a1=  b=c d=e,f,g x=\"value with quote\" y=val\"ue with \"multiple\" quo\"te  "), Ok(&[
-            ("a", None),
-            ("a1", Some("=")),
-            ("b", Some("=c")),
-            ("d", Some("=e,f,g")),
-            ("x", Some("=\"value with quote\"")),
-            ("y", Some("=val\"ue with \"multiple\" quo\"te")),
-        ]));
+        check(
+            c"  a  a1=  b=c d=e,f,g x=\"value with quote\" y=val\"ue with \"multiple\" quo\"te  ",
+            Ok(&[
+                ("a", None),
+                ("a1", Some("=")),
+                ("b", Some("=c")),
+                ("d", Some("=e,f,g")),
+                ("x", Some("=\"value with quote\"")),
+                ("y", Some("=val\"ue with \"multiple\" quo\"te")),
+            ]),
+        );
     }
 }
diff --git a/guest/pvmfw/src/device_assignment.rs b/guest/pvmfw/src/device_assignment.rs
index f37f443..bb2e6ce 100644
--- a/guest/pvmfw/src/device_assignment.rs
+++ b/guest/pvmfw/src/device_assignment.rs
@@ -37,18 +37,6 @@
 use zerocopy::byteorder::big_endian::U32;
 use zerocopy::FromBytes as _;
 
-// TODO(b/308694211): Use cstr! from vmbase instead.
-macro_rules! cstr {
-    ($str:literal) => {{
-        const S: &str = concat!($str, "\0");
-        const C: &::core::ffi::CStr = match ::core::ffi::CStr::from_bytes_with_nul(S.as_bytes()) {
-            Ok(v) => v,
-            Err(_) => panic!("string contains interior NUL"),
-        };
-        C
-    }};
-}
-
 // TODO(b/277993056): Keep constants derived from platform.dts in one place.
 const CELLS_PER_INTERRUPT: usize = 3; // from /intc node in platform.dts
 
@@ -332,7 +320,7 @@
     //       };
     //    };
     //
-    // Then locate_overlay_target_path(cstr!("/fragment@rng/__overlay__/rng")) is Ok("/rng")
+    // Then locate_overlay_target_path(c"/fragment@rng/__overlay__/rng") is Ok("/rng")
     //
     // Contrary to fdt_overlay_target_offset(), this API enforces overlay target property
     // 'target-path = "/"', so the overlay doesn't modify and/or append platform DT's existing
@@ -343,10 +331,9 @@
         dtbo_node: &FdtNode,
     ) -> Result<CString> {
         let fragment_node = dtbo_node.supernode_at_depth(1)?;
-        let target_path = fragment_node
-            .getprop_str(cstr!("target-path"))?
-            .ok_or(DeviceAssignmentError::InvalidDtbo)?;
-        if target_path != cstr!("/") {
+        let target_path =
+            fragment_node.getprop_str(c"target-path")?.ok_or(DeviceAssignmentError::InvalidDtbo)?;
+        if target_path != c"/" {
             return Err(DeviceAssignmentError::UnsupportedOverlayTarget);
         }
 
@@ -415,7 +402,7 @@
 
     /// Parses Physical devices in VM DTBO
     fn parse_physical_devices(&self) -> Result<BTreeMap<Phandle, PhysicalDeviceInfo>> {
-        let Some(physical_node) = self.as_ref().node(cstr!("/host"))? else {
+        let Some(physical_node) = self.as_ref().node(c"/host")? else {
             return Ok(BTreeMap::new());
         };
 
@@ -459,7 +446,7 @@
         let vm_dtbo = self.as_ref();
 
         let mut phandle_map = BTreeMap::new();
-        let Some(local_fixups) = vm_dtbo.node(cstr!("/__local_fixups__"))? else {
+        let Some(local_fixups) = vm_dtbo.node(c"/__local_fixups__")? else {
             return Ok(phandle_map);
         };
 
@@ -615,15 +602,14 @@
 
 impl PvIommu {
     fn parse(node: &FdtNode) -> Result<Self> {
-        let iommu_cells = node
-            .getprop_u32(cstr!("#iommu-cells"))?
-            .ok_or(DeviceAssignmentError::InvalidPvIommu)?;
+        let iommu_cells =
+            node.getprop_u32(c"#iommu-cells")?.ok_or(DeviceAssignmentError::InvalidPvIommu)?;
         // Ensures #iommu-cells = <1>. It means that `<iommus>` entry contains pair of
         // (pvIOMMU ID, vSID)
         if iommu_cells != 1 {
             return Err(DeviceAssignmentError::InvalidPvIommu);
         }
-        let id = node.getprop_u32(cstr!("id"))?.ok_or(DeviceAssignmentError::InvalidPvIommu)?;
+        let id = node.getprop_u32(c"id")?.ok_or(DeviceAssignmentError::InvalidPvIommu)?;
         Ok(Self { id })
     }
 }
@@ -687,10 +673,10 @@
 
 impl PhysIommu {
     fn parse(node: &FdtNode) -> Result<Option<Self>> {
-        let Some(token) = node.getprop_u64(cstr!("android,pvmfw,token"))? else {
+        let Some(token) = node.getprop_u64(c"android,pvmfw,token")? else {
             return Ok(None);
         };
-        let Some(iommu_cells) = node.getprop_u32(cstr!("#iommu-cells"))? else {
+        let Some(iommu_cells) = node.getprop_u32(c"#iommu-cells")? else {
             return Err(DeviceAssignmentError::InvalidPhysIommu);
         };
         // Currently only supports #iommu-cells = <1>.
@@ -715,7 +701,7 @@
         phys_iommus: &BTreeMap<Phandle, PhysIommu>,
     ) -> Result<Vec<(PhysIommu, Sid)>> {
         let mut iommus = vec![];
-        let Some(mut cells) = node.getprop_cells(cstr!("iommus"))? else {
+        let Some(mut cells) = node.getprop_cells(c"iommus")? else {
             return Ok(iommus);
         };
         while let Some(cell) = cells.next() {
@@ -735,7 +721,7 @@
     }
 
     fn parse(node: &FdtNode, phys_iommus: &BTreeMap<Phandle, PhysIommu>) -> Result<Option<Self>> {
-        let Some(phandle) = node.getprop_u32(cstr!("android,pvmfw,target"))? else {
+        let Some(phandle) = node.getprop_u32(c"android,pvmfw,target")? else {
             return Ok(None);
         };
         let target = Phandle::try_from(phandle)?;
@@ -812,7 +798,7 @@
         // Validation: Validate if interrupts cell numbers are multiple of #interrupt-cells.
         // We can't know how many interrupts would exist.
         let interrupts_cells = node
-            .getprop_cells(cstr!("interrupts"))?
+            .getprop_cells(c"interrupts")?
             .ok_or(DeviceAssignmentError::InvalidInterrupts)?
             .count();
         if interrupts_cells % CELLS_PER_INTERRUPT != 0 {
@@ -820,7 +806,7 @@
         }
 
         // Once validated, keep the raw bytes so patch can be done with setprop()
-        Ok(node.getprop(cstr!("interrupts")).unwrap().unwrap().into())
+        Ok(node.getprop(c"interrupts").unwrap().unwrap().into())
     }
 
     // TODO(b/277993056): Also validate /__local_fixups__ to ensure that <iommus> has phandle.
@@ -829,7 +815,7 @@
         pviommus: &BTreeMap<Phandle, PvIommu>,
     ) -> Result<Vec<(PvIommu, Vsid)>> {
         let mut iommus = vec![];
-        let Some(mut cells) = node.getprop_cells(cstr!("iommus"))? else {
+        let Some(mut cells) = node.getprop_cells(c"iommus")? else {
             return Ok(iommus);
         };
         while let Some(cell) = cells.next() {
@@ -917,15 +903,15 @@
 
     fn patch(&self, fdt: &mut Fdt, pviommu_phandles: &BTreeMap<PvIommu, Phandle>) -> Result<()> {
         let mut dst = fdt.node_mut(&self.node_path)?.unwrap();
-        dst.setprop(cstr!("reg"), &to_be_bytes(&self.reg))?;
-        dst.setprop(cstr!("interrupts"), &self.interrupts)?;
+        dst.setprop(c"reg", &to_be_bytes(&self.reg))?;
+        dst.setprop(c"interrupts", &self.interrupts)?;
         let mut iommus = Vec::with_capacity(8 * self.iommus.len());
         for (pviommu, vsid) in &self.iommus {
             let phandle = pviommu_phandles.get(pviommu).unwrap();
             iommus.extend_from_slice(&u32::from(*phandle).to_be_bytes());
             iommus.extend_from_slice(&vsid.0.to_be_bytes());
         }
-        dst.setprop(cstr!("iommus"), &iommus)?;
+        dst.setprop(c"iommus", &iommus)?;
 
         Ok(())
     }
@@ -939,7 +925,7 @@
 }
 
 impl DeviceAssignmentInfo {
-    const PVIOMMU_COMPATIBLE: &'static CStr = cstr!("pkvm,pviommu");
+    const PVIOMMU_COMPATIBLE: &'static CStr = c"pkvm,pviommu";
 
     /// Parses pvIOMMUs in fdt
     // Note: This will validate pvIOMMU ids' uniqueness, even when unassigned.
@@ -1046,8 +1032,8 @@
         Self::validate_pviommu_topology(&assigned_devices)?;
 
         let mut vm_dtbo_mask = vm_dtbo.build_mask(assigned_device_paths)?;
-        vm_dtbo_mask.mask_all(&DtPathTokens::new(cstr!("/__local_fixups__"))?);
-        vm_dtbo_mask.mask_all(&DtPathTokens::new(cstr!("/__symbols__"))?);
+        vm_dtbo_mask.mask_all(&DtPathTokens::new(c"/__local_fixups__")?);
+        vm_dtbo_mask.mask_all(&DtPathTokens::new(c"/__symbols__")?);
 
         // Note: Any node without __overlay__ will be ignored by fdt_apply_overlay,
         // so doesn't need to be filtered.
@@ -1060,7 +1046,7 @@
         let vm_dtbo = vm_dtbo.as_mut();
 
         // Filter unused references in /__local_fixups__
-        if let Some(local_fixups) = vm_dtbo.node_mut(cstr!("/__local_fixups__"))? {
+        if let Some(local_fixups) = vm_dtbo.node_mut(c"/__local_fixups__")? {
             filter_with_mask(local_fixups, &self.vm_dtbo_mask)?;
         }
 
@@ -1078,7 +1064,7 @@
         for pviommu in &self.pviommus {
             let mut node = compatible.ok_or(DeviceAssignmentError::TooManyPvIommu)?;
             let phandle = node.as_node().get_phandle()?.ok_or(DeviceAssignmentError::Internal)?;
-            node.setprop_inplace(cstr!("id"), &pviommu.id.to_be_bytes())?;
+            node.setprop_inplace(c"id", &pviommu.id.to_be_bytes())?;
             if pviommu_phandles.insert(*pviommu, phandle).is_some() {
                 return Err(DeviceAssignmentError::Internal);
             }
@@ -1108,10 +1094,10 @@
 
 /// Cleans device trees not to contain any pre-populated nodes/props for device assignment.
 pub fn clean(fdt: &mut Fdt) -> Result<()> {
-    let mut compatible = fdt.root_mut().next_compatible(cstr!("pkvm,pviommu"))?;
+    let mut compatible = fdt.root_mut().next_compatible(c"pkvm,pviommu")?;
     // Filters pre-populated
     while let Some(filtered_pviommu) = compatible {
-        compatible = filtered_pviommu.delete_and_next_compatible(cstr!("pkvm,pviommu"))?;
+        compatible = filtered_pviommu.delete_and_next_compatible(c"pkvm,pviommu")?;
     }
 
     // Removes any dangling references in __symbols__ (e.g. removed pvIOMMUs)
@@ -1239,24 +1225,23 @@
                 return Err(FdtError::NotFound.into());
             };
 
-            let reg = node.getprop(cstr!("reg"))?.ok_or(DeviceAssignmentError::MalformedReg)?;
-            let interrupts = node
-                .getprop(cstr!("interrupts"))?
-                .ok_or(DeviceAssignmentError::InvalidInterrupts)?;
+            let reg = node.getprop(c"reg")?.ok_or(DeviceAssignmentError::MalformedReg)?;
+            let interrupts =
+                node.getprop(c"interrupts")?.ok_or(DeviceAssignmentError::InvalidInterrupts)?;
             let mut iommus = vec![];
-            if let Some(mut cells) = node.getprop_cells(cstr!("iommus"))? {
+            if let Some(mut cells) = node.getprop_cells(c"iommus")? {
                 while let Some(pviommu_id) = cells.next() {
                     // pvIOMMU id
                     let phandle = Phandle::try_from(pviommu_id)?;
                     let pviommu = fdt
                         .node_with_phandle(phandle)?
                         .ok_or(DeviceAssignmentError::MalformedIommus)?;
-                    let compatible = pviommu.getprop_str(cstr!("compatible"));
-                    if compatible != Ok(Some(cstr!("pkvm,pviommu"))) {
+                    let compatible = pviommu.getprop_str(c"compatible");
+                    if compatible != Ok(Some(c"pkvm,pviommu")) {
                         return Err(DeviceAssignmentError::MalformedIommus);
                     }
                     let id = pviommu
-                        .getprop_u32(cstr!("id"))?
+                        .getprop_u32(c"id")?
                         .ok_or(DeviceAssignmentError::MalformedIommus)?;
                     iommus.push(id);
 
@@ -1273,8 +1258,8 @@
 
     fn collect_pviommus(fdt: &Fdt) -> Result<Vec<u32>> {
         let mut pviommus = BTreeSet::new();
-        for pviommu in fdt.compatible_nodes(cstr!("pkvm,pviommu"))? {
-            if let Ok(Some(id)) = pviommu.getprop_u32(cstr!("id")) {
+        for pviommu in fdt.compatible_nodes(c"pkvm,pviommu")? {
+            if let Ok(Some(id)) = pviommu.getprop_u32(c"id") {
                 pviommus.insert(id);
             }
         }
@@ -1395,24 +1380,24 @@
 
         let symbols = vm_dtbo.symbols().unwrap().unwrap();
 
-        let rng = vm_dtbo.node(cstr!("/fragment@0/__overlay__/rng")).unwrap();
+        let rng = vm_dtbo.node(c"/fragment@0/__overlay__/rng").unwrap();
         assert_ne!(rng, None);
-        let rng_symbol = symbols.getprop_str(cstr!("rng")).unwrap();
-        assert_eq!(Some(cstr!("/fragment@0/__overlay__/rng")), rng_symbol);
+        let rng_symbol = symbols.getprop_str(c"rng").unwrap();
+        assert_eq!(Some(c"/fragment@0/__overlay__/rng"), rng_symbol);
 
-        let light = vm_dtbo.node(cstr!("/fragment@0/__overlay__/light")).unwrap();
+        let light = vm_dtbo.node(c"/fragment@0/__overlay__/light").unwrap();
         assert_eq!(light, None);
-        let light_symbol = symbols.getprop_str(cstr!("light")).unwrap();
+        let light_symbol = symbols.getprop_str(c"light").unwrap();
         assert_eq!(None, light_symbol);
 
-        let led = vm_dtbo.node(cstr!("/fragment@0/__overlay__/led")).unwrap();
+        let led = vm_dtbo.node(c"/fragment@0/__overlay__/led").unwrap();
         assert_eq!(led, None);
-        let led_symbol = symbols.getprop_str(cstr!("led")).unwrap();
+        let led_symbol = symbols.getprop_str(c"led").unwrap();
         assert_eq!(None, led_symbol);
 
-        let backlight = vm_dtbo.node(cstr!("/fragment@0/__overlay__/bus0/backlight")).unwrap();
+        let backlight = vm_dtbo.node(c"/fragment@0/__overlay__/bus0/backlight").unwrap();
         assert_eq!(backlight, None);
-        let backlight_symbol = symbols.getprop_str(cstr!("backlight")).unwrap();
+        let backlight_symbol = symbols.getprop_str(c"backlight").unwrap();
         assert_eq!(None, backlight_symbol);
     }
 
@@ -1440,19 +1425,19 @@
         }
         device_info.patch(platform_dt).unwrap();
 
-        let rng_node = platform_dt.node(cstr!("/bus0/backlight")).unwrap().unwrap();
-        let phandle = rng_node.getprop_u32(cstr!("phandle")).unwrap();
+        let rng_node = platform_dt.node(c"/bus0/backlight").unwrap().unwrap();
+        let phandle = rng_node.getprop_u32(c"phandle").unwrap();
         assert_ne!(None, phandle);
 
         // Note: Intentionally not using AssignedDeviceNode for matching all props.
         type FdtResult<T> = libfdt::Result<T>;
         let expected: Vec<(FdtResult<&CStr>, FdtResult<Vec<u8>>)> = vec![
-            (Ok(cstr!("android,backlight,ignore-gctrl-reset")), Ok(Vec::new())),
-            (Ok(cstr!("compatible")), Ok(Vec::from(*b"android,backlight\0"))),
-            (Ok(cstr!("interrupts")), Ok(into_fdt_prop(vec![0x0, 0xF, 0x4]))),
-            (Ok(cstr!("iommus")), Ok(Vec::new())),
-            (Ok(cstr!("phandle")), Ok(into_fdt_prop(vec![phandle.unwrap()]))),
-            (Ok(cstr!("reg")), Ok(into_fdt_prop(vec![0x0, 0x9, 0x0, 0xFF]))),
+            (Ok(c"android,backlight,ignore-gctrl-reset"), Ok(Vec::new())),
+            (Ok(c"compatible"), Ok(Vec::from(*b"android,backlight\0"))),
+            (Ok(c"interrupts"), Ok(into_fdt_prop(vec![0x0, 0xF, 0x4]))),
+            (Ok(c"iommus"), Ok(Vec::new())),
+            (Ok(c"phandle"), Ok(into_fdt_prop(vec![phandle.unwrap()]))),
+            (Ok(c"reg"), Ok(into_fdt_prop(vec![0x0, 0x9, 0x0, 0xFF]))),
         ];
 
         let mut properties: Vec<_> = rng_node
@@ -1493,7 +1478,7 @@
         }
         device_info.patch(platform_dt).unwrap();
 
-        let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu")).unwrap();
+        let compatible = platform_dt.root().next_compatible(c"pkvm,pviommu").unwrap();
         assert_eq!(None, compatible);
 
         if let Some(symbols) = platform_dt.symbols().unwrap() {
@@ -1794,12 +1779,12 @@
         let mut platform_dt_data = pvmfw_fdt_template::RAW.to_vec();
         let platform_dt = Fdt::from_mut_slice(&mut platform_dt_data).unwrap();
 
-        let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu"));
+        let compatible = platform_dt.root().next_compatible(c"pkvm,pviommu");
         assert_ne!(None, compatible.unwrap());
 
         clean(platform_dt).unwrap();
 
-        let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu"));
+        let compatible = platform_dt.root().next_compatible(c"pkvm,pviommu");
         assert_eq!(Ok(None), compatible);
     }
 
diff --git a/guest/pvmfw/src/fdt.rs b/guest/pvmfw/src/fdt.rs
index 4370675..29212f9 100644
--- a/guest/pvmfw/src/fdt.rs
+++ b/guest/pvmfw/src/fdt.rs
@@ -28,7 +28,6 @@
 use core::fmt;
 use core::mem::size_of;
 use core::ops::Range;
-use cstr::cstr;
 use hypervisor_backends::get_device_assigner;
 use hypervisor_backends::get_mem_sharer;
 use libfdt::AddressRange;
@@ -83,10 +82,10 @@
 /// Extract from /config the address range containing the pre-loaded kernel. Absence of /config is
 /// not an error.
 pub fn read_kernel_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
-    let addr = cstr!("kernel-address");
-    let size = cstr!("kernel-size");
+    let addr = c"kernel-address";
+    let size = c"kernel-size";
 
-    if let Some(config) = fdt.node(cstr!("/config"))? {
+    if let Some(config) = fdt.node(c"/config")? {
         if let (Some(addr), Some(size)) = (config.getprop_u32(addr)?, config.getprop_u32(size)?) {
             let addr = addr as usize;
             let size = size as usize;
@@ -101,8 +100,8 @@
 /// Extract from /chosen the address range containing the pre-loaded ramdisk. Absence is not an
 /// error as there can be initrd-less VM.
 pub fn read_initrd_range_from(fdt: &Fdt) -> libfdt::Result<Option<Range<usize>>> {
-    let start = cstr!("linux,initrd-start");
-    let end = cstr!("linux,initrd-end");
+    let start = c"linux,initrd-start";
+    let end = c"linux,initrd-end";
 
     if let Some(chosen) = fdt.chosen()? {
         if let (Some(start), Some(end)) = (chosen.getprop_u32(start)?, chosen.getprop_u32(end)?) {
@@ -118,14 +117,14 @@
     let end = u32::try_from(initrd_range.end).unwrap();
 
     let mut node = fdt.chosen_mut()?.ok_or(FdtError::NotFound)?;
-    node.setprop(cstr!("linux,initrd-start"), &start.to_be_bytes())?;
-    node.setprop(cstr!("linux,initrd-end"), &end.to_be_bytes())?;
+    node.setprop(c"linux,initrd-start", &start.to_be_bytes())?;
+    node.setprop(c"linux,initrd-end", &end.to_be_bytes())?;
     Ok(())
 }
 
 fn read_bootargs_from(fdt: &Fdt) -> libfdt::Result<Option<CString>> {
     if let Some(chosen) = fdt.chosen()? {
-        if let Some(bootargs) = chosen.getprop_str(cstr!("bootargs"))? {
+        if let Some(bootargs) = chosen.getprop_str(c"bootargs")? {
             // We need to copy the string to heap because the original fdt will be invalidated
             // by the templated DT
             let copy = CString::new(bootargs.to_bytes()).map_err(|_| FdtError::BadValue)?;
@@ -140,7 +139,7 @@
     // This function is called before the verification is done. So, we just copy the bootargs to
     // the new FDT unmodified. This will be filtered again in the modify_for_next_stage function
     // if the VM is not debuggable.
-    node.setprop(cstr!("bootargs"), bootargs.to_bytes_with_nul())
+    node.setprop(c"bootargs", bootargs.to_bytes_with_nul())
 }
 
 /// Reads and validates the memory range in the DT.
@@ -186,9 +185,9 @@
 fn patch_memory_range(fdt: &mut Fdt, memory_range: &Range<usize>) -> libfdt::Result<()> {
     let addr = u64::try_from(MEM_START).unwrap();
     let size = u64::try_from(memory_range.len()).unwrap();
-    fdt.node_mut(cstr!("/memory"))?
+    fdt.node_mut(c"/memory")?
         .ok_or(FdtError::NotFound)?
-        .setprop_inplace(cstr!("reg"), [addr.to_be(), size.to_be()].as_bytes())
+        .setprop_inplace(c"reg", [addr.to_be(), size.to_be()].as_bytes())
 }
 
 #[derive(Debug, Default)]
@@ -207,7 +206,7 @@
     let mut table = ArrayVec::new();
     let mut opp_nodes = opp_node.subnodes()?;
     for subnode in opp_nodes.by_ref().take(table.capacity()) {
-        let prop = subnode.getprop_u64(cstr!("opp-hz"))?.ok_or(FdtError::NotFound)?;
+        let prop = subnode.getprop_u64(c"opp-hz")?.ok_or(FdtError::NotFound)?;
         table.push(prop);
     }
 
@@ -239,7 +238,7 @@
 }
 
 fn read_cpu_map_from(fdt: &Fdt) -> libfdt::Result<Option<BTreeMap<Phandle, (usize, usize)>>> {
-    let Some(cpu_map) = fdt.node(cstr!("/cpus/cpu-map"))? else {
+    let Some(cpu_map) = fdt.node(c"/cpus/cpu-map")? else {
         return Ok(None);
     };
 
@@ -254,7 +253,7 @@
             let Some(core) = cluster.subnode(&name)? else {
                 break;
             };
-            let cpu = core.getprop_u32(cstr!("cpu"))?.ok_or(FdtError::NotFound)?;
+            let cpu = core.getprop_u32(c"cpu")?.ok_or(FdtError::NotFound)?;
             let prev = topology.insert(cpu.try_into()?, (n, m));
             if prev.is_some() {
                 return Err(FdtError::BadValue);
@@ -273,10 +272,10 @@
     let cpu_map = read_cpu_map_from(fdt)?;
     let mut topology: CpuTopology = Default::default();
 
-    let mut cpu_nodes = fdt.compatible_nodes(cstr!("arm,armv8"))?;
+    let mut cpu_nodes = fdt.compatible_nodes(c"arm,armv8")?;
     for (idx, cpu) in cpu_nodes.by_ref().take(cpus.capacity()).enumerate() {
-        let cpu_capacity = cpu.getprop_u32(cstr!("capacity-dmips-mhz"))?;
-        let opp_phandle = cpu.getprop_u32(cstr!("operating-points-v2"))?;
+        let cpu_capacity = cpu.getprop_u32(c"capacity-dmips-mhz")?;
+        let opp_phandle = cpu.getprop_u32(c"operating-points-v2")?;
         let opptable_info = if let Some(phandle) = opp_phandle {
             let phandle = phandle.try_into()?;
             let node = fdt.node_with_phandle(phandle)?.ok_or(FdtError::NotFound)?;
@@ -313,7 +312,7 @@
 }
 
 fn read_vcpufreq_info(fdt: &Fdt) -> libfdt::Result<Option<VcpufreqInfo>> {
-    let mut nodes = fdt.compatible_nodes(cstr!("virtual,android-v-only-cpufreq"))?;
+    let mut nodes = fdt.compatible_nodes(c"virtual,android-v-only-cpufreq")?;
     let Some(node) = nodes.next() else {
         return Ok(None);
     };
@@ -351,7 +350,7 @@
     node: FdtNodeMut,
     opptable: Option<ArrayVec<[u64; CpuInfo::MAX_OPPTABLES]>>,
 ) -> libfdt::Result<()> {
-    let oppcompat = cstr!("operating-points-v2");
+    let oppcompat = c"operating-points-v2";
     let next = node.next_compatible(oppcompat)?.ok_or(FdtError::NoSpace)?;
 
     let Some(opptable) = opptable else {
@@ -362,7 +361,7 @@
 
     for entry in opptable {
         let mut subnode = next_subnode.ok_or(FdtError::NoSpace)?;
-        subnode.setprop_inplace(cstr!("opp-hz"), &entry.to_be_bytes())?;
+        subnode.setprop_inplace(c"opp-hz", &entry.to_be_bytes())?;
         next_subnode = subnode.next_subnode()?;
     }
 
@@ -391,14 +390,14 @@
     cpus: &[CpuInfo],
     topology: &Option<CpuTopology>,
 ) -> libfdt::Result<()> {
-    const COMPAT: &CStr = cstr!("arm,armv8");
+    const COMPAT: &CStr = c"arm,armv8";
     let mut cpu_phandles = Vec::new();
     for (idx, cpu) in cpus.iter().enumerate() {
         let mut cur = get_nth_compatible(fdt, idx, COMPAT)?.ok_or(FdtError::NoSpace)?;
         let phandle = cur.as_node().get_phandle()?.unwrap();
         cpu_phandles.push(phandle);
         if let Some(cpu_capacity) = cpu.cpu_capacity {
-            cur.setprop_inplace(cstr!("capacity-dmips-mhz"), &cpu_capacity.to_be_bytes())?;
+            cur.setprop_inplace(c"capacity-dmips-mhz", &cpu_capacity.to_be_bytes())?;
         }
         patch_opptable(cur, cpu.opptable_info)?;
     }
@@ -418,7 +417,7 @@
                     iter = if let Some(core_idx) = core {
                         let phandle = *cpu_phandles.get(core_idx).unwrap();
                         let value = u32::from(phandle).to_be_bytes();
-                        core_node.setprop_inplace(cstr!("cpu"), &value)?;
+                        core_node.setprop_inplace(c"cpu", &value)?;
                         core_node.next_subnode()?
                     } else {
                         core_node.delete_and_next_subnode()?
@@ -430,7 +429,7 @@
             }
         }
     } else {
-        fdt.node_mut(cstr!("/cpus/cpu-map"))?.unwrap().nop()?;
+        fdt.node_mut(c"/cpus/cpu-map")?.unwrap().nop()?;
     }
 
     Ok(())
@@ -440,7 +439,7 @@
 /// the guest that don't require being validated by pvmfw.
 fn parse_untrusted_props(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
     let mut props = BTreeMap::new();
-    if let Some(node) = fdt.node(cstr!("/avf/untrusted"))? {
+    if let Some(node) = fdt.node(c"/avf/untrusted")? {
         for property in node.properties()? {
             let name = property.name()?;
             let value = property.value()?;
@@ -457,7 +456,7 @@
 /// Read candidate properties' names from DT which could be overlaid
 fn parse_vm_ref_dt(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
     let mut property_map = BTreeMap::new();
-    if let Some(avf_node) = fdt.node(cstr!("/avf"))? {
+    if let Some(avf_node) = fdt.node(c"/avf")? {
         for property in avf_node.properties()? {
             let name = property.name()?;
             let value = property.value()?;
@@ -471,8 +470,7 @@
 }
 
 fn validate_untrusted_props(props: &BTreeMap<CString, Vec<u8>>) -> Result<(), FdtValidationError> {
-    const FORBIDDEN_PROPS: &[&CStr] =
-        &[cstr!("compatible"), cstr!("linux,phandle"), cstr!("phandle")];
+    const FORBIDDEN_PROPS: &[&CStr] = &[c"compatible", c"linux,phandle", c"phandle"];
 
     for name in FORBIDDEN_PROPS {
         if props.contains_key(*name) {
@@ -491,9 +489,9 @@
     props_info: &BTreeMap<CString, Vec<u8>>,
 ) -> libfdt::Result<()> {
     let root_vm_dt = vm_dt.root_mut();
-    let mut avf_vm_dt = root_vm_dt.add_subnode(cstr!("avf"))?;
+    let mut avf_vm_dt = root_vm_dt.add_subnode(c"avf")?;
     // TODO(b/318431677): Validate nodes beyond /avf.
-    let avf_node = vm_ref_dt.node(cstr!("/avf"))?.ok_or(FdtError::NotFound)?;
+    let avf_node = vm_ref_dt.node(c"/avf")?.ok_or(FdtError::NotFound)?;
     for (name, value) in props_info.iter() {
         if let Some(ref_value) = avf_node.getprop(name)? {
             if value != ref_value {
@@ -551,14 +549,13 @@
 
 /// Read pci host controller ranges, irq maps, and irq map masks from DT
 fn read_pci_info_from(fdt: &Fdt) -> libfdt::Result<PciInfo> {
-    let node =
-        fdt.compatible_nodes(cstr!("pci-host-cam-generic"))?.next().ok_or(FdtError::NotFound)?;
+    let node = fdt.compatible_nodes(c"pci-host-cam-generic")?.next().ok_or(FdtError::NotFound)?;
 
     let mut ranges = node.ranges::<(u32, u64), u64, u64>()?.ok_or(FdtError::NotFound)?;
     let range0 = ranges.next().ok_or(FdtError::NotFound)?;
     let range1 = ranges.next().ok_or(FdtError::NotFound)?;
 
-    let irq_masks = node.getprop_cells(cstr!("interrupt-map-mask"))?.ok_or(FdtError::NotFound)?;
+    let irq_masks = node.getprop_cells(c"interrupt-map-mask")?.ok_or(FdtError::NotFound)?;
     let mut chunks = CellChunkIterator::<{ PciInfo::IRQ_MASK_CELLS }>::new(irq_masks);
     let irq_masks = (&mut chunks).take(PciInfo::MAX_IRQS).collect();
 
@@ -567,7 +564,7 @@
         return Err(FdtError::NoSpace);
     }
 
-    let irq_maps = node.getprop_cells(cstr!("interrupt-map"))?.ok_or(FdtError::NotFound)?;
+    let irq_maps = node.getprop_cells(c"interrupt-map")?.ok_or(FdtError::NotFound)?;
     let mut chunks = CellChunkIterator::<{ PciInfo::IRQ_MAP_CELLS }>::new(irq_maps);
     let irq_maps = (&mut chunks).take(PciInfo::MAX_IRQS).collect();
 
@@ -721,16 +718,16 @@
 
 fn patch_pci_info(fdt: &mut Fdt, pci_info: &PciInfo) -> libfdt::Result<()> {
     let mut node =
-        fdt.root_mut().next_compatible(cstr!("pci-host-cam-generic"))?.ok_or(FdtError::NotFound)?;
+        fdt.root_mut().next_compatible(c"pci-host-cam-generic")?.ok_or(FdtError::NotFound)?;
 
     let irq_masks_size = pci_info.irq_masks.len() * size_of::<PciIrqMask>();
-    node.trimprop(cstr!("interrupt-map-mask"), irq_masks_size)?;
+    node.trimprop(c"interrupt-map-mask", irq_masks_size)?;
 
     let irq_maps_size = pci_info.irq_maps.len() * size_of::<PciIrqMap>();
-    node.trimprop(cstr!("interrupt-map"), irq_maps_size)?;
+    node.trimprop(c"interrupt-map", irq_maps_size)?;
 
     node.setprop_inplace(
-        cstr!("ranges"),
+        c"ranges",
         [pci_info.ranges[0].to_cells(), pci_info.ranges[1].to_cells()].as_flattened(),
     )
 }
@@ -747,7 +744,7 @@
 fn read_serial_info_from(fdt: &Fdt) -> libfdt::Result<SerialInfo> {
     let mut addrs = ArrayVec::new();
 
-    let mut serial_nodes = fdt.compatible_nodes(cstr!("ns16550a"))?;
+    let mut serial_nodes = fdt.compatible_nodes(c"ns16550a")?;
     for node in serial_nodes.by_ref().take(addrs.capacity()) {
         let reg = node.first_reg()?;
         addrs.push(reg.addr);
@@ -793,7 +790,7 @@
 }
 
 fn read_wdt_info_from(fdt: &Fdt) -> libfdt::Result<WdtInfo> {
-    let mut node_iter = fdt.compatible_nodes(cstr!("qemu,vcpu-stall-detector"))?;
+    let mut node_iter = fdt.compatible_nodes(c"qemu,vcpu-stall-detector")?;
     let node = node_iter.next().ok_or(FdtError::NotFound)?;
     let mut ranges = node.reg()?.ok_or(FdtError::NotFound)?;
 
@@ -803,7 +800,7 @@
         warn!("Discarding extra vmwdt <reg> entries.");
     }
 
-    let interrupts = node.getprop_cells(cstr!("interrupts"))?.ok_or(FdtError::NotFound)?;
+    let interrupts = node.getprop_cells(c"interrupts")?.ok_or(FdtError::NotFound)?;
     let mut chunks = CellChunkIterator::<{ WdtInfo::IRQ_CELLS }>::new(interrupts);
     let irq = chunks.next().ok_or(FdtError::NotFound)?;
 
@@ -831,15 +828,15 @@
 
     let mut node = fdt
         .root_mut()
-        .next_compatible(cstr!("qemu,vcpu-stall-detector"))?
+        .next_compatible(c"qemu,vcpu-stall-detector")?
         .ok_or(libfdt::FdtError::NotFound)?;
-    node.setprop_inplace(cstr!("interrupts"), interrupts.as_bytes())?;
+    node.setprop_inplace(c"interrupts", interrupts.as_bytes())?;
     Ok(())
 }
 
 /// Patch the DT by deleting the ns16550a compatible nodes whose address are unknown
 fn patch_serial_info(fdt: &mut Fdt, serial_info: &SerialInfo) -> libfdt::Result<()> {
-    let name = cstr!("ns16550a");
+    let name = c"ns16550a";
     let mut next = fdt.root_mut().next_compatible(name);
     while let Some(current) = next? {
         let reg =
@@ -889,27 +886,27 @@
 
 fn patch_swiotlb_info(fdt: &mut Fdt, swiotlb_info: &SwiotlbInfo) -> libfdt::Result<()> {
     let mut node =
-        fdt.root_mut().next_compatible(cstr!("restricted-dma-pool"))?.ok_or(FdtError::NotFound)?;
+        fdt.root_mut().next_compatible(c"restricted-dma-pool")?.ok_or(FdtError::NotFound)?;
 
     if let Some(range) = swiotlb_info.fixed_range() {
         node.setprop_addrrange_inplace(
-            cstr!("reg"),
+            c"reg",
             range.start.try_into().unwrap(),
             range.len().try_into().unwrap(),
         )?;
-        node.nop_property(cstr!("size"))?;
-        node.nop_property(cstr!("alignment"))?;
+        node.nop_property(c"size")?;
+        node.nop_property(c"alignment")?;
     } else {
-        node.nop_property(cstr!("reg"))?;
-        node.setprop_inplace(cstr!("size"), &swiotlb_info.size.to_be_bytes())?;
-        node.setprop_inplace(cstr!("alignment"), &swiotlb_info.align.unwrap().to_be_bytes())?;
+        node.nop_property(c"reg")?;
+        node.setprop_inplace(c"size", &swiotlb_info.size.to_be_bytes())?;
+        node.setprop_inplace(c"alignment", &swiotlb_info.align.unwrap().to_be_bytes())?;
     }
 
     Ok(())
 }
 
 fn patch_gic(fdt: &mut Fdt, num_cpus: usize) -> libfdt::Result<()> {
-    let node = fdt.compatible_nodes(cstr!("arm,gic-v3"))?.next().ok_or(FdtError::NotFound)?;
+    let node = fdt.compatible_nodes(c"arm,gic-v3")?.next().ok_or(FdtError::NotFound)?;
     let mut ranges = node.reg()?.ok_or(FdtError::NotFound)?;
     let range0 = ranges.next().ok_or(FdtError::NotFound)?;
     let mut range1 = ranges.next().ok_or(FdtError::NotFound)?;
@@ -927,16 +924,15 @@
     let (addr1, size1) = range1.to_cells();
     let value = [addr0, size0.unwrap(), addr1, size1.unwrap()];
 
-    let mut node =
-        fdt.root_mut().next_compatible(cstr!("arm,gic-v3"))?.ok_or(FdtError::NotFound)?;
-    node.setprop_inplace(cstr!("reg"), value.as_flattened())
+    let mut node = fdt.root_mut().next_compatible(c"arm,gic-v3")?.ok_or(FdtError::NotFound)?;
+    node.setprop_inplace(c"reg", value.as_flattened())
 }
 
 fn patch_timer(fdt: &mut Fdt, num_cpus: usize) -> libfdt::Result<()> {
     const NUM_INTERRUPTS: usize = 4;
     const CELLS_PER_INTERRUPT: usize = 3;
-    let node = fdt.compatible_nodes(cstr!("arm,armv8-timer"))?.next().ok_or(FdtError::NotFound)?;
-    let interrupts = node.getprop_cells(cstr!("interrupts"))?.ok_or(FdtError::NotFound)?;
+    let node = fdt.compatible_nodes(c"arm,armv8-timer")?.next().ok_or(FdtError::NotFound)?;
+    let interrupts = node.getprop_cells(c"interrupts")?.ok_or(FdtError::NotFound)?;
     let mut value: ArrayVec<[u32; NUM_INTERRUPTS * CELLS_PER_INTERRUPT]> =
         interrupts.take(NUM_INTERRUPTS * CELLS_PER_INTERRUPT).collect();
 
@@ -953,20 +949,19 @@
 
     let value = value.into_inner();
 
-    let mut node =
-        fdt.root_mut().next_compatible(cstr!("arm,armv8-timer"))?.ok_or(FdtError::NotFound)?;
-    node.setprop_inplace(cstr!("interrupts"), value.as_bytes())
+    let mut node = fdt.root_mut().next_compatible(c"arm,armv8-timer")?.ok_or(FdtError::NotFound)?;
+    node.setprop_inplace(c"interrupts", value.as_bytes())
 }
 
 fn patch_untrusted_props(fdt: &mut Fdt, props: &BTreeMap<CString, Vec<u8>>) -> libfdt::Result<()> {
-    let avf_node = if let Some(node) = fdt.node_mut(cstr!("/avf"))? {
+    let avf_node = if let Some(node) = fdt.node_mut(c"/avf")? {
         node
     } else {
-        fdt.root_mut().add_subnode(cstr!("avf"))?
+        fdt.root_mut().add_subnode(c"avf")?
     };
 
     // The node shouldn't already be present; if it is, return the error.
-    let mut node = avf_node.add_subnode(cstr!("untrusted"))?;
+    let mut node = avf_node.add_subnode(c"untrusted")?;
 
     for (name, value) in props {
         node.setprop(name, value)?;
@@ -982,9 +977,9 @@
 }
 
 fn patch_vcpufreq(fdt: &mut Fdt, vcpufreq_info: &Option<VcpufreqInfo>) -> libfdt::Result<()> {
-    let mut node = fdt.node_mut(cstr!("/cpufreq"))?.unwrap();
+    let mut node = fdt.node_mut(c"/cpufreq")?.unwrap();
     if let Some(info) = vcpufreq_info {
-        node.setprop_addrrange_inplace(cstr!("reg"), info.addr, info.size)
+        node.setprop_addrrange_inplace(c"reg", info.addr, info.size)
     } else {
         node.nop()
     }
@@ -1304,9 +1299,9 @@
     patch_dice_node(fdt, bcc.as_ptr() as usize, bcc.len())?;
 
     if let Some(mut chosen) = fdt.chosen_mut()? {
-        empty_or_delete_prop(&mut chosen, cstr!("avf,strict-boot"), strict_boot)?;
-        empty_or_delete_prop(&mut chosen, cstr!("avf,new-instance"), new_instance)?;
-        chosen.setprop_inplace(cstr!("kaslr-seed"), &kaslr_seed.to_be_bytes())?;
+        empty_or_delete_prop(&mut chosen, c"avf,strict-boot", strict_boot)?;
+        empty_or_delete_prop(&mut chosen, c"avf,new-instance", new_instance)?;
+        chosen.setprop_inplace(c"kaslr-seed", &kaslr_seed.to_be_bytes())?;
     };
     if !debuggable {
         if let Some(bootargs) = read_bootargs_from(fdt)? {
@@ -1323,13 +1318,13 @@
 fn patch_dice_node(fdt: &mut Fdt, addr: usize, size: usize) -> libfdt::Result<()> {
     // We reject DTs with missing reserved-memory node as validation should have checked that the
     // "swiotlb" subnode (compatible = "restricted-dma-pool") was present.
-    let node = fdt.node_mut(cstr!("/reserved-memory"))?.ok_or(libfdt::FdtError::NotFound)?;
+    let node = fdt.node_mut(c"/reserved-memory")?.ok_or(libfdt::FdtError::NotFound)?;
 
-    let mut node = node.next_compatible(cstr!("google,open-dice"))?.ok_or(FdtError::NotFound)?;
+    let mut node = node.next_compatible(c"google,open-dice")?.ok_or(FdtError::NotFound)?;
 
     let addr: u64 = addr.try_into().unwrap();
     let size: u64 = size.try_into().unwrap();
-    node.setprop_inplace(cstr!("reg"), [addr.to_be_bytes(), size.to_be_bytes()].as_flattened())
+    node.setprop_inplace(c"reg", [addr.to_be_bytes(), size.to_be_bytes()].as_flattened())
 }
 
 fn empty_or_delete_prop(
@@ -1376,7 +1371,7 @@
 }
 
 fn has_common_debug_policy(fdt: &Fdt, debug_feature_name: &CStr) -> libfdt::Result<bool> {
-    if let Some(node) = fdt.node(cstr!("/avf/guest/common"))? {
+    if let Some(node) = fdt.node(c"/avf/guest/common")? {
         if let Some(value) = node.getprop_u32(debug_feature_name)? {
             return Ok(value == 1);
         }
@@ -1385,8 +1380,8 @@
 }
 
 fn filter_out_dangerous_bootargs(fdt: &mut Fdt, bootargs: &CStr) -> libfdt::Result<()> {
-    let has_crashkernel = has_common_debug_policy(fdt, cstr!("ramdump"))?;
-    let has_console = has_common_debug_policy(fdt, cstr!("log"))?;
+    let has_crashkernel = has_common_debug_policy(fdt, c"ramdump")?;
+    let has_console = has_common_debug_policy(fdt, c"log")?;
 
     let accepted: &[(&str, Box<dyn Fn(Option<&str>) -> bool>)] = &[
         ("panic", Box::new(|v| if let Some(v) = v { v == "=-1" } else { false })),
@@ -1417,5 +1412,5 @@
     new_bootargs.push(b'\0');
 
     let mut node = fdt.chosen_mut()?.ok_or(FdtError::NotFound)?;
-    node.setprop(cstr!("bootargs"), new_bootargs.as_slice())
+    node.setprop(c"bootargs", new_bootargs.as_slice())
 }
diff --git a/guest/pvmfw/src/main.rs b/guest/pvmfw/src/main.rs
index a28a039..5ff9c4c 100644
--- a/guest/pvmfw/src/main.rs
+++ b/guest/pvmfw/src/main.rs
@@ -40,7 +40,6 @@
 use alloc::borrow::Cow;
 use alloc::boxed::Box;
 use bssl_avf::Digester;
-use cstr::cstr;
 use diced_open_dice::{bcc_handover_parse, DiceArtifacts, DiceContext, Hidden, VM_KEY_ALGORITHM};
 use libfdt::{Fdt, FdtNode};
 use log::{debug, error, info, trace, warn};
@@ -220,7 +219,7 @@
 
 fn instance_id(fdt: &Fdt) -> Result<&[u8], RebootReason> {
     let node = avf_untrusted_node(fdt)?;
-    let id = node.getprop(cstr!("instance-id")).map_err(|e| {
+    let id = node.getprop(c"instance-id").map_err(|e| {
         error!("Failed to get instance-id in DT: {e}");
         RebootReason::InvalidFdt
     })?;
@@ -231,7 +230,7 @@
 }
 
 fn avf_untrusted_node(fdt: &Fdt) -> Result<FdtNode, RebootReason> {
-    let node = fdt.node(cstr!("/avf/untrusted")).map_err(|e| {
+    let node = fdt.node(c"/avf/untrusted").map_err(|e| {
         error!("Failed to get /avf/untrusted node: {e}");
         RebootReason::InvalidFdt
     })?;
diff --git a/guest/pvmfw/src/rollback.rs b/guest/pvmfw/src/rollback.rs
index bc16332..15d22b3 100644
--- a/guest/pvmfw/src/rollback.rs
+++ b/guest/pvmfw/src/rollback.rs
@@ -19,7 +19,6 @@
 use crate::instance::EntryBody;
 use crate::instance::Error as InstanceError;
 use crate::instance::{get_recorded_entry, record_instance_entry};
-use cstr::cstr;
 use diced_open_dice::Hidden;
 use libfdt::{Fdt, FdtNode};
 use log::{error, info};
@@ -138,7 +137,7 @@
 fn should_defer_rollback_protection(fdt: &Fdt) -> Result<bool, RebootReason> {
     let node = avf_untrusted_node(fdt)?;
     let defer_rbp = node
-        .getprop(cstr!("defer-rollback-protection"))
+        .getprop(c"defer-rollback-protection")
         .map_err(|e| {
             error!("Failed to get defer-rollback-protection property in DT: {e}");
             RebootReason::InvalidFdt
@@ -148,7 +147,7 @@
 }
 
 fn avf_untrusted_node(fdt: &Fdt) -> Result<FdtNode, RebootReason> {
-    let node = fdt.node(cstr!("/avf/untrusted")).map_err(|e| {
+    let node = fdt.node(c"/avf/untrusted").map_err(|e| {
         error!("Failed to get /avf/untrusted node: {e}");
         RebootReason::InvalidFdt
     })?;
diff --git a/guest/rialto/Android.bp b/guest/rialto/Android.bp
index a525168..35ede7a 100644
--- a/guest/rialto/Android.bp
+++ b/guest/rialto/Android.bp
@@ -12,7 +12,6 @@
         "libbssl_avf_nostd",
         "libciborium_io_nostd",
         "libciborium_nostd",
-        "libcstr",
         "libdiced_open_dice_nostd",
         "libhypervisor_backends",
         "liblibfdt_nostd",
diff --git a/guest/rialto/src/fdt.rs b/guest/rialto/src/fdt.rs
index e97a262..06879d0 100644
--- a/guest/rialto/src/fdt.rs
+++ b/guest/rialto/src/fdt.rs
@@ -15,24 +15,23 @@
 //! High-level FDT functions.
 
 use core::ops::Range;
-use cstr::cstr;
 use libfdt::{Fdt, FdtError};
 
 /// Reads the DICE data range from the given `fdt`.
 pub fn read_dice_range_from(fdt: &Fdt) -> libfdt::Result<Range<usize>> {
-    let node = fdt.node(cstr!("/reserved-memory"))?.ok_or(FdtError::NotFound)?;
-    let node = node.next_compatible(cstr!("google,open-dice"))?.ok_or(FdtError::NotFound)?;
+    let node = fdt.node(c"/reserved-memory")?.ok_or(FdtError::NotFound)?;
+    let node = node.next_compatible(c"google,open-dice")?.ok_or(FdtError::NotFound)?;
     node.first_reg()?.try_into()
 }
 
 pub(crate) fn read_vendor_hashtree_root_digest(fdt: &Fdt) -> libfdt::Result<Option<&[u8]>> {
-    let node = fdt.node(cstr!("/avf"))?.ok_or(FdtError::NotFound)?;
-    node.getprop(cstr!("vendor_hashtree_descriptor_root_digest"))
+    let node = fdt.node(c"/avf")?.ok_or(FdtError::NotFound)?;
+    node.getprop(c"vendor_hashtree_descriptor_root_digest")
 }
 
 pub(crate) fn read_is_strict_boot(fdt: &Fdt) -> libfdt::Result<bool> {
     match fdt.chosen()? {
-        Some(node) => Ok(node.getprop(cstr!("avf,strict-boot"))?.is_some()),
+        Some(node) => Ok(node.getprop(c"avf,strict-boot")?.is_some()),
         None => Ok(false),
     }
 }
diff --git a/guest/vmbase_example/Android.bp b/guest/vmbase_example/Android.bp
index 09bd77c..ab21191 100644
--- a/guest/vmbase_example/Android.bp
+++ b/guest/vmbase_example/Android.bp
@@ -9,7 +9,6 @@
     srcs: ["src/main.rs"],
     rustlibs: [
         "libaarch64_paging",
-        "libcstr",
         "libdiced_open_dice_nostd",
         "liblibfdt_nostd",
         "liblog_rust_nostd",
diff --git a/guest/vmbase_example/src/main.rs b/guest/vmbase_example/src/main.rs
index 4c5e880..f5b41bd 100644
--- a/guest/vmbase_example/src/main.rs
+++ b/guest/vmbase_example/src/main.rs
@@ -27,7 +27,6 @@
 use crate::pci::check_pci;
 use alloc::{vec, vec::Vec};
 use core::ptr::addr_of_mut;
-use cstr::cstr;
 use libfdt::Fdt;
 use log::{debug, error, info, trace, warn, LevelFilter};
 use vmbase::{
@@ -147,7 +146,7 @@
         info!("memory @ {reg:#x?}");
     }
 
-    let compatible = cstr!("ns16550a");
+    let compatible = c"ns16550a";
 
     for c in reader.compatible_nodes(compatible).unwrap() {
         let reg = c.reg().unwrap().unwrap().next().unwrap();
@@ -159,17 +158,17 @@
     writer.unpack().unwrap();
     info!("FDT successfully unpacked.");
 
-    let path = cstr!("/memory");
+    let path = c"/memory";
     let node = writer.node_mut(path).unwrap().unwrap();
-    let name = cstr!("child");
+    let name = c"child";
     let mut child = node.add_subnode(name).unwrap();
     info!("Created subnode '{}/{}'.", path.to_str().unwrap(), name.to_str().unwrap());
 
-    let name = cstr!("str-property");
+    let name = c"str-property";
     child.appendprop(name, b"property-value\0").unwrap();
     info!("Appended property '{}'.", name.to_str().unwrap());
 
-    let name = cstr!("pair-property");
+    let name = c"pair-property";
     let addr = 0x0123_4567u64;
     let size = 0x89ab_cdefu64;
     child.appendprop_addrrange(name, addr, size).unwrap();
diff --git a/libs/debian_service/proto/DebianService.proto b/libs/debian_service/proto/DebianService.proto
index 7ab0af7..43955fa 100644
--- a/libs/debian_service/proto/DebianService.proto
+++ b/libs/debian_service/proto/DebianService.proto
@@ -31,9 +31,9 @@
   int32 cid = 1;
 }
 
-// TODO(b/382998551): Add more information about the port.
 message ActivePort {
   int32 port = 1;
+  string comm = 2;
 }
 
 message ReportVmActivePortsRequest {
diff --git a/libs/libfdt/Android.bp b/libs/libfdt/Android.bp
index 09f288d..829b30f 100644
--- a/libs/libfdt/Android.bp
+++ b/libs/libfdt/Android.bp
@@ -35,7 +35,6 @@
     ],
     edition: "2021",
     rustlibs: [
-        "libcstr",
         "liblibfdt_bindgen",
         "libstatic_assertions",
         "libzerocopy_nostd",
@@ -79,7 +78,6 @@
     ],
     prefer_rlib: true,
     rustlibs: [
-        "libcstr",
         "liblibfdt",
     ],
 }
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index c969749..0dcd31a 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -31,7 +31,6 @@
 
 use core::ffi::{c_void, CStr};
 use core::ops::Range;
-use cstr::cstr;
 use libfdt::get_slice_at_ptr;
 use zerocopy::IntoBytes as _;
 
@@ -167,12 +166,12 @@
 
     /// Returns the standard (deprecated) device_type <string> property.
     pub fn device_type(&self) -> Result<Option<&CStr>> {
-        self.getprop_str(cstr!("device_type"))
+        self.getprop_str(c"device_type")
     }
 
     /// Returns the standard reg <prop-encoded-array> property.
     pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
-        if let Some(cells) = self.getprop_cells(cstr!("reg"))? {
+        if let Some(cells) = self.getprop_cells(c"reg")? {
             let parent = self.parent()?;
 
             let addr_cells = parent.address_cells()?;
@@ -186,7 +185,7 @@
 
     /// Returns the standard ranges property.
     pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
-        if let Some(cells) = self.getprop_cells(cstr!("ranges"))? {
+        if let Some(cells) = self.getprop_cells(c"ranges")? {
             let parent = self.parent()?;
             let addr_cells = self.address_cells()?;
             let parent_addr_cells = parent.address_cells()?;
@@ -320,9 +319,9 @@
     /// Returns the phandle
     pub fn get_phandle(&self) -> Result<Option<Phandle>> {
         // This rewrites the fdt_get_phandle() because it doesn't return error code.
-        if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
+        if let Some(prop) = self.getprop_u32(c"phandle")? {
             Ok(Some(prop.try_into()?))
-        } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
+        } else if let Some(prop) = self.getprop_u32(c"linux,phandle")? {
             Ok(Some(prop.try_into()?))
         } else {
             Ok(None)
@@ -693,8 +692,8 @@
     ///
     /// NOTE: This does not support individual "/memory@XXXX" banks.
     pub fn memory(&self) -> Result<MemRegIterator> {
-        let node = self.root().subnode(cstr!("memory"))?.ok_or(FdtError::NotFound)?;
-        if node.device_type()? != Some(cstr!("memory")) {
+        let node = self.root().subnode(c"memory")?.ok_or(FdtError::NotFound)?;
+        if node.device_type()? != Some(c"memory") {
             return Err(FdtError::BadValue);
         }
         node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
@@ -707,12 +706,12 @@
 
     /// Returns the standard /chosen node.
     pub fn chosen(&self) -> Result<Option<FdtNode>> {
-        self.root().subnode(cstr!("chosen"))
+        self.root().subnode(c"chosen")
     }
 
     /// Returns the standard /chosen node as mutable.
     pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
-        self.node_mut(cstr!("/chosen"))
+        self.node_mut(c"/chosen")
     }
 
     /// Returns the root node of the tree.
@@ -722,12 +721,12 @@
 
     /// Returns the standard /__symbols__ node.
     pub fn symbols(&self) -> Result<Option<FdtNode>> {
-        self.root().subnode(cstr!("__symbols__"))
+        self.root().subnode(c"__symbols__")
     }
 
     /// Returns the standard /__symbols__ node as mutable
     pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
-        self.node_mut(cstr!("/__symbols__"))
+        self.node_mut(c"/__symbols__")
     }
 
     /// Returns a tree node by its full path.
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index f521a00..e027164 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -17,7 +17,6 @@
 //! Integration tests of the library libfdt.
 
 use core::ffi::CStr;
-use cstr::cstr;
 use libfdt::{Fdt, FdtError, FdtNodeMut, Phandle};
 use std::collections::HashSet;
 use std::ffi::CString;
@@ -82,14 +81,14 @@
     let fdt = Fdt::from_slice(&data).unwrap();
 
     let root = fdt.root();
-    assert_eq!(root.name(), Ok(cstr!("")));
+    assert_eq!(root.name(), Ok(c""));
 
     let chosen = fdt.chosen().unwrap().unwrap();
-    assert_eq!(chosen.name(), Ok(cstr!("chosen")));
+    assert_eq!(chosen.name(), Ok(c"chosen"));
 
-    let nested_node_path = cstr!("/cpus/PowerPC,970@0");
+    let nested_node_path = c"/cpus/PowerPC,970@0";
     let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
-    assert_eq!(nested_node.name(), Ok(cstr!("PowerPC,970@0")));
+    assert_eq!(nested_node.name(), Ok(c"PowerPC,970@0"));
 }
 
 #[test]
@@ -97,7 +96,7 @@
     let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
     let fdt = Fdt::from_slice(&data).unwrap();
     let root = fdt.root();
-    let expected = [Ok(cstr!("cpus")), Ok(cstr!("randomnode")), Ok(cstr!("chosen"))];
+    let expected = [Ok(c"cpus"), Ok(c"randomnode"), Ok(c"chosen")];
 
     let root_subnodes = root.subnodes().unwrap();
     let subnode_names: Vec<_> = root_subnodes.map(|node| node.name()).collect();
@@ -112,11 +111,11 @@
     let one_be = 0x1_u32.to_be_bytes();
     type Result<T> = core::result::Result<T, FdtError>;
     let expected: Vec<(Result<&CStr>, Result<&[u8]>)> = vec![
-        (Ok(cstr!("model")), Ok(b"MyBoardName\0".as_ref())),
-        (Ok(cstr!("compatible")), Ok(b"MyBoardName\0MyBoardFamilyName\0".as_ref())),
-        (Ok(cstr!("#address-cells")), Ok(&one_be)),
-        (Ok(cstr!("#size-cells")), Ok(&one_be)),
-        (Ok(cstr!("empty_prop")), Ok(&[])),
+        (Ok(c"model"), Ok(b"MyBoardName\0".as_ref())),
+        (Ok(c"compatible"), Ok(b"MyBoardName\0MyBoardFamilyName\0".as_ref())),
+        (Ok(c"#address-cells"), Ok(&one_be)),
+        (Ok(c"#size-cells"), Ok(&one_be)),
+        (Ok(c"empty_prop"), Ok(&[])),
     ];
 
     let properties = root.properties().unwrap();
@@ -129,8 +128,8 @@
 fn node_supernode_at_depth() {
     let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
     let fdt = Fdt::from_slice(&data).unwrap();
-    let node = fdt.node(cstr!("/cpus/PowerPC,970@1")).unwrap().unwrap();
-    let expected = vec![Ok(cstr!("")), Ok(cstr!("cpus")), Ok(cstr!("PowerPC,970@1"))];
+    let node = fdt.node(c"/cpus/PowerPC,970@1").unwrap().unwrap();
+    let expected = vec![Ok(c""), Ok(c"cpus"), Ok(c"PowerPC,970@1")];
 
     let mut supernode_names = vec![];
     let mut depth = 0;
@@ -187,12 +186,12 @@
     // Test linux,phandle
     let phandle = Phandle::new(0xFF).unwrap();
     let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
-    assert_eq!(node.name(), Ok(cstr!("node_zz")));
+    assert_eq!(node.name(), Ok(c"node_zz"));
 
     // Test phandle
     let phandle = Phandle::new(0x22).unwrap();
     let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
-    assert_eq!(node.name(), Ok(cstr!("node_abc")));
+    assert_eq!(node.name(), Ok(c"node_abc"));
 }
 
 #[test]
@@ -203,12 +202,12 @@
     // Test linux,phandle
     let phandle = Phandle::new(0xFF).unwrap();
     let node: FdtNodeMut = fdt.node_mut_with_phandle(phandle).unwrap().unwrap();
-    assert_eq!(node.as_node().name(), Ok(cstr!("node_zz")));
+    assert_eq!(node.as_node().name(), Ok(c"node_zz"));
 
     // Test phandle
     let phandle = Phandle::new(0x22).unwrap();
     let node: FdtNodeMut = fdt.node_mut_with_phandle(phandle).unwrap().unwrap();
-    assert_eq!(node.as_node().name(), Ok(cstr!("node_abc")));
+    assert_eq!(node.as_node().name(), Ok(c"node_abc"));
 }
 
 #[test]
@@ -217,15 +216,15 @@
     let fdt = Fdt::from_slice(&data).unwrap();
 
     // Test linux,phandle
-    let node = fdt.node(cstr!("/node_z/node_zz")).unwrap().unwrap();
+    let node = fdt.node(c"/node_z/node_zz").unwrap().unwrap();
     assert_eq!(node.get_phandle(), Ok(Phandle::new(0xFF)));
 
     // Test phandle
-    let node = fdt.node(cstr!("/node_a/node_ab/node_abc")).unwrap().unwrap();
+    let node = fdt.node(c"/node_a/node_ab/node_abc").unwrap().unwrap();
     assert_eq!(node.get_phandle(), Ok(Phandle::new(0x22)));
 
     // Test no phandle
-    let node = fdt.node(cstr!("/node_b")).unwrap().unwrap();
+    let node = fdt.node(c"/node_b").unwrap().unwrap();
     assert_eq!(node.get_phandle(), Ok(None));
 }
 
@@ -234,7 +233,7 @@
     let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
     let fdt = Fdt::from_mut_slice(&mut data).unwrap();
     let phandle = Phandle::new(0xFF).unwrap();
-    let path = cstr!("/node_z/node_zz");
+    let path = c"/node_z/node_zz";
 
     fdt.node_with_phandle(phandle).unwrap().unwrap();
     let node = fdt.node_mut(path).unwrap().unwrap();
@@ -259,8 +258,8 @@
     let fdt = Fdt::from_mut_slice(&mut data).unwrap();
     fdt.unpack().unwrap();
 
-    let node_path = cstr!("/node_z/node_zz");
-    let subnode_name = cstr!("123456789");
+    let node_path = c"/node_z/node_zz";
+    let subnode_name = c"123456789";
 
     for len in 0..subnode_name.to_bytes().len() {
         let name = &subnode_name.to_bytes()[0..len];
@@ -289,7 +288,7 @@
     let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
     let fdt = Fdt::from_slice(&data).unwrap();
 
-    let name = cstr!("node_a");
+    let name = c"node_a";
     let root = fdt.root();
     let node = root.subnode(name).unwrap();
     assert_ne!(None, node);
@@ -309,7 +308,7 @@
     assert_ne!(None, node);
     let node = node.unwrap();
 
-    assert_eq!(Ok(cstr!("node_a")), node.name());
+    assert_eq!(Ok(c"node_a"), node.name());
 }
 
 #[test]
@@ -317,7 +316,7 @@
     let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
     let fdt = Fdt::from_slice(&data).unwrap();
 
-    let name = cstr!("node_a");
+    let name = c"node_a";
     let node = {
         let root = fdt.root();
         root.subnode(name).unwrap().unwrap()
@@ -332,7 +331,7 @@
     let fdt = Fdt::from_mut_slice(&mut data).unwrap();
 
     let symbols = fdt.symbols().unwrap().unwrap();
-    assert_eq!(symbols.name(), Ok(cstr!("__symbols__")));
+    assert_eq!(symbols.name(), Ok(c"__symbols__"));
 
     // Validates type.
     let _symbols: FdtNodeMut = fdt.symbols_mut().unwrap().unwrap();
@@ -343,14 +342,14 @@
     let mut data = fs::read(TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH).unwrap();
     let fdt = Fdt::from_mut_slice(&mut data).unwrap();
 
-    let mut memory = fdt.node_mut(cstr!("/memory")).unwrap().unwrap();
+    let mut memory = fdt.node_mut(c"/memory").unwrap().unwrap();
     {
         let memory = memory.as_node();
-        assert_eq!(memory.name(), Ok(cstr!("memory")));
+        assert_eq!(memory.name(), Ok(c"memory"));
     }
 
     // Just check whether borrow checker doesn't complain this.
-    memory.setprop_inplace(cstr!("device_type"), b"MEMORY\0").unwrap();
+    memory.setprop_inplace(c"device_type", b"MEMORY\0").unwrap();
 }
 
 #[test]
@@ -358,18 +357,13 @@
     let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
     let fdt = Fdt::from_mut_slice(&mut data).unwrap();
 
-    let node_z = fdt.node(cstr!("/node_z")).unwrap().unwrap();
+    let node_z = fdt.node(c"/node_z").unwrap().unwrap();
     let descendants: Vec<_> =
         node_z.descendants().map(|(node, depth)| (node.name().unwrap(), depth)).collect();
 
     assert_eq!(
         descendants,
-        vec![
-            (cstr!("node_za"), 1),
-            (cstr!("node_zb"), 1),
-            (cstr!("node_zz"), 1),
-            (cstr!("node_zzz"), 2)
-        ]
+        vec![(c"node_za", 1), (c"node_zb", 1), (c"node_zz", 1), (c"node_zzz", 2)]
     );
 }
 
@@ -382,7 +376,7 @@
     let mut subnode_iter = root.first_subnode().unwrap();
 
     while let Some(subnode) = subnode_iter {
-        if subnode.as_node().name() == Ok(cstr!("node_z")) {
+        if subnode.as_node().name() == Ok(c"node_z") {
             subnode_iter = subnode.delete_and_next_subnode().unwrap();
         } else {
             subnode_iter = subnode.next_subnode().unwrap();
@@ -390,12 +384,7 @@
     }
 
     let root = fdt.root();
-    let expected_names = vec![
-        Ok(cstr!("node_a")),
-        Ok(cstr!("node_b")),
-        Ok(cstr!("node_c")),
-        Ok(cstr!("__symbols__")),
-    ];
+    let expected_names = vec![Ok(c"node_a"), Ok(c"node_b"), Ok(c"node_c"), Ok(c"__symbols__")];
     let subnode_names: Vec<_> = root.subnodes().unwrap().map(|node| node.name()).collect();
 
     assert_eq!(expected_names, subnode_names);
@@ -407,19 +396,19 @@
     let fdt = Fdt::from_mut_slice(&mut data).unwrap();
 
     let expected_nodes = vec![
-        (Ok(cstr!("node_b")), 1),
-        (Ok(cstr!("node_c")), 1),
-        (Ok(cstr!("node_z")), 1),
-        (Ok(cstr!("node_za")), 2),
-        (Ok(cstr!("node_zb")), 2),
-        (Ok(cstr!("__symbols__")), 1),
+        (Ok(c"node_b"), 1),
+        (Ok(c"node_c"), 1),
+        (Ok(c"node_z"), 1),
+        (Ok(c"node_za"), 2),
+        (Ok(c"node_zb"), 2),
+        (Ok(c"__symbols__"), 1),
     ];
 
     let mut expected_nodes_iter = expected_nodes.iter();
     let mut iter = fdt.root_mut().next_node(0).unwrap();
     while let Some((node, depth)) = iter {
         let node_name = node.as_node().name();
-        if node_name == Ok(cstr!("node_a")) || node_name == Ok(cstr!("node_zz")) {
+        if node_name == Ok(c"node_a") || node_name == Ok(c"node_zz") {
             iter = node.delete_and_next_node(depth).unwrap();
         } else {
             // Note: Checking name here is easier than collecting names and assert_eq!(),
@@ -464,7 +453,7 @@
         root.name()
         // Make root to be dropped
     };
-    assert_eq!(Ok(cstr!("")), name);
+    assert_eq!(Ok(c""), name);
 }
 
 #[test]
@@ -473,7 +462,7 @@
     let fdt = Fdt::create_empty_tree(&mut data).unwrap();
 
     let root = fdt.root_mut();
-    let names = [cstr!("a"), cstr!("b")];
+    let names = [c"a", c"b"];
     root.add_subnodes(&names).unwrap();
 
     let expected: HashSet<_> = names.into_iter().collect();
@@ -492,14 +481,14 @@
     let name = {
         let node_a = {
             let root = fdt.root();
-            root.subnode(cstr!("node_a")).unwrap()
+            root.subnode(c"node_a").unwrap()
             // Make root to be dropped
         };
         assert_ne!(None, node_a);
         node_a.unwrap().name()
         // Make node_a to be dropped
     };
-    assert_eq!(Ok(cstr!("node_a")), name);
+    assert_eq!(Ok(c"node_a"), name);
 }
 
 #[test]
@@ -521,7 +510,7 @@
         first_subnode.name()
         // Make first_subnode to be dropped
     };
-    assert_eq!(Ok(cstr!("node_a")), first_subnode_name);
+    assert_eq!(Ok(c"node_a"), first_subnode_name);
 }
 
 #[test]
@@ -543,5 +532,5 @@
         first_descendant.name()
         // Make first_descendant to be dropped
     };
-    assert_eq!(Ok(cstr!("node_a")), first_descendant_name);
+    assert_eq!(Ok(c"node_a"), first_descendant_name);
 }
diff --git a/libs/libservice_vm_fake_chain/Android.bp b/libs/libservice_vm_fake_chain/Android.bp
index 56fb22a..65eddf8 100644
--- a/libs/libservice_vm_fake_chain/Android.bp
+++ b/libs/libservice_vm_fake_chain/Android.bp
@@ -26,9 +26,6 @@
         "//packages/modules/Virtualization/guest/rialto:__subpackages__",
     ],
     prefer_rlib: true,
-    rustlibs: [
-        "libcstr",
-    ],
 }
 
 rust_library {
diff --git a/libs/libservice_vm_fake_chain/src/client_vm.rs b/libs/libservice_vm_fake_chain/src/client_vm.rs
index dc499e0..fa72739 100644
--- a/libs/libservice_vm_fake_chain/src/client_vm.rs
+++ b/libs/libservice_vm_fake_chain/src/client_vm.rs
@@ -22,7 +22,6 @@
 use ciborium::{cbor, value::Value};
 use core::result;
 use coset::CborSerializable;
-use cstr::cstr;
 use diced_open_dice::{
     hash, retry_bcc_format_config_descriptor, retry_bcc_main_flow, Config, DiceArtifacts,
     DiceConfigValues, DiceError, DiceMode, InputValues, OwnedDiceArtifacts, Result, HASH_SIZE,
@@ -96,7 +95,7 @@
 
     // Adds an entry describing the Microdroid kernel.
     let config_values = DiceConfigValues {
-        component_name: Some(cstr!("vm_entry")),
+        component_name: Some(c"vm_entry"),
         component_version: Some(12),
         resettable: true,
         security_version: Some(13),
diff --git a/libs/libservice_vm_fake_chain/src/service_vm.rs b/libs/libservice_vm_fake_chain/src/service_vm.rs
index 04297e4..5064ff8 100644
--- a/libs/libservice_vm_fake_chain/src/service_vm.rs
+++ b/libs/libservice_vm_fake_chain/src/service_vm.rs
@@ -24,7 +24,6 @@
     iana::{self, EnumI64},
     Algorithm, AsCborValue, CborSerializable, CoseKey, KeyOperation, KeyType, Label,
 };
-use cstr::cstr;
 use diced_open_dice::{
     derive_cdi_private_key_seed, keypair_from_seed, retry_bcc_format_config_descriptor,
     retry_bcc_main_flow, retry_dice_main_flow, CdiValues, Config, DiceConfigValues, DiceError,
@@ -113,7 +112,7 @@
 
     // Gets the pvmfw certificate to as the root certificate of DICE chain.
     let config_values = DiceConfigValues {
-        component_name: Some(cstr!("Protected VM firmware")),
+        component_name: Some(c"Protected VM firmware"),
         component_version: Some(1),
         resettable: true,
         rkp_vm_marker: true,
@@ -156,7 +155,7 @@
 pub fn fake_service_vm_dice_artifacts() -> Result<OwnedDiceArtifacts> {
     let (cdi_values, dice_chain) = fake_dice_artifacts_up_to_pvmfw()?;
     let config_values = DiceConfigValues {
-        component_name: Some(cstr!("vm_entry")),
+        component_name: Some(c"vm_entry"),
         component_version: Some(12),
         resettable: true,
         rkp_vm_marker: true,
diff --git a/libs/libvmbase/Android.bp b/libs/libvmbase/Android.bp
index 3088633..de347c7 100644
--- a/libs/libvmbase/Android.bp
+++ b/libs/libvmbase/Android.bp
@@ -80,7 +80,6 @@
         "libaarch64_paging",
         "libbuddy_system_allocator",
         "libcfg_if",
-        "libcstr",
         "libhypervisor_backends",
         "liblibfdt_nostd",
         "liblog_rust_nostd",
diff --git a/libs/libvmbase/src/bionic.rs b/libs/libvmbase/src/bionic.rs
index 3c0cd6f..37b6e45 100644
--- a/libs/libvmbase/src/bionic.rs
+++ b/libs/libvmbase/src/bionic.rs
@@ -24,7 +24,6 @@
 use core::slice;
 use core::str;
 
-use cstr::cstr;
 use log::error;
 use log::info;
 
@@ -230,138 +229,138 @@
 fn cstr_error(n: c_int) -> &'static CStr {
     // Messages taken from errno(1).
     match n {
-        0 => cstr!("Success"),
-        1 => cstr!("Operation not permitted"),
-        2 => cstr!("No such file or directory"),
-        3 => cstr!("No such process"),
-        4 => cstr!("Interrupted system call"),
-        5 => cstr!("Input/output error"),
-        6 => cstr!("No such device or address"),
-        7 => cstr!("Argument list too long"),
-        8 => cstr!("Exec format error"),
-        9 => cstr!("Bad file descriptor"),
-        10 => cstr!("No child processes"),
-        11 => cstr!("Resource temporarily unavailable"),
-        12 => cstr!("Cannot allocate memory"),
-        13 => cstr!("Permission denied"),
-        14 => cstr!("Bad address"),
-        15 => cstr!("Block device required"),
-        16 => cstr!("Device or resource busy"),
-        17 => cstr!("File exists"),
-        18 => cstr!("Invalid cross-device link"),
-        19 => cstr!("No such device"),
-        20 => cstr!("Not a directory"),
-        21 => cstr!("Is a directory"),
-        22 => cstr!("Invalid argument"),
-        23 => cstr!("Too many open files in system"),
-        24 => cstr!("Too many open files"),
-        25 => cstr!("Inappropriate ioctl for device"),
-        26 => cstr!("Text file busy"),
-        27 => cstr!("File too large"),
-        28 => cstr!("No space left on device"),
-        29 => cstr!("Illegal seek"),
-        30 => cstr!("Read-only file system"),
-        31 => cstr!("Too many links"),
-        32 => cstr!("Broken pipe"),
-        33 => cstr!("Numerical argument out of domain"),
-        34 => cstr!("Numerical result out of range"),
-        35 => cstr!("Resource deadlock avoided"),
-        36 => cstr!("File name too long"),
-        37 => cstr!("No locks available"),
-        38 => cstr!("Function not implemented"),
-        39 => cstr!("Directory not empty"),
-        40 => cstr!("Too many levels of symbolic links"),
-        42 => cstr!("No message of desired type"),
-        43 => cstr!("Identifier removed"),
-        44 => cstr!("Channel number out of range"),
-        45 => cstr!("Level 2 not synchronized"),
-        46 => cstr!("Level 3 halted"),
-        47 => cstr!("Level 3 reset"),
-        48 => cstr!("Link number out of range"),
-        49 => cstr!("Protocol driver not attached"),
-        50 => cstr!("No CSI structure available"),
-        51 => cstr!("Level 2 halted"),
-        52 => cstr!("Invalid exchange"),
-        53 => cstr!("Invalid request descriptor"),
-        54 => cstr!("Exchange full"),
-        55 => cstr!("No anode"),
-        56 => cstr!("Invalid request code"),
-        57 => cstr!("Invalid slot"),
-        59 => cstr!("Bad font file format"),
-        60 => cstr!("Device not a stream"),
-        61 => cstr!("No data available"),
-        62 => cstr!("Timer expired"),
-        63 => cstr!("Out of streams resources"),
-        64 => cstr!("Machine is not on the network"),
-        65 => cstr!("Package not installed"),
-        66 => cstr!("Object is remote"),
-        67 => cstr!("Link has been severed"),
-        68 => cstr!("Advertise error"),
-        69 => cstr!("Srmount error"),
-        70 => cstr!("Communication error on send"),
-        71 => cstr!("Protocol error"),
-        72 => cstr!("Multihop attempted"),
-        73 => cstr!("RFS specific error"),
-        74 => cstr!("Bad message"),
-        75 => cstr!("Value too large for defined data type"),
-        76 => cstr!("Name not unique on network"),
-        77 => cstr!("File descriptor in bad state"),
-        78 => cstr!("Remote address changed"),
-        79 => cstr!("Can not access a needed shared library"),
-        80 => cstr!("Accessing a corrupted shared library"),
-        81 => cstr!(".lib section in a.out corrupted"),
-        82 => cstr!("Attempting to link in too many shared libraries"),
-        83 => cstr!("Cannot exec a shared library directly"),
-        84 => cstr!("Invalid or incomplete multibyte or wide character"),
-        85 => cstr!("Interrupted system call should be restarted"),
-        86 => cstr!("Streams pipe error"),
-        87 => cstr!("Too many users"),
-        88 => cstr!("Socket operation on non-socket"),
-        89 => cstr!("Destination address required"),
-        90 => cstr!("Message too long"),
-        91 => cstr!("Protocol wrong type for socket"),
-        92 => cstr!("Protocol not available"),
-        93 => cstr!("Protocol not supported"),
-        94 => cstr!("Socket type not supported"),
-        95 => cstr!("Operation not supported"),
-        96 => cstr!("Protocol family not supported"),
-        97 => cstr!("Address family not supported by protocol"),
-        98 => cstr!("Address already in use"),
-        99 => cstr!("Cannot assign requested address"),
-        100 => cstr!("Network is down"),
-        101 => cstr!("Network is unreachable"),
-        102 => cstr!("Network dropped connection on reset"),
-        103 => cstr!("Software caused connection abort"),
-        104 => cstr!("Connection reset by peer"),
-        105 => cstr!("No buffer space available"),
-        106 => cstr!("Transport endpoint is already connected"),
-        107 => cstr!("Transport endpoint is not connected"),
-        108 => cstr!("Cannot send after transport endpoint shutdown"),
-        109 => cstr!("Too many references: cannot splice"),
-        110 => cstr!("Connection timed out"),
-        111 => cstr!("Connection refused"),
-        112 => cstr!("Host is down"),
-        113 => cstr!("No route to host"),
-        114 => cstr!("Operation already in progress"),
-        115 => cstr!("Operation now in progress"),
-        116 => cstr!("Stale file handle"),
-        117 => cstr!("Structure needs cleaning"),
-        118 => cstr!("Not a XENIX named type file"),
-        119 => cstr!("No XENIX semaphores available"),
-        120 => cstr!("Is a named type file"),
-        121 => cstr!("Remote I/O error"),
-        122 => cstr!("Disk quota exceeded"),
-        123 => cstr!("No medium found"),
-        124 => cstr!("Wrong medium type"),
-        125 => cstr!("Operation canceled"),
-        126 => cstr!("Required key not available"),
-        127 => cstr!("Key has expired"),
-        128 => cstr!("Key has been revoked"),
-        129 => cstr!("Key was rejected by service"),
-        130 => cstr!("Owner died"),
-        131 => cstr!("State not recoverable"),
-        132 => cstr!("Operation not possible due to RF-kill"),
-        133 => cstr!("Memory page has hardware error"),
-        _ => cstr!("Unknown errno value"),
+        0 => c"Success",
+        1 => c"Operation not permitted",
+        2 => c"No such file or directory",
+        3 => c"No such process",
+        4 => c"Interrupted system call",
+        5 => c"Input/output error",
+        6 => c"No such device or address",
+        7 => c"Argument list too long",
+        8 => c"Exec format error",
+        9 => c"Bad file descriptor",
+        10 => c"No child processes",
+        11 => c"Resource temporarily unavailable",
+        12 => c"Cannot allocate memory",
+        13 => c"Permission denied",
+        14 => c"Bad address",
+        15 => c"Block device required",
+        16 => c"Device or resource busy",
+        17 => c"File exists",
+        18 => c"Invalid cross-device link",
+        19 => c"No such device",
+        20 => c"Not a directory",
+        21 => c"Is a directory",
+        22 => c"Invalid argument",
+        23 => c"Too many open files in system",
+        24 => c"Too many open files",
+        25 => c"Inappropriate ioctl for device",
+        26 => c"Text file busy",
+        27 => c"File too large",
+        28 => c"No space left on device",
+        29 => c"Illegal seek",
+        30 => c"Read-only file system",
+        31 => c"Too many links",
+        32 => c"Broken pipe",
+        33 => c"Numerical argument out of domain",
+        34 => c"Numerical result out of range",
+        35 => c"Resource deadlock avoided",
+        36 => c"File name too long",
+        37 => c"No locks available",
+        38 => c"Function not implemented",
+        39 => c"Directory not empty",
+        40 => c"Too many levels of symbolic links",
+        42 => c"No message of desired type",
+        43 => c"Identifier removed",
+        44 => c"Channel number out of range",
+        45 => c"Level 2 not synchronized",
+        46 => c"Level 3 halted",
+        47 => c"Level 3 reset",
+        48 => c"Link number out of range",
+        49 => c"Protocol driver not attached",
+        50 => c"No CSI structure available",
+        51 => c"Level 2 halted",
+        52 => c"Invalid exchange",
+        53 => c"Invalid request descriptor",
+        54 => c"Exchange full",
+        55 => c"No anode",
+        56 => c"Invalid request code",
+        57 => c"Invalid slot",
+        59 => c"Bad font file format",
+        60 => c"Device not a stream",
+        61 => c"No data available",
+        62 => c"Timer expired",
+        63 => c"Out of streams resources",
+        64 => c"Machine is not on the network",
+        65 => c"Package not installed",
+        66 => c"Object is remote",
+        67 => c"Link has been severed",
+        68 => c"Advertise error",
+        69 => c"Srmount error",
+        70 => c"Communication error on send",
+        71 => c"Protocol error",
+        72 => c"Multihop attempted",
+        73 => c"RFS specific error",
+        74 => c"Bad message",
+        75 => c"Value too large for defined data type",
+        76 => c"Name not unique on network",
+        77 => c"File descriptor in bad state",
+        78 => c"Remote address changed",
+        79 => c"Can not access a needed shared library",
+        80 => c"Accessing a corrupted shared library",
+        81 => c".lib section in a.out corrupted",
+        82 => c"Attempting to link in too many shared libraries",
+        83 => c"Cannot exec a shared library directly",
+        84 => c"Invalid or incomplete multibyte or wide character",
+        85 => c"Interrupted system call should be restarted",
+        86 => c"Streams pipe error",
+        87 => c"Too many users",
+        88 => c"Socket operation on non-socket",
+        89 => c"Destination address required",
+        90 => c"Message too long",
+        91 => c"Protocol wrong type for socket",
+        92 => c"Protocol not available",
+        93 => c"Protocol not supported",
+        94 => c"Socket type not supported",
+        95 => c"Operation not supported",
+        96 => c"Protocol family not supported",
+        97 => c"Address family not supported by protocol",
+        98 => c"Address already in use",
+        99 => c"Cannot assign requested address",
+        100 => c"Network is down",
+        101 => c"Network is unreachable",
+        102 => c"Network dropped connection on reset",
+        103 => c"Software caused connection abort",
+        104 => c"Connection reset by peer",
+        105 => c"No buffer space available",
+        106 => c"Transport endpoint is already connected",
+        107 => c"Transport endpoint is not connected",
+        108 => c"Cannot send after transport endpoint shutdown",
+        109 => c"Too many references: cannot splice",
+        110 => c"Connection timed out",
+        111 => c"Connection refused",
+        112 => c"Host is down",
+        113 => c"No route to host",
+        114 => c"Operation already in progress",
+        115 => c"Operation now in progress",
+        116 => c"Stale file handle",
+        117 => c"Structure needs cleaning",
+        118 => c"Not a XENIX named type file",
+        119 => c"No XENIX semaphores available",
+        120 => c"Is a named type file",
+        121 => c"Remote I/O error",
+        122 => c"Disk quota exceeded",
+        123 => c"No medium found",
+        124 => c"Wrong medium type",
+        125 => c"Operation canceled",
+        126 => c"Required key not available",
+        127 => c"Key has expired",
+        128 => c"Key has been revoked",
+        129 => c"Key was rejected by service",
+        130 => c"Owner died",
+        131 => c"State not recoverable",
+        132 => c"Operation not possible due to RF-kill",
+        133 => c"Memory page has hardware error",
+        _ => c"Unknown errno value",
     }
 }
diff --git a/libs/libvmbase/src/fdt.rs b/libs/libvmbase/src/fdt.rs
index aaf354e..2113787 100644
--- a/libs/libvmbase/src/fdt.rs
+++ b/libs/libvmbase/src/fdt.rs
@@ -17,7 +17,6 @@
 pub mod pci;
 
 use core::ops::Range;
-use cstr::cstr;
 use libfdt::{self, Fdt, FdtError};
 
 /// Represents information about a SWIOTLB buffer.
@@ -34,7 +33,7 @@
 impl SwiotlbInfo {
     /// Creates a `SwiotlbInfo` struct from the given device tree.
     pub fn new_from_fdt(fdt: &Fdt) -> libfdt::Result<Option<SwiotlbInfo>> {
-        let Some(node) = fdt.compatible_nodes(cstr!("restricted-dma-pool"))?.next() else {
+        let Some(node) = fdt.compatible_nodes(c"restricted-dma-pool")?.next() else {
             return Ok(None);
         };
         let (addr, size, align) = if let Some(mut reg) = node.reg()? {
@@ -42,8 +41,8 @@
             let size = reg.size.ok_or(FdtError::BadValue)?;
             (Some(reg.addr.try_into().unwrap()), size.try_into().unwrap(), None)
         } else {
-            let size = node.getprop_u64(cstr!("size"))?.ok_or(FdtError::NotFound)?;
-            let align = node.getprop_u64(cstr!("alignment"))?.ok_or(FdtError::NotFound)?;
+            let size = node.getprop_u64(c"size")?.ok_or(FdtError::NotFound)?;
+            let align = node.getprop_u64(c"alignment")?.ok_or(FdtError::NotFound)?;
             (None, size.try_into().unwrap(), Some(align.try_into().unwrap()))
         };
         Ok(Some(Self { addr, size, align }))
diff --git a/tests/Terminal/Android.bp b/tests/Terminal/Android.bp
index 029fbea..a4e1f6b 100644
--- a/tests/Terminal/Android.bp
+++ b/tests/Terminal/Android.bp
@@ -4,7 +4,7 @@
 
 android_test {
     name: "TerminalAppTests",
-    srcs: ["src/**/*.java"],
+    srcs: ["src/**/*.kt"],
     libs: [
         "android.test.runner.stubs.system",
         "android.test.base.stubs.system",
diff --git a/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.java b/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.java
deleted file mode 100644
index b0afb54..0000000
--- a/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.virtualization.terminal;
-
-import static org.junit.Assert.assertTrue;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.SystemProperties;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.microdroid.test.common.DeviceProperties;
-import com.android.microdroid.test.common.MetricsProcessor;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-@RunWith(AndroidJUnit4.class)
-public class TerminalAppTest {
-    private Instrumentation mInstr;
-    private Context mTargetContext;
-    private DeviceProperties mProperties;
-    private final MetricsProcessor mMetricsProc = new MetricsProcessor("avf_perf/terminal/");
-
-    @Before
-    public void setup() {
-        mInstr = InstrumentationRegistry.getInstrumentation();
-        mTargetContext = mInstr.getTargetContext();
-        mProperties = DeviceProperties.create(SystemProperties::get);
-        installVmImage();
-    }
-
-    private void installVmImage() {
-        final long INSTALL_TIMEOUT_MILLIS = 300_000; // 5 min
-
-        Intent intent = new Intent(mTargetContext, InstallerActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        if (mInstr.startActivitySync(intent) instanceof InstallerActivity activity) {
-            assertTrue(
-                    "Failed to install VM image",
-                    activity.waitForInstallCompleted(INSTALL_TIMEOUT_MILLIS));
-        }
-    }
-
-    @Test
-    public void boot() throws Exception {
-        final boolean isNestedVirt = mProperties.isCuttlefish() || mProperties.isGoldfish();
-        final long BOOT_TIMEOUT_MILLIS = isNestedVirt ? 180_000 : 30_000; // 30 sec (or 3 min)
-
-        Intent intent = new Intent(mTargetContext, MainActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        long start = System.currentTimeMillis();
-        if (mInstr.startActivitySync(intent) instanceof MainActivity activity) {
-            assertTrue("Failed to boot in 30s", activity.waitForBootCompleted(BOOT_TIMEOUT_MILLIS));
-        }
-        long delay = System.currentTimeMillis() - start;
-
-        // TODO: measure multiple times?
-        List<Long> measurements = new ArrayList<>();
-        measurements.add(delay);
-        Map<String, Double> stats = mMetricsProc.computeStats(measurements, "boot", "ms");
-        Bundle bundle = new Bundle();
-        for (Map.Entry<String, Double> entry : stats.entrySet()) {
-            bundle.putDouble(entry.getKey(), entry.getValue());
-        }
-        mInstr.sendStatus(0, bundle);
-    }
-
-    @After
-    public void tearDown() throws IOException {
-        PortsStateManager.getInstance(mTargetContext).clearEnabledPorts();
-        InstalledImage.getDefault(mTargetContext).uninstallFully();
-    }
-}
diff --git a/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.kt b/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.kt
new file mode 100644
index 0000000..88bdfab
--- /dev/null
+++ b/tests/Terminal/src/com/android/virtualization/terminal/TerminalAppTest.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 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.
+ */
+package com.android.virtualization.terminal
+
+import android.app.Instrumentation
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.SystemProperties
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.microdroid.test.common.DeviceProperties
+import com.android.microdroid.test.common.MetricsProcessor
+import java.io.IOException
+import java.lang.Exception
+import java.util.ArrayList
+import org.junit.After
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TerminalAppTest {
+    private lateinit var instr: Instrumentation
+    private lateinit var targetContext: Context
+    private lateinit var properties: DeviceProperties
+    private val metricsProc = MetricsProcessor("avf_perf/terminal/")
+
+    @Before
+    fun setup() {
+        instr = InstrumentationRegistry.getInstrumentation()
+        targetContext = instr.targetContext
+        properties =
+            DeviceProperties.create(DeviceProperties.PropertyGetter { SystemProperties.get(it) })
+        installVmImage()
+    }
+
+    private fun installVmImage() {
+        val INSTALL_TIMEOUT_MILLIS: Long = 300000 // 5 min
+
+        val intent = Intent(targetContext, InstallerActivity::class.java)
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+        val activity = instr.startActivitySync(intent)
+        if (activity is InstallerActivity) {
+            Assert.assertTrue(
+                "Failed to install VM image",
+                activity.waitForInstallCompleted(INSTALL_TIMEOUT_MILLIS),
+            )
+        }
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun boot() {
+        val isNestedVirt = properties.isCuttlefish() || properties.isGoldfish()
+        val BOOT_TIMEOUT_MILLIS =
+            (if (isNestedVirt) 180000 else 30000).toLong() // 30 sec (or 3 min)
+
+        val intent = Intent(targetContext, MainActivity::class.java)
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+        val start = System.currentTimeMillis()
+        val activity = instr.startActivitySync(intent)
+        if (activity is MainActivity) {
+            Assert.assertTrue(
+                "Failed to boot in 30s",
+                activity.waitForBootCompleted(BOOT_TIMEOUT_MILLIS),
+            )
+        }
+        val delay = System.currentTimeMillis() - start
+
+        // TODO: measure multiple times?
+        val measurements: MutableList<Long?> = ArrayList<Long?>()
+        measurements.add(delay)
+        val stats = metricsProc.computeStats(measurements, "boot", "ms")
+        val bundle = Bundle()
+        for (entry in stats.entries) {
+            bundle.putDouble(entry.key, entry.value)
+        }
+        instr.sendStatus(0, bundle)
+    }
+
+    @After
+    @Throws(IOException::class)
+    fun tearDown() {
+        PortsStateManager.getInstance(targetContext).clearEnabledPorts()
+        InstalledImage.getDefault(targetContext).uninstallFully()
+    }
+}
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index cb374a5..8a95fe9 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -224,7 +224,6 @@
         "libandroid_logger",
         "libanyhow",
         "libavflog",
-        "libcstr",
         "liblog_rust",
         "libvm_payload_rs",
     ],
diff --git a/tests/testapk/src/native/testbinary.rs b/tests/testapk/src/native/testbinary.rs
index 2502113..a84b955 100644
--- a/tests/testapk/src/native/testbinary.rs
+++ b/tests/testapk/src/native/testbinary.rs
@@ -24,7 +24,6 @@
     },
     binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, Strong},
 };
-use cstr::cstr;
 use log::{error, info};
 use std::process::exit;
 use std::string::String;
@@ -130,7 +129,7 @@
 }
 
 fn unimplemented<T>() -> BinderResult<T> {
-    let message = cstr!("Got a call to an unimplemented ITestService method in testbinary.rs");
+    let message = c"Got a call to an unimplemented ITestService method in testbinary.rs";
     error!("{message:?}");
     Err(Status::new_exception(ExceptionCode::UNSUPPORTED_OPERATION, Some(message)))
 }