Andorid QCOM GPS: 代码流程

GPS基础知识

http://fancyerii.github.io/2020/04/06/gps/

常见术语

信噪比,英文名称叫做SNR或S/N(SIGNAL-NOISE RATIO),又称为讯噪比。
是指一个电子设备或者电子系统中信号与噪声的比例 , 信噪比越大此颗卫星越有效(也就是说可以定位)

伪随机噪声(PRN)码: 用于表示卫星相关的信息

TTFF

Time to first fix (TTFF) is a measure of the time required for a GPS navigation device to acquire satellite signals and navigation data, and calculate a position solution (called a fix).

历书Almanac:

历书仅提供基本轨道参数,精度低,可用于接收机快速捕捉卫星和预报,包括全部卫星的大概位置,用于卫星预报 

星历:
含基本轨道参数及摄动改正量,由其确定的卫星位置精度高,可用于定位计算, 只是当前接收机观测到的卫星的精确位置,用于定位

A-GPS

最后我们简单的介绍一下A-GPS,了解一下加快GPS接收器启动速度的方法。

市场上结合了移动无线功能和卫星导航功能(如GPS)的设备数量在不断增加。这种组合通常用于基于位置的服务(LBS)。可以说这些设备并非总处于工作状态,尤其是定位通过GPS完成时更是如此,原因在于GPS接收机的功耗限制了电池工作时间。

由于GPS设备很少工作,它有可能没有关于卫星位置的信息。在停用2h或更长的时间后,为能开始工作它必须首先下载卫星的轨道数据。GPS接收机获取轨道数据并计算出首次位置一般至少需要18~36s的时间(该时间称为首次定位时间:TTFF)。在不利的接收条件下(例如,城区高层建筑妨碍了对天空的直视时),可能需要数分钟才能完成首次位置的计算。启动慢是GPS固有的限制,无法通过改进接收机技术来克服。

当缺少轨道数据时,GPS接收机必须执行一次完整的搜索过程,以便找到可用的卫星、下载数据和计算位置。在编码-频率域内对大约30颗GPS卫星进行搜索非常耗时,编码-频率域每级的积分时间通常至少需要1ms(1个C/A码周期)。如果将频率范围按50Hz的步长划分(即频率间隔为2×6000/50Hz=240Hz),则需要对多达1023×50=51150个位置(bins)进行搜索(需要51s)。

在信号较弱时可通过提供额外的卫星轨道数据和其他GPS信息来快速定位和测量。这些信息可通过其他信道获得,例如通过GSM、GPRS、CDMA或UMTS。这一应用称作辅助服务,并用于辅助GPS(A-GPS或AGPS)。A-GPS是一种使用辅助数据来加速定位的功能或服务。GPS接收机通过移动通信网络或直接经互联网获得辅助数据。辅助数据中包含以下信息:

  • 卫星星座(星历);
  • 精确轨道数据(星历、轨道);
  • 时间信息;
  • GPS接收机的多普勒频率和频移(误差)。

通过使用这些辅助数据,即便在不利的信号条件下GPS接收机也能够迅速定位。在弱信号条件下,这通常是获取定位的唯一途径。取决于辅助数据的复杂性和完整性,启动时间可能会显著缩短。剩余的启动时间取决于GPS信号的强度。通常辅助信息的可用性和精度越高,启动时间就越短。

集成了GPS设备的移动台仍需至少能看到4颗卫星。使用A-GPS时,GPS接收机需要一个用于接收辅助数据的接口。通过减少轨道数据的接收时间从而最大程度节省了启动时间。因为我们的手机通常会同时有无线网络和GPS,因此它的启动速度比纯GPS设备快。

Location和GPS

GNSS(GPS)代码流程

0. Android location java API

描述android java层怎样获得定位数据
https://www.runoob.com/w3cnote/android-tutorial-gps.html

以 RequestLocationUpdates GPS的代码流程为例,展示下Location的代码框架


1. location aidl:


aidl定义的是client 和 service间数据交换的格式包括接口和数据结构,Location相关的aidl文件很多,代码位于
frameworks/base/location/java/android/location/
这里重点关注:

1.1 ILocationListener


