Made it easier to disable overlay mechanism of location components.

Fixed b/8276827

Vendor might want to provide their own implementation of "network
location", "fused location" and "geocoder" service. Location manager now
allows those service to be replaced by packages that have the same
signature as one of the packages in config_locationProviderPackageNames.
Such behavior might not be desirable on some devices. This change
make this behavior configurable by 3 boolean flags.

Details:
- Added three boolean flags in core/res/res/values/config.xml to enable
or disable NLP/FLP/Geocoder overlay
- Added 3 package name for the stock NLP/FLP/Geocoder. They are needed
  only when overlay is disabled because LocationManagerService need to
  know which package is preferred when searching for
  NLP/FLP/Geocoder service.
- Made ServiceWatcher able to handle non-overlayable services.
- Fixed an NPE isue in ServiceWatcher. mPm.queryIntentServicesAsUser
  might return null.
- Fixed an bug: justCheckThisPackage in bindBestPackageLocked is always
  ignored.

Change-Id: Id221961ac7c3aa8ad44b894f9523f04f770ae237
This commit is contained in:
Zhentao Sun
2013-04-17 17:47:53 -07:00
parent 339ac85483
commit c5fc9988f1
7 changed files with 204 additions and 65 deletions

View File

@@ -633,6 +633,60 @@
<!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool>
<!-- Whether to enable network location overlay which allows network
location provider to be replaced by an app at run-time. When disabled,
only the config_networkLocationProviderPackageName package will be
searched for network location provider, otherwise packages whose
signature matches the signatures of config_locationProviderPackageNames
will be searched, and the service with the highest version number will
be picked. Anyone who wants to disable the overlay mechanism can set it
to false.
-->
<bool name="config_enableNetworkLocationOverlay" translatable="false">true</bool>
<!-- Package name providing network location support. Used only when
config_enableNetworkLocationOverlay is false. -->
<string name="config_networkLocationProviderPackageName" translatable="false">@null</string>
<!-- Whether to enable fused location provider overlay which allows fused
location provider to be replaced by an app at run-time. When disabled,
only the config_fusedLocationProviderPackageName package will be
searched for fused location provider, otherwise packages whose
signature matches the signatures of config_locationProviderPackageNames
will be searched, and the service with the highest version number will
be picked. Anyone who wants to disable the overlay mechanism can set it
to false.
-->
<bool name="config_enableFusedLocationOverlay" translatable="false">true</bool>
<!-- Package name providing fused location support. Used only when
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
<!-- Whether to enable geocoder overlay which allows geocoder to be replaced
by an app at run-time. When disabled, only the
config_geocoderProviderPackageName package will be searched for
geocoder, otherwise packages whose signature matches the signatures of
config_locationProviderPackageNames will be searched, and the service
with the highest version number will be picked. Anyone who wants to
disable the overlay mechanism can set it to false.
-->
<bool name="config_enableGeocoderOverlay" translatable="false">true</bool>
<!-- Package name providing geocoder API support. Used only when
config_enableGeocoderOverlay is false. -->
<string name="config_geocoderProviderPackageName" translatable="false">@null</string>
<!-- Whether to enable geofence overlay which allows geofence to be replaced
by an app at run-time. When disabled, only the
config_geofenceProviderPackageName package will be searched for
geofence implementation, otherwise packages whose signature matches the
signatures of config_locationProviderPackageNames will be searched, and
the service with the highest version number will be picked. Anyone who
wants to disable the overlay mechanism can set it to false.
-->
<bool name="config_enableGeofenceOverlay" translatable="false">true</bool>
<!-- Package name providing geofence API support. Used only when
config_enableGeofenceOverlay is false. -->
<string name="config_geofenceProviderPackageName" translatable="false">@null</string>
<!-- Package name(s) containing location provider support.
These packages can contain services implementing location providers,
such as the Geocode Provider, Network Location Provider, and

View File

