Loading android/app/src/com/android/bluetooth/BluetoothMethodProxy.java +0 −9 Original line number Diff line number Diff line Loading @@ -44,9 +44,6 @@ import android.provider.Telephony; import android.util.Log; import com.android.bluetooth.bass_client.BassClientPeriodicAdvertisingManager; import com.android.bluetooth.gatt.AppAdvertiseStats; import com.android.bluetooth.gatt.ContextMap; import com.android.bluetooth.gatt.GattService; import com.android.internal.annotations.VisibleForTesting; import com.android.obex.HeaderSet; Loading Loading @@ -264,12 +261,6 @@ public class BluetoothMethodProxy { manager.transferSetInfo(bda, serviceData, advHandle, callback); } /** Proxies {@link AppAdvertiseStats}. */ public AppAdvertiseStats createAppAdvertiseStats( int appUid, int id, String name, ContextMap map, GattService service) { return new AppAdvertiseStats(appUid, id, name, map, service); } /** Proxies {@link Thread#start()}. */ public void threadStart(Thread thread) { thread.start(); Loading android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java +16 −3 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.os.RemoteException; import android.util.Log; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.gatt.GattService.AdvertiserMap; import com.android.internal.annotations.VisibleForTesting; import java.util.Collections; Loading @@ -53,7 +52,11 @@ public class AdvertiseManager { Map<IBinder, AdvertiserInfo> mAdvertisers = Collections.synchronizedMap(new HashMap<>()); static int sTempRegistrationId = -1; /** Constructor of {@link AdvertiseManager}. */ AdvertiseManager(GattService service) { this(service, AdvertiseManagerNativeInterface.getInstance(), new AdvertiserMap()); } @VisibleForTesting AdvertiseManager( GattService service, AdvertiseManagerNativeInterface nativeInterface, Loading @@ -70,6 +73,12 @@ public class AdvertiseManager { mHandler = new Handler(thread.getLooper()); } // TODO(b/327849650): We shouldn't need this, it should be safe to do in the cleanup method. But // it would be a logic change. void clear() { mAdvertiserMap.clear(); } void cleanup() { Log.d(TAG, "cleanup()"); mNativeInterface.cleanup(); Loading @@ -87,6 +96,10 @@ public class AdvertiseManager { } } void dump(StringBuilder sb) { mAdvertiserMap.dump(sb); } static class AdvertiserInfo { /* When id is negative, the registration is ongoing. When the registration finishes, id * becomes equal to advertiser_id */ Loading Loading @@ -263,7 +276,7 @@ public class AdvertiseManager { Log.d(TAG, "startAdvertisingSet() - reg_id=" + cbId + ", callback: " + binder); mAdvertiserMap.add(cbId, callback, mService); mAdvertiserMap.addAppAdvertiseStats(cbId, mService); mAdvertiserMap.recordAdvertiseStart( cbId, parameters, Loading android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java +1 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ public class AdvertiseManagerNativeInterface { private AdvertiseManager mManager; /** Get singleton instance. */ public static AdvertiseManagerNativeInterface getInstance() { static AdvertiseManagerNativeInterface getInstance() { synchronized (INSTANCE_LOCK) { if (sInstance == null) { sInstance = new AdvertiseManagerNativeInterface(); Loading android/app/src/com/android/bluetooth/gatt/AdvertiserMap.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 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. */ package com.android.bluetooth.gatt; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertisingSetParameters; import android.bluetooth.le.PeriodicAdvertisingParameters; import android.content.Context; import android.os.Binder; import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.internal.annotations.GuardedBy; import com.google.common.collect.EvictingQueue; import java.util.HashMap; /** Helper class that keeps track of advertiser stats. */ class AdvertiserMap { private static final String TAG = GattServiceConfig.TAG_PREFIX + "AdvertiserMap"; /** Internal map to keep track of logging information by advertise id */ @GuardedBy("this") private final HashMap<Integer, AppAdvertiseStats> mAppAdvertiseStats = new HashMap<>(); private static final int ADVERTISE_STATE_MAX_SIZE = 5; @GuardedBy("this") private final EvictingQueue<AppAdvertiseStats> mLastAdvertises = EvictingQueue.create(ADVERTISE_STATE_MAX_SIZE); /** Add an entry to the stats map if it doesn't already exist. */ void addAppAdvertiseStats(int id, Context context) { int appUid = Binder.getCallingUid(); String appName = context.getPackageManager().getNameForUid(appUid); if (appName == null) { // Assign an app name if one isn't found appName = "Unknown App (UID: " + appUid + ")"; } synchronized (this) { if (!mAppAdvertiseStats.containsKey(id)) { addAppAdvertiseStats(id, new AppAdvertiseStats(appUid, id, appName)); } } } @VisibleForTesting synchronized void addAppAdvertiseStats(int id, AppAdvertiseStats stats) { mAppAdvertiseStats.put(id, stats); } /** Remove the context for a given application ID. */ synchronized void removeAppAdvertiseStats(int id) { mAppAdvertiseStats.remove(id); } /** Get Logging info by ID */ synchronized AppAdvertiseStats getAppAdvertiseStatsById(int id) { return mAppAdvertiseStats.get(id); } /** update the advertiser ID by the regiseter ID */ synchronized void setAdvertiserIdByRegId(int regId, int advertiserId) { AppAdvertiseStats stats = mAppAdvertiseStats.get(regId); if (stats == null) { return; } stats.setId(advertiserId); mAppAdvertiseStats.remove(regId); mAppAdvertiseStats.put(advertiserId, stats); } synchronized void recordAdvertiseStart( int id, AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } int advertiseInstanceCount = mAppAdvertiseStats.size(); Log.d(TAG, "advertiseInstanceCount is " + advertiseInstanceCount); AppAdvertiseStats.recordAdvertiseInstanceCount(advertiseInstanceCount); stats.recordAdvertiseStart( parameters, advertiseData, scanResponse, periodicParameters, periodicData, duration, maxExtAdvEvents, advertiseInstanceCount); } synchronized void recordAdvertiseStop(int id) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.recordAdvertiseStop(mAppAdvertiseStats.size()); mAppAdvertiseStats.remove(id); mLastAdvertises.add(stats); } synchronized void enableAdvertisingSet( int id, boolean enable, int duration, int maxExtAdvEvents) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.enableAdvertisingSet(enable, duration, maxExtAdvEvents, mAppAdvertiseStats.size()); } synchronized void setAdvertisingData(int id, AdvertiseData data) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setAdvertisingData(data); } synchronized void setScanResponseData(int id, AdvertiseData data) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setScanResponseData(data); } synchronized void setAdvertisingParameters(int id, AdvertisingSetParameters parameters) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setAdvertisingParameters(parameters); } synchronized void setPeriodicAdvertisingParameters( int id, PeriodicAdvertisingParameters parameters) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setPeriodicAdvertisingParameters(parameters); } synchronized void setPeriodicAdvertisingData(int id, AdvertiseData data) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setPeriodicAdvertisingData(data); } synchronized void onPeriodicAdvertiseEnabled(int id, boolean enable) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.onPeriodicAdvertiseEnabled(enable); } /** Erases all entries. */ synchronized void clear() { mAppAdvertiseStats.clear(); mLastAdvertises.clear(); } /** Logs advertiser debug information. */ synchronized void dump(StringBuilder sb) { if (!mLastAdvertises.isEmpty()) { sb.append("\n last " + mLastAdvertises.size() + " advertising:"); for (AppAdvertiseStats stats : mLastAdvertises) { AppAdvertiseStats.dumpToString(sb, stats); } sb.append("\n"); } if (!mAppAdvertiseStats.isEmpty()) { sb.append( " Total number of ongoing advertising : " + mAppAdvertiseStats.size()); sb.append("\n Ongoing advertising:"); for (Integer key : mAppAdvertiseStats.keySet()) { AppAdvertiseStats stats = mAppAdvertiseStats.get(key); AppAdvertiseStats.dumpToString(sb, stats); } } sb.append("\n"); Log.d(TAG, sb.toString()); } } android/app/src/com/android/bluetooth/gatt/AppAdvertiseStats.java +3 −13 Original line number Diff line number Diff line Loading @@ -39,8 +39,7 @@ import java.util.List; import java.util.Map; /** AdvStats class helps keep track of information about advertising on a per application basis. */ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public class AppAdvertiseStats { class AppAdvertiseStats { private static final String TAG = AppAdvertiseStats.class.getSimpleName(); private static DateTimeFormatter sDateFormat = Loading @@ -49,12 +48,6 @@ public class AppAdvertiseStats { static final String[] PHY_LE_STRINGS = {"LE_1M", "LE_2M", "LE_CODED"}; static final int UUID_STRING_FILTER_LEN = 8; // ContextMap here is needed to grab Apps and Connections ContextMap mContextMap; // GattService is needed to add scan event protos to be dumped later GattService mGattService; static class AppAdvertiserData { public boolean includeDeviceName = false; public boolean includeTxPowerLevel = false; Loading Loading @@ -88,7 +81,7 @@ public class AppAdvertiseStats { } private int mAppUid; private String mAppName; @VisibleForTesting String mAppName; private int mId; private boolean mAdvertisingEnabled = false; private boolean mPeriodicAdvertisingEnabled = false; Loading @@ -107,13 +100,10 @@ public class AppAdvertiseStats { private int mPeriodicInterval = 0; public ArrayList<AppAdvertiserRecord> mAdvertiserRecords = new ArrayList<AppAdvertiserRecord>(); @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public AppAdvertiseStats(int appUid, int id, String name, ContextMap map, GattService service) { AppAdvertiseStats(int appUid, int id, String name) { this.mAppUid = appUid; this.mId = id; this.mAppName = name; this.mContextMap = map; this.mGattService = service; } void recordAdvertiseStart( Loading Loading
android/app/src/com/android/bluetooth/BluetoothMethodProxy.java +0 −9 Original line number Diff line number Diff line Loading @@ -44,9 +44,6 @@ import android.provider.Telephony; import android.util.Log; import com.android.bluetooth.bass_client.BassClientPeriodicAdvertisingManager; import com.android.bluetooth.gatt.AppAdvertiseStats; import com.android.bluetooth.gatt.ContextMap; import com.android.bluetooth.gatt.GattService; import com.android.internal.annotations.VisibleForTesting; import com.android.obex.HeaderSet; Loading Loading @@ -264,12 +261,6 @@ public class BluetoothMethodProxy { manager.transferSetInfo(bda, serviceData, advHandle, callback); } /** Proxies {@link AppAdvertiseStats}. */ public AppAdvertiseStats createAppAdvertiseStats( int appUid, int id, String name, ContextMap map, GattService service) { return new AppAdvertiseStats(appUid, id, name, map, service); } /** Proxies {@link Thread#start()}. */ public void threadStart(Thread thread) { thread.start(); Loading
android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java +16 −3 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.os.RemoteException; import android.util.Log; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.gatt.GattService.AdvertiserMap; import com.android.internal.annotations.VisibleForTesting; import java.util.Collections; Loading @@ -53,7 +52,11 @@ public class AdvertiseManager { Map<IBinder, AdvertiserInfo> mAdvertisers = Collections.synchronizedMap(new HashMap<>()); static int sTempRegistrationId = -1; /** Constructor of {@link AdvertiseManager}. */ AdvertiseManager(GattService service) { this(service, AdvertiseManagerNativeInterface.getInstance(), new AdvertiserMap()); } @VisibleForTesting AdvertiseManager( GattService service, AdvertiseManagerNativeInterface nativeInterface, Loading @@ -70,6 +73,12 @@ public class AdvertiseManager { mHandler = new Handler(thread.getLooper()); } // TODO(b/327849650): We shouldn't need this, it should be safe to do in the cleanup method. But // it would be a logic change. void clear() { mAdvertiserMap.clear(); } void cleanup() { Log.d(TAG, "cleanup()"); mNativeInterface.cleanup(); Loading @@ -87,6 +96,10 @@ public class AdvertiseManager { } } void dump(StringBuilder sb) { mAdvertiserMap.dump(sb); } static class AdvertiserInfo { /* When id is negative, the registration is ongoing. When the registration finishes, id * becomes equal to advertiser_id */ Loading Loading @@ -263,7 +276,7 @@ public class AdvertiseManager { Log.d(TAG, "startAdvertisingSet() - reg_id=" + cbId + ", callback: " + binder); mAdvertiserMap.add(cbId, callback, mService); mAdvertiserMap.addAppAdvertiseStats(cbId, mService); mAdvertiserMap.recordAdvertiseStart( cbId, parameters, Loading
android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java +1 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ public class AdvertiseManagerNativeInterface { private AdvertiseManager mManager; /** Get singleton instance. */ public static AdvertiseManagerNativeInterface getInstance() { static AdvertiseManagerNativeInterface getInstance() { synchronized (INSTANCE_LOCK) { if (sInstance == null) { sInstance = new AdvertiseManagerNativeInterface(); Loading
android/app/src/com/android/bluetooth/gatt/AdvertiserMap.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 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. */ package com.android.bluetooth.gatt; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertisingSetParameters; import android.bluetooth.le.PeriodicAdvertisingParameters; import android.content.Context; import android.os.Binder; import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.internal.annotations.GuardedBy; import com.google.common.collect.EvictingQueue; import java.util.HashMap; /** Helper class that keeps track of advertiser stats. */ class AdvertiserMap { private static final String TAG = GattServiceConfig.TAG_PREFIX + "AdvertiserMap"; /** Internal map to keep track of logging information by advertise id */ @GuardedBy("this") private final HashMap<Integer, AppAdvertiseStats> mAppAdvertiseStats = new HashMap<>(); private static final int ADVERTISE_STATE_MAX_SIZE = 5; @GuardedBy("this") private final EvictingQueue<AppAdvertiseStats> mLastAdvertises = EvictingQueue.create(ADVERTISE_STATE_MAX_SIZE); /** Add an entry to the stats map if it doesn't already exist. */ void addAppAdvertiseStats(int id, Context context) { int appUid = Binder.getCallingUid(); String appName = context.getPackageManager().getNameForUid(appUid); if (appName == null) { // Assign an app name if one isn't found appName = "Unknown App (UID: " + appUid + ")"; } synchronized (this) { if (!mAppAdvertiseStats.containsKey(id)) { addAppAdvertiseStats(id, new AppAdvertiseStats(appUid, id, appName)); } } } @VisibleForTesting synchronized void addAppAdvertiseStats(int id, AppAdvertiseStats stats) { mAppAdvertiseStats.put(id, stats); } /** Remove the context for a given application ID. */ synchronized void removeAppAdvertiseStats(int id) { mAppAdvertiseStats.remove(id); } /** Get Logging info by ID */ synchronized AppAdvertiseStats getAppAdvertiseStatsById(int id) { return mAppAdvertiseStats.get(id); } /** update the advertiser ID by the regiseter ID */ synchronized void setAdvertiserIdByRegId(int regId, int advertiserId) { AppAdvertiseStats stats = mAppAdvertiseStats.get(regId); if (stats == null) { return; } stats.setId(advertiserId); mAppAdvertiseStats.remove(regId); mAppAdvertiseStats.put(advertiserId, stats); } synchronized void recordAdvertiseStart( int id, AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } int advertiseInstanceCount = mAppAdvertiseStats.size(); Log.d(TAG, "advertiseInstanceCount is " + advertiseInstanceCount); AppAdvertiseStats.recordAdvertiseInstanceCount(advertiseInstanceCount); stats.recordAdvertiseStart( parameters, advertiseData, scanResponse, periodicParameters, periodicData, duration, maxExtAdvEvents, advertiseInstanceCount); } synchronized void recordAdvertiseStop(int id) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.recordAdvertiseStop(mAppAdvertiseStats.size()); mAppAdvertiseStats.remove(id); mLastAdvertises.add(stats); } synchronized void enableAdvertisingSet( int id, boolean enable, int duration, int maxExtAdvEvents) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.enableAdvertisingSet(enable, duration, maxExtAdvEvents, mAppAdvertiseStats.size()); } synchronized void setAdvertisingData(int id, AdvertiseData data) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setAdvertisingData(data); } synchronized void setScanResponseData(int id, AdvertiseData data) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setScanResponseData(data); } synchronized void setAdvertisingParameters(int id, AdvertisingSetParameters parameters) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setAdvertisingParameters(parameters); } synchronized void setPeriodicAdvertisingParameters( int id, PeriodicAdvertisingParameters parameters) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setPeriodicAdvertisingParameters(parameters); } synchronized void setPeriodicAdvertisingData(int id, AdvertiseData data) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.setPeriodicAdvertisingData(data); } synchronized void onPeriodicAdvertiseEnabled(int id, boolean enable) { AppAdvertiseStats stats = mAppAdvertiseStats.get(id); if (stats == null) { return; } stats.onPeriodicAdvertiseEnabled(enable); } /** Erases all entries. */ synchronized void clear() { mAppAdvertiseStats.clear(); mLastAdvertises.clear(); } /** Logs advertiser debug information. */ synchronized void dump(StringBuilder sb) { if (!mLastAdvertises.isEmpty()) { sb.append("\n last " + mLastAdvertises.size() + " advertising:"); for (AppAdvertiseStats stats : mLastAdvertises) { AppAdvertiseStats.dumpToString(sb, stats); } sb.append("\n"); } if (!mAppAdvertiseStats.isEmpty()) { sb.append( " Total number of ongoing advertising : " + mAppAdvertiseStats.size()); sb.append("\n Ongoing advertising:"); for (Integer key : mAppAdvertiseStats.keySet()) { AppAdvertiseStats stats = mAppAdvertiseStats.get(key); AppAdvertiseStats.dumpToString(sb, stats); } } sb.append("\n"); Log.d(TAG, sb.toString()); } }
android/app/src/com/android/bluetooth/gatt/AppAdvertiseStats.java +3 −13 Original line number Diff line number Diff line Loading @@ -39,8 +39,7 @@ import java.util.List; import java.util.Map; /** AdvStats class helps keep track of information about advertising on a per application basis. */ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public class AppAdvertiseStats { class AppAdvertiseStats { private static final String TAG = AppAdvertiseStats.class.getSimpleName(); private static DateTimeFormatter sDateFormat = Loading @@ -49,12 +48,6 @@ public class AppAdvertiseStats { static final String[] PHY_LE_STRINGS = {"LE_1M", "LE_2M", "LE_CODED"}; static final int UUID_STRING_FILTER_LEN = 8; // ContextMap here is needed to grab Apps and Connections ContextMap mContextMap; // GattService is needed to add scan event protos to be dumped later GattService mGattService; static class AppAdvertiserData { public boolean includeDeviceName = false; public boolean includeTxPowerLevel = false; Loading Loading @@ -88,7 +81,7 @@ public class AppAdvertiseStats { } private int mAppUid; private String mAppName; @VisibleForTesting String mAppName; private int mId; private boolean mAdvertisingEnabled = false; private boolean mPeriodicAdvertisingEnabled = false; Loading @@ -107,13 +100,10 @@ public class AppAdvertiseStats { private int mPeriodicInterval = 0; public ArrayList<AppAdvertiserRecord> mAdvertiserRecords = new ArrayList<AppAdvertiserRecord>(); @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public AppAdvertiseStats(int appUid, int id, String name, ContextMap map, GattService service) { AppAdvertiseStats(int appUid, int id, String name) { this.mAppUid = appUid; this.mId = id; this.mAppName = name; this.mContextMap = map; this.mGattService = service; } void recordAdvertiseStart( Loading