android gps機制分析--之三
1 gps開啟/初始化
在Java層開啟gps,其實對於gps庫來說,就是執行初始化過程。1.1 Java層分析
android系統中開啟GPS的方法往資料庫裡面寫值,
private void enableGps(boolean enable) {
try {
Settings.Secure.setLocationProviderEnabled(getContentResolver(),
LocationManager.GPS_PROVIDER, enable);
} catch (Exception e) {
}
}
最後往setting資料庫中的location_providers_allowed欄位寫值。
putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, userId);
LocationManagerService的systemRunning方法中會監聽setting資料庫中的location_providers_allowed欄位值的變化,
mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true, new ContentObserver(mLocationHandler) { @Override public void onChange(boolean selfChange) { synchronized (mLock) { updateProvidersLocked(); } } }, UserHandle.USER_ALL);
如果該值有變化,則呼叫updateProvidersLocked方法。主要的流程圖如下,
在updateProvidersLocked方法中,如果支援gps,呼叫updateProviderListenersLocked方法,
updateProviderListenersLocked(name, true);
updateProviderListenersLocked主要方法如下,
••••• boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name); •••• if (enabled) { p.enable(); if (listeners > 0) { applyRequirementsLocked(provider); } } else { p.disable(); }
首先呼叫isAllowedByCurrentUserSettingsLocked方法讀取資料庫欄位值,然後根據該值進行相應的開啟/關閉GPS操作。
private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
if (mEnabledProviders.contains(provider)) {
return true;
}
if (mDisabledProviders.contains(provider)) {
return false;
}
// Use system settings
ContentResolver resolver = mContext.getContentResolver();
return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
}
Settings中的isLocationProviderEnabledForUser方法如下,
public static final boolean isLocationProviderEnabledForUser(ContentResolver cr, String provider, int userId) {
String allowedProviders = Settings.Secure.getStringForUser(cr,
LOCATION_PROVIDERS_ALLOWED, userId);
return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
}
GpsLocationProvider的enable方法如下,
@Override
public void enable() {
synchronized (mLock) {
if (mEnabled) return;
mEnabled = true;
}
sendMessage(ENABLE, 1, null);
}
ProviderHandler對ENABLE訊息處理如下,
case ENABLE:
if (msg.arg1 == 1) {
handleEnable();
} else {
handleDisable();
}
break;
handleEnable方法如下,
private void handleEnable() {
if (DEBUG) Log.d(TAG, "handleEnable");
boolean enabled = native_init(); //初始化GPS HAL層模組
if (enabled) {
mSupportsXtra = native_supports_xtra();//判斷GPS模組是否支援Xtra
// TODO: remove the following native calls if we can make sure they are redundant.
if (mSuplServerHost != null) {// 設定SUPL伺服器地址和埠
native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
}
if (mC2KServerHost != null) { //設定CDMA2000
native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
}
mGpsMeasurementsProvider.onGpsEnabledChanged();
mGpsNavigationMessageProvider.onGpsEnabledChanged();
} else {
synchronized (mLock) {
mEnabled = false;
}
Log.w(TAG, "Failed to enable location provider");
}
}
1.2 HAL初始化
com_android_server_location_GpsLocationProvider的android_location_GpsLocationProvider_init方法如下,
static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
{
// this must be set before calling into the HAL library
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);
// fail if the main interface fails to initialize
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
return JNI_FALSE;
// if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
// but continue to allow the rest of the GPS interface to work.
if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
sGpsXtraInterface = NULL;
if (sAGpsInterface)
sAGpsInterface->init(&sAGpsCallbacks);
if (sGpsNiInterface)
sGpsNiInterface->init(&sGpsNiCallbacks);
if (sAGpsRilInterface)
sAGpsRilInterface->init(&sAGpsRilCallbacks);
if (sGpsGeofencingInterface)
sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
return JNI_TRUE;
}
主要是向HAL層設定回撥方法介面,當HAL層有情況需要通知JNI層時,就會回撥這些方法。
這6組回撥方法的定義,回撥方法幾乎完全一樣。sGpsCallbacks的定義如下,
GpsCallbacks sGpsCallbacks = {
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,
};
sGpsCallbacks中包含9個回撥方法。
這樣,HAL庫就可以回撥C方法了。
由此可見, com_android_server_location_GpsLocationProvider只是Java和HAL庫之間的一個紐帶。
1,Java中載入HAL庫,並且對HAL庫進行初始化。然後就可以對HAL的GPS發出指令,例如開啟,關閉GPS等。這時資料流的方向為,
Java-->JNI--> GPS庫
2,GPS庫中執行開啟/關閉動作,向Java上報衛星以及定位訊息。這時資料流的方向為,
GPS庫-->JNI--> Java
GPS庫中對應的init方法為, loc.cpp 的loc_init方法,
static int loc_init(GpsCallbacks* callbacks)
{
int retVal = -1;
ENTRY_LOG();
LOC_API_ADAPTER_EVENT_MASK_T event;
if (NULL == callbacks) {
LOC_LOGE("loc_init failed. cb = NULL\n");
EXIT_LOG(%d, retVal);
return retVal;
}
event = LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT |
LOC_API_ADAPTER_BIT_SATELLITE_REPORT |
LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST |
LOC_API_ADAPTER_BIT_ASSISTANCE_DATA_REQUEST |
LOC_API_ADAPTER_BIT_IOCTL_REPORT |
LOC_API_ADAPTER_BIT_STATUS_REPORT |
LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT |
LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST;
// 繼續註冊回撥
LocCallbacks clientCallbacks = {local_loc_cb, /* location_cb */
callbacks->status_cb, /* status_cb */
local_sv_cb, /* sv_status_cb */
callbacks->nmea_cb, /* nmea_cb */
callbacks->set_capabilities_cb, /* set_capabilities_cb */
callbacks->acquire_wakelock_cb, /* acquire_wakelock_cb */
callbacks->release_wakelock_cb, /* release_wakelock_cb */
callbacks->create_thread_cb, /* create_thread_cb */
NULL, /* location_ext_parser */
NULL, /* sv_ext_parser */
callbacks->request_utc_time_cb, /* request_utc_time_cb */
};
gps_loc_cb = callbacks->location_cb;
gps_sv_cb = callbacks->sv_status_cb;
// loc_eng_init以及裡面的方法較複雜,暫不論述。
retVal = loc_eng_init(loc_afw_data, &clientCallbacks, event, NULL);
loc_afw_data.adapter->mSupportsAgpsRequests = !loc_afw_data.adapter->hasAgpsExtendedCapabilities();
loc_afw_data.adapter->mSupportsPositionInjection = !loc_afw_data.adapter->hasCPIExtendedCapabilities();
loc_afw_data.adapter->mSupportsTimeInjection = !loc_afw_data.adapter->hasCPIExtendedCapabilities();
loc_afw_data.adapter->setGpsLockMsg(0);
loc_afw_data.adapter->requestUlp(getCarrierCapabilities());
loc_afw_data.adapter->setXtraUserAgent();
if(retVal) {
LOC_LOGE("loc_eng_init() fail!");
goto err;
}
loc_afw_data.adapter->setPowerVoteRight(loc_get_target() == TARGET_QCA1530);
loc_afw_data.adapter->setPowerVote(true);
LOC_LOGD("loc_eng_init() success!");
err:
EXIT_LOG(%d, retVal);
return retVal;
}
gps.h中有對應的GpsCallbacks結構,
typedef struct {
/** set to sizeof(GpsCallbacks) */
size_t size;
gps_location_callback location_cb;
gps_status_callback status_cb;
gps_sv_status_callback sv_status_cb;
gps_nmea_callback nmea_cb;
gps_set_capabilities set_capabilities_cb;
gps_acquire_wakelock acquire_wakelock_cb;
gps_release_wakelock release_wakelock_cb;
gps_create_thread create_thread_cb;
gps_request_utc_time request_utc_time_cb;
} GpsCallbacks;
這樣,HAL層的gps_location_callback方法就對應com_android_server_location_GpsLocationProvide
中的location_callback方法,其他的回撥對應的也一樣。