问题: 手机定位权限开启,在安装某些厂商定制的apk时,首次安装正常启动,再次启动,则应用崩溃.根据系统日志,定位到问题是在LocationManager.java中.系统日志如下图:
问题分析: app中会申请定位的权限,但是系统中,现在network provider不存在,当provider不存在时,调用LocationManagerService.java 的 requestLocationUpdates(),安卓系统会抛出异常.
---------------------------------分析---------------------------------------------------------------
(1) 当app 获取定位时,会通过LocationManager.java 提供的api,获取定位,
源码路径:frameworks/base/location/java/android/location/LocationManager.java
/**
* @param provider 由 {@link #getAllProviders()} 列出的提供者
* @param locationRequest 包含位置参数的位置请求
* @param executor 处理监听器回调的执行器
* @param Listener 接收位置更新的监听器
*
* 如果提供者为 null 或不存在,则抛出 IllegalArgumentException
* 如果 locationRequest 为 null,则抛出 IllegalArgumentException
* 如果侦听器为空,则@抛出 IllegalArgumentException
* 如果没有合适的权限,则抛出@抛出SecurityException
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider,
@NonNull LocationRequest locationRequest,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(locationRequest != null, "invalid null location request");
try {
synchronized (sLocationListeners) {
WeakReference reference = sLocationListeners.get(
listener);
LocationListenerTransport transport = reference != null ? reference.get() : null;
if (transport == null) {
transport = new LocationListenerTransport(listener, executor);
} else {
Preconditions.checkState(transport.isRegistered());
transport.setExecutor(executor);
}
//调用LocationManagerService的方法
mService.registerLocationListener(provider, locationRequest, transport,
mContext.getPackageName(), mContext.getAttributionTag(),
AppOpsManager.toReceiverId(listener));
sLocationListeners.put(listener, new WeakReference<>(transport));
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
(2)接着着调用LocationManagerService 的 registerLocationListenner() 方法.
源码路径:frameworks/base/services/core/java/com/android/server/location/LocationManagerService.java
@Override
public void registerLocationListener(String provider, LocationRequest request,
ILocationListener listener, String packageName, @Nullable String attributionTag,
String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
identity.getPid());
LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
// clients in the system process should have an attribution tag set
if (identity.getPid() == Process.myPid() && attributionTag == null) {
Log.w(TAG, "system location request with no attribution tag",
new IllegalArgumentException());
}
request = validateLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
//当provider不存在时,抛出异常
Preconditions.checkArgument(manager != null,
"provider \"" + provider + "\" does not exist");
manager.registerLocationRequest(request, identity, permissionLevel, listener);
}
(3)上面源码上可以看到,当LocationProvider 为 null 时,系统会抛出异常,这就是日志中看到的异常,因此,可以在 locationProvider 不为为 null 的时,才执行后面的步骤,在LocationManager.java中,提供了一个 isProviderEnabled()方法去判断provider是否可用.
源码路径:frameworks/base/location/java/android/location/LocationManager.java
//如果提供程序存在并且已启用返回true;如果provider为null,则抛出 IllegalArgumentException
public boolean isProviderEnabled(@NonNull String provider) {
return isProviderEnabledForUser(provider, Process.myUserHandle());
}
(4) 因此,最终的解决方案为:
源码路径:frameworks/base/location/java/android/location/LocationManager.java
/**
* @param provider 由 {@link #getAllProviders()} 列出的提供者
* @param locationRequest 包含位置参数的位置请求
* @param executor 处理监听器回调的执行器
* @param Listener 接收位置更新的监听器
*
* 如果提供者为 null 或不存在,则抛出 IllegalArgumentException
* 如果 locationRequest 为 null,则抛出 IllegalArgumentException
* 如果侦听器为空,则@抛出 IllegalArgumentException
* 如果没有合适的权限,则抛出@抛出SecurityException
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void requestLocationUpdates(@NonNull String provider,
@NonNull LocationRequest locationRequest,
@NonNull @CallbackExecutor Executor executor,
@NonNull LocationListener listener) {
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(locationRequest != null, "invalid null location request");
try {
synchronized (sLocationListeners) {
WeakReference reference = sLocationListeners.get(
listener);
LocationListenerTransport transport = reference != null ? reference.get() : null;
if (transport == null) {
transport = new LocationListenerTransport(listener, executor);
} else {
Preconditions.checkState(transport.isRegistered());
transport.setExecutor(executor);
}
//当名字为NETWORK_PROVIDER的provider不可用时,不更新定位信息
+ if(!isProviderEnabled(NETWORK_PROVIDER))
+ return ;
//调用LocationManagerService的方法
mService.registerLocationListener(provider, locationRequest, transport,
mContext.getPackageName(), mContext.getAttributionTag(),
AppOpsManager.toReceiverId(listener));
sLocationListeners.put(listener, new WeakReference<>(transport));
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}