1.首先看一下在android应用中是如何获取Location的
LocationManager locationManager;
String serviceName = Context.LOCATION_SERVICE;
locationManager = (LocationManager) this.getSystemService(serviceName); // 查找到服务信息
Criteria criteria = new Criteria(); //定义标准
criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗
String provider = locationManager.getBestProvider(criteria, true); // 获取最好的provider,就是在此时检测权限的
Location location = locationManager.getLastKnownLocation(provider); // 通过GPS获取位置
updateToNewLocation(location);
// 设置监听器,自动更新的最小时间为间隔N秒(1秒为1*1000,这样写主要为了方便)或最小位移变化超过N米
locationManager.requestLocationUpdates(provider, 100 * 1000, 500,
locationListener);
首先通过getSystemService找到LocationManager服务,然后设定需要的地理位置的一些标准。然后通过LocationManager中的getBestProvider函数调用LocationManagerService.java中的getBestProvider函数来找到最好的Provider,其中Provider有四种:
1)NETWORK_PROVIDER:通过信号塔和wifi接入点来定位
2)GPS_PROVIDER:需要ACCESS_FINE_LOCATION权限,是通过卫星定位
3)PASSIVE_PROVIDER:需要ACCESS_FINE_LOCATION权限
4)FUSED_PROVIDER:融合所有的位置信息提供最佳的地理位置
2.下面来看一下getBestProvider函数
public String getBestProvider(Criteria criteria, boolean enabledOnly) {
String result = null;
List<String> providers = getProviders(criteria, enabledOnly);
if (!providers.isEmpty()) {
result = pickBest(providers);
if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
return result;
}
providers = getProviders(null, enabledOnly);
if (!providers.isEmpty()) {
result = pickBest(providers);
if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
return result;
}
if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
return null;
}
首先通过根据标准Criteria通过getProviders()方法查找所有的符合的providers,如果providers不为空,那么通过pickBest函数,在providers列表中选择一个最好的provider,pickBest函数如下:
private String pickBest(List providers) {
if (providers.contains(LocationManager.GPS_PROVIDER)) {
return LocationManager.GPS_PROVIDER;
} else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
return LocationManager.NETWORK_PROVIDER;
} else {
return providers.get(0);
}
}
意思就是如果providers列表中存在GPS则首先选择GPS,如果没有GPS,则首先选择NET_PROVIDER,如果两个都么有,那么就选择providers中的第一个。(接上一段)如果providers列表为空,那么则通过getProviders(null, enabledOnly)来获取无标准的providers,接着做上面同样的事情。如果此时providers列表还是为空,那么返回null。
3.getProviders函数
public List getProviders(Criteria criteria, boolean enabledOnly) {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
ArrayList out;
int uid = Binder.getCallingUid();;
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
out = new ArrayList(mProviders.size());
for (LocationProviderInterface provider : mProviders) {
String name = provider.getName();
if (LocationManager.FUSED_PROVIDER.equals(name)) {
continue;
}
if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
continue;
}
if (criteria != null && !LocationProvider.propertiesMeetCriteria(
name, provider.getProperties(), criteria)) {
continue;
}
out.add(name);
}
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
if (D) Log.d(TAG, "getProviders()=" + out);
return out;
}
该函数首先通过getCallerAllowedResolutionLevel()函数来获取应用允许的位置信息分辨率(即权限审查)。getCallerAllowedResolutionLevel()函数如下:
private int getCallerAllowedResolutionLevel() {
return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
}
该函数简单的调用了getAllowedResolutionLevel(),函数如下:
private int getAllowedResolutionLevel(int pid, int uid) {
if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
pid, uid) == PackageManager.PERMISSION_GRANTED) {
return RESOLUTION_LEVEL_FINE;
} else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
pid, uid) == PackageManager.PERMISSION_GRANTED) {
return RESOLUTION_LEVEL_COARSE;
} else {
return RESOLUTION_LEVEL_NONE;
}
}
分析以下这张图:
图中ContextImpl类和ContextWrapper类中checkPermission函数如下:
ContextImpl类中的checkPermission函数如下:经分析可知最终调用的还是ActivityManagerService类中的checkPermission()。
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
try {
return ActivityManagerNative.getDefault().checkPermission(
permission, pid, uid);
} catch (RemoteException e) {
return PackageManager.PERMISSION_DENIED;
}
}
ContextWrapper类中checkPermission函数如下:其中mBase是Context的实例,其实调用的是ContextImpl类中的checkPermission函数。
public int checkPermission(String permission, int pid, int uid) {
return mBase.checkPermission(permission, pid, uid);
}
所以,最终调用checkPermission函数为PackageManagerService.java中的checkPermission函数。getAllowedResolutionLevel()进行权限检查后回去应用申请的权限,如果应用细粒度和粗粒度的权限都申请了,那么返回细粒度的分辨率即可。
对权限就分析到这吧