位置服务是 Android 中对隐私高度敏感但又不可或缺的子系统之一。它将卫星接收器、基站数据库、Wi‑Fi 指纹识别引擎以及传感器融合算法封装在一套统一的框架 API——LocationManager背后,同时实施多层权限模型,区分精细位置、粗略位置、前台访问与后台访问。本章将逐层梳理该软件栈:从公开 SDK 接口,到LocationManagerService、GNSS HAL AIDL 契约、融合定位与网络定位提供者、地理围栏、地理编码,以及将位置转换为时区标识的 GeoTZ 模块。本章覆盖 Android 17 下该子系统的现状:GNSS HAL 已升级至 AIDL 第 7 版本,结构化 GNSS 辅助接口取代旧设备上不透明的 PSDS 二进制块;大量功能标志被移除,若干曾经的实验行为(人口密度粗略位置、GNSS 辅助数据注入)成为默认代码路径。
除非特别说明,所有源码路径均相对于 AOSP 根目录。
33.1 位置服务架构
33.1.1 三大核心支柱
Android 位置子系统基于三个概念支柱构建:
| 支柱 | 用途 | 关键产物 |
|---|---|---|
| 提供者抽象 | 在统一接口之下屏蔽各类定位引擎的差异 | AbstractLocationProvider |
| 请求多路复用 | 将数百个应用请求合并为每个提供者的一条最优请求 | LocationProviderManager |
| 权限强制校验 | 通过精细 / 粗略 / 后台权限校验管控每一条数据流 | LocationPermissions |
33.1.2 分层示意图

