1bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray/* 2bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Copyright (C) 2016 The Android Open Source Project 3bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 4bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Licensed under the Apache License, Version 2.0 (the "License"); 5bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * you may not use this file except in compliance with the License. 6bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * You may obtain a copy of the License at 7bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 8bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * http://www.apache.org/licenses/LICENSE-2.0 9bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 10bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Unless required by applicable law or agreed to in writing, software 11bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * distributed under the License is distributed on an "AS IS" BASIS, 12bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * See the License for the specific language governing permissions and 14bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * limitations under the License. 15bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 16bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 17bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Raypackage com.android.internal.location.gnssmetrics; 18bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 19bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Rayimport android.os.SystemClock; 20d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Rayimport android.os.connectivity.GpsBatteryStats; 21bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 22d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Rayimport android.text.format.DateUtils; 23bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Rayimport android.util.Base64; 2478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Rayimport android.util.Log; 25bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Rayimport android.util.TimeUtils; 26bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 27168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Rayimport java.util.Arrays; 28168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray 2978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Rayimport com.android.internal.app.IBatteryStats; 30bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Rayimport com.android.internal.location.nano.GnssLogsProto.GnssLog; 31d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Rayimport com.android.internal.location.nano.GnssLogsProto.PowerMetrics; 32bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 33bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray/** 34bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * GnssMetrics: Is used for logging GNSS metrics 35bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @hide 36bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 37bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Raypublic class GnssMetrics { 38bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 3978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray private static final String TAG = GnssMetrics.class.getSimpleName(); 4078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 4178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* Constant which indicates GPS signal quality is poor */ 4278ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray public static final int GPS_SIGNAL_QUALITY_POOR = 0; 4378ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 4478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* Constant which indicates GPS signal quality is good */ 4578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray public static final int GPS_SIGNAL_QUALITY_GOOD = 1; 4678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 4778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* Number of GPS signal quality levels */ 4878ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray public static final int NUM_GPS_SIGNAL_QUALITY_LEVELS = GPS_SIGNAL_QUALITY_GOOD + 1; 4978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 50bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Default time between location fixes (in millisecs) */ 51bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private static final int DEFAULT_TIME_BETWEEN_FIXES_MILLISECS = 1000; 52bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 53bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /* The time since boot when logging started */ 54bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private String logStartInElapsedRealTime; 55bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 5678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* GNSS power metrics */ 5778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray private GnssPowerMetrics mGnssPowerMetrics; 5878ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 59bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Constructor */ 6078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray public GnssMetrics(IBatteryStats stats) { 6178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray mGnssPowerMetrics = new GnssPowerMetrics(stats); 62bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray locationFailureStatistics = new Statistics(); 63bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray timeToFirstFixSecStatistics = new Statistics(); 64bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray positionAccuracyMeterStatistics = new Statistics(); 65168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray topFourAverageCn0Statistics = new Statistics(); 66bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray reset(); 67bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 68bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 69bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** 70bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Logs the status of a location report received from the HAL 71bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 72bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @param isSuccessful 73bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 74bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public void logReceivedLocationStatus(boolean isSuccessful) { 75bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (!isSuccessful) { 76bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray locationFailureStatistics.addItem(1.0); 77bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return; 78bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 79bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray locationFailureStatistics.addItem(0.0); 80bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return; 81bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 82bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 83bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** 84bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Logs missed reports 85bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 86bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @param desiredTimeBetweenFixesMilliSeconds 87bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @param actualTimeBetweenFixesMilliSeconds 88bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 89bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public void logMissedReports(int desiredTimeBetweenFixesMilliSeconds, 90bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray int actualTimeBetweenFixesMilliSeconds) { 91bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray int numReportMissed = (actualTimeBetweenFixesMilliSeconds / 92bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray Math.max(DEFAULT_TIME_BETWEEN_FIXES_MILLISECS, desiredTimeBetweenFixesMilliSeconds)) - 1; 93bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (numReportMissed > 0) { 94bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray for (int i = 0; i < numReportMissed; i++) { 95bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray locationFailureStatistics.addItem(1.0); 96bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 97bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 98bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return; 99bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 100bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 101bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** 102bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Logs time to first fix 103bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 104bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @param timeToFirstFixMilliSeconds 105bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 106bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public void logTimeToFirstFixMilliSecs(int timeToFirstFixMilliSeconds) { 107bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray timeToFirstFixSecStatistics.addItem((double) (timeToFirstFixMilliSeconds/1000)); 108bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return; 109bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 110bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 111bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** 112bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Logs position accuracy 113bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 114bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @param positionAccuracyMeters 115bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 116bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public void logPositionAccuracyMeters(float positionAccuracyMeters) { 117bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray positionAccuracyMeterStatistics.addItem((double) positionAccuracyMeters); 118bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return; 119bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 120bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 121168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray /* 122168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray * Logs CN0 when at least 4 SVs are available 123168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray * 124168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray */ 125168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray public void logCn0(float[] cn0s, int numSv) { 12678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray if (numSv == 0 || cn0s == null || cn0s.length == 0 || cn0s.length < numSv) { 12778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray if (numSv == 0) { 12878ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray mGnssPowerMetrics.reportSignalQuality(null, 0); 12978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 130168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray return; 131168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray } 132168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray float[] cn0Array = Arrays.copyOf(cn0s, numSv); 133168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray Arrays.sort(cn0Array); 13478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray mGnssPowerMetrics.reportSignalQuality(cn0Array, numSv); 13578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray if (numSv < 4) { 13678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray return; 13778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 138168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray if (cn0Array[numSv - 4] > 0.0) { 139168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray double top4AvgCn0 = 0.0; 140168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray for (int i = numSv - 4; i < numSv; i++) { 141168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray top4AvgCn0 += (double) cn0Array[i]; 142168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray } 143168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray top4AvgCn0 /= 4; 144168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray topFourAverageCn0Statistics.addItem(top4AvgCn0); 145168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray } 146168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray return; 147168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray } 148168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray 149bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** 150bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Dumps GNSS metrics as a proto string 151bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @return 152bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 153bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public String dumpGnssMetricsAsProtoString() { 154bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray GnssLog msg = new GnssLog(); 155bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (locationFailureStatistics.getCount() > 0) { 156bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.numLocationReportProcessed = locationFailureStatistics.getCount(); 157bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.percentageLocationFailure = (int) (100.0 * locationFailureStatistics.getMean()); 158bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 159bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (timeToFirstFixSecStatistics.getCount() > 0) { 160bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.numTimeToFirstFixProcessed = timeToFirstFixSecStatistics.getCount(); 161bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.meanTimeToFirstFixSecs = (int) timeToFirstFixSecStatistics.getMean(); 162bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.standardDeviationTimeToFirstFixSecs 163bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray = (int) timeToFirstFixSecStatistics.getStandardDeviation(); 164bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 165bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (positionAccuracyMeterStatistics.getCount() > 0) { 166bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.numPositionAccuracyProcessed = positionAccuracyMeterStatistics.getCount(); 167bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.meanPositionAccuracyMeters = (int) positionAccuracyMeterStatistics.getMean(); 168bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray msg.standardDeviationPositionAccuracyMeters 169bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray = (int) positionAccuracyMeterStatistics.getStandardDeviation(); 170bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 171168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray if (topFourAverageCn0Statistics.getCount() > 0) { 172168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray msg.numTopFourAverageCn0Processed = topFourAverageCn0Statistics.getCount(); 173168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray msg.meanTopFourAverageCn0DbHz = topFourAverageCn0Statistics.getMean(); 174168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray msg.standardDeviationTopFourAverageCn0DbHz 175168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray = topFourAverageCn0Statistics.getStandardDeviation(); 176168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray } 177d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray msg.powerMetrics = mGnssPowerMetrics.buildProto(); 178bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT); 179bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray reset(); 180bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return s; 181bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 182bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 183bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** 184bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Dumps GNSS Metrics as text 185bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * 186bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * @return GNSS Metrics 187bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 188bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public String dumpGnssMetricsAsText() { 189bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray StringBuilder s = new StringBuilder(); 190bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append("GNSS_KPI_START").append('\n'); 191bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" KPI logging start time: ").append(logStartInElapsedRealTime).append("\n"); 192bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" KPI logging end time: "); 193bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s); 194bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append("\n"); 195bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" Number of location reports: ").append( 196bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray locationFailureStatistics.getCount()).append("\n"); 197bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (locationFailureStatistics.getCount() > 0) { 198bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" Percentage location failure: ").append( 199bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 100.0 * locationFailureStatistics.getMean()).append("\n"); 200bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 201bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" Number of TTFF reports: ").append( 202bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray timeToFirstFixSecStatistics.getCount()).append("\n"); 203bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (timeToFirstFixSecStatistics.getCount() > 0) { 204bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" TTFF mean (sec): ").append(timeToFirstFixSecStatistics.getMean()).append("\n"); 205bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" TTFF standard deviation (sec): ").append( 206bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray timeToFirstFixSecStatistics.getStandardDeviation()).append("\n"); 207bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 208bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" Number of position accuracy reports: ").append( 209bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray positionAccuracyMeterStatistics.getCount()).append("\n"); 210bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (positionAccuracyMeterStatistics.getCount() > 0) { 211bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" Position accuracy mean (m): ").append( 212bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray positionAccuracyMeterStatistics.getMean()).append("\n"); 213bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append(" Position accuracy standard deviation (m): ").append( 214bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray positionAccuracyMeterStatistics.getStandardDeviation()).append("\n"); 215bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 216168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray s.append(" Number of CN0 reports: ").append( 217168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray topFourAverageCn0Statistics.getCount()).append("\n"); 218168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray if (topFourAverageCn0Statistics.getCount() > 0) { 219168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray s.append(" Top 4 Avg CN0 mean (dB-Hz): ").append( 220168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray topFourAverageCn0Statistics.getMean()).append("\n"); 221168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray s.append(" Top 4 Avg CN0 standard deviation (dB-Hz): ").append( 222168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray topFourAverageCn0Statistics.getStandardDeviation()).append("\n"); 223168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray } 224bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray s.append("GNSS_KPI_END").append("\n"); 225d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats(); 226d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray if (stats != null) { 227b30c0b7477d9faf3697f6b33b9cba4f900d2bc06Siddharth Ray s.append("Power Metrics").append("\n"); 228b30c0b7477d9faf3697f6b33b9cba4f900d2bc06Siddharth Ray s.append(" Time on battery (min): " 229b30c0b7477d9faf3697f6b33b9cba4f900d2bc06Siddharth Ray + stats.getLoggingDurationMs() / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n"); 230d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray long[] t = stats.getTimeInGpsSignalQualityLevel(); 231d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray if (t != null && t.length == NUM_GPS_SIGNAL_QUALITY_LEVELS) { 232d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray s.append(" Amount of time (while on battery) Top 4 Avg CN0 > " + 233d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray Double.toString(GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) + 234d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray " dB-Hz (min): ").append(t[1] / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n"); 235d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray s.append(" Amount of time (while on battery) Top 4 Avg CN0 <= " + 236d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray Double.toString(GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) + 237d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray " dB-Hz (min): ").append(t[0] / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n"); 238d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } 239d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray s.append(" Energy consumed while on battery (mAh): ").append( 240d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray stats.getEnergyConsumedMaMs() / ((double) DateUtils.HOUR_IN_MILLIS)).append("\n"); 241d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } 242bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return s.toString(); 243bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 244bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 245bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Class for storing statistics */ 246bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private class Statistics { 247bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 248bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Resets statistics */ 249bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public void reset() { 250bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray count = 0; 251bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray sum = 0.0; 252bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray sumSquare = 0.0; 253bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 254bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 255bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Adds an item */ 256bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public void addItem(double item) { 257bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray count++; 258bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray sum += item; 259bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray sumSquare += item * item; 260bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 261bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 262bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Returns number of items added */ 263bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public int getCount() { 264bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return count; 265bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 266bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 267bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Returns mean */ 268bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public double getMean() { 269bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return sum/count; 270bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 271bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 272bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Returns standard deviation */ 273bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray public double getStandardDeviation() { 274bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray double m = sum/count; 275bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray m = m * m; 276bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray double v = sumSquare/count; 277bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray if (v > m) { 278bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return Math.sqrt(v - m); 279bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 280bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return 0; 281bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 282bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 283bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private int count; 284bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private double sum; 285bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private double sumSquare; 286bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 287bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 288bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Location failure statistics */ 289bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private Statistics locationFailureStatistics; 290bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 291bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Time to first fix statistics */ 292bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private Statistics timeToFirstFixSecStatistics; 293bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 294bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** Position accuracy statistics */ 295bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private Statistics positionAccuracyMeterStatistics; 296bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray 297168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray /** Top 4 average CN0 statistics */ 298168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray private Statistics topFourAverageCn0Statistics; 299168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray 300bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray /** 301bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray * Resets GNSS metrics 302bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray */ 303bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray private void reset() { 304bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray StringBuilder s = new StringBuilder(); 305bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s); 306bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray logStartInElapsedRealTime = s.toString(); 307bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray locationFailureStatistics.reset(); 308bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray timeToFirstFixSecStatistics.reset(); 309bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray positionAccuracyMeterStatistics.reset(); 310168f12a056f7ef3adb9f9d52aaa51977b4082213Siddharth Ray topFourAverageCn0Statistics.reset(); 311bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray return; 312bb608c8958a96b450094417482ba05126ce0c8f0Siddharth Ray } 31378ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 31478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* Class for handling GNSS power related metrics */ 31578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray private class GnssPowerMetrics { 31678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 31778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* Threshold for Top Four Average CN0 below which GNSS signal quality is declared poor */ 318d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray public static final double POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ = 20.0; 31978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 32078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* Minimum change in Top Four Average CN0 needed to trigger a report */ 32178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray private static final double REPORTING_THRESHOLD_DB_HZ = 1.0; 32278ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 32378ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* BatteryStats API */ 32478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray private final IBatteryStats mBatteryStats; 32578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 32678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /* Last reported Top Four Average CN0 */ 32778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray private double mLastAverageCn0; 32878ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 32978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray public GnssPowerMetrics(IBatteryStats stats) { 33078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray mBatteryStats = stats; 33178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray // Used to initialize the variable to a very small value (unachievable in practice) so that 33278ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray // the first CNO report will trigger an update to BatteryStats 33378ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray mLastAverageCn0 = -100.0; 33478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 33578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 33678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /** 337d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray * Builds power metrics proto buf. This is included in the gnss proto buf. 338d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray * @return PowerMetrics 339d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray */ 340d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray public PowerMetrics buildProto() { 341d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray PowerMetrics p = new PowerMetrics(); 342d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats(); 343d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray if (stats != null) { 344d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray p.loggingDurationMs = stats.getLoggingDurationMs(); 345d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray p.energyConsumedMah = stats.getEnergyConsumedMaMs() / ((double) DateUtils.HOUR_IN_MILLIS); 346d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray long[] t = stats.getTimeInGpsSignalQualityLevel(); 347d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray p.timeInSignalQualityLevelMs = new long[t.length]; 348d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray for (int i = 0; i < t.length; i++) { 349d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray p.timeInSignalQualityLevelMs[i] = t[i]; 350d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } 351d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } 352d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray return p; 353d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } 354d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray 355d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray /** 356d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray * Returns the GPS power stats 357d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray * @return GpsBatteryStats 358d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray */ 359d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray public GpsBatteryStats getGpsBatteryStats() { 360d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray try { 361d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray return mBatteryStats.getGpsBatteryStats(); 362d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } catch (Exception e) { 363d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray Log.w(TAG, "Exception", e); 364d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray return null; 365d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } 366d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray } 367d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray 368d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray /** 36978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray * Reports signal quality to BatteryStats. Signal quality is based on Top four average CN0. If 37078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray * the number of SVs seen is less than 4, then signal quality is the average CN0. 37178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray * Changes are reported only if the average CN0 changes by more than REPORTING_THRESHOLD_DB_HZ. 37278ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray */ 37378ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray public void reportSignalQuality(float[] ascendingCN0Array, int numSv) { 37478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray double avgCn0 = 0.0; 37578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray if (numSv > 0) { 37678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray for (int i = Math.max(0, numSv - 4); i < numSv; i++) { 37778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray avgCn0 += (double) ascendingCN0Array[i]; 37878ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 37978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray avgCn0 /= Math.min(numSv, 4); 38078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 38178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray if (Math.abs(avgCn0 - mLastAverageCn0) < REPORTING_THRESHOLD_DB_HZ) { 38278ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray return; 38378ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 38478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray try { 38578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray mBatteryStats.noteGpsSignalQuality(getSignalLevel(avgCn0)); 38678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray mLastAverageCn0 = avgCn0; 38778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } catch (Exception e) { 38878ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray Log.w(TAG, "Exception", e); 38978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 39078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray return; 39178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 39278ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray 39378ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray /** 39478ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray * Obtains signal level based on CN0 39578ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray */ 39678ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray private int getSignalLevel(double cn0) { 39778ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray if (cn0 > POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) { 39878ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray return GnssMetrics.GPS_SIGNAL_QUALITY_GOOD; 39978ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 40078ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray return GnssMetrics.GPS_SIGNAL_QUALITY_POOR; 40178ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 40278ccaf5d287cbb6bd214913d72653aa74ecfef76Siddharth Ray } 403d679a767b49ea4bd4aee83a4bc2425fdce67b950Siddharth Ray} 404