• 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.util.Log
20 import androidx.annotation.Keep
21 import com.android.internal.annotations.GuardedBy
22 import com.android.system.virtualmachine.flags.Flags
23 import com.android.virtualization.terminal.MainActivity.Companion.TAG
24 import com.android.virtualization.terminal.proto.DebianServiceGrpc.DebianServiceImplBase
25 import com.android.virtualization.terminal.proto.ForwardingRequestItem
26 import com.android.virtualization.terminal.proto.QueueOpeningRequest
27 import com.android.virtualization.terminal.proto.ReportVmActivePortsRequest
28 import com.android.virtualization.terminal.proto.ReportVmActivePortsResponse
29 import com.android.virtualization.terminal.proto.ShutdownQueueOpeningRequest
30 import com.android.virtualization.terminal.proto.ShutdownRequestItem
31 import com.android.virtualization.terminal.proto.StorageBalloonQueueOpeningRequest
32 import com.android.virtualization.terminal.proto.StorageBalloonRequestItem
33 import io.grpc.stub.ServerCallStreamObserver
34 import io.grpc.stub.StreamObserver
35 
36 internal class DebianServiceImpl(context: Context) : DebianServiceImplBase() {
37     private val portsStateManager = PortsStateManager.getInstance(context)
38     private var portsStateListener: PortsStateManager.Listener? = null
39     private var shutdownRunnable: Runnable? = null
40     private val mLock = Object()
41     @GuardedBy("mLock") private var storageBalloonCallback: StorageBalloonCallback? = null
42 
reportVmActivePortsnull43     override fun reportVmActivePorts(
44         request: ReportVmActivePortsRequest,
45         responseObserver: StreamObserver<ReportVmActivePortsResponse?>,
46     ) {
47         portsStateManager.updateActivePorts(request.portsList)
48         Log.d(TAG, "reportVmActivePorts: " + portsStateManager.getActivePorts())
49         val reply = ReportVmActivePortsResponse.newBuilder().setSuccess(true).build()
50         responseObserver.onNext(reply)
51         responseObserver.onCompleted()
52     }
53 
openForwardingRequestQueuenull54     override fun openForwardingRequestQueue(
55         request: QueueOpeningRequest,
56         responseObserver: StreamObserver<ForwardingRequestItem?>,
57     ) {
58         Log.d(TAG, "OpenForwardingRequestQueue")
59         portsStateListener =
60             object : PortsStateManager.Listener {
61                 override fun onPortsStateUpdated(
62                     oldActivePorts: Set<Int>,
63                     newActivePorts: Set<Int>,
64                 ) {
65                     updateListeningPorts()
66                 }
67             }
68         portsStateManager.registerListener(portsStateListener!!)
69         updateListeningPorts()
70         runForwarderHost(request.cid, ForwarderHostCallback(responseObserver))
71         responseObserver.onCompleted()
72     }
73 
shutdownDebiannull74     fun shutdownDebian(): Boolean {
75         if (shutdownRunnable == null) {
76             Log.d(TAG, "mShutdownRunnable is not ready.")
77             return false
78         }
79         shutdownRunnable!!.run()
80         return true
81     }
82 
openShutdownRequestQueuenull83     override fun openShutdownRequestQueue(
84         request: ShutdownQueueOpeningRequest?,
85         responseObserver: StreamObserver<ShutdownRequestItem?>,
86     ) {
87         val serverCallStreamObserver =
88             responseObserver as ServerCallStreamObserver<ShutdownRequestItem?>
89         serverCallStreamObserver.setOnCancelHandler { shutdownRunnable = null }
90         Log.d(TAG, "openShutdownRequestQueue")
91         shutdownRunnable = Runnable {
92             if (serverCallStreamObserver.isCancelled()) {
93                 return@Runnable
94             }
95             responseObserver.onNext(ShutdownRequestItem.newBuilder().build())
96             responseObserver.onCompleted()
97             shutdownRunnable = null
98         }
99     }
100 
101     private class StorageBalloonCallback(
102         private val responseObserver: StreamObserver<StorageBalloonRequestItem?>
103     ) {
setAvailableStorageBytesnull104         fun setAvailableStorageBytes(availableBytes: Long) {
105             Log.d(TAG, "send setStorageBalloon: $availableBytes")
106             val item =
107                 StorageBalloonRequestItem.newBuilder().setAvailableBytes(availableBytes).build()
108             responseObserver.onNext(item)
109         }
110 
closeConnectionnull111         fun closeConnection() {
112             Log.d(TAG, "close StorageBalloonQueue")
113             responseObserver.onCompleted()
114         }
115     }
116 
setAvailableStorageBytesnull117     fun setAvailableStorageBytes(availableBytes: Long): Boolean {
118         synchronized(mLock) {
119             if (storageBalloonCallback == null) {
120                 Log.d(TAG, "storageBalloonCallback is not ready.")
121                 return false
122             }
123             storageBalloonCallback!!.setAvailableStorageBytes(availableBytes)
124         }
125         return true
126     }
127 
openStorageBalloonRequestQueuenull128     override fun openStorageBalloonRequestQueue(
129         request: StorageBalloonQueueOpeningRequest?,
130         responseObserver: StreamObserver<StorageBalloonRequestItem?>,
131     ) {
132         if (!Flags.terminalStorageBalloon()) {
133             return
134         }
135         Log.d(TAG, "openStorageRequestQueue")
136         synchronized(mLock) {
137             if (storageBalloonCallback != null) {
138                 Log.d(TAG, "RequestQueue already exists. Closing connection.")
139                 storageBalloonCallback!!.closeConnection()
140             }
141             storageBalloonCallback = StorageBalloonCallback(responseObserver)
142         }
143     }
144 
closeStorageBalloonRequestQueuenull145     fun closeStorageBalloonRequestQueue() {
146         Log.d(TAG, "Stopping storage balloon queue")
147         synchronized(mLock) {
148             if (storageBalloonCallback != null) {
149                 storageBalloonCallback!!.closeConnection()
150                 storageBalloonCallback = null
151             }
152         }
153     }
154 
155     @Keep
156     private class ForwarderHostCallback(
157         private val responseObserver: StreamObserver<ForwardingRequestItem?>
158     ) {
159 
onForwardingRequestReceivednull160         fun onForwardingRequestReceived(guestTcpPort: Int, vsockPort: Int) {
161             val item =
162                 ForwardingRequestItem.newBuilder()
163                     .setGuestTcpPort(guestTcpPort)
164                     .setVsockPort(vsockPort)
165                     .build()
166             responseObserver.onNext(item)
167         }
168     }
169 
killForwarderHostnull170     fun killForwarderHost() {
171         Log.d(TAG, "Stopping port forwarding")
172         if (portsStateListener != null) {
173             portsStateManager.unregisterListener(portsStateListener!!)
174             portsStateListener = null
175         }
176         terminateForwarderHost()
177     }
178 
updateListeningPortsnull179     private fun updateListeningPorts() {
180         val activePorts: Set<Int> = portsStateManager.getActivePorts()
181         val enabledPorts: Set<Int> = portsStateManager.getEnabledPorts()
182         updateListeningPorts(activePorts.filter { enabledPorts.contains(it) }.toIntArray())
183     }
184 
185     companion object {
186         init {
187             System.loadLibrary("forwarder_host_jni")
188         }
189 
runForwarderHostnull190         @JvmStatic private external fun runForwarderHost(cid: Int, callback: ForwarderHostCallback?)
191 
192         @JvmStatic private external fun terminateForwarderHost()
193 
194         @JvmStatic private external fun updateListeningPorts(ports: IntArray?)
195     }
196 }
197