来源:frameworks/base/location/java/android/location/LocationManager.java —— 标记@SystemService(Context.LOCATION_SERVICE)的公开 SDK 类。
33.1.3 提供者名称常量
LocationManagerService定义用于标记各个提供者的字符串常量,与LocationManager内常量保持一致:
| 常量 | 取值 | 说明 |
|---|---|---|
GPS_PROVIDER |
"gps" |
基于卫星(GNSS)定位 |
NETWORK_PROVIDER |
"network" |
基站 / Wi‑Fi 定位 |
FUSED_PROVIDER |
"fused" |
传感器融合最优定位结果 |
PASSIVE_PROVIDER |
"passive" |
监听全部位置更新,不主动发起定位 |
GPS_HARDWARE_PROVIDER |
"gps_hardware" |
原始 GNSS HAL,需要LOCATION_HARDWARE权限 |
33.1.4 启动序列
LocationManagerService.Lifecycle继承SystemService。其启动阶段回调定义了精确执行顺序:
onStart()
publishBinderService(Context.LOCATION_SERVICE, mService)
onBootPhase(PHASE_SYSTEM_SERVICES_READY)
SystemInjector.onSystemReady()
LocationManagerService.onSystemReady()
onBootPhase(PHASE_THIRD_PARTY_APPS_CAN_START)
LocationManagerService.onSystemThirdPartyAppsCanStart()
1. create NetworkProvider (ProxyLocationProvider)
2. create FusedProvider (ProxyLocationProvider, direct‑boot aware)
3. create GnssNative + GnssManagerService (also registers the
GNSS assistance proxy in GnssManagerService.onSystemReady())
4. create GnssLocationProvider, or a ProxyLocationProvider GNSS
overlay (ACTION_GNSS_PROVIDER); optionally also expose the raw
HAL as the "gps_hardware" provider
5. bind GeocodeProvider (ProxyGeocodeProvider)
6. bind PopulationDensityProvider (ProxyPopulationDensityProvider)
7. bind HardwareActivityRecognitionProxy (unless Flags.disableHardwareAr())
8. bind GeofenceProxy -> GeofenceHardwareService
来源:frameworks/base/services/core/java/com/android/server/location/LocationManagerService.java,onSystemThirdPartyAppsCanStart() 第 495‑638 行。
网络提供者要在 GNSS 提供者之前创建,源码注释说明原因:
“network provider should always be initialized before the gps provider since the gps provider has unfortunate hard dependencies on the network provider” “网络提供者必须在 gps 提供者之前初始化,因为 gps 提供者对网络提供者存在无法规避的强依赖”
Android 17 带来三处关键变更:
- GNSS 提供者支持代理覆盖层。当
config_useGnssHardwareProvider为 false 时,LMS 首先通过ProxyLocationProvider.create(..., ACTION_GNSS_PROVIDER, config_enableGnssLocationOverlay, ...)绑定外部 GNSS 提供者;若无覆盖层,则回退使用进程内GnssLocationProvider。如果存在覆盖层,原始 HAL 仍然独立通过GPS_HARDWARE_PROVIDER对外暴露(受LOCATION_HARDWARE权限保护),因为 GNSS HAL 仅支持单个客户端。 - 人口密度功能不再受功能标志控制。
ProxyPopulationDensityProvider无条件注册;曾经用于开关该功能的population_density_provider与density_based_coarse_locations标志已被清理,唯一约束条件是设备上是否存在对应提供者服务(见 33.5.8 节)。 - GNSS 辅助代理移入 GNSS 子系统。不再从
onSystemThirdPartyAppsCanStart()执行绑定,ProxyGnssAssistanceProvider现在在GnssManagerService.onSystemReady()内部完成注册(见 33.10.5 节)。
33.1.5 源码文件总览
位置子系统分布在多个目录,完整源码树映射如下:
frameworks/base/
location/java/android/location/
LocationManager.java -- 公开SDK API
Geocoder.java -- 正向/反向地理编码API
Geofence.java -- 地理围栏定义
Location.java -- 位置数据对象
LocationRequest.java -- 定位请求参数
GnssStatus.java -- 卫星状态
GnssMeasurement.java -- 框架层原始观测值
GnssClock.java -- GNSS时钟状态
GnssCapabilities.java -- HAL能力封装
GnssAntennaInfo.java -- 天线相位中心数据
Criteria.java -- 旧版提供者选择条件
Address.java -- 地理编码得到的地址
services/core/java/com/android/server/location/
LocationManagerService.java -- 核心系统服务
LocationPermissions.java -- 权限校验逻辑
LocationShellCommand.java -- adb shell cmd location
HardwareActivityRecognitionProxy.java
geofence/
GeofenceManager.java -- 软件地理围栏引擎
GeofenceProxy.java -- 硬件地理围栏桥接层
gnss/
GnssManagerService.java -- GNSS子系统管理器
GnssLocationProvider.java -- GNSS定位提供者
GnssConfiguration.java -- GNSS配置管理
GnssMetrics.java -- 性能指标统计
GnssListenerMultiplexer.java
GnssMeasurementsProvider.java
GnssNavigationMessageProvider.java
GnssStatusProvider.java
GnssNmeaProvider.java
GnssAntennaInfoProvider.java
GnssGeofenceProxy.java
GnssPositionMode.java
GnssPowerStats.java
GnssPsdsDownloader.java
GnssSatelliteBlocklistHelper.java
GnssVisibilityControl.java
GnssNetworkConnectivityHandler.java
ExponentialBackOff.java
NetworkTimeHelper.java -- NTP时间抽象策略
NtpNetworkTimeHelper.java
TimeDetectorNetworkTimeHelper.java
hal/
GnssNative.java -- 对接HAL的JNI桥接层
provider/
AbstractLocationProvider.java
LocationProviderController.java -- 提供者控制接口
LocationProviderManager.java
PassiveLocationProvider.java
PassiveLocationProviderManager.java
MockLocationProvider.java
MockableLocationProvider.java
StationaryThrottlingLocationProvider.java
DelegateLocationProvider.java
proxy/
ProxyLocationProvider.java
ProxyGeocodeProvider.java
ProxyPopulationDensityProvider.java
ProxyGnssAssistanceProvider.java
injector/
Injector.java -- 依赖注入接口
(UserInfoHelper, SettingsHelper, AlarmHelper, ... and their
System* concrete implementations)
listeners/
ListenerMultiplexer.java, ListenerRegistration.java,
BinderListenerRegistration.java, PendingIntentListenerRegistration.java
settings/
LocationSettings.java
LocationUserSettings.java
fudger/
LocationFudger.java
LocationFudgerCache.java
altitude/
AltitudeService.java
countrydetector/
ComprehensiveCountryDetector.java, LocationBasedCountryDetector.java
contexthub/
ContextHubService.java and the Context Hub / endpoint brokers
eventlog/
LocationEventLog.java
hardware/interfaces/gnss/
aidl/android/hardware/gnss/
IGnss.aidl -- GNSS HAL根接口(V7)
IGnssCallback.aidl -- 框架回调与能力位掩码
GnssConstellationType.aidl -- 卫星星座枚举
GnssMeasurement.aidl -- 原始观测值
GnssSignalType.aidl -- 信号类型描述符
IGnssGeofence.aidl -- 硬件地理围栏
IGnssMeasurementInterface.aidl
IGnssBatching.aidl
IGnssPsds.aidl
IGnssConfiguration.aidl
IGnssPowerIndication.aidl
IGnssDebug.aidl
IGnssAntennaInfo.aidl
IAGnss.aidl
IAGnssRil.aidl
gnss_assistance/ -- 结构化辅助数据HAL(V5及以上)
IGnssAssistanceInterface.aidl, GnssAssistance.aidl, and the
per‑constellation ephemeris/almanac/ionospheric model parcelables
measurement_corrections/
visibility_control/
packages/modules/GeoTZ/
locationtzprovider/ -- TimeZoneProviderService
geotz_lookup/ -- 基于S2的时区查找
s2storage/ -- S2几何存储
output_data/ -- tzs2.dat 二进制数据
33.1.6 类继承关

