定位
定位方式有很多种,比如说GPS,Network,基站。
如何判断设备支持什么类型的定位?
在LocationManager里提供了方法,获取到所有的Providers
public List<String> getAllProviders() {
try {
return mService.getAllProviders();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
通过context就可以获取到LocationManager了,LocationManager服务在系统初始化的时候注册,所以通过context就可以获取到了。详情请看附录。
系统架构
主要看看GPS的
GPS主要关注GnssLocationProvider,其他的Provider用于其他定位方式。
创建的地方在LocationManagerService
mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
hardwear对应的文件在hardwear目录下
\android8.1\hardware\interfaces\gnss\1.0\default
主要的类关系图
完整的上层获取到底层Location信息变化的流程(Android8.1版本)
以下步骤,省略了权限,是否支持GPS检查之类的安全操作,主要路线如下:对着代码走一次就知道了。
===============App层=============================================
1、获取到LocationManager
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
2、向LocationManager里添加监听
lm.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000,//时间
100.0f,//触发通知的变化距离
new LocationListener() {
@Override
public void onLocationChanged(Location location) {
//location变化
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
//状态变化
}
@Override
public void onProviderEnabled(String provider) {
//定位方式开启:gps、network..
}
@Override
public void onProviderDisabled(String provider) {
//定位方式关闭
}
}
);
3、做了一层包装,然后调用requestLocationUpdates
public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance,
@NonNull LocationListener listener) {
checkProvider(provider);
checkListener(listener);
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
provider, minTime, minDistance, false);
requestLocationUpdates(request, listener, null, null);
}
4、调用到远程服务的requestLocationUpdates
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 {
mService.requestLocationUpdates(request, transport, intent, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (IllegalArgumentException e) {
Log.e(TAG, "IllegalArgumentException", e);
}
}
===============Framework层 Java =============================================
5、远程服务是谁呢?
private final ILocationManager mService;
public class LocationManagerService extends ILocationManager.Stub
远程服务是LocationManagerService
那我们在LocationManagerService里找找requestLocationUpdates方法
@Override
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
PendingIntent intent, String packageName) {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
checkPackageName(packageName);
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
WorkSource workSource = request.getWorkSource();
if (workSource != null && workSource.size() > 0) {
checkDeviceStatsAllowed();
}
boolean hideFromAppOps = request.getHideFromAppOps();
if (hideFromAppOps) {
checkUpdateAppOpsAllowed();
}
LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
// providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();
try {
// We don't check for MODE_IGNORED here; we will do that when we go to deliver
// a location.
checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
synchronized (mLock) {
Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
packageName, workSource, hideFromAppOps);
requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
6、走到这里,关心Listener在哪里调用就知道Location在哪里更新了
上面的代码里我们走到了checkListenerOrIntentLocked
private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
if (intent == null && listener == null) {
throw new IllegalArgumentException("need either listener or intent");
} else if (intent != null && listener != null) {
throw new IllegalArgumentException("cannot register both listener and intent");
} else if (intent != null) {
checkPendingIntent(intent);
return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
} else {
return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
}
}
7、getReceiverLocked里会创建Receiver,Listener主成了Receiver的成员变量了。这里是framework层的LocationManagerService
private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
String packageName, WorkSource workSource, boolean hideFromAppOps) {
IBinder binder = listener.asBinder();
Receiver receiver = mReceivers.get(binder);
if (receiver == null) {
receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
hideFromAppOps);
try {
receiver.getListener().asBinder().linkToDeath(receiver, 0);
} catch (RemoteException e) {
Slog.e(TAG, "linkToDeath failed:", e);
return null;
}
mReceivers.put(binder, receiver);
}
return receiver;
}
8、通知上层更新的地方
mListener.onStatusChanged(provider, status, extras);
mListener.onLocationChanged(new Location(location));
mListener.onProviderEnabled(provider);
mListener.onProviderDisabled(provider);
这就对应着我们开头设置监听的地方了。
那么以上又是如何通知的呢?
9、通知LocationChange的地方
public boolean callLocationChangedLocked(Location location) {
...
mListener.onLocationChanged(new Location(location));
...
}
哪里通知Location变化呢?
private void handleLocationChangedLocked(Location location, boolean passive) {
...
if (!receiver.callStatusChangedLocked(provider, status, extras)) {
receiverDead = true;
Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
}
...
}
往上回去找则是
private void handleLocationChanged(Location location, boolean passive) {
...
synchronized (mLock) {
if (isAllowedByCurrentUserSettingsLocked(provider)) {
if (!passive) {
// notify passive provider of the new location
mPassiveProvider.updateLocation(myLocation);
}
handleLocationChangedLocked(myLocation, passive);
}
}
}
其实就是在Handler里接收到消息以后通知的
private class LocationWorkerHandler extends Handler {
public LocationWorkerHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOCATION_CHANGED:
handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
break;
}
}
}
所以,我们找到MSG_LOCATION_CHANGED发送的地方,就知道Location是从哪里来的了。
在LocationManagerService.java里
@Override
public void reportLocation(Location location, boolean passive) {
checkCallerIsProvider();
if (!location.isComplete()) {
Log.w(TAG, "Dropping incomplete location: " + location);
return;
}
mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
m.arg1 = (passive ? 1 : 0);
mLocationHandler.sendMessageAtFrontOfQueue(m);
}
接下来则便是要找到reportLocation是哪里调用的呢?
当系统启动的时候,会走这个代码
com.android.server.LocationManagerService#loadProvidersLocked
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
mLocationHandler.getLooper());
reportLocation是被GnssLocationProvider里通知的。
在创建GnssLocationProvider的时候,把this传进去了,也就是LocationManagerService。那么GnssLocationProvider就可以通知LocationManagerService里的reportLocation方法了。
代码如下:
/**
* called from native code to update our position.
*/
private void reportLocation(boolean hasLatLong, Location location) {
...
synchronized (mLocation) {
mLocation = location;
// It would be nice to push the elapsed real-time timestamp
// further down the stack, but this is still useful
mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
mLocation.setExtras(mLocationExtras);
try {
mILocationManager.reportLocation(mLocation, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocation");
}
}
...
}
到这里,我们可以看到注释,called from native code to update our position.这个方法是被Native调用的,也就是底层通过反射的方式调用此方法。这里就到了framework的jni层了。
===============Framework层 JNI =============================================
./base/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
我们就以reportLocation这个方法为例,在com_android_server_location_GnssLocationProvider.cpp里
Return<void> GnssCallback::gnssLocationCb(
const ::android::hardware::gnss::V1_0::GnssLocation& location) {
JNIEnv* env = getJniEnv();
jobject jLocation = translateLocation(env, location);
bool hasLatLong = (static_cast<uint32_t>(location.gnssLocationFlags) &
hardware::gnss::V1_0::GnssLocationFlags::HAS_LAT_LONG) != 0;
env->CallVoidMethod(mCallbacksObj,
method_reportLocation,
boolToJbool(hasLatLong),
jLocation);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
}
这里面就是Location变化的回调了。
到这里的话,就到了framework的jni层了。
再往下就到hal层了。引入的头文件
#include <android/hardware/gnss/1.0/IGnss.h>
#include <vendor/sprd/hardware/gnss/1.0/IGnssExt.h>
#include <vendor/sprd/hardware/gnss/1.0/IAGnssRilExt.h>
sp<IGnssExt> gnssHal = nullptr;
# 可以看到通过gnssHal去设置了callback,然后底层就可以通过回调的方式通知到framework层的jni层了
auto result = gnssHal->setCallback(gnssCbIface);
============== hal 层 =============================================
\android8.1\hardware\interfaces\gnss\1.0\default
附录
服务在哪里注册的?为什么context.getSystemService(xxx) 就可以获取到服务?
服务会在SystemServiceRegistry.java进行注册,这个是在系统初始化的时候进行注册的。调用context.getSystemService(xxx)服务,除了WindowService、SearchService、LayoutInflateService以外,其他的Service都是从contextImpl中的getSystemService(serviceName)中获取的。前面三个服务,直接在Activity/contextWrapper里创建返回了。
ContextImpl.java里获取常见的服务:
注释的是key,返回的是value。我们前面Context.LOCATION_SERVICE,对应的就是LocationManager了,所以返回了LocationManager。如果想知道ContextImpl.java里是如何获取的,请继续往下看吧。
#WINDOW_SERVICE
android.view.WindowManager
#LAYOUT_INFLATER_SERVICE
android.view.LayoutInflater
#ACTIVITY_SERVICE
android.app.ActivityManager
#POWER_SERVICE
android.os.PowerManager
#ALARM_SERVICE
android.app.AlarmManager
#NOTIFICATION_SERVICE
android.app.NotificationManager
#KEYGUARD_SERVICE
android.app.KeyguardManager
#LOCATION_SERVICE
android.location.LocationManager
#SEARCH_SERVICE
android.app.SearchManager
#SENSOR_SERVICE
android.hardware.SensorManager
#STORAGE_SERVICE
android.os.storage.StorageManager
#VIBRATOR_SERVICE
android.os.Vibrator
#CONNECTIVITY_SERVICE
android.net.ConnectivityManager
#WIFI_SERVICE
android.net.wifi.WifiManager
#AUDIO_SERVICE
android.media.AudioManager
#MEDIA_ROUTER_SERVICE
android.media.MediaRouter
#TELEPHONY_SERVICE
android.telephony.TelephonyManager
#TELEPHONY_SUBSCRIPTION_SERVICE
android.telephony.SubscriptionManager
#CARRIER_CONFIG_SERVICE
android.telephony.CarrierConfigManager
#INPUT_METHOD_SERVICE
android.view.inputmethod.InputMethodManager
#UI_MODE_SERVICE
android.app.UiModeManager
#DOWNLOAD_SERVICE
android.app.DownloadManager
#BATTERY_SERVICE
android.os.BatteryManager
#JOB_SCHEDULER_SERVICE
android.app.job.JobScheduler
#NETWORK_STATS_SERVICE
android.app.usage.NetworkStatsManager
android.os.HardwarePropertiesManager
#HARDWARE_PROPERTIES_SERVICE
在android.app.ContextImpl.java中,路径在frameworks/base/core/java/android/app/ContextImpl.java里
我们可以看到
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
也就是说,是从SystemServiceRegistry里获取的,里面维护者一个Map集合。
key是服务的名称,值是服务。也就是上面这个表,当然,还可以添加其他服务。