Merge "Remove unnecessary OWNERS file in libs/dice" into main
diff --git a/android/TerminalApp/AndroidManifest.xml b/android/TerminalApp/AndroidManifest.xml
index 61737fe..6a1ecaf 100644
--- a/android/TerminalApp/AndroidManifest.xml
+++ b/android/TerminalApp/AndroidManifest.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     package="com.android.virtualization.terminal">
@@ -65,7 +80,8 @@
         <service
             android:name="com.android.virtualization.vmlauncher.VmLauncherService"
             android:exported="false"
-            android:foregroundServiceType="specialUse">
+            android:foregroundServiceType="specialUse"
+            android:stopWithTask="true" >
             <property
                 android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
                 android:value="Run VM instances" />
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
index a9102b0..0774bb1 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerActivity.java
@@ -29,12 +29,15 @@
 import android.os.RemoteException;
 import android.text.format.Formatter;
 import android.util.Log;
+import android.view.View;
 import android.widget.CheckBox;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import com.google.android.material.progressindicator.LinearProgressIndicator;
+
 import java.lang.ref.WeakReference;
 import java.util.concurrent.ExecutorService;
 
@@ -128,6 +131,12 @@
     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
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index 4e32de7..ebf6154 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -80,7 +80,7 @@
     private static final String VM_ADDR = "192.168.0.2";
     private static final int TTYD_PORT = 7681;
     private static final int REQUEST_CODE_INSTALLER = 0x33;
-    private static final int FONT_SIZE_DEFAULT = 12;
+    private static final int FONT_SIZE_DEFAULT = 13;
 
     private X509Certificate[] mCertificates;
     private PrivateKey mPrivateKey;
diff --git a/android/TerminalApp/res/drawable/baseline_call_missed_outgoing_24.xml b/android/TerminalApp/res/drawable/baseline_call_missed_outgoing_24.xml
index ec1f990..052d14d 100644
--- a/android/TerminalApp/res/drawable/baseline_call_missed_outgoing_24.xml
+++ b/android/TerminalApp/res/drawable/baseline_call_missed_outgoing_24.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="?attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
 
     <path android:fillColor="@android:color/white" android:pathData="M3,8.41l9,9l7,-7V15h2V7h-8v2h4.59L12,14.59L4.41,7L3,8.41z"/>
diff --git a/android/TerminalApp/res/drawable/baseline_settings_backup_restore_24.xml b/android/TerminalApp/res/drawable/baseline_settings_backup_restore_24.xml
index 513c42b..895707d 100644
--- a/android/TerminalApp/res/drawable/baseline_settings_backup_restore_24.xml
+++ b/android/TerminalApp/res/drawable/baseline_settings_backup_restore_24.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
 
     <path android:fillColor="@android:color/white" android:pathData="M14,12c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2 0.9,2 2,2 2,-0.9 2,-2zM12,3c-4.97,0 -9,4.03 -9,9L0,12l4,4 4,-4L5,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.51,0 -2.91,-0.49 -4.06,-1.3l-1.42,1.44C8.04,20.3 9.94,21 12,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9z"/>
diff --git a/android/TerminalApp/res/drawable/baseline_storage_24.xml b/android/TerminalApp/res/drawable/baseline_storage_24.xml
index 503d1bc..2978ffb 100644
--- a/android/TerminalApp/res/drawable/baseline_storage_24.xml
+++ b/android/TerminalApp/res/drawable/baseline_storage_24.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
 
     <path android:fillColor="@android:color/white" android:pathData="M2,20h20v-4L2,16v4zM4,17h2v2L4,19v-2zM2,4v4h20L22,4L2,4zM6,7L4,7L4,5h2v2zM2,14h20v-4L2,10v4zM4,11h2v2L4,13v-2z"/>
diff --git a/android/TerminalApp/res/drawable/ic_launcher_background.xml b/android/TerminalApp/res/drawable/ic_launcher_background.xml
index 07d5da9..34e738d 100644
--- a/android/TerminalApp/res/drawable/ic_launcher_background.xml
+++ b/android/TerminalApp/res/drawable/ic_launcher_background.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="108dp"
     android:height="108dp"
diff --git a/android/TerminalApp/res/drawable/ic_launcher_foreground.xml b/android/TerminalApp/res/drawable/ic_launcher_foreground.xml
index 8b28c8e..65a3b27 100644
--- a/android/TerminalApp/res/drawable/ic_launcher_foreground.xml
+++ b/android/TerminalApp/res/drawable/ic_launcher_foreground.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="108dp"
     android:height="108dp"
