Merge "Speak something for the invisible element" into main
diff --git a/android/TerminalApp/Android.bp b/android/TerminalApp/Android.bp
index 2711af0..733a72b 100644
--- a/android/TerminalApp/Android.bp
+++ b/android/TerminalApp/Android.bp
@@ -9,7 +9,6 @@
"java/**/*.kt",
],
resource_dirs: ["res"],
- asset_dirs: ["assets"],
static_libs: [
"androidx-constraintlayout_constraintlayout",
"androidx.window_window",
diff --git a/android/TerminalApp/assets/.gitkeep b/android/TerminalApp/assets/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/android/TerminalApp/assets/.gitkeep
+++ /dev/null
diff --git a/android/TerminalApp/assets/client.p12 b/android/TerminalApp/assets/client.p12
deleted file mode 100644
index f1f5820..0000000
--- a/android/TerminalApp/assets/client.p12
+++ /dev/null
Binary files differ
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.java b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.java
new file mode 100644
index 0000000..12f485a
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ImageArchive.java
@@ -0,0 +1,116 @@
+/*
+ * 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.os.Build;
+import android.os.Environment;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
+import java.util.function.Function;
+
+/**
+ * ImageArchive models the archive file (images.tar.gz) where VM payload files are in. This class
+ * provides methods for handling the archive file, most importantly installing it.
+ */
+class ImageArchive {
+ private static final String DIR_IN_SDCARD = "linux";
+ private static final String ARCHIVE_NAME = "images.tar.gz";
+ private static final String HOST_URL = "https://dl.google.com/android/ferrochrome/latest";
+
+ // Only one can be non-null
+ private final URL mUrl;
+ private final Path mPath;
+
+ private ImageArchive(URL url) {
+ mUrl = url;
+ mPath = null;
+ }
+
+ private ImageArchive(Path path) {
+ mUrl = null;
+ mPath = path;
+ }
+
+ /** Creates ImageArchive which is located in the sdcard. This archive is for testing only. */
+ public static ImageArchive fromSdCard() {
+ Path dir = Environment.getExternalStoragePublicDirectory(DIR_IN_SDCARD).toPath();
+ Path file = dir.resolve(ARCHIVE_NAME);
+ return new ImageArchive(file);
+ }
+
+ /** Creates ImageArchive which is hosted in the Google server. This is the official archive. */
+ public static ImageArchive fromInternet() {
+ String arch = Arrays.asList(Build.SUPPORTED_ABIS).contains("x86_64") ? "x86_64" : "aarch64";
+ try {
+ URL url = new URL(HOST_URL + "/" + arch + "/" + ARCHIVE_NAME);
+ return new ImageArchive(url);
+ } catch (MalformedURLException e) {
+ // cannot happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ private InputStream getInputStream(Function<InputStream, InputStream> filter)
+ throws IOException {
+ InputStream is = mPath != null ? new FileInputStream(mPath.toFile()) : mUrl.openStream();
+ BufferedInputStream bufStream = new BufferedInputStream(is);
+ return filter == null ? bufStream : filter.apply(bufStream);
+ }
+
+ /**
+ * Installs this ImageArchive to a directory pointed by path. filter can be supplied to provide
+ * an additional input stream which will be used during the installation.
+ */
+ public void installTo(Path path, Function<InputStream, InputStream> filter) throws IOException {
+ try (InputStream stream = getInputStream(filter);
+ GzipCompressorInputStream gzStream = new GzipCompressorInputStream(stream);
+ TarArchiveInputStream tarStream = new TarArchiveInputStream(gzStream)) {
+
+ Files.createDirectories(path);
+ ArchiveEntry entry;
+ while ((entry = tarStream.getNextEntry()) != null) {
+ Path to = path.resolve(entry.getName());
+ if (Files.isDirectory(to)) {
+ Files.createDirectories(to);
+ } else {
+ Files.copy(tarStream, to, StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+ }
+ postInstall();
+ }
+
+ // To save storage, delete the source archive on the disk.
+ private void postInstall() throws IOException {
+ if (mPath != null) {
+ Files.deleteIfExists(mPath);
+ }
+ }
+}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
index 4b2e640..a8b4ca2 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/InstallerService.java
@@ -64,9 +64,6 @@
? "https://dl.google.com/android/ferrochrome/latest/x86_64/images.tar.gz"
: "https://dl.google.com/android/ferrochrome/latest/aarch64/images.tar.gz";
- private static final String SELINUX_FILE_CONTEXT =
- "u:object_r:virtualizationservice_data_file:";
-
private final Object mLock = new Object();
private Notification mNotification;
@@ -162,9 +159,6 @@
mExecutorService.execute(
() -> {
boolean success = downloadFromSdcard() || downloadFromUrl(isWifiOnly);
- if (success) {
- reLabelImagesSELinuxContext();
- }
stopForeground(STOP_FOREGROUND_REMOVE);
synchronized (mLock) {
@@ -176,24 +170,6 @@
});
}
- private void reLabelImagesSELinuxContext() {
- File payloadFolder = InstallUtils.getInternalStorageDir(this).toFile();
-
- // The context should be u:object_r:privapp_data_file:s0:c35,c257,c512,c768
- // and we want to get s0:c35,c257,c512,c768 part
- String level = SELinux.getFileContext(payloadFolder.toString()).split(":", 4)[3];
- String targetContext = SELINUX_FILE_CONTEXT + level;
-
- File[] files = payloadFolder.listFiles();
- for (File file : files) {
- if (file.isFile() &&
- !Objects.equals(SELinux.getFileContext(file.toString()),
- targetContext)) {
- SELinux.setFileContext(file.toString(), targetContext);
- }
- }
- }
-
private boolean downloadFromSdcard() {
// Installing from sdcard is preferred, but only supported only in debuggable build.
if (Build.isDebuggable()) {
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
index 1b39ff0..a332a9d 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
@@ -47,7 +47,7 @@
HashSet<String>()
)
- for (port in ports!!) {
+ for (port in ports!!.sortedWith(compareBy( { it.toInt() } ))) {
val enabled =
sharedPref.getBoolean(
getString(R.string.preference_forwarding_port_is_enabled) + port,
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 1cae344..9a733b6 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -573,41 +573,42 @@
.or_binder_exception(ExceptionCode::SECURITY)?;
}
- // Check if partition images are labeled incorrectly. This is to prevent random images
- // which are not protected by the Android Verified Boot (e.g. bits downloaded by apps) from
- // being loaded in a pVM. This applies to everything but the instance image in the raw
- // config, and everything but the non-executable, generated partitions in the app
- // config.
- config
- .disks
- .iter()
- .flat_map(|disk| disk.partitions.iter())
- .filter(|partition| {
- if is_app_config {
- !is_safe_app_partition(&partition.label)
- } else {
- !is_safe_raw_partition(&partition.label)
- }
- })
- .try_for_each(check_label_for_partition)
- .or_service_specific_exception(-1)?;
+ let kernel = maybe_clone_file(&config.kernel)?;
+ let initrd = maybe_clone_file(&config.initrd)?;
+
+ if config.protectedVm {
+ // Fail fast with a meaningful error message in case device doesn't support pVMs.
+ check_protected_vm_is_supported()?;
+
+ // In a protected VM, we require custom kernels to come from a trusted source
+ // (b/237054515).
+ check_label_for_kernel_files(&kernel, &initrd).or_service_specific_exception(-1)?;
+
+ // Check if partition images are labeled incorrectly. This is to prevent random images
+ // which are not protected by the Android Verified Boot (e.g. bits downloaded by apps)
+ // from being loaded in a pVM. This applies to everything but the instance image in the
+ // raw config, and everything but the non-executable, generated partitions in the app
+ // config.
+ config
+ .disks
+ .iter()
+ .flat_map(|disk| disk.partitions.iter())
+ .filter(|partition| {
+ if is_app_config {
+ !is_safe_app_partition(&partition.label)
+ } else {
+ !is_safe_raw_partition(&partition.label)
+ }
+ })
+ .try_for_each(check_label_for_partition)
+ .or_service_specific_exception(-1)?;
+ }
// Check if files for payloads and bases are NOT coming from /vendor and /odm, as they may
// have unstable interfaces.
// TODO(b/316431494): remove once Treble interfaces are stabilized.
check_partitions_for_files(config).or_service_specific_exception(-1)?;
- let kernel = maybe_clone_file(&config.kernel)?;
- let initrd = maybe_clone_file(&config.initrd)?;
-
- if config.protectedVm {
- // In a protected VM, we require custom kernels to come from a trusted source
- // (b/237054515).
- check_label_for_kernel_files(&kernel, &initrd).or_service_specific_exception(-1)?;
- // Fail fast with a meaningful error message in case device doesn't support pVMs.
- check_protected_vm_is_supported()?;
- }
-
let zero_filler_path = temporary_directory.join("zero.img");
write_zero_filler(&zero_filler_path)
.context("Failed to make composite image")
diff --git a/build/debian/fai_config/scripts/AVF/10-systemd b/build/debian/fai_config/scripts/AVF/10-systemd
index a514299..94838bc 100755
--- a/build/debian/fai_config/scripts/AVF/10-systemd
+++ b/build/debian/fai_config/scripts/AVF/10-systemd
@@ -10,3 +10,5 @@
ln -s /etc/systemd/system/forwarder_guest_launcher.service $target/etc/systemd/system/multi-user.target.wants/forwarder_guest_launcher.service
ln -s /etc/systemd/system/virtiofs_internal.service $target/etc/systemd/system/multi-user.target.wants/virtiofs_internal.service
ln -s /etc/systemd/system/backup_mount.service $target/etc/systemd/system/multi-user.target.wants/backup_mount.service
+
+sed -i 's/#LLMNR=yes/LLMNR=no/' $target/etc/systemd/resolved.conf
diff --git a/guest/forwarder_guest_launcher/src/main.rs b/guest/forwarder_guest_launcher/src/main.rs
index 1da37b4..f6944d6 100644
--- a/guest/forwarder_guest_launcher/src/main.rs
+++ b/guest/forwarder_guest_launcher/src/main.rs
@@ -35,6 +35,7 @@
}
const NON_PREVILEGED_PORT_RANGE_START: i32 = 1024;
+const TTYD_PORT: i32 = 7681;
const TCPSTATES_IP_4: i8 = 4;
const TCPSTATES_STATE_CLOSE: &str = "CLOSE";
const TCPSTATES_STATE_LISTEN: &str = "LISTEN";
@@ -108,6 +109,10 @@
Ok(())
}
+fn is_forwardable_port(port: i32) -> bool {
+ port >= NON_PREVILEGED_PORT_RANGE_START && port != TTYD_PORT
+}
+
async fn report_active_ports(
mut client: DebianServiceClient<Channel>,
) -> Result<(), Box<dyn std::error::Error>> {
@@ -130,7 +135,7 @@
.map(|x| x.socket)
.filter(|x| x.is_ipv4())
.map(|x| x.port().into())
- .filter(|x| *x >= NON_PREVILEGED_PORT_RANGE_START) // Ignore privileged ports
+ .filter(|x| is_forwardable_port(*x))
.collect();
send_active_ports_report(listening_ports.clone(), &mut client).await?;
@@ -140,7 +145,7 @@
if row.ip != TCPSTATES_IP_4 {
continue;
}
- if row.lport < NON_PREVILEGED_PORT_RANGE_START {
+ if !is_forwardable_port(row.lport) {
continue;
}
if row.rport > 0 {