Merge "vmbase: bionic: Make FILE* non-dereferencable" into main
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java b/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
index e18aca2..b3c0746 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -709,6 +709,10 @@
config.consoleInputDevice = mConsoleInputDevice;
config.devices = EMPTY_STRING_ARRAY;
config.platformVersion = "~1.0";
+ config.audioConfig =
+ Optional.ofNullable(customImageConfig.getAudioConfig())
+ .map(ac -> ac.toParcelable())
+ .orElse(null);
return config;
}
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java b/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
index 7fbfb33..125e01c 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
@@ -39,6 +39,7 @@
private static final String KEY_SWITCHES = "switches";
private static final String KEY_NETWORK = "network";
private static final String KEY_GPU = "gpu";
+ private static final String KEY_AUDIO_CONFIG = "audio_config";
@Nullable private final String name;
@Nullable private final String kernelPath;
@@ -47,6 +48,7 @@
@Nullable private final String[] params;
@Nullable private final Disk[] disks;
@Nullable private final DisplayConfig displayConfig;
+ @Nullable private final AudioConfig audioConfig;
private final boolean touch;
private final boolean keyboard;
private final boolean mouse;
@@ -118,7 +120,8 @@
boolean mouse,
boolean switches,
boolean network,
- GpuConfig gpuConfig) {
+ GpuConfig gpuConfig,
+ AudioConfig audioConfig) {
this.name = name;
this.kernelPath = kernelPath;
this.initrdPath = initrdPath;
@@ -132,6 +135,7 @@
this.switches = switches;
this.network = network;
this.gpuConfig = gpuConfig;
+ this.audioConfig = audioConfig;
}
static VirtualMachineCustomImageConfig from(PersistableBundle customImageConfigBundle) {
@@ -164,6 +168,9 @@
builder.useMouse(customImageConfigBundle.getBoolean(KEY_MOUSE));
builder.useNetwork(customImageConfigBundle.getBoolean(KEY_NETWORK));
builder.setGpuConfig(GpuConfig.from(customImageConfigBundle.getPersistableBundle(KEY_GPU)));
+ PersistableBundle audioConfigPb =
+ customImageConfigBundle.getPersistableBundle(KEY_AUDIO_CONFIG);
+ builder.setAudioConfig(AudioConfig.from(audioConfigPb));
return builder.build();
}
@@ -200,10 +207,18 @@
pb.putPersistableBundle(
KEY_GPU,
Optional.ofNullable(gpuConfig).map(gc -> gc.toPersistableBundle()).orElse(null));
+ pb.putPersistableBundle(
+ KEY_AUDIO_CONFIG,
+ Optional.ofNullable(audioConfig).map(ac -> ac.toPersistableBundle()).orElse(null));
return pb;
}
@Nullable
+ public AudioConfig getAudioConfig() {
+ return audioConfig;
+ }
+
+ @Nullable
public DisplayConfig getDisplayConfig() {
return displayConfig;
}
@@ -252,6 +267,7 @@
private String bootloaderPath;
private List<String> params = new ArrayList<>();
private List<Disk> disks = new ArrayList<>();
+ private AudioConfig audioConfig;
private DisplayConfig displayConfig;
private boolean touch;
private boolean keyboard;
@@ -342,6 +358,12 @@
}
/** @hide */
+ public Builder setAudioConfig(AudioConfig audioConfig) {
+ this.audioConfig = audioConfig;
+ return this;
+ }
+
+ /** @hide */
public VirtualMachineCustomImageConfig build() {
return new VirtualMachineCustomImageConfig(
this.name,
@@ -356,7 +378,83 @@
mouse,
switches,
network,
- gpuConfig);
+ gpuConfig,
+ audioConfig);
+ }
+ }
+
+ /** @hide */
+ public static final class AudioConfig {
+ private static final String KEY_USE_MICROPHONE = "use_microphone";
+ private static final String KEY_USE_SPEAKER = "use_speaker";
+ private final boolean useMicrophone;
+ private final boolean useSpeaker;
+
+ private AudioConfig(boolean useMicrophone, boolean useSpeaker) {
+ this.useMicrophone = useMicrophone;
+ this.useSpeaker = useSpeaker;
+ }
+
+ /** @hide */
+ public boolean useMicrophone() {
+ return useMicrophone;
+ }
+
+ /** @hide */
+ public boolean useSpeaker() {
+ return useSpeaker;
+ }
+
+ android.system.virtualizationservice.AudioConfig toParcelable() {
+ android.system.virtualizationservice.AudioConfig parcelable =
+ new android.system.virtualizationservice.AudioConfig();
+ parcelable.useSpeaker = this.useSpeaker;
+ parcelable.useMicrophone = this.useMicrophone;
+
+ return parcelable;
+ }
+
+ private static AudioConfig from(PersistableBundle pb) {
+ if (pb == null) {
+ return null;
+ }
+ Builder builder = new Builder();
+ builder.setUseMicrophone(pb.getBoolean(KEY_USE_MICROPHONE));
+ builder.setUseSpeaker(pb.getBoolean(KEY_USE_SPEAKER));
+ return builder.build();
+ }
+
+ private PersistableBundle toPersistableBundle() {
+ PersistableBundle pb = new PersistableBundle();
+ pb.putBoolean(KEY_USE_MICROPHONE, this.useMicrophone);
+ pb.putBoolean(KEY_USE_SPEAKER, this.useSpeaker);
+ return pb;
+ }
+
+ /** @hide */
+ public static class Builder {
+ private boolean useMicrophone = false;
+ private boolean useSpeaker = false;
+
+ /** @hide */
+ public Builder() {}
+
+ /** @hide */
+ public Builder setUseMicrophone(boolean useMicrophone) {
+ this.useMicrophone = useMicrophone;
+ return this;
+ }
+
+ /** @hide */
+ public Builder setUseSpeaker(boolean useSpeaker) {
+ this.useSpeaker = useSpeaker;
+ return this;
+ }
+
+ /** @hide */
+ public AudioConfig build() {
+ return new AudioConfig(useMicrophone, useSpeaker);
+ }
}
}
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 10dafdf..671a012 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -17,7 +17,7 @@
use crate::{get_calling_pid, get_calling_uid, get_this_pid};
use crate::atom::{write_vm_booted_stats, write_vm_creation_stats};
use crate::composite::make_composite_image;
-use crate::crosvm::{CrosvmConfig, DiskFile, DisplayConfig, GpuConfig, InputDeviceOption, PayloadState, VmContext, VmInstance, VmState};
+use crate::crosvm::{AudioConfig, CrosvmConfig, DiskFile, DisplayConfig, GpuConfig, InputDeviceOption, PayloadState, VmContext, VmInstance, VmState};
use crate::debug_config::DebugConfig;
use crate::dt_overlay::{create_device_tree_overlay, VM_DT_OVERLAY_MAX_SIZE, VM_DT_OVERLAY_PATH};
use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images, add_microdroid_vendor_image};
@@ -578,8 +578,12 @@
} else {
None
};
- let virtio_snd_backend =
- if cfg!(paravirtualized_devices) { Some(String::from("aaudio")) } else { None };
+
+ let audio_config = if cfg!(paravirtualized_devices) {
+ config.audioConfig.as_ref().map(AudioConfig::new)
+ } else {
+ None
+ };
// Actually start the VM.
let crosvm_config = CrosvmConfig {
@@ -610,10 +614,10 @@
input_device_options,
hugepages: config.hugePages,
tap,
- virtio_snd_backend,
console_input_device: config.consoleInputDevice.clone(),
boost_uclamp: config.boostUclamp,
gpu_config,
+ audio_config,
};
let instance = Arc::new(
VmInstance::new(
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index 13c018b..a9a91fe 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -46,6 +46,7 @@
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
MemoryTrimLevel::MemoryTrimLevel,
VirtualMachineAppConfig::DebugLevel::DebugLevel,
+ AudioConfig::AudioConfig as AudioConfigParcelable,
DisplayConfig::DisplayConfig as DisplayConfigParcelable,
GpuConfig::GpuConfig as GpuConfigParcelable,
};
@@ -131,10 +132,22 @@
pub input_device_options: Vec<InputDeviceOption>,
pub hugepages: bool,
pub tap: Option<File>,
- pub virtio_snd_backend: Option<String>,
pub console_input_device: Option<String>,
pub boost_uclamp: bool,
pub gpu_config: Option<GpuConfig>,
+ pub audio_config: Option<AudioConfig>,
+}
+
+#[derive(Debug)]
+pub struct AudioConfig {
+ pub use_microphone: bool,
+ pub use_speaker: bool,
+}
+
+impl AudioConfig {
+ pub fn new(raw_config: &AudioConfigParcelable) -> Self {
+ AudioConfig { use_microphone: raw_config.useMicrophone, use_speaker: raw_config.useSpeaker }
+ }
}
#[derive(Debug)]
@@ -1159,8 +1172,12 @@
command.preserved_fds(preserved_fds);
if cfg!(paravirtualized_devices) {
- if let Some(virtio_snd_backend) = &config.virtio_snd_backend {
- command.arg("--virtio-snd").arg(format!("backend={}", virtio_snd_backend));
+ if let Some(audio_config) = &config.audio_config {
+ command.arg("--virtio-snd").arg(format!(
+ "backend=aaudio,num_input_devices={},num_output_devices={}",
+ if audio_config.use_microphone { 1 } else { 0 },
+ if audio_config.use_speaker { 1 } else { 0 }
+ ));
}
}
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/AudioConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/AudioConfig.aidl
new file mode 100644
index 0000000..3e62d95
--- /dev/null
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/AudioConfig.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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 android.system.virtualizationservice;
+
+parcelable AudioConfig {
+ boolean useMicrophone;
+ boolean useSpeaker;
+}
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index 69664b4..07d52db 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -15,6 +15,7 @@
*/
package android.system.virtualizationservice;
+import android.system.virtualizationservice.AudioConfig;
import android.system.virtualizationservice.CpuTopology;
import android.system.virtualizationservice.DiskImage;
import android.system.virtualizationservice.DisplayConfig;
@@ -97,4 +98,6 @@
boolean boostUclamp;
@nullable GpuConfig gpuConfig;
+
+ @nullable AudioConfig audioConfig;
}
diff --git a/vmlauncher_app/AndroidManifest.xml b/vmlauncher_app/AndroidManifest.xml
index bae3227..f39e53b 100644
--- a/vmlauncher_app/AndroidManifest.xml
+++ b/vmlauncher_app/AndroidManifest.xml
@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.software.virtualization_framework" android:required="true" />
<application
android:label="VmLauncherApp">
diff --git a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
index e13d2c9..e9262ed 100644
--- a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
+++ b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
@@ -16,8 +16,10 @@
package com.android.virtualization.vmlauncher;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.system.virtualmachine.VirtualMachineConfig.CPU_TOPOLOGY_MATCH_HOST;
+import android.Manifest.permission;
import android.app.Activity;
import android.crosvm.ICrosvmAndroidDisplayService;
import android.graphics.PixelFormat;
@@ -31,6 +33,7 @@
import android.system.virtualmachine.VirtualMachineCallback;
import android.system.virtualmachine.VirtualMachineConfig;
import android.system.virtualmachine.VirtualMachineCustomImageConfig;
+import android.system.virtualmachine.VirtualMachineCustomImageConfig.AudioConfig;
import android.system.virtualmachine.VirtualMachineCustomImageConfig.DisplayConfig;
import android.system.virtualmachine.VirtualMachineCustomImageConfig.GpuConfig;
import android.system.virtualmachine.VirtualMachineException;
@@ -76,6 +79,7 @@
private ExecutorService mExecutorService;
private VirtualMachine mVirtualMachine;
private ParcelFileDescriptor mCursorStream;
+ private static final int RECORD_AUDIO_PERMISSION_REQUEST_CODE = 101;
private VirtualMachineConfig createVirtualMachineConfig(String jsonPath) {
VirtualMachineConfig.Builder configBuilder =
@@ -191,6 +195,10 @@
customImageConfigBuilder.useSwitches(true);
customImageConfigBuilder.useNetwork(true);
+ AudioConfig.Builder audioConfigBuilder = new AudioConfig.Builder();
+ audioConfigBuilder.setUseMicrophone(true);
+ audioConfigBuilder.setUseSpeaker(true);
+ customImageConfigBuilder.setAudioConfig(audioConfigBuilder.build());
configBuilder.setCustomImageConfig(customImageConfigBuilder.build());
} catch (JSONException | IOException e) {
@@ -224,6 +232,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ checkAndRequestRecordAudioPermission();
mExecutorService = Executors.newCachedThreadPool();
try {
// To ensure that the previous display service is removed.
@@ -519,6 +528,14 @@
}
}
+ private void checkAndRequestRecordAudioPermission() {
+ if (getApplicationContext().checkSelfPermission(permission.RECORD_AUDIO)
+ != PERMISSION_GRANTED) {
+ requestPermissions(
+ new String[] {permission.RECORD_AUDIO}, RECORD_AUDIO_PERMISSION_REQUEST_CODE);
+ }
+ }
+
/** Reads data from an input stream and posts it to the output data */
static class Reader implements Runnable {
private final String mName;