• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.virtualization.terminal
17 
18 import android.content.Context
19 import android.system.virtualmachine.VirtualMachine
20 import android.system.virtualmachine.VirtualMachineCallback
21 import android.system.virtualmachine.VirtualMachineConfig
22 import android.system.virtualmachine.VirtualMachineException
23 import android.system.virtualmachine.VirtualMachineManager
24 import android.util.Log
25 import com.android.virtualization.terminal.MainActivity.Companion.TAG
26 import java.util.concurrent.CompletableFuture
27 import java.util.concurrent.ForkJoinPool
28 
29 /** Utility class for creating a VM and waiting for it to finish. */
30 internal class Runner private constructor(val vm: VirtualMachine, callback: Callback) {
31     /** Get future about VM's exit status. */
32     val exitStatus = callback.finishedSuccessfully
33 
34     private class Callback : VirtualMachineCallback {
35         val finishedSuccessfully: CompletableFuture<Boolean> = CompletableFuture<Boolean>()
36 
onPayloadStartednull37         override fun onPayloadStarted(vm: VirtualMachine) {
38             // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
39         }
40 
onPayloadReadynull41         override fun onPayloadReady(vm: VirtualMachine) {
42             // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
43         }
44 
onPayloadFinishednull45         override fun onPayloadFinished(vm: VirtualMachine, exitCode: Int) {
46             // This event is only from Microdroid-based VM. Custom VM shouldn't emit this.
47         }
48 
onErrornull49         override fun onError(vm: VirtualMachine, errorCode: Int, message: String) {
50             Log.e(TAG, "Error from VM. code: $errorCode ($message)")
51             finishedSuccessfully.complete(false)
52         }
53 
onStoppednull54         override fun onStopped(vm: VirtualMachine, reason: Int) {
55             Log.d(TAG, "VM stopped. Reason: $reason")
56             finishedSuccessfully.complete(true)
57         }
58     }
59 
60     companion object {
61         /** Create a virtual machine of the given config, under the given context. */
62         @Throws(VirtualMachineException::class)
createnull63         fun create(context: Context, config: VirtualMachineConfig): Runner {
64             // context may already be the app context, but calling this again is not harmful.
65             // See b/359439878 on why vmm should be obtained from the app context.
66             val appContext = context.getApplicationContext()
67             val vmm =
68                 appContext.getSystemService<VirtualMachineManager>(
69                     VirtualMachineManager::class.java
70                 )
71             val customConfig = config.customImageConfig
72             requireNotNull(customConfig) { "CustomImageConfig is missing" }
73 
74             val name = customConfig.name
75             require(!name.isNullOrEmpty()) { "Virtual machine's name is missing in the config" }
76 
77             var vm = vmm.getOrCreate(name, config)
78             try {
79                 vm.config = config
80             } catch (e: VirtualMachineException) {
81                 vmm.delete(name)
82                 vm = vmm.create(name, config)
83                 Log.w(TAG, "Re-creating virtual machine ($name)", e)
84             }
85 
86             val cb = Callback()
87             vm.setCallback(ForkJoinPool.commonPool(), cb)
88             vm.run()
89             return Runner(vm, cb)
90         }
91     }
92 }
93