Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


title: Android 17 LocationManager 架构与性能优化 chapter: '1.25' section: '1.25' status: finalized pipeline_stage: ready-to-publish applicable_versions: Android 12 (API 31) - Android 17 (API 37) last_verified: '2026-08-18' last_verified_against: AOSP android-17.0.0_r1 confidence: high sources:

  • type: aosp path: frameworks/base/location/java/android/location/LocationManager.java
  • type: aosp path: frameworks/base/location/java/android/location/LocationRequest.java
  • type: aosp path: frameworks/base/location/java/android/location/GnssMeasurementRequest.java
  • type: aosp path: frameworks/base/location/java/android/location/GnssMeasurementsEvent.java
  • type: aosp path: frameworks/base/location/java/android/location/GnssStatus.java
  • type: aosp path: frameworks/base/location/java/android/location/ILocationManager.aidl
  • type: aosp path: frameworks/base/location/java/android/location/ILocationListener.aidl
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/LocationManagerService.java
  • type: aosp path: frameworks/base/services/java/com/android/server/SystemServer.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/provider/LocationProviderManager.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/fudger/LocationFudger.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/gnss/GnssPsdsDownloader.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
  • type: aosp path: frameworks/base/services/core/jni/gnss/Gnss.cpp
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/geofence/GeofenceManager.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
  • type: aosp path: frameworks/base/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java
  • type: aosp path: hardware/interfaces/gnss/aidl/android/hardware/gnss/IGnss.aidl
  • type: aosp path: hardware/interfaces/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
  • type: aosp path: hardware/interfaces/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
  • type: aosp path: hardware/interfaces/gnss/aidl/android/hardware/gnss/IGnssGeofence.aidl
  • type: aosp path: hardware/interfaces/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl
  • type: official path: developer.android.com/reference/android/location/LocationManager
  • type: official path: developer.android.com/reference/android/location/LocationRequest
  • type: official path: developer.android.com/reference/android/location/GnssMeasurementRequest
  • type: official path: developer.android.com/develop/sensors-and-location/location/permissions
  • type: official path: developer.android.com/develop/sensors-and-location/location/background tags:
  • location
  • gps
  • gnss
  • system-service
  • geofence
  • hal
  • performance
  • power related_chapters:
  • '1.10'
  • '1.21'
  • '1.19'
  • '5.3'
  • '8.1'

Android 17 LocationManager 架构与性能优化

LocationManager 是 Android 平台位置 API 的客户端入口。应用选定 provider,描述更新间隔、质量、批处理延迟等需求,再通过 Binder 把请求交给 system_server。这里保留 API 中的 provider 一词,它表示按名称选择的位置提供者或数据源。服务端负责权限检查、前后台限制、请求合并、Provider 调度、结果裁剪和回调投递。

范围限定在 Android 平台 API 与 AOSP 服务端。Google Play services 的 FusedLocationProviderClientLocationCallback 和 Geofencing API 是另一套客户端 API;它们可能使用系统的 fused provider,也可能在自己的服务中增加策略,但不能用来解释 LocationManager 的公开调用链。

平台基线是 Android 17 / API 37 / android-17.0.0_r1,GNSS(全球卫星导航系统)HAL 接口以同一平台标签下的 hardware/interfaces 为准。GPS 是 GNSS 中的一套卫星系统,Android 的 gps provider 名称不表示底层只能使用 GPS 星座。Linux kernel 实现不在讨论范围内,厂商 GNSS 驱动行为不能推断为 LocationManagerService 的固定语义。

1. 系统边界:应用提出需求,Provider 提供位置

Android 17 的主链路如下:

App process
  LocationManager
    ├─ getLastKnownLocation(provider)
    ├─ getCurrentLocation(provider, ..., Consumer<Location>)
    └─ requestLocationUpdates(provider, ..., LocationListener/PendingIntent)
                     │
                     │ ILocationManager
                     ▼
system_server
  LocationManagerService
    └─ LocationProviderManager(每个 provider 一个实例)
         ├─ passive → PassiveLocationProvider
         ├─ gps     → GnssLocationProvider(默认)或配置的代理 Provider
         │              └─ GnssNative → JNI GnssHal → vendor GNSS HAL
         ├─ network → ProxyLocationProvider → 外部系统 Provider 服务
         └─ fused   → ProxyLocationProvider → 外部系统 Provider 服务