diff --git a/android/TerminalApp/res/drawable/ic_lock_open.xml b/android/TerminalApp/res/drawable/ic_lock_open.xml
deleted file mode 100644
index c623592..0000000
--- a/android/TerminalApp/res/drawable/ic_lock_open.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="48dp"
-    android:height="48dp"
-    android:viewportWidth="960"
-    android:viewportHeight="960"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M220,326L610,326L610,230Q610,175.83 572.12,137.92Q534.24,100 480.12,100Q426,100 388,137.92Q350,175.83 350,230L290,230Q290,151 345.61,95.5Q401.21,40 480.11,40Q559,40 614.5,95.58Q670,151.15 670,230L670,326L740,326Q764.75,326 782.38,343.62Q800,361.25 800,386L800,820Q800,844.75 782.38,862.37Q764.75,880 740,880L220,880Q195.25,880 177.63,862.37Q160,844.75 160,820L160,386Q160,361.25 177.63,343.62Q195.25,326 220,326ZM220,820L740,820Q740,820 740,820Q740,820 740,820L740,386Q740,386 740,386Q740,386 740,386L220,386Q220,386 220,386Q220,386 220,386L220,820Q220,820 220,820Q220,820 220,820ZM480.17,680Q512,680 534.5,657.97Q557,635.94 557,605Q557,575 534.33,550.5Q511.66,526 479.83,526Q448,526 425.5,550.5Q403,575 403,605.5Q403,636 425.67,658Q448.34,680 480.17,680ZM220,820Q220,820 220,820Q220,820 220,820L220,386Q220,386 220,386Q220,386 220,386L220,386Q220,386 220,386Q220,386 220,386L220,820Q220,820 220,820Q220,820 220,820Z"/>
-</vector>
-
diff --git a/android/TerminalApp/res/drawable/ic_settings.xml b/android/TerminalApp/res/drawable/ic_settings.xml
index 4bcd4aa..d117e96 100644
--- a/android/TerminalApp/res/drawable/ic_settings.xml
+++ b/android/TerminalApp/res/drawable/ic_settings.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
diff --git a/android/TerminalApp/res/drawable/ic_terminal.xml b/android/TerminalApp/res/drawable/ic_terminal.xml
new file mode 100644
index 0000000..03d7054
--- /dev/null
+++ b/android/TerminalApp/res/drawable/ic_terminal.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="142"
+    android:viewportHeight="168.75">
+  <group android:translateY="133.59375">
+    <path android:pathData="M9.078125,-77.484375L69.75,-51.40625L69.75,-37.765625L9.078125,-11.609375L9.078125,-28.40625L52.53125,-44.71875L9.078125,-60.75L9.078125,-77.484375Z"
+        android:fillColor="#3BBA46"/>
+    <path android:pathData="M139.76562,0L139.76562,13.5L75.21875,13.5L75.21875,0L139.76562,0Z"
+        android:fillColor="#3BBA46"/>
+  </group>
+</vector>
\ No newline at end of file
diff --git a/android/TerminalApp/res/layout/activity_headless.xml b/android/TerminalApp/res/layout/activity_headless.xml
index 7da87af..8a15dd8 100644
--- a/android/TerminalApp/res/layout/activity_headless.xml
+++ b/android/TerminalApp/res/layout/activity_headless.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
diff --git a/android/TerminalApp/res/layout/activity_installer.xml b/android/TerminalApp/res/layout/activity_installer.xml
index c375cb8..ce37129 100644
--- a/android/TerminalApp/res/layout/activity_installer.xml
+++ b/android/TerminalApp/res/layout/activity_installer.xml
@@ -1,56 +1,92 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:fitsSystemWindows="true"
-    android:paddingLeft="16dp"
-    android:paddingRight="16dp">
-    <TextView
-        android:id="@+id/installer_title"
-        android:layout_width="match_parent"
+    android:fitsSystemWindows="true">
+
+    <com.google.android.material.progressindicator.LinearProgressIndicator
+        android:id="@+id/installer_progress"
+        android:indeterminate="true"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
         android:layout_alignParentStart="true"
-        android:textSize="32sp"
-        android:text="@string/installer_title_text" />
+        android:visibility="invisible"
+        />
 
     <ImageView
-        android:id="@+id/installer_icon"
-        android:layout_width="match_parent"
-        android:layout_height="300dp"
-        android:padding="10dp"
-        android:layout_below="@id/installer_title"
+        android:id="@+id/installer_terminal_icon"
+        android:layout_width="30dp"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_terminal"
+        android:adjustViewBounds="true"
         android:layout_alignParentStart="true"
-        android:src="@drawable/ic_lock_open"
-        android:adjustViewBounds="true" />
+        android:layout_marginTop="48dp"
+        android:layout_marginLeft="32dp"
+        android:layout_marginRight="32dp"
+        app:tint="?attr/colorPrimary" />
+
+    <TextView
+        android:id="@+id/installer_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:singleLine="false"
+        android:text="@string/installer_title_text"
+        android:layout_below="@id/installer_terminal_icon"
+        android:layout_marginTop="24dp"
+        android:layout_marginBottom="24dp"
+        android:layout_marginLeft="32dp"
+        android:layout_marginRight="32dp"
+        android:textSize="36sp" />
 
     <TextView
         android:id="@+id/installer_desc"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:padding="10dp"
-        android:layout_below="@id/installer_icon"
-        android:layout_alignParentStart="true"
         android:singleLine="false"
-        android:textSize="24sp" />
+        android:layout_below="@id/installer_title"
+        android:lineSpacingExtra="5dp"
+        android:layout_marginTop="24dp"
+        android:layout_marginLeft="32dp"
+        android:layout_marginRight="32dp"
+        android:textSize="16sp" />
 
     <CheckBox
         android:id="@+id/installer_wait_for_wifi_checkbox"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="10dp"
+        android:textSize="16sp"
+        android:layout_marginLeft="42dp"
+        android:layout_marginRight="42dp"
+        android:layout_above="@id/installer_install_button"
         android:layout_alignParentEnd="true"
-        android:layout_below="@id/installer_desc"
         android:text="@string/installer_wait_for_wifi_checkbox_text" />
 
     <Button
         android:id="@+id/installer_install_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="10dp"
         android:layout_alignParentBottom="true"
         android:layout_alignParentEnd="true"
+        android:layout_marginBottom="32dp"
+        android:layout_marginLeft="40dp"
+        android:layout_marginRight="40dp"
+        android:backgroundTint="?attr/colorPrimaryDark"
         android:text="@string/installer_install_button_enabled_text" />
-
 </RelativeLayout>
diff --git a/android/TerminalApp/res/layout/settings_activity.xml b/android/TerminalApp/res/layout/settings_activity.xml
index 3ec2617..9edfd96 100644
--- a/android/TerminalApp/res/layout/settings_activity.xml
+++ b/android/TerminalApp/res/layout/settings_activity.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
diff --git a/android/TerminalApp/res/layout/settings_disk_resize.xml b/android/TerminalApp/res/layout/settings_disk_resize.xml
index a41b580..6c8c2c1 100644
--- a/android/TerminalApp/res/layout/settings_disk_resize.xml
+++ b/android/TerminalApp/res/layout/settings_disk_resize.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/android/TerminalApp/res/layout/settings_list_item.xml b/android/TerminalApp/res/layout/settings_list_item.xml
index 89f2d82..7b27421 100644
--- a/android/TerminalApp/res/layout/settings_list_item.xml
+++ b/android/TerminalApp/res/layout/settings_list_item.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding.xml b/android/TerminalApp/res/layout/settings_port_forwarding.xml
index 1d68907..199b8cb 100644
--- a/android/TerminalApp/res/layout/settings_port_forwarding.xml
+++ b/android/TerminalApp/res/layout/settings_port_forwarding.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding_item.xml b/android/TerminalApp/res/layout/settings_port_forwarding_item.xml
index 9e5981e..5418bf8 100644
--- a/android/TerminalApp/res/layout/settings_port_forwarding_item.xml
+++ b/android/TerminalApp/res/layout/settings_port_forwarding_item.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/android/TerminalApp/res/layout/settings_recovery.xml b/android/TerminalApp/res/layout/settings_recovery.xml
index e18c8a6..12344c6 100644
--- a/android/TerminalApp/res/layout/settings_recovery.xml
+++ b/android/TerminalApp/res/layout/settings_recovery.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
diff --git a/android/TerminalApp/res/menu/main_menu.xml b/android/TerminalApp/res/menu/main_menu.xml
index 0fee90e..42ba85d 100644
--- a/android/TerminalApp/res/menu/main_menu.xml
+++ b/android/TerminalApp/res/menu/main_menu.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
     <item android:id="@+id/menu_item_settings"
