Loading src/com/android/bluetooth/gatt/AppScanStats.java 0 → 100644 +207 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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.ScanSettings; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import com.android.bluetooth.btservice.BluetoothProto; /** * ScanStats class helps keep track of information about scans * on a per application basis. * @hide */ /*package*/ class AppScanStats { static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); /* ContextMap here is needed to grab Apps and Connections */ ContextMap contextMap; class LastScan { long duration; long timestamp; boolean opportunistic; boolean background; public LastScan(long timestamp, long duration, boolean opportunistic, boolean background) { this.duration = duration; this.timestamp = timestamp; this.opportunistic = opportunistic; this.background = background; } } static final int NUM_SCAN_DURATIONS_KEPT = 5; String appName; int scansStarted = 0; int scansStopped = 0; boolean isScanning = false; boolean isRegistered = false; long minScanTime = Long.MAX_VALUE; long maxScanTime = 0; long totalScanTime = 0; List<LastScan> lastScans = new ArrayList<LastScan>(NUM_SCAN_DURATIONS_KEPT + 1); long startTime = 0; long stopTime = 0; public AppScanStats(String name, ContextMap map) { appName = name; contextMap = map; } synchronized void recordScanStart(ScanSettings settings) { if (isScanning) return; this.scansStarted++; isScanning = true; startTime = System.currentTimeMillis(); LastScan scan = new LastScan(startTime, 0, false, false); if (settings != null) { scan.opportunistic = settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC; scan.background = (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0; } lastScans.add(scan); BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_START); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); contextMap.addScanEvent(scanEvent); } synchronized void recordScanStop() { if (!isScanning) return; this.scansStopped++; isScanning = false; stopTime = System.currentTimeMillis(); long scanDuration = stopTime - startTime; minScanTime = Math.min(scanDuration, minScanTime); maxScanTime = Math.max(scanDuration, maxScanTime); totalScanTime += scanDuration; LastScan curr = lastScans.get(lastScans.size() - 1); curr.duration = scanDuration; if (lastScans.size() > NUM_SCAN_DURATIONS_KEPT) { lastScans.remove(0); } BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_STOP); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); contextMap.addScanEvent(scanEvent); } synchronized void dumpToString(StringBuilder sb) { long currTime = System.currentTimeMillis(); long maxScan = maxScanTime; long minScan = minScanTime; long scanDuration = 0; if (lastScans.isEmpty()) return; if (isScanning) { scanDuration = currTime - startTime; minScan = Math.min(scanDuration, minScan); maxScan = Math.max(scanDuration, maxScan); } if (minScan == Long.MAX_VALUE) { minScan = 0; } long avgScan = 0; if (scansStarted > 0) { avgScan = (totalScanTime + scanDuration) / scansStarted; } LastScan lastScan = lastScans.get(lastScans.size() - 1); sb.append(" " + appName); if (isRegistered) sb.append(" (Registered)"); if (lastScan.opportunistic) sb.append(" (Opportunistic)"); if (lastScan.background) sb.append(" (Background)"); sb.append("\n"); sb.append(" LE scans (started/stopped) : " + scansStarted + " / " + scansStopped + "\n"); sb.append(" Scan time in ms (min/max/avg/total): " + minScan + " / " + maxScan + " / " + avgScan + " / " + totalScanTime + "\n"); if (lastScans.size() != 0) { int lastScansSize = scansStopped < NUM_SCAN_DURATIONS_KEPT ? scansStopped : NUM_SCAN_DURATIONS_KEPT; sb.append(" Last " + lastScansSize + " scans :\n"); for (int i = 0; i < lastScansSize; i++) { LastScan scan = lastScans.get(i); Date timestamp = new Date(scan.timestamp); sb.append(" " + dateFormat.format(timestamp) + " - "); sb.append(scan.duration + "ms "); if (scan.opportunistic) sb.append("Opp "); if (scan.background) sb.append("Back"); sb.append("\n"); } } if (isRegistered) { ContextMap.App appEntry = contextMap.getByName(appName); sb.append(" Application ID : " + appEntry.id + "\n"); sb.append(" UUID : " + appEntry.uuid + "\n"); if (isScanning) { sb.append(" Current scan duration in ms : " + scanDuration + "\n"); } List<ContextMap.Connection> connections = contextMap.getConnectionByApp(appEntry.id); sb.append(" Connections: " + connections.size() + "\n"); Iterator<ContextMap.Connection> ii = connections.iterator(); while(ii.hasNext()) { ContextMap.Connection connection = ii.next(); long connectionTime = System.currentTimeMillis() - connection.startTime; sb.append(" " + connection.connId + ": " + connection.address + " " + connectionTime + "ms\n"); } } sb.append("\n"); } } src/com/android/bluetooth/gatt/ContextMap.java +29 −218 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ package com.android.bluetooth.gatt; import android.bluetooth.le.ScanSettings; import android.content.Context; import android.os.Binder; import android.os.IBinder; Loading @@ -23,13 +22,9 @@ import android.os.IBinder.DeathRecipient; import android.os.IInterface; import android.os.RemoteException; import android.util.Log; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; Loading @@ -38,7 +33,6 @@ import java.util.HashMap; import java.util.Map; import com.android.bluetooth.btservice.BluetoothProto; /** * Helper class that keeps track of registered GATT applications. * This class manages application callbacks and keeps track of GATT connections. Loading @@ -46,202 +40,7 @@ import com.android.bluetooth.btservice.BluetoothProto; */ /*package*/ class ContextMap<T> { private static final String TAG = GattServiceConfig.TAG_PREFIX + "ContextMap"; static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); static final int NUM_SCAN_EVENTS_KEPT = 20; ArrayList<BluetoothProto.ScanEvent> mScanEvents = new ArrayList<BluetoothProto.ScanEvent>(NUM_SCAN_EVENTS_KEPT); /** * ScanStats class helps keep track of information about scans * on a per application basis. */ class ScanStats { class LastScan { long durration; long timestamp; boolean opportunistic; boolean background; public LastScan(long timestamp, long durration, boolean opportunistic, boolean background) { this.durration = durration; this.timestamp = timestamp; this.opportunistic = opportunistic; this.background = background; } } static final int NUM_SCAN_DURATIONS_KEPT = 5; String appName; int scansStarted = 0; int scansStopped = 0; boolean isScanning = false; boolean isRegistered = false; boolean isOpportunisticScan = false; boolean isBackgroundScan = false; long minScanTime = Long.MAX_VALUE; long maxScanTime = 0; long totalScanTime = 0; List<LastScan> lastScans = new ArrayList<LastScan>(NUM_SCAN_DURATIONS_KEPT + 1); long startTime = 0; long stopTime = 0; public ScanStats(String name) { appName = name; } synchronized void recordScanStart(ScanSettings settings) { if (isScanning) return; this.scansStarted++; isScanning = true; startTime = System.currentTimeMillis(); BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_START); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); lastScans.add(new LastScan(startTime, 0, false, false)); if (settings != null) { isOpportunisticScan = settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC; isBackgroundScan = (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0; } synchronized(mScanEvents) { if(mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) mScanEvents.remove(0); mScanEvents.add(scanEvent); } } synchronized void recordScanStop() { if (!isScanning) return; this.scansStopped++; isScanning = false; stopTime = System.currentTimeMillis(); long currTime = stopTime - startTime; minScanTime = Math.min(currTime, minScanTime); maxScanTime = Math.max(currTime, maxScanTime); totalScanTime += currTime; LastScan curr = lastScans.get(lastScans.size() - 1); curr.durration = currTime; curr.opportunistic = isOpportunisticScan; curr.background = isBackgroundScan; isOpportunisticScan = false; isBackgroundScan = false; if (lastScans.size() > NUM_SCAN_DURATIONS_KEPT) { lastScans.remove(0); } BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_STOP); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); synchronized(mScanEvents) { if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) mScanEvents.remove(0); mScanEvents.add(scanEvent); } } synchronized void dumpToString(StringBuilder sb) { long currTime = System.currentTimeMillis(); long maxScan = maxScanTime; long minScan = minScanTime; long currScan = 0; if (isScanning) { currScan = currTime - startTime; minScan = Math.min(currScan, minScan); maxScan = Math.max(currScan, maxScan); } if (minScan == Long.MAX_VALUE) { minScan = 0; } long lastScan = 0; if (stopTime != 0) { lastScan = currTime - stopTime; } long avgScan = 0; if (scansStarted > 0) { avgScan = (totalScanTime + currScan) / scansStarted; } sb.append(" " + appName); if (isRegistered) sb.append(" (Registered)"); if (isOpportunisticScan) sb.append(" (Opportunistic)"); if (isBackgroundScan) sb.append(" (Background)"); sb.append("\n"); sb.append(" LE scans (started/stopped) : " + scansStarted + " / " + scansStopped + "\n"); sb.append(" Scan time in ms (min/max/avg/total): " + minScan + " / " + maxScan + " / " + avgScan + " / " + totalScanTime + "\n"); if (lastScans.size() != 0) { int lastScansSize = scansStopped < NUM_SCAN_DURATIONS_KEPT ? scansStopped : NUM_SCAN_DURATIONS_KEPT; sb.append(" Last " + lastScansSize + " scans :\n"); for (int i = 0; i < lastScansSize; i++) { LastScan scan = lastScans.get(i); Date timestamp = new Date(scan.timestamp); sb.append(" " + dateFormat.format(timestamp) + " - "); sb.append(scan.durration + "ms "); if (scan.opportunistic) sb.append("Opp "); if (scan.background) sb.append("Back"); sb.append("\n"); } } if (isRegistered) { App appEntry = getByName(appName); sb.append(" Application ID : " + appEntry.id + "\n"); sb.append(" UUID : " + appEntry.uuid + "\n"); if (isScanning) { sb.append(" Current scan duration in ms : " + currScan + "\n"); } List<Connection> connections = getConnectionByApp(appEntry.id); sb.append(" Connections: " + connections.size() + "\n"); Iterator<Connection> ii = connections.iterator(); while(ii.hasNext()) { Connection connection = ii.next(); long connectionTime = System.currentTimeMillis() - connection.startTime; sb.append(" " + connection.connId + ": " + connection.address + " " + connectionTime + "ms\n"); } } sb.append("\n"); } } /** * Connection class helps map connection IDs to device addresses. Loading Loading @@ -335,7 +134,11 @@ import com.android.bluetooth.btservice.BluetoothProto; List<App> mApps = new ArrayList<App>(); /** Internal map to keep track of logging information by app name */ HashMap<String, ScanStats> mScanStats = new HashMap<String, ScanStats>(); HashMap<String, AppScanStats> mAppScanStats = new HashMap<String, AppScanStats>(); /** Internal list of scan events to use with the proto */ ArrayList<BluetoothProto.ScanEvent> mScanEvents = new ArrayList<BluetoothProto.ScanEvent>(NUM_SCAN_EVENTS_KEPT); /** Internal list of connected devices **/ Set<Connection> mConnections = new HashSet<Connection>(); Loading @@ -352,12 +155,12 @@ import com.android.bluetooth.btservice.BluetoothProto; } synchronized (mApps) { mApps.add(new App(uuid, callback, appName)); ScanStats scanStats = mScanStats.get(appName); if (scanStats == null) { scanStats = new ScanStats(appName); mScanStats.put(appName, scanStats); AppScanStats appScanStats = mAppScanStats.get(appName); if (appScanStats == null) { appScanStats = new AppScanStats(appName, this); mAppScanStats.put(appName, appScanStats); } scanStats.isRegistered = true; appScanStats.isRegistered = true; } } Loading @@ -371,7 +174,7 @@ import com.android.bluetooth.btservice.BluetoothProto; App entry = i.next(); if (entry.uuid.equals(uuid)) { entry.unlinkToDeath(); mScanStats.get(entry.name).isRegistered = false; mAppScanStats.get(entry.name).isRegistered = false; i.remove(); break; } Loading @@ -389,7 +192,7 @@ import com.android.bluetooth.btservice.BluetoothProto; App entry = i.next(); if (entry.id == id) { entry.unlinkToDeath(); mScanStats.get(entry.name).isRegistered = false; mAppScanStats.get(entry.name).isRegistered = false; i.remove(); break; } Loading Loading @@ -467,10 +270,10 @@ import com.android.bluetooth.btservice.BluetoothProto; /** * Get Logging info by ID */ ScanStats getScanStatsById(int id) { AppScanStats getAppScanStatsById(int id) { App temp = getById(id); if (temp != null) { return mScanStats.get(temp.name); return mAppScanStats.get(temp.name); } return null; } Loading @@ -478,8 +281,8 @@ import com.android.bluetooth.btservice.BluetoothProto; /** * Get Logging info by application name */ ScanStats getScanStatsByName(String name) { return mScanStats.get(name); AppScanStats getAppScanStatsByName(String name) { return mAppScanStats.get(name); } /** Loading Loading @@ -577,19 +380,27 @@ import com.android.bluetooth.btservice.BluetoothProto; return connectedmap; } void addScanEvent(BluetoothProto.ScanEvent event) { synchronized(mScanEvents) { if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) mScanEvents.remove(0); mScanEvents.add(event); } } /** * Logs debug information. */ void dump(StringBuilder sb) { sb.append(" Entries: " + mScanStats.size() + "\n\n"); sb.append(" Entries: " + mAppScanStats.size() + "\n\n"); Iterator<Map.Entry<String,ScanStats>> it = mScanStats.entrySet().iterator(); Iterator<Map.Entry<String, AppScanStats>> it = mAppScanStats.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, ScanStats> entry = it.next(); Map.Entry<String, AppScanStats> entry = it.next(); String name = entry.getKey(); ScanStats scanStats = entry.getValue(); scanStats.dumpToString(sb); AppScanStats appScanStats = entry.getValue(); appScanStats.dumpToString(sb); } } Loading src/com/android/bluetooth/gatt/GattService.java +2 −2 Original line number Diff line number Diff line Loading @@ -1338,7 +1338,7 @@ public class GattService extends ProfileService { scanClient.hasPeersMacAddressPermission = Utils.checkCallerHasPeersMacAddressPermission( this); scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, callingPackage); mClientMap.getScanStatsById(appIf).recordScanStart(settings); mClientMap.getAppScanStatsById(appIf).recordScanStart(settings); mScanManager.startScan(scanClient); } Loading @@ -1353,7 +1353,7 @@ public class GattService extends ProfileService { int scanQueueSize = mScanManager.getBatchScanQueue().size() + mScanManager.getRegularScanQueue().size(); if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize); mClientMap.getScanStatsById(client.clientIf).recordScanStop(); mClientMap.getAppScanStatsById(client.clientIf).recordScanStop(); mScanManager.stopScan(client); } Loading Loading
src/com/android/bluetooth/gatt/AppScanStats.java 0 → 100644 +207 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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.ScanSettings; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import com.android.bluetooth.btservice.BluetoothProto; /** * ScanStats class helps keep track of information about scans * on a per application basis. * @hide */ /*package*/ class AppScanStats { static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); /* ContextMap here is needed to grab Apps and Connections */ ContextMap contextMap; class LastScan { long duration; long timestamp; boolean opportunistic; boolean background; public LastScan(long timestamp, long duration, boolean opportunistic, boolean background) { this.duration = duration; this.timestamp = timestamp; this.opportunistic = opportunistic; this.background = background; } } static final int NUM_SCAN_DURATIONS_KEPT = 5; String appName; int scansStarted = 0; int scansStopped = 0; boolean isScanning = false; boolean isRegistered = false; long minScanTime = Long.MAX_VALUE; long maxScanTime = 0; long totalScanTime = 0; List<LastScan> lastScans = new ArrayList<LastScan>(NUM_SCAN_DURATIONS_KEPT + 1); long startTime = 0; long stopTime = 0; public AppScanStats(String name, ContextMap map) { appName = name; contextMap = map; } synchronized void recordScanStart(ScanSettings settings) { if (isScanning) return; this.scansStarted++; isScanning = true; startTime = System.currentTimeMillis(); LastScan scan = new LastScan(startTime, 0, false, false); if (settings != null) { scan.opportunistic = settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC; scan.background = (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0; } lastScans.add(scan); BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_START); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); contextMap.addScanEvent(scanEvent); } synchronized void recordScanStop() { if (!isScanning) return; this.scansStopped++; isScanning = false; stopTime = System.currentTimeMillis(); long scanDuration = stopTime - startTime; minScanTime = Math.min(scanDuration, minScanTime); maxScanTime = Math.max(scanDuration, maxScanTime); totalScanTime += scanDuration; LastScan curr = lastScans.get(lastScans.size() - 1); curr.duration = scanDuration; if (lastScans.size() > NUM_SCAN_DURATIONS_KEPT) { lastScans.remove(0); } BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_STOP); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); contextMap.addScanEvent(scanEvent); } synchronized void dumpToString(StringBuilder sb) { long currTime = System.currentTimeMillis(); long maxScan = maxScanTime; long minScan = minScanTime; long scanDuration = 0; if (lastScans.isEmpty()) return; if (isScanning) { scanDuration = currTime - startTime; minScan = Math.min(scanDuration, minScan); maxScan = Math.max(scanDuration, maxScan); } if (minScan == Long.MAX_VALUE) { minScan = 0; } long avgScan = 0; if (scansStarted > 0) { avgScan = (totalScanTime + scanDuration) / scansStarted; } LastScan lastScan = lastScans.get(lastScans.size() - 1); sb.append(" " + appName); if (isRegistered) sb.append(" (Registered)"); if (lastScan.opportunistic) sb.append(" (Opportunistic)"); if (lastScan.background) sb.append(" (Background)"); sb.append("\n"); sb.append(" LE scans (started/stopped) : " + scansStarted + " / " + scansStopped + "\n"); sb.append(" Scan time in ms (min/max/avg/total): " + minScan + " / " + maxScan + " / " + avgScan + " / " + totalScanTime + "\n"); if (lastScans.size() != 0) { int lastScansSize = scansStopped < NUM_SCAN_DURATIONS_KEPT ? scansStopped : NUM_SCAN_DURATIONS_KEPT; sb.append(" Last " + lastScansSize + " scans :\n"); for (int i = 0; i < lastScansSize; i++) { LastScan scan = lastScans.get(i); Date timestamp = new Date(scan.timestamp); sb.append(" " + dateFormat.format(timestamp) + " - "); sb.append(scan.duration + "ms "); if (scan.opportunistic) sb.append("Opp "); if (scan.background) sb.append("Back"); sb.append("\n"); } } if (isRegistered) { ContextMap.App appEntry = contextMap.getByName(appName); sb.append(" Application ID : " + appEntry.id + "\n"); sb.append(" UUID : " + appEntry.uuid + "\n"); if (isScanning) { sb.append(" Current scan duration in ms : " + scanDuration + "\n"); } List<ContextMap.Connection> connections = contextMap.getConnectionByApp(appEntry.id); sb.append(" Connections: " + connections.size() + "\n"); Iterator<ContextMap.Connection> ii = connections.iterator(); while(ii.hasNext()) { ContextMap.Connection connection = ii.next(); long connectionTime = System.currentTimeMillis() - connection.startTime; sb.append(" " + connection.connId + ": " + connection.address + " " + connectionTime + "ms\n"); } } sb.append("\n"); } }
src/com/android/bluetooth/gatt/ContextMap.java +29 −218 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ package com.android.bluetooth.gatt; import android.bluetooth.le.ScanSettings; import android.content.Context; import android.os.Binder; import android.os.IBinder; Loading @@ -23,13 +22,9 @@ import android.os.IBinder.DeathRecipient; import android.os.IInterface; import android.os.RemoteException; import android.util.Log; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; Loading @@ -38,7 +33,6 @@ import java.util.HashMap; import java.util.Map; import com.android.bluetooth.btservice.BluetoothProto; /** * Helper class that keeps track of registered GATT applications. * This class manages application callbacks and keeps track of GATT connections. Loading @@ -46,202 +40,7 @@ import com.android.bluetooth.btservice.BluetoothProto; */ /*package*/ class ContextMap<T> { private static final String TAG = GattServiceConfig.TAG_PREFIX + "ContextMap"; static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); static final int NUM_SCAN_EVENTS_KEPT = 20; ArrayList<BluetoothProto.ScanEvent> mScanEvents = new ArrayList<BluetoothProto.ScanEvent>(NUM_SCAN_EVENTS_KEPT); /** * ScanStats class helps keep track of information about scans * on a per application basis. */ class ScanStats { class LastScan { long durration; long timestamp; boolean opportunistic; boolean background; public LastScan(long timestamp, long durration, boolean opportunistic, boolean background) { this.durration = durration; this.timestamp = timestamp; this.opportunistic = opportunistic; this.background = background; } } static final int NUM_SCAN_DURATIONS_KEPT = 5; String appName; int scansStarted = 0; int scansStopped = 0; boolean isScanning = false; boolean isRegistered = false; boolean isOpportunisticScan = false; boolean isBackgroundScan = false; long minScanTime = Long.MAX_VALUE; long maxScanTime = 0; long totalScanTime = 0; List<LastScan> lastScans = new ArrayList<LastScan>(NUM_SCAN_DURATIONS_KEPT + 1); long startTime = 0; long stopTime = 0; public ScanStats(String name) { appName = name; } synchronized void recordScanStart(ScanSettings settings) { if (isScanning) return; this.scansStarted++; isScanning = true; startTime = System.currentTimeMillis(); BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_START); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); lastScans.add(new LastScan(startTime, 0, false, false)); if (settings != null) { isOpportunisticScan = settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC; isBackgroundScan = (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0; } synchronized(mScanEvents) { if(mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) mScanEvents.remove(0); mScanEvents.add(scanEvent); } } synchronized void recordScanStop() { if (!isScanning) return; this.scansStopped++; isScanning = false; stopTime = System.currentTimeMillis(); long currTime = stopTime - startTime; minScanTime = Math.min(currTime, minScanTime); maxScanTime = Math.max(currTime, maxScanTime); totalScanTime += currTime; LastScan curr = lastScans.get(lastScans.size() - 1); curr.durration = currTime; curr.opportunistic = isOpportunisticScan; curr.background = isBackgroundScan; isOpportunisticScan = false; isBackgroundScan = false; if (lastScans.size() > NUM_SCAN_DURATIONS_KEPT) { lastScans.remove(0); } BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_STOP); scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); scanEvent.setInitiator(appName); scanEvent.setEventTimeMillis(System.currentTimeMillis()); synchronized(mScanEvents) { if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) mScanEvents.remove(0); mScanEvents.add(scanEvent); } } synchronized void dumpToString(StringBuilder sb) { long currTime = System.currentTimeMillis(); long maxScan = maxScanTime; long minScan = minScanTime; long currScan = 0; if (isScanning) { currScan = currTime - startTime; minScan = Math.min(currScan, minScan); maxScan = Math.max(currScan, maxScan); } if (minScan == Long.MAX_VALUE) { minScan = 0; } long lastScan = 0; if (stopTime != 0) { lastScan = currTime - stopTime; } long avgScan = 0; if (scansStarted > 0) { avgScan = (totalScanTime + currScan) / scansStarted; } sb.append(" " + appName); if (isRegistered) sb.append(" (Registered)"); if (isOpportunisticScan) sb.append(" (Opportunistic)"); if (isBackgroundScan) sb.append(" (Background)"); sb.append("\n"); sb.append(" LE scans (started/stopped) : " + scansStarted + " / " + scansStopped + "\n"); sb.append(" Scan time in ms (min/max/avg/total): " + minScan + " / " + maxScan + " / " + avgScan + " / " + totalScanTime + "\n"); if (lastScans.size() != 0) { int lastScansSize = scansStopped < NUM_SCAN_DURATIONS_KEPT ? scansStopped : NUM_SCAN_DURATIONS_KEPT; sb.append(" Last " + lastScansSize + " scans :\n"); for (int i = 0; i < lastScansSize; i++) { LastScan scan = lastScans.get(i); Date timestamp = new Date(scan.timestamp); sb.append(" " + dateFormat.format(timestamp) + " - "); sb.append(scan.durration + "ms "); if (scan.opportunistic) sb.append("Opp "); if (scan.background) sb.append("Back"); sb.append("\n"); } } if (isRegistered) { App appEntry = getByName(appName); sb.append(" Application ID : " + appEntry.id + "\n"); sb.append(" UUID : " + appEntry.uuid + "\n"); if (isScanning) { sb.append(" Current scan duration in ms : " + currScan + "\n"); } List<Connection> connections = getConnectionByApp(appEntry.id); sb.append(" Connections: " + connections.size() + "\n"); Iterator<Connection> ii = connections.iterator(); while(ii.hasNext()) { Connection connection = ii.next(); long connectionTime = System.currentTimeMillis() - connection.startTime; sb.append(" " + connection.connId + ": " + connection.address + " " + connectionTime + "ms\n"); } } sb.append("\n"); } } /** * Connection class helps map connection IDs to device addresses. Loading Loading @@ -335,7 +134,11 @@ import com.android.bluetooth.btservice.BluetoothProto; List<App> mApps = new ArrayList<App>(); /** Internal map to keep track of logging information by app name */ HashMap<String, ScanStats> mScanStats = new HashMap<String, ScanStats>(); HashMap<String, AppScanStats> mAppScanStats = new HashMap<String, AppScanStats>(); /** Internal list of scan events to use with the proto */ ArrayList<BluetoothProto.ScanEvent> mScanEvents = new ArrayList<BluetoothProto.ScanEvent>(NUM_SCAN_EVENTS_KEPT); /** Internal list of connected devices **/ Set<Connection> mConnections = new HashSet<Connection>(); Loading @@ -352,12 +155,12 @@ import com.android.bluetooth.btservice.BluetoothProto; } synchronized (mApps) { mApps.add(new App(uuid, callback, appName)); ScanStats scanStats = mScanStats.get(appName); if (scanStats == null) { scanStats = new ScanStats(appName); mScanStats.put(appName, scanStats); AppScanStats appScanStats = mAppScanStats.get(appName); if (appScanStats == null) { appScanStats = new AppScanStats(appName, this); mAppScanStats.put(appName, appScanStats); } scanStats.isRegistered = true; appScanStats.isRegistered = true; } } Loading @@ -371,7 +174,7 @@ import com.android.bluetooth.btservice.BluetoothProto; App entry = i.next(); if (entry.uuid.equals(uuid)) { entry.unlinkToDeath(); mScanStats.get(entry.name).isRegistered = false; mAppScanStats.get(entry.name).isRegistered = false; i.remove(); break; } Loading @@ -389,7 +192,7 @@ import com.android.bluetooth.btservice.BluetoothProto; App entry = i.next(); if (entry.id == id) { entry.unlinkToDeath(); mScanStats.get(entry.name).isRegistered = false; mAppScanStats.get(entry.name).isRegistered = false; i.remove(); break; } Loading Loading @@ -467,10 +270,10 @@ import com.android.bluetooth.btservice.BluetoothProto; /** * Get Logging info by ID */ ScanStats getScanStatsById(int id) { AppScanStats getAppScanStatsById(int id) { App temp = getById(id); if (temp != null) { return mScanStats.get(temp.name); return mAppScanStats.get(temp.name); } return null; } Loading @@ -478,8 +281,8 @@ import com.android.bluetooth.btservice.BluetoothProto; /** * Get Logging info by application name */ ScanStats getScanStatsByName(String name) { return mScanStats.get(name); AppScanStats getAppScanStatsByName(String name) { return mAppScanStats.get(name); } /** Loading Loading @@ -577,19 +380,27 @@ import com.android.bluetooth.btservice.BluetoothProto; return connectedmap; } void addScanEvent(BluetoothProto.ScanEvent event) { synchronized(mScanEvents) { if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) mScanEvents.remove(0); mScanEvents.add(event); } } /** * Logs debug information. */ void dump(StringBuilder sb) { sb.append(" Entries: " + mScanStats.size() + "\n\n"); sb.append(" Entries: " + mAppScanStats.size() + "\n\n"); Iterator<Map.Entry<String,ScanStats>> it = mScanStats.entrySet().iterator(); Iterator<Map.Entry<String, AppScanStats>> it = mAppScanStats.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, ScanStats> entry = it.next(); Map.Entry<String, AppScanStats> entry = it.next(); String name = entry.getKey(); ScanStats scanStats = entry.getValue(); scanStats.dumpToString(sb); AppScanStats appScanStats = entry.getValue(); appScanStats.dumpToString(sb); } } Loading
src/com/android/bluetooth/gatt/GattService.java +2 −2 Original line number Diff line number Diff line Loading @@ -1338,7 +1338,7 @@ public class GattService extends ProfileService { scanClient.hasPeersMacAddressPermission = Utils.checkCallerHasPeersMacAddressPermission( this); scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, callingPackage); mClientMap.getScanStatsById(appIf).recordScanStart(settings); mClientMap.getAppScanStatsById(appIf).recordScanStart(settings); mScanManager.startScan(scanClient); } Loading @@ -1353,7 +1353,7 @@ public class GattService extends ProfileService { int scanQueueSize = mScanManager.getBatchScanQueue().size() + mScanManager.getRegularScanQueue().size(); if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize); mClientMap.getScanStatsById(client.clientIf).recordScanStop(); mClientMap.getAppScanStatsById(client.clientIf).recordScanStop(); mScanManager.stopScan(client); } Loading