• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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.os.storage.StorageManager
20 import android.os.storage.StorageManager.UUID_DEFAULT
21 import android.util.Log
22 import androidx.work.WorkManager
23 import androidx.work.Worker
24 import androidx.work.WorkerParameters
25 import com.android.virtualization.terminal.MainActivity.Companion.TAG
26 import java.util.concurrent.TimeUnit
27 
28 class StorageBalloonWorker(appContext: Context, workerParams: WorkerParameters) :
29     Worker(appContext, workerParams) {
30 
doWorknull31     override fun doWork(): Result {
32         Log.d(TAG, "StorageBalloonWorker.doWork() called")
33 
34         var storageManager =
35             applicationContext.getSystemService(Context.STORAGE_SERVICE) as StorageManager
36         val hostAllocatableBytes = storageManager.getAllocatableBytes(UUID_DEFAULT)
37 
38         val guestAvailableBytes = calculateGuestAvailableStorageSize(hostAllocatableBytes)
39         // debianService must be set when this function is called.
40         debianService!!.setAvailableStorageBytes(guestAvailableBytes)
41 
42         val delaySeconds = calculateDelaySeconds(hostAllocatableBytes)
43         scheduleNextTask(delaySeconds)
44 
45         return Result.success()
46     }
47 
calculateGuestAvailableStorageSizenull48     private fun calculateGuestAvailableStorageSize(hostAllocatableBytes: Long): Long {
49         return hostAllocatableBytes - HOST_RESERVED_BYTES
50     }
51 
calculateDelaySecondsnull52     private fun calculateDelaySeconds(hostAvailableBytes: Long): Long {
53         return when {
54             hostAvailableBytes < CRITICAL_STORAGE_THRESHOLD_BYTES -> CRITICAL_DELAY_SECONDS
55             hostAvailableBytes < LOW_STORAGE_THRESHOLD_BYTES -> LOW_STORAGE_DELAY_SECONDS
56             hostAvailableBytes < MODERATE_STORAGE_THRESHOLD_BYTES -> MODERATE_STORAGE_DELAY_SECONDS
57             else -> NORMAL_DELAY_SECONDS
58         }
59     }
60 
scheduleNextTasknull61     private fun scheduleNextTask(delaySeconds: Long) {
62         val storageBalloonTaskRequest =
63             androidx.work.OneTimeWorkRequest.Builder(StorageBalloonWorker::class.java)
64                 .setInitialDelay(delaySeconds, TimeUnit.SECONDS)
65                 .build()
66         androidx.work.WorkManager.getInstance(applicationContext)
67             .enqueueUniqueWork(
68                 "storageBalloonTask",
69                 androidx.work.ExistingWorkPolicy.REPLACE,
70                 storageBalloonTaskRequest,
71             )
72         Log.d(TAG, "next storage balloon task is scheduled in $delaySeconds seconds")
73     }
74 
75     companion object {
76         private var debianService: DebianServiceImpl? = null
77 
78         // Reserve 1GB as host-only region.
79         private const val HOST_RESERVED_BYTES = 1024L * 1024 * 1024
80 
81         // Thresholds for deciding time period to report storage information to the guest.
82         // Less storage is available on the host, more frequently the host will report storage
83         // information to the guest.
84         //
85         // Critical: (host storage < 1GB) => report every 5 seconds
86         private const val CRITICAL_STORAGE_THRESHOLD_BYTES = 1L * 1024 * 1024 * 1024
87         private const val CRITICAL_DELAY_SECONDS = 5L
88         // Low: (1GB <= storage < 5GB) => report every 60 seconds
89         private const val LOW_STORAGE_THRESHOLD_BYTES = 5L * 1024 * 1024 * 1024
90         private const val LOW_STORAGE_DELAY_SECONDS = 60L
91         // Moderate: (5GB <= storage < 10GB) => report every 15 minutes
92         private const val MODERATE_STORAGE_THRESHOLD_BYTES = 10L * 1024 * 1024 * 1024
93         private const val MODERATE_STORAGE_DELAY_SECONDS = 15L * 60
94         // Normal: report every 60 minutes
95         private const val NORMAL_DELAY_SECONDS = 60L * 60
96 
startnull97         internal fun start(ctx: Context, ds: DebianServiceImpl) {
98             debianService = ds
99             val storageBalloonTaskRequest =
100                 androidx.work.OneTimeWorkRequest.Builder(StorageBalloonWorker::class.java)
101                     .setInitialDelay(1, TimeUnit.SECONDS)
102                     .build()
103             androidx.work.WorkManager.getInstance(ctx)
104                 .enqueueUniqueWork(
105                     "storageBalloonTask",
106                     androidx.work.ExistingWorkPolicy.REPLACE,
107                     storageBalloonTaskRequest,
108                 )
109         }
110     }
111 }
112