1 /* 2 * Copyright (C) 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 package com.android.bluetooth.gatt; 17 18 import android.bluetooth.le.AdvertiseData; 19 import android.bluetooth.le.AdvertisingSetParameters; 20 import android.bluetooth.le.PeriodicAdvertisingParameters; 21 import android.content.AttributionSource; 22 import android.content.Context; 23 import android.os.Binder; 24 import android.util.Log; 25 26 import androidx.annotation.VisibleForTesting; 27 28 import com.android.bluetooth.BluetoothEventLogger; 29 import com.android.internal.annotations.GuardedBy; 30 31 import java.util.HashMap; 32 33 /** Helper class that keeps track of advertiser stats. */ 34 class AdvertiserMap { 35 private static final String TAG = 36 GattServiceConfig.TAG_PREFIX + AdvertiserMap.class.getSimpleName(); 37 38 /** Internal map to keep track of logging information by advertise id */ 39 @GuardedBy("this") 40 private final HashMap<Integer, AppAdvertiseStats> mAppAdvertiseStats = new HashMap<>(); 41 42 private final BluetoothEventLogger mLastAdvertises = 43 new BluetoothEventLogger(5, "Last Advertising"); 44 45 /** Add an entry to the stats map if it doesn't already exist. */ addAppAdvertiseStats(int id, Context context, AttributionSource attrSource)46 void addAppAdvertiseStats(int id, Context context, AttributionSource attrSource) { 47 int appUid = Binder.getCallingUid(); 48 String appName = context.getPackageManager().getNameForUid(appUid); 49 if (appName == null) { 50 // Assign an app name if one isn't found 51 appName = "Unknown App (UID: " + appUid + ")"; 52 } 53 54 synchronized (this) { 55 if (!mAppAdvertiseStats.containsKey(id)) { 56 addAppAdvertiseStats(id, new AppAdvertiseStats(appUid, id, appName, attrSource)); 57 } 58 } 59 } 60 61 @VisibleForTesting addAppAdvertiseStats(int id, AppAdvertiseStats stats)62 synchronized void addAppAdvertiseStats(int id, AppAdvertiseStats stats) { 63 mAppAdvertiseStats.put(id, stats); 64 } 65 66 /** Remove the context for a given application ID. */ removeAppAdvertiseStats(int id)67 synchronized void removeAppAdvertiseStats(int id) { 68 mAppAdvertiseStats.remove(id); 69 } 70 71 /** Get Logging info by ID */ getAppAdvertiseStatsById(int id)72 synchronized AppAdvertiseStats getAppAdvertiseStatsById(int id) { 73 return mAppAdvertiseStats.get(id); 74 } 75 76 /** update the advertiser ID by the register ID */ setAdvertiserIdByRegId(int regId, int advertiserId)77 synchronized void setAdvertiserIdByRegId(int regId, int advertiserId) { 78 AppAdvertiseStats stats = mAppAdvertiseStats.get(regId); 79 if (stats == null) { 80 return; 81 } 82 stats.setId(advertiserId); 83 mAppAdvertiseStats.remove(regId); 84 mAppAdvertiseStats.put(advertiserId, stats); 85 } 86 recordAdvertiseStart( int id, AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents)87 synchronized void recordAdvertiseStart( 88 int id, 89 AdvertisingSetParameters parameters, 90 AdvertiseData advertiseData, 91 AdvertiseData scanResponse, 92 PeriodicAdvertisingParameters periodicParameters, 93 AdvertiseData periodicData, 94 int duration, 95 int maxExtAdvEvents) { 96 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 97 if (stats == null) { 98 return; 99 } 100 int advertiseInstanceCount = mAppAdvertiseStats.size(); 101 Log.d(TAG, "advertiseInstanceCount is " + advertiseInstanceCount); 102 AppAdvertiseStats.recordAdvertiseInstanceCount(advertiseInstanceCount); 103 stats.recordAdvertiseStart( 104 parameters, 105 advertiseData, 106 scanResponse, 107 periodicParameters, 108 periodicData, 109 duration, 110 maxExtAdvEvents, 111 advertiseInstanceCount); 112 } 113 recordAdvertiseStop(int id)114 synchronized void recordAdvertiseStop(int id) { 115 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 116 if (stats == null) { 117 return; 118 } 119 stats.recordAdvertiseStop(mAppAdvertiseStats.size()); 120 mAppAdvertiseStats.remove(id); 121 122 StringBuilder sb = new StringBuilder(); 123 AppAdvertiseStats.dumpToString(sb, stats); 124 mLastAdvertises.add(sb.toString()); 125 } 126 enableAdvertisingSet( int id, boolean enable, int duration, int maxExtAdvEvents)127 synchronized void enableAdvertisingSet( 128 int id, boolean enable, int duration, int maxExtAdvEvents) { 129 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 130 if (stats == null) { 131 return; 132 } 133 stats.enableAdvertisingSet(enable, duration, maxExtAdvEvents, mAppAdvertiseStats.size()); 134 } 135 setAdvertisingData(int id, AdvertiseData data)136 synchronized void setAdvertisingData(int id, AdvertiseData data) { 137 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 138 if (stats == null) { 139 return; 140 } 141 stats.setAdvertisingData(data); 142 } 143 setScanResponseData(int id, AdvertiseData data)144 synchronized void setScanResponseData(int id, AdvertiseData data) { 145 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 146 if (stats == null) { 147 return; 148 } 149 stats.setScanResponseData(data); 150 } 151 setAdvertisingParameters(int id, AdvertisingSetParameters parameters)152 synchronized void setAdvertisingParameters(int id, AdvertisingSetParameters parameters) { 153 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 154 if (stats == null) { 155 return; 156 } 157 stats.setAdvertisingParameters(parameters); 158 } 159 setPeriodicAdvertisingParameters( int id, PeriodicAdvertisingParameters parameters)160 synchronized void setPeriodicAdvertisingParameters( 161 int id, PeriodicAdvertisingParameters parameters) { 162 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 163 if (stats == null) { 164 return; 165 } 166 stats.setPeriodicAdvertisingParameters(parameters); 167 } 168 setPeriodicAdvertisingData(int id, AdvertiseData data)169 synchronized void setPeriodicAdvertisingData(int id, AdvertiseData data) { 170 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 171 if (stats == null) { 172 return; 173 } 174 stats.setPeriodicAdvertisingData(data); 175 } 176 onPeriodicAdvertiseEnabled(int id, boolean enable)177 synchronized void onPeriodicAdvertiseEnabled(int id, boolean enable) { 178 AppAdvertiseStats stats = mAppAdvertiseStats.get(id); 179 if (stats == null) { 180 return; 181 } 182 stats.onPeriodicAdvertiseEnabled(enable); 183 } 184 185 /** Erases all entries. */ clear()186 synchronized void clear() { 187 mAppAdvertiseStats.clear(); 188 mLastAdvertises.clear(); 189 } 190 191 /** Logs advertiser debug information. */ dump(StringBuilder sb)192 synchronized void dump(StringBuilder sb) { 193 mLastAdvertises.dump(sb); 194 195 if (!mAppAdvertiseStats.isEmpty()) { 196 sb.append(" Total number of ongoing advertising : ") 197 .append(mAppAdvertiseStats.size()); 198 sb.append("\n Ongoing advertising:"); 199 for (Integer key : mAppAdvertiseStats.keySet()) { 200 AppAdvertiseStats stats = mAppAdvertiseStats.get(key); 201 AppAdvertiseStats.dumpToString(sb, stats); 202 } 203 } 204 sb.append("\n"); 205 Log.d(TAG, sb.toString()); 206 } 207 } 208