oneway interface ILocationListener
{
    @UnsupportedAppUsage
    void onLocationChanged(in Location location);
    @UnsupportedAppUsage
    void onProviderEnabled(String provider);
    @UnsupportedAppUsage
    void onProviderDisabled(String provider);

    // --- deprecated ---
    @UnsupportedAppUsage
    void onStatusChanged(String provider, int status, in Bundle extras);
}

1.2 Location.aidl


parcelable Location;

1.3 ILocationManager


/**
 * System private API for talking with the location service.
 *
 * @hide
 */
interface ILocationManager
{
    void requestLocationUpdates(in LocationRequest request, in ILocationListener listener,
            in PendingIntent intent, String packageName);
}

2 location hidl client的实现


LocationManager lManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
/*问什么getSystemService("location")返回的是LocationManager,难道和
@SystemService(Context.LOCATION_SERVICE) 这句话有关系?

*/

frameworks/base/location/java/android/location/LocationManager.java
/**
 * This class provides access to the system location services.  These
 * services allow applications to obtain periodic updates of the
 * device's geographical location, or to fire an application-specified
 * {@link Intent} when the device enters the proximity of a given
 * geographical location.
 */
@SystemService(Context.LOCATION_SERVICE)
@RequiresFeature(PackageManager.FEATURE_LOCATION)
public class LocationManager {
    //构造函数得到mService: location的代理,??
    public LocationManager(@NonNull Context context, @NonNull ILocationManager service) {
        mService = service;
    }

    private void requestLocationUpdates(LocationRequest request, LocationListener listener,
            Looper looper, PendingIntent intent) {
        android.util.SeempLog.record(47);

        String packageName = mContext.getPackageName();

        // wrap the listener class
        ListenerTransport transport = wrapListener(listener, looper);
    //通过mService调用service
        mService.requestLocationUpdates(request, transport, intent, packageName);

    }
}

2. location manager service的实现


frameworks/base/services/core/java/com/android/server/LocationManagerService.java
frameworks/base/services/core/java/com/android/server/location/
/**
 * The service class that manages LocationProviders and issues location
 * updates and alerts.
 */
public class LocationManagerService extends ILocationManager.Stub {
}

2.1 requestLocationUpdates的实现


public void 
requestLocationUpdates(LocationRequest request, ILocationListener listener, PendingIntent intent, String packageName)
    requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, int uid, String packageName)
        applyRequirementsLocked(String providerName)
            applyRequirementsLocked(LocationProvider provider)
                provider.setRequestLocked(providerRequest, worksource);
                setRequest(ProviderRequest request, WorkSource source)
                    sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));

            
handleMessage(Message msg)        
    handleSetRequest(gpsRequest.request, gpsRequest.source);[SET_REQUEST]
        updateEnabled();
            native_init();
        updateRequirements();        
            startNavigating()
                setPositionMode
                    native_set_position_mode
                        gnssHal_V1_1->setPositionMode_1_1
jni层
frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
//location service层的所有jni实现都是在这个文件,名字可能有点怪

using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
/* Initializes the GNSS service handle. */
static void android_location_GnssLocationProvider_set_gps_service_handle() {
    gnssHal_V2_0 = IGnss_V2_0::getService();// 得到了hidl service的代理,通过gnssHal_V2_0访问hidl service
    if (gnssHal_V2_0 != nullptr) {
        gnssHal = gnssHal_V2_0;
        gnssHal_V1_1 = gnssHal_V2_0;
        return;
    }
}

HIDL hal: jni层通过getService得到 对应hidl service 的代理接口,jni层通过返回的gnssHal_V2_0和hidl service通信;

3 hidl hal

hidl hal有两个易混淆的宏:

LOC_HIDL_VERSION=3.0 

hardware/qcom/gps/android/Android.mk: GNSS_HIDL_VERSION=2.0

vendor/qcom/proprietary/gps-release/gps_vendor_product.mk: LOC_HIDL_VERSION = 3.0

代码路径: 接口的service实现在hardware/qcom/gps/xxx路径下
hardware/interfaces/gnss
hardware/interfaces/gnss/1.0/IGnss.hal

还有一部分接口在:接口的实现在vendor/qcom/proprietary/gps/路径下

vendor/qcom/proprietary/interfaces/gnss/