LocationManagerServiceSystemServer 中启动。Lifecycle 构造服务实例时先创建 passive provider,onStart() 发布 location Binder 服务;到 PHASE_THIRD_PARTY_APPS_CAN_START,再初始化 network、fused、GNSS 以及相关代理服务。GNSS 放在这些 Provider 之后初始化,避免早期 GNSS 回调依赖尚未就绪的系统组件。

1.1 四个常见 Provider 的含义

ProviderAndroid 17 framework 实现请求是否主动驱动数据源需要注意的边界
gps默认是 GnssLocationProvider,可由配置的代理 Provider 覆盖默认路径进入 JNI 和厂商 GNSS HAL;能力、功耗和射频表现取决于设备
networkProxyLocationProvider算法位于受配置约束的系统 Provider 服务中,AOSP 不规定其一定由 GMS 实现
fusedProxyLocationProvider系统要求存在可直接启动的系统实现;它不等同于 Play services 客户端类
passivePassiveLocationProvider只接收其他 Provider 已产生的位置,不独立启动定位硬件

在纯 AOSP、GMS(Google Mobile Services)设备和 OEM 设备上,network/fused 背后的包可能不同。framework 能验证的是绑定条件、Binder 协议和 Provider 输出,无法据此断言外部服务采用 Wi-Fi 指纹、卡尔曼滤波或某个私有数据库。设备若配置 GNSS Provider override(替代实现),gps 会绑定代理实现,进程内 HAL 路径则可注册为受 LOCATION_HARDWARE 权限保护的 gps_hardware provider。

1.2 FUSED_PROVIDER 与 Play services API

这两个名称容易产生误解:

  • LocationManager.FUSED_PROVIDER 是平台定义的 provider 名称。调用者仍通过 LocationManagerLocationListenerPendingIntent 使用它。
  • FusedLocationProviderClient 是 Google Play services 的客户端 API,回调类型是 LocationCallback
  • 平台 LocationManager 没有接收 LocationCallbackrequestLocationUpdates 重载。

排查问题时,应先看应用链接的是 android.location.* 还是 com.google.android.gms.location.*。API 入口不同,进程、日志和版本依赖也会不同。

[源码依据:SystemServer.javaLocationManagerService.LifecycleProxyLocationProvider.javaandroid-17.0.0_r1]

2. 提供者由调用者选择,quality 不负责自动选源

平台 API 的规则是:provider 决定请求交给谁,LocationRequest.quality 只是给该 Provider 的质量提示。

例如,调用:

locationManager.requestLocationUpdates(
        LocationManager.GPS_PROVIDER,
        request,
        executor,
        listener);

服务端会查找名为 gpsLocationProviderManager。它不会因为 request 使用 QUALITY_LOW_POWER 就把请求迁移到 network;同理,向 network provider 提交 QUALITY_HIGH_ACCURACY 也不会自动启动 GNSS。Provider 对 quality 的解释由具体实现决定。

旧的 Criteria API 可以让 framework 从现有 Provider 中挑选一个名称,但那是调用前的 Provider 选择,不是一次请求同时驱动多个 Provider。

2.1 LocationRequest 中值得区分的字段

字段服务端用途
intervalMillis期望更新周期,也是同一 Provider 合并请求时的主要调度输入
quality质量/功耗提示;数值越小表示要求越高,100104 更强
minUpdateIntervalMillis对单个注册的投递限速
minUpdateDistanceMeters对单个注册按位移过滤
maxUpdateDelayMillis允许批量延迟;达到条件时 Provider 才可能 batching(先缓存多条位置,再成批交付)
durationMillis注册有效时间
maxUpdates成功投递达到次数后移除注册
lowPower传给 Provider 的低功耗提示,是否支持由实现决定
WorkSource供有权限的调用者指定这项工作应归因给谁;普通应用不能随意伪造

公开的 Builder 形式自 API 31 起可用。maxUpdatesdurationMillis 也不是 Android 14 才出现的字段。

下面的示例用于明确指定平台 gps provider,并允许最多 10 秒的批量延迟:

LocationRequest request = new LocationRequest.Builder(5_000L)
        .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY)
        .setMinUpdateIntervalMillis(2_000L)
        .setMaxUpdateDelayMillis(10_000L)
        .build();