@@ -1534,6 +1534,10 @@
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
<java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
<java-symbol type="bool" name="config_sf_limitedAlpha" />
<java-symbol type="bool" name="config_unplugTurnsOnScreen" />
<java-symbol type="bool" name="config_wifi_background_scan_support" />
@@ -1618,6 +1622,10 @@
<java-symbol type="string" name="car_mode_disable_notification_title" />
<java-symbol type="string" name="chooser_wallpaper" />
<java-symbol type="string" name="config_datause_iface" />
<java-symbol type="string" name="config_fusedLocationProviderPackageName" />
<java-symbol type="string" name="config_geocoderProviderPackageName" />
<java-symbol type="string" name="config_geofenceProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
<java-symbol type="string" name="config_wimaxManagerClassname" />
<java-symbol type="string" name="config_wimaxNativeLibLocation" />
<java-symbol type="string" name="config_wimaxServiceClassname" />

View File

@@ -380,7 +380,10 @@ public class LocationManagerService extends ILocationManager.Stub {
mContext,
LocationManager.NETWORK_PROVIDER,
NETWORK_LOCATION_SERVICE_ACTION,
providerPackageNames, mLocationHandler);
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
com.android.internal.R.string.config_networkLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames,
mLocationHandler);
if (networkProvider != null) {
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
mProxyProviders.add(networkProvider);
@@ -394,7 +397,10 @@ public class LocationManagerService extends ILocationManager.Stub {
mContext,
LocationManager.FUSED_PROVIDER,
FUSED_LOCATION_SERVICE_ACTION,
providerPackageNames, mLocationHandler);
com.android.internal.R.bool.config_enableFusedLocationOverlay,
com.android.internal.R.string.config_fusedLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames,
mLocationHandler);
if (fusedLocationProvider != null) {
addProviderLocked(fusedLocationProvider);
mProxyProviders.add(fusedLocationProvider);
@@ -406,15 +412,22 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// bind to geocoder provider
mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
com.android.internal.R.bool.config_enableGeocoderOverlay,
com.android.internal.R.string.config_geocoderProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames,
mLocationHandler);
if (mGeocodeProvider == null) {
Slog.e(TAG, "no geocoder provider found");
}
// bind to geofence provider
GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, providerPackageNames,
mLocationHandler, gpsProvider.getGpsGeofenceProxy());
GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
com.android.internal.R.bool.config_enableGeofenceOverlay,
com.android.internal.R.string.config_geofenceProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames,
mLocationHandler,
gpsProvider.getGpsGeofenceProxy());
if (provider == null) {
Slog.e(TAG, "no geofence provider found");
}
@@ -1290,14 +1303,14 @@ public class LocationManagerService extends ILocationManager.Stub {
if (name == null) {
throw new IllegalArgumentException("provider name must not be null");
}
if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+ " " + name + " " + request + " from " + packageName + "(" + uid + ")");
LocationProviderInterface provider = mProvidersByName.get(name);
if (provider == null) {
throw new IllegalArgumentException("provider doesn't exisit: " + provider);
}
if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+ " " + name + " " + request + " from " + packageName + "(" + uid + ")");
UpdateRecord record = new UpdateRecord(name, request, receiver);
UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
if (oldRecord != null) {

View File

@@ -27,6 +27,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
@@ -36,6 +37,7 @@ import com.android.internal.content.PackageMonitor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -53,6 +55,13 @@ public class ServiceWatcher implements ServiceConnection {
private final PackageManager mPm;
private final List<HashSet<Signature>> mSignatureSets;
private final String mAction;
/**
* If mServicePackageName is not null, only this package will be searched for the service that
* implements mAction. When null, all packages in the system that matches one of the signature
* in mSignatureSets are searched.
*/
private final String mServicePackageName;
private final Runnable mNewServiceWork;
private final Handler mHandler;
@@ -87,19 +96,40 @@ public class ServiceWatcher implements ServiceConnection {
}
public ServiceWatcher(Context context, String logTag, String action,
List<String> initialPackageNames, Runnable newServiceWork, Handler handler) {
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId, Runnable newServiceWork,
Handler handler) {
mContext = context;
mTag = logTag;
mAction = action;
mPm = mContext.getPackageManager();
mNewServiceWork = newServiceWork;
mHandler = handler;
Resources resources = context.getResources();
// Whether to enable service overlay.
boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
ArrayList<String> initialPackageNames = new ArrayList<String>();
if (enableOverlay) {
// A list of package names used to create the signatures.
String[] pkgs = resources.getStringArray(initialPackageNamesResId);
if (pkgs != null) initialPackageNames.addAll(Arrays.asList(pkgs));
mServicePackageName = null;
if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
} else {
// The default package name that is searched for service implementation when overlay is
// disabled.
String servicePackageName = resources.getString(defaultServicePackageNameResId);
if (servicePackageName != null) initialPackageNames.add(servicePackageName);
mServicePackageName = servicePackageName;
if (D) Log.d(mTag, "Overlay disabled, default package=" + servicePackageName);
}
mSignatureSets = getSignatureSets(context, initialPackageNames);
}
public boolean start() {
synchronized (mLock) {
if (!bindBestPackageLocked(null)) return false;
if (!bindBestPackageLocked(mServicePackageName)) return false;
}
// listen for user change
@@ -115,8 +145,10 @@ public class ServiceWatcher implements ServiceConnection {
}
}, UserHandle.ALL, intentFilter, null, mHandler);
// listen for relevant package changes
mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
// listen for relevant package changes if service overlay is enabled.
if (mServicePackageName == null) {
mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
}
return true;
}
@@ -133,50 +165,55 @@ public class ServiceWatcher implements ServiceConnection {
if (justCheckThisPackage != null) {
intent.setPackage(justCheckThisPackage);
}
List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(new Intent(mAction),
List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
PackageManager.GET_META_DATA, UserHandle.USER_OWNER);
int bestVersion = Integer.MIN_VALUE;
String bestPackage = null;
boolean bestIsMultiuser = false;
for (ResolveInfo rInfo : rInfos) {
String packageName = rInfo.serviceInfo.packageName;
if (rInfos != null) {
for (ResolveInfo rInfo : rInfos) {
String packageName = rInfo.serviceInfo.packageName;
// check signature
try {
PackageInfo pInfo;
pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (!isSignatureMatch(pInfo.signatures)) {
Log.w(mTag, packageName + " resolves service " + mAction +
", but has wrong signature, ignoring");
// check signature
try {
PackageInfo pInfo;
pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (!isSignatureMatch(pInfo.signatures)) {
Log.w(mTag, packageName + " resolves service " + mAction
+ ", but has wrong signature, ignoring");
continue;
}
} catch (NameNotFoundException e) {
Log.wtf(mTag, e);
continue;
}
} catch (NameNotFoundException e) {
Log.wtf(mTag, e);
continue;
// check metadata
int version = Integer.MIN_VALUE;
boolean isMultiuser = false;
if (rInfo.serviceInfo.metaData != null) {
version = rInfo.serviceInfo.metaData.getInt(
EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
}
if (version > mVersion) {
bestVersion = version;
bestPackage = packageName;
bestIsMultiuser = isMultiuser;
}
}
// check metadata
int version = Integer.MIN_VALUE;
boolean isMultiuser = false;
if (rInfo.serviceInfo.metaData != null) {
version = rInfo.serviceInfo.metaData.getInt(EXTRA_SERVICE_VERSION,
Integer.MIN_VALUE);
isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
}
if (version > mVersion) {
bestVersion = version;
bestPackage = packageName;
bestIsMultiuser = isMultiuser;
if (D) {
Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
(justCheckThisPackage == null ? ""
: "(" + justCheckThisPackage + ") "), rInfos.size(),
(bestPackage == null ? "no new best package"
: "new best package: " + bestPackage)));
}
} else {
if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction);
}
if (D) Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
(justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "),
rInfos.size(),
(bestPackage == null ? "no new best package" : "new best package: "
+ bestPackage)));
if (bestPackage != null) {
bindToPackageLocked(bestPackage, bestVersion, bestIsMultiuser);
return true;
@@ -243,8 +280,9 @@ public class ServiceWatcher implements ServiceConnection {
// package updated, make sure to rebind
unbindLocked();
}
// check the updated package in case it is better
bindBestPackageLocked(packageName);
// Need to check all packages because this method is also called when a
// system app is uninstalled and the stock version in reinstalled.
bindBestPackageLocked(null);
}
}
@@ -256,7 +294,7 @@ public class ServiceWatcher implements ServiceConnection {
unbindLocked();
}
// check the new package is case it is better
bindBestPackageLocked(packageName);
bindBestPackageLocked(null);
}
}
@@ -271,6 +309,20 @@ public class ServiceWatcher implements ServiceConnection {
}
}
}
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
synchronized (mLock) {
if (packageName.equals(mPackageName)) {
// service enabled or disabled, make sure to rebind
unbindLocked();
}
// the service might be disabled, need to search for a new
// package
bindBestPackageLocked(null);
}
return super.onPackageChanged(packageName, uid, components);
}
};
@Override
@@ -323,7 +375,7 @@ public class ServiceWatcher implements ServiceConnection {
synchronized (mLock) {
if (!mIsMultiuser) {
unbindLocked();
bindBestPackageLocked(null);
bindBestPackageLocked(mServicePackageName);
}
}
}

