1. Android LocationManagerService流程分析
2. Android 从NetWork获取位置信息流程分析
3. Android 从PassiveProvider获取位置信息
此provider用于通过GPS提供位置信息,此功能需要设备硬件支持。
涉及的类:
frameworks/base/location/java/android/location/LocationManager.java
frameworks/base/services/core/java/com/android/server/LocationManagerService.java
frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
frameworks/base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
hardware/interfaces/gnss/1.1/default/Gnss.cpp
GnssLocationProvider用到native 的方法都在com_android_server_location_GnssLocationProvider.cpp 文件中进行映射和定义。
此provider在LocationManagerService.java文件中的loadProvidersLocked方法中加载,如果设备支持GPS功能,则添加GnssLocationProvider。通过 addProviderLocked 方法将当前provider添加到mProvidersByName 和mProviders 全局变量中。
frameworks/base/services/core/java/com/android/server/LocationManagerService.java
if (GnssLocationProvider.isSupported()) { // 判断该设备是否支持GPS,如果支持则添加provider
// Create a gps location provider
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
mLocationHandler.getLooper());
mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
addProviderLocked(gnssProvider);
mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
}
GnssLocationProvider.isSupported() 方法会调用native层的 android_location_GnssLocationProvider_is_supported方法:
static jboolean android_location_GnssLocationProvider_is_supported(
JNIEnv* /* env */, jclass /* clazz */) {
return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
//
}
// gnssHal初始化,首先使用IGnss的V1.1版本是否可用,如果不可用再使用V1.0版本检测是否GPS可用。
static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
gnssHal_V1_1 = IGnss_V1_1::getService();
if (gnssHal_V1_1 == nullptr) {
ALOGD("gnssHal 1.1 was null, trying 1.0");
gnssHal = IGnss_V1_0::getService();
} else {
gnssHal = gnssHal_V1_1;
}
}
当三方应用调用requestLocationUpdates 方法来请求GPS位置信息时,最终会调到每个provider的 setRequest 方法里,GnssLocationProvider 的setRequest 方法会通过handler发送SET_REQUEST 消息后调用 handleSetRequest 方法处理这个请求
frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
public void setRequest(ProviderRequest request, WorkSource source) {
sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
}
private final class ProviderHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
...
case SET_REQUEST:
GpsRequest gpsRequest = (GpsRequest) msg.obj;
handleSetRequest(gpsRequest.request, gpsRequest.source);
break;
...
private void handleSetRequest(ProviderRequest request, WorkSource source) {
mProviderRequest = request;
mWorkSource = source;
updateRequirements();
}
frameworks/base/services/core/java/com/android/server/location/GnssLocationProvider.java
private void updateRequirements() {
if (mProviderRequest == null || mWorkSource == null) {
return;
}
boolean singleShot = false;
// ProviderRequest.locationRequests 中保存了同一时间所有的位置信息请求,判断是否只需要从GPS请求一次数据即可完成所有应用的请求。
if (mProviderRequest.locationRequests != null
&& mProviderRequest.locationRequests.size() > 0) {
// if any request has zero or more than one updates
// requested, then this is not single-shot mode
singleShot = true;
for (LocationRequest lr : mProviderRequest.locationRequests) {
if (lr.getNumUpdates() != 1) {
singleShot = false;
}
}
}
if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
// 记录请求信息
updateClientUids(mWorkSource);
mFixInterval = (int) mProviderRequest.interval;
mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
// check for overflow
if (mFixInterval != mProviderRequest.interval) {
Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
mFixInterval = Integer.MAX_VALUE;
}
// 设置 GPS engine 参数
if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
// change period and/or lowPowerMode
if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
mFixInterval, 0, 0, mLowPowerMode)) {
Log.e(TAG, "set_position_mode failed in updateRequirements");
}
} else if (!mStarted) {
// 如果没有启动GPS 定位,启动它
startNavigating(singleShot);
} else {
// GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING
// 当请求位置信息最小间隔事件比 NO_FIX_TIMEOUT大,则在NO_FIX_TIMEOUT 时间后进行休眠,不再进行地位(应该是为了省电)
mAlarmManager.cancel(mTimeoutIntent);
if (mFixInterval >= NO_FIX_TIMEOUT) {
// set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
// and our fix interval is not short
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); }
}
} else {
updateClientUids(new WorkSource());
// 停止获取位置信息
stopNavigating();
mAlarmManager.cancel(mWakeupIntent);
mAlarmManager.cancel(mTimeoutIntent);
}
}
mBroadcastReceiver 会收到TimeoutIntent里面标识的广播,然后执行hibernate方法来关闭GPS定位
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
...
if (action.equals(ALARM_WAKEUP)) {
startNavigating(false);
} else if (action.equals(ALARM_TIMEOUT)) {
hibernate();
...
}
在关闭GPS定位后会在mFixInterval时间后启动mWakeupIntent广播开启GPS定位功能,mBroadcastReceiver 收到广播后会调用startNavigating启动GPS定位。
private void hibernate() {
// stop GPS until our next fix interval arrives
stopNavigating();
mAlarmManager.cancel(mTimeoutIntent);
mAlarmManager.cancel(mWakeupIntent);
long now = SystemClock.elapsedRealtime();
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
}
private void stopNavigating() {
if (mStarted) {
mStarted = false;
mSingleShot = false;
native_stop();
mLastFixTime = 0;
updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); // 将GPS 状态设置为暂时不可用的状态,这时我们通过getStatus方法将会得到GPS暂时不可用的状态
mLocationExtras.reset();
}
}
现在回到没有启动GPS的状态,调用startNavigating 方法启动它。
private void startNavigating(boolean singleShot) {
if (!mStarted) {
mTimeToFirstFix = 0;
mLastFixTime = 0;
mStarted = true;
mSingleShot = singleShot;
mPositionMode = GPS_POSITION_MODE_STANDALONE;
// 判断是否超过了GPS 限制的最大速度(600m/s),该值定义在ITAR_SPEED_LIMIT_METERS_PER_SECOND 变量中
if (mItarSpeedLimitExceeded) {
Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " +
"until slow enough speed reported.");
}
boolean agpsEnabled =
(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
// 通过AGPS和Properties设置SUPL mode
mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
// 判断GPS engine是否有定时功能,如果没有则默认频率为1s,如果有则频率间隔设置为用户请求的时间间隔
int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
// 设置GPS 模式
if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
interval, 0, 0, mLowPowerMode)) {
mStarted = false;
Log.e(TAG, "set_position_mode failed in startNavigating()");
return;
}
// 启动GPS定位
if (!native_start()) {
mStarted = false;
Log.e(TAG, "native_start failed in startNavigating()");
return;
}
// 休眠GPS定位功能,当达到用户需要定位数据的时候再请求数据。
updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
mLocationExtras.reset();
mFixRequestTime = SystemClock.elapsedRealtime();
if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
// set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
// and our fix interval is not short
if (mFixInterval >= NO_FIX_TIMEOUT) {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
}
}
}
}
native_set_position_mode 方法设置定位属性会调用com_android_server_location_GnssLocationProvider 类下面的android_location_GnssLocationProvider_set_position_mode 方法
com_android_server_location_GnssLocationProvider.cpp
static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
jint preferred_time, jboolean low_power_mode) {
Return<bool> result = false;
if (gnssHal_V1_1 != nullptr) {
// 查看了setPositionMode_1_1 方法,发现知识往GPS 里面设置了请求位置信息的频率时间间隔,并没有做其他属性设置。
result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence),
min_interval,
preferred_accuracy,
preferred_time,
low_power_mode);
// setPositionMode 方法会调用 mGnssIface ->set_position_mode 方法设置各个参数,暂时没有找到 mGnssIface 的实现类
} else if (gnssHal != nullptr) {
result = gnssHal->setPositionMode(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence),
min_interval,
preferred_accuracy,
preferred_time);
}
if (!result.isOk()) {
ALOGE("%s: GNSS setPositionMode failed\n", __func__);
return JNI_FALSE;
} else {
return result;
}
}
native_start 会调用JNI层的android_location_GnssLocationProvider_start 方法启动GPS定位, gnssHal 的实现为Gnss.cpp类
com_android_server_location_GnssLocationProvider.cpp
static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) {
if (gnssHal != nullptr) {
auto result = gnssHal->start(); // 调用Gnss.start()方法
if (!result.isOk()) {
return JNI_FALSE;
} else {
return result;
}
} else {
return JNI_FALSE;
}
}
Gnss.cpp
Return<bool> Gnss::start() {
// 重启GPS 定位
if (mIsActive) {
ALOGW("Gnss has started. Restarting...");
stop();
}
mIsActive = true;
// 当GPS已经启动,启动线程获取Location信息,等待mMinIntervalMs 时间后,回调reportLocation 方法和reportSvStatus 方法将数据发送给com_android_server_location_GnssLocationProvider
mThread = std::thread([this]() {
while (mIsActive == true) {
auto svStatus = this->getMockSvStatus();
this->reportSvStatus(svStatus);
auto location = this->getMockLocation();
this->reportLocation(location);
std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
}
});
return true;
}
下面以reportLocation 为例,通过sGnssCallback->gnssLocationCb 回传获取到的Location信息
Gnss.cpp
Return<void> Gnss::reportLocation(const GnssLocation& location) const {
std::unique_lock<std::mutex> lock(mMutex);
if (sGnssCallback == nullptr) {
ALOGE("%s: sGnssCallback is null.", __func__);
return Void();
}
// 调用gnssLocationCb方法将数据传给 方法将数据发送给com_android_server_location_GnssLocationProvider
sGnssCallback->gnssLocationCb(location);
return Void();
}
sGnssCallback 是通过Gnss.setCallback_1_1()方法传进来的,整个初始化sGnssCallback流程如下
GnssLocationProvider.enable() -> GnssLocationProvider.handleEnable() -> GnssLocationProvider.native_init() -> com_android_server_location_GnssLocationProvider->android_location_GnssLocationProvider_init() -> gnssHal_V1_1->setCallback_1_1(IGnssCallback) or gnssHal->setCallback(IGnssCallback)
到此,IGnssCallback 回调即从com_android_server_location_GnssLocationProvider 传到了 gnss 类中。
现在我们分析sGnssCallback->gnssLocationCb的实现方法,在com_android_server_location_GnssLocationProvider.cpp 文件中实现的。
com_android_server_location_GnssLocationProvider.cpp
Return<void> GnssCallback::gnssLocationCb(const GnssLocation& location) {
JNIEnv* env = getJniEnv();
// 将Location对象封装为可以跨进程的对象,之后需要发送给GnssLocationProvider
jobject jLocation = translateLocation(env, location);
bool hasLatLong = (static_cast<uint32_t>(location.gnssLocationFlags) &
GnssLocationFlags::HAS_LAT_LONG) != 0;
// 通过 method_reportLocation 方法回调GnssLocationProvider的reportLocation()方法。
env->CallVoidMethod(mCallbacksObj,
method_reportLocation,
boolToJbool(hasLatLong),
jLocation);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
env->DeleteLocalRef(jLocation);
return Void();
}
在 android_location_GnssLocationProvider_init_once 方法中会将 GnssLocationProvider 中的native方法与 com_android_server_location_GnssLocationProvider 中的方法进行映射,比如我们在com_android_server_location_GnssLocationProvider 中调用env->CallVoidMethod(mCallbacksObj, method_reportLocation, boolToJbool(hasLatLong), jLocation),会调用GnssLocationProvider类中的reportLocation()方法。
com_android_server_location_GnssLocationProvider.cpp
static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass clazz) {
method_reportLocation = env->GetMethodID(clazz, "reportLocation",
"(ZLandroid/location/Location;)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V");
...
}
到此,已经将硬件获取到的GPS位置信息上传到了FW层。reportLocation()方法会调用LocationManagerService的reportLocation()方法回调用户的回调函数或者通过广播的形式将Location发送给三方应用(具体流程可以参考LocationManagerService.md中的分析)