Merge "Convert vintf_fragments into vintf_fragment module(s)" into main
diff --git a/android/TerminalApp/Android.bp b/android/TerminalApp/Android.bp
index 1a7c581..d91af2f 100644
--- a/android/TerminalApp/Android.bp
+++ b/android/TerminalApp/Android.bp
@@ -4,10 +4,16 @@
android_app {
name: "VmTerminalApp",
- srcs: ["java/**/*.java"],
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.kt",
+ ],
resource_dirs: ["res"],
static_libs: [
"vm_launcher_lib",
+ "androidx-constraintlayout_constraintlayout",
+ "com.google.android.material_material",
+ "androidx.window_window",
],
platform_apis: true,
privileged: true,
diff --git a/android/TerminalApp/AndroidManifest.xml b/android/TerminalApp/AndroidManifest.xml
index e338c49..f09412e 100644
--- a/android/TerminalApp/AndroidManifest.xml
+++ b/android/TerminalApp/AndroidManifest.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.virtualization.terminal" >
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.virtualization.terminal">
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
@@ -9,9 +10,11 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<uses-feature android:name="android.software.virtualization_framework" android:required="true" />
+
<application
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
+ android:theme="@style/Theme.Material3.DayNight.NoActionBar"
android:usesCleartextTraffic="true">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden|navigation|uiMode|screenLayout|smallestScreenSize"
@@ -21,6 +24,26 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
+ <activity android:name=".SettingsActivity">
+ </activity>
+ <activity android:name=".SettingsDiskResizeActivity">
+ </activity>
+ <activity android:name=".SettingsPortForwardingActivity">
+ </activity>
+ <activity android:name=".SettingsRecoveryActivity">
+ </activity>
+ <property
+ android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
+ android:value="true" />
+ <provider
+ android:name="androidx.startup.InitializationProvider"
+ android:authorities="${applicationId}.androidx-startup"
+ android:exported="false"
+ tools:node="merge">
+ <meta-data
+ android:name="${applicationId}.SplitInitializer"
+ android:value="androidx.startup" />
+ </provider>
<activity-alias
android:name=".MainActivityAlias"
android:targetActivity="com.android.virtualization.terminal.MainActivity"
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index a6723fb..846f975 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -15,9 +15,9 @@
*/
package com.android.virtualization.terminal;
-import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -30,9 +30,14 @@
import android.widget.TextView;
import android.widget.Toast;
+import androidx.appcompat.app.AppCompatActivity;
+
import com.android.virtualization.vmlauncher.VmLauncherServices;
-public class MainActivity extends Activity implements VmLauncherServices.VmLauncherServiceCallback {
+import com.google.android.material.appbar.MaterialToolbar;
+
+public class MainActivity extends AppCompatActivity implements
+ VmLauncherServices.VmLauncherServiceCallback {
private static final String TAG = "VmTerminalApp";
private String mVmIpAddr;
private WebView mWebView;
@@ -44,6 +49,9 @@
VmLauncherServices.startVmLauncherService(this, this);
setContentView(R.layout.activity_headless);
+
+ MaterialToolbar toolbar = (MaterialToolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setDatabaseEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
@@ -101,7 +109,7 @@
}
@Override
- public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.copy_ip_addr) {
// TODO(b/340126051): remove this menu item when port forwarding is supported.
@@ -111,7 +119,12 @@
} else if (id == R.id.stop_vm) {
VmLauncherServices.stopVmLauncherService(this);
return true;
+
+ } else if (id == R.id.menu_item_settings) {
+ Intent intent = new Intent(this, SettingsActivity.class);
+ this.startActivity(intent);
+ return true;
}
- return super.onMenuItemSelected(featureId, item);
+ return super.onOptionsItemSelected(item);
}
}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsActivity.kt
new file mode 100644
index 0000000..dccfea3
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsActivity.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+class SettingsActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.settings_activity)
+
+ val settingsItems = arrayOf(
+ SettingsItem(
+ resources.getString(R.string.settings_disk_resize_title),
+ resources.getString(R.string.settings_disk_resize_sub_title),
+ R.drawable.baseline_storage_24,
+ SettingsItemEnum.DiskResize
+ ),
+ SettingsItem(
+ resources.getString(R.string.settings_port_forwarding_title),
+ resources.getString(R.string.settings_port_forwarding_sub_title),
+ R.drawable.baseline_call_missed_outgoing_24,
+ SettingsItemEnum.PortForwarding
+ ),
+ SettingsItem(
+ resources.getString(R.string.settings_recovery_title),
+ resources.getString(R.string.settings_recovery_sub_title),
+ R.drawable.baseline_settings_backup_restore_24,
+ SettingsItemEnum.Recovery
+ ),
+ )
+ val settingsListItemAdapter = SettingsItemAdapter(settingsItems)
+
+ val recyclerView: RecyclerView = findViewById(R.id.settings_list_recycler_view)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.adapter = settingsListItemAdapter
+ }
+}
\ No newline at end of file
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
new file mode 100644
index 0000000..4be291f
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsDiskResizeActivity.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.Bundle
+import android.widget.TextView
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.isVisible
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.slider.Slider
+
+class SettingsDiskResizeActivity : AppCompatActivity() {
+ private var diskSize: Float = 104F
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.settings_disk_resize)
+ val diskSizeText = findViewById<TextView>(R.id.settings_disk_resize_disk_size)
+ val diskSizeSlider = findViewById<Slider>(R.id.settings_disk_resize_disk_size_slider)
+ val cancelButton = findViewById<MaterialButton>(R.id.settings_disk_resize_cancel_button)
+ val resizeButton = findViewById<MaterialButton>(R.id.settings_disk_resize_resize_button)
+ diskSizeText.text = diskSize.toInt().toString()
+ diskSizeSlider.value = diskSize
+
+ diskSizeSlider.addOnChangeListener { _, value, _ ->
+ diskSizeText.text = value.toInt().toString()
+ cancelButton.isVisible = true
+ resizeButton.isVisible = true
+ }
+ cancelButton.setOnClickListener {
+ diskSizeSlider.value = diskSize
+ cancelButton.isVisible = false
+ resizeButton.isVisible = false
+ }
+
+ resizeButton.setOnClickListener {
+ diskSize = diskSizeSlider.value
+ cancelButton.isVisible = false
+ resizeButton.isVisible = false
+ Toast.makeText(this@SettingsDiskResizeActivity, R.string.settings_disk_resize_resize_message, Toast.LENGTH_SHORT)
+ .show()
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsItem.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsItem.kt
new file mode 100644
index 0000000..e1723a7
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsItem.kt
@@ -0,0 +1,28 @@
+/*
+ * 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
+
+enum class SettingsItemEnum {
+ DiskResize, PortForwarding, Recovery
+}
+
+class SettingsItem(
+ val title: String,
+ val subTitle: String,
+ val icon: Int,
+ val settingsItemEnum: SettingsItemEnum
+) {
+}
\ No newline at end of file
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsItemAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsItemAdapter.kt
new file mode 100644
index 0000000..86f5c92
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsItemAdapter.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.card.MaterialCardView
+
+class SettingsItemAdapter(private val dataSet: Array<SettingsItem>) :
+ RecyclerView.Adapter<SettingsItemAdapter.ViewHolder>() {
+
+ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ val card: MaterialCardView = view.findViewById(R.id.settings_list_item_card)
+ val icon: ImageView = view.findViewById(R.id.settings_list_item_icon)
+ val title: TextView = view.findViewById(R.id.settings_list_item_title)
+ val subTitle: TextView = view.findViewById(R.id.settings_list_item_sub_title)
+ }
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
+ val view = LayoutInflater.from(viewGroup.context)
+ .inflate(R.layout.settings_list_item, viewGroup, false)
+ return ViewHolder(view)
+ }
+
+ override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
+ viewHolder.icon.setImageResource(dataSet[position].icon)
+ viewHolder.title.text = dataSet[position].title
+ viewHolder.subTitle.text = dataSet[position].subTitle
+
+ viewHolder.card.setOnClickListener { view ->
+ val intent = Intent(
+ viewHolder.itemView.context,
+ when (dataSet[position].settingsItemEnum) {
+ SettingsItemEnum.DiskResize -> SettingsDiskResizeActivity::class.java
+ SettingsItemEnum.PortForwarding -> SettingsPortForwardingActivity::class.java
+ SettingsItemEnum.Recovery -> SettingsRecoveryActivity::class.java
+ }
+ )
+ view.context.startActivity(intent)
+ }
+ }
+
+ override fun getItemCount() = dataSet.size
+}
\ No newline at end of file
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
new file mode 100644
index 0000000..6c36cc8
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingActivity.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+class SettingsPortForwardingActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.settings_port_forwarding)
+
+ val settingsPortForwardingItems = arrayOf(
+ SettingsPortForwardingItem(8080, true),
+ SettingsPortForwardingItem(443, false),
+ SettingsPortForwardingItem(80, false)
+ )
+
+ val settingsPortForwardingAdapter =
+ SettingsPortForwardingAdapter(settingsPortForwardingItems)
+
+ val recyclerView: RecyclerView = findViewById(R.id.settings_port_forwarding_recycler_view)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.adapter = settingsPortForwardingAdapter
+ }
+}
\ No newline at end of file
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingAdapter.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingAdapter.kt
new file mode 100644
index 0000000..1fa38e3
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingAdapter.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.materialswitch.MaterialSwitch
+
+class SettingsPortForwardingAdapter(private val dataSet: Array<SettingsPortForwardingItem>) :
+ RecyclerView.Adapter<SettingsPortForwardingAdapter.ViewHolder>() {
+
+ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ val enabledSwitch: MaterialSwitch =
+ view.findViewById(R.id.settings_port_forwarding_item_enabled_switch)
+ val port: TextView = view.findViewById(R.id.settings_port_forwarding_item_port)
+ }
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
+ val view = LayoutInflater.from(viewGroup.context)
+ .inflate(R.layout.settings_port_forwarding_item, viewGroup, false)
+ return ViewHolder(view)
+ }
+
+ override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
+ viewHolder.port.text = dataSet[position].port.toString()
+ viewHolder.enabledSwitch.isChecked = dataSet[position].enabled
+ }
+
+ override fun getItemCount() = dataSet.size
+}
\ No newline at end of file
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingItem.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingItem.kt
new file mode 100644
index 0000000..599e377
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsPortForwardingItem.kt
@@ -0,0 +1,18 @@
+/*
+ * 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
+
+class SettingsPortForwardingItem(val port: Int, val enabled: Boolean) {}
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
new file mode 100644
index 0000000..7256015
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SettingsRecoveryActivity.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.card.MaterialCardView
+
+class SettingsRecoveryActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.settings_recovery)
+ val resetCard = findViewById<MaterialCardView>(R.id.settings_recovery_reset_card)
+ resetCard.setOnClickListener {
+ Toast.makeText(this@SettingsRecoveryActivity, R.string.settings_recovery_reset_message, Toast.LENGTH_SHORT).show()
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/SplitInitializer.kt b/android/TerminalApp/java/com/android/virtualization/terminal/SplitInitializer.kt
new file mode 100644
index 0000000..cb917bd
--- /dev/null
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/SplitInitializer.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.virtualization.terminal
+
+import android.content.Context
+import androidx.startup.Initializer
+import androidx.window.embedding.RuleController
+
+class SplitInitializer : Initializer<RuleController> {
+
+ override fun create(context: Context): RuleController {
+ return RuleController.getInstance(context).apply {
+ setRules(RuleController.parseRules(context, R.xml.main_split_config))
+ }
+ }
+
+ override fun dependencies(): List<Class<out Initializer<*>>> {
+ return emptyList()
+ }
+}
\ No newline at end of file
diff --git a/android/TerminalApp/res/drawable/baseline_call_missed_outgoing_24.xml b/android/TerminalApp/res/drawable/baseline_call_missed_outgoing_24.xml
new file mode 100644
index 0000000..597c317
--- /dev/null
+++ b/android/TerminalApp/res/drawable/baseline_call_missed_outgoing_24.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" 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"/>
+
+</vector>
diff --git a/android/TerminalApp/res/drawable/baseline_settings_backup_restore_24.xml b/android/TerminalApp/res/drawable/baseline_settings_backup_restore_24.xml
new file mode 100644
index 0000000..22b23ba
--- /dev/null
+++ b/android/TerminalApp/res/drawable/baseline_settings_backup_restore_24.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" 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"/>
+
+</vector>
diff --git a/android/TerminalApp/res/drawable/baseline_storage_24.xml b/android/TerminalApp/res/drawable/baseline_storage_24.xml
new file mode 100644
index 0000000..6e52e3f
--- /dev/null
+++ b/android/TerminalApp/res/drawable/baseline_storage_24.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" 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"/>
+
+</vector>
diff --git a/android/TerminalApp/res/layout/activity_headless.xml b/android/TerminalApp/res/layout/activity_headless.xml
index 3fe5271..f786a0f 100644
--- a/android/TerminalApp/res/layout/activity_headless.xml
+++ b/android/TerminalApp/res/layout/activity_headless.xml
@@ -7,6 +7,11 @@
android:orientation="vertical"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
+ <com.google.android.material.appbar.MaterialToolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/ip_addr_textview"
android:layout_width="wrap_content"
diff --git a/android/TerminalApp/res/layout/settings_activity.xml b/android/TerminalApp/res/layout/settings_activity.xml
new file mode 100644
index 0000000..b1acf23
--- /dev/null
+++ b/android/TerminalApp/res/layout/settings_activity.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <com.google.android.material.search.SearchBar
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/settings_list_recycler_view"
+ android:layout_marginHorizontal="16dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</LinearLayout>
\ No newline at end of file
diff --git a/android/TerminalApp/res/layout/settings_disk_resize.xml b/android/TerminalApp/res/layout/settings_disk_resize.xml
new file mode 100644
index 0000000..3c09f52
--- /dev/null
+++ b/android/TerminalApp/res/layout/settings_disk_resize.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="24dp"
+ android:layout_marginTop="24dp"
+ android:fitsSystemWindows="true">
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_disk_resize_title"
+ android:textSize="48sp"
+ android:layout_marginBottom="24dp"/>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/settings_disk_resize_disk_size"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="36sp"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/settings_disk_resize_disk_size_slider"/>
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_disk_resize_resize_gb_assigned"
+ android:textSize="14sp"
+ app:layout_constraintLeft_toRightOf="@+id/settings_disk_resize_disk_size"
+ app:layout_constraintBottom_toTopOf="@+id/settings_disk_resize_disk_size_slider"/>
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_disk_resize_resize_gb_total"
+ android:textSize="14sp"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/settings_disk_resize_disk_size_slider"/>
+
+ <com.google.android.material.slider.Slider
+ android:id="@+id/settings_disk_resize_disk_size_slider"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginBottom="36dp"
+ app:tickVisible="false"
+ android:valueFrom="0"
+ android:valueTo="256"
+ android:stepSize="4"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/settings_disk_resize_cancel_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/settings_disk_resize_resize_cancel"
+ android:visibility="invisible"
+ android:layout_marginHorizontal="8dp"
+ app:layout_constraintTop_toTopOf="@+id/settings_disk_resize_disk_size_slider"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintRight_toLeftOf="@+id/settings_disk_resize_resize_button" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/settings_disk_resize_resize_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/settings_disk_resize_resize_restart_vm_to_apply"
+ android:visibility="invisible"
+ android:layout_marginHorizontal="8dp"
+ app:layout_constraintTop_toTopOf="@+id/settings_disk_resize_disk_size_slider"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintRight_toRightOf="parent" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/android/TerminalApp/res/layout/settings_list_item.xml b/android/TerminalApp/res/layout/settings_list_item.xml
new file mode 100644
index 0000000..89f2d82
--- /dev/null
+++ b/android/TerminalApp/res/layout/settings_list_item.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:gravity="center_vertical"
+ android:layout_height="wrap_content">
+
+ <com.google.android.material.card.MaterialCardView
+ android:id="@+id/settings_list_item_card"
+ app:strokeWidth="0dp"
+ app:cardCornerRadius="28dp"
+ app:checkedIcon="@null"
+ android:focusable="true"
+ android:checkable="true"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="88dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="16dp">
+
+ <com.google.android.material.imageview.ShapeableImageView
+ android:id="@+id/settings_list_item_icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginEnd="24dp"
+ android:scaleType="centerCrop"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent" />
+
+ <TextView
+ android:id="@+id/settings_list_item_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="24dp"
+ android:textSize="20sp"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/settings_list_item_sub_title"
+ app:layout_constraintStart_toEndOf="@id/settings_list_item_icon"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+ <TextView
+ android:id="@+id/settings_list_item_sub_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:layout_marginBottom="20dp"
+ android:layout_marginStart="24dp"
+ app:layout_constraintTop_toBottomOf="@+id/settings_list_item_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/settings_list_item_icon"
+ app:layout_constraintEnd_toEndOf="parent" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </com.google.android.material.card.MaterialCardView>
+</FrameLayout>
\ No newline at end of file
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding.xml b/android/TerminalApp/res/layout/settings_port_forwarding.xml
new file mode 100644
index 0000000..1d68907
--- /dev/null
+++ b/android/TerminalApp/res/layout/settings_port_forwarding.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="24dp"
+ android:layout_marginTop="24dp"
+ android:fitsSystemWindows="true">
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_port_forwarding_title"
+ android:textSize="48sp"
+ android:layout_marginBottom="24dp"/>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/settings_port_forwarding_recycler_view"
+ android:layout_marginHorizontal="16dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</LinearLayout>
\ No newline at end of file
diff --git a/android/TerminalApp/res/layout/settings_port_forwarding_item.xml b/android/TerminalApp/res/layout/settings_port_forwarding_item.xml
new file mode 100644
index 0000000..9e5981e
--- /dev/null
+++ b/android/TerminalApp/res/layout/settings_port_forwarding_item.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintCircleRadius="@dimen/material_emphasis_medium"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <TextView
+ android:id="@+id/settings_port_forwarding_item_port"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"/>
+
+ <com.google.android.material.materialswitch.MaterialSwitch
+ android:id="@+id/settings_port_forwarding_item_enabled_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintRight_toRightOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/android/TerminalApp/res/layout/settings_recovery.xml b/android/TerminalApp/res/layout/settings_recovery.xml
new file mode 100644
index 0000000..e18c8a6
--- /dev/null
+++ b/android/TerminalApp/res/layout/settings_recovery.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_marginEnd="24dp"
+ android:layout_marginTop="24dp"
+ android:fitsSystemWindows="true">
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/settings_recovery_title"
+ android:textSize="48sp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="24dp"/>
+
+ <com.google.android.material.card.MaterialCardView
+ android:id="@+id/settings_recovery_reset_card"
+ app:strokeWidth="0dp"
+ app:cardCornerRadius="0dp"
+ app:checkedIcon="@null"
+ android:focusable="true"
+ android:checkable="true"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="88dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginStart="24dp">
+
+ <TextView
+ android:id="@+id/settings_recovery_reset_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="24dp"
+ android:textSize="20sp"
+ android:text="@string/settings_recovery_reset_title"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/settings_recovery_reset_sub_title"
+ app:layout_constraintLeft_toLeftOf="parent" />
+
+ <TextView
+ android:id="@+id/settings_recovery_reset_sub_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:layout_marginBottom="20dp"
+ android:layout_marginStart="24dp"
+ android:text="@string/settings_recovery_reset_sub_title"
+ app:layout_constraintTop_toBottomOf="@+id/settings_recovery_reset_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent" />
+ </androidx.constraintlayout.widget.ConstraintLayout>
+ </com.google.android.material.card.MaterialCardView>
+</LinearLayout>
\ No newline at end of file
diff --git a/android/TerminalApp/res/menu/main_menu.xml b/android/TerminalApp/res/menu/main_menu.xml
index cc34cda..9c83923 100644
--- a/android/TerminalApp/res/menu/main_menu.xml
+++ b/android/TerminalApp/res/menu/main_menu.xml
@@ -4,4 +4,6 @@
android:title="Copy the IP address"/>
<item android:id="@+id/stop_vm"
android:title="Stop the existing VM instance"/>
+ <item android:id="@+id/menu_item_settings"
+ android:title="Settings"/>
</menu>
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/dimens.xml b/android/TerminalApp/res/values/dimens.xml
new file mode 100644
index 0000000..e6ed461
--- /dev/null
+++ b/android/TerminalApp/res/values/dimens.xml
@@ -0,0 +1,3 @@
+<resources>
+ <dimen name="activity_split_ratio">0.3</dimen>
+</resources>
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/integers.xml b/android/TerminalApp/res/values/integers.xml
new file mode 100644
index 0000000..0c7d2b9
--- /dev/null
+++ b/android/TerminalApp/res/values/integers.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="split_min_width">720</integer>
+</resources>
\ No newline at end of file
diff --git a/android/TerminalApp/res/values/strings.xml b/android/TerminalApp/res/values/strings.xml
index 79da7cd..c3a3348 100644
--- a/android/TerminalApp/res/values/strings.xml
+++ b/android/TerminalApp/res/values/strings.xml
@@ -20,4 +20,21 @@
<string name="vm_creation_message">Virtual machine is booting. Please wait.</string>
<string name="vm_stop_message">Virtual machine is stopped. Exiting.</string>
<string name="vm_error_message">Virtual machine crashed. Exiting.</string>
+
+ <string name="settings_disk_resize_title">Disk Resize</string>
+ <string name="settings_disk_resize_sub_title">Resize / Rootfs</string>
+ <string name="settings_disk_resize_resize_message">Disk size set</string>
+ <string name="settings_disk_resize_resize_gb_assigned">GB Assigned</string>
+ <string name="settings_disk_resize_resize_gb_total">256 GB total</string>
+ <string name="settings_disk_resize_resize_cancel">Cancel</string>
+ <string name="settings_disk_resize_resize_restart_vm_to_apply">Restart VM to apply</string>
+
+ <string name="settings_port_forwarding_title">Port Forwarding</string>
+ <string name="settings_port_forwarding_sub_title">Configure port forwarding</string>
+
+ <string name="settings_recovery_title">Recovery</string>
+ <string name="settings_recovery_sub_title">Partition Recovery options</string>
+ <string name="settings_recovery_reset_title">Change to Initial version</string>
+ <string name="settings_recovery_reset_sub_title">Remove all</string>
+ <string name="settings_recovery_reset_message">VM reset</string>
</resources>
diff --git a/android/TerminalApp/res/xml/main_split_config.xml b/android/TerminalApp/res/xml/main_split_config.xml
new file mode 100644
index 0000000..f51e7ea
--- /dev/null
+++ b/android/TerminalApp/res/xml/main_split_config.xml
@@ -0,0 +1,37 @@
+<resources xmlns:window="http://schemas.android.com/apk/res-auto">
+
+ <!-- Define a split for the named activities. -->
+ <ActivityRule window:alwaysExpand="true">
+ <ActivityFilter window:activityName=".MainActivity" />
+ </ActivityRule>
+
+ <SplitPairRule
+ window:clearTop="true"
+ window:finishPrimaryWithSecondary="adjacent"
+ window:finishSecondaryWithPrimary="always"
+ window:splitLayoutDirection="locale"
+ window:splitMaxAspectRatioInPortrait="alwaysAllow"
+ window:splitMinWidthDp="@integer/split_min_width"
+ window:splitRatio="@dimen/activity_split_ratio">
+ <SplitPairFilter
+ window:primaryActivityName="com.android.virtualization.terminal.SettingsActivity"
+ window:secondaryActivityName="com.android.virtualization.terminal.SettingsDiskResizeActivity" />
+ <SplitPairFilter
+ window:primaryActivityName="com.android.virtualization.terminal.SettingsActivity"
+ window:secondaryActivityName="com.android.virtualization.terminal.SettingsPortForwardingActivity" />
+ <SplitPairFilter
+ window:primaryActivityName="com.android.virtualization.terminal.SettingsActivity"
+ window:secondaryActivityName="com.android.virtualization.terminal.SettingsRecoveryActivity" />
+ </SplitPairRule>
+
+ <SplitPlaceholderRule
+ window:placeholderActivityName="com.android.virtualization.terminal.SettingsDiskResizeActivity"
+ window:splitLayoutDirection="locale"
+ window:splitMaxAspectRatioInPortrait="alwaysAllow"
+ window:splitMinWidthDp="@integer/split_min_width"
+ window:splitRatio="@dimen/activity_split_ratio">
+ window:stickyPlaceholder="false">
+ <ActivityFilter
+ window:activityName="com.android.virtualization.terminal.SettingsActivity"/>
+ </SplitPlaceholderRule>
+</resources>
\ No newline at end of file
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 87fb611..23652d2 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -33,7 +33,7 @@
CpuTopology::CpuTopology,
DiskImage::DiskImage,
InputDevice::InputDevice,
- IVirtualMachine::{BnVirtualMachine, IVirtualMachine},
+ IVirtualMachine::{self, BnVirtualMachine},
IVirtualMachineCallback::IVirtualMachineCallback,
IVirtualizationService::IVirtualizationService,
Partition::Partition,
@@ -62,9 +62,8 @@
use apkverify::{HashAlgorithm, V4Signature};
use avflog::LogResult;
use binder::{
- self, wait_for_interface, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor,
- Status, StatusCode, Strong,
- IntoBinderResult,
+ self, wait_for_interface, Accessor, BinderFeatures, ConnectionInfo, ExceptionCode, Interface, ParcelFileDescriptor,
+ SpIBinder, Status, StatusCode, Strong, IntoBinderResult,
};
use cstr::cstr;
use glob::glob;
@@ -90,7 +89,7 @@
use std::sync::{Arc, Mutex, Weak, LazyLock};
use vbmeta::VbMetaImage;
use vmconfig::{VmConfig, get_debug_level};
-use vsock::VsockStream;
+use vsock::{VsockAddr, VsockStream};
use zip::ZipArchive;
/// The unique ID of a VM used (together with a port number) for vsock communication.
@@ -98,6 +97,9 @@
pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservice";
+/// Vsock privileged ports are below this number.
+const VSOCK_PRIV_PORT_MAX: u32 = 1024;
+
/// The size of zero.img.
/// Gaps in composite disk images are filled with a shared zero.img.
const ZERO_FILLER_SIZE: u64 = 4096;
@@ -221,7 +223,8 @@
console_out_fd: Option<&ParcelFileDescriptor>,
console_in_fd: Option<&ParcelFileDescriptor>,
log_fd: Option<&ParcelFileDescriptor>,
- ) -> binder::Result<Strong<dyn IVirtualMachine>> {
+ dump_dt_fd: Option<&ParcelFileDescriptor>,
+ ) -> binder::Result<Strong<dyn IVirtualMachine::IVirtualMachine>> {
let mut is_protected = false;
let ret = self.create_vm_internal(
config,
@@ -229,6 +232,7 @@
console_in_fd,
log_fd,
&mut is_protected,
+ dump_dt_fd,
);
write_vm_creation_stats(config, is_protected, &ret);
ret
@@ -485,7 +489,8 @@
console_in_fd: Option<&ParcelFileDescriptor>,
log_fd: Option<&ParcelFileDescriptor>,
is_protected: &mut bool,
- ) -> binder::Result<Strong<dyn IVirtualMachine>> {
+ dump_dt_fd: Option<&ParcelFileDescriptor>,
+ ) -> binder::Result<Strong<dyn IVirtualMachine::IVirtualMachine>> {
let requester_uid = get_calling_uid();
let requester_debug_pid = get_calling_pid();
@@ -527,6 +532,7 @@
clone_or_prepare_logger_fd(console_out_fd, format!("Console({})", cid))?;
let console_in_fd = console_in_fd.map(clone_file).transpose()?;
let log_fd = clone_or_prepare_logger_fd(log_fd, format!("Log({})", cid))?;
+ let dump_dt_fd = dump_dt_fd.map(clone_file).transpose()?;
// Counter to generate unique IDs for temporary image files.
let mut next_temporary_image_id = 0;
@@ -744,6 +750,7 @@
audio_config,
no_balloon: config.noBalloon,
usb_config,
+ dump_dt_fd,
};
let instance = Arc::new(
VmInstance::new(
@@ -1326,14 +1333,14 @@
}
impl VirtualMachine {
- fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
+ fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine::IVirtualMachine> {
BnVirtualMachine::new_binder(VirtualMachine { instance }, BinderFeatures::default())
}
}
impl Interface for VirtualMachine {}
-impl IVirtualMachine for VirtualMachine {
+impl IVirtualMachine::IVirtualMachine for VirtualMachine {
fn getCid(&self) -> binder::Result<i32> {
// Don't check permission. The owner of the VM might have passed this binder object to
// others.
@@ -1394,19 +1401,48 @@
fn connectVsock(&self, port: i32) -> binder::Result<ParcelFileDescriptor> {
if !matches!(&*self.instance.vm_state.lock().unwrap(), VmState::Running { .. }) {
- return Err(anyhow!("VM is not running")).or_service_specific_exception(-1);
+ return Err(Status::new_service_specific_error_str(
+ IVirtualMachine::ERROR_UNEXPECTED,
+ Some("Virtual Machine is not running"),
+ ));
}
let port = port as u32;
- if port < 1024 {
- return Err(anyhow!("Can't connect to privileged port {port}"))
- .or_service_specific_exception(-1);
+ if port < VSOCK_PRIV_PORT_MAX {
+ return Err(Status::new_service_specific_error_str(
+ IVirtualMachine::ERROR_UNEXPECTED,
+ Some("Can't connect to privileged port {port}"),
+ ));
}
let stream = VsockStream::connect_with_cid_port(self.instance.cid, port)
.context("Failed to connect")
- .or_service_specific_exception(-1)?;
+ .or_service_specific_exception(IVirtualMachine::ERROR_UNEXPECTED)?;
Ok(vsock_stream_to_pfd(stream))
}
+ fn createAccessorBinder(&self, name: &str, port: i32) -> binder::Result<SpIBinder> {
+ if !matches!(&*self.instance.vm_state.lock().unwrap(), VmState::Running { .. }) {
+ return Err(Status::new_service_specific_error_str(
+ IVirtualMachine::ERROR_UNEXPECTED,
+ Some("Virtual Machine is not running"),
+ ));
+ }
+ let port = port as u32;
+ if port < VSOCK_PRIV_PORT_MAX {
+ return Err(Status::new_service_specific_error_str(
+ IVirtualMachine::ERROR_UNEXPECTED,
+ Some("Can't connect to privileged port {port}"),
+ ));
+ }
+ let cid = self.instance.cid;
+ let get_connection_info =
+ move |_instance: &str| Some(ConnectionInfo::Vsock(VsockAddr::new(cid, port)));
+ let accessor = Accessor::new(name, get_connection_info);
+ accessor
+ .as_binder()
+ .context("The newly created Accessor should always have a binder")
+ .or_service_specific_exception(IVirtualMachine::ERROR_UNEXPECTED)
+ }
+
fn setHostConsoleName(&self, ptsname: &str) -> binder::Result<()> {
self.instance.vm_context.global_context.setHostConsoleName(ptsname)
}
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index b2be736..25271f8 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -135,6 +135,7 @@
pub audio_config: Option<AudioConfig>,
pub no_balloon: bool,
pub usb_config: UsbConfig,
+ pub dump_dt_fd: Option<File>,
}
#[derive(Debug)]
@@ -985,6 +986,11 @@
// Keep track of what file descriptors should be mapped to the crosvm process.
let mut preserved_fds = config.indirect_files.into_iter().map(|f| f.into()).collect();
+ if let Some(dump_dt_fd) = config.dump_dt_fd {
+ let dump_dt_fd = add_preserved_fd(&mut preserved_fds, dump_dt_fd);
+ command.arg("--dump-device-tree-blob").arg(dump_dt_fd);
+ }
+
// Setup the serial devices.
// 1. uart device: used as the output device by bootloaders and as early console by linux
// 2. uart device: used to report the reason for the VM failing.
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
index afa25e2..e52222a 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachine.aidl
@@ -19,6 +19,13 @@
import android.system.virtualizationservice.VirtualMachineState;
interface IVirtualMachine {
+ /**
+ * Encountered an unexpected error. This is an implementation detail and the client
+ * can do nothing about it.
+ * This is used as a Service Specific Exception.
+ */
+ const int ERROR_UNEXPECTED = -1;
+
/** Get the CID allocated to the VM. */
int getCid();
@@ -48,6 +55,19 @@
/** Open a vsock connection to the CID of the VM on the given port. */
ParcelFileDescriptor connectVsock(int port);
+ /**
+ * Create an Accessor in libbinder that will open a vsock connection
+ * to the CID of the VM on the given port.
+ *
+ * \param instance name of the service that the accessor is responsible for.
+ * This is the same instance that we expect clients to use when trying
+ * to get the service with the ServiceManager APIs.
+ *
+ * \return IBinder of the IAccessor on success, or throws a service specific exception
+ * on error. See the ERROR_* values above.
+ */
+ IBinder createAccessorBinder(String instance, int port);
+
/** Set the name of the peer end (ptsname) of the host console. */
void setHostConsoleName(in @utf8InCpp String pathname);
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
index 234d8d0..0c3f6b7 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualizationService.aidl
@@ -35,11 +35,14 @@
* `consoleInFd` is provided then console input to the VM will be read from it. If `osLogFd` is
* provided then the OS-level logs will be sent to it. `osLogFd` is supported only when the OS
* running in the VM has the logging system. In case of Microdroid, the logging system is logd.
+ * `dumpDtFd` is the file where to dump the VM's device tree. It is only used in
+ * debugging/testing.
*/
IVirtualMachine createVm(in VirtualMachineConfig config,
in @nullable ParcelFileDescriptor consoleOutFd,
in @nullable ParcelFileDescriptor consoleInFd,
- in @nullable ParcelFileDescriptor osLogFd);
+ in @nullable ParcelFileDescriptor osLogFd,
+ in @nullable ParcelFileDescriptor dumpDtFd);
/**
* Allocate an instance_id to the (newly created) VM.
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index 609bbdf..81ca8fa 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -114,6 +114,10 @@
#[cfg(debuggable_vms_improvements)]
#[arg(long)]
enable_earlycon: bool,
+
+ /// Path to file to dump VM device tree.
+ #[arg(long)]
+ dump_device_tree: Option<PathBuf>,
}
impl DebugConfig {
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index 823546f..0e1f4cc 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -203,6 +203,7 @@
config.debug.console.as_ref().map(|p| p.as_ref()),
config.debug.console_in.as_ref().map(|p| p.as_ref()),
config.debug.log.as_ref().map(|p| p.as_ref()),
+ config.debug.dump_device_tree.as_ref().map(|p| p.as_ref()),
)
}
@@ -284,6 +285,7 @@
config.debug.console.as_ref().map(|p| p.as_ref()),
config.debug.console_in.as_ref().map(|p| p.as_ref()),
config.debug.log.as_ref().map(|p| p.as_ref()),
+ config.debug.dump_device_tree.as_ref().map(|p| p.as_ref()),
)
}
@@ -306,6 +308,7 @@
console_out_path: Option<&Path>,
console_in_path: Option<&Path>,
log_path: Option<&Path>,
+ dump_device_tree: Option<&Path>,
) -> Result<(), Error> {
let console_out = if let Some(console_out_path) = console_out_path {
Some(File::create(console_out_path).with_context(|| {
@@ -330,9 +333,17 @@
} else {
Some(duplicate_fd(io::stdout())?)
};
+ let dump_dt = if let Some(dump_device_tree) = dump_device_tree {
+ Some(File::create(dump_device_tree).with_context(|| {
+ format!("Failed to open file to dump device tree: {:?}", dump_device_tree)
+ })?)
+ } else {
+ None
+ };
let callback = Box::new(Callback {});
- let vm = VmInstance::create(service, config, console_out, console_in, log, Some(callback))
- .context("Failed to create VM")?;
+ let vm =
+ VmInstance::create(service, config, console_out, console_in, log, dump_dt, Some(callback))
+ .context("Failed to create VM")?;
vm.start().context("Failed to start VM")?;
let debug_level = get_debug_level(config).unwrap_or(DebugLevel::NONE);
diff --git a/android/vm_demo_native/main.cpp b/android/vm_demo_native/main.cpp
index bc42036..d7ff02e 100644
--- a/android/vm_demo_native/main.cpp
+++ b/android/vm_demo_native/main.cpp
@@ -226,8 +226,10 @@
ScopedFileDescriptor console_out_fd(fcntl(fileno(stdout), F_DUPFD_CLOEXEC));
ScopedFileDescriptor console_in_fd(fcntl(fileno(stdin), F_DUPFD_CLOEXEC));
ScopedFileDescriptor log_fd(fcntl(fileno(stdout), F_DUPFD_CLOEXEC));
+ ScopedFileDescriptor dump_dt_fd(-1);
- ScopedAStatus ret = service.createVm(config, console_out_fd, console_in_fd, log_fd, &vm);
+ ScopedAStatus ret =
+ service.createVm(config, console_out_fd, console_in_fd, log_fd, dump_dt_fd, &vm);
if (!ret.isOk()) {
return Error() << "Failed to create VM";
}
diff --git a/build/debian/build.sh b/build/debian/build.sh
index c50e5e5..0d13019 100755
--- a/build/debian/build.sh
+++ b/build/debian/build.sh
@@ -2,15 +2,15 @@
# This is a script to build a Debian image that can run in a VM created via AVF.
# TODOs:
-# - Support x86_64 architecture
# - Add Android-specific packages via a new class
# - Use a stable release from debian-cloud-images
show_help() {
- echo Usage: $0 [OPTION]... [FILE]
- echo Builds a debian image and save it to FILE.
- echo Options:
- echo -h Pring usage and this help message and exit.
+ echo "Usage: sudo $0 [OPTION]... [FILE]"
+ echo "Builds a debian image and save it to FILE. [sudo is required]"
+ echo "Options:"
+ echo "-h Print usage and this help message and exit."
+ echo "-a ARCH Architecture of the image [default is aarch64]"
}
check_sudo() {
@@ -21,104 +21,118 @@
}
parse_options() {
- while getopts ":h" option; do
+ while getopts "ha:" option; do
case ${option} in
h)
show_help
exit;;
+ a)
+ if [[ "$OPTARG" != "aarch64" && "$OPTARG" != "x86_64" ]]; then
+ echo "Invalid architecture: $OPTARG"
+ exit
+ fi
+ arch="$OPTARG"
+ if [[ "$arch" == "x86_64" ]]; then
+ debian_arch="amd64"
+ fi
+ ;;
+ *)
+ echo "Invalid option: $OPTARG"
+ exit
+ ;;
esac
done
- if [ -n "$1" ]; then
- built_image=$1
+ if [[ "${*:$OPTIND:1}" ]]; then
+ built_image="${*:$OPTIND:1}"
fi
}
install_prerequisites() {
apt update
+ packages=(
+ binfmt-support
+ build-essential
+ ca-certificates
+ curl
+ debsums
+ dosfstools
+ fai-server
+ fai-setup-storage
+ fdisk
+ make
+ python3
+ python3-libcloud
+ python3-marshmallow
+ python3-pytest
+ python3-yaml
+ qemu-user-static
+ qemu-utils
+ sudo
+ udev
+ )
+ if [[ "$arch" == "aarch64" ]]; then
+ packages+=(
+ gcc-aarch64-linux-gnu
+ libc6-dev-arm64-cross
+ qemu-system-arm
+ )
+ else
+ packages+=(
+ qemu-system
+ )
+ fi
DEBIAN_FRONTEND=noninteractive \
- apt install --no-install-recommends --assume-yes \
- binfmt-support \
- build-essential \
- ca-certificates \
- curl \
- debsums \
- dosfstools \
- fai-server \
- fai-setup-storage \
- fdisk \
- gcc-aarch64-linux-gnu \
- libc6-dev-arm64-cross \
- make \
- python3 \
- python3-libcloud \
- python3-marshmallow \
- python3-pytest \
- python3-yaml \
- qemu-system-arm \
- qemu-user-static \
- qemu-utils \
- sudo \
- udev \
+ apt install --no-install-recommends --assume-yes "${packages[@]}"
-
- if [ ! -f $HOME/.cargo/bin/cargo ]; then
+ if [ ! -f $"HOME"/.cargo/bin/cargo ]; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
fi
- source $HOME/.cargo/env
- rustup target add aarch64-unknown-linux-gnu
-
- sed -i s/losetup\ -f/losetup\ -P\ -f/g /usr/sbin/fai-diskimage
- sed -i 's/wget \$/wget -t 0 \$/g' /usr/share/debootstrap/functions
-
- apt install --no-install-recommends --assume-yes curl
- # just for testing
- echo libseccomp: $(curl -is https://deb.debian.org/debian/pool/main/libs/libseccomp/libseccomp2_2.5.4-1+deb12u1_arm64.deb | head -n 1)
- echo libsemanage-common: $(curl -is https://deb.debian.org/debian/pool/main/libs/libsemanage/libsemanage-common_3.4-1_all.deb | head -n 1)
- echo libpcre2: $(curl -is https://deb.debian.org/debian/pool/main/p/pcre2/libpcre2-8-0_10.42-1_arm64.deb | head -n 1)
+ source "$HOME"/.cargo/env
+ rustup target add "${arch}"-unknown-linux-gnu
}
download_debian_cloud_image() {
local ver=master
local prj=debian-cloud-images
- local url=https://salsa.debian.org/cloud-team/${prj}/-/archive/${ver}/${prj}-${ver}.tar.gz
- local outdir=${debian_cloud_image}
+ local url="https://salsa.debian.org/cloud-team/${prj}/-/archive/${ver}/${prj}-${ver}.tar.gz"
+ local outdir="${debian_cloud_image}"
- mkdir -p ${outdir}
- wget -O - ${url} | tar xz -C ${outdir} --strip-components=1
+ mkdir -p "${outdir}"
+ wget -O - "${url}" | tar xz -C "${outdir}" --strip-components=1
}
copy_android_config() {
- local src=$(dirname $0)/fai_config
- local dst=${config_space}
+ local src="$(dirname "$0")/fai_config"
+ local dst="${config_space}"
- cp -R ${src}/* ${dst}
- cp $(dirname $0)/image.yaml ${resources_dir}
+ cp -R "${src}"/* "${dst}"
+ cp "$(dirname "$0")/image.yaml" "${resources_dir}"
local ttyd_version=1.7.7
- local url=https://github.com/tsl0922/ttyd/releases/download/${ttyd_version}/ttyd.aarch64
- mkdir -p ${dst}/files/usr/local/bin/ttyd
- wget ${url} -O ${dst}/files/usr/local/bin/ttyd/AVF
- chmod 777 ${dst}/files/usr/local/bin/ttyd/AVF
+ local url="https://github.com/tsl0922/ttyd/releases/download/${ttyd_version}/ttyd.${arch}"
+ mkdir -p "${dst}/files/usr/local/bin/ttyd"
+ wget "${url}" -O "${dst}/files/usr/local/bin/ttyd/AVF"
+ chmod 777 "${dst}/files/usr/local/bin/ttyd/AVF"
- pushd $(dirname $0)/forwarder_guest > /dev/null
- RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc" cargo build \
- --target aarch64-unknown-linux-gnu \
- --target-dir ${workdir}/forwarder_guest
- mkdir -p ${dst}/files/usr/local/bin/forwarder_guest
- cp ${workdir}/forwarder_guest/aarch64-unknown-linux-gnu/debug/forwarder_guest ${dst}/files/usr/local/bin/forwarder_guest/AVF
- chmod 777 ${dst}/files/usr/local/bin/forwarder_guest/AVF
+ pushd "$(dirname "$0")/forwarder_guest" > /dev/null
+ RUSTFLAGS="-C linker=${arch}-linux-gnu-gcc" cargo build \
+ --target "${arch}-unknown-linux-gnu" \
+ --target-dir "${workdir}/forwarder_guest"
+ mkdir -p "${dst}/files/usr/local/bin/forwarder_guest"
+ cp "${workdir}/forwarder_guest/${arch}-unknown-linux-gnu/debug/forwarder_guest" "${dst}/files/usr/local/bin/forwarder_guest/AVF"
+ chmod 777 "${dst}/files/usr/local/bin/forwarder_guest/AVF"
popd > /dev/null
}
run_fai() {
- local out=${built_image}
- make -C ${debian_cloud_image} image_bookworm_nocloud_arm64
- mv ${debian_cloud_image}/image_bookworm_nocloud_arm64.raw ${out}
+ local out="${built_image}"
+ make -C "${debian_cloud_image}" "image_bookworm_nocloud_${debian_arch}"
+ mv "${debian_cloud_image}/image_bookworm_nocloud_${debian_arch}.raw" "${out}"
}
clean_up() {
- rm -rf ${workdir}
+ rm -rf "${workdir}"
}
set -e
@@ -130,8 +144,10 @@
debian_version=bookworm
config_space=${debian_cloud_image}/config_space/${debian_version}
resources_dir=${debian_cloud_image}/src/debian_cloud_images/resources
+arch=aarch64
+debian_arch=arm64
+parse_options "$@"
check_sudo
-parse_options $@
install_prerequisites
download_debian_cloud_image
copy_android_config
diff --git a/build/debian/build_in_container.sh b/build/debian/build_in_container.sh
index 6bc366b..fd1a975 100755
--- a/build/debian/build_in_container.sh
+++ b/build/debian/build_in_container.sh
@@ -1,5 +1,24 @@
#!/bin/bash
-if [ -z $ANDROID_BUILD_TOP ]; then echo "forgot to source build/envsetup.sh?" && exit 1; fi
+if [ -z "$ANDROID_BUILD_TOP" ]; then echo "forgot to source build/envsetup.sh?" && exit 1; fi
-docker run --privileged -it -v $ANDROID_BUILD_TOP/packages/modules/Virtualization:/root/Virtualization -v /dev:/dev ubuntu:22.04 /root/Virtualization/build/debian/build.sh
+arch=aarch64
+while getopts "a:" option; do
+ case ${option} in
+ a)
+ if [[ "$OPTARG" != "aarch64" && "$OPTARG" != "x86_64" ]]; then
+ echo "Invalid architecture: $OPTARG"
+ exit
+ fi
+ arch="$OPTARG"
+ ;;
+ *)
+ echo "Invalid option: $OPTARG"
+ exit
+ ;;
+ esac
+done
+
+docker run --privileged -it --workdir /root/Virtualization/build/debian -v \
+ "$ANDROID_BUILD_TOP/packages/modules/Virtualization:/root/Virtualization" -v \
+ /dev:/dev ubuntu:22.04 /root/Virtualization/build/debian/build.sh -a "$arch"
diff --git a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
index f71557d..6b932e9 100644
--- a/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
+++ b/build/debian/fai_config/files/etc/systemd/system/ttyd.service/AVF
@@ -3,7 +3,7 @@
After=syslog.target
After=network.target
[Service]
-ExecStart=/usr/local/bin/ttyd -W screen -aAxR -S main login
+ExecStart=/usr/local/bin/ttyd -W screen -aAxR -S main login -f droid
Type=simple
Restart=always
User=root
diff --git a/build/debian/fai_config/scripts/AVF/20-useradd b/build/debian/fai_config/scripts/AVF/20-useradd
new file mode 100755
index 0000000..9fbcd43
--- /dev/null
+++ b/build/debian/fai_config/scripts/AVF/20-useradd
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+$ROOTCMD useradd -m -u 1000 -N -G sudo droid
+$ROOTCMD echo 'droid ALL=(ALL) NOPASSWD:ALL' >> $target/etc/sudoers
\ No newline at end of file
diff --git a/guest/rialto/tests/test.rs b/guest/rialto/tests/test.rs
index 582b69e..7ec5647 100644
--- a/guest/rialto/tests/test.rs
+++ b/guest/rialto/tests/test.rs
@@ -335,6 +335,14 @@
let virtmgr = vmclient::VirtualizationService::new().context("Failed to spawn VirtMgr")?;
let service = virtmgr.connect().context("Failed to connect to VirtMgr")?;
info!("Connected to VirtMgr for service VM");
- VmInstance::create(service.as_ref(), &config, console, /* consoleIn */ None, log, None)
- .context("Failed to create VM")
+ VmInstance::create(
+ service.as_ref(),
+ &config,
+ console,
+ /* consoleIn */ None,
+ log,
+ /* dump_dt */ None,
+ None,
+ )
+ .context("Failed to create VM")
}
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java
index 3b16a8a..b278610 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachine.java
@@ -1578,7 +1578,8 @@
: createVirtualMachineConfigForAppFrom(vmConfig, service);
mVirtualMachine =
- service.createVm(vmConfigParcel, consoleOutFd, consoleInFd, mLogWriter);
+ service.createVm(
+ vmConfigParcel, consoleOutFd, consoleInFd, mLogWriter, null);
mVirtualMachine.registerCallback(new CallbackTranslator(service));
if (mMemoryManagementCallbacks != null) {
mContext.registerComponentCallbacks(mMemoryManagementCallbacks);
diff --git a/libs/libcompos_common/compos_client.rs b/libs/libcompos_common/compos_client.rs
index 107f8d0..316eaa9 100644
--- a/libs/libcompos_common/compos_client.rs
+++ b/libs/libcompos_common/compos_client.rs
@@ -152,6 +152,7 @@
console_fd,
/* console_in_fd */ None,
log_fd,
+ /* dump_dt */ None,
Some(callback),
)
.context("Failed to create VM")?;
diff --git a/libs/libservice_vm_manager/src/lib.rs b/libs/libservice_vm_manager/src/lib.rs
index d7b4dd6..0f322bb 100644
--- a/libs/libservice_vm_manager/src/lib.rs
+++ b/libs/libservice_vm_manager/src/lib.rs
@@ -244,8 +244,9 @@
let console_out = Some(android_log_fd()?);
let console_in = None;
let log = Some(android_log_fd()?);
+ let dump_dt = None;
let callback = None;
- VmInstance::create(service.as_ref(), &config, console_out, console_in, log, callback)
+ VmInstance::create(service.as_ref(), &config, console_out, console_in, log, dump_dt, callback)
.context("Failed to create service VM")
}
diff --git a/libs/libvmclient/src/lib.rs b/libs/libvmclient/src/lib.rs
index ce7d5a5..13630c0 100644
--- a/libs/libvmclient/src/lib.rs
+++ b/libs/libvmclient/src/lib.rs
@@ -208,14 +208,21 @@
console_out: Option<File>,
console_in: Option<File>,
log: Option<File>,
+ dump_dt: Option<File>,
callback: Option<Box<dyn VmCallback + Send + Sync>>,
) -> BinderResult<Self> {
let console_out = console_out.map(ParcelFileDescriptor::new);
let console_in = console_in.map(ParcelFileDescriptor::new);
let log = log.map(ParcelFileDescriptor::new);
+ let dump_dt = dump_dt.map(ParcelFileDescriptor::new);
- let vm =
- service.createVm(config, console_out.as_ref(), console_in.as_ref(), log.as_ref())?;
+ let vm = service.createVm(
+ config,
+ console_out.as_ref(),
+ console_in.as_ref(),
+ log.as_ref(),
+ dump_dt.as_ref(),
+ )?;
let cid = vm.getCid()?;
diff --git a/microfuchsia/microfuchsiad/src/instance_starter.rs b/microfuchsia/microfuchsiad/src/instance_starter.rs
index 15fcc06..61a024f 100644
--- a/microfuchsia/microfuchsiad/src/instance_starter.rs
+++ b/microfuchsia/microfuchsiad/src/instance_starter.rs
@@ -90,6 +90,7 @@
console_out,
console_in,
/* log= */ None,
+ /* dump_dt= */ None,
None,
)
.context("Failed to create VM")?;
diff --git a/tests/vm_accessor/README.md b/tests/vm_accessor/README.md
index c85cf3c..8b0eb2a 100644
--- a/tests/vm_accessor/README.md
+++ b/tests/vm_accessor/README.md
@@ -1,15 +1,16 @@
# Demo for serving a service in a VM
You can implement a service in a VM, and let client in the Android can use it
-as if it's in the Android. To do so, implement IAccessor.
+as if it's in the Android. To do so, use libbinder's IAccessor.
-IAccessor allows AIDL service in a VM can be accessed via servicemanager.
-To do so, VM owners should also provide IAccessor implementation. servicemanager
-will connect to the IAccessor and get the binder of the service in a VM with it.
+IAccessor allows AIDL service in a VM to be accessed via servicemanager.
+To do so, VM owners should also provide IAccessor through libbinder's service
+manager APIs. servicemanager will connect to the IAccessor and get the binder
+of the service in a VM with it.
com.android.virt.accessor_demo apex contains the minimum setup for IAccessor as
follows:
- - accessor_demo: Sample implementation of IAccessor, which is expected to
+ - accessor_demo: Sample implementation using IAccessor, which is expected to
launch VM and returns the Vsock connection of service in the VM.
- AccessorVmApp: Sample app that conatins VM payload. Provides the actual
implementation of service in a VM.
diff --git a/tests/vm_accessor/accessor/Android.bp b/tests/vm_accessor/accessor/Android.bp
index 7c0ee6d..8055f91 100644
--- a/tests/vm_accessor/accessor/Android.bp
+++ b/tests/vm_accessor/accessor/Android.bp
@@ -14,7 +14,6 @@
],
rustlibs: [
"android.system.virtualizationservice-rust",
- "android.os.accessor-rust",
"libanyhow",
"libandroid_logger",
"libbinder_rs",
diff --git a/tests/vm_accessor/accessor/src/accessor.rs b/tests/vm_accessor/accessor/src/accessor.rs
deleted file mode 100644
index 966bffb..0000000
--- a/tests/vm_accessor/accessor/src/accessor.rs
+++ /dev/null
@@ -1,56 +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.
-
-//! IAcessor implementation.
-//! TODO: Keep this in proper places, so other pVMs can use this.
-//! TODO: Allows to customize VMs for launching. (e.g. port, ...)
-
-use android_os_accessor::aidl::android::os::IAccessor::IAccessor;
-use binder::{self, Interface, ParcelFileDescriptor};
-use log::info;
-use std::time::Duration;
-use vmclient::VmInstance;
-
-// Note: Do not use LazyServiceGuard here, to make this service and VM are quit
-// when nobody references it.
-// TODO(b/353492849): Do not use IAccessor directly.
-#[derive(Debug)]
-pub struct Accessor {
- // Note: we can't simply keep reference by specifying lifetime to Accessor,
- // because 'trait Interface' requires 'static.
- vm: VmInstance,
- port: i32,
- instance: String,
-}
-
-impl Accessor {
- pub fn new(vm: VmInstance, port: i32, instance: &str) -> Self {
- Self { vm, port, instance: instance.into() }
- }
-}
-
-impl Interface for Accessor {}
-
-impl IAccessor for Accessor {
- fn addConnection(&self) -> binder::Result<ParcelFileDescriptor> {
- self.vm.wait_until_ready(Duration::from_secs(20)).unwrap();
-
- info!("VM is ready. Connecting to service via port {}", self.port);
-
- self.vm.vm.connectVsock(self.port)
- }
- fn getInstanceName(&self) -> binder::Result<String> {
- Ok(self.instance.clone())
- }
-}
diff --git a/tests/vm_accessor/accessor/src/main.rs b/tests/vm_accessor/accessor/src/main.rs
index 49f5794..db53d8e 100644
--- a/tests/vm_accessor/accessor/src/main.rs
+++ b/tests/vm_accessor/accessor/src/main.rs
@@ -14,16 +14,14 @@
//! Android VM control tool.
-mod accessor;
mod run;
-use accessor::Accessor;
-use android_os_accessor::aidl::android::os::IAccessor::BnAccessor;
use anyhow::Error;
use anyhow::{anyhow, bail};
-use binder::{BinderFeatures, ProcessState};
+use binder::ProcessState;
use log::info;
use run::run_vm;
+use std::time::Duration;
// Private contract between IAccessor impl and VM service.
const PORT: i32 = 5678;
@@ -40,11 +38,13 @@
);
let vm = run_vm()?;
+ vm.wait_until_ready(Duration::from_secs(20)).unwrap();
+ let accessor = vm.vm.createAccessorBinder(SERVICE_NAME, PORT).unwrap();
+
+ let accessor_delegator = binder::delegate_accessor(SERVICE_NAME, accessor).unwrap();
// If you want to serve multiple services in a VM, then register Accessor impls multiple times.
- let accessor = Accessor::new(vm, PORT, SERVICE_NAME);
- let accessor_binder = BnAccessor::new_binder(accessor, BinderFeatures::default());
- binder::register_lazy_service(SERVICE_NAME, accessor_binder.as_binder()).map_err(|e| {
+ binder::register_lazy_service(SERVICE_NAME, accessor_delegator).map_err(|e| {
anyhow!("Failed to register lazy service, service={SERVICE_NAME}, err={e:?}",)
})?;
info!("service {SERVICE_NAME} is registered as lazy service");
diff --git a/tests/vm_accessor/accessor/src/run.rs b/tests/vm_accessor/accessor/src/run.rs
index 932baab..6dcc507 100644
--- a/tests/vm_accessor/accessor/src/run.rs
+++ b/tests/vm_accessor/accessor/src/run.rs
@@ -128,6 +128,7 @@
Some(android_log_fd()?), /* console_out */
None, /* console_in */
Some(android_log_fd()?), /* log */
+ None, /* dump_dt */
Some(Box::new(Callback {})),
)
.context("Failed to create VM")?;
diff --git a/tests/vmbase_example/src/main.rs b/tests/vmbase_example/src/main.rs
index e0563b7..34a2b0b 100644
--- a/tests/vmbase_example/src/main.rs
+++ b/tests/vmbase_example/src/main.rs
@@ -119,6 +119,7 @@
Some(console),
/* consoleIn */ None,
Some(log_writer),
+ /* dump_dt */ None,
None,
)
.context("Failed to create VM")?;