package vendor.qti.gnss@1.0;
import android.hardware.gnss@1.0;
interface ILocHidlGnss extends IGnss { //继承android.hardware.gnss@1.0
}

3.1 setPositionMode


    /**
     * Sets the GnssPositionMode parameter,its associated recurrence value,
     * the time between fixes,requested fix accuracy and time to first fix.
     *
     * @param mode  Parameter must be one of MS_BASED or STANDALONE.
     * It is allowed by the platform (and it is recommended) to fallback to
     * MS_BASED if MS_ASSISTED is passed in, and MS_BASED is supported.
     * @recurrence GNSS position recurrence value, either periodic or single.
     * @param minIntervalMs Represents the time between fixes in milliseconds.
     * @param preferredAccuracyMeters Represents the requested fix accuracy in meters.
     * @param preferredTimeMs Represents the requested time to first fix in milliseconds.

     * @return success Returns true if successful.
     */
    setPositionMode(GnssPositionMode mode, GnssPositionRecurrence recurrence,
                    uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
                    uint32_t preferredTimeMs)
        generates (bool success);

3.2 hidl service的实现: setPositionMode_1_1


hardware/qcom/gps/android/2.0/Gnss.cpp
Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
        V1_0::IGnss::GnssPositionRecurrence recurrence,
        uint32_t minIntervalMs,
        uint32_t preferredAccuracyMeters,
        uint32_t preferredTimeMs,
        bool lowPowerMode) {
    ENTRY_LOG_CALLFLOW();
    bool retVal = false;
    GnssAPIClient* api = getApi();
    if (api) {
        GnssPowerMode powerMode = lowPowerMode?
                GNSS_POWER_MODE_M4 : GNSS_POWER_MODE_M2;
        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
                preferredAccuracyMeters, preferredTimeMs, powerMode, minIntervalMs);
    }
    return retVal;
}


bool 
GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
        IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
        uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
        locAPIUpdateTrackingOptions(mTrackingOptions);

void LocationAPIClientBase::locAPIUpdateTrackingOptions(TrackingOptions& options)
{
    pthread_mutex_lock(&mMutex);
    if (mLocationAPI) {
        uint32_t session = 0;
        session = mRequestQueues[REQUEST_TRACKING].getSession();
        if (session > 0) {
            mRequestQueues[REQUEST_TRACKING].push(new UpdateTrackingOptionsRequest(*this));
            mLocationAPI->updateTrackingOptions(session, options);
        } else {
            LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
        }
    }
    pthread_mutex_unlock(&mMutex);
}

mLocationAPI->updateTrackingOptions(session, options);
static void updateTrackingOptions(
        LocationAPI* client, uint32_t id, TrackingOptions& trackingOptions)
{
    if (NULL != gGnssAdapter) {
        gGnssAdapter->updateTrackingOptionsCommand(
                client, id, trackingOptions);
    }
}

hardware/qcom/gps/gnss/GnssAdapter.cpp
void
GnssAdapter::updateTrackingOptionsCommand(LocationAPI* client, uint32_t id,
                                          TrackingOptions& options)
{
    LOC_LOGD("%s]: client %p id %u minInterval %u mode %u",
             __func__, client, id, options.minInterval, options.mode);

    mApi.startDistanceBasedTracking(mSessionId, mOptions,
                            new LocApiResponse(*mAdapter.getContext(),
                                        [] (LocationError /*err*/) {}));  
    或者
    startTimeBasedTracking;
}
// 不管是startDistanceBasedTracking 还是 startTimeBasedTracking,最终都会调到:
vendor/qcom/opensource/location/loc_api/loc_api_v02/LocApiV02.cpp

vendor/qcom/opensource/location/loc_api/loc_api_v02/loc_api_v02_client.c

/*
@brief Sends a message to the location engine. If the locClientSendMsg()
         function is successful, the client should expect an indication
         (except start, stop, event reg and sensor injection messages),
         through the registered callback in the locOpen() function. The
         indication will contain the status of the request and if status is a
         success, indication also contains the payload
         associated with response.
*/
locClientStatusEnumType locClientSendReq(
  locClientHandleType      handle,
  uint32_t                 reqId,
  locClientReqUnionType    reqPayload )
{
    qmi_client_send_msg_sync(
           pCallbackData->userHandle,
           reqId,
           pReqData,
           reqLen,
           &resp,
           sizeof(resp),
           LOC_CLIENT_ACK_TIMEOUT);

    LOC_LOGv("qmi_client_send_msg_sync returned %d", rc);
}

