gps搜星流程

前面有讲过gps的搜星流程,本文要讲解的是跟搜星类似的流程–gps定位流程,由于整个过程比较相似,所以决定用一篇文章来讲解,modem层到loc eng层的数据传递和loc eng层到android framework层的数据传递


loc eng层的gps location是通过location_cb函数来扔给android framework层的,我们需要看下loc eng层的location_cb是在哪里被调用的,具体如下: 
hardware/qcom/gps/loc_api/libloc_api_50001/loc_eng.cpp

void LocEngReportPosition::proc() const { //跟搜星流程是不是很相似,同样是通过loc eng层的一个proc()方法把location的数据传递给上层的 LocEngAdapter* adapter = (LocEngAdapter*)mAdapter; loc_eng_data_s_type* locEng = (loc_eng_data_s_type*)adapter->getOwner(); if (locEng->mute_session_state != LOC_MUTE_SESS_IN_SESSION) { bool reported = falseif (locEng->location_cb != NULL) { if (LOC_SESS_FAILURE == mStatus) { //如果状态不对,那么给到上层的location信息是NULL // in case we want to handle the failure case locEng->location_cb(NULL, NULL); reported = true; } // what's in the else if is... (line by line) // 1. this is a final fix; and // 1.1 it is a Satellite fix; or // 1.2 it is a sensor fix // 2. (must be intermediate fix... implicit) // 2.1 we accepte intermediate; and // 2.2 it is NOT the case that // 2.2.1 there is inaccuracy; and // 2.2.2 we care about inaccuracy; and // 2.2.3 the inaccuracy exceeds our tolerance else if ((LOC_SESS_SUCCESS == mStatus && ((LOC_POS_TECH_MASK_SATELLITE | LOC_POS_TECH_MASK_SENSORS | LOC_POS_TECH_MASK_HYBRID) & mTechMask)) || (LOC_SESS_INTERMEDIATE == locEng->intermediateFix && !((mLocation.gpsLocation.flags & GPS_LOCATION_HAS_ACCURACY) && (gps_conf.ACCURACY_THRES != 0) && (mLocation.gpsLocation.accuracy > gps_conf.ACCURACY_THRES)))) { //否则把location的信息通过location_cb传递给android framework层, //注意:这里传递的数据类型是UlpLocation*类型的,不是HAL层所能识别的格式GpsLocation* //搜星流程在这里传递的是HAL层能识别的GpsSvStatus*类型的,所以必定有一个地方在做UlpLocation到GpsLocation的转换 locEng->location_cb((UlpLocation*)&(mLocation), (void*)mLocationExt); reported = true; } } // if we have reported this fix if (reported && // and if this is a singleshot GPS_POSITION_RECURRENCE_SINGLE == locEng->adapter->getPositionMode().recurrence) { if (LOC_SESS_INTERMEDIATE == mStatus) { // modem could be still working for a final fix, // although we no longer need it. So stopFix(). locEng->adapter->stopFix(); } // turn off the session flag. locEng->adapter->setInSession(false); } if (locEng->generateNmea && mLocation.position_source == ULP_LOCATION_IS_FROM_GNSS && mTechMask & (LOC_POS_TECH_MASK_SATELLITE | LOC_POS_TECH_MASK_SENSORS | LOC_POS_TECH_MASK_HYBRID)) { unsigned char generate_nmea = reported && (mStatus != LOC_SESS_FAILURE); loc_eng_nmea_generate_pos(locEng, mLocation, mLocationExtended, generate_nmea); } // Free the allocated memory for rawData UlpLocation* gp = (UlpLocation*)&(mLocation); if (gp != NULL && gp->rawData != NULL) { delete (char*)gp->rawData; gp->rawData = http://blog.csdn.net/lele_cheny/article/details/NULL; gp->rawDataSize = 0; } } }


gps定位流程跟搜星流程一样,都是消息触发机制,location的信息是从底层(modem层)发送上来的,所以我们从底层往上来跟进整个流程


gps定位流程底层会有比很多callback绑定,如果是跟搜星流程一样的callback的话,我们就一笔带过,如果有不一样的才拿出来分析。

同样从loc_api层的locClientIndCb开始走起: 
vendor/qcom/opensource/location/loc_api/loc_api_v02/loc_api_v02_client.c

static void locClientIndCb ( qmi_client_type user_handle, unsigned int msg_id, void *ind_buf, unsigned int ind_buf_len, void *ind_cb_data ) { //定义和初始化,关键参数ind_cb_data会赋值给locClientCallbackDataType类型的pCallbackData locClientIndEnumT indType; size_t indSize = 0; qmi_client_error_type rc ; locClientCallbackDataType* pCallbackData = http://blog.csdn.net/lele_cheny/article/details/(locClientCallbackDataType *)ind_cb_data; LOC_LOGV("%s:%d]: Indication: msg_id=%d buf_len=%d pCallbackData = http://blog.csdn.net/lele_cheny/article/details/%p/n", __func__, __LINE__, (uint32_t)msg_id, ind_buf_len, pCallbackData); // check callback data if(NULL == pCallbackData ||(pCallbackData != pCallbackData->pMe)) { //如果传进来的参数是NULL,那么一切免谈了 LOC_LOGE("%s:%d]: invalid callback data", __func__, __LINE__); return; } // check user handle if(memcmp(&pCallbackData->userHandle, &user_handle, sizeof(user_handle))) { LOC_LOGE("%s:%d]: invalid user_handle got %p expected %p\n", __func__, __LINE__, user_handle, pCallbackData->userHandle); //填充callback的userHandle,如果异常则返回 return; } // Get the indication size and type ( eventInd or respInd) //顾名思义从msg_id里面获取size和type,type分为event和response iftrue == locClientGetSizeAndTypeByIndId(msg_id, &indSize, &indType)) { void *indBuffer = NULL; // if the client did not register for this event then just drop it if( (eventIndType == indType) && ( (NULL == pCallbackData->eventCallback) || (false == isClientRegisteredForEvent(pCallbackData->eventRegMask, msg_id)) ) ) { //如果是eventIndType,但是eventCallback是NULL,或者msg_id的eventRegMask是没有注册的 LOC_LOGW("%s:%d]: client is not registered for event %d\n", __func__, __LINE__, (uint32_t)msg_id); return; } // decode the indication indBuffer = malloc(indSize); if(NULL == indBuffer) { //分配内存失败 LOC_LOGE("%s:%d]: memory allocation failed\n", __func__, __LINE__); return; } //初始化rc为QMI_NO_ERR rc = QMI_NO_ERR; if (ind_buf_len > 0) { // decode the indication //解析qmi message,ind_buf是传入数据,indBuffer是解析之后的数据 rc = qmi_client_message_decode( user_handle, QMI_IDL_INDICATION, msg_id, ind_buf, ind_buf_len, indBuffer, indSize); } if( rc == QMI_NO_ERR ) { //validate indication //解析完毕之后就要开始switch case了,其中case是msg_id if (true == locClientHandleIndication(msg_id, indBuffer, indSize)) { //一般只要indBuffer没有问题,就会走这个flow if(eventIndType == indType) { locClientEventIndUnionType eventIndUnion; /* copy the eventCallback function pointer from the callback * data to local variable. This is to protect against the race * condition between open/close and indication callback. */ //这里可以看到eventCallback赋值给了localEventCallback,就是等于后面的globalEventCb(具体后面有讲),这里是重点!!! locClientEventIndCbType localEventCallback = pCallbackData->eventCallback; // dummy event eventIndUnion.pPositionReportEvent = (qmiLocEventPositionReportIndMsgT_v02 *)indBuffer; /* call the event callback * To avoid calling the eventCallback after locClientClose * is called, check pCallbackData->eventCallback again here */ if((NULL != localEventCallback) && (NULL != pCallbackData->eventCallback)) { //如果LocalEventCallback不为NULL,则调用callback所绑定的函数,也就是globalEventCb localEventCallback( (locClientHandleType)pCallbackData, msg_id, eventIndUnion, pCallbackData->pClientcookie); } } else if(respIndType == indType) { //resp类型的msg先不讲 locClientRespIndUnionType respIndUnion; /* copy the respCallback function pointer from the callback * data to local variable. This is to protect against the race * condition between open/close and indication callback. */ locClientRespIndCbType localRespCallback = pCallbackData->respCallback; // dummy to suppress compiler warnings respIndUnion.pDeleteAssistDataInd = (qmiLocDeleteAssistDataIndMsgT_v02 *)indBuffer; /* call the response callback * To avoid calling the respCallback after locClientClose * is called, check pCallbackData->respCallback again here */ if((NULL != localRespCallback) && (NULL != pCallbackData->respCallback)) { localRespCallback( (locClientHandleType)pCallbackData, msg_id, respIndUnion, pCallbackData->pClientCookie); } } } else // error handling indication { LOC_LOGE("%s:%d]: Error handling the indication %d\n", __func__, __LINE__, (uint32_t)msg_id); } } else { LOC_LOGE("%s:%d]: Error decoding indication %d\n", __func__, __LINE__, rc); } if(indBuffer) { free (indBuffer); } } else // Id not found { LOC_LOGE("%s:%d]: Error indication not found %d\n", __func__, __LINE__,(uint32_t)msg_id); } return; }

同样到locClientHandleIndication里面进去看下: 
vendor/qcom/opensource/location/loc_api/loc_api_v02/loc_api_v02_client.c

static bool locClientHandleIndication( uint32_t indId, void* indBuffer, size_t indSize ) { bool status = falseswitch(indId) { ... //从这里开始就跟sv_status_cb走不一样的flow了,这里需要care的id是QMI_LOC_EVENT_POSITION_REPORT_IND_V02 // handle position report case QMI_LOC_EVENT_POSITION_REPORT_IND_V02: { status = locClientHandlePosReportInd(indId, indBuffer, indSize); break; } ... return status; }

在往下看之前,有必要看一个数据结构,主要是为了存储decorder出来的信息,具体如下(一个庞大的结构体,主要包含了会话状态,经度,纬度,海拔,速度等信息): 
vendor/qcom/opensource/location/loc_api/loc_api_v02/location_service_v02.h

/** Indication Message; Sends the position report to the control point. */ typedef struct { /* Mandatory */ /* Session Status */ qmiLocSessionStatusEnumT_v02 sessionStatus; //session的状态,具体值下面有列出 /**< Session status. Valid values: \n - eQMI_LOC_SESS_STATUS_SUCCESS (0) -- Session was successful - eQMI_LOC_SESS_STATUS_IN_PROGRESS (1) -- Session is still in progress; further position reports will be generated until either the fix criteria specified by the client are met or the client response timeout occurs - eQMI_LOC_SESS_STATUS_GENERAL_FAILURE (2) -- Session failed - eQMI_LOC_SESS_STATUS_TIMEOUT (3) -- Fix request failed because the session timed out - eQMI_LOC_SESS_STATUS_USER_END (4) -- Fix request failed because the session was ended by the user - eQMI_LOC_SESS_STATUS_BAD_PARAMETER (5) -- Fix request failed due to bad parameters in the request - eQMI_LOC_SESS_STATUS_PHONE_OFFLINE (6) -- Fix request failed because the phone is offline - eQMI_LOC_SESS_STATUS_ENGINE_LOCKED (7) -- Fix request failed because the engine is locked */ /* Mandatory */ /* Session ID */ uint8_t sessionId; /**< ID of the session that was specified in the Start request QMI_LOC_START_REQ. \n - Range: 0 to 255 */ /* Optional */ /* Latitude */ uint8_t latitude_valid; /**< Must be set to true if latitude is being passed */ double latitude; /**< Latitude (specified in WGS84 datum). \begin{itemize1} \item Type: Floating point \item Units: Degrees \item Range: -90.0 to 90.0 \begin{itemize1} \item Positive values indicate northern latitude //北纬度是正数 \item Negative values indicate southern latitude //南纬度是负数 \vspace{-0.18in} \end{itemize1} \end{itemize1} */ /* Optional */ /* Longitude */ uint8_t longitude_valid; /**< Must be set to true if longitude is being passed */ double longitude; /**< Longitude (specified in WGS84 datum). \begin{itemize1} \item Type: Floating point \item Units: Degrees \item Range: -180.0 to 180.0 \begin{itemize1} \item Positive values indicate eastern longitude //东经度是正数 \item Negative values indicate western longitude //西经度是负数 \vspace{-0.18in} \end{itemize1} \end{itemize1} */ /* Optional */ /* Circular Horizontal Position Uncertainty */ uint8_t horUncCircular_valid; /**< Must be set to true if horUncCircular is being passed */ float horUncCircular; /**< Horizontal position uncertainty (circular).\n - Units: Meters */ /* Optional */ /* Horizontal Elliptical Uncertainty (Semi-Minor Axis) */ uint8_t horUncEllipseSemiMinor_valid; /**< Must be set to true if horUncEllipseSemiMinor is being passed */ float horUncEllipseSemiMinor; /**< Semi-minor axis of horizontal elliptical uncertainty.\n - Units: Meters */ /* Optional */ /* Horizontal Elliptical Uncertainty (Semi-Major Axis) */ uint8_t horUncEllipseSemiMajor_valid; /**< Must be set to true if horUncEllipseSemiMajor is being passed */ float horUncEllipseSemiMajor; /**< Semi-major axis of horizontal elliptical uncertainty.\n - Units: Meters */ /* Optional */ /* Elliptical Horizontal Uncertainty Azimuth */ uint8_t horUncEllipseOrientAzimuth_valid; /**< Must be set to true if horUncEllipseOrientAzimuth is being passed */ float horUncEllipseOrientAzimuth; /**< Elliptical horizontal uncertainty azimuth of orientation.\n - Units: Decimal degrees \n - Range: 0 to 180 */ /* Optional */ /* Horizontal Confidence */ uint8_t horConfidence_valid; /**< Must be set to true if horConfidence is being passed */ uint8_t horConfidence; /**< Horizontal uncertainty confidence. If both elliptical and horizontal uncertainties are specified in this message, the confidence corresponds to the elliptical uncertainty. \n - Units: Percent \n - Range: 0 to 99 */ /* Optional */ /* Horizontal Reliability */ uint8_t horReliability_valid; /**< Must be set to true if horReliability is being passed */ qmiLocReliabilityEnumT_v02 horReliability; /**< Specifies the reliability of the horizontal position. Valid values: \n - eQMI_LOC_RELIABILITY_NOT_SET (0) -- Location reliability is not set - eQMI_LOC_RELIABILITY_VERY_LOW (1) -- Location reliability is very low; use it at your own risk - eQMI_LOC_RELIABILITY_LOW (2) -- Location reliability is low; little or no cross-checking is possible - eQMI_LOC_RELIABILITY_MEDIUM (3) -- Location reliability is medium; limited cross-check passed - eQMI_LOC_RELIABILITY_HIGH (4) -- Location reliability is high; strong cross-check passed */ /* Optional */ /* Horizontal Speed */ uint8_t speedHorizontal_valid; /**< Must be set to true if speedHorizontal is being passed */ float speedHorizontal; //水平速度,单位是m/s /**< Horizontal speed.\n - Units: Meters/second */ /* Optional */ /* Speed Uncertainty */ uint8_t speedUnc_valid; /**< Must be set to true if speedUnc is being passed */ float speedUnc; //三维速度,单位是m/s /**< 3-D Speed uncertainty.\n - Units: Meters/second */ /* Optional */ /* Altitude With Respect to Ellipsoid */ uint8_t altitudeWrtEllipsoid_valid; /**< Must be set to true if altitudeWrtEllipsoid is being passed */ float altitudeWrtEllipsoid; /**< Altitude with respect to the WGS84 ellipsoid.\n - Units: Meters \n - Range: -500 to 15883 */ /* Optional */ /* Altitude With Respect to Sea Level */ uint8_t altitudeWrtMeanSeaLevel_valid; /**< Must be set to true if altitudeWrtMeanSeaLevel is being passed */ float altitudeWrtMeanSeaLevel; /**< Altitude with respect to mean sea level.\n - Units: Meters */ /* Optional */ /* Vertical Uncertainty */ uint8_t vertUnc_valid; /**< Must be set to true if vertUnc is being passed */ float vertUnc; /**< Vertical uncertainty.\n - Units: Meters */ /* Optional */ /* Vertical Confidence */ uint8_t vertConfidence_valid; /**< Must be set to true if vertConfidence is being passed */ uint8_t vertConfidence; /**< Vertical uncertainty confidence.\n - Units: Percent \n - Range: 0 to 99 */ /* Optional */ /* Vertical Reliability */ uint8_t vertReliability_valid; /**< Must be set to true if vertReliability is being passed */ qmiLocReliabilityEnumT_v02 vertReliability; /**< Specifies the reliability of the vertical position. Valid values: \n - eQMI_LOC_RELIABILITY_NOT_SET (0) -- Location reliability is not set - eQMI_LOC_RELIABILITY_VERY_LOW (1) -- Location reliability is very low; use it at your own risk - eQMI_LOC_RELIABILITY_LOW (2) -- Location reliability is low; little or no cross-checking is possible - eQMI_LOC_RELIABILITY_MEDIUM (3) -- Location reliability is medium; limited cross-check passed - eQMI_LOC_RELIABILITY_HIGH (4) -- Location reliability is high; strong cross-check passed */ /* Optional */ /* Vertical Speed */ uint8_t speedVertical_valid; /**< Must be set to true if speedVertical is being passed */ float speedVertical; //垂直速度,单位是m/s /**< Vertical speed.\n - Units: Meters/second */ /* Optional */ /* Heading */ uint8_t heading_valid; /**< Must be set to true if heading is being passed */ float heading; /**< Heading.\n - Units: Degrees \n - Range: 0 to 359.999 */ /* Optional */ /* Heading Uncertainty */ uint8_t headingUnc_valid; /**< Must be set to true if headingUnc is being passed */ float headingUnc; /**< Heading uncertainty.\n - Units: Degrees \n - Range: 0 to 359.999 */ /* Optional */ /* Magnetic Deviation */ uint8_t magneticDeviation_valid; /**< Must be set to true if magneticDeviation is being passed */ float magneticDeviation; /**< Difference between the bearing to true north and the bearing shown on a magnetic compass. The deviation is positive when the magnetic north is east of true north. */ /* Optional */ /* Technology Used */ uint8_t technologyMask_valid; /**< Must be set to true if technologyMask is being passed */ qmiLocPosTechMaskT_v02 technologyMask; //定位的方法,方式有卫星,基站,Wi-Fi,传感器等等 /**< Technology used in computing this fix. Valid bitmasks: \n - QMI_LOC_POS_TECH_MASK_SATELLITE (0x00000001) -- Satellites were used to generate the fix - QMI_LOC_POS_TECH_MASK_CELLID (0x00000002) -- Cell towers were used to generate the fix - QMI_LOC_POS_TECH_MASK_WIFI (0x00000004) -- Wi-Fi access points were used to generate the fix - QMI_LOC_POS_TECH_MASK_SENSORS (0x00000008) -- Sensors were used to generate the fix - QMI_LOC_POS_TECH_MASK_REFERENCE_LOCATION (0x00000010) -- Reference Location was used to generate the fix - QMI_LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION (0x00000020) -- Coarse position injected into the location engine was used to generate the fix - QMI_LOC_POS_TECH_MASK_AFLT (0x00000040) -- AFLT was used to generate the fix - QMI_LOC_POS_TECH_MASK_HYBRID (0x00000080) -- GNSS and Network-provided measurements were used to generate the fix */ /* Optional */ /* Dilution of Precision */ uint8_t DOP_valid; /**< Must be set to true if DOP is being passed */ qmiLocDOPStructT_v02 DOP; /**< \vspace{0.06in} \n Dilution of precision associated with this position. */ /* Optional */ /* UTC Timestamp */ uint8_t timestampUtc_valid; /**< Must be set to true if timestampUtc is being passed */ uint64_t timestampUtc; /**< UTC timestamp. \n - Units: Milliseconds since Jan. 1, 1970 */ /* Optional */ /* Leap Seconds */ uint8_t leapSeconds_valid; /**< Must be set to true if leapSeconds is being passed */ uint8_t leapSeconds; /**< Leap second information. If leapSeconds is not available, timestampUtc is calculated based on a hard-coded value for leap seconds. \n - Units: Seconds */ /* Optional */ /* GPS Time */ uint8_t gpsTime_valid; /**< Must be set to true if gpsTime is being passed */ qmiLocGPSTimeStructT_v02 gpsTime; /**< \vspace{0.06in} \n The number of weeks since Jan. 5, 1980, and milliseconds into the current week. */ /* Optional */ /* Time Uncertainty */ uint8_t timeUnc_valid; /**< Must be set to true if timeUnc is being passed */ float timeUnc; /**< Time uncertainty. \n - Units: Milliseconds */ /* Optional */ /* Time Source */ uint8_t timeSrc_valid; /**< Must be set to true if timeSrc is being passed */ qmiLocTimeSourceEnumT_v02 timeSrc; /**< Time source. Valid values: \n - eQMI_LOC_TIME_SRC_INVALID (0) -- Invalid time. - eQMI_LOC_TIME_SRC_NETWORK_TIME_TRANSFER (1) -- Time is set by the 1X system - eQMI_LOC_TIME_SRC_NETWORK_TIME_TAGGING (2) -- Time is set by WCDMA/GSM time tagging (i.e., associating network time with GPS time) - eQMI_LOC_TIME_SRC_EXTERNAL_INPUT (3) -- Time is set by an external injection - eQMI_LOC_TIME_SRC_TOW_DECODE (4) -- Time is set after decoding over-the-air GPS navigation data from one GPS satellite - eQMI_LOC_TIME_SRC_TOW_CONFIRMED (5) -- Time is set after decoding over-the-air GPS navigation data from multiple satellites - eQMI_LOC_TIME_SRC_TOW_AND_WEEK_CONFIRMED (6) -- Both time of the week and the GPS week number are known - eQMI_LOC_TIME_SRC_NAV_SOLUTION (7) -- Time is set by the position engine after the fix is obtained - eQMI_LOC_TIME_SRC_SOLVE_FOR_TIME (8) -- Time is set by the position engine after performing SFT; this is done when the clock time uncertainty is large - eQMI_LOC_TIME_SRC_GLO_TOW_DECODE (9) -- Time is set after decoding GLO satellites - eQMI_LOC_TIME_SRC_TIME_TRANSFORM (10) -- Time is set after transforming the GPS to GLO time - eQMI_LOC_TIME_SRC_WCDMA_SLEEP_TIME_TAGGING (11) -- Time is set by the sleep time tag provided by the WCDMA network - eQMI_LOC_TIME_SRC_GSM_SLEEP_TIME_TAGGING (12) -- Time is set by the sleep time tag provided by the GSM network - eQMI_LOC_TIME_SRC_UNKNOWN (13) -- Source of the time is unknown - eQMI_LOC_TIME_SRC_SYSTEM_TIMETICK (14) -- Time is derived from the system clock (better known as the slow clock); GNSS time is maintained irrespective of the GNSS receiver state - eQMI_LOC_TIME_SRC_QZSS_TOW_DECODE (15) -- Time is set after decoding QZSS satellites - eQMI_LOC_TIME_SRC_BDS_TOW_DECODE (16) -- Time is set after decoding BDS satellites */ /* Optional */ /* Sensor Data Usage */ uint8_t sensorDataUsage_valid; /**< Must be set to true if sensorDataUsage is being passed */ qmiLocSensorUsageIndicatorStructT_v02 sensorDataUsage; /**< \vspace{0.06in} \n Indicates whether sensor data was used in computing the position in this position report. */ /* Optional */ /* Fix Count for This Session */ uint8_t fixId_valid; /**< Must be set to true if fixId is being passed */ uint32_t fixId; /**< Fix count for the session. Starts with 0 and increments by one for each successive position report for a particular session. */ /* Optional */ /* SVs Used to Calculate the Fix */ uint8_t gnssSvUsedList_valid; /**< Must be set to true if gnssSvUsedList is being passed */ uint32_t gnssSvUsedList_len; /**< Must be set to # of elements in gnssSvUsedList */ uint16_t gnssSvUsedList[QMI_LOC_MAX_SV_USED_LIST_LENGTH_V02]; /**< Each entry in the list contains the SV ID of a satellite used for calculating this position report. The following information is associated with each SV ID: \n Range: \n - For GPS: 1 to 32 \n - For SBAS: 33 to 64 \n - For GLONASS: 65 to 96 \n - For QZSS: 193 to 197 \n - For BDS: 201 to 237 */ /* Optional */ /* Altitude Assumed */ uint8_t altitudeAssumed_valid; /**< Must be set to true if altitudeAssumed is being passed */ uint8_t altitudeAssumed; //FALSE说明海拔是计算出来的,TRUE说明海拔是推测的 /**< Indicates whether altitude is assumed or calculated: \begin{itemize1} \item 0x00 (FALSE) -- Altitude is calculated \item 0x01 (TRUE) -- Altitude is assumed; there may not be enough satellites to determine the precise altitude \vspace{-0.18in} \end{itemize1}*/ }qmiLocEventPositionReportIndMsgT_v02; /* Message */

跟locClientHandleSatReportInd的作用类似,locClientHandlePosReportInd的主要作用是打印position相应的信息,具体实现如下: 
vendor/qcom/opensource/location/loc_api/loc_api_v02/loc_api_v02_client.c

static bool locClientHandlePosReportInd ( uint32_t msg_id, const void* ind_buf, uint32_t ind_buf_len ) { // validate position report //把decorder出来的数据强转成qmiLocEventPositionReportIndMsgT_v02*类型的 qmiLocEventPositionReportIndMsgT_v02 *posReport = (qmiLocEventPositionReportIndMsgT_v02 *)ind_buf; //打印相应的position信息 LOC_LOGV ("%s:%d]: len = %d lat = %f, lon = %f, alt = %f\n", __func__, __LINE__, ind_buf_len, posReport->latitude, posReport->longitude, posReport->altitudeWrtEllipsoid); return true; }

localEventCallback最终绑定的是globalEventCb,具体在《gps搜星流程(下)》有讲过,这里就不再讲了,我们直接来看globalEventCb: 
vendor/qcom/opensource/location/loc_api/loc_api_v02/LocApiV02.cpp

static void globalEventCb(locClientHandleType clientHandle, uint32_t eventId, const locClientEventIndUnionType eventPayload, void* pClientCookie) { MODEM_LOG_CALLFLOW(%s, loc_get_v02_event_name(eventId)); LocApiV02 *locApiV02Instance = (LocApiV02 *)pClientCookie; LOC_LOGV ("%s:%d] client = %p, event id = %d, client cookie ptr = %p\n", __func__, __LINE__, clientHandle, eventId, pClientCookie); // return if null is passed if( NULL == locApiV02Instance) { LOC_LOGE ("%s:%d] NULL object passed : client = %p, event id = %d\n", __func__, __LINE__, clientHandle, eventId); return; } locApiV02Instance->eventCb(clientHandle, eventId, eventPayload); }

看下eventCb的具体实现: 
vendor/qcom/opensource/location/loc_api/loc_api_v02/LocApiV02.cpp

/* event callback registered with the loc_api v02 interface */ void LocApiV02 :: eventCb(locClientHandleType clientHandle, uint32_t eventId, locClientEventIndUnionType eventPayload) { LOC_LOGD("%s:%d]: event id = %d\n", __func__, __LINE__, eventId); switch(eventId) { ... //跟搜星流程不一样了哦,这里是position report,不是satellite report了哈 //Position Report case QMI_LOC_EVENT_POSITION_REPORT_IND_V02: reportPosition(eventPayload.pPositionReportEvent); break; ... } }

在看reportPosition之前,有两个结构体需要介绍一下: 
1:loc eng层能识别的position格式UlpLocation: 
hardware/qcom/gps/core/gps_extended_c.h

typedef struct { /** set to sizeof(UlpLocation) */ size_t size; GpsLocation gpsLocation; //看到了没,HAL层能识别的GpsLocation类型!!! /* Provider indicator for HYBRID or GPS */ uint16_t position_source; /*allows HAL to pass additional information related to the location */ int rawDataSize; /* in # of bytes */ void * rawData; bool is_indoor; float floor_number; char map_url[GPS_LOCATION_MAP_URL_SIZE]; unsigned char map_index[GPS_LOCATION_MAP_INDEX_SIZE]; } UlpLocation;

2:HAL层能够识别的position格式GpsLocation: 
hardware/libhardware/include/hardware/gps.h

/** Represents a location. */ typedef struct { /** set to sizeof(GpsLocation) */ size_t size; /** Contains GpsLocationFlags bits. */ uint16_t flags; /** Represents latitude in degrees. */ double latitude; /** Represents longitude in degrees. */ double longitude; /** Represents altitude in meters above the WGS 84 reference * ellipsoid. */ double altitude; /** Represents speed in meters per second. */ float speed; /** Represents heading in degrees. */ float bearing; /** Represents expected accuracy in meters. */ float accuracy; /** Timestamp for the location fix. */ GpsUtcTime timestamp; } GpsLocation;

继续跟进看下reportPosition的具体实现: 
vendor/qcom/opensource/location/loc_api/loc_api_v02/LocApiV02.cpp

/* convert position report to loc eng format and send the converted position to loc eng */ void LocApiV02 :: reportPosition ( const qmiLocEventPositionReportIndMsgT_v02 *location_report_ptr) { //从传入的参数可以看到,loc_api层用的position类型是qmiLocEventPositionReportIndMsgT_v02*类型的 //UlpLocation类型,这个是给loc eng层用的哈,所以可以猜测这个函数的作用是: //把qmiLocEventPositionReportIndMsgT_v02逐步填充到UlpLocation中,然后传递给loc eng层 UlpLocation location; LocPosTechMask tech_Mask = LOC_POS_TECH_MASK_DEFAULT; LOC_LOGD("Reporting postion from V2 Adapter\n"); memset(&location, 0sizeof (UlpLocation)); location.size = sizeof(location); GpsLocationExtended locationExtended; memset(&locationExtended, 0sizeof (GpsLocationExtended)); locationExtended.size = sizeof(locationExtended); // Process the position from final and intermediate reports if( (location_report_ptr->sessionStatus == eQMI_LOC_SESS_STATUS_SUCCESS_V02) || (location_report_ptr->sessionStatus == eQMI_LOC_SESS_STATUS_IN_PROGRESS_V02) ) { // Latitude & Longitude if( (location_report_ptr->latitude_valid == 1 ) && (location_report_ptr->longitude_valid == 1) && (location_report_ptr->latitude != 0 || location_report_ptr->longitude!= 0)) { //看见没?开始填充了UlpLocation类型了,这里填充的是flags,latitude,longtitude三个 //这里gpsLocation是GpsLocation类型的,所以一步到位直接填充的是HAL层能识别的GpsLocation类型 location.gpsLocation.flags |= GPS_LOCATION_HAS_LAT_LONG; location.gpsLocation.latitude = location_report_ptr->latitude; location.gpsLocation.longitude = location_report_ptr->longitude; // Time stamp (UTC) if(location_report_ptr->timestampUtc_valid == 1) { //如果timestampUtc是可用的,则填充到GpsLocation的timestamp location.gpsLocation.timestamp = location_report_ptr->timestampUtc; } // Altitude if(location_report_ptr->altitudeWrtEllipsoid_valid == 1 ) { //填充GpsLocation的altitude location.gpsLocation.flags |= GPS_LOCATION_HAS_ALTITUDE; location.gpsLocation.altitude = location_report_ptr->altitudeWrtEllipsoid; } // Speed if((location_report_ptr->speedHorizontal_valid == 1) && (location_report_ptr->speedVertical_valid ==1 ) ) { //原来GpsLocation的速度是用勾股定理算出来的,水平速度和海拔速度的平方和开根号 location.gpsLocation.flags |= GPS_LOCATION_HAS_SPEED; location.gpsLocation.speed = sqrt( (location_report_ptr->speedHorizontal * location_report_ptr->speedHorizontal) + (location_report_ptr->speedVertical * location_report_ptr->speedVertical) ); } // Heading if(location_report_ptr->heading_valid == 1) { location.gpsLocation.flags |= GPS_LOCATION_HAS_BEARING; location.gpsLocation.bearing = location_report_ptr->heading; } // Uncertainty (circular) if( (location_report_ptr->horUncCircular_valid ) ) { //GpsLocation的精度,单位是m location.gpsLocation.flags |= GPS_LOCATION_HAS_ACCURACY; location.gpsLocation.accuracy = location_report_ptr->horUncCircular; } // Technology Mask tech_Mask |= location_report_ptr->technologyMask; //Mark the location source as from GNSS location.gpsLocation.flags |= LOCATION_HAS_SOURCE_INFO; //填充UlpLocation的position_source location.position_source = ULP_LOCATION_IS_FROM_GNSS; if (location_report_ptr->magneticDeviation_valid) { locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_MAG_DEV; locationExtended.magneticDeviation = location_report_ptr->magneticDeviation; } if (location_report_ptr->DOP_valid) { locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_DOP; locationExtended.pdop = location_report_ptr->DOP.PDOP; locationExtended.hdop = location_report_ptr->DOP.HDOP; locationExtended.vdop = location_report_ptr->DOP.VDOP; } if (location_report_ptr->altitudeWrtMeanSeaLevel_valid) { locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL; locationExtended.altitudeMeanSeaLevel = location_report_ptr->altitudeWrtMeanSeaLevel; } if (location_report_ptr->vertUnc_valid) { locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_VERT_UNC; locationExtended.vert_unc = location_report_ptr->vertUnc; } if (location_report_ptr->speedUnc_valid ) { locationExtended.flags |= GPS_LOCATION_EXTENDED_HAS_SPEED_UNC; locationExtended.speed_unc = location_report_ptr->speedUnc; } //经过上面的一堆填充,总算拿到了完整的UlpLocation数据,当然也就包含了完整的GpsLocation数据, //然后调用LocApiBase::reportPosition,带着UlpLocation的数据进入到了loc eng层哈 LocApiBase::reportPosition( location, locationExtended, (void*)location_report_ptr, (location_report_ptr->sessionStatus == eQMI_LOC_SESS_STATUS_IN_PROGRESS_V02 ? LOC_SESS_INTERMEDIATE : LOC_SESS_SUCCESS), tech_Mask); } } else { LocApiBase::reportPosition(location, locationExtended, NULL, LOC_SESS_FAILURE); LOC_LOGD("%s:%d]: Ignoring position report with sess status = %d, " "fix id = %u\n", __func__, __LINE__, location_report_ptr->sessionStatus, location_report_ptr->fixId ); } }

继续跟进LocApiBase::reportPosition的实现: 
hardware/qcom/gps/core/LocApiBase.cpp

void LocApiBase::reportPosition(UlpLocation &location, GpsLocationExtended &locationExtended, void* locationExt, enum loc_sess_status status, LocPosTechMask loc_technology_mask) { // loop through adapters, and deliver to all adapters. TO_ALL_LOCADAPTERS( mLocAdapters[i]->reportPosition(location, locationExtended, locationExt, status, loc_technology_mask) ); }

TO_ALL_LOCADAPTERS的define前面有讲过,这里就不再赘述了,直接看下LocAdapterBase的reportPosition具体定义: 
hardware/qcom/gps/core/LocAdapterBase.h

class LocAdapterBase { ... public//带着UlpLocation类型的参数,postion的数据就这么传到了loc eng层 virtual void reportPosition(UlpLocation &location, GpsLocationExtended &locationExtended, void* locationExt, enum loc_sess_status status, LocPosTechMask loc_technology_mask); ... }

具体实现: 
hardware/qcom/gps/core/LocAdapterBase.cpp

void LocAdapterBase:: reportPosition(UlpLocation &location, GpsLocationExtended &locationExtended, void* locationExt, enum loc_sess_status status, LocPosTechMask loc_technology_mask) DEFAULT_IMPL()

继续在LocInternalAdapter里面去找下reportPosition的定义,原因前面有讲过: 
hardware/qcom/gps/loc_api/libloc_api_50001/LocEngAdapter.cpp

void LocInternalAdapter::reportPosition(UlpLocation &location, GpsLocationExtended &locationExtended, void* locationExt, enum loc_sess_status status, LocPosTechMask loc_technology_mask) { //注意new出来的LocEngReportPosition对象的第二个参数是传入的UlpLocation类型的数据 sendMsg(new LocEngReportPosition(mLocEngAdapter, location, locationExtended, locationExt, status, loc_technology_mask)); }

又到了sendMsg(new xxx)的套路了,这个在gps搜星流程里面有分析过,会把msg发送到message queue中,然后loopMain取出msg,依次执行msg的log()和proc(),所以我们直接来看LocEngReportPosition的proc(): 
hardware/qcom/gps/loc_api/libloc_api_50001/loc_eng.cpp

void LocEngReportPosition::proc() const { LocEngAdapter* adapter = (LocEngAdapter*)mAdapter; loc_eng_data_s_type* locEng = (loc_eng_data_s_type*)adapter->getOwner(); if (locEng->mute_session_state != LOC_MUTE_SESS_IN_SESSION) { bool reported = falseif (locEng->location_cb != NULL) { if (LOC_SESS_FAILURE == mStatus) { // in case we want to handle the failure case locEng->location_cb(NULL, NULL); reported = true; } // what's in the else if is... (line by line) // 1. this is a final fix; and // 1.1 it is a Satellite fix; or // 1.2 it is a sensor fix // 2. (must be intermediate fix... implicit) // 2.1 we accepte intermediate; and // 2.2 it is NOT the case that // 2.2.1 there is inaccuracy; and // 2.2.2 we care about inaccuracy; and // 2.2.3 the inaccuracy exceeds our tolerance else if ((LOC_SESS_SUCCESS == mStatus && ((LOC_POS_TECH_MASK_SATELLITE | LOC_POS_TECH_MASK_SENSORS | LOC_POS_TECH_MASK_HYBRID) & mTechMask)) || (LOC_SESS_INTERMEDIATE == locEng->intermediateFix && !((mLocation.gpsLocation.flags & GPS_LOCATION_HAS_ACCURACY) && (gps_conf.ACCURACY_THRES != 0) && (mLocation.gpsLocation.accuracy > gps_conf.ACCURACY_THRES)))) { //看到了久违的loc eng层callback,参数是mLocation,这个在哪里赋值的呢? //其实跟gps搜星流程一样的,mLocation的赋值操作是在LocEngReportPosition的构造函数阶段完成的 locEng->location_cb((UlpLocation*)&(mLocation), (void*)mLocationExt); reported = true; } } // if we have reported this fix if (reported && // and if this is a singleshot GPS_POSITION_RECURRENCE_SINGLE == locEng->adapter->getPositionMode().recurrence) { if (LOC_SESS_INTERMEDIATE == mStatus) { // modem could be still working for a final fix, // although we no longer need it. So stopFix(). locEng->adapter->stopFix(); } // turn off the session flag. locEng->adapter->setInSession(false); } if (locEng->generateNmea && mLocation.position_source == ULP_LOCATION_IS_FROM_GNSS && mTechMask & (LOC_POS_TECH_MASK_SATELLITE | LOC_POS_TECH_MASK_SENSORS | LOC_POS_TECH_MASK_HYBRID)) { unsigned char generate_nmea = reported && (mStatus != LOC_SESS_FAILURE); loc_eng_nmea_generate_pos(locEng, mLocation, mLocationExtended, generate_nmea); } // Free the allocated memory for rawData UlpLocation* gp = (UlpLocation*)&(mLocation); if (gp != NULL && gp->rawData != NULL) { delete (char*)gp->rawData; gp->rawData = http://blog.csdn.net/lele_cheny/article/details/NULL; gp->rawDataSize = 0; } } }

来看下LocEngReportPosition的构造函数具体实现: 
hardware/qcom/gps/loc_api/libloc_api_50001/loc_eng.cpp

LocEngReportPosition::LocEngReportPosition(LocAdapterBase* adapter, UlpLocation &loc, GpsLocationExtended &locExtended, void* locExt, enum loc_sess_status st, LocPosTechMask technology) : //第二个参数是loc,被赋值给了mLocation,跟callback用的那个参数就对起来了 LocMsg(), mAdapter(adapter), mLocation(loc), mLocationExtended(locExtended), mLocationExt(((loc_eng_data_s_type*) ((LocEngAdapter*) (mAdapter))->getOwner())->location_ext_parser(locExt)), mStatus(st), mTechMask(technology) { locallog(); }


到这里modem层到loc eng层的position数据就对应起来了,接下来要看下loc eng层的数据要怎么传到android framework层!


为了不重复造轮子,我们直接用《gps搜星流程(上)》总结的规律:HAL层,loc层,loc eng层的callback关系就打通了,都是透传,也就是说loc_eng_data_s_type(loc eng层)的callback函数其实就是对应着GpsCallbacks(HAL层)同名的callback函数。

但是有一点跟gps搜星流程不一致的是,callback的参数在gps搜星流程一文中用的是GpsSvStatus,属于HAL层的数据结构,但是gps定位流程的callback用的参数是UlpLocation,属于loc_api层的数据结构,所以我们唯一要理清的一点就是这个数据类型是在哪里转换的。

hardware/qcom/gps/loc_api/libloc_api_50001/oc.cpp

//这里把local_loc_cb跟LocCallbacks的location_cb绑定起来, //跟sv_status_cb一样,这里也用了两个中间callback,分别是local_loc_cb和gps_loc_cb LocCallbacks clientCallbacks = {local_loc_cb, /* location_cb */ ...}; static void local_loc_cb(UlpLocation* location, void* locExt) { ENTRY_LOG(); if (NULL != location) { CALLBACK_LOG_CALLFLOW("location_cb - from", %d, location->position_source); if (NULL != gps_loc_cb) { //看到了没,&location->gpsLocation就是GpsLocation*类型的, //location的loc eng层到HAL层的数据类型就是在这里转换的 gps_loc_cb(&location->gpsLocation); } } EXIT_LOG(%s, VOID_RET); } //GpsCallbacks的location_cb跟gps_loc_cb绑定到一起,其实就是绑定的是local_loc_cb, //也就是LocCallbacks的location_cb,这个过程中完成了UlpLocation到GpsLocation的转换 gps_loc_cb = callbacks->location_cb;

这里就走到了GpsCallbacks的location_cb,跟进去看下: 
frameworks/base/services/core/jni/com_android_server_location_GpsLocationProvider.cpp

GpsCallbacks sGpsCallbacks = { //GpsCallbacks的location_cb又绑定到了jni的location_callback //也就是说loc eng层的proc()最终调用到了jni的location_callback方法 sizeof(GpsCallbacks), location_callback, status_callback, sv_status_callback, nmea_callback, set_capabilities_callback, acquire_wakelock_callback, release_wakelock_callback, create_thread_callback, request_utc_time_callback, };

看下location_callback的具体实现: 
frameworks/base/services/core/jni/com_android_server_location_GpsLocationProvider.cpp

static void location_callback(GpsLocation* location) { JNIEnv* env = AndroidRuntime::getJNIEnv(); 又是典型的jni层调用android framework层函数的用法 env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags, (jdouble)location->latitude, (jdouble)location->longitude, (jdouble)location->altitude, (jfloat)location->speed, (jfloat)location->bearing, (jfloat)location->accuracy, (jlong)location->timestamp); checkAndClearExceptionFromCallback(env, __FUNCTION__); } frameworks/base/services/core/jni/com_android_server_location_GpsLocationProvider.cpp ```c static jmethodID method_reportLocation; method_reportLocation = env->GetMethodID(clazz, "reportLocation""(IDDDFFFJ)V"); <div class="se-preview-section-delimiter"></div>

接下来要去找一下reportLocation的实现,这就到了android framework层了,具体实现如下: 
frameworks/base/services/core/Java/com/android/server/location/GpsLocationProvider.java

/** * called from native code to update our position. */ private void reportLocation(int flags, double latitude, double longitude, double altitude, float speed, float bearing, float accuracy, long timestamp) { //这里有一点跟reportSvStatus不一样,这里的reportLocation是带有参数的,直接传递到android framework层 //reportSvStatus的数据是存储在了jni层,在jni层有一个写操作(memcpy做的)和一个读操作(native_read_sv_status做的) if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + " timestamp: " + timestamp); //接下来是把jni层传递上来的参数填充到android framework层的location数据结构中,这个结构的类型就是Location类型 synchronized (mLocation) { mLocationFlags = flags; if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { mLocation.setLatitude(latitude); mLocation.setLongitude(longitude); mLocation.setTime(timestamp); // It would be nice to push the elapsed real-time timestamp // further down the stack, but this is still useful mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); } if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) { mLocation.setAltitude(altitude); } else { mLocation.removeAltitude(); } if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) { mLocation.setSpeed(speed); } else { mLocation.removeSpeed(); } if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) { mLocation.setBearing(bearing); } else { mLocation.removeBearing(); } if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) { mLocation.setAccuracy(accuracy); } else { mLocation.removeAccuracy(); } mLocation.setExtras(mLocationExtras); try { mILocationManager.reportLocation(mLocation, false); } catch (RemoteException e) { Log.e(TAG, "RemoteException calling reportLocation"); } } mLastFixTime = System.currentTimeMillis(); // report time to first fix if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) { mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime); if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); // notify status listeners mListenerHelper.onFirstFix(mTimeToFirstFix); } if (mSingleShot) { stopNavigating(); } if (mStarted && mStatus != LocationProvider.AVAILABLE) { // we want to time out if we do not receive a fix // within the time out and we are requesting infrequent fixes if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { mAlarmManager.cancel(mTimeoutIntent); } // send an intent to notify that the GPS is receiving fixes. Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); mContext.sendBroadcastAsUser(intent, UserHandle.ALL); updateStatus(LocationProvider.AVAILABLE, mSvCount); } if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { if (DEBUG) Log.d(TAG, "got fix, hibernating"); hibernate(); } }


到这里,从modem层(前面有讲过,这里的modem层其实是指modem+QMI)到android framework层的的gps location数据就分析完毕了,android framework主要拿到了经度,维度,时间,海拔,速度,精度等内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值