Addition of GNSS key performance indicator logs
Bug: 35963181 Test: Manual Change-Id: Ibbc8986eb5c52b8e0065b5fd2fdb8579eda11949
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* 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.internal.location.gnssmetrics;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import android.util.Base64;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.location.nano.GnssLogsProto.GnssLog;
|
||||
|
||||
/**
|
||||
* GnssMetrics: Is used for logging GNSS metrics
|
||||
* @hide
|
||||
*/
|
||||
public class GnssMetrics {
|
||||
|
||||
/** Default time between location fixes (in millisecs) */
|
||||
private static final int DEFAULT_TIME_BETWEEN_FIXES_MILLISECS = 1000;
|
||||
|
||||
/* The time since boot when logging started */
|
||||
private String logStartInElapsedRealTime;
|
||||
|
||||
/** Constructor */
|
||||
public GnssMetrics() {
|
||||
locationFailureStatistics = new Statistics();
|
||||
timeToFirstFixSecStatistics = new Statistics();
|
||||
positionAccuracyMeterStatistics = new Statistics();
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the status of a location report received from the HAL
|
||||
*
|
||||
* @param isSuccessful
|
||||
*/
|
||||
public void logReceivedLocationStatus(boolean isSuccessful) {
|
||||
if (!isSuccessful) {
|
||||
locationFailureStatistics.addItem(1.0);
|
||||
return;
|
||||
}
|
||||
locationFailureStatistics.addItem(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs missed reports
|
||||
*
|
||||
* @param desiredTimeBetweenFixesMilliSeconds
|
||||
* @param actualTimeBetweenFixesMilliSeconds
|
||||
*/
|
||||
public void logMissedReports(int desiredTimeBetweenFixesMilliSeconds,
|
||||
int actualTimeBetweenFixesMilliSeconds) {
|
||||
int numReportMissed = (actualTimeBetweenFixesMilliSeconds /
|
||||
Math.max(DEFAULT_TIME_BETWEEN_FIXES_MILLISECS, desiredTimeBetweenFixesMilliSeconds)) - 1;
|
||||
if (numReportMissed > 0) {
|
||||
for (int i = 0; i < numReportMissed; i++) {
|
||||
locationFailureStatistics.addItem(1.0);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs time to first fix
|
||||
*
|
||||
* @param timeToFirstFixMilliSeconds
|
||||
*/
|
||||
public void logTimeToFirstFixMilliSecs(int timeToFirstFixMilliSeconds) {
|
||||
timeToFirstFixSecStatistics.addItem((double) (timeToFirstFixMilliSeconds/1000));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs position accuracy
|
||||
*
|
||||
* @param positionAccuracyMeters
|
||||
*/
|
||||
public void logPositionAccuracyMeters(float positionAccuracyMeters) {
|
||||
positionAccuracyMeterStatistics.addItem((double) positionAccuracyMeters);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps GNSS metrics as a proto string
|
||||
* @return
|
||||
*/
|
||||
public String dumpGnssMetricsAsProtoString() {
|
||||
GnssLog msg = new GnssLog();
|
||||
if (locationFailureStatistics.getCount() > 0) {
|
||||
msg.numLocationReportProcessed = locationFailureStatistics.getCount();
|
||||
msg.percentageLocationFailure = (int) (100.0 * locationFailureStatistics.getMean());
|
||||
}
|
||||
if (timeToFirstFixSecStatistics.getCount() > 0) {
|
||||
msg.numTimeToFirstFixProcessed = timeToFirstFixSecStatistics.getCount();
|
||||
msg.meanTimeToFirstFixSecs = (int) timeToFirstFixSecStatistics.getMean();
|
||||
msg.standardDeviationTimeToFirstFixSecs
|
||||
= (int) timeToFirstFixSecStatistics.getStandardDeviation();
|
||||
}
|
||||
if (positionAccuracyMeterStatistics.getCount() > 0) {
|
||||
msg.numPositionAccuracyProcessed = positionAccuracyMeterStatistics.getCount();
|
||||
msg.meanPositionAccuracyMeters = (int) positionAccuracyMeterStatistics.getMean();
|
||||
msg.standardDeviationPositionAccuracyMeters
|
||||
= (int) positionAccuracyMeterStatistics.getStandardDeviation();
|
||||
}
|
||||
String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT);
|
||||
reset();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps GNSS Metrics as text
|
||||
*
|
||||
* @return GNSS Metrics
|
||||
*/
|
||||
public String dumpGnssMetricsAsText() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("GNSS_KPI_START").append('\n');
|
||||
s.append(" KPI logging start time: ").append(logStartInElapsedRealTime).append("\n");
|
||||
s.append(" KPI logging end time: ");
|
||||
TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
|
||||
s.append("\n");
|
||||
s.append(" Number of location reports: ").append(
|
||||
locationFailureStatistics.getCount()).append("\n");
|
||||
if (locationFailureStatistics.getCount() > 0) {
|
||||
s.append(" Percentage location failure: ").append(
|
||||
100.0 * locationFailureStatistics.getMean()).append("\n");
|
||||
}
|
||||
s.append(" Number of TTFF reports: ").append(
|
||||
timeToFirstFixSecStatistics.getCount()).append("\n");
|
||||
if (timeToFirstFixSecStatistics.getCount() > 0) {
|
||||
s.append(" TTFF mean (sec): ").append(timeToFirstFixSecStatistics.getMean()).append("\n");
|
||||
s.append(" TTFF standard deviation (sec): ").append(
|
||||
timeToFirstFixSecStatistics.getStandardDeviation()).append("\n");
|
||||
}
|
||||
s.append(" Number of position accuracy reports: ").append(
|
||||
positionAccuracyMeterStatistics.getCount()).append("\n");
|
||||
if (positionAccuracyMeterStatistics.getCount() > 0) {
|
||||
s.append(" Position accuracy mean (m): ").append(
|
||||
positionAccuracyMeterStatistics.getMean()).append("\n");
|
||||
s.append(" Position accuracy standard deviation (m): ").append(
|
||||
positionAccuracyMeterStatistics.getStandardDeviation()).append("\n");
|
||||
}
|
||||
s.append("GNSS_KPI_END").append("\n");
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/** Class for storing statistics */
|
||||
private class Statistics {
|
||||
|
||||
/** Resets statistics */
|
||||
public void reset() {
|
||||
count = 0;
|
||||
sum = 0.0;
|
||||
sumSquare = 0.0;
|
||||
}
|
||||
|
||||
/** Adds an item */
|
||||
public void addItem(double item) {
|
||||
count++;
|
||||
sum += item;
|
||||
sumSquare += item * item;
|
||||
}
|
||||
|
||||
/** Returns number of items added */
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/** Returns mean */
|
||||
public double getMean() {
|
||||
return sum/count;
|
||||
}
|
||||
|
||||
/** Returns standard deviation */
|
||||
public double getStandardDeviation() {
|
||||
double m = sum/count;
|
||||
m = m * m;
|
||||
double v = sumSquare/count;
|
||||
if (v > m) {
|
||||
return Math.sqrt(v - m);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int count;
|
||||
private double sum;
|
||||
private double sumSquare;
|
||||
}
|
||||
|
||||
/** Location failure statistics */
|
||||
private Statistics locationFailureStatistics;
|
||||
|
||||
/** Time to first fix statistics */
|
||||
private Statistics timeToFirstFixSecStatistics;
|
||||
|
||||
/** Position accuracy statistics */
|
||||
private Statistics positionAccuracyMeterStatistics;
|
||||
|
||||
/**
|
||||
* Resets GNSS metrics
|
||||
*/
|
||||
private void reset() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
|
||||
logStartInElapsedRealTime = s.toString();
|
||||
locationFailureStatistics.reset();
|
||||
timeToFirstFixSecStatistics.reset();
|
||||
positionAccuracyMeterStatistics.reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
36
proto/src/gnss.proto
Normal file
36
proto/src/gnss.proto
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
// Author: siddharthr@google.com (Siddharth Ray)
|
||||
// Protos for uploading GNSS metrics.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package clearcut.connectivity;
|
||||
|
||||
option java_package = "com.android.internal.location";
|
||||
option java_outer_classname = "GnssLogsProto";
|
||||
|
||||
message GnssLog {
|
||||
// Number of location reports processed
|
||||
optional int32 num_location_report_processed = 1;
|
||||
|
||||
// Location failure (in percent)
|
||||
optional int32 percentage_location_failure = 2;
|
||||
|
||||
// Number of time to first fix processed
|
||||
optional int32 num_time_to_first_fix_processed = 3;
|
||||
|
||||
// Mean time to first fix (in seconds)
|
||||
optional int32 mean_time_to_first_fix_secs = 4;
|
||||
|
||||
// Standard deviation of time to first fix (in seconds)
|
||||
optional int32 standard_deviation_time_to_first_fix_secs = 5;
|
||||
|
||||
// Number of position accuracy processed
|
||||
optional int32 num_position_accuracy_processed = 6;
|
||||
|
||||
// Mean position accuracy (in meters)
|
||||
optional int32 mean_position_accuracy_meters = 7;
|
||||
|
||||
// Standard deviation of position accuracy (in meters)
|
||||
optional int32 standard_deviation_position_accuracy_meters = 8;
|
||||
}
|
||||
@@ -241,6 +241,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
|
||||
|
||||
private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
|
||||
private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
|
||||
private IBatchedLocationCallback mGnssBatchingCallback;
|
||||
private LinkedCallback mGnssBatchingDeathCallback;
|
||||
private boolean mGnssBatchingInProgress = false;
|
||||
@@ -584,6 +585,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
mLocationHandler.getLooper());
|
||||
mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
|
||||
mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
|
||||
mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
|
||||
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
|
||||
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
|
||||
addProviderLocked(gnssProvider);
|
||||
@@ -3030,6 +3032,12 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
|
||||
|
||||
synchronized (mLock) {
|
||||
if (args.length > 0 && args[0].equals("--gnssmetrics")) {
|
||||
if (mGnssMetricsProvider != null) {
|
||||
pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
pw.println("Current Location Manager state:");
|
||||
pw.println(" Location Listeners:");
|
||||
for (Receiver receiver : mReceivers.values()) {
|
||||
|
||||
@@ -77,10 +77,12 @@ import android.util.NtpTrustedTime;
|
||||
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.location.gnssmetrics.GnssMetrics;
|
||||
import com.android.internal.location.GpsNetInitiatedHandler;
|
||||
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
import com.android.server.power.BatterySaverPolicy;
|
||||
import com.android.server.power.BatterySaverPolicy.ServiceType;
|
||||
|
||||
@@ -412,6 +414,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
|
||||
private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
|
||||
private boolean mItarSpeedLimitExceeded = false;
|
||||
|
||||
// GNSS Metrics
|
||||
private GnssMetrics mGnssMetrics;
|
||||
|
||||
private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
|
||||
@Override
|
||||
public void registerGnssStatusCallback(IGnssStatusListener callback) {
|
||||
@@ -768,6 +773,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
|
||||
return isEnabled();
|
||||
}
|
||||
};
|
||||
mGnssMetrics = new GnssMetrics();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1477,6 +1483,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
|
||||
if (mItarSpeedLimitExceeded) {
|
||||
Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
|
||||
" GPS/GNSS Navigation output blocked.");
|
||||
mGnssMetrics.logReceivedLocationStatus(false);
|
||||
return; // No output of location allowed
|
||||
}
|
||||
|
||||
@@ -1496,11 +1503,23 @@ public class GnssLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
mGnssMetrics.logReceivedLocationStatus(hasLatLong);
|
||||
if (hasLatLong) {
|
||||
if (location.hasAccuracy()) {
|
||||
mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
|
||||
}
|
||||
if (mTimeToFirstFix > 0) {
|
||||
int timeBetweenFixes = (int) (System.currentTimeMillis() - mLastFixTime);
|
||||
mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
|
||||
}
|
||||
}
|
||||
|
||||
mLastFixTime = System.currentTimeMillis();
|
||||
// report time to first fix
|
||||
if (mTimeToFirstFix == 0 && hasLatLong) {
|
||||
mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
|
||||
if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
|
||||
mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
|
||||
|
||||
// notify status listeners
|
||||
mListenerHelper.onFirstFix(mTimeToFirstFix);
|
||||
@@ -1782,6 +1801,25 @@ public class GnssLocationProvider implements LocationProviderInterface {
|
||||
};
|
||||
}
|
||||
|
||||
public interface GnssMetricsProvider {
|
||||
/**
|
||||
* Returns GNSS metrics as proto string
|
||||
*/
|
||||
String getGnssMetricsAsProtoString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public GnssMetricsProvider getGnssMetricsProvider() {
|
||||
return new GnssMetricsProvider() {
|
||||
@Override
|
||||
public String getGnssMetricsAsProtoString() {
|
||||
return mGnssMetrics.dumpGnssMetricsAsProtoString();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Batching if enabled
|
||||
*/
|
||||
@@ -2411,6 +2449,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
@@ -2427,10 +2467,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
|
||||
if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
|
||||
if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
|
||||
s.append(")\n");
|
||||
|
||||
s.append(" internal state: ").append(native_get_internal_state());
|
||||
s.append(mGnssMetrics.dumpGnssMetricsAsText());
|
||||
s.append(" native internal state: ").append(native_get_internal_state());
|
||||
s.append("\n");
|
||||
|
||||
pw.append(s);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user