Create AppDataUsageCycleController
To improve performance and better organization and testings. Fix: 240931350 Test: manual - on AppDataUsage Test: unit test Change-Id: I277133b55378a3445aceb826d771b14c0fc91e4a
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.settings.datausage.lib
|
||||
|
||||
import android.app.usage.NetworkStats
|
||||
import android.app.usage.NetworkStatsManager
|
||||
import android.content.Context
|
||||
import android.net.NetworkTemplate
|
||||
import android.util.Log
|
||||
import android.util.Range
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
||||
interface IAppDataUsageDetailsRepository {
|
||||
suspend fun queryDetailsForCycles(): List<NetworkUsageDetailsData>
|
||||
}
|
||||
|
||||
class AppDataUsageDetailsRepository @JvmOverloads constructor(
|
||||
context: Context,
|
||||
private val template: NetworkTemplate,
|
||||
private val cycles: List<Long>?,
|
||||
private val uids: List<Int>,
|
||||
private val networkCycleDataRepository: INetworkCycleDataRepository =
|
||||
NetworkCycleDataRepository(context, template)
|
||||
) : IAppDataUsageDetailsRepository {
|
||||
private val networkStatsManager = context.getSystemService(NetworkStatsManager::class.java)!!
|
||||
|
||||
override suspend fun queryDetailsForCycles(): List<NetworkUsageDetailsData> = coroutineScope {
|
||||
getCycles().map {
|
||||
async {
|
||||
queryDetails(it)
|
||||
}
|
||||
}.awaitAll().filter { it.totalUsage > 0 }
|
||||
}
|
||||
|
||||
private fun getCycles(): List<Range<Long>> =
|
||||
cycles?.zipWithNext { endTime, startTime -> Range(startTime, endTime) }
|
||||
?: networkCycleDataRepository.getCycles()
|
||||
|
||||
private fun queryDetails(range: Range<Long>): NetworkUsageDetailsData {
|
||||
var totalUsage = 0L
|
||||
var foregroundUsage = 0L
|
||||
for (uid in uids) {
|
||||
val usage = getUsage(range, uid, NetworkStats.Bucket.STATE_ALL)
|
||||
if (usage > 0L) {
|
||||
totalUsage += usage
|
||||
foregroundUsage +=
|
||||
getUsage(range, uid, NetworkStats.Bucket.STATE_FOREGROUND)
|
||||
}
|
||||
}
|
||||
return NetworkUsageDetailsData(
|
||||
range = range,
|
||||
totalUsage = totalUsage,
|
||||
foregroundUsage = foregroundUsage,
|
||||
backgroundUsage = totalUsage - foregroundUsage,
|
||||
)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun getUsage(range: Range<Long>, uid: Int, state: Int): Long = try {
|
||||
networkStatsManager.queryDetailsForUidTagState(
|
||||
template, range.lower, range.upper, uid, NetworkStats.Bucket.TAG_NONE, state,
|
||||
).getTotalUsage()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Exception querying network detail.", e)
|
||||
0
|
||||
}
|
||||
|
||||
private fun NetworkStats.getTotalUsage(): Long = use {
|
||||
var bytes = 0L
|
||||
val bucket = NetworkStats.Bucket()
|
||||
while (getNextBucket(bucket)) {
|
||||
bytes += bucket.rxBytes + bucket.txBytes
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val TAG = "AppDataUsageDetailsRepo"
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,9 @@ import android.os.Process
|
||||
import android.os.UserHandle
|
||||
import android.util.Log
|
||||
import android.util.SparseArray
|
||||
import android.util.SparseBooleanArray
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.util.keyIterator
|
||||
import com.android.settings.R
|
||||
import com.android.settingslib.AppItem
|
||||
import com.android.settingslib.net.UidDetailProvider
|
||||
@@ -195,6 +197,10 @@ class AppDataUsageRepository(
|
||||
val bytes: Long,
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun getAppUidList(uids: SparseBooleanArray) =
|
||||
uids.keyIterator().asSequence().map { getAppUid(it) }.distinct().toList()
|
||||
|
||||
@JvmStatic
|
||||
fun getAppUid(uid: Int): Int {
|
||||
if (Process.isSdkSandboxUid(uid)) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import kotlinx.coroutines.coroutineScope
|
||||
|
||||
interface INetworkCycleDataRepository {
|
||||
suspend fun loadCycles(): List<NetworkUsageData>
|
||||
fun getCycles(): List<Range<Long>>
|
||||
fun getPolicy(): NetworkPolicy?
|
||||
suspend fun querySummary(startTime: Long, endTime: Long): NetworkCycleChartData?
|
||||
}
|
||||
@@ -48,7 +49,7 @@ class NetworkCycleDataRepository(
|
||||
override suspend fun loadCycles(): List<NetworkUsageData> =
|
||||
getCycles().queryUsage().filter { it.usage > 0 }
|
||||
|
||||
private fun getCycles(): List<Range<Long>> {
|
||||
override fun getCycles(): List<Range<Long>> {
|
||||
val policy = getPolicy() ?: return queryCyclesAsFourWeeks()
|
||||
return policy.cycleIterator().asSequence().map {
|
||||
Range(it.lower.toInstant().toEpochMilli(), it.upper.toInstant().toEpochMilli())
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.settings.datausage.lib
|
||||
|
||||
import android.util.Range
|
||||
|
||||
/**
|
||||
* Details data structure representing usage data in a period.
|
||||
*/
|
||||
data class NetworkUsageDetailsData(
|
||||
val range: Range<Long>,
|
||||
val totalUsage: Long,
|
||||
val foregroundUsage: Long,
|
||||
val backgroundUsage: Long,
|
||||
) {
|
||||
companion object {
|
||||
val AllZero = NetworkUsageDetailsData(
|
||||
range = Range(0, 0),
|
||||
totalUsage = 0,
|
||||
foregroundUsage = 0,
|
||||
backgroundUsage = 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user