Android 从GPS中获取位置信息流程分析

与Android 位置信息相关的分析

1. Android LocationManagerService流程分析
2. Android 从NetWork获取位置信息流程分析
3. Android 从PassiveProvider获取位置信息

GnssLocationProvider

此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中的分析)

你可能感兴趣的:(android开发,android,java,开发语言,GPS,GnssLocation)