GPS简单模拟

注册回调 LocationListener,listener 被封装在 receiver 中

    @Override
    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
            PendingIntent intent, String packageName) {
        ...
        Receiver receiver;
        if (intent != null) {
            receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
                    hideFromAppOps);
        } else {
            receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
                    hideFromAppOps);
        }
        requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
    }
    
    @GuardedBy("mLock")
    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
            int uid, String packageName) {

        UpdateRecord record = new UpdateRecord(name, request, receiver);
    
        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
        if (oldRecord != null) {
            oldRecord.disposeLocked(false);
        }

        if (!provider.isUseableLocked() && !isSettingsExemptLocked(record)) {
            receiver.callProviderEnabledLocked(name, false);
        }

        applyRequirementsLocked(name);

        receiver.updateMonitoring(true);
    }

调用回调 reportLocation() --> handleLocationChangedLocked --> receiver.callLocationChangedLocked

hal会从驱动读取GPS信息然后调用 --> jni 的函数 reportLocation() 上报

void Gnss::locationCb(GpsLocation* location) {
    android::hardware::gnss::V1_0::GnssLocation gnssLocation = convertToGnssLocation(location);
    auto ret = sGnssCbIface->gnssLocationCb(gnssLocation);
}

template<class T>
Return<void> GnssCallback::gnssLocationCbImpl(const T& location) {
    JNIEnv* env = getJniEnv();

    jobject jLocation = translateGnssLocation(env, location);

    env->CallVoidMethod(mCallbacksObj,
                        method_reportLocation,
                        boolToJbool(hasLatLong(location)),
                        jLocation);
    checkAndClearExceptionFromCallback(env, __FUNCTION__);
    env->DeleteLocalRef(jLocation);
    return Void();
}

JNI获取GNSS HAL接口

/* Initializes the GNSS service handle. */
static void android_location_GnssLocationProvider_set_gps_service_handle() {
    gnssHal = IGnss_V1_0::getService();
}

获取GNSS接口,添加CallBack

// hardware/interfaces/gnss/1.0/default/Gnss.cpp

Gnss::Gnss(gps_device_t* gnssDevice) :
        mDeathRecipient(new GnssHidlDeathRecipient(this)) {
    mGnssIface = gnssDevice->get_gps_interface(gnssDevice);
}

Return<bool> Gnss::setCallback(const sp<IGnssCallback>& callback)  {
    ...
    return (mGnssIface->init(&sGnssCb) == 0);
}

结构体对齐 init函数调用的实际是qemu_gps_init

hardware/libhardware/include/hardware/gps.h
/** Represents the standard GPS interface. */
typedef struct {
    size_t          size;

    int   (*init)( GpsCallbacks* callbacks );
    ...
} GpsInterface;

static const GpsInterface  qemuGpsInterface = {
    sizeof(GpsInterface),
    qemu_gps_init,
    ...
};

device/generic/goldfish/gps/gps_qemu.c

NmeaReader 读取32字节,解析在nmea_reader_addc中

// 
else if (fd == gps_fd)
{
    char  buff[32];
    D("gps fd event");
    for (;;) {
        int  nn, ret;

        ret = read( fd, buff, sizeof(buff) );
        if (ret < 0) {
            if (errno == EINTR)
                continue;
            if (errno != EWOULDBLOCK)
                ALOGE("error while reading from gps daemon socket: %s:", strerror(errno));
            break;
        }
        D("received %d bytes: %.*s", ret, ret, buff);
        for (nn = 0; nn < ret; nn++)
            nmea_reader_addc( reader, buff[nn] );
    }
    D("gps fd event end");
}

一些字段含义

r->sv_status.num_svs = 6;  //卫星数量
r->sv_status_changed = 1; //状态回调
r->sv_status.used_in_fix_mask |= (1 << (r->sv_status.num_svs));
r->fix.accuracy = 8.0;  //精度
r->fix.timestamp = 1685782786; //时间戳
r->fix.latitude = strtod(propbuf_latitude,NULL);
r->fix.longitude = strtod(propbuf_longitude,NULL);
r->fix.flags    |= GPS_LOCATION_HAS_LAT_LONG;
r->fix.flags   |= GPS_LOCATION_HAS_ACCURACY;
D("lat : %f  lon : %f ",  r->fix.latitude, r->fix.longitude);

实现一个最简单的虚拟定位模拟

diff --git a/frameworks/base/services/core/java/com/android/server/LocationManagerService.java b/frameworks/base/services/core/java/com/android/server/LocationManagerService.java
index 90e467034e..0f4a2e51d1 100644
--- a/frameworks/base/services/core/java/com/android/server/LocationManagerService.java
+++ b/frameworks/base/services/core/java/com/android/server/LocationManagerService.java
@@ -98,6 +98,7 @@ import com.android.internal.location.ProviderRequest;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.location.AbstractLocationProvider;
 import com.android.server.location.ActivityRecognitionProxy;
 import com.android.server.location.CallerIdentity;
@@ -2553,12 +2554,36 @@ public class LocationManagerService extends ILocationManager.Stub {
                             hideFromAppOps);
                 }
                 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
+                requestReportLocation();
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
         }
     }

+    public void requestReportLocation() {
+        Location loc = createLocation(121.54611623716278, 25.094571969899793);
+        LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
+        if  (loc != null && gpsProvider != null) {
+            gpsProvider.onReportLocation(loc);
+        }
+    }
+
+    private Location createLocation(double longitude, double latitude) {
+        Location location = new Location(LocationManager.GPS_PROVIDER);
+        location.setLongitude(longitude);
+        location.setLatitude(latitude);
+        location.setTime(System.currentTimeMillis());
+        location.setAccuracy(5.0f);
+        location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        return location;
+    }

image
image

posted @ 2025-09-17 13:04  梦过无声  阅读(24)  评论(0)    收藏  举报