所有提供者的控制面由包私有接口LocationProviderController定义(setRequest、start、stop、flush、sendExtraCommand);AbstractLocationProvider通过内部Controller实现该接口,向LocationProviderManager暴露自身状态。
来源:frameworks/base/services/core/java/com/android/server/location/provider/(AbstractLocationProvider.java、DelegateLocationProvider.java、StationaryThrottlingLocationProvider.java、MockableLocationProvider.java、LocationProviderController.java)。
33.2 LocationManagerService
LocationManagerService(简称 LMS)是所有LocationManager调用背后唯一的系统服务。它实现ILocationManager.Stub Binder 接口,应用通过Context.getSystemService(Context.LOCATION_SERVICE)发起调用。
来源:frameworks/base/services/core/java/com/android/server/location/LocationManagerService.java,Android17 版本共 2073 行。
33.2.1 成员与数据结构
public class LocationManagerService extends ILocationManager.Stub
implements LocationProviderManager.StateChangedListener {
final Object mLock = new Object();
private final Context mContext;
private final Injector mInjector;
private final GeofenceManager mGeofenceManager;
private volatile @Nullable GnssManagerService mGnssManagerService;
private ProxyGeocodeProvider mGeocodeProvider;
private final PassiveLocationProviderManager mPassiveManager;
// CopyOnWriteArrayList: 写操作需要加锁,读操作无锁
final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers;
}
mProviderManagers列表中,每一个注册的提供者对应一个LocationProviderManager实例。CopyOnWriteArrayList模式保证高频getLocationProviderManager(name)查找时读路径无锁。
33.2.2 依赖注入模式
LMS 使用Injector接口,解除与 Android 系统服务之间的强耦合。使得无需完整system_server环境即可完成单元测试。

