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

Commit e7baef38 authored by Yu-Han Yang's avatar Yu-Han Yang
Browse files

Implement requestLocationCb

- For network location, send a single request and inject it.

- For fused location, send a 'streaming' request for 30 sec duration and
1 Hz updates.

Bug: 72405645

Test: locally added a cts in LocationManager to trigger the flow.

Change-Id: I8ce73976e4e62836037bf3563f239719c9a89305
parent e8b3a537
Loading
Loading
Loading
Loading
+154 −23
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.location;

import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -28,11 +29,11 @@ import android.hardware.location.GeofenceHardware;
import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
import android.location.FusedBatchOptions;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
import android.location.GnssStatus;
import android.location.IGnssStatusListener;
import android.location.IGnssStatusProvider;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
import android.location.IGpsGeofenceHardware;
import android.location.ILocationManager;
import android.location.INetInitiatedListener;
@@ -48,16 +49,16 @@ import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -68,25 +69,21 @@ import android.os.WorkSource.WorkChain;
import android.provider.Settings;
import android.provider.Telephony.Carriers;
import android.provider.Telephony.Sms.Intents;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import android.telephony.CarrierConfigManager;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
import android.util.Log;
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 libcore.io.IoUtils;

import com.android.internal.location.gnssmetrics.GnssMetrics;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -97,11 +94,13 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Map;
import java.util.HashMap;

import libcore.io.IoUtils;

