问题: 手机定位权限开启,在安装定制化apk时,首次安装正常启动,再次启动,则应用崩溃.根据系统日志,定位到问题是在LocationManager.java中.系统日志如下图:
问题分析: app中会申请定位的权限,但是系统中,现在network provider不存在,当provider不存在时,调用LocationManagerService.java 的 requestLocationUpdates(),安卓系统会抛出异常.
(1) 当app 获取定位时,会通过LocationManager.java 提供的api,获取定位,
源码路径:frameworks/base/location/java/android/location/LocationManager.java
@UnsupportedAppUsage
private void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper, PendingIntent intent) {
String packageName = mContext.getPackageName();
// wrap the listener class
ListenerTransport transport = wrapListener(listener, looper);
try {
//调用LocatonManagerService中的方法
mService.requestLocationUpdates(request, transport, intent, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
(2)接着着调用LocationManagerService 的requestLocationUpdates() 方法.
源码路径:frameworks/base/services/core/java/com/android/server/LocationManagerService.java
@Override
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
PendingIntent intent, String packageName) {
......
Receiver receiver;
if (intent != null) {
receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
hideFromAppOps);
} else {
receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
hideFromAppOps);
}
//进一步调用
requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
} finally {
Binder.restoreCallingIdentity(identity);
}
......
(3)接着着调用 requestLocationUpdatesLocked()
@GuardedBy("mLock")
private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
int uid, String packageName) {
// Figure out the provider. Either its explicitly request (legacy use cases), or
// use the fused provider
if (request == null) request = DEFAULT_LOCATION_REQUEST;
//获取需要的provider
String name = request.getProvider();
//provider name 不能为空,否则抛出异常
if (name == null) {
throw new IllegalArgumentException("provider name must not be null");
}
//通过provider name 来获取 locationProvider
LocationProvider provider = getLocationProviderLocked(name);
// 当 locationProvider 为null 时,会抛出异常
if (provider == null) {
throw new IllegalArgumentException("provider doesn't exist: " + name);
}
UpdateRecord record = new UpdateRecord(name, request, receiver);
if (D) {
Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+ " " + name + " " + request + " from " + packageName + "(" + uid + " "
+ (record.mIsForegroundUid ? "foreground" : "background")
+ (isThrottlingExemptLocked(receiver.mCallerIdentity)
? " [whitelisted]" : "") + ")");
}
UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
if (oldRecord != null) {
oldRecord.disposeLocked(false);
}
if (!provider.isUseableLocked() && !isSettingsExemptLocked(record)) {
// Notify the listener that updates are currently disabled - but only if the request
// does not ignore location settings
receiver.callProviderEnabledLocked(name, false);
}
applyRequirementsLocked(name);
// Update the monitoring here just in case multiple location requests were added to the
// same receiver (this request may be high power and the initial might not have been).
receiver.updateMonitoring(true);
}
(4)上面源码上可以看到,当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());
}
(5) 因此,最终的解决方案为:
源码路径:frameworks/base/location/java/android/location/LocationManager.java
@UnsupportedAppUsage
private void requestLocationUpdates(LocationRequest request, LocationListener listener,
Looper looper, PendingIntent intent) {
String packageName = mContext.getPackageName();
// wrap the listener class
ListenerTransport transport = wrapListener(listener, looper);
try {
//如果名字为NETWORK_PROVIDER的LocationProvider为null,就不继续后面的获取位置的流程
+ if (!isProviderEnabled(NETWORK_PROVIDER))
+ retrun ;
//调用LocatonManagerService中的方法
mService.requestLocationUpdates(request, transport, intent, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}