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