/**
 * A GNSS implementation of LocationProvider used by LocationManager.
@@ -215,6 +214,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
    private static final int INITIALIZE_HANDLER = 13;
    private static final int REQUEST_SUPL_CONNECTION = 14;
    private static final int RELEASE_SUPL_CONNECTION = 15;
    private static final int REQUEST_LOCATION = 16;

    // Request setid
    private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
@@ -248,6 +248,13 @@ public class GnssLocationProvider implements LocationProviderInterface {
    private static final int TCP_MIN_PORT = 0;
    private static final int TCP_MAX_PORT = 0xffff;

    // 10 seconds.
    private static final long LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS = 10 * 1000;
    // 1 second, or 1 Hz frequency.
    private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
    // 30 seconds.
    private static final long LOCATION_UPDATE_DURATION_MILLIS = 30 * 1000;

    /** simpler wrapper for ProviderRequest + Worksource */
    private static class GpsRequest {
        public ProviderRequest request;
@@ -373,6 +380,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
    private final GnssStatusListenerHelper mListenerHelper;
    private final GnssMeasurementsProvider mGnssMeasurementsProvider;
    private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
    private final FusedLocationListener mFusedLocationListener = new FusedLocationListener();
    private static int sNumFusedLocationUpdatesRequests = 0;

    // Handler for processing events
    private Handler mHandler;
@@ -1038,6 +1047,89 @@ public class GnssLocationProvider implements LocationProviderInterface {
        });
    }

    private void handleRequestLocation(boolean independentFromGnss) {
        if (isRequestLocationRateLimited()) {
            if (DEBUG) {
                Log.d(TAG, "RequestLocation is denied due to too frequent requests.");
            }
            return;
        }

        LocationManager locationManager = (LocationManager) mContext.getSystemService(
                Context.LOCATION_SERVICE);

        if (independentFromGnss) {
            // For fast GNSS TTFF
            Location networkLocation = getLastFreshLocation(locationManager,
                    LocationManager.NETWORK_PROVIDER);
            if (networkLocation != null) {
                handleUpdateLocation(networkLocation);
                return;
            }
            locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER,
                    new NetworkLocationListener(),
                    mHandler.getLooper());
        } else {
            // For Device-Based Hybrid (E911)
            locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER,
                    LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
                    mFusedLocationListener, mHandler.getLooper());
            sNumFusedLocationUpdatesRequests++;
            mHandler.postDelayed(() -> {
                if (--sNumFusedLocationUpdatesRequests == 0) {
                    locationManager.removeUpdates(mFusedLocationListener);
                }
            }, LOCATION_UPDATE_DURATION_MILLIS);
        }
    }

    private void injectBestLocation(Location location) {
        int gnssLocationFlags = LOCATION_HAS_LAT_LONG |
                (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) |
                (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) |
                (location.hasBearing() ? LOCATION_HAS_BEARING : 0) |
                (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) |
                (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) |
                (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) |
                (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0);

        double latitudeDegrees = location.getLatitude();
        double longitudeDegrees = location.getLongitude();
        double altitudeMeters = location.getAltitude();
        float speedMetersPerSec = location.getSpeed();
        float bearingDegrees = location.getBearing();
        float horizontalAccuracyMeters = location.getAccuracy();
        float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
        float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
        float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
        long timestamp = location.getTime();
        native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
                altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
                verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
                timestamp);
    }

    /**
     * Get the last fresh location.
     *
     * Return null if the last location is not available or not fresh.
     */
    private @Nullable
    Location getLastFreshLocation(LocationManager locationManager, String provider) {
        Location location = locationManager.getLastKnownLocation(provider);
        if (location != null && System.currentTimeMillis() - location.getTime()
                < LOCATION_TIME_FRESHNESS_THESHOLD_MILLIS) {
            return location;
        }
        return null;
    }

    /** Returns true if the location request is too frequent. */
    private boolean isRequestLocationRateLimited() {
        // TODO(b/73198123): implement exponential backoff.
        return false;
    }

    private void handleDownloadXtraData() {
        if (!mSupportsXtra) {
            // native code reports xtra not supported, don't try
@@ -2243,6 +2335,16 @@ public class GnssLocationProvider implements LocationProviderInterface {
        native_agps_set_id(type, data);
    }

    /**
     * Called from native code to request location info.
     */
    private void requestLocation(boolean independentFromGnss) {
        if (DEBUG) {
            Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss);
        }
        sendMessage(REQUEST_LOCATION, 0, independentFromGnss);
    }

    /**
     * Called from native code to request utc time info
     */
@@ -2254,7 +2356,6 @@ public class GnssLocationProvider implements LocationProviderInterface {
    /**
     * Called from native code to request reference location info
     */

    private void requestRefLocation() {
        TelephonyManager phone = (TelephonyManager)
                mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -2330,6 +2431,9 @@ public class GnssLocationProvider implements LocationProviderInterface {
                case INJECT_NTP_TIME:
                    handleInjectNtpTime();
                    break;
                case REQUEST_LOCATION:
                    handleRequestLocation((boolean) msg.obj);
                    break;
                case DOWNLOAD_XTRA_DATA:
                    handleDownloadXtraData();
                    break;
@@ -2455,25 +2559,37 @@ public class GnssLocationProvider implements LocationProviderInterface {
        }
    }

    private final class NetworkLocationListener implements LocationListener {
    private abstract class LocationChangeListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            // this callback happens on mHandler looper
            if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
                handleUpdateLocation(location);
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        public void onProviderDisabled(String provider) {
        }
    }

    private final class NetworkLocationListener extends LocationChangeListener {
        @Override
        public void onProviderEnabled(String provider) {
        public void onLocationChanged(Location location) {
            // this callback happens on mHandler looper
            if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
                handleUpdateLocation(location);
            }
        }
    }

    private final class FusedLocationListener extends LocationChangeListener {
        @Override
        public void onProviderDisabled(String provider) {
        public void onLocationChanged(Location location) {
            if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) {
                Log.d(TAG, "fused location listener: " + location);
                injectBestLocation(location);
            }
        }
    }

@@ -2641,6 +2757,8 @@ public class GnssLocationProvider implements LocationProviderInterface {
                return "RELEASE_SUPL_CONNECTION";
            case INJECT_NTP_TIME:
                return "INJECT_NTP_TIME";
            case REQUEST_LOCATION:
                return "REQUEST_LOCATION";
            case DOWNLOAD_XTRA_DATA:
                return "DOWNLOAD_XTRA_DATA";
            case INJECT_NTP_TIME_FINISHED:
@@ -2764,6 +2882,19 @@ public class GnssLocationProvider implements LocationProviderInterface {

    private native int native_read_nmea(byte[] buffer, int bufferSize);

    private native void native_inject_best_location(
            int gnssLocationFlags,
            double latitudeDegrees,
            double longitudeDegrees,
            double altitudeMeters,
            float speedMetersPerSec,
            float bearingDegrees,
            float horizontalAccuracyMeters,
            float verticalAccuracyMeters,
            float speedAccuracyMetersPerSecond,
            float bearingAccuracyDegrees,
            long timestamp);

    private native void native_inject_location(double latitude, double longitude, float accuracy);

    // XTRA Support
+72 −1
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ static jmethodID method_setGnssYearOfHardware;
static jmethodID method_setGnssHardwareModelName;
static jmethodID method_xtraDownloadRequest;
static jmethodID method_reportNiNotification;
static jmethodID method_requestLocation;
static jmethodID method_requestRefLocation;
static jmethodID method_requestSetID;
static jmethodID method_requestUtcTime;
@@ -346,6 +347,34 @@ static jobject translateLocation(JNIEnv* env, const GnssLocation& location) {
    return object.get();
}

static GnssLocation createGnssLocation(
        jint gnssLocationFlags,
        jdouble latitudeDegrees,
        jdouble longitudeDegrees,
        jdouble altitudeMeters,
        jfloat speedMetersPerSec,
        jfloat bearingDegrees,
        jfloat horizontalAccuracyMeters,
        jfloat verticalAccuracyMeters,
        jfloat speedAccuracyMetersPerSecond,
        jfloat bearingAccuracyDegrees,
        jlong timestamp) {
    GnssLocation location;
    location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags);
    location.latitudeDegrees = static_cast<double>(latitudeDegrees);
    location.longitudeDegrees = static_cast<double>(longitudeDegrees);
    location.altitudeMeters = static_cast<double>(altitudeMeters);
    location.speedMetersPerSec = static_cast<float>(speedMetersPerSec);
    location.bearingDegrees = static_cast<float>(bearingDegrees);
    location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters);
    location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters);
    location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond);
    location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees);
    location.timestamp = static_cast<uint64_t>(timestamp);

    return location;
}

