summaryrefslogtreecommitdiff
path: root/service/src/ActiveLog.kt
blob: ac49031f90467deafcf743d208ff9072b05b6f07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * 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.
 */

// @file:JvmName("ActiveLogs")

package com.android.server.bluetooth

import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_SATELLITE_MODE
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT
import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH
import android.os.Binder
import androidx.annotation.VisibleForTesting
import com.android.bluetooth.BluetoothStatsLog
import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED
import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED
import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED
import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__UNKNOWN
import java.io.PrintWriter

private const val TAG = "ActiveLogs"

object ActiveLogs {
    @VisibleForTesting internal const val MAX_ENTRIES_STORED = 20
    @VisibleForTesting
    internal val activeLogs: ArrayDeque<ActiveLog> = ArrayDeque(MAX_ENTRIES_STORED)

    @JvmStatic
    fun dump(writer: PrintWriter) {
        if (activeLogs.isEmpty()) {
            writer.println("Bluetooth never enabled!")
        } else {
            writer.println("Enable log:")
            activeLogs.forEach { writer.println("  $it") }
        }
    }

    @JvmStatic
    fun add(reason: Int, enable: Boolean) {
        add(reason, enable, "BluetoothSystemServer", false)
    }

    @JvmStatic
    fun add(reason: Int, enable: Boolean, packageName: String, isBle: Boolean) {
        val last = activeLogs.lastOrNull()
        if (activeLogs.size == MAX_ENTRIES_STORED) {
            activeLogs.removeFirst()
        }
        activeLogs.addLast(ActiveLog(reason, packageName, enable, isBle))
        val state =
            if (enable) BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED
            else BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED
        val lastState: Int
        val timeSinceLastChanged: Long
        if (last != null) {
            lastState =
                if (last.enable) BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED
                else BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED
            timeSinceLastChanged = System.currentTimeMillis() - last.timestamp
        } else {
            lastState = BLUETOOTH_ENABLED_STATE_CHANGED__STATE__UNKNOWN
            timeSinceLastChanged = 0
        }

        BluetoothStatsLog.write_non_chained(
            BLUETOOTH_ENABLED_STATE_CHANGED,
            Binder.getCallingUid(),
            null,
            state,
            reason,
            packageName,
            lastState,
            timeSinceLastChanged,
        )
    }
}

@VisibleForTesting
internal class ActiveLog(
    private val reason: Int,
    private val packageName: String,
    val enable: Boolean,
    private val isBle: Boolean,
) {
    val timestamp = System.currentTimeMillis()

    init {
        Log.d(TAG, this.toString())
    }

    override fun toString() =
        Log.timeToStringWithZone(timestamp) +
            " \tPackage [$packageName] requested to [" +
            (if (enable) "Enable" else "Disable") +
            (if (isBle) "Ble" else "") +
            "]. \tReason is " +
            getEnableDisableReasonString(reason)
}

private fun getEnableDisableReasonString(reason: Int): String {
    return when (reason) {
        ENABLE_DISABLE_REASON_APPLICATION_REQUEST -> "APPLICATION_REQUEST"
        ENABLE_DISABLE_REASON_AIRPLANE_MODE -> "AIRPLANE_MODE"
        ENABLE_DISABLE_REASON_DISALLOWED -> "DISALLOWED"
        ENABLE_DISABLE_REASON_RESTARTED -> "RESTARTED"
        ENABLE_DISABLE_REASON_START_ERROR -> "START_ERROR"
        ENABLE_DISABLE_REASON_SYSTEM_BOOT -> "SYSTEM_BOOT"
        ENABLE_DISABLE_REASON_CRASH -> "CRASH"
        ENABLE_DISABLE_REASON_USER_SWITCH -> "USER_SWITCH"
        ENABLE_DISABLE_REASON_RESTORE_USER_SETTING -> "RESTORE_USER_SETTING"
        ENABLE_DISABLE_REASON_FACTORY_RESET -> "FACTORY_RESET"
        ENABLE_DISABLE_REASON_SATELLITE_MODE -> "SATELLITE MODE"
        else -> "UNKNOWN[$reason]"
    }
}