View File

@@ -40,8 +40,10 @@ public class GeocoderProxy {
private final ServiceWatcher mServiceWatcher;
public static GeocoderProxy createAndBind(Context context,
List<String> initialPackageNames, Handler handler) {
GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames, handler);
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId, Handler handler) {
GeocoderProxy proxy = new GeocoderProxy(context, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId, handler);
if (proxy.bind()) {
return proxy;
} else {
@@ -49,11 +51,13 @@ public class GeocoderProxy {
}
}
public GeocoderProxy(Context context, List<String> initialPackageNames, Handler handler) {
private GeocoderProxy(Context context,
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId, Handler handler) {
mContext = context;
mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, initialPackageNames,
null, handler);
mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId, null, handler);
}
private boolean bind () {

View File

@@ -59,8 +59,10 @@ public final class GeofenceProxy {
};
public static GeofenceProxy createAndBind(Context context,
List<String> initialPackageNames, Handler handler, IGpsGeofenceHardware gpsGeofence) {
GeofenceProxy proxy = new GeofenceProxy(context, initialPackageNames, handler, gpsGeofence);
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) {
GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId, handler, gpsGeofence);
if (proxy.bindGeofenceProvider()) {
return proxy;
} else {
@@ -68,11 +70,12 @@ public final class GeofenceProxy {
}
}
private GeofenceProxy(Context context, List<String> initialPackageName, Handler handler,
IGpsGeofenceHardware gpsGeofence) {
private GeofenceProxy(Context context,
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId, Handler handler, IGpsGeofenceHardware gpsGeofence) {
mContext = context;
mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, initialPackageName,
mRunnable, handler);
mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId, mRunnable, handler);
mGpsGeofenceHardware = gpsGeofence;
bindHardwareGeofence();
}

View File

@@ -53,10 +53,13 @@ public class LocationProviderProxy implements LocationProviderInterface {
private ProviderRequest mRequest = null;
private WorkSource mWorksource = new WorkSource();
public static LocationProviderProxy createAndBind(Context context, String name, String action,
List<String> initialPackageNames, Handler handler) {
public static LocationProviderProxy createAndBind(
Context context, String name, String action,
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId, Handler handler) {
LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
initialPackageNames, handler);
overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId,
handler);
if (proxy.bind()) {
return proxy;
} else {
@@ -65,10 +68,12 @@ public class LocationProviderProxy implements LocationProviderInterface {
}
private LocationProviderProxy(Context context, String name, String action,
List<String> initialPackageNames, Handler handler) {
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId, Handler handler) {
mContext = context;
mName = name;
mServiceWatcher = new ServiceWatcher(mContext, TAG, action, initialPackageNames,
mServiceWatcher = new ServiceWatcher(mContext, TAG + "-" + name, action, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId,
mNewServiceWork, handler);
}