LocationListener listener = location -> {
    // 把重计算转交给工作线程;这里保持回调短小。
};

locationManager.requestLocationUpdates(
        LocationManager.GPS_PROVIDER,
        request,
        context.getMainExecutor(),
        listener);

LocationRequest.Builder(long) 的参数是更新间隔,不是 priority(优先级)。示例中的 10_000 / 2 >= 5_000 满足 framework 接受 batching 参数的基本比例,但设备还要具备 batching 扩展,Provider 也要接受该请求;因此这段代码不构成硬件批处理保证。

[源码依据:LocationManager.javaLocationRequest.javaLocationManagerService.validateLocationRequest()android-17.0.0_r1]

3. 三类位置读取的成本不同

3.1 最近位置:只读缓存

getLastKnownLocation(provider) 通过 ILocationManager.getLastLocation() 读取指定 Provider 的服务端缓存。它不会为了这次调用启动 Provider,返回值可以为 null,也可能已经过时。业务必须结合 Location.getElapsedRealtimeAgeMillis()、accuracy(估计精度半径)和数据完整性判断能否使用。

系统日期时间可能被修改,不能用 System.currentTimeMillis() - location.getTime() 作为唯一新鲜度依据。比较位置年龄应优先使用单调递增、不受改时钟影响的 elapsed realtime。

3.2 单次位置:先尝试缓存,再等待新结果

getCurrentLocation() 的 Android 17 服务端行为包含两个明确上限:

  1. 注册激活时,指定 Provider 若有不超过 30 秒的合格缓存,可以立即返回;
  2. 请求 duration 超过 30 秒时,LocationProviderManager 会把它截到 30 秒。

权限、位置开关、Provider 状态或 AppOps 导致注册不活跃时,回调可能很快收到 null。超时也返回 null。调用者应保留并在业务结束时触发 CancellationSignal,不要把“等待单次结果”写成无期限状态。

3.3 连续更新:注册会参与 Provider 合并

requestLocationUpdates() 会建立长期注册。Listener 适合进程存活且生命周期清晰的页面或服务;PendingIntent 适合需要跨组件交付的场景,但仍受后台位置权限、前台服务和系统节流规则约束。

使用 Listener 时,应保存同一个实例,并在生命周期结束时取消:

private final LocationListener listener = this::onLocationChanged;

@Override
protected void onStart() {
    super.onStart();
    locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            request,
            getMainExecutor(),
            listener);
}

@Override
protected void onStop() {
    locationManager.removeUpdates(listener);
    super.onStop();
}

removeUpdates() 需要原先的 Listener 对象。及时取消既能断开 Activity/Fragment 与回调对象的引用,也能把该注册从服务端合并请求中移除,避免页面不可见后仍维持高频 Provider 请求。若产品需要后台定位,应把注册放到有明确停止条件且满足权限要求的组件,不应依赖页面对象继续存活。

4. Binder 入口之后发生了什么

以连续 Listener 注册为例,Android 17 的主要路径是:

LocationManager.requestLocationUpdates()
  → ILocationManager.registerLocationListener()
    → LocationManagerService.registerLocationListener()
      → CallerIdentity + permission level
      → validateLocationRequest()
      → getLocationProviderManager(provider)
      → LocationProviderManager.registerLocationRequest()
        → Registration 参与活跃性判断与请求合并

4.1 身份、权限和请求清洗

LocationManagerService 从 Binder 调用构造 CallerIdentity,读取 fine/coarse 权限级别,并检查 provider 是否存在。validateLocationRequest() 会处理:

  • 普通调用者无权指定的 WorkSource
  • lowPower、忽略位置设置、ADAS(高级驾驶辅助系统)GNSS bypass(绕过部分常规限制)等受限字段;
  • 包名、attribution tag 与调用 UID 的一致性;
  • 对特权 bypass 的权限及 allowlist(允许名单)限制。

所以,客户端对象中的隐藏字段不等于服务端会照单执行。调试系统应用时,要同时打印“客户端构造的请求”和 dumpsys location 中“服务端接受后的请求”。

4.2 注册能否生效,由动态状态共同决定