diff --git a/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher.xml b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher.xml
index 7353dbd..f96d8eb 100644
--- a/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@color/ic_launcher_background"/>
     <foreground android:drawable="@drawable/ic_launcher_foreground"/>
diff --git a/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher_round.xml
index 7353dbd..f96d8eb 100644
--- a/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/android/TerminalApp/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@color/ic_launcher_background"/>
     <foreground android:drawable="@drawable/ic_launcher_foreground"/>
diff --git a/android/TerminalApp/res/values/dimens.xml b/android/TerminalApp/res/values/dimens.xml
index e6ed461..e00ef7c 100644
--- a/android/TerminalApp/res/values/dimens.xml
+++ b/android/TerminalApp/res/values/dimens.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <resources>
     <dimen name="activity_split_ratio">0.3</dimen>
 </resources>
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/ic_launcher_background.xml b/android/TerminalApp/res/values/ic_launcher_background.xml
index 337764a..8740b87 100644
--- a/android/TerminalApp/res/values/ic_launcher_background.xml
+++ b/android/TerminalApp/res/values/ic_launcher_background.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <resources>
     <color name="ic_launcher_background">#070E1E</color>
 </resources>
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/integers.xml b/android/TerminalApp/res/values/integers.xml
index e20987c..dc64c81 100644
--- a/android/TerminalApp/res/values/integers.xml
+++ b/android/TerminalApp/res/values/integers.xml
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <resources>
     <integer name="split_min_width">720</integer>
     <integer name="disk_size_round_up_step_size_in_mb">4</integer>
diff --git a/android/TerminalApp/res/xml/main_split_config.xml b/android/TerminalApp/res/xml/main_split_config.xml
index f51e7ea..c2da907 100644
--- a/android/TerminalApp/res/xml/main_split_config.xml
+++ b/android/TerminalApp/res/xml/main_split_config.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--  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.
+ -->
+
 <resources xmlns:window="http://schemas.android.com/apk/res-auto">
 
     <!-- Define a split for the named activities. -->
diff --git a/android/forwarder_host/src/forwarder_host.rs b/android/forwarder_host/src/forwarder_host.rs
index 26bae89..7496a02 100644
--- a/android/forwarder_host/src/forwarder_host.rs
+++ b/android/forwarder_host/src/forwarder_host.rs
@@ -28,7 +28,7 @@
 use std::time::Duration;
 
 use forwarder::forwarder::ForwarderSession;
-use jni::objects::{JObject, JValue};
+use jni::objects::{JIntArray, JObject, JValue};
 use jni::sys::jint;
 use jni::JNIEnv;
 use log::{debug, error, info, warn};
@@ -45,11 +45,16 @@
 static SHUTDOWN_EVT: LazyLock<EventFd> =
     LazyLock::new(|| EventFd::new().expect("Could not create shutdown eventfd"));
 
+static UPDATE_EVT: LazyLock<EventFd> =
+    LazyLock::new(|| EventFd::new().expect("Could not create update eventfd"));
+
+static UPDATE_QUEUE: LazyLock<Arc<Mutex<VecDeque<u16>>>> =
+    LazyLock::new(|| Arc::new(Mutex::new(VecDeque::new())));
+
 #[remain::sorted]
 #[derive(Debug)]
 enum Error {
     BindVsock(io::Error),
-    EventFdNew(nix::Error),
     IncorrectCid(u32),
     LaunchForwarderGuest(jni::errors::Error),
     NoListenerForPort(u16),
@@ -62,7 +67,6 @@
     TcpAccept(io::Error),
     TcpListenerPort(io::Error),
     UpdateEventRead(nix::Error),
-    UpdateEventWrite(nix::Error),
     VsockAccept(io::Error),
     VsockAcceptTimeout,
     VsockListenerPort(io::Error),
@@ -78,7 +82,6 @@
         #[remain::sorted]
         match self {
             BindVsock(e) => write!(f, "failed to bind vsock: {}", e),
-            EventFdNew(e) => write!(f, "failed to create eventfd: {}", e),
             IncorrectCid(cid) => write!(f, "chunnel connection from unexpected cid {}", cid),
             LaunchForwarderGuest(e) => write!(f, "failed to launch forwarder_guest {}", e),
             NoListenerForPort(port) => write!(f, "could not find listener for port: {}", port),
@@ -93,7 +96,6 @@
                 write!(f, "failed to read local sockaddr for tcp listener: {}", e)
             }
             UpdateEventRead(e) => write!(f, "failed to read update eventfd: {}", e),
-            UpdateEventWrite(e) => write!(f, "failed to write update eventfd: {}", e),
             VsockAccept(e) => write!(f, "failed to accept vsock: {}", e),
             VsockAcceptTimeout => write!(f, "timed out waiting for vsock connection"),
             VsockListenerPort(e) => write!(f, "failed to get vsock listener port: {}", e),
@@ -101,12 +103,6 @@
     }
 }
 
-/// A TCP forwarding target. Uniquely identifies a listening port in a given container.
-struct TcpForwardTarget {
-    pub port: u16,
-    pub vsock_cid: u32,
-}
-
 /// A tag that uniquely identifies a particular forwarding session. This has arbitrarily been
 /// chosen as the fd of the local (TCP) socket.
 type SessionTag = u32;
