摘要: 本文抛砖引玉,简述Android GPS信息获取系统调用流程。
App源代码下载目录:
应用程序获取GPS,到底经过哪些流程,请让我为你一一呈现。
要想获取GPS信息,你先的有一台GPS设备,先的打开GPS服务,然后运行应用程序,我们首先从打开GPS服务开始。
1. 系统设置中开启GPS服务
代码:
packages\apps\Settings\src\com\android\settings\location\LocationSettings.java
public class LocationSettings extends LocationSettingsBase
implements SwitchBar.OnSwitchChangeListener
{
private SwitchBar mSwitchBar;
private Switch mSwitch;
...
@Override public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
final SettingsActivity activity = (SettingsActivity) getActivity();
mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
mSwitchBar = activity.getSwitchBar();
mSwitch = mSwitchBar.getSwitch();
mSwitchBar.show();
}
}
@Override public void onResume() // Activity第一启动的时候执行onCreate()->onStart()->onResume()
{
super.onResume();
createPreferenceHierarchy();
if (!mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
mValidListener = true;
}
}
@Override public void onPause() // 被另一个透明或者Dialog样式的Activity 覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,已经失去了焦点故不可与用户交互。
{
try {
getActivity().unregisterReceiver(mReceiver);
} catch (RuntimeException e) {
// Ignore exceptions caused by race condition
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Swallowing " + e);
}
}
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
mValidListener = false;
}
super.onPause();
}
private PreferenceScreen createPreferenceHierarchy()
{
final SettingsActivity activity = (SettingsActivity) getActivity();
PreferenceScreen root = getPreferenceScreen();
if (root != null) {
root.removeAll();
}
addPreferencesFromResource(R.xml.location_settings);
root = getPreferenceScreen();
setupManagedProfileCategory(root);
mLocationMode = root.findPreference(KEY_LOCATION_MODE); // private Preference mLocationMode; //"location_mode"
mLocationMode.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
activity.startPreferencePanel(LocationMode.class.getName(), null,
R.string.location_mode_screen_title, null, LocationSettings.this, 0);
return true;
}
});
mAgpsEnabled = getActivity().getResources().getBoolean(R.bool.config_agps_enabled);
mAssistedGps = (CheckBoxPreference)root.findPreference(KEY_ASSISTED_GPS);
if (!mAgpsEnabled) {
root.removePreference(mAssistedGps);
mAGpsParas = (Preference) root.findPreference(KEY_ASSISTED_GPS_PARAS);
root.removePreference(mAGpsParas);
}
if (mAssistedGps != null) {
mAssistedGps.setChecked(Settings.Global.getInt(getContentResolver(),
Settings.Global.ASSISTED_GPS_ENABLED, 2) == 1);
}
mCategoryRecentLocationRequests = (PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS); // "recent_location_requests"
RecentLocationApps recentApps = new RecentLocationApps(activity);
List<Preference> recentLocationRequests = recentApps.getAppList();
if (recentLocationRequests.size() > 0) {
addPreferencesSorted(recentLocationRequests, mCategoryRecentLocationRequests);
} else {
// If there's no item to display, add a "No recent apps" item.
Preference banner = new Preference(activity);
banner.setLayoutResource(R.layout.location_list_no_item);
banner.setTitle(R.string.location_no_recent_apps);
banner.setSelectable(false);
mCategoryRecentLocationRequests.addPreference(banner);
}
boolean lockdownOnLocationAccess = false;
// Checking if device policy has put a location access lock-down on the managed
// profile. If managed profile has lock-down on location access then its
// injected location services must not be shown.
if (mManagedProfile != null
&& mUm.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile)) {
lockdownOnLocationAccess = true;
}
addLocationServices(activity, root, lockdownOnLocationAccess);
refreshLocationMode();
return root;
}
private void addLocationServices(Context context, PreferenceScreen root, boolean lockdownOnLocationAccess)
{
PreferenceCategory categoryLocationServices = (PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES); // "location_services"
injector = new SettingsInjector(context);
// If location access is locked down by device policy then we only show injected settings for the primary profile.
List<Preference> locationServices = injector.getInjectedSettings(lockdownOnLocationAccess ? UserHandle.myUserId() : UserHandle.USER_CURRENT);
mReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received settings change intent: " + intent);
}
injector.reloadStatusMessages();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED); // "android.location.InjectedSettingChanged"
context.registerReceiver(mReceiver, filter);
if (locationServices.size() > 0) {
addPreferencesSorted(locationServices, categoryLocationServices);
} else {
// If there's no item to display, remove the whole category.
root.removePreference(categoryLocationServices);
}
}
// Listens to the state change of the location master switch.
@Override public void onSwitchChanged(Switch switchView, boolean isChecked)
{
if (isChecked) {
setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
} else {
setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_OFF);
}
}
代码: packages\apps\Settings\src\com\android\settings\location\LocationSettingsBase.java
public void setLocationMode(int mode)
{
if (isRestricted()) {
if (Log.isLoggable(TAG, Log.INFO)) {
Log.i(TAG, "Restricted user, not setting location mode");
}
mode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF);
if (mActive) {
onModeChanged(mode, true);
}
return;
}
Intent intent = new Intent(MODE_CHANGING_ACTION);
intent.putExtra(CURRENT_MODE_KEY, mCurrentMode);
intent.putExtra(NEW_MODE_KEY, mode);
getActivity().sendBroadcast(intent, android.Manifest.permission.WRITE_SECURE_SETTINGS);
Settings.Secure.putInt(getContentResolver(), Settings.Secure.LOCATION_MODE, mode);
refreshLocationMode();
}
代码: packages\apps\Settings\src\com\android\settings\location\LocationSettings.java
@Override public void
onModeChanged(int mode, boolean restricted)
{
switch (mode) {
case android.provider.Settings.Secure.LOCATION_MODE_OFF:
mLocationMode.setSummary(R.string.location_mode_location_off_title); // private Preference mLocationMode;
break;
case android.provider.Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
mLocationMode.setSummary(R.string.location_mode_sensors_only_title);
break;
case android.provider.Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
mLocationMode.setSummary(R.string.location_mode_battery_saving_title);
break;
case android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
mLocationMode.setSummary(R.string.location_mode_high_accuracy_title);
break;
default:
break;
}
final boolean enabled = (mode != android.provider.Settings.Secure.LOCATION_MODE_OFF); // 是否打开GPS服务
mSwitchBar.setEnabled(!restricted); // 是否限制用户设置
mLocationMode.setEnabled(enabled && !restricted);
mCategoryRecentLocationRequests.setEnabled(enabled);
if (enabled != mSwitch.isChecked()) {
// set listener to null so that that code below doesn't trigger onCheckedChanged()
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
}
mSwitch.setChecked(enabled);
if (mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
}
}
if (mManagedProfilePreference != null) {
if (mUm.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile)) {
changeManagedProfileLocationAccessStatus(false, R.string.managed_profile_location_switch_lockdown);
} else {
if (enabled) {
changeManagedProfileLocationAccessStatus(true, R.string.switch_on_text); // 设置界面显示: On
} else {
changeManagedProfileLocationAccessStatus(false, R.string.switch_off_text); // 设置界面显示: Off
}
}
}
// As a safety measure, also reloads on location mode change to ensure the settings are
// up-to-date even if an affected app doesn't send the setting changed broadcast.
injector.reloadStatusMessages();
}
2. 应用程序
为了使代码尽量简洁,省略诸多可靠性判断语句,本代码测试前,请先打开设备的GPS功能。
下面是最简单的获取GPS信息的应用程序代码,只需要android.permission.ACCESS_FINE_LOCATION权限。
MainActivity.java代码:
package com.tom.tomgpstest;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.EditText;
public class MainActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LocationManager lm = (LocationManager)
getSystemService(Context.LOCATION_SERVICE); // public static final String LOCATION_SERVICE = "location";
Location location= lm.
getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(location!=null)
{
EditText editText = (EditText)findViewById(R.id.editText);
editText.append("\n经度:");
editText.append(String.valueOf(location.
getLongitude()));
editText.append("\n纬度:");
editText.append(String.valueOf(location.getLatitude()));
editText.append("\n海拔:");
editText.append(String.valueOf(location.getAltitude()));
}
}
}
代码最重要的一行是:LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);从系统服务中获取LocationManager服务。
于是我们追踪LOCATION_SERVICE服务。
注: getSystemService这个方法基于context,只有存在TextView控件的窗体中这个方法才会被激活
3. LOCATION_SERVICE服务
代码: frameworks\base\core\java\android\app\Activity.java
@Override public Object getSystemService(@ServiceName @NonNull String name)
{
if (getBaseContext() == null) {
throw new IllegalStateException("System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) // public static final String WINDOW_SERVICE = "window";
{
return mWindowManager;
}
else if (SEARCH_SERVICE.equals(name)) // public static final String SEARCH_SERVICE = "search";
{
ensureSearchManager();
return mSearchManager;
}
return
super.getSystemService(name); // Context.LOCATION_SERVICE调用本行
}
Activity继承ContextThemeWrapper,ContextThemeWrapper继承ContextWrapper。ContextWrapper.getSystemService()里面调用mBase.getSystemService()。
ContextWrapper中mBase是一个ContextImpl实例变量。
代码: frameworks\base\core\java\android\app\ContextImpl.java
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();
...
@Override public Object getSystemService(String name)
{
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); // "location"已在其中
return fetcher == null ? null : fetcher.getService(this); // 从后面分析可知,"location"的fetcher是LocationManager的一个实例
}
...
static class ServiceFetcher
{
int mContextCacheIndex = -1;
public Object
getService(ContextImpl ctx)
{
ArrayList<Object> cache = ctx.mServiceCache;
Object service;
synchronized (cache) {
if (cache.size() == 0) {
// Initialize the cache vector on first access.
// At this point sNextPerContextServiceCacheIndex
// is the number of potential services that are
// cached per-Context.
for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
cache.add(null);
}
} else {
service = cache.get(mContextCacheIndex);
if (service != null) {
return service;
}
}
service = createService(ctx);
cache.set(mContextCacheIndex, service);
return service;
}
}
public Object createService(ContextImpl ctx) {
throw new RuntimeException("Not implemented");
}
}
...
static // 用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块。
{
...
registerService(LOCATION_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(LOCATION_SERVICE);
return
new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
}});
...
}
...
private static void
registerService(String serviceName, ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.
put(serviceName, fetcher);
}
ServiceManager.getService()代码: frameworks\base\core\java\android\os\ServiceManager.java
public static IBinder getService(String name)
{
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name); // 不再往下追踪了
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
4. LocationManager.getLastKnownLocation()
代码: frameworks\base\location\java\android\location\LocationManager.java
public class LocationManager
{
private final ILocationManager mService;
...
public Location getLastKnownLocation(String provider)
{
checkProvider(provider);
String packageName = mContext.getPackageName();
LocationRequest request = LocationRequest.createFromDeprecatedProvider(provider, 0, 0, true);
try {
return
mService.getLastLocation(request, packageName);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException", e);
return null;
}
}
...
}
代码: frameworks\base\services\core\java\com\android\server\LocationManagerService.java
private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
...
@Override public Location getLastLocation(LocationRequest request, String packageName)
{
if (D) Log.d(TAG, "getLastLocation: " + request);
if (request == null) request = DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, request.getProvider());
// no need to sanitize this request, as only the provider name is used
final int uid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
if (mBlacklist.isBlacklisted(packageName)) {
if (D) Log.d(TAG, "not returning last loc for blacklisted app: " + packageName);
return null;
}
if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
if (D) Log.d(TAG, "not returning last loc for no op app: " + packageName);
return null;
}
synchronized (mLock) {
// Figure out the provider. Either its explicitly request (deprecated API's),
// or use the fused provider
String name = request.getProvider();
if (name == null) name = LocationManager.FUSED_PROVIDER;
LocationProviderInterface provider = mProvidersByName.get(name);
if (provider == null) return null;
if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Location location;
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
// Make sure that an app with coarse permissions can't get frequent location
// updates by calling LocationManager.getLastKnownLocation repeatedly.
location =
mLastLocationCoarseInterval.get(name); // 获取更新慢的Location // private final HashMap<String, Location> mLastLocationCoarseInterval = new HashMap<String, Location>();
} else {
location =
mLastLocation.get(name); // 获取Location //private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
}
if (location == null) {
return null;
}
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
if (noGPSLocation != null) {
return new Location(mLocationFudger.getOrCreate(noGPSLocation)); // 返回Location
}
} else {
return new Location(location); // 返回Location
}
}
return null;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
5. Location.getLongitude()
代码: frameworks\base\location\java\android\location\LocationManager.java
public class Location implements Parcelable
{
...
public double
getLongitude()
{
return mLongitude;
}
...
}
注: base\services\core\java\com\android\server\location\GpsLocationProvider.java中reportLocation(),buildLocation()调用了setLongitude().
附录: SystemServer中LOCATION_SERVICE服务
代码: frameworks\base\services\java\com\android\server\SystemServer.java
在startOtherServices()函数中,LOCATION_SERVICE服务被加入服务列表之中:
if (!disableLocation)
{
try {
Slog.i(TAG, "Location Manager");
location = new LocationManagerService(context);
ServiceManager.addService(Context.LOCATION_SERVICE, location);
} catch (Throwable e) {
reportWtf("starting Location Manager", e);
}
...
final LocationManagerService locationF = location; ...
mActivityManagerService.systemReady(new Runnable()
{
@Override public void run() {
... try {
if (locationF != null) locationF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying Location Service running", e); }
...
} }
addService()代码:frameworks\base\services\core\java\com\android\server\LocationManagerService.java
systemRunning()
{
synchronized (mLock)
{
if (D) Log.d(TAG, "systemReady()");
// fetch package manager
mPackageManager = mContext.getPackageManager();
// fetch power manager
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
// prepare worker thread
mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
// prepare mLocationHandler's dependents
mLocationFudger = new LocationFudger(mContext, mLocationHandler);
mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
mBlacklist.init();
mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
// Monitor for app ops mode changes.
AppOpsManager.OnOpChangedListener callback
= new AppOpsManager.OnOpChangedInternalListener() {
public void onOpChanged(int op, String packageName) {
synchronized (mLock) {
for (Receiver receiver : mReceivers.values()) {
receiver.updateMonitoring(true);
}
applyAllProviderRequirementsLocked();
}
}
};
mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
updateUserProfiles(mCurrentUserId);
// prepare providers
loadProvidersLocked(); // 执行gpsProvider = new GpsLocationProvider(...),静态块class_init_native()被调用,对应frameworks\base\services\core\com_android_server_location_GpsLocationProvider.cpp, android_location_GpsLocationProvider_class_init_native(),其中执行hw_get_module("gps",...),我的代码hardware\qcom\gps\loc_api\libloc_api_50001\gps.c中构建了gps模块(知道了硬件代码实现位置),获取gps_device_t* gps_device = (gps_device_t *)device; sGpsInterface = gps_device->get_gps_interface(gps_device);
updateProvidersLocked(); // 调用GpsLocationProvider.enable(),引发handleEnable(),运行native_init(),对应android_location_GpsLocationProvider_init()),与native层通信,不再细究
}
// listen for settings changes
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
new ContentObserver(mLocationHandler) {
@Override
public void onChange(boolean selfChange) {
synchronized (mLock) {
updateProvidersLocked();
}
}
}, UserHandle.USER_ALL);
mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
// listen for user change
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
mContext.registerReceiverAsUser(new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
} else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
|| Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
updateUserProfiles(mCurrentUserId);
}
}
}, UserHandle.ALL, intentFilter, null, mLocationHandler);
} ...
private void loadProvidersLocked()
{
// create a passive location provider, which is always enabled
PassiveProvider passiveProvider = new PassiveProvider(this);
addProviderLocked(passiveProvider);
mEnabledProviders.add(passiveProvider.getName());
mPassiveProvider = passiveProvider;
// Create a gps location provider
GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
mLocationHandler.getLooper());
if (GpsLocationProvider.isSupported()) {
mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
addProviderLocked(gpsProvider);
mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
}
mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider(); ...
}
addService()代码: frameworks\base\core\java\android\os\ServiceManager.java
public final class ServiceManager
{
...
public static void addService(String name, IBinder service)
{
try {
getIServiceManager().addService(name, service, false);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
private static IServiceManager getIServiceManager()
{
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
...
}
asInterface()代码: frameworks\base\core\java\android\os\ServiceManagerNative.java
public abstract class ServiceManagerNative extends Binder implements IServiceManager
{
...
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
...
public void addService(String name, IBinder service, boolean allowIsolated) throws RemoteException
{
Parcel data = Parcel.obtain(); // 从sOwnedPool取回一个新的Parcel对象
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor); // 实现在frameworks\base\core\jni\android_os_Parcel.cpp
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0); // private IBinder mRemote;
reply.recycle();
data.recycle();
}
...
}
说明:Parcel定义:
public final class Parcel
{
...
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
...
}
IServiceManager代码: frameworks\base\core\java\android\os\IServiceManager.java
public interface IServiceManager extends IInterface
{
...
public void addService(String name, IBinder service, boolean allowIsolated) throws RemoteException;
...
static final String descriptor = "android.os.IServiceManager";
...
}