1b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker/* 2b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * Copyright (C) 2016 The Android Open Source Project 3b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * 4b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * Licensed under the Apache License, Version 2.0 (the "License"); 5b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * you may not use this file except in compliance with the License. 6b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * You may obtain a copy of the License at 7b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * 8b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * http://www.apache.org/licenses/LICENSE-2.0 9b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * 10b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * Unless required by applicable law or agreed to in writing, software 11b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * distributed under the License is distributed on an "AS IS" BASIS, 12b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * See the License for the specific language governing permissions and 14b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * limitations under the License. 15b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker */ 16b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerpackage com.android.bluetooth.gatt; 17b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 18b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport android.bluetooth.le.ScanSettings; 19edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panickerimport android.os.Binder; 20edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panickerimport android.os.WorkSource; 21edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panickerimport android.os.ServiceManager; 22ca4e714ae37050265379fc6604a4e01db9ecae15Ajay Panickerimport android.os.SystemClock; 23edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panickerimport android.os.RemoteException; 24edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panickerimport com.android.internal.app.IBatteryStats; 25b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport java.text.DateFormat; 26b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport java.text.SimpleDateFormat; 27b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport java.util.ArrayList; 28b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport java.util.Date; 29b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport java.util.Iterator; 30b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport java.util.List; 31ff0aaa12c3204523136cc75886add779e4727d00Vinay Kaliaimport java.util.HashMap; 32b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 33b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panickerimport com.android.bluetooth.btservice.BluetoothProto; 34b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker/** 35b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * ScanStats class helps keep track of information about scans 36b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * on a per application basis. 37b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker * @hide 38b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker */ 39b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker/*package*/ class AppScanStats { 40b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 41b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 42b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker /* ContextMap here is needed to grab Apps and Connections */ 43b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker ContextMap contextMap; 44b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 45c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker /* GattService is needed to add scan event protos to be dumped later */ 46c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker GattService gattService; 47c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker 48edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker /* Battery stats is used to keep track of scans and result stats */ 49edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker IBatteryStats batteryStats; 50edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker 51b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker class LastScan { 52b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long duration; 5312991e68679245a717ba3a94df90c57d438e259eVinay Kalia long suspendDuration; 5412991e68679245a717ba3a94df90c57d438e259eVinay Kalia long suspendStartTime; 5512991e68679245a717ba3a94df90c57d438e259eVinay Kalia boolean isSuspended; 56b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long timestamp; 57b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker boolean opportunistic; 581fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker boolean timeout; 59b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker boolean background; 60bd11ad34482a898a53bbd9f55bf3607c40c648ecAjay Panicker boolean filtered; 61c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker int results; 62ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia int scannerId; 63b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 64bd11ad34482a898a53bbd9f55bf3607c40c648ecAjay Panicker public LastScan(long timestamp, long duration, boolean opportunistic, boolean background, 65ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia boolean filtered, int scannerId) { 66b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker this.duration = duration; 67b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker this.timestamp = timestamp; 68b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker this.opportunistic = opportunistic; 69b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker this.background = background; 70bd11ad34482a898a53bbd9f55bf3607c40c648ecAjay Panicker this.filtered = filtered; 71c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker this.results = 0; 72ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia this.scannerId = scannerId; 7312991e68679245a717ba3a94df90c57d438e259eVinay Kalia this.suspendDuration = 0; 7412991e68679245a717ba3a94df90c57d438e259eVinay Kalia this.suspendStartTime = 0; 7512991e68679245a717ba3a94df90c57d438e259eVinay Kalia this.isSuspended = false; 76b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 77b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 78b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 79b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker static final int NUM_SCAN_DURATIONS_KEPT = 5; 80b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 811fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker // This constant defines the time window an app can scan multiple times. 821fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker // Any single app can scan up to |NUM_SCAN_DURATIONS_KEPT| times during 831fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker // this window. Once they reach this limit, they must wait until their 841fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker // earliest recorded scan exits this window. 851fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker static final long EXCESSIVE_SCANNING_PERIOD_MS = 30 * 1000; 861fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker 8765e839fa45222955a605f6270a240edc68b21617Ajay Panicker // Maximum msec before scan gets downgraded to opportunistic 8865e839fa45222955a605f6270a240edc68b21617Ajay Panicker static final int SCAN_TIMEOUT_MS = 30 * 60 * 1000; 8965e839fa45222955a605f6270a240edc68b21617Ajay Panicker 90b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker String appName; 91edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker WorkSource workSource; // Used for BatteryStats 92b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker int scansStarted = 0; 93b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker int scansStopped = 0; 94b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker boolean isRegistered = false; 95b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long minScanTime = Long.MAX_VALUE; 96b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long maxScanTime = 0; 97ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia long mScanStartTime = 0; 98ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia long mTotalScanTime = 0; 9912991e68679245a717ba3a94df90c57d438e259eVinay Kalia long mTotalSuspendTime = 0; 100ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia List<LastScan> lastScans = new ArrayList<LastScan>(NUM_SCAN_DURATIONS_KEPT); 101ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia HashMap<Integer, LastScan> ongoingScans = new HashMap<Integer, LastScan>(); 102b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long startTime = 0; 103b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long stopTime = 0; 104c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker int results = 0; 105b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 106edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker public AppScanStats(String name, WorkSource source, ContextMap map, GattService service) { 107b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker appName = name; 108b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker contextMap = map; 109c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker gattService = service; 110edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker batteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batterystats")); 111edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker 112edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker if (source == null) { 113edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker // Bill the caller if the work source isn't passed through 114edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker source = new WorkSource(Binder.getCallingUid(), appName); 115edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker } 116edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker workSource = source; 117c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker } 118c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker 119ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia synchronized void addResult(int scannerId) { 120ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia LastScan scan = getScanFromScannerId(scannerId); 121ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (scan != null) { 122ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia int batteryStatsResults = ++scan.results; 1238dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker 1248dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker // Only update battery stats after receiving 100 new results in order 1258dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker // to lower the cost of the binder transaction 1268dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker if (batteryStatsResults % 100 == 0) { 1278dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker try { 1288dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker batteryStats.noteBleScanResults(workSource, 100); 1298dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker } catch (RemoteException e) { 1308dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker /* ignore */ 1318dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker } 1328dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker } 1338dc1ac7b011ff262830a0a28f66ae53fe5f63f74Ajay Panicker } 134c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker 135c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker results++; 136b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 137b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 138ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia boolean isScanning() { 139ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia return !ongoingScans.isEmpty(); 140ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia } 141ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia 142ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia LastScan getScanFromScannerId(int scannerId) { 143ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia return ongoingScans.get(scannerId); 144ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia } 1452e20779b97be2073942b1fc8093414ae08e03136Vinay Kalia 146ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia synchronized void recordScanStart(ScanSettings settings, boolean filtered, int scannerId) { 147ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia LastScan existingScan = getScanFromScannerId(scannerId); 148ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (existingScan != null) { 149ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia return; 150ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia } 151b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker this.scansStarted++; 152ca4e714ae37050265379fc6604a4e01db9ecae15Ajay Panicker startTime = SystemClock.elapsedRealtime(); 153b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 154ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia LastScan scan = new LastScan(startTime, 0, false, false, filtered, scannerId); 155b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker if (settings != null) { 156b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scan.opportunistic = settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC; 157b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scan.background = (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0; 158b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 159b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 160b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); 161b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_START); 162b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); 163b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scanEvent.setEventTimeMillis(System.currentTimeMillis()); 1643d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker scanEvent.setInitiator(truncateAppName(appName)); 165c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker gattService.addScanEvent(scanEvent); 166edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker 167d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker if (!isScanning()) mScanStartTime = startTime; 168d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker try { 169d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker boolean isUnoptimized = !(scan.filtered || scan.background || scan.opportunistic); 170d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker batteryStats.noteBleScanStarted(workSource, isUnoptimized); 171d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker } catch (RemoteException e) { 172d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker /* ignore */ 173edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker } 174b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 175ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia ongoingScans.put(scannerId, scan); 176ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia } 1772e20779b97be2073942b1fc8093414ae08e03136Vinay Kalia 178ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia synchronized void recordScanStop(int scannerId) { 179ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia LastScan scan = getScanFromScannerId(scannerId); 180ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (scan == null) { 181ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia return; 182ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia } 183b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker this.scansStopped++; 184ca4e714ae37050265379fc6604a4e01db9ecae15Ajay Panicker stopTime = SystemClock.elapsedRealtime(); 185ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia long scanDuration = stopTime - scan.timestamp; 186ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia scan.duration = scanDuration; 18712991e68679245a717ba3a94df90c57d438e259eVinay Kalia if (scan.isSuspended) { 18812991e68679245a717ba3a94df90c57d438e259eVinay Kalia scan.suspendDuration += stopTime - scan.suspendStartTime; 18912991e68679245a717ba3a94df90c57d438e259eVinay Kalia mTotalSuspendTime += scan.suspendDuration; 19012991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 191ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia ongoingScans.remove(scannerId); 192ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (lastScans.size() >= NUM_SCAN_DURATIONS_KEPT) { 193b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker lastScans.remove(0); 194b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 195ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia lastScans.add(scan); 196b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 197b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent(); 198b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_STOP); 199b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE); 200b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scanEvent.setEventTimeMillis(System.currentTimeMillis()); 2013d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker scanEvent.setInitiator(truncateAppName(appName)); 202c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker gattService.addScanEvent(scanEvent); 203edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker 204ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (!isScanning()) { 205d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker long totalDuration = stopTime - mScanStartTime; 206d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker mTotalScanTime += totalDuration; 207d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker minScanTime = Math.min(totalDuration, minScanTime); 208d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker maxScanTime = Math.max(totalDuration, maxScanTime); 209d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker } 210d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker 211d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker try { 212d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker // Inform battery stats of any results it might be missing on 213d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker // scan stop 214d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker boolean isUnoptimized = !(scan.filtered || scan.background || scan.opportunistic); 215d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker batteryStats.noteBleScanResults(workSource, scan.results % 100); 216d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker batteryStats.noteBleScanStopped(workSource, isUnoptimized); 217d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker } catch (RemoteException e) { 218d5078f2b255eafb78881f39e23ae329f8515db58Ajay Panicker /* ignore */ 219edbc90eb917a8a509d2d03fb304763b768ec5517Ajay Panicker } 220b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 221b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 22212991e68679245a717ba3a94df90c57d438e259eVinay Kalia synchronized void recordScanSuspend(int scannerId) { 22312991e68679245a717ba3a94df90c57d438e259eVinay Kalia LastScan scan = getScanFromScannerId(scannerId); 22412991e68679245a717ba3a94df90c57d438e259eVinay Kalia if (scan == null || scan.isSuspended) { 22512991e68679245a717ba3a94df90c57d438e259eVinay Kalia return; 22612991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 22712991e68679245a717ba3a94df90c57d438e259eVinay Kalia scan.suspendStartTime = SystemClock.elapsedRealtime(); 22812991e68679245a717ba3a94df90c57d438e259eVinay Kalia scan.isSuspended = true; 22912991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 23012991e68679245a717ba3a94df90c57d438e259eVinay Kalia 23112991e68679245a717ba3a94df90c57d438e259eVinay Kalia synchronized void recordScanResume(int scannerId) { 23212991e68679245a717ba3a94df90c57d438e259eVinay Kalia LastScan scan = getScanFromScannerId(scannerId); 23312991e68679245a717ba3a94df90c57d438e259eVinay Kalia if (scan == null || !scan.isSuspended) { 23412991e68679245a717ba3a94df90c57d438e259eVinay Kalia return; 23512991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 23612991e68679245a717ba3a94df90c57d438e259eVinay Kalia scan.isSuspended = false; 23712991e68679245a717ba3a94df90c57d438e259eVinay Kalia stopTime = SystemClock.elapsedRealtime(); 23812991e68679245a717ba3a94df90c57d438e259eVinay Kalia scan.suspendDuration += stopTime - scan.suspendStartTime; 23912991e68679245a717ba3a94df90c57d438e259eVinay Kalia mTotalSuspendTime += scan.suspendDuration; 24012991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 24112991e68679245a717ba3a94df90c57d438e259eVinay Kalia 242ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia synchronized void setScanTimeout(int scannerId) { 243ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (!isScanning()) return; 2441fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker 245ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia LastScan scan = getScanFromScannerId(scannerId); 246ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (scan != null) { 247ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia scan.timeout = true; 2481fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker } 2491fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker } 2501fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker 2511fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker synchronized boolean isScanningTooFrequently() { 2521fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker if (lastScans.size() < NUM_SCAN_DURATIONS_KEPT) { 2531fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker return false; 2541fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker } 2551fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker 256ca4e714ae37050265379fc6604a4e01db9ecae15Ajay Panicker return (SystemClock.elapsedRealtime() - lastScans.get(0).timestamp) 257ca4e714ae37050265379fc6604a4e01db9ecae15Ajay Panicker < EXCESSIVE_SCANNING_PERIOD_MS; 2581fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker } 2591fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker 26065e839fa45222955a605f6270a240edc68b21617Ajay Panicker synchronized boolean isScanningTooLong() { 261ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (!isScanning()) { 26265e839fa45222955a605f6270a240edc68b21617Ajay Panicker return false; 26365e839fa45222955a605f6270a240edc68b21617Ajay Panicker } 264ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia return (SystemClock.elapsedRealtime() - mScanStartTime) > SCAN_TIMEOUT_MS; 26565e839fa45222955a605f6270a240edc68b21617Ajay Panicker } 26665e839fa45222955a605f6270a240edc68b21617Ajay Panicker 2673d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker // This function truncates the app name for privacy reasons. Apps with 2683d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker // four part package names or more get truncated to three parts, and apps 2693d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker // with three part package names names get truncated to two. Apps with two 2703d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker // or less package names names are untouched. 2713d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker // Examples: one.two.three.four => one.two.three 2723d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker // one.two.three => one.two 2733d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker private String truncateAppName(String name) { 2743d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker String initiator = name; 2753d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker String[] nameSplit = initiator.split("\\."); 2763d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker if (nameSplit.length > 3) { 2773d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker initiator = nameSplit[0] + "." + 2783d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker nameSplit[1] + "." + 2793d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker nameSplit[2]; 2803d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker } else if (nameSplit.length == 3) { 2813d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker initiator = nameSplit[0] + "." + nameSplit[1]; 2823d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker } 2833d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker 2843d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker return initiator; 2853d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker } 2863d69ae195b8d3918958ea703a188cc77e511da6cAjay Panicker 287b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker synchronized void dumpToString(StringBuilder sb) { 288ca4e714ae37050265379fc6604a4e01db9ecae15Ajay Panicker long currTime = SystemClock.elapsedRealtime(); 289b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long maxScan = maxScanTime; 290b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long minScan = minScanTime; 291b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long scanDuration = 0; 292b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 293ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (isScanning()) { 294ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia scanDuration = currTime - mScanStartTime; 295b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 296ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia minScan = Math.min(scanDuration, minScan); 297ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia maxScan = Math.max(scanDuration, maxScan); 298b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 299b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker if (minScan == Long.MAX_VALUE) { 300b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker minScan = 0; 301b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 302b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 303ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia /*TODO: Average scan time can be skewed for 304ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia * multiple scan clients. It will show less than 305ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia * actual value. 306ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia * */ 307b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker long avgScan = 0; 308ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia long totalScanTime = mTotalScanTime + scanDuration; 309b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker if (scansStarted > 0) { 310ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia avgScan = totalScanTime / scansStarted; 311b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 312b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 313b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" " + appName); 314b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker if (isRegistered) sb.append(" (Registered)"); 315c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker 316c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker if (!lastScans.isEmpty()) { 317c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker LastScan lastScan = lastScans.get(lastScans.size() - 1); 318c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker if (lastScan.opportunistic) sb.append(" (Opportunistic)"); 319c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker if (lastScan.background) sb.append(" (Background)"); 320c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker if (lastScan.timeout) sb.append(" (Forced-Opportunistic)"); 321bd11ad34482a898a53bbd9f55bf3607c40c648ecAjay Panicker if (lastScan.filtered) sb.append(" (Filtered)"); 322c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker } 323b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append("\n"); 324b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 325b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" LE scans (started/stopped) : " + 326b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scansStarted + " / " + 327b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker scansStopped + "\n"); 328b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" Scan time in ms (min/max/avg/total): " + 329b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker minScan + " / " + 330b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker maxScan + " / " + 331b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker avgScan + " / " + 332b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker totalScanTime + "\n"); 33312991e68679245a717ba3a94df90c57d438e259eVinay Kalia if (mTotalSuspendTime != 0) { 33412991e68679245a717ba3a94df90c57d438e259eVinay Kalia sb.append(" Total time suspended : " + mTotalSuspendTime + "ms\n"); 33512991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 336c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker sb.append(" Total number of results : " + 337c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker results + "\n"); 338b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 339ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia long currentTime = System.currentTimeMillis(); 340ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia long elapsedRt = SystemClock.elapsedRealtime(); 341c82ac85eacc5607433592f476dbbe73d7670efe1Ajay Panicker if (!lastScans.isEmpty()) { 342ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append(" Last " + lastScans.size() + " scans :\n"); 343b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 344ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia for (int i = 0; i < lastScans.size(); i++) { 345b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker LastScan scan = lastScans.get(i); 346ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia Date timestamp = new Date(currentTime - elapsedRt + scan.timestamp); 347b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" " + dateFormat.format(timestamp) + " - "); 348b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(scan.duration + "ms "); 349b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker if (scan.opportunistic) sb.append("Opp "); 350c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker if (scan.background) sb.append("Back "); 3511fdc7c138db776b02bc751fd7a80c519ea3324d1Ajay Panicker if (scan.timeout) sb.append("Forced "); 352bd11ad34482a898a53bbd9f55bf3607c40c648ecAjay Panicker if (scan.filtered) sb.append("Filter "); 353c30f06668bc683b13319a33775ee8f9def3283c8Ajay Panicker sb.append(scan.results + " results"); 354ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append(" (" + scan.scannerId + ")"); 355ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append("\n"); 35612991e68679245a717ba3a94df90c57d438e259eVinay Kalia if (scan.suspendDuration != 0) { 35712991e68679245a717ba3a94df90c57d438e259eVinay Kalia sb.append(" └" 35812991e68679245a717ba3a94df90c57d438e259eVinay Kalia + " Suspended Time: " + scan.suspendDuration + "ms\n"); 35912991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 360ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia } 361ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia } 362ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia 363ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (!ongoingScans.isEmpty()) { 364ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append(" Ongoing scans :\n"); 365ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia for (Integer key : ongoingScans.keySet()) { 366ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia LastScan scan = ongoingScans.get(key); 367ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia Date timestamp = new Date(currentTime - elapsedRt + scan.timestamp); 368ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append(" " + dateFormat.format(timestamp) + " - "); 369ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append((elapsedRt - scan.timestamp) + "ms "); 370ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (scan.opportunistic) sb.append("Opp "); 371ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (scan.background) sb.append("Back "); 372ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (scan.timeout) sb.append("Forced "); 373ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia if (scan.filtered) sb.append("Filter "); 37412991e68679245a717ba3a94df90c57d438e259eVinay Kalia if (scan.isSuspended) sb.append("Suspended "); 375ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append(scan.results + " results"); 376ff0aaa12c3204523136cc75886add779e4727d00Vinay Kalia sb.append(" (" + scan.scannerId + ")"); 377b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append("\n"); 37812991e68679245a717ba3a94df90c57d438e259eVinay Kalia if (scan.suspendStartTime != 0) { 37912991e68679245a717ba3a94df90c57d438e259eVinay Kalia long duration = scan.suspendDuration 38012991e68679245a717ba3a94df90c57d438e259eVinay Kalia + (scan.isSuspended ? (elapsedRt - scan.suspendStartTime) : 0); 38112991e68679245a717ba3a94df90c57d438e259eVinay Kalia sb.append(" └" 38212991e68679245a717ba3a94df90c57d438e259eVinay Kalia + " Suspended Time: " + duration + "ms\n"); 38312991e68679245a717ba3a94df90c57d438e259eVinay Kalia } 384b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 385b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 386b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 387a86ae2ce4305fb0af5522b3f46513b137e98836fAjay Panicker ContextMap.App appEntry = contextMap.getByName(appName); 388a86ae2ce4305fb0af5522b3f46513b137e98836fAjay Panicker if (appEntry != null && isRegistered) { 389b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" Application ID : " + 390b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker appEntry.id + "\n"); 391b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" UUID : " + 392b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker appEntry.uuid + "\n"); 393b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 394b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker List<ContextMap.Connection> connections = 395b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker contextMap.getConnectionByApp(appEntry.id); 396b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 397b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" Connections: " + connections.size() + "\n"); 398b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker 399b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker Iterator<ContextMap.Connection> ii = connections.iterator(); 400b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker while(ii.hasNext()) { 401b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker ContextMap.Connection connection = ii.next(); 402ca4e714ae37050265379fc6604a4e01db9ecae15Ajay Panicker long connectionTime = SystemClock.elapsedRealtime() - connection.startTime; 403b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append(" " + connection.connId + ": " + 404b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker connection.address + " " + connectionTime + "ms\n"); 405b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 406b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 407b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker sb.append("\n"); 408b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker } 409b7af521b6c2d1ccaaea687207dfbcd0c34489a3cAjay Panicker} 410