Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb608c89 authored by Siddharth Ray's avatar Siddharth Ray
Browse files

Addition of GNSS key performance indicator logs

Bug: 35963181
Test: Manual
Change-Id: Ibbc8986eb5c52b8e0065b5fd2fdb8579eda11949
parent 0eea46e0
Loading
Loading
Loading
Loading
+226 −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.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;
  }
}
 No newline at end of file

proto/src/gnss.proto

0 → 100644
+36 −0
Original line number Diff line number Diff line
// 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;
}
 No newline at end of file
+8 −0
Original line number Diff line number Diff line
@@ -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()) {
+42 −3
Original line number Diff line number Diff line
@@ -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);
    }