4. Position Report GPS

描述定位数据如何上传到Android Java level的。

//vendor/qcom/opensource/location/loc_api/loc_api_v02/LocApiV02.cpp
/* static event callbacks that call the LocApiV02 callbacks*/
/* global event callback, call the eventCb function in loc api adapter v02
   instance */
static void globalEventCb(locClientHandleType clientHandle,
                          uint32_t eventId,
                          const locClientEventIndUnionType eventPayload,
                          void*  pClientCookie)
{
    switch (eventId) {
    case QMI_LOC_EVENT_POSITION_REPORT_IND_V02:
    LocApiV02 *locApiV02Instance = (LocApiV02 *)pClientCookie;
    LOC_LOGv ("client = %p, event id = 0x%X, client cookie ptr = %p",
              clientHandle, eventId, pClientCookie);
    locApiV02Instance->eventCb(clientHandle, eventId, eventPayload);
}

hardware/qcom/gps/gnss/GnssAdapter.cpp
        // prepare the callback functions
        // callback function for engine hub to report back position event
        GnssAdapterReportEnginePositionsEventCb reportPositionEventCb =
            [this](int count, EngineLocationInfo* locationArr) {
                    // report from engine hub on behalf of PPE will be treated as fromUlp
                    reportEnginePositionsEvent(count, locationArr);
            };

    reportEnginePositionsEvent
        reportEnginePositions

hardware/qcom/gps/android/1.0/location_api/GnssAPIClient.cpp
void GnssAPIClient::onTrackingCb(Location location)
{
    LOC_LOGD("%s]: (flags: %02x)", __FUNCTION__, location.flags);
    mMutex.lock();
    auto gnssCbIface(mGnssCbIface);
    mMutex.unlock();

    if (gnssCbIface != nullptr) {
        GnssLocation gnssLocation;
        convertGnssLocation(location, gnssLocation);
        auto r = gnssCbIface->gnssLocationCb(gnssLocation);
    }
}

frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
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();
}

Return<void> GnssCallback::gnssLocationCb(const GnssLocation_V1_0& location) {
    return gnssLocationCbImpl<GnssLocation_V1_0>(location);
}

Return<void>
GnssCallback::gnssLocationCb_2_0(const GnssLocation_V2_0& location) {
    return gnssLocationCbImpl<GnssLocation_V2_0>(location);
}


    @NativeEntryPoint
    private void reportLocation(boolean hasLatLong, Location location) {
        sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
    }

    private void handleReportLocation(boolean hasLatLong, Location location) {
        if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
    reportLocation(...);
    }

    /**
     * Call this method to report a new location. May be called from any thread.
     */
    protected void reportLocation(Location location) {
        mLocationProviderManager.onReportLocation(location);
    }

//frameworks/base/services/core/java/com/android/server/LocationManagerService.java
//发送到client
    @Override
        public void onReportLocation(Location location) {
            // no security check necessary because this is coming from an internal-only interface
            // move calls coming from below LMS onto a different thread to avoid deadlock
            mHandler.post(() -> {
                synchronized (mLock) {
                    handleLocationChangedLocked(location, this);
                }
            });
     }

Modem侧

大概意思作为QMI-loc service (提供定位信息)注册到QCSI框架 .
 

 

参考

hal层的框架发展为hidl hal, 以前的文档可能是之前的架构,需要注意

https://www.ibm.com/developerworks/cn/opensource/os-cn-android-location/index.html
Android 系统中 Location Service 的实现与架构

http://zenki2001cn.github.io/Wiki/Android/GPS%E7%B3%BB%E7%BB%9F.html#toc_1

http://zenki2001cn.github.io/Wiki/Android/GPS%E4%BF%A1%E6%81%AF%E7%9A%84%E5%86%85%E5%AE%B9%E6%8F%90%E4%BE%9B%E8%80%85.html

http://zenki2001cn.github.io/Wiki/Android/GPS%E6%9C%8D%E5%8A%A1.html

http://zenki2001cn.github.io/Wiki/Android/GPS%E7%9A%84HAL%E5%B1%82.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值