LocationProviderManager 会持续重算注册是否 active(当前能够参与请求合并并接收位置),条件包括:

  • 调用者是否仍有相应位置权限;
  • 用户是否可见、Provider 对该用户是否启用;
  • 包是否命中位置黑名单;
  • 前后台状态及后台节流;
  • Battery Saver 的位置模式、屏幕状态;
  • AppOps 是否允许本次使用;
  • 特权 bypass 是否仍满足策略。

Binder 注册成功不代表 Provider 马上运行,也不代表每个位置都能交付。权限、前后台和省电状态可以在注册存续期间改变,服务端会随之更新 active 状态。

4.3 coarse 权限会改请求,也会改结果

Android 12 起,用户可以在应用同时请求 fine(精确)和 coarse(粗略)权限时选择 approximate location(大致位置)。Android 17 服务端对只有 coarse 权限的注册至少做两层处理:

  1. LocationProviderManager 把 quality 改为 QUALITY_LOW_POWER,并把 interval 与 min interval 提高到内部的 10 分钟下限;
  2. 位置结果经过 LocationFudger(模糊位置生成器),通过随时间变化的偏移和网格化生成 coarse 位置。

“10 分钟”是 android-17.0.0_r1 的 framework 内部调度下限,不是公开 API 对所有设备、所有版本的回调承诺。coarse 也不是简单地截断经纬度小数位。应用不应依赖固定的模糊半径或固定小数位数。

后台还有另一层动态 interval 调整。Android 官方文档将普通后台应用描述为每小时只能收到少量位置更新;具体节流值由系统配置、设备版本、进程状态和豁免条件共同决定。

[源码依据:LocationProviderManager.Registration.calculateProviderLocationRequest()LocationFudger.javaandroid-17.0.0_r1]

5. 同一 Provider 的请求如何合并

每个 Provider 有自己的 LocationProviderManager,只合并发往该 Provider 且当前 active 的注册。合并过程不是“全系统挑一个最佳位置源”。

5.1 ProviderRequest 的合并规则

Android 17 的 mergeRegistrations() 对非 passive 请求执行:

  • interval 取最小值;
  • quality 取数值最小值,也就是更强的质量要求;
  • max update delay 取最小值;
  • ADAS bypass 与 ignore-settings 标志做 OR;
  • lowPower 做 AND;
  • WorkSource 收集接近最短 interval、会影响底层工作量的注册。

如果 maxUpdateDelay / 2 < interval,framework 把合并后的 batching delay 置为 0。这样可以避免一个不具备批处理意义的延迟字段反复触发 Provider 重配。公开 LocationRequest 文档也把“最大延迟至少为 interval 的两倍”列为可能批处理的条件。

例如,同一 gps provider 有两个 active 请求:

A: interval=5s,  quality=HIGH, maxDelay=20s, lowPower=false
B: interval=30s, quality=LOW,  maxDelay=60s, lowPower=true

合并给 gps Provider:
interval=5s
quality=HIGH
maxDelay=20s
lowPower=false

这个结果只配置一次 gps Provider。A、B 各自是否收到某个位置,仍要经过各自注册的 min interval、min distance、权限、AppOps、duration 和 max updates 过滤。B 不会因为底层以 5 秒工作就必然每 5 秒收到回调。

5.2 一条高频请求会抬高该 Provider 的共同成本

同一 Provider 的活动请求共享底层工作。一条 1 秒 GPS 请求可能使 GNSS 持续工作;其他低频 GPS 注册虽然被单独限速,底层工作强度已经由频率最高、质量要求最强的请求决定。优化时应找出参与合并的最短 interval 和最强 quality,而不能只看某个业务模块自己的配置。

dumpsys location 会列出 Provider 请求和注册,是定位“哪条请求让 GPS 高频工作”的首选证据。WorkSource/BatteryStats 用于能耗归因,但合并后的归因集合不能表示各应用的实际能耗占比。

6. 位置上报与回调投递

Provider 上报 LocationResult 后,LocationProviderManager 会先更新缓存,再对注册逐一处理。连续更新的主要过滤点包括:

  • 经纬度是否合法;
  • min update interval,包含 framework 允许的小幅时序抖动;
  • min update distance;
  • duration 与 max updates;
  • fine/coarse 结果选择;
  • AppOps 是否允许本次交付。

回调路径可简化为:

Provider.reportLocation()
  → LocationProviderManager
    → Registration.acceptLocationChange()
      → ILocationListener.onLocationChanged()(oneway Binder)
        → App 的 LocationListenerTransport
          → 指定 Executor
            → LocationListener.onLocationChanged()
              → IRemoteCallback 通知 system_server 本次处理完成

6.1 Executor 堵塞为什么也会带来系统成本

对非 passive 的连续更新,服务端在交付前获取一个 partial wakelock(允许屏幕关闭但暂时阻止 CPU 休眠的锁),超时为 30 秒。应用侧 LocationListenerTransport 在指定 Executor 上完成回调后,通过 IRemoteCallback 通知服务端释放它。

这带来三点工程约束:

  1. oneway Binder(异步单向调用)只表示发送方不等待同步返回,不表示应用回调没有背压;这里的背压是接收端处理不过来后产生的队列压力;
  2. Executor 队列长时间拥塞,会延后 completion callback(处理完成通知),服务端 wakelock 只能等回调或 30 秒超时;
  3. 回调中如果需要比这更长的后台工作,应用应自行采用符合系统约束的执行与保活机制,不能把 framework 的交付 wakelock 当作业务 wakelock。

不要假设 Perfetto 中存在稳定的 LocationManagerServiceGnssLocationProvider 自定义 track(时间轨道)。android-17.0.0_r1 的这些 Java 路径没有提供可依赖的统一 slice(带起止时间的区间事件)名称。可结合 Binder、线程调度、CPU frequency/idle、wakelock 和应用自定义 trace 分析延迟。

[源码依据:ILocationListener.aidlLocationManager.LocationListenerTransportLocationProviderManager.Registration.acceptLocationChange()android-17.0.0_r1]

7. GNSS 从 framework 到 HAL

这里的 AIDL 是当前稳定的 HAL 接口技术,HIDL 是旧版接口技术;JNI 是 Java 与本地 C++ 代码之间的调用桥梁。

Android 17 的 GNSS 主路径是:

LocationProviderManager[gps]
  → GnssLocationProvider
    → GnssNative(Java)
      → JNI
        → services/core/jni/gnss/Gnss.cpp
          → AIDL IGnss 或旧版 HIDL IGnss
            → vendor GNSS service / chipset

GnssLocationProvider 运行在 system_server,主要任务是把合并后的 ProviderRequest 转换成 GNSS 引擎配置,管理启动、停止、framework 调度、batching、辅助数据和指标。GnssNative 汇集 Java/JNI 回调。射频跟踪、基带算法和大部分硬件电源状态位于厂商实现。

7.1 Android 17 仍保留 AIDL/HIDL 兼容路径

JNI GnssHal 先等待 VINTF(Vendor Interface,系统与 vendor 组件的接口声明)中列出的 AIDL 服务。AIDL interface version 大于等于 2 时,构造过程直接结束;否则还会依次探测 HIDL 2.1、2.0、1.1、1.0。Android 17 仍带着多版本兼容代码,不能预设设备只走 AIDL。分析单机问题时,要从 dumpsysGnssJni 日志确认连接到的接口版本。

AIDL IGnss 的主生命周期接口是:

  • setCallback()
  • start() / stop()
  • close()
  • setPositionMode()
  • 时间、位置和 aiding data(辅助定位数据)注入;
  • 获取 measurement(原始卫星测量)、PSDS、batching、geofence、power indication(功耗报告)等扩展。

IGnss 没有 open()。各扩展通常使用自己的 setCallback()init() 建立回调。

7.2 能力位是“设备支持什么”,不是性能数字

HAL 会上报 scheduling、measurement、geofence、low-power mode 等能力。framework 据此启用对应路径。例如,没有调度能力时,GnssLocationProvider 可以通过 alarm 在低频请求之间休眠和唤醒;具备调度能力时,可把周期直接交给 HAL。

能力位不能推导出固定精度、TTFF(Time to First Fix,首次定位时间)或电流值。天线、天空可视度、频段、热状态、厂商固件、辅助数据、移动速度和测量环境都会改变结果。通用章节不应给出“GPS 恒定 3–10 米”或“batching 恒定 1–5 mA”一类设备无关结论。

8. GNSS 调度、batching 与 full tracking

8.1 普通定位请求如何驱动 GNSS

GnssLocationProvider.updateRequirements() 从合并请求读取 interval、max update delay、low-power 提示和 WorkSource:

  • 满足 batching 条件时,停止普通导航并启动硬件 batch;
  • 已启动且 HAL 支持 scheduling 时,更新 setPositionMode()
  • 尚未启动时,设置 position mode 后调用 start()
  • HAL 不支持 scheduling 时,framework 用 alarm 辅助长间隔轮询;
  • Provider request 变为 inactive 时,停止 navigation 和 batching。

这里没有“interval 大于 10 秒就必定 batching”的规则。

8.2 Hardware batching 的必要条件

Android 17 framework 至少检查:

  1. initBatching() 成功;
  2. HAL 报告的 batch size 大于 1;
  3. batchLength = min(maxUpdateDelay, framework 上限)
  4. batchLength / 2 >= max(interval, framework 最小 batch interval)

满足这些条件后,GnssNative.startBatch() 才会进入 IGnssBatching.start()。如果请求的 batch 长度小于硬件缓冲区容量对应的时长,framework 还会设置精确定时器(alarm),按 batch 长度调用 flushBatch()

batching 的收益来自减少 AP(Application Processor,应用处理器)唤醒和 Binder/Java 交付次数,但 GNSS 接收机仍可能按设定周期采样。它不能自动把射频跟踪成本降为零。评估收益要同时比较 AP idle(空闲)时间、唤醒次数、GNSS power stats(功耗统计)和厂商电源轨数据。

8.3 GNSS measurement 的 full tracking 是另一条请求

GnssMeasurementRequest.Builder.setFullTracking(true) 自 API 31 起用于原始 GNSS measurements。它要求关闭 duty cycling(周期性停机以省电),以连续跟踪更多 GNSS 信号,通常会增加功耗。多个 measurement listener 合并时,只要任一 active 请求要求 full tracking(全程跟踪),合并结果就启用 full tracking;measurement interval 也取最短值。

API 34 增加了 GnssMeasurementsEvent.isFullTracking(),调用者可以在 HAL 支持相应信息时判断事件是否处于 full-tracking 模式。

普通 LocationRequestQUALITY_HIGH_ACCURACY + 短 interval 不等价于显式 GnssMeasurementRequest.setFullTracking(true)IGnssPowerIndication 也不是 full-tracking 开关:它只提供 setCallback()requestGnssPowerStats(),用途是报告 GNSS power capabilities/statistics(功耗能力与统计)。

[源码依据:GnssLocationProvider.updateRequirements()GnssMeasurementsProvider.mergeRegistrations()IGnssBatching.aidlIGnssPowerIndication.aidlandroid-17.0.0_r1]

9. PSDS 与 TTFF:把测量事实和经验值分开

9.1 PSDS 数据路径

PSDS(Predicted Satellite Data Service,预测卫星数据服务)向 GNSS 提供辅助数据。HAL 通过 PSDS callback 请求 framework 下载数据,Android 17 的路径是:

vendor GNSS HAL
  → IGnssPsdsCallback.downloadRequest(type)
    → GnssLocationProvider
      → GnssPsdsDownloader
        → 下载配置的厂商 URL
          → GnssNative.injectPsdsData(type, opaque bytes)
            → IGnssPsds.injectPsdsData()

framework 把 PSDS 内容视为 opaque bytes(不解析内部格式的不透明字节),不会自行拆成“星历表字段”。GnssPsdsDownloader 对单次内容设置 1 MB 上限,连接超时 30 秒、读取超时 60 秒;服务器地址来自设备配置。下载失败会按 framework 策略重试,但设备是否支持某类 PSDS、数据含义及有效期由 HAL/服务配置决定。

PSDS 有助于缩短部分启动场景的捕获时间,却不是 TTFF 的唯一变量。时间/位置注入、SUPL(Secure User Plane Location,一种通过数据网络提供定位辅助信息的协议)、网络状态、aiding data、天线、天空遮挡、干扰、频段和厂商算法都可能影响首次定位。

9.2 framework 如何记录 TTFF

startNavigating() 成功调用 HAL start() 后记录 mFixRequestTime。收到第一份含经纬度的有效 GNSS location 时:

TTFF = first valid fix elapsed realtime - mFixRequestTime

结果写入 GnssMetricsGnssStatus.Callback.onFirstFix(ttffMillis) 也向有权限的监听者暴露相应事件。这个定义可以用于同设备、同场景的前后对比;“冷启动必为 30–60 秒”或“A-GPS 必为 1–5 秒”没有跨设备保证。

做可重复测试时,至少记录:

  • 设备、build fingerprint(精确标识系统构建的字符串)、GNSS HAL 接口版本;
  • 是否删除 aiding data,是否重启 GNSS;
  • 网络、SUPL/PSDS 状态;
  • 室外天空条件、静止/运动状态;
  • 请求开始的 elapsed realtime 与首个有效定位(fix);
  • 多轮分布,而非只报一次最小值。

10. 地理围栏:公开 proximity alert 与硬件围栏是两条路径

10.1 LocationManager.addProximityAlert() 的 framework 路径

平台遗留 API 的调用链是:

LocationManager.addProximityAlert()
  → ILocationManager.requestGeofence()
    → LocationManagerService
      → GeofenceManager
        → 使用 FUSED_PROVIDER 请求位置
          → system_server 中计算进入/离开
            → PendingIntent

GeofenceManager 要求 fine location 权限。proximity alert(邻近提醒)由中心点、半径和 PendingIntent 定义。它为所有 active 围栏合并一个位置请求,根据“当前位置到最近围栏边界的距离 / 假定最大速度”估算下次更新间隔,并受后台 proximity alert 节流值约束,最长不超过 2 小时。缓存位置超过 5 分钟就不用于这个估算。

收到位置后,它计算中心距离,并用:

effectiveRadius = max(geofenceRadius, locationAccuracy)
inside = distanceToCenter <= effectiveRadius

UNKNOWN/OUTSIDE 进入 INSIDE 时发送 entering;只有先处于 INSIDE,之后转为 OUTSIDE,才发送 exiting。该实现没有网格空间索引、loitering delay(进入后停留多久才触发)或通用 hysteresis margin(防止边界抖动的迟滞余量)。

10.2 硬件 GNSS geofence 路径

Android 17 还存在独立的硬件围栏基础设施:

配置的 Geofence Provider
  ↔ GeofenceProxy
  ↔ GeofenceHardwareService
  ↔ GnssGeofenceProxy
  ↔ GnssNative
  ↔ IGnssGeofence

GnssGeofenceProxy 支持 add/remove/pause/resume,并缓存已接受的条目,以便 HAL 重启后恢复。GeofenceProxy 是否创建取决于设备 overlay 与可解析的系统服务。

不能由此得出 addProximityAlert() 会自动把同一个围栏切换到 GNSS 硬件。前者在 GeofenceManager 中以位置更新做软件判断;后者服务于设备配置的硬件 geofence provider。Google Play services Geofencing API 也不属于这条公开平台调用链。

[源码依据:GeofenceManager.javaGeofenceProxy.javaGnssGeofenceProxy.javaIGnssGeofence.aidlandroid-17.0.0_r1]

11. 性能问题的证据链

位置问题常同时跨越应用、system_server、Provider 服务和 vendor HAL。只看一条回调耗时,很难区分请求未激活、Provider 没有产生有效定位(fix)、结果被过滤或 Executor 堵塞。

11.1 先用 dumpsys location 建立状态快照

以下命令分别查看常规状态、详细状态和 GNSS 指标:

adb shell dumpsys location
adb shell dumpsys location -a
adb shell dumpsys location --gnssmetrics

应重点核对:

  • provider 是否存在、是否启用;
  • 每个 Provider 的 active request(当前生效的合并请求)与注册调用者;
  • interval、quality、max delay 是否已被服务端改写;
  • last location(最近缓存位置)的年龄;
  • GNSS 是否启动、是否处于 batching,以及 capabilities 与 TTFF 指标;
  • framework proximity alerts 和硬件 geofence 状态。

命令输出会随 build 类型和厂商扩展变化。调试量产使用的 user build 时,部分身份或 HAL 细节可能被裁剪。

11.2 分清应用记录与系统观测点

普通应用只能稳定记录自己的请求和回调,不能直接在 system_server 的注册激活或 Provider 上报处增加时间点。应用侧应使用单调时钟,例如 SystemClock.elapsedRealtimeNanos(),记录这三个事件:

A_request   调用 LocationManager API
A_callback  指定 Executor 开始执行回调
A_done      应用完成轻量回调处理

这组数据能直接计算应用看到的端到端等待时间 A_callback - A_request,以及回调工作时间 A_done - A_callback。前者包含服务端策略、Provider 产出、Binder 投递和 Executor 排队,不能仅凭应用日志继续归因。

要继续分段,需要在用于调试的 userdebug/eng 构建、定制 framework/Provider 或设备已经提供对应 Perfetto 数据源时,增加系统侧观测点:

观测点所在层可用于解释的阶段
S_activesystem_server 注册变为 active,合并后的 ProviderRequest 更新请求是否通过权限、位置开关、前后台和省电策略
P_reportProvider 向 framework 上报 LocationResultProvider 或 GNSS/HAL 等待时间
S_deliversystem_server 决定向目标注册投递单注册过滤与服务端投递时间

当这些事件来自同一次受控请求,并且都使用可换算到同一单调时钟域的时间戳时,才可以计算:

  • S_active - A_request:Binder 入口、校验与激活;
  • P_report - S_active:Provider 等待,GNSS 场景还要结合 TTFF;
  • S_deliver - P_report:缓存更新、单注册过滤与投递准备;
  • A_callback - S_deliver:Binder、进程调度和 Executor 排队。

并发请求下,不能用“时间上最近的一条 location”猜测跨进程事件属于同一个注册。应使用定制关联 ID,或把实验限制为单应用、单 provider、单注册,再结合调用者身份、请求参数和 Location.getElapsedRealtimeNanos() 交叉核对。

Perfetto 可组合 schedbinder_driver、CPU frequency/idle、wakelock/power、network,以及设备提供的 vendor GNSS data source(跟踪数据源)。没有明确的 framework/HAL 事件或自定义时间戳时,不能凭模糊的 Gnss 字符串把某段 slice 当成 TTFF。

11.3 常见症状与核查点

症状第一批证据高概率方向
注册成功但无回调active 状态、provider 是否启用、AppOps权限/后台/省电限制,或 Provider 没有结果
回调频率低于请求服务端改写后的 interval、单注册过滤coarse/后台节流、min interval、min distance、batching
GPS 长时间保持 activegps 的合并请求和调用者另一条更短 interval 请求、未取消注册
TTFF 变长多轮 TTFF、PSDS/SUPL/网络、天空条件辅助数据、射频环境、HAL/固件变化
回调后系统仍持有 wakelockApp Executor 与处理完成通知的时间Executor 拥塞或回调耗时
围栏漏报使用的平台/GMS API、位置 accuracy、软件/硬件路径路径判断错误、权限/后台限制、位置本身不稳定

12. 设计与检查清单

应用侧:

  • 明确写出使用的平台 API 还是 Play services API;
  • 明确选哪个 provider,不把 quality 当作自动选源器;
  • 最近位置要检查年龄与 accuracy;
  • 单次请求处理 null、取消与 30 秒服务端上限;
  • 连续请求绑定清晰生命周期,停止时用同一 Listener 或 PendingIntent 取消;
  • 回调只做轻量工作,避免堵塞指定 Executor;
  • 需要 approximate location(大致位置)时按能力降级,不假设固定模糊半径;
  • 后台定位同时检查后台位置权限、前台服务类型和系统节流。

系统与厂商侧:

  • dumpsys location 中的服务端请求为准,不只看客户端对象;
  • 分 Provider 查最短 interval、最强 quality 和最小 max delay;
  • 确认 GNSS 使用 AIDL 还是 HIDL,以及能力位(capabilities)是否匹配预期;
  • 对 batching 同时验证 HAL 支持、batch size、请求比例和实际 flush;
  • 把 measurement full tracking 与普通 LocationRequest、power indication 分开;
  • TTFF、精度和电流只报告指定设备与测试条件下的统计分布;
  • 区分 GeofenceManager 软件 proximity alert 与硬件 geofence provider。

13. 与其他章节的关系

关联章节内容边界
§1.10Binder oneway、线程调度与回调完成通知
§1.22network/fused Provider 的网络依赖,但定位算法不由 ConnectivityManager 决定
§5.3应用定位周期、后台限制与电池预算
§8.1Executor/主线程拥塞造成的通用响应延迟

android-17.0.0_r1 包含上述平台 API、服务端合并、GNSS HAL 兼容路径与两类 geofence 基础设施。厂商 Provider 算法、GNSS 芯片功耗和射频性能不属于 AOSP 可统一保证的范围,相关结论必须附具体设备与测量条件。