• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 
17 // @file:JvmName("ActiveLogs")
18 
19 package com.android.server.bluetooth
20 
21 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE
22 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST
23 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH
24 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED
25 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET
26 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED
27 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING
28 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_SATELLITE_MODE
29 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR
30 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT
31 import android.bluetooth.BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH
32 import android.os.Binder
33 import androidx.annotation.VisibleForTesting
34 import com.android.bluetooth.BluetoothStatsLog
35 import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED
36 import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED
37 import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED
38 import com.android.bluetooth.BluetoothStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__UNKNOWN
39 import java.io.PrintWriter
40 
41 private const val TAG = "ActiveLogs"
42 
43 object ActiveLogs {
44     @VisibleForTesting internal const val MAX_ENTRIES_STORED = 20
45     @VisibleForTesting
46     internal val activeLogs: ArrayDeque<ActiveLog> = ArrayDeque(MAX_ENTRIES_STORED)
47 
48     @JvmStatic
dumpnull49     fun dump(writer: PrintWriter) {
50         if (activeLogs.isEmpty()) {
51             writer.println("Bluetooth never enabled!")
52         } else {
53             writer.println("Enable log:")
54             activeLogs.forEach { writer.println("  $it") }
55         }
56     }
57 
58     @JvmStatic
addnull59     fun add(reason: Int, enable: Boolean) {
60         add(reason, enable, "BluetoothSystemServer", false)
61     }
62 
63     @JvmStatic
addnull64     fun add(reason: Int, enable: Boolean, packageName: String, isBle: Boolean) {
65         val last = activeLogs.lastOrNull()
66         if (activeLogs.size == MAX_ENTRIES_STORED) {
67             activeLogs.removeFirst()
68         }
69         activeLogs.addLast(ActiveLog(reason, packageName, enable, isBle))
70         val state =
71             if (enable) BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED
72             else BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED
73         val lastState: Int
74         val timeSinceLastChanged: Long
75         if (last != null) {
76             lastState =
77                 if (last.enable) BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED
78                 else BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED
79             timeSinceLastChanged = System.currentTimeMillis() - last.timestamp
80         } else {
81             lastState = BLUETOOTH_ENABLED_STATE_CHANGED__STATE__UNKNOWN
82             timeSinceLastChanged = 0
83         }
84 
85         BluetoothStatsLog.write_non_chained(
86             BLUETOOTH_ENABLED_STATE_CHANGED,
87             Binder.getCallingUid(),
88             null,
89             state,
90             reason,
91             packageName,
92             lastState,
93             timeSinceLastChanged,
94         )
95     }
96 }
97 
98 @VisibleForTesting
99 internal class ActiveLog(
100     private val reason: Int,
101     private val packageName: String,
102     val enable: Boolean,
103     private val isBle: Boolean,
104 ) {
105     val timestamp = System.currentTimeMillis()
106 
107     init {
108         Log.d(TAG, this.toString())
109     }
110 
toStringnull111     override fun toString() =
112         Log.timeToStringWithZone(timestamp) +
113             " \tPackage [$packageName] requested to [" +
114             (if (enable) "Enable" else "Disable") +
115             (if (isBle) "Ble" else "") +
116             "]. \tReason is " +
117             getEnableDisableReasonString(reason)
118 }
119 
120 private fun getEnableDisableReasonString(reason: Int): String {
121     return when (reason) {
122         ENABLE_DISABLE_REASON_APPLICATION_REQUEST -> "APPLICATION_REQUEST"
123         ENABLE_DISABLE_REASON_AIRPLANE_MODE -> "AIRPLANE_MODE"
124         ENABLE_DISABLE_REASON_DISALLOWED -> "DISALLOWED"
125         ENABLE_DISABLE_REASON_RESTARTED -> "RESTARTED"
126         ENABLE_DISABLE_REASON_START_ERROR -> "START_ERROR"
127         ENABLE_DISABLE_REASON_SYSTEM_BOOT -> "SYSTEM_BOOT"
128         ENABLE_DISABLE_REASON_CRASH -> "CRASH"
129         ENABLE_DISABLE_REASON_USER_SWITCH -> "USER_SWITCH"
130         ENABLE_DISABLE_REASON_RESTORE_USER_SETTING -> "RESTORE_USER_SETTING"
131         ENABLE_DISABLE_REASON_FACTORY_RESET -> "FACTORY_RESET"
132         ENABLE_DISABLE_REASON_SATELLITE_MODE -> "SATELLITE MODE"
133         else -> "UNKNOWN[$reason]"
134     }
135 }
136