@@ -127,7 +123,6 @@
 struct PortListeners {
     tcp4_listener: TcpListener,
     tcp6_listener: TcpListener,
-    forward_target: TcpForwardTarget,
 }
 
 /// SocketFamily specifies whether a socket uses IPv4 or IPv6.
@@ -140,25 +135,18 @@
 struct ForwarderSessions<'a> {
     listening_ports: BTreeMap<u16, PortListeners>,
     tcp4_forwarders: HashMap<SessionTag, ForwarderSession>,
-    update_evt: EventFd,
-    update_queue: Arc<Mutex<VecDeque<TcpForwardTarget>>>,
+    cid: u32,
     jni_env: JNIEnv<'a>,
     jni_cb: JObject<'a>,
 }
 
 impl<'a> ForwarderSessions<'a> {
     /// Creates a new instance of ForwarderSessions.
-    fn new(
-        update_evt: EventFd,
-        update_queue: Arc<Mutex<VecDeque<TcpForwardTarget>>>,
-        jni_env: JNIEnv<'a>,
-        jni_cb: JObject<'a>,
-    ) -> Result<Self> {
+    fn new(cid: i32, jni_env: JNIEnv<'a>, jni_cb: JObject<'a>) -> Result<Self> {
         Ok(ForwarderSessions {
             listening_ports: BTreeMap::new(),
             tcp4_forwarders: HashMap::new(),
-            update_evt,
-            update_queue,
+            cid: cid as u32,
             jni_env,
             jni_cb,
         })
@@ -167,12 +155,11 @@
     /// Adds or removes listeners based on the latest listening ports from the D-Bus thread.
     fn process_update_queue(&mut self, poll_ctx: &PollContext<Token>) -> Result<()> {
         // Unwrap of LockResult is customary.
-        let mut update_queue = self.update_queue.lock().unwrap();
+        let mut update_queue = UPDATE_QUEUE.lock().unwrap();
         let mut active_ports: BTreeSet<u16> = BTreeSet::new();
 
         // Add any new listeners first.
-        while let Some(target) = update_queue.pop_front() {
-            let port = target.port;
+        while let Some(port) = update_queue.pop_front() {
             // Ignore privileged ports.
             if port < 1024 {
                 continue;
@@ -201,7 +188,7 @@
                 poll_ctx
                     .add(&tcp6_listener, Token::Ipv6Listener(port))
                     .map_err(Error::PollContextAdd)?;
-                o.insert(PortListeners { tcp4_listener, tcp6_listener, forward_target: target });
+                o.insert(PortListeners { tcp4_listener, tcp6_listener });
             }
             active_ports.insert(port);
         }
@@ -218,7 +205,7 @@
         }
 
         // Consume the eventfd.
-        self.update_evt.read().map_err(Error::UpdateEventRead)?;
+        UPDATE_EVT.read().map_err(Error::UpdateEventRead)?;
 
         Ok(())
     }
@@ -240,12 +227,8 @@
         // This session should be dropped if any of the PollContext setup fails. Since the only
         // extant fds for the underlying sockets will be closed, they will be unregistered from
         // epoll set automatically.
-        let session = create_forwarder_session(
-            listener,
-            &port_listeners.forward_target,
-            &mut self.jni_env,
-            &self.jni_cb,
-        )?;
+        let session =
+            create_forwarder_session(listener, self.cid, &mut self.jni_env, &self.jni_cb)?;
 
         let tag = session.local_stream().as_raw_fd() as u32;
 
@@ -293,7 +276,7 @@
 
     fn run(&mut self) -> Result<()> {
         let poll_ctx: PollContext<Token> = PollContext::new().map_err(Error::PollContextNew)?;
-        poll_ctx.add(&self.update_evt, Token::UpdatePorts).map_err(Error::PollContextAdd)?;
+        poll_ctx.add(&*UPDATE_EVT, Token::UpdatePorts).map_err(Error::PollContextAdd)?;
         poll_ctx.add(&*SHUTDOWN_EVT, Token::Shutdown).map_err(Error::PollContextAdd)?;
 
         loop {
@@ -340,7 +323,7 @@
 /// Creates a forwarder session from a `listener` that has a pending connection to accept.
 fn create_forwarder_session(
     listener: &TcpListener,
-    target: &TcpForwardTarget,
+    cid: u32,
     jni_env: &mut JNIEnv,
     jni_cb: &JObject,
 ) -> Result<ForwarderSession> {
@@ -376,7 +359,7 @@
         Some(_) => {
             let (vsock_stream, sockaddr) = vsock_listener.accept().map_err(Error::VsockAccept)?;
 
-            if sockaddr.cid() != target.vsock_cid {
+            if sockaddr.cid() != cid {
                 Err(Error::IncorrectCid(sockaddr.cid()))
             } else {
                 Ok(ForwarderSession::new(tcp_stream.into(), vsock_stream.into()))
@@ -386,33 +369,10 @@
     }
 }
 
-fn update_listening_ports(
-    update_queue: &Arc<Mutex<VecDeque<TcpForwardTarget>>>,
-    update_evt: &EventFd,
-    cid: i32,
-) -> Result<()> {
-    let mut update_queue = update_queue.lock().unwrap();
-
-    // TODO(b/340126051): Bring listening ports from the guest.
-    update_queue.push_back(TcpForwardTarget {
-        port: 12345, /* Example value for testing */
-        vsock_cid: cid as u32,
-    });
-
-    update_evt.write(1).map_err(Error::UpdateEventWrite)?;
-    Ok(())
-}
-
 // TODO(b/340126051): Host can receive opened ports from the guest.
 fn run_forwarder_host(cid: i32, jni_env: JNIEnv, jni_cb: JObject) -> Result<()> {
     debug!("Starting forwarder_host");
-    let update_evt = EventFd::new().map_err(Error::EventFdNew)?;
-    let update_queue = Arc::new(Mutex::new(VecDeque::new()));
-
-    // TODO(b/340126051): Instead of one-time execution, bring port info with separated thread.
-    update_listening_ports(&update_queue, &update_evt, cid)?;
-
-    let mut sessions = ForwarderSessions::new(update_evt, update_queue, jni_env, jni_cb)?;
+    let mut sessions = ForwarderSessions::new(cid, jni_env, jni_cb)?;
     sessions.run()
 }
 
@@ -442,3 +402,22 @@
 ) {
     SHUTDOWN_EVT.write(1).expect("Failed to write shutdown event FD");
 }
+
+/// JNI function for updating listening ports.
+#[no_mangle]
+pub extern "C" fn Java_com_android_virtualization_vmlauncher_DebianServiceImpl_updateListeningPorts(
+    env: JNIEnv,
+    _class: JObject,
+    ports: JIntArray,
+) {
+    let length = env.get_array_length(&ports).expect("Failed to get length of port array");
+    let mut buf = vec![0; length as usize];
+    env.get_int_array_region(ports, 0, &mut buf).expect("Failed to get port array");
+
+    let mut update_queue = UPDATE_QUEUE.lock().unwrap();
+    update_queue.clear();
+    for port in buf {
+        update_queue.push_back(port.try_into().expect("Failed to add port into update queue"));
+    }
+    UPDATE_EVT.write(1).expect("failed to write update eventfd");
+}
diff --git a/build/microdroid/Android.bp b/build/microdroid/Android.bp
index d5d8108..d9e39f0 100644
--- a/build/microdroid/Android.bp
+++ b/build/microdroid/Android.bp
@@ -139,7 +139,10 @@
             ],
         },
     },
-    linker_config_src: "linker.config.json",
+    linkerconfig: {
+        gen_linker_config: true,
+        linker_config_srcs: ["linker.config.json"],
+    },
     base_dir: "system",
     dirs: microdroid_rootdirs + select(release_flag("RELEASE_AVF_ENABLE_DICE_CHANGES"), {
         true: ["microdroid_resources"],
diff --git a/guest/port_listener/build.sh b/guest/port_listener/build.sh
deleted file mode 100755
index a1d0205..0000000
--- a/guest/port_listener/build.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-
-set -e
-
-check_sudo() {
-	if [ "$EUID" -ne 0 ]; then
-		echo "Please run as root."
-		exit
-	fi
-}
-
-install_prerequisites() {
-    apt update
-    apt install --no-install-recommends --assume-yes \
-        bpftool \
-        clang \
-        libbpf-dev \
-        libgoogle-glog-dev \
-        libstdc++-14-dev
-}
-
-build_port_listener() {
-    cp $(dirname $0)/src/* ${workdir}
-    out_dir=${PWD}
-    pushd ${workdir}
-        bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
-        clang \
-            -O2 \
-            -Wall \
-            -target bpf \
-            -g \
-            -c listen_tracker.ebpf.c \
-            -o listen_tracker.ebpf.o
-        bpftool gen skeleton listen_tracker.ebpf.o > listen_tracker.skel.h
-        clang++ \
-            -O2 \
-            -Wall \
-            -lbpf \
-            -lglog \
-            -o port_listener \
-            main.cc
-        cp port_listener ${out_dir}
-    popd
-}
-
-clean_up() {
-	rm -rf ${workdir}
-}
-trap clean_up EXIT
-workdir=$(mktemp -d)
-
-check_sudo
-install_prerequisites
-build_port_listener
diff --git a/guest/port_listener/src/common.h b/guest/port_listener/src/common.h
deleted file mode 100644
index d6e507c..0000000
--- a/guest/port_listener/src/common.h
+++ /dev/null
@@ -1,31 +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.
-
-// Copied from ChromiumOS with relicensing:
-// src/platform2/vm_tools/port_listener/common.h
-
-#ifndef VM_TOOLS_PORT_LISTENER_COMMON_H_
-#define VM_TOOLS_PORT_LISTENER_COMMON_H_
-
-enum State {
-    kPortListenerUp,
-    kPortListenerDown,
-};
-
-struct event {
-    enum State state;
-    uint16_t port;
-};
-
-#endif // VM_TOOLS_PORT_LISTENER_COMMON_H_
diff --git a/guest/port_listener/src/listen_tracker.ebpf.c b/guest/port_listener/src/listen_tracker.ebpf.c
deleted file mode 100644
index 9e98aad..0000000
--- a/guest/port_listener/src/listen_tracker.ebpf.c
+++ /dev/null
@@ -1,80 +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.
-
-// Copied from ChromiumOS with relicensing:
-// src/platform2/vm_tools/port_listener/listen_tracker.ebpf.c
-
-// bpf_helpers.h uses types defined here
-#include <bpf/bpf_helpers.h>
-
-#include "common.h"
-#include "vmlinux.h"
-
-// For some reason 6.1 doesn't include these symbols in the debug build
-// so they don't get included in vmlinux.h. These features have existed since
-// well before 6.1.
-#define BPF_F_NO_PREALLOC (1U << 0)
-#define BPF_ANY 0
-
-struct {
-    __uint(type, BPF_MAP_TYPE_RINGBUF);
-    __uint(max_entries, 1 << 24);
-} events SEC(".maps");
-
-struct {
-    __uint(type, BPF_MAP_TYPE_HASH);
-    __type(key, struct sock*);
-    __type(value, __u8);
-    __uint(max_entries, 65535);
-    __uint(map_flags, BPF_F_NO_PREALLOC);
-} sockmap SEC(".maps");
-
-const __u8 set_value = 0;
-
-SEC("tp/sock/inet_sock_set_state")
-int tracepoint_inet_sock_set_state(struct trace_event_raw_inet_sock_set_state* ctx) {
-    // We don't support anything other than TCP.
-    if (ctx->protocol != IPPROTO_TCP) {
-        return 0;
-    }
-    struct sock* sk = (struct sock*)ctx->skaddr;
-    // If we're transitioning away from LISTEN but we don't know about this
-    // socket yet then don't report anything.
-    if (ctx->oldstate == BPF_TCP_LISTEN && bpf_map_lookup_elem(&sockmap, &sk) == NULL) {
-        return 0;
-    }
-    // If we aren't transitioning to or from TCP_LISTEN then we don't care.
-    if (ctx->newstate != BPF_TCP_LISTEN && ctx->oldstate != BPF_TCP_LISTEN) {
-        return 0;
-    }
-
-    struct event* ev;
-    ev = bpf_ringbuf_reserve(&events, sizeof(*ev), 0);
-    if (!ev) {
-        return 0;
-    }
-    ev->port = ctx->sport;
-
-    if (ctx->newstate == BPF_TCP_LISTEN) {
-        bpf_map_update_elem(&sockmap, &sk, &set_value, BPF_ANY);
-        ev->state = kPortListenerUp;
-    }
-    if (ctx->oldstate == BPF_TCP_LISTEN) {
-        bpf_map_delete_elem(&sockmap, &sk);
-        ev->state = kPortListenerDown;
-    }
-    bpf_ringbuf_submit(ev, 0);
-
-    return 0;
-}
diff --git a/guest/port_listener/src/main.cc b/guest/port_listener/src/main.cc
deleted file mode 100644
index 1caceaf..0000000
--- a/guest/port_listener/src/main.cc
+++ /dev/null
@@ -1,167 +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.
-
-// Copied from ChromiumOS with relicensing:
-// src/platform2/vm_tools/port_listener/main.cc
-
-#include <bpf/libbpf.h>
-#include <bpf/libbpf_legacy.h>
-#include <glog/logging.h>
-#include <linux/vm_sockets.h> // Needs to come after sys/socket.h
-#include <sys/socket.h>
-
-#include <memory>
-#include <unordered_map>
-
-#include "common.h"
-#include "listen_tracker.skel.h"
-
-typedef std::unordered_map<int, int> port_usage_map;
-
-namespace port_listener {
-namespace {
-
-int HandleEvent(void* ctx, void* const data, size_t size) {
-    port_usage_map* map = reinterpret_cast<port_usage_map*>(ctx);
-    const struct event* ev = (struct event*)data;
-
-    switch (ev->state) {
-        case kPortListenerUp:
-            (*map)[ev->port]++;
-            break;
-
-        case kPortListenerDown:
-            if ((*map)[ev->port] > 0) {
-                (*map)[ev->port]--;
-            } else {
-                LOG(INFO) << "Received down event while port count was 0; ignoring";
-            }
-
-            break;
-
-        default:
-            LOG(ERROR) << "Unknown event state " << ev->state;
-    }
-
-    LOG(INFO) << "Listen event: port=" << ev->port << " state=" << ev->state;
-
-    return 0;
-}
-
-typedef std::unique_ptr<struct ring_buffer, decltype(&ring_buffer__free)> ring_buffer_ptr;
-typedef std::unique_ptr<listen_tracker_ebpf, decltype(&listen_tracker_ebpf__destroy)>
-        listen_tracker_ptr;
-
-// BPFProgram tracks the state and resources of the listen_tracker BPF program.
-class BPFProgram {
-public:
-    // Default movable but not copyable.
-    BPFProgram(BPFProgram&& other) = default;
-    BPFProgram(const BPFProgram& other) = delete;
-    BPFProgram& operator=(BPFProgram&& other) = default;
-    BPFProgram& operator=(const BPFProgram& other) = delete;
-
-    // Load loads the listen_tracker BPF program and prepares it for polling. On
-    // error nullptr is returned.
-    static std::unique_ptr<BPFProgram> Load() {
-        auto* skel = listen_tracker_ebpf__open();
-        if (!skel) {
-            PLOG(ERROR) << "Failed to open listen_tracker BPF skeleton";
-            return nullptr;
-        }
-        listen_tracker_ptr skeleton(skel, listen_tracker_ebpf__destroy);
-
-        int err = listen_tracker_ebpf__load(skeleton.get());
-        if (err) {
-            PLOG(ERROR) << "Failed to load listen_tracker BPF program";
-            return nullptr;
-        }
-
-        auto map = std::make_unique<port_usage_map>();
-        auto* rb = ring_buffer__new(bpf_map__fd(skel->maps.events), HandleEvent, map.get(), NULL);
-        if (!rb) {
-            PLOG(ERROR) << "Failed to open ring buffer for listen_tracker";
-            return nullptr;
-        }
-        ring_buffer_ptr ringbuf(rb, ring_buffer__free);
-
-        err = listen_tracker_ebpf__attach(skeleton.get());
-        if (err) {
-            PLOG(ERROR) << "Failed to attach listen_tracker";
-            return nullptr;
-        }
-
-        return std::unique_ptr<BPFProgram>(
-                new BPFProgram(std::move(skeleton), std::move(ringbuf), std::move(map)));
-    }
-
-    // Poll waits for the listen_tracker BPF program to post a new event to the
-    // ring buffer. BPFProgram handles integrating this new event into the
-    // port_usage map and callers should consult port_usage() after Poll returns
-    // for the latest data.
-    const bool Poll() {
-        int err = ring_buffer__poll(rb_.get(), -1);
-        if (err < 0) {
-            LOG(ERROR) << "Error polling ring buffer ret=" << err;
-            return false;
-        }
-
-        return true;
-    }
-
-    const port_usage_map& port_usage() { return *port_usage_; }
-
-private:
-    BPFProgram(listen_tracker_ptr&& skeleton, ring_buffer_ptr&& rb,
-               std::unique_ptr<port_usage_map>&& port_usage)
-          : skeleton_(std::move(skeleton)),
-            rb_(std::move(rb)),
-            port_usage_(std::move(port_usage)) {}
-
-    listen_tracker_ptr skeleton_;
-    ring_buffer_ptr rb_;
-    std::unique_ptr<port_usage_map> port_usage_;
-};
-
-} // namespace
-} // namespace port_listener
-
-int main(int argc, char** argv) {
-    google::InitGoogleLogging(argv[0]);
-    libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
-
-    // Load our BPF program.
-    auto program = port_listener::BPFProgram::Load();
-    if (program == nullptr) {
-        LOG(ERROR) << "Failed to load BPF program";
-        return EXIT_FAILURE;
-    }
-
-    // main loop: poll for listen updates
-    for (;;) {
-        if (!program->Poll()) {
-            LOG(ERROR) << "Failure while polling BPF program";
-            return EXIT_FAILURE;
-        }
-        // port_usage will be updated with the latest usage data
-
-        for (auto it : program->port_usage()) {
-            if (it.second <= 0) {
-                continue;
-            }
-            // TODO(b/340126051): Add listening TCP4 ports.
-        }
-        // TODO(b/340126051): Notify port information to the guest agent.
-    }
-}
diff --git a/guest/pvmfw/src/device_assignment.rs b/guest/pvmfw/src/device_assignment.rs
index da9462b..9b55cff 100644
--- a/guest/pvmfw/src/device_assignment.rs
+++ b/guest/pvmfw/src/device_assignment.rs
@@ -784,14 +784,16 @@
             if reg.size != phys_reg.size {
                 return Err(DeviceAssignmentError::InvalidRegSize(reg.size, phys_reg.size));
             }
-            let expected_token = phys_reg.addr;
-            // If this call returns successfully, hyp has mapped the MMIO region at `reg`.
-            let token = hypervisor.get_phys_mmio_token(reg.addr, reg.size).map_err(|e| {
-                error!("Hypervisor error while requesting MMIO token: {e}");
-                DeviceAssignmentError::InvalidReg(reg.addr)
-            })?;
-            if token != expected_token {
-                return Err(DeviceAssignmentError::InvalidRegToken(token, expected_token));
+            for offset in (0..reg.size).step_by(granule) {
+                let expected_token = phys_reg.addr + offset;
+                // If this call returns successfully, hyp has mapped the MMIO granule.
+                let token = hypervisor.get_phys_mmio_token(reg.addr + offset).map_err(|e| {
+                    error!("Hypervisor error while requesting MMIO token: {e}");
+                    DeviceAssignmentError::InvalidReg(reg.addr)
+                })?;
+                if token != expected_token {
+                    return Err(DeviceAssignmentError::InvalidRegToken(token, expected_token));
+                }
             }
         }
 
@@ -1143,7 +1145,7 @@
 #[cfg(test)]
 trait DeviceAssigningHypervisor {
     /// Returns MMIO token.
-    fn get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> MockHypervisorResult<u64>;
+    fn get_phys_mmio_token(&self, base_ipa: u64) -> MockHypervisorResult<u64>;
 
     /// Returns DMA token as a tuple of (phys_iommu_id, phys_sid).
     fn get_phys_iommu_token(&self, pviommu_id: u64, vsid: u64) -> MockHypervisorResult<(u64, u64)>;
@@ -1206,7 +1208,7 @@
     }
 
     impl DeviceAssigningHypervisor for MockHypervisor {
-        fn get_phys_mmio_token(&self, base_ipa: u64, _size: u64) -> MockHypervisorResult<u64> {
+        fn get_phys_mmio_token(&self, base_ipa: u64) -> MockHypervisorResult<u64> {
             let token = self.get_mmio_token(base_ipa);
 
             Ok(*token.ok_or(MockHypervisorError::FailedGetPhysMmioToken)?)
diff --git a/guest/trusty/security_vm/launcher/Android.bp b/guest/trusty/security_vm/launcher/Android.bp
index ff628fd..e482e02 100644
--- a/guest/trusty/security_vm/launcher/Android.bp
+++ b/guest/trusty/security_vm/launcher/Android.bp
@@ -18,3 +18,40 @@
         false: false,
     }),
 }
+
+prebuilt_etc {
+    name: "lk_trusty.elf",
+    system_ext_specific: true,
+    relative_install_path: "vm/trusty_vm",
+    filename: "lk_trusty.elf",
+    arch: {
+        x86_64: {
+            src: ":trusty_security_vm_signed",
+        },
+    },
+    src: ":empty_file",
+}
+
+filegroup {
+    name: "trusty_vm_sign_key",
+    srcs: [":avb_testkey_rsa4096"],
+}
+
+// python -c "import hashlib; print(hashlib.sha256(b'trusty_security_vm_salt').hexdigest())"
+trusty_security_vm_salt = "75a71e967c1a1e0f805cca20465e7acf83e6a04e567a67c426d8b5a94f8d61c5"
+
+avb_add_hash_footer {
+    name: "trusty_security_vm_signed",
+    filename: "trusty_security_vm_signed",
+    partition_name: "boot",
+    private_key: ":trusty_vm_sign_key",
+    salt: trusty_security_vm_salt,
+    src: ":empty_file",
+    enabled: false,
+    arch: {
+        x86_64: {
+            src: ":trusty-test-lk.elf",
+            enabled: true,
+        },
+    },
+}
diff --git a/libs/libvmbase/src/hyp/hypervisor/common.rs b/libs/libvmbase/src/hyp/hypervisor/common.rs
index de0fe12..8f0e4dc 100644
--- a/libs/libvmbase/src/hyp/hypervisor/common.rs
+++ b/libs/libvmbase/src/hyp/hypervisor/common.rs
@@ -69,7 +69,7 @@
 /// Device assigning hypervisor
 pub trait DeviceAssigningHypervisor {
     /// Returns MMIO token.
-    fn get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> Result<u64>;
+    fn get_phys_mmio_token(&self, base_ipa: u64) -> Result<u64>;
 
     /// Returns DMA token as a tuple of (phys_iommu_id, phys_sid).
     fn get_phys_iommu_token(&self, pviommu_id: u64, vsid: u64) -> Result<(u64, u64)>;
diff --git a/libs/libvmbase/src/hyp/hypervisor/kvm.rs b/libs/libvmbase/src/hyp/hypervisor/kvm.rs
index e496f09..7ed829e 100644
--- a/libs/libvmbase/src/hyp/hypervisor/kvm.rs
+++ b/libs/libvmbase/src/hyp/hypervisor/kvm.rs
@@ -173,10 +173,9 @@
 }
 
 impl DeviceAssigningHypervisor for ProtectedKvmHypervisor {
-    fn get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> Result<u64> {
+    fn get_phys_mmio_token(&self, base_ipa: u64) -> Result<u64> {
         let mut args = [0u64; 17];
         args[0] = base_ipa;
-        args[1] = size;
 
         let ret = checked_hvc64_expect_results(VENDOR_HYP_KVM_DEV_REQ_MMIO_FUNC_ID, args)?;
         Ok(ret[0])
diff --git a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
index 61679f2..c64ff77 100644
--- a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
+++ b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/DebianServiceImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.virtualization.vmlauncher;
 
+import android.content.Context;
+import android.content.SharedPreferences;
 import android.util.Log;
 
 import androidx.annotation.Keep;
@@ -28,17 +30,47 @@
 
 import io.grpc.stub.StreamObserver;
 
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
 final class DebianServiceImpl extends DebianServiceGrpc.DebianServiceImplBase {
     public static final String TAG = "DebianService";
+    private static final String PREFERENCE_FILE_KEY =
+            "com.android.virtualization.terminal.PREFERENCE_FILE_KEY";
+    private static final String PREFERENCE_FORWARDING_PORTS = "PREFERENCE_FORWARDING_PORTS";
+    private static final String PREFERENCE_FORWARDING_PORT_IS_ENABLED_PREFIX =
+            "PREFERENCE_FORWARDING_PORT_IS_ENABLED_";
+
+    private final Context mContext;
+    private final SharedPreferences mSharedPref;
+    private SharedPreferences.OnSharedPreferenceChangeListener mPortForwardingListener;
     private final DebianServiceCallback mCallback;
 
+
     static {
         System.loadLibrary("forwarder_host_jni");
     }
 
-    protected DebianServiceImpl(DebianServiceCallback callback) {
+    DebianServiceImpl(Context context, DebianServiceCallback callback) {
         super();
         mCallback = callback;
+        mContext = context;
+        mSharedPref = mContext.getSharedPreferences(PREFERENCE_FILE_KEY, Context.MODE_PRIVATE);
+        // TODO(b/340126051): Instead of putting fixed value, receive active port list info from the
+        // guest.
+        if (!mSharedPref.contains(PREFERENCE_FORWARDING_PORTS)) {
+            SharedPreferences.Editor editor = mSharedPref.edit();
+            Set<String> ports = new HashSet<>();
+            for (int port = 8080; port < 8090; port++) {
+                ports.add(Integer.toString(port));
+                editor.putBoolean(
+                        PREFERENCE_FORWARDING_PORT_IS_ENABLED_PREFIX + Integer.toString(port),
+                        false);
+            }
+            editor.putStringSet(PREFERENCE_FORWARDING_PORTS, ports);
+            editor.apply();
+        }
     }
 
     @Override
@@ -55,6 +87,19 @@
     public void openForwardingRequestQueue(
             QueueOpeningRequest request, StreamObserver<ForwardingRequestItem> responseObserver) {
         Log.d(DebianServiceImpl.TAG, "OpenForwardingRequestQueue");
+        mPortForwardingListener =
+                new SharedPreferences.OnSharedPreferenceChangeListener() {
+                    @Override
+                    public void onSharedPreferenceChanged(
+                            SharedPreferences sharedPreferences, String key) {
+                        if (key.startsWith(PREFERENCE_FORWARDING_PORT_IS_ENABLED_PREFIX)
+                                || key.equals(PREFERENCE_FORWARDING_PORTS)) {
+                            updateListeningPorts();
+                        }
+                    }
+                };
+        mSharedPref.registerOnSharedPreferenceChangeListener(mPortForwardingListener);
+        updateListeningPorts();
         runForwarderHost(request.getCid(), new ForwarderHostCallback(responseObserver));
         responseObserver.onCompleted();
     }
@@ -79,7 +124,32 @@
 
     private static native void runForwarderHost(int cid, ForwarderHostCallback callback);
 
-    public static native void terminateForwarderHost();
+    private static native void terminateForwarderHost();
+
+    void killForwarderHost() {
+        Log.d(DebianServiceImpl.TAG, "Stopping port forwarding");
+        if (mPortForwardingListener != null) {
+            mSharedPref.unregisterOnSharedPreferenceChangeListener(mPortForwardingListener);
+            terminateForwarderHost();
+        }
+    }
+
+    private static native void updateListeningPorts(int[] ports);
+
+    private void updateListeningPorts() {
+        updateListeningPorts(
+                mSharedPref
+                        .getStringSet(PREFERENCE_FORWARDING_PORTS, Collections.emptySet())
+                        .stream()
+                        .filter(
+                                port ->
+                                        mSharedPref.getBoolean(
+                                                PREFERENCE_FORWARDING_PORT_IS_ENABLED_PREFIX + port,
+                                                false))
+                        .map(Integer::valueOf)
+                        .mapToInt(Integer::intValue)
+                        .toArray());
+    }
 
     protected interface DebianServiceCallback {
         void onIpAddressAvailable(String ipAddr);
diff --git a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java
index 2bd85e1..846fd26 100644
--- a/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java
+++ b/libs/vm_launcher_lib/java/com/android/virtualization/vmlauncher/VmLauncherService.java
@@ -60,6 +60,7 @@
     private VirtualMachine mVirtualMachine;
     private ResultReceiver mResultReceiver;
     private Server mServer;
+    private DebianServiceImpl mDebianService;
 
     @Override
     public IBinder onBind(Intent intent) {
@@ -107,9 +108,7 @@
                             if (mResultReceiver != null) {
                                 mResultReceiver.send(success ? RESULT_STOP : RESULT_ERROR, null);
                             }
-                            if (!success) {
-                                stopSelf();
-                            }
+                            stopSelf();
                         });
         Path logPath = getFileStreamPath(mVirtualMachine.getName() + ".log").toPath();
         Logger.setup(mVirtualMachine, logPath, mExecutorService);
@@ -129,6 +128,7 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+        stopDebianServer();
         if (mVirtualMachine != null) {
             if (mVirtualMachine.getStatus() == VirtualMachine.STATUS_RUNNING) {
                 try {
@@ -142,7 +142,6 @@
             mExecutorService = null;
             mVirtualMachine = null;
         }
-        stopDebianServer();
     }
 
     private void startDebianServer() {
@@ -174,10 +173,11 @@
         try {
             // TODO(b/372666638): gRPC for java doesn't support vsock for now.
             int port = 0;
+            mDebianService = new DebianServiceImpl(this, this);
             mServer =
                     OkHttpServerBuilder.forPort(port, InsecureServerCredentials.create())
                             .intercept(interceptor)
-                            .addService(new DebianServiceImpl(this))
+                            .addService(mDebianService)
                             .build()
                             .start();
         } catch (IOException e) {
@@ -199,8 +199,10 @@
     }
 
     private void stopDebianServer() {
+        if (mDebianService != null) {
+            mDebianService.killForwarderHost();
+        }
         if (mServer != null) {
-            DebianServiceImpl.terminateForwarderHost();
             mServer.shutdown();
         }
     }