/*
 * GnssCallback class implements the callback methods for IGnss interface.
 */
@@ -474,7 +503,9 @@ Return<void> GnssCallback::gnssRequestTimeCb() {
}

Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) {
    // TODO(b/72405645): call into java implementation
    JNIEnv* env = getJniEnv();
    env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss));
    checkAndClearExceptionFromCallback(env, __FUNCTION__);
    return Void();
}

@@ -1042,6 +1073,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
    method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
    method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
            "(IIIIILjava/lang/String;Ljava/lang/String;II)V");
    method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(Z)V");
    method_requestRefLocation = env->GetMethodID(clazz, "requestRefLocation", "()V");
    method_requestSetID = env->GetMethodID(clazz, "requestSetID", "(I)V");
    method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
@@ -1441,6 +1473,42 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */,
    }
}

static void android_location_GnssLocationProvider_inject_best_location(
        JNIEnv*,
        jobject,
        jint gnssLocationFlags,
        jdouble latitudeDegrees,
        jdouble longitudeDegrees,
        jdouble altitudeMeters,
        jfloat speedMetersPerSec,
        jfloat bearingDegrees,
        jfloat horizontalAccuracyMeters,
        jfloat verticalAccuracyMeters,
        jfloat speedAccuracyMetersPerSecond,
        jfloat bearingAccuracyDegrees,
        jlong timestamp) {
    if (gnssHal_V1_1 != nullptr) {
        GnssLocation location = createGnssLocation(
                gnssLocationFlags,
                latitudeDegrees,
                longitudeDegrees,
                altitudeMeters,
                speedMetersPerSec,
                bearingDegrees,
                horizontalAccuracyMeters,
                verticalAccuracyMeters,
                speedAccuracyMetersPerSecond,
                bearingAccuracyDegrees,
                timestamp);
        auto result = gnssHal_V1_1->injectBestLocation(location);
        if (!result.isOk() || !result) {
            ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
        }
    } else {
        ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__);
    }
}

static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
        jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
    if (gnssHal != nullptr) {
@@ -1996,6 +2064,9 @@ static const JNINativeMethod sMethods[] = {
            android_location_GnssLocationProvider_read_nmea)},
    {"native_inject_time", "(JJI)V", reinterpret_cast<void *>(
            android_location_GnssLocationProvider_inject_time)},
    {"native_inject_best_location",
            "(IDDDFFFFFFJ)V",
            reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_best_location)},
    {"native_inject_location",
            "(DDF)V",
            reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_location)},