每一个 Helper 都有对应的System*具体实现(例如SystemSettingsHelper、SystemEmergencyHelper),封装真实系统 API 调用。
来源:frameworks/base/services/core/java/com/android/server/location/injector/(20 + 文件)。
33.2.3 提供者管理
添加提供者
void addLocationProviderManager(
LocationProviderManager manager,
@Nullable AbstractLocationProvider realProvider) {
synchronized (mProviderManagers) {
manager.startManager(this);
if (realProvider != null) {
int defaultStationaryThrottlingSetting =
mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WATCH) ? 0 : 1;
boolean enableStationaryThrottling = Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.LOCATION_ENABLE_STATIONARY_THROTTLE,
defaultStationaryThrottlingSetting) != 0;
// In Android 17 throttling is only ever applied to the GPS provider,
// and only when the keep_gnss_stationary_throttling flag is on.
if (!(Flags.keepGnssStationaryThrottling() && enableStationaryThrottling
&& GPS_PROVIDER.equals(manager.getName()))) {
enableStationaryThrottling = false;
}
if (enableStationaryThrottling) {
realProvider = new StationaryThrottlingLocationProvider(
manager.getName(), mInjector, realProvider);
}
}
manager.setRealProvider(realProvider);
mProviderManagers.add(manager);
}
}
装饰器StationaryThrottlingLocationProvider:当设备进入 Doze 休眠、加速度传感器判定设备静止时,降低定位频率;不再向硬件请求新定位,而是以较长时间间隔复用上一次缓存位置。
Android17 对控制逻辑做了简化:旧的Flags.disableStationaryThrottling()标志被移除;节流装饰器仅作用于 GPS 提供者,同时需要开启Flags.keepGnssStationaryThrottling()并且打开Settings.Global.LOCATION_ENABLE_STATIONARY_THROTTLE配置。手机设备该配置默认为 1(开启),Wear OS 手表设备默认为 0(关闭),因为小尺寸设备静止检测可靠性较差。也就是说,网络提供者与融合提供者不再被该装饰器包裹,这与旧版本行为存在差异。
移除提供者
private void removeLocationProviderManager(LocationProviderManager manager) {
synchronized (mProviderManagers) {
mProviderManagers.remove(manager);
manager.setMockProvider(null);
manager.setRealProvider(null);
manager.stopManager();
}
}
33.2.4 请求处理流程
当应用调用LocationManager.requestLocationUpdates(),Binder 调用进入registerLocationListener():

validateLocationRequest()校验并清洗每一个字段:
WorkSource:需要UPDATE_DEVICE_STATS权限- 低功耗模式:需要
LOCATION_HARDWARE权限 - 对 AppOps 隐藏:需要
UPDATE_APP_OPS_STATS - ADAS GNSS 绕过:仅车载设备、仅 GPS 提供者可用
- 忽略位置开关设置:需要绕过权限
33.2.5 获取当前位置
getCurrentLocation()为一次性定位接口。LMS 将逻辑委托给LocationProviderManager.getCurrentLocation(),返回ICancellationSignal,应用可使用该对象取消未完成的定位请求。
33.2.6 获取上一次已知位置
getLastLocation()返回指定提供者最近缓存的位置。调用LocationProviderManager.getLastLocation(),同样执行权限校验与粗略位置模糊处理。
33.2.7 位置系统设置
每个用户下位置开关启用 / 禁用状态由Settings.Secure.LOCATION_MODE维护。LMS 监听配置变更:
mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
this::onLocationModeChanged);
当模式发生变化,LMS 执行:
- 使
LocationManager本地缓存失效 - 记录事件日志
- 广播
LocationManager.MODE_CHANGED_ACTION - 刷新对应用户的 AppOps 限制
33.2.8 LocationProviderManager
LocationProviderManager(简称 LPM)是请求多路复用逻辑的核心,共 3123 行,是位置包内最大的单个类。每个实例管理一个命名定位提供者。
主要职责:
| 职责 | 实现机制 |
|---|---|
| 将 N 个应用请求合并为 1 条提供者请求 | mergeRegistrations() |
| 维护每个注册项状态(活跃、权限) | 内部类Registration |
| 向匹配的注册项分发位置结果 | deliverToListeners() |
| 对 COARSE 权限客户端做位置模糊处理 | LocationFudger |
| 支持测试用模拟提供者 | setMockProvider() |
| 提供诊断用的提供者请求监听器 | addProviderRequestListener() |
来源:frameworks/base/services/core/java/com/android/server/location/provider/LocationProviderManager.java
33.2.9 LPM 常量与阈值
LPM 定义若干控制行为的常量,排查位置分发问题必须理解这些参数:
// 粗略位置客户端最小更新间隔(10分钟)
private static final long MIN_COARSE_INTERVAL_MS = 10 * 60 * 1000;
// 判断为高功耗请求的最大间隔(5分钟)
private static final long MAX_HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
// 判定位置为“当前有效”的最大存活时间(30秒)
private static final long MAX_CURRENT_LOCATION_AGE_MS = 30 * 1000;
// getCurrentLocation最大超时(30秒)
private static final long MAX_GET_CURRENT_LOCATION_TIMEOUT_MS = 30 * 1000;
// 最小更新间隔抖动容忍百分比(10%)
private static final float FASTEST_INTERVAL_JITTER_PERCENTAGE = .10f;
// 最小更新间隔绝对抖动上限(30秒)
private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 30 * 1000;
// 延迟请求生效的最小等待时间(30秒)
private static final long MIN_REQUEST_DELAY_MS = 30 * 1000;
// 位置分发持有的Wakelock超时(30秒)
private static final long WAKELOCK_TIMEOUT_MS = 30 * 1000;
// PendingIntent客户端允许FGS启动的临时白名单时长(10秒)
private static final long TEMPORARY_APP_ALLOWLIST_DURATION_MS = 10 * 1000;
MIN_COARSE_INTERVAL_MS = 10分钟是粗略权限客户端硬性下限。即便应用仅拥有ACCESS_COARSE_LOCATION却请求 1 秒更新间隔,LPM 也会将实际间隔钳位到 10 分钟。该隐私防护策略防止粗略权限应用通过位置变化量反推精细位置。
Android17 中这些常量未发生修改,核对源码LocationProviderManager.java第 155‑180 行确认。
33.2.10 LPM 省电模式
LocationProviderManager通过LocationPowerSaveModeHelper对接 Android 电池省电机制,定义四种模式:
| 模式 | 常量 | 行为 |
|---|---|---|
| 无变更 | LOCATION_MODE_NO_CHANGE |
正常工作 |
| 息屏关闭 GPS | LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF |
息屏时停止 GPS |
| 息屏全部关闭 | LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF |
息屏停止所有提供者 |
| 仅前台允许 | LOCATION_MODE_FOREGROUND_ONLY |
仅前台应用收到位置更新 |
| 息屏节流 | LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF |
息屏降低更新频率 |
LPM 监听屏幕亮灭状态:
mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener);
当处于LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF模式并且是 GPS 提供者,屏幕熄灭时合并后的请求会被抑制。
33.2.11 LPM 注册类型
LPM 支持三类注册:
- Listener 注册:
ILocationListenerBinder 回调,接收持续位置更新。 - PendingIntent 注册:触发
PendingIntent,Intent 携带位置附加数据。 - 当前位置请求:一次性定位,返回
ICancellationSignal,由getCurrentLocation()发起。
每个注册项记录:
LocationRequest(间隔、精度、时长等)CallerIdentity(uid、pid、包名、归因标签)@PermissionLevel(FINE / COARSE / NONE)- 调用进程是否处于前台
- 注册项是否处于活跃状态(全部前置条件满足)
33.2.12 LPM 位置分发流水线
当提供者上报新LocationResult,LPM 经过多阶段流水线处理:

AltitudeConverter(可用时)将 WGS84 椭球高度转换为平均海平面海拔,优化展示海拔的应用体验。
来源:frameworks/base/services/core/java/com/android/server/location/altitude/AltitudeService.java
33.2.13 位置模糊处理细节
向仅拥有粗略权限的客户端分发位置时,LocationFudger混淆真实坐标,算法逻辑:
- 将真实坐标对齐到网格,网格单元宽度为
mAccuracyM。该数值从Settings.Secure通过SettingsHelper.getCoarseLocationAccuracyM()读取,默认DEFAULT_COARSE_LOCATION_ACCURACY_M = 2000.0f(2 千米),下限MIN_ACCURACY_M = 200.0f。 - 添加缓慢漂移的随机偏移量。对象构造时通过
SecureRandom生成种子(设备每次开机重新生成),每OFFSET_UPDATE


152

被折叠的 条评论
为什么被折叠?



