Refactor how location providers are managed

Put enabled/disabled state under location provider control, and use it
to represent whether a location provider may be used, not whether the
user has enabled or disabled a location provider.

Bug: 118885128
Test: manually
Change-Id: I1209c49c13ca8995b223f383ad332322fffc7a96
This commit is contained in:
Soonil Nagarkar
2018-10-24 17:54:54 -07:00
parent 4c47901848
commit 1575a04e7b
22 changed files with 1165 additions and 1302 deletions

View File

@@ -451,6 +451,7 @@ java_defaults {
"location/java/android/location/IGpsGeofenceHardware.aidl",
"location/java/android/location/INetInitiatedListener.aidl",
"location/java/com/android/internal/location/ILocationProvider.aidl",
"location/java/com/android/internal/location/ILocationProviderManager.aidl",
"media/java/android/media/IAudioFocusDispatcher.aidl",
"media/java/android/media/IAudioRoutesObserver.aidl",
"media/java/android/media/IAudioService.aidl",

View File

@@ -22732,8 +22732,8 @@ package android.location {
method public boolean addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler);
method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
method public void clearTestProviderEnabled(java.lang.String);
method public void clearTestProviderLocation(java.lang.String);
method public deprecated void clearTestProviderEnabled(java.lang.String);
method public deprecated void clearTestProviderLocation(java.lang.String);
method public deprecated void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);

View File

@@ -1849,13 +1849,16 @@ Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lco
Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
Lcom/android/internal/location/ILocationProvider;->disable()V
Lcom/android/internal/location/ILocationProvider;->enable()V
Lcom/android/internal/location/ILocationProvider;->getProperties()Lcom/android/internal/location/ProviderProperties;
Lcom/android/internal/location/ILocationProvider;->getStatus(Landroid/os/Bundle;)I
Lcom/android/internal/location/ILocationProvider;->getStatusUpdateTime()J
Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z
Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V
Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V
Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V
Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V
Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager;
Lcom/android/internal/location/ILocationProviderManager;->onReportLocation(Landroid/location/Location;)V
Lcom/android/internal/location/ILocationProviderManager;->onSetEnabled(Z)V
Lcom/android/internal/location/ILocationProviderManager;->onSetProperties(Lcom/android/internal/location/ProviderProperties;)V
Lcom/android/internal/logging/MetricsLogger;-><init>()V
Lcom/android/internal/net/LegacyVpnInfo;-><init>()V
Lcom/android/internal/net/VpnConfig;-><init>()V

View File

@@ -96,9 +96,7 @@ interface ILocationManager
void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
void removeTestProvider(String provider, String opPackageName);
void setTestProviderLocation(String provider, in Location loc, String opPackageName);
void clearTestProviderLocation(String provider, String opPackageName);
void setTestProviderEnabled(String provider, boolean enabled, String opPackageName);
void clearTestProviderEnabled(String provider, String opPackageName);
// --- deprecated ---
void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime,
@@ -108,12 +106,8 @@ interface ILocationManager
// --- internal ---
// Used by location providers to tell the location manager when it has a new location.
// Passive is true if the location is coming from the passive provider, in which case
// it need not be shared with other providers.
// --- deprecated ---
void reportLocation(in Location location, boolean passive);
// Used when a (initially Gnss) Location batch arrives
void reportLocationBatch(in List<Location> locations);
// for reporting callback completion

View File

@@ -1537,14 +1537,11 @@ public class LocationManager {
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
* @throws IllegalArgumentException if no provider with the given name exists
*
* @deprecated This function has always been a no-op, and may be removed in the future.
*/
public void clearTestProviderLocation(String provider) {
try {
mService.clearTestProviderLocation(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Deprecated
public void clearTestProviderLocation(String provider) {}
/**
* Sets a mock enabled value for the given provider. This value will be used in place
@@ -1575,13 +1572,12 @@ public class LocationManager {
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
* @throws IllegalArgumentException if no provider with the given name exists
*
* @deprecated Use {@link #setTestProviderEnabled(String, boolean)} instead.
*/
@Deprecated
public void clearTestProviderEnabled(String provider) {
try {
mService.clearTestProviderEnabled(provider, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
setTestProviderEnabled(provider, true);
}
/**

View File

@@ -16,29 +16,26 @@
package com.android.internal.location;
import android.location.Location;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderRequest;
/**
* Binder interface for services that implement location providers.
* <p>Use {@link LocationProviderBase} as a helper to implement this
* interface.
* Binder interface for services that implement location providers. Do not implement this directly,
* extend {@link LocationProviderBase} instead.
* @hide
*/
interface ILocationProvider {
void enable();
void disable();
void setRequest(in ProviderRequest request, in WorkSource ws);
oneway void setLocationProviderManager(in ILocationProviderManager manager);
// --- deprecated (but still supported) ---
ProviderProperties getProperties();
oneway void setRequest(in ProviderRequest request, in WorkSource ws);
oneway void sendExtraCommand(String command, in Bundle extras);
// --- deprecated and will be removed the future ---
int getStatus(out Bundle extras);
long getStatusUpdateTime();
boolean sendExtraCommand(String command, inout Bundle extras);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.location;
import android.location.Location;
import com.android.internal.location.ProviderProperties;
/**
* Binder interface for manager of all location providers.
* @hide
*/
interface ILocationProviderManager {
void onSetEnabled(boolean enabled);
void onSetProperties(in ProviderProperties properties);
void onReportLocation(in Location location);
}

View File

@@ -16,15 +16,15 @@
package com.android.internal.location;
import java.util.ArrayList;
import java.util.List;
import android.annotation.UnsupportedAppUsage;
import android.location.LocationRequest;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.TimeUtils;
import java.util.ArrayList;
import java.util.List;
/** @hide */
public final class ProviderRequest implements Parcelable {
/** Location reporting is requested (true) */
@@ -35,6 +35,13 @@ public final class ProviderRequest implements Parcelable {
@UnsupportedAppUsage
public long interval = Long.MAX_VALUE;
/**
* When this flag is true, providers should ignore all location settings, user consents, power
* restrictions or any other restricting factors and always satisfy this request to the best of
* their ability. This flag should only be used in event of an emergency.
*/
public boolean forceLocation = false;
/**
* Whether provider shall make stronger than normal tradeoffs to substantially restrict power
* use.

View File

@@ -8,14 +8,18 @@ package com.android.location.provider {
public abstract class LocationProviderBase {
ctor public LocationProviderBase(java.lang.String, com.android.location.provider.ProviderPropertiesUnbundled);
method public android.os.IBinder getBinder();
method public abstract void onDisable();
method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public abstract void onEnable();
method public deprecated int onGetStatus(android.os.Bundle);
method public deprecated long onGetStatusUpdateTime();
method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
method public final void reportLocation(android.location.Location);
method public boolean isEnabled();
method protected deprecated void onDisable();
method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method protected deprecated void onEnable();
method protected deprecated int onGetStatus(android.os.Bundle);
method protected deprecated long onGetStatusUpdateTime();
method protected void onInit();
method protected boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
method public void reportLocation(android.location.Location);
method public void setEnabled(boolean);
method public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled);
field public static final java.lang.String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
field public static final java.lang.String FUSED_PROVIDER = "fused";
}
@@ -38,6 +42,7 @@ package com.android.location.provider {
}
public final class ProviderRequestUnbundled {
method public boolean getForceLocation();
method public long getInterval();
method public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
method public boolean getReportLocation();

View File

@@ -16,6 +16,7 @@
package com.android.location.provider;
import android.annotation.Nullable;
import android.content.Context;
import android.location.ILocationManager;
import android.location.Location;
@@ -29,12 +30,11 @@ import android.os.WorkSource;
import android.util.Log;
import com.android.internal.location.ILocationProvider;
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.util.FastPrintWriter;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
@@ -55,12 +55,6 @@ import java.io.PrintWriter;
* of this package for more information.
*/
public abstract class LocationProviderBase {
private final String TAG;
/** @hide */
protected final ILocationManager mLocationManager;
private final ProviderProperties mProperties;
private final IBinder mBinder;
/**
* Bundle key for a version of the location containing no GPS data.
@@ -77,49 +71,34 @@ public abstract class LocationProviderBase {
*/
public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;
private final class Service extends ILocationProvider.Stub {
@Override
public void enable() {
onEnable();
}
@Override
public void disable() {
onDisable();
}
@Override
public void setRequest(ProviderRequest request, WorkSource ws) {
onSetRequest(new ProviderRequestUnbundled(request), ws);
}
@Override
public ProviderProperties getProperties() {
return mProperties;
}
@Override
public int getStatus(Bundle extras) {
return onGetStatus(extras);
}
@Override
public long getStatusUpdateTime() {
return onGetStatusUpdateTime();
}
@Override
public boolean sendExtraCommand(String command, Bundle extras) {
return onSendExtraCommand(command, extras);
}
@Override
public void dump(FileDescriptor fd, String[] args) {
PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
onDump(fd, pw, args);
pw.flush();
}
}
private final String mTag;
private final IBinder mBinder;
/**
* This field may be removed in the future, do not rely on it.
*
* @deprecated Do not use this field! Use LocationManager APIs instead. If you use this field
* you may be broken in the future.
* @hide
*/
@Deprecated
protected final ILocationManager mLocationManager;
// write locked on mBinder, read lock is optional depending on atomicity requirements
@Nullable private volatile ILocationProviderManager mManager;
private volatile ProviderProperties mProperties;
private volatile boolean mEnabled;
public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
TAG = tag;
IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
mLocationManager = ILocationManager.Stub.asInterface(b);
mProperties = properties.getProviderProperties();
mTag = tag;
mBinder = new Service();
mLocationManager = ILocationManager.Stub.asInterface(
ServiceManager.getService(Context.LOCATION_SERVICE));
mManager = null;
mProperties = properties.getProviderProperties();
mEnabled = true;
}
public IBinder getBinder() {
@@ -127,51 +106,116 @@ public abstract class LocationProviderBase {
}
/**
* Used by the location provider to report new locations.
* Sets whether this provider is currently enabled or not. Note that this is specific to the
* provider only, and is not related to global location settings. This is a hint to the Location
* Manager that this provider will generally be unable to fulfill incoming requests. This
* provider may still receive callbacks to onSetRequest while not enabled, and must decide
* whether to attempt to satisfy those requests or not.
*
* @param location new Location to report
*
* Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
* Some guidelines: providers should set their own enabled/disabled status based only on state
* "owned" by that provider. For instance, providers should not take into account the state of
* the location master setting when setting themselves enabled or disabled, as this state is not
* owned by a particular provider. If a provider requires some additional user consent that is
* particular to the provider, this should be use to set the enabled/disabled state. If the
* provider proxies to another provider, the child provider's enabled/disabled state should be
* taken into account in the parent's enabled/disabled state. For most providers, it is expected
* that they will be always enabled.
*/
public final void reportLocation(Location location) {
try {
mLocationManager.reportLocation(location, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException", e);
} catch (Exception e) {
// never crash provider, might be running in a system process
Log.e(TAG, "Exception", e);
public void setEnabled(boolean enabled) {
synchronized (mBinder) {
if (mEnabled == enabled) {
return;
}
mEnabled = enabled;
}
ILocationProviderManager manager = mManager;
if (manager != null) {
try {
manager.onSetEnabled(mEnabled);
} catch (RemoteException | RuntimeException e) {
Log.w(mTag, e);
}
}
}
/**
* Enable the location provider.
* <p>The provider may initialize resources, but does
* not yet need to report locations.
* Sets the provider properties that may be queried by clients. Generally speaking, providers
* should try to avoid changing their properties after construction.
*/
public abstract void onEnable();
public void setProperties(ProviderPropertiesUnbundled properties) {
synchronized (mBinder) {
mProperties = properties.getProviderProperties();
}
ILocationProviderManager manager = mManager;
if (manager != null) {
try {
manager.onSetProperties(mProperties);
} catch (RemoteException | RuntimeException e) {
Log.w(mTag, e);
}
}
}
/**
* Disable the location provider.
* <p>The provider must release resources, and stop
* performing work. It may no longer report locations.
* Returns true if this provider has been set as enabled. This will be true unless explicitly
* set otherwise.
*/
public abstract void onDisable();
public boolean isEnabled() {
return mEnabled;
}
/**
* Set the {@link ProviderRequest} requirements for this provider.
* <p>Each call to this method overrides all previous requests.
* <p>This method might trigger the provider to start returning
* locations, or to stop returning locations, depending on the
* parameters in the request.
* Reports a new location from this provider.
*/
public abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
public void reportLocation(Location location) {
ILocationProviderManager manager = mManager;
if (manager != null) {
try {
manager.onReportLocation(location);
} catch (RemoteException | RuntimeException e) {
Log.w(mTag, e);
}
}
}
protected void onInit() {
// call once so that providers designed for APIs pre-Q are not broken
onEnable();
}
/**
* @deprecated This callback will be invoked once when the provider is created to maintain
* backwards compatibility with providers not designed for Android Q and above. This method
* should only be implemented in location providers that need to support SDKs below Android Q.
* Even in this case, it is usually unnecessary to implement this callback with the correct
* design. This method may be removed in the future.
*/
@Deprecated
protected void onEnable() {}
/**
* @deprecated This callback will be never be invoked on Android Q and above. This method should
* only be implemented in location providers that need to support SDKs below Android Q. Even in
* this case, it is usually unnecessary to implement this callback with the correct design. This
* method may be removed in the future.
*/
@Deprecated
protected void onDisable() {}
/**
* Set the {@link ProviderRequest} requirements for this provider. Each call to this method
* overrides all previous requests. This method might trigger the provider to start returning
* locations, or to stop returning locations, depending on the parameters in the request.
*/
protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
/**
* Dump debug information.
*/
public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
}
protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {}
/**
* This method will no longer be invoked.
@@ -187,10 +231,12 @@ public abstract class LocationProviderBase {
* <p>If extras is non-null, additional status information may be
* added to it in the form of provider-specific key/value pairs.
*
* @deprecated This method will no longer be invoked.
* @deprecated This callback will be never be invoked on Android Q and above. This method should
* only be implemented in location providers that need to support SDKs below Android Q. This
* method may be removed in the future.
*/
@Deprecated
public int onGetStatus(Bundle extras) {
protected int onGetStatus(Bundle extras) {
return LocationProvider.AVAILABLE;
}
@@ -206,24 +252,64 @@ public abstract class LocationProviderBase {
*
* @return time of last status update in millis since last reboot
*
* @deprecated This method will no longer be invoked.
* @deprecated This callback will be never be invoked on Android Q and above. This method should
* only be implemented in location providers that need to support SDKs below Android Q. This
* method may be removed in the future.
*/
@Deprecated
public long onGetStatusUpdateTime() {
protected long onGetStatusUpdateTime() {
return 0;
}
/**
* Implements addditional location provider specific additional commands.
*
* @param command name of the command to send to the provider.
* @param extras optional arguments for the command (or null).
* The provider may optionally fill the extras Bundle with results from the command.
*
* @return true if the command succeeds.
* Implements location provider specific custom commands. The return value will be ignored on
* Android Q and above.
*/
public boolean onSendExtraCommand(String command, Bundle extras) {
// default implementation
protected boolean onSendExtraCommand(@Nullable String command, @Nullable Bundle extras) {
return false;
}
private final class Service extends ILocationProvider.Stub {
@Override
public void setLocationProviderManager(ILocationProviderManager manager) {
synchronized (mBinder) {
try {
manager.onSetProperties(mProperties);
manager.onSetEnabled(mEnabled);
} catch (RemoteException e) {
Log.w(mTag, e);
}
mManager = manager;
}
onInit();
}
@Override
public void setRequest(ProviderRequest request, WorkSource ws) {
onSetRequest(new ProviderRequestUnbundled(request), ws);
}
@Override
public int getStatus(Bundle extras) {
return onGetStatus(extras);
}
@Override
public long getStatusUpdateTime() {
return onGetStatusUpdateTime();
}
@Override
public void sendExtraCommand(String command, Bundle extras) {
onSendExtraCommand(command, extras);
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
onDump(fd, pw, args);
}
}
}

View File

@@ -16,13 +16,13 @@
package com.android.location.provider;
import java.util.ArrayList;
import java.util.List;
import android.location.LocationRequest;
import com.android.internal.location.ProviderRequest;
import java.util.ArrayList;
import java.util.List;
/**
* This class is an interface to Provider Requests for unbundled applications.
*
@@ -46,6 +46,10 @@ public final class ProviderRequestUnbundled {
return mRequest.interval;
}
public boolean getForceLocation() {
return mRequest.forceLocation;
}
/**
* Never null.
*/

View File

@@ -23,7 +23,6 @@ import android.content.IntentFilter;
import android.location.Criteria;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -34,87 +33,53 @@ import com.android.location.provider.ProviderRequestUnbundled;
import java.io.FileDescriptor;
import java.io.PrintWriter;
public class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
private static final String TAG = "FusedLocationProvider";
private static ProviderPropertiesUnbundled PROPERTIES = ProviderPropertiesUnbundled.create(
false, false, false, false, true, true, true, Criteria.POWER_LOW,
Criteria.ACCURACY_FINE);
private static final int MSG_ENABLE = 1;
private static final int MSG_DISABLE = 2;
private static final int MSG_SET_REQUEST = 3;
private final Context mContext;
private final Handler mHandler;
private final FusionEngine mEngine;
private static class RequestWrapper {
public ProviderRequestUnbundled request;
public WorkSource source;
public RequestWrapper(ProviderRequestUnbundled request, WorkSource source) {
this.request = request;
this.source = source;
}
}
public FusedLocationProvider(Context context) {
super(TAG, PROPERTIES);
mEngine = new FusionEngine(context, Looper.myLooper());
// listen for user change
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
context.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mEngine.switchUser();
}
}
}, UserHandle.ALL, intentFilter, null, mHandler);
}
/**
* For serializing requests to mEngine.
*/
private Handler mHandler = new Handler() {
private final BroadcastReceiver mUserSwitchReceiver = new BroadcastReceiver() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ENABLE:
mEngine.init(FusedLocationProvider.this);
break;
case MSG_DISABLE:
mEngine.deinit();
break;
case MSG_SET_REQUEST:
{
RequestWrapper wrapper = (RequestWrapper) msg.obj;
mEngine.setRequest(wrapper.request, wrapper.source);
break;
}
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mEngine.switchUser();
}
}
};
@Override
public void onEnable() {
mHandler.sendEmptyMessage(MSG_ENABLE);
FusedLocationProvider(Context context) {
super(TAG, PROPERTIES);
mContext = context;
mHandler = new Handler(Looper.myLooper());
mEngine = new FusionEngine(context, Looper.myLooper(), this);
}
@Override
public void onDisable() {
mHandler.sendEmptyMessage(MSG_DISABLE);
void init() {
// listen for user change
mContext.registerReceiverAsUser(mUserSwitchReceiver, UserHandle.ALL,
new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
}
void destroy() {
mContext.unregisterReceiver(mUserSwitchReceiver);
mHandler.post(() -> mEngine.setRequest(null));
}
@Override
public void onSetRequest(ProviderRequestUnbundled request, WorkSource source) {
mHandler.obtainMessage(MSG_SET_REQUEST, new RequestWrapper(request, source)).sendToTarget();
mHandler.post(() -> mEngine.setRequest(request));
}
@Override
public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
// perform synchronously
mEngine.dump(fd, pw, args);
}
}

View File

@@ -21,27 +21,24 @@ import android.content.Intent;
import android.os.IBinder;
public class FusedLocationService extends Service {
private FusedLocationProvider mProvider;
@Override
public IBinder onBind(Intent intent) {
if (mProvider == null) {
mProvider = new FusedLocationProvider(getApplicationContext());
mProvider = new FusedLocationProvider(this);
mProvider.init();
}
return mProvider.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
// make sure to stop performing work
if (mProvider != null) {
mProvider.onDisable();
}
return false;
}
@Override
public void onDestroy() {
mProvider = null;
if (mProvider != null) {
mProvider.destroy();
mProvider = null;
}
}
}

View File

@@ -16,14 +16,6 @@
package com.android.location.fused;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
import com.android.location.provider.LocationProviderBase;
import com.android.location.provider.LocationRequestUnbundled;
import com.android.location.provider.ProviderRequestUnbundled;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
@@ -32,9 +24,16 @@ import android.os.Bundle;
import android.os.Looper;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.WorkSource;
import android.util.Log;
import com.android.location.provider.LocationProviderBase;
import com.android.location.provider.LocationRequestUnbundled;
import com.android.location.provider.ProviderRequestUnbundled;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
public class FusionEngine implements LocationListener {
public interface Callback {
void reportLocation(Location location);
@@ -47,72 +46,35 @@ public class FusionEngine implements LocationListener {
public static final long SWITCH_ON_FRESHNESS_CLIFF_NS = 11 * 1000000000L; // 11 seconds
private final Context mContext;
private final LocationManager mLocationManager;
private final Looper mLooper;
private final Callback mCallback;
// all fields are only used on mLooper thread. except for in dump() which is not thread-safe
private Callback mCallback;
private Location mFusedLocation;
private Location mGpsLocation;
private Location mNetworkLocation;
private boolean mEnabled;
private ProviderRequestUnbundled mRequest;
private final HashMap<String, ProviderStats> mStats = new HashMap<>();
public FusionEngine(Context context, Looper looper) {
mContext = context;
FusionEngine(Context context, Looper looper, Callback callback) {
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
mNetworkLocation = new Location("");
mNetworkLocation.setAccuracy(Float.MAX_VALUE);
mGpsLocation = new Location("");
mGpsLocation.setAccuracy(Float.MAX_VALUE);
mLooper = looper;
mCallback = callback;
mStats.put(GPS, new ProviderStats());
mStats.put(NETWORK, new ProviderStats());
}
public void init(Callback callback) {
Log.i(TAG, "engine started (" + mContext.getPackageName() + ")");
mCallback = callback;
}
/**
* Called to stop doing any work, and release all resources
* This can happen when a better fusion engine is installed
* in a different package, and this one is no longer needed.
* Called on mLooper thread
*/
public void deinit() {
mRequest = null;
disable();
Log.i(TAG, "engine stopped (" + mContext.getPackageName() + ")");
}
/** Called on mLooper thread */
public void enable() {
if (!mEnabled) {
mEnabled = true;
updateRequirements();
}
}
/** Called on mLooper thread */
public void disable() {
if (mEnabled) {
mEnabled = false;
updateRequirements();
}
}
/** Called on mLooper thread */
public void setRequest(ProviderRequestUnbundled request, WorkSource source) {
public void setRequest(ProviderRequestUnbundled request) {
mRequest = request;
mEnabled = request.getReportLocation();
updateRequirements();
}
@@ -120,6 +82,7 @@ public class FusionEngine implements LocationListener {
public boolean requested;
public long requestTime;
public long minTime;
@Override
public String toString() {
return (requested ? " REQUESTED" : " ---");
@@ -154,7 +117,7 @@ public class FusionEngine implements LocationListener {
}
private void updateRequirements() {
if (!mEnabled || mRequest == null) {
if (mRequest == null || !mRequest.getReportLocation()) {
mRequest = null;
disableProvider(NETWORK);
disableProvider(GPS);
@@ -200,29 +163,30 @@ public class FusionEngine implements LocationListener {
* Test whether one location (a) is better to use than another (b).
*/
private static boolean isBetterThan(Location locationA, Location locationB) {
if (locationA == null) {
return false;
}
if (locationB == null) {
return true;
}
// A provider is better if the reading is sufficiently newer. Heading
// underground can cause GPS to stop reporting fixes. In this case it's
// appropriate to revert to cell, even when its accuracy is less.
if (locationA.getElapsedRealtimeNanos() > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
return true;
}
if (locationA == null) {
return false;
}
if (locationB == null) {
return true;
}
// A provider is better if the reading is sufficiently newer. Heading
// underground can cause GPS to stop reporting fixes. In this case it's
// appropriate to revert to cell, even when its accuracy is less.
if (locationA.getElapsedRealtimeNanos()
> locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
return true;
}
// A provider is better if it has better accuracy. Assuming both readings
// are fresh (and by that accurate), choose the one with the smaller
// accuracy circle.
if (!locationA.hasAccuracy()) {
return false;
}
if (!locationB.hasAccuracy()) {
return true;
}
return locationA.getAccuracy() < locationB.getAccuracy();
// A provider is better if it has better accuracy. Assuming both readings
// are fresh (and by that accurate), choose the one with the smaller
// accuracy circle.
if (!locationA.hasAccuracy()) {
return false;
}
if (!locationB.hasAccuracy()) {
return true;
}
return locationA.getAccuracy() < locationB.getAccuracy();
}
private void updateFusedLocation() {
@@ -252,9 +216,9 @@ public class FusionEngine implements LocationListener {
}
if (mCallback != null) {
mCallback.reportLocation(mFusedLocation);
mCallback.reportLocation(mFusedLocation);
} else {
Log.w(TAG, "Location updates received while fusion engine not started");
Log.w(TAG, "Location updates received while fusion engine not started");
}
}
@@ -272,19 +236,22 @@ public class FusionEngine implements LocationListener {
/** Called on mLooper thread */
@Override
public void onStatusChanged(String provider, int status, Bundle extras) { }
public void onStatusChanged(String provider, int status, Bundle extras) {
}
/** Called on mLooper thread */
@Override
public void onProviderEnabled(String provider) { }
public void onProviderEnabled(String provider) {
}
/** Called on mLooper thread */
@Override
public void onProviderDisabled(String provider) { }
public void onProviderDisabled(String provider) {
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
s.append("mEnabled=").append(mEnabled).append(' ').append(mRequest).append('\n');
s.append(mRequest).append('\n');
s.append("fused=").append(mFusedLocation).append('\n');
s.append(String.format("gps %s\n", mGpsLocation));
s.append(" ").append(mStats.get(GPS)).append('\n');

View File

@@ -16,9 +16,7 @@
package com.android.server;
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -168,13 +166,13 @@ public class ServiceWatcher implements ServiceConnection {
// called on handler thread
@GuardedBy("mBindLock")
protected void onBind() {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
}
// called on handler thread
@GuardedBy("mBindLock")
protected void onUnbind() {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
}
/**
@@ -205,12 +203,12 @@ public class ServiceWatcher implements ServiceConnection {
@Override
public void onPackageRemoved(String packageName, int uid) {
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
}
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
return super.onPackageChanged(packageName, uid, components);
}
}.register(mContext, UserHandle.ALL, true, mHandler);
@@ -243,20 +241,16 @@ public class ServiceWatcher implements ServiceConnection {
return true;
}
/** Returns thje name of the currently connected package or null. */
/** Returns the name of the currently connected package or null. */
@Nullable
public String getCurrentPackageName() {
ComponentName bestComponent = mBestComponent;
return bestComponent == null ? null : bestComponent.getPackageName();
}
public int getCurrentPackageVersion() {
return mBestVersion;
}
/**
* Runs the given BinderRunner if currently connected. Returns true if it was run, and false
* otherwise. All invocations to runOnBinder are run serially.
* Runs the given BinderRunner if currently connected. All invocations to runOnBinder are run
* serially.
*/
public final void runOnBinder(BinderRunner runner) {
synchronized (mBindLock) {
@@ -267,7 +261,7 @@ public class ServiceWatcher implements ServiceConnection {
} catch (Exception e) {
// remote exceptions cannot be allowed to crash system server
Log.e(TAG, "exception while while running " + runner + " on " + service
+ " from " + mBestComponent.toShortString(), e);
+ " from " + this, e);
}
}
}
@@ -280,14 +274,6 @@ public class ServiceWatcher implements ServiceConnection {
UserHandle.USER_SYSTEM).isEmpty();
}
/**
* Searches and binds to the best package, or do nothing if the best package
* is already bound, unless force rebinding is requested.
*
* @param forceRebind Force a rebinding to the best package if it's already
* bound.
*/
@WorkerThread
private void bindBestPackage(boolean forceRebind) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
@@ -365,7 +351,6 @@ public class ServiceWatcher implements ServiceConnection {
}
}
@WorkerThread
private void bind(ComponentName component, int version, int userId) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
@@ -382,7 +367,6 @@ public class ServiceWatcher implements ServiceConnection {
UserHandle.of(userId));
}
@WorkerThread
private void unbind() {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
@@ -396,7 +380,6 @@ public class ServiceWatcher implements ServiceConnection {
mBestUserId = UserHandle.USER_NULL;
}
@MainThread
@Override
public final void onServiceConnected(ComponentName component, IBinder binder) {
mHandler.post(() -> {
@@ -410,7 +393,6 @@ public class ServiceWatcher implements ServiceConnection {
});
}
@MainThread
@Override
public final void onServiceDisconnected(ComponentName component) {
mHandler.post(() -> {

View File

@@ -0,0 +1,149 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.location;
import android.location.Location;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
/**
* Location Manager's interface for location providers.
*
* @hide
*/
public abstract class AbstractLocationProvider {
/**
* Interface for communicating from a location provider back to the location service.
*/
public interface LocationProviderManager {
/**
* Called on location provider construction to make the location service aware of this
* provider and what it's initial enabled/disabled state should be.
*/
void onAttachProvider(AbstractLocationProvider locationProvider, boolean initiallyEnabled);
/**
* May be called to inform the location service of a change in this location provider's
* enabled/disabled state.
*/
void onSetEnabled(boolean enabled);
/**
* May be called to inform the location service of a change in this location provider's
* properties.
*/
void onSetProperties(ProviderProperties properties);
/**
* May be called to inform the location service that this provider has a new location
* available.
*/
void onReportLocation(Location location);
/**
* May be called to inform the location service that this provider has a new location
* available.
*/
void onReportLocation(List<Location> locations);
}
private final LocationProviderManager mLocationProviderManager;
protected AbstractLocationProvider(LocationProviderManager locationProviderManager) {
this(locationProviderManager, true);
}
protected AbstractLocationProvider(LocationProviderManager locationProviderManager,
boolean initiallyEnabled) {
mLocationProviderManager = locationProviderManager;
mLocationProviderManager.onAttachProvider(this, initiallyEnabled);
}
/**
* Call this method to report a new location. May be called from any thread.
*/
protected void reportLocation(Location location) {
mLocationProviderManager.onReportLocation(location);
}
/**
* Call this method to report a new location. May be called from any thread.
*/
protected void reportLocation(List<Location> locations) {
mLocationProviderManager.onReportLocation(locations);
}
/**
* Call this method to report a change in provider enabled/disabled status. May be called from
* any thread.
*/
protected void setEnabled(boolean enabled) {
mLocationProviderManager.onSetEnabled(enabled);
}
/**
* Call this method to report a change in provider properties. May be called from
* any thread.
*/
protected void setProperties(ProviderProperties properties) {
mLocationProviderManager.onSetProperties(properties);
}
/**
* Called when the location service delivers a new request for fulfillment to the provider.
* Replaces any previous requests completely.
*/
public abstract void setRequest(ProviderRequest request, WorkSource source);
/**
* Called to dump debug or log information.
*/
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
/**
* Retrieves the current status of the provider.
*
* @deprecated Will be removed in a future release.
*/
@Deprecated
public int getStatus(Bundle extras) {
return LocationProvider.AVAILABLE;
}
/**
* Retrieves the last update time of the status of the provider.
*
* @deprecated Will be removed in a future release.
*/
@Deprecated
public long getStatusUpdateTime() {
return 0;
}
/** Sends a custom command to this provider. */
public abstract void sendExtraCommand(String command, Bundle extras);
}

View File

@@ -34,7 +34,6 @@ import android.location.GnssStatus;
import android.location.IGnssStatusListener;
import android.location.IGnssStatusProvider;
import android.location.IGpsGeofenceHardware;
import android.location.ILocationManager;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationListener;
@@ -84,6 +83,10 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -97,8 +100,18 @@ import java.util.Properties;
*
* {@hide}
*/
public class GnssLocationProvider extends LocationProviderInterface
implements InjectNtpTimeCallback, GnssSatelliteBlacklistCallback {
public class GnssLocationProvider extends AbstractLocationProvider implements
InjectNtpTimeCallback,
GnssSatelliteBlacklistCallback {
/**
* Indicates that this method is a native entry point. Useful purely for IDEs which can
* understand entry points, and thus eliminate incorrect warnings about methods not used.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
private @interface NativeEntryPoint {
}
private static final String TAG = "GnssLocationProvider";
@@ -249,7 +262,7 @@ public class GnssLocationProvider extends LocationProviderInterface
}
public void set(int svCount, int meanCn0, int maxCn0) {
synchronized(this) {
synchronized (this) {
mSvCount = svCount;
mMeanCn0 = meanCn0;
mMaxCn0 = maxCn0;
@@ -258,7 +271,7 @@ public class GnssLocationProvider extends LocationProviderInterface
}
public void reset() {
set(0,0,0);
set(0, 0, 0);
}
// Also used by outside methods to add to other bundles
@@ -314,7 +327,7 @@ public class GnssLocationProvider extends LocationProviderInterface
MAX_RETRY_INTERVAL);
// true if we are enabled, protected by this
private boolean mEnabled;
private boolean mEnabled = true;
// states for injecting ntp and downloading xtra data
private static final int STATE_PENDING_NETWORK = 0;
@@ -328,9 +341,6 @@ public class GnssLocationProvider extends LocationProviderInterface
// true if GPS is navigating
private boolean mNavigating;
// true if GPS engine is on
private boolean mEngineOn;
// requested frequency of fixes, in milliseconds
private int mFixInterval = 1000;
@@ -380,7 +390,6 @@ public class GnssLocationProvider extends LocationProviderInterface
private boolean mSuplEsEnabled = false;
private final Context mContext;
private final ILocationManager mILocationManager;
private final LocationExtras mLocationExtras = new LocationExtras();
private final GnssStatusListenerHelper mListenerHelper;
private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
@@ -479,17 +488,22 @@ public class GnssLocationProvider extends LocationProviderInterface
return;
}
if (action.equals(ALARM_WAKEUP)) {
startNavigating(false);
} else if (action.equals(ALARM_TIMEOUT)) {
hibernate();
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
|| PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_SCREEN_ON.equals(action)) {
updateLowPowerMode();
} else if (action.equals(SIM_STATE_CHANGED)) {
subscriptionOrSimChanged(context);
switch (action) {
case ALARM_WAKEUP:
startNavigating(false);
break;
case ALARM_TIMEOUT:
hibernate();
break;
case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
case Intent.ACTION_SCREEN_OFF:
case Intent.ACTION_SCREEN_ON:
updateLowPowerMode();
break;
case SIM_STATE_CHANGED:
subscriptionOrSimChanged(context);
break;
}
}
};
@@ -507,9 +521,7 @@ public class GnssLocationProvider extends LocationProviderInterface
*/
@Override
public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
mHandler.post(()->{
native_set_satellite_blacklist(constellations, svids);
});
mHandler.post(() -> native_set_satellite_blacklist(constellations, svids));
}
private void subscriptionOrSimChanged(Context context) {
@@ -572,7 +584,7 @@ public class GnssLocationProvider extends LocationProviderInterface
}
interface SetCarrierProperty {
public boolean set(int value);
boolean set(int value);
}
private void reloadGpsProperties(Context context, Properties properties) {
@@ -587,7 +599,7 @@ public class GnssLocationProvider extends LocationProviderInterface
/*
* Overlay carrier properties from a debug configuration file.
*/
loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
loadPropertiesFromFile(properties);
// TODO: we should get rid of C2K specific setting.
setSuplHostPort(properties.getProperty("SUPL_HOST"),
properties.getProperty("SUPL_PORT"));
@@ -603,15 +615,15 @@ public class GnssLocationProvider extends LocationProviderInterface
if (native_is_gnss_configuration_supported()) {
Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
{
put("SUPL_VER", (val) -> native_set_supl_version(val));
put("SUPL_MODE", (val) -> native_set_supl_mode(val));
put("SUPL_ES", (val) -> native_set_supl_es(val));
put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
put("SUPL_VER", GnssLocationProvider::native_set_supl_version);
put("SUPL_MODE", GnssLocationProvider::native_set_supl_mode);
put("SUPL_ES", GnssLocationProvider::native_set_supl_es);
put("LPP_PROFILE", GnssLocationProvider::native_set_lpp_profile);
put("A_GLONASS_POS_PROTOCOL_SELECT",
(val) -> native_set_gnss_pos_protocol_select(val));
GnssLocationProvider::native_set_gnss_pos_protocol_select);
put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
(val) -> native_set_emergency_supl_pdn(val));
put("GPS_LOCK", (val) -> native_set_gps_lock(val));
GnssLocationProvider::native_set_emergency_supl_pdn);
put("GPS_LOCK", GnssLocationProvider::native_set_gps_lock);
}
};
@@ -622,7 +634,7 @@ public class GnssLocationProvider extends LocationProviderInterface
try {
int propertyValueInt = Integer.decode(propertyValueString);
boolean result = entry.getValue().set(propertyValueInt);
if (result == false) {
if (!result) {
Log.e(TAG, "Unable to set " + propertyName);
}
} catch (NumberFormatException e) {
@@ -664,10 +676,9 @@ public class GnssLocationProvider extends LocationProviderInterface
}
}
private boolean loadPropertiesFromFile(String filename,
Properties properties) {
private void loadPropertiesFromFile(Properties properties) {
try {
File file = new File(filename);
File file = new File(DEBUG_PROPERTIES_FILE);
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
@@ -677,16 +688,15 @@ public class GnssLocationProvider extends LocationProviderInterface
}
} catch (IOException e) {
if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename);
return false;
if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
}
return true;
}
public GnssLocationProvider(Context context, ILocationManager ilocationManager,
public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
Looper looper) {
super(locationProviderManager, true);
mContext = context;
mILocationManager = ilocationManager;
// Create a wake lock
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -763,19 +773,20 @@ public class GnssLocationProvider extends LocationProviderInterface
mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
mGnssBatchingProvider = new GnssBatchingProvider();
mGnssGeofenceProvider = new GnssGeofenceProvider();
}
/**
* Returns the name of this provider.
*/
@Override
public String getName() {
return LocationManager.GPS_PROVIDER;
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SHUTDOWN);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (getSendingUserId() == UserHandle.USER_ALL) {
mEnabled = false;
handleDisable();
}
}
}, UserHandle.ALL, intentFilter, null, mHandler);
@Override
public ProviderProperties getProperties() {
return PROPERTIES;
setProperties(PROPERTIES);
}
/**
@@ -840,9 +851,9 @@ public class GnssLocationProvider extends LocationProviderInterface
locationManager.requestLocationUpdates(provider,
LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
locationListener, mHandler.getLooper());
locationListener.numLocationUpdateRequest++;
locationListener.mNumLocationUpdateRequest++;
mHandler.postDelayed(() -> {
if (--locationListener.numLocationUpdateRequest == 0) {
if (--locationListener.mNumLocationUpdateRequest == 0) {
Log.i(TAG,
String.format("Removing location updates from %s provider.", provider));
locationManager.removeUpdates(locationListener);
@@ -905,43 +916,40 @@ public class GnssLocationProvider extends LocationProviderInterface
// hold wake lock while task runs
mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
byte[] data = xtraDownloader.downloadXtraData();
if (data != null) {
if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
native_inject_xtra_data(data, data.length);
mXtraBackOff.reset();
}
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
byte[] data = xtraDownloader.downloadXtraData();
if (data != null) {
if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
native_inject_xtra_data(data, data.length);
mXtraBackOff.reset();
}
sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
if (data == null) {
// try again later
// since this is delayed and not urgent we do not hold a wake lock here
mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
mXtraBackOff.nextBackoffMillis());
}
if (data == null) {
// try again later
// since this is delayed and not urgent we do not hold a wake lock here
mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
mXtraBackOff.nextBackoffMillis());
}
// Release wake lock held by task, synchronize on mLock in case multiple
// download tasks overrun.
synchronized (mLock) {
if (mDownloadXtraWakeLock.isHeld()) {
// This wakelock may have time-out, if a timeout was specified.
// Catch (and ignore) any timeout exceptions.
try {
mDownloadXtraWakeLock.release();
if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
} catch (Exception e) {
Log.i(TAG, "Wakelock timeout & release race exception in "
+ "handleDownloadXtraData()", e);
}
} else {
Log.e(TAG, "WakeLock expired before release in "
+ "handleDownloadXtraData()");
// Release wake lock held by task, synchronize on mLock in case multiple
// download tasks overrun.
synchronized (mLock) {
if (mDownloadXtraWakeLock.isHeld()) {
// This wakelock may have time-out, if a timeout was specified.
// Catch (and ignore) any timeout exceptions.
try {
mDownloadXtraWakeLock.release();
if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
} catch (Exception e) {
Log.i(TAG, "Wakelock timeout & release race exception in "
+ "handleDownloadXtraData()", e);
}
} else {
Log.e(TAG, "WakeLock expired before release in "
+ "handleDownloadXtraData()");
}
}
});
@@ -954,21 +962,6 @@ public class GnssLocationProvider extends LocationProviderInterface
}
}
/**
* Enables this provider. When enabled, calls to getStatus()
* must be handled. Hardware may be started up
* when the provider is enabled.
*/
@Override
public void enable() {
synchronized (mLock) {
if (mEnabled) return;
mEnabled = true;
}
sendMessage(ENABLE, 1, null);
}
private void setSuplHostPort(String hostString, String portString) {
if (hostString != null) {
mSuplServerHost = hostString;
@@ -1052,21 +1045,6 @@ public class GnssLocationProvider extends LocationProviderInterface
}
}
/**
* Disables this provider. When disabled, calls to getStatus()
* need not be handled. Hardware may be shut
* down while the provider is disabled.
*/
@Override
public void disable() {
synchronized (mLock) {
if (!mEnabled) return;
mEnabled = false;
}
sendMessage(ENABLE, 0, null);
}
private void handleDisable() {
if (DEBUG) Log.d(TAG, "handleDisable");
@@ -1083,7 +1061,6 @@ public class GnssLocationProvider extends LocationProviderInterface
mGnssNavigationMessageProvider.onGpsEnabledChanged();
}
@Override
public boolean isEnabled() {
synchronized (mLock) {
return mEnabled;
@@ -1147,7 +1124,7 @@ public class GnssLocationProvider extends LocationProviderInterface
updateClientUids(mWorkSource);
mFixInterval = (int) mProviderRequest.interval;
mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
mLowPowerMode = mProviderRequest.lowPowerMode;
// check for overflow
if (mFixInterval != mProviderRequest.interval) {
Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
@@ -1171,7 +1148,8 @@ public class GnssLocationProvider extends LocationProviderInterface
// set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
// and our fix interval is not short
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); }
SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
}
}
} else {
updateClientUids(new WorkSource());
@@ -1220,16 +1198,14 @@ public class GnssLocationProvider extends LocationProviderInterface
List<WorkChain> goneChains = diffs[1];
if (newChains != null) {
for (int i = 0; i < newChains.size(); ++i) {
final WorkChain newChain = newChains.get(i);
for (WorkChain newChain : newChains) {
mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(),
newChain.getAttributionTag());
}
}
if (goneChains != null) {
for (int i = 0; i < goneChains.size(); i++) {
final WorkChain goneChain = goneChains.get(i);
for (WorkChain goneChain : goneChains) {
mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
goneChain.getAttributionTag());
}
@@ -1262,32 +1238,27 @@ public class GnssLocationProvider extends LocationProviderInterface
}
@Override
public boolean sendExtraCommand(String command, Bundle extras) {
public void sendExtraCommand(String command, Bundle extras) {
long identity = Binder.clearCallingIdentity();
try {
boolean result = false;
if ("delete_aiding_data".equals(command)) {
result = deleteAidingData(extras);
deleteAidingData(extras);
} else if ("force_time_injection".equals(command)) {
requestUtcTime();
result = true;
} else if ("force_xtra_injection".equals(command)) {
if (mSupportsXtra) {
xtraDownloadRequest();
result = true;
}
} else {
Log.w(TAG, "sendExtraCommand: unknown command " + command);
}
return result;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
private boolean deleteAidingData(Bundle extras) {
private void deleteAidingData(Bundle extras) {
int flags;
if (extras == null) {
@@ -1311,10 +1282,7 @@ public class GnssLocationProvider extends LocationProviderInterface
if (flags != 0) {
native_delete_aiding_data(flags);
return true;
}
return false;
}
private void startNavigating(boolean singleShot) {
@@ -1358,7 +1326,7 @@ public class GnssLocationProvider extends LocationProviderInterface
}
int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
mLowPowerMode = mProviderRequest.lowPowerMode;
if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
interval, 0, 0, mLowPowerMode)) {
mStarted = false;
@@ -1415,10 +1383,7 @@ public class GnssLocationProvider extends LocationProviderInterface
return ((mEngineCapabilities & capability) != 0);
}
/**
* called from native code to update our position.
*/
@NativeEntryPoint
private void reportLocation(boolean hasLatLong, Location location) {
sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
}
@@ -1444,11 +1409,7 @@ public class GnssLocationProvider extends LocationProviderInterface
location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
location.setExtras(mLocationExtras.getBundle());
try {
mILocationManager.reportLocation(location, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocation");
}
reportLocation(location);
if (mStarted) {
mGnssMetrics.logReceivedLocationStatus(hasLatLong);
@@ -1482,7 +1443,8 @@ public class GnssLocationProvider extends LocationProviderInterface
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
// For devices that use framework scheduling, a timer may be set to ensure we don't
// spend too much power searching for a location, when the requested update rate is slow.
// spend too much power searching for a location, when the requested update rate is
// slow.
// As we just recievied a location, we'll cancel that timer.
if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
mAlarmManager.cancel(mTimeoutIntent);
@@ -1502,9 +1464,7 @@ public class GnssLocationProvider extends LocationProviderInterface
}
}
/**
* called from native code to update our status
*/
@NativeEntryPoint
private void reportStatus(int status) {
if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
@@ -1512,16 +1472,13 @@ public class GnssLocationProvider extends LocationProviderInterface
switch (status) {
case GPS_STATUS_SESSION_BEGIN:
mNavigating = true;
mEngineOn = true;
break;
case GPS_STATUS_SESSION_END:
mNavigating = false;
break;
case GPS_STATUS_ENGINE_ON:
mEngineOn = true;
break;
case GPS_STATUS_ENGINE_OFF:
mEngineOn = false;
mNavigating = false;
break;
}
@@ -1538,17 +1495,15 @@ public class GnssLocationProvider extends LocationProviderInterface
// Helper class to carry data to handler for reportSvStatus
private static class SvStatusInfo {
public int mSvCount;
public int[] mSvidWithFlags;
public float[] mCn0s;
public float[] mSvElevations;
public float[] mSvAzimuths;
public float[] mSvCarrierFreqs;
private int mSvCount;
private int[] mSvidWithFlags;
private float[] mCn0s;
private float[] mSvElevations;
private float[] mSvAzimuths;
private float[] mSvCarrierFreqs;
}
/**
* called from native code to update SV info
*/
@NativeEntryPoint
private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
SvStatusInfo svStatusInfo = new SvStatusInfo();
@@ -1622,16 +1577,12 @@ public class GnssLocationProvider extends LocationProviderInterface
}
}
/**
* called from native code to update AGPS status
*/
@NativeEntryPoint
private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
mNetworkConnectivityHandler.onReportAGpsStatus(type, status, ipaddr);
}
/**
* called from native code to report NMEA data received
*/
@NativeEntryPoint
private void reportNmea(long timestamp) {
if (!mItarSpeedLimitExceeded) {
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
@@ -1640,57 +1591,38 @@ public class GnssLocationProvider extends LocationProviderInterface
}
}
/**
* called from native code - GNSS measurements callback
*/
@NativeEntryPoint
private void reportMeasurementData(GnssMeasurementsEvent event) {
if (!mItarSpeedLimitExceeded) {
// send to handler to allow native to return quickly
mHandler.post(new Runnable() {
@Override
public void run() {
mGnssMeasurementsProvider.onMeasurementsAvailable(event);
}
});
mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event));
}
}
/**
* called from native code - GNSS navigation message callback
*/
@NativeEntryPoint
private void reportNavigationMessage(GnssNavigationMessage event) {
if (!mItarSpeedLimitExceeded) {
// send to handler to allow native to return quickly
mHandler.post(new Runnable() {
@Override
public void run() {
mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
}
});
mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event));
}
}
/**
* called from native code to inform us what the GPS engine capabilities are
*/
@NativeEntryPoint
private void setEngineCapabilities(final int capabilities) {
// send to handler thread for fast native return, and in-order handling
mHandler.post(new Runnable() {
@Override
public void run() {
mEngineCapabilities = capabilities;
mHandler.post(() -> {
mEngineCapabilities = capabilities;
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
mNtpTimeHelper.enablePeriodicTimeInjection();
requestUtcTime();
}
mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability(
GPS_CAPABILITY_MEASUREMENTS));
mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
GPS_CAPABILITY_NAV_MESSAGES));
restartRequests();
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
mNtpTimeHelper.enablePeriodicTimeInjection();
requestUtcTime();
}
mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability(
GPS_CAPABILITY_MEASUREMENTS));
mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
GPS_CAPABILITY_NAV_MESSAGES));
restartRequests();
});
}
@@ -1710,27 +1642,21 @@ public class GnssLocationProvider extends LocationProviderInterface
updateRequirements();
}
/**
* Called from native code to inform us the hardware year.
*/
@NativeEntryPoint
private void setGnssYearOfHardware(final int yearOfHardware) {
// mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync
if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
mHardwareYear = yearOfHardware;
}
/**
* Called from native code to inform us the hardware model name.
*/
@NativeEntryPoint
private void setGnssHardwareModelName(final String modelName) {
// mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync
if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName);
mHardwareModelName = modelName;
}
/**
* Called from native code to inform us GNSS HAL service died.
*/
@NativeEntryPoint
private void reportGnssServiceDied() {
if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
mHandler.post(() -> {
@@ -1750,6 +1676,7 @@ public class GnssLocationProvider extends LocationProviderInterface
* Returns the year of underlying GPS hardware.
*/
int getGnssYearOfHardware();
/**
* Returns the model name of underlying GPS hardware.
*/
@@ -1765,6 +1692,7 @@ public class GnssLocationProvider extends LocationProviderInterface
public int getGnssYearOfHardware() {
return mHardwareYear;
}
@Override
public String getGnssHardwareModelName() {
return mHardwareModelName;
@@ -1790,32 +1718,19 @@ public class GnssLocationProvider extends LocationProviderInterface
* @hide
*/
public GnssMetricsProvider getGnssMetricsProvider() {
return new GnssMetricsProvider() {
@Override
public String getGnssMetricsAsProtoString() {
return mGnssMetrics.dumpGnssMetricsAsProtoString();
}
};
return () -> mGnssMetrics.dumpGnssMetricsAsProtoString();
}
/**
* called from native code - GNSS location batch callback
*/
@NativeEntryPoint
private void reportLocationBatch(Location[] locationArray) {
List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
if (DEBUG) {
Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
}
try {
mILocationManager.reportLocationBatch(locations);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocationBatch");
}
reportLocation(locations);
}
/**
* called from native code to request XTRA data
*/
@NativeEntryPoint
private void xtraDownloadRequest() {
if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
@@ -1843,10 +1758,7 @@ public class GnssLocationProvider extends LocationProviderInterface
}
}
/**
* Called from native to report GPS Geofence transition
* All geofence callbacks are called on the same thread
*/
@NativeEntryPoint
private void reportGeofenceTransition(int geofenceId, Location location, int transition,
long transitionTimestamp) {
mHandler.post(() -> {
@@ -1864,9 +1776,7 @@ public class GnssLocationProvider extends LocationProviderInterface
});
}
/**
* called from native code to report GPS status change.
*/
@NativeEntryPoint
private void reportGeofenceStatus(int status, Location location) {
mHandler.post(() -> {
if (mGeofenceHardwareImpl == null) {
@@ -1884,9 +1794,7 @@ public class GnssLocationProvider extends LocationProviderInterface
});
}
/**
* called from native code - Geofence Add callback
*/
@NativeEntryPoint
private void reportGeofenceAddStatus(int geofenceId, int status) {
mHandler.post(() -> {
if (mGeofenceHardwareImpl == null) {
@@ -1896,9 +1804,7 @@ public class GnssLocationProvider extends LocationProviderInterface
});
}
/**
* called from native code - Geofence Remove callback
*/
@NativeEntryPoint
private void reportGeofenceRemoveStatus(int geofenceId, int status) {
mHandler.post(() -> {
if (mGeofenceHardwareImpl == null) {
@@ -1908,9 +1814,7 @@ public class GnssLocationProvider extends LocationProviderInterface
});
}
/**
* called from native code - Geofence Pause callback
*/
@NativeEntryPoint
private void reportGeofencePauseStatus(int geofenceId, int status) {
mHandler.post(() -> {
if (mGeofenceHardwareImpl == null) {
@@ -1920,9 +1824,7 @@ public class GnssLocationProvider extends LocationProviderInterface
});
}
/**
* called from native code - Geofence Resume callback
*/
@NativeEntryPoint
private void reportGeofenceResumeStatus(int geofenceId, int status) {
mHandler.post(() -> {
if (mGeofenceHardwareImpl == null) {
@@ -1954,7 +1856,8 @@ public class GnssLocationProvider extends LocationProviderInterface
return mNetInitiatedListener;
}
// Called by JNI function to report an NI request.
/** Reports a NI notification. */
@NativeEntryPoint
public void reportNiNotification(
int notificationId,
int niType,
@@ -1997,11 +1900,10 @@ public class GnssLocationProvider extends LocationProviderInterface
}
/**
* Called from native code to request set id info.
* We should be careful about receiving null string from the TelephonyManager,
* because sending null String to JNI function would cause a crash.
*/
@NativeEntryPoint
private void requestSetID(int flags) {
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -2030,9 +1932,7 @@ public class GnssLocationProvider extends LocationProviderInterface
native_agps_set_id(type, data);
}
/**
* Called from native code to request location info.
*/
@NativeEntryPoint
private void requestLocation(boolean independentFromGnss) {
if (DEBUG) {
Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss);
@@ -2040,17 +1940,13 @@ public class GnssLocationProvider extends LocationProviderInterface
sendMessage(REQUEST_LOCATION, 0, independentFromGnss);
}
/**
* Called from native code to request utc time info
*/
@NativeEntryPoint
private void requestUtcTime() {
if (DEBUG) Log.d(TAG, "utcTimeRequest");
sendMessage(INJECT_NTP_TIME, 0, null);
}
/**
* Called from native code to request reference location info
*/
@NativeEntryPoint
private void requestRefLocation() {
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -2104,11 +2000,7 @@ public class GnssLocationProvider extends LocationProviderInterface
int message = msg.what;
switch (message) {
case ENABLE:
if (msg.arg1 == 1) {
handleEnable();
} else {
handleDisable();
}
handleEnable();
break;
case SET_REQUEST:
GpsRequest gpsRequest = (GpsRequest) msg.obj;
@@ -2153,7 +2045,8 @@ public class GnssLocationProvider extends LocationProviderInterface
}
/**
* This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
* This method is bound to {@link #GnssLocationProvider(Context, LocationProviderManager,
* Looper)}.
* It is in charge of loading properties and registering for events that will be posted to
* this handler.
*/
@@ -2206,12 +2099,11 @@ public class GnssLocationProvider extends LocationProviderInterface
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
long minTime = 0;
float minDistance = 0;
boolean oneShot = false;
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
LocationManager.PASSIVE_PROVIDER,
minTime,
minDistance,
oneShot);
false);
// Don't keep track of this request since it's done on behalf of other clients
// (which are kept track of separately).
request.setHideFromAppOps(true);
@@ -2219,11 +2111,14 @@ public class GnssLocationProvider extends LocationProviderInterface
request,
new NetworkLocationListener(),
getLooper());
// enable gps provider, it will never be disabled (legacy behavior)
sendEmptyMessage(ENABLE);
}
}
private abstract class LocationChangeListener implements LocationListener {
int numLocationUpdateRequest;
private int mNumLocationUpdateRequest;
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {

View File

@@ -1,78 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.location;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
* Location Manager's interface for location providers.
* @hide
*/
public abstract class LocationProviderInterface {
/** Get name. */
public abstract String getName();
/** Enable. */
public abstract void enable();
/** Disable. */
public abstract void disable();
/** Is enabled. */
public abstract boolean isEnabled();
/** Set request. */
public abstract void setRequest(ProviderRequest request, WorkSource source);
/** dump. */
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
/** Get properties. */
public abstract ProviderProperties getProperties();
/**
* Get status.
*
* @deprecated Will be removed in a future release.
*/
@Deprecated
public int getStatus(Bundle extras) {
return LocationProvider.AVAILABLE;
}
/**
* Get status update time.
*
* @deprecated Will be removed in a future release.
*/
@Deprecated
public long getStatusUpdateTime() {
return 0;
}
/** Send extra command. */
public abstract boolean sendExtraCommand(String command, Bundle extras);
}

View File

@@ -18,6 +18,7 @@ package com.android.server.location;
import android.annotation.Nullable;
import android.content.Context;
import android.location.Location;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.IBinder;
@@ -27,6 +28,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ILocationProvider;
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.os.BackgroundThread;
@@ -41,21 +43,35 @@ import java.io.PrintWriter;
/**
* Proxy for ILocationProvider implementations.
*/
public class LocationProviderProxy extends LocationProviderInterface {
public class LocationProviderProxy extends AbstractLocationProvider {
private static final String TAG = "LocationProviderProxy";
private static final boolean D = LocationManagerService.D;
private final ServiceWatcher mServiceWatcher;
private final String mName;
// used to ensure that updates to mRequest and mWorkSource are atomic
private final Object mRequestLock = new Object();
private final ServiceWatcher mServiceWatcher;
private volatile boolean mEnabled = false;
@Nullable
private volatile ProviderProperties mProperties;
private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() {
// executed on binder thread
@Override
public void onSetEnabled(boolean enabled) {
LocationProviderProxy.this.setEnabled(enabled);
}
// executed on binder thread
@Override
public void onSetProperties(ProviderProperties properties) {
LocationProviderProxy.this.setProperties(properties);
}
// executed on binder thread
@Override
public void onReportLocation(Location location) {
LocationProviderProxy.this.reportLocation(location);
}
};
@GuardedBy("mRequestLock")
@Nullable
@@ -69,10 +85,10 @@ public class LocationProviderProxy extends LocationProviderInterface {
*/
@Nullable
public static LocationProviderProxy createAndBind(
Context context, String name, String action,
Context context, LocationProviderManager locationProviderManager, String action,
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId) {
LocationProviderProxy proxy = new LocationProviderProxy(context, name,
LocationProviderProxy proxy = new LocationProviderProxy(context, locationProviderManager,
action, overlaySwitchResId, defaultServicePackageNameResId,
initialPackageNamesResId);
if (proxy.bind()) {
@@ -82,21 +98,27 @@ public class LocationProviderProxy extends LocationProviderInterface {
}
}
private LocationProviderProxy(Context context, String name,
private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager,
String action, int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId) {
super(locationProviderManager, false);
mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId,
BackgroundThread.getHandler()) {
@Override
protected void onBind() {
runOnBinder(LocationProviderProxy.this::initializeService);
}
};
mName = name;
mProperties = null;
@Override
protected void onUnbind() {
setEnabled(false);
setProperties(null);
}
};
mRequest = null;
mWorkSource = new WorkSource();
}
@@ -107,83 +129,26 @@ public class LocationProviderProxy extends LocationProviderInterface {
private void initializeService(IBinder binder) {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
if (D) Log.d(TAG, "applying state to connected service");
ProviderProperties[] properties = new ProviderProperties[1];
ProviderRequest request;
WorkSource source;
synchronized (mRequestLock) {
request = mRequest;
source = mWorkSource;
}
if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
try {
// load properties from provider
properties[0] = service.getProperties();
if (properties[0] == null) {
Log.e(TAG, mServiceWatcher.getCurrentPackageName()
+ " has invalid location provider properties");
}
service.setLocationProviderManager(mManager);
// apply current state to new service
if (mEnabled) {
service.enable();
if (request != null) {
service.setRequest(request, source);
synchronized (mRequestLock) {
if (mRequest != null) {
service.setRequest(mRequest, mWorkSource);
}
}
} catch (RemoteException e) {
Log.w(TAG, e);
}
mProperties = properties[0];
}
@Nullable
public String getConnectedPackageName() {
return mServiceWatcher.getCurrentPackageName();
}
@Override
public String getName() {
return mName;
}
@Override
public ProviderProperties getProperties() {
return mProperties;
}
@Override
public void enable() {
mEnabled = true;
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
service.enable();
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
}
@Override
public void disable() {
mEnabled = false;
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
service.disable();
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
}
@Override
public boolean isEnabled() {
return mEnabled;
}
@Override
public void setRequest(ProviderRequest request, WorkSource source) {
synchronized (mRequestLock) {
@@ -202,60 +167,53 @@ public class LocationProviderProxy extends LocationProviderInterface {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.append("REMOTE SERVICE");
pw.append(" name=").append(mName);
pw.append(" pkg=").append(mServiceWatcher.getCurrentPackageName());
pw.append(" version=").append(Integer.toString(mServiceWatcher.getCurrentPackageVersion()));
pw.append('\n');
pw.println(" service=" + mServiceWatcher);
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
TransferPipe.dumpAsync(service.asBinder(), fd, args);
TransferPipe.dumpAsync(binder, fd, args);
} catch (IOException | RemoteException e) {
pw.println("Failed to dump location provider: " + e);
pw.println(" failed to dump location provider: " + e);
}
});
}
@Override
public int getStatus(Bundle extras) {
int[] result = new int[]{LocationProvider.TEMPORARILY_UNAVAILABLE};
int[] status = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
result[0] = service.getStatus(extras);
status[0] = service.getStatus(extras);
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
return result[0];
return status[0];
}
@Override
public long getStatusUpdateTime() {
long[] result = new long[]{0L};
long[] updateTime = new long[] {0L};
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
result[0] = service.getStatusUpdateTime();
updateTime[0] = service.getStatusUpdateTime();
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
return result[0];
return updateTime[0];
}
@Override
public boolean sendExtraCommand(String command, Bundle extras) {
boolean[] result = new boolean[]{false};
public void sendExtraCommand(String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
result[0] = service.sendExtraCommand(command, extras);
service.sendExtraCommand(command, extras);
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
return result[0];
}
}

View File

@@ -16,14 +16,11 @@
package com.android.server.location;
import android.location.ILocationManager;
import android.annotation.Nullable;
import android.location.Location;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.WorkSource;
import android.util.Log;
import android.util.PrintWriterPrinter;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -36,62 +33,56 @@ import java.io.PrintWriter;
*
* {@hide}
*/
public class MockProvider extends LocationProviderInterface {
private final String mName;
private final ProviderProperties mProperties;
private final ILocationManager mLocationManager;
public class MockProvider extends AbstractLocationProvider {
private final Location mLocation;
private boolean mHasLocation;
private boolean mEnabled;
@Nullable private Location mLocation;
private int mStatus;
private long mStatusUpdateTime;
private Bundle mExtras;
private static final String TAG = "MockProvider";
public MockProvider(
LocationProviderManager locationProviderManager, ProviderProperties properties) {
super(locationProviderManager, true);
public MockProvider(String name, ILocationManager locationManager,
ProviderProperties properties) {
if (properties == null) throw new NullPointerException("properties is null");
mName = name;
mLocationManager = locationManager;
mProperties = properties;
mLocation = new Location(name);
mStatus = LocationProvider.AVAILABLE;
mStatusUpdateTime = 0L;
mExtras = null;
}
@Override
public String getName() {
return mName;
}
@Override
public ProviderProperties getProperties() {
return mProperties;
}
@Override
public void disable() {
mEnabled = false;
}
@Override
public void enable() {
mEnabled = true;
mLocation = null;
mStatus = LocationProvider.AVAILABLE;
mStatusUpdateTime = 0;
mExtras = null;
setProperties(properties);
}
/** Sets the enabled state of this mock provider. */
public void setEnabled(boolean enabled) {
mEnabled = enabled;
super.setEnabled(enabled);
}
/** Sets the location to report for this mock provider. */
public void setLocation(Location l) {
mLocation = new Location(l);
if (mEnabled) {
reportLocation(l);
}
}
/** Sets the status for this mock provider. */
public void setStatus(int status, Bundle extras, long updateTime) {
mStatus = status;
mStatusUpdateTime = updateTime;
mExtras = extras;
}
@Override
public boolean isEnabled() {
return mEnabled;
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(" last location=" + mLocation);
}
@Override
public void setRequest(ProviderRequest request, WorkSource source) {}
@Override
public int getStatus(Bundle extras) {
if (mExtras != null) {
@@ -107,50 +98,6 @@ public class MockProvider extends LocationProviderInterface {
return mStatusUpdateTime;
}
public void setLocation(Location l) {
mLocation.set(l);
mHasLocation = true;
if (mEnabled) {
try {
mLocationManager.reportLocation(mLocation, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocation");
}
}
}
public void clearLocation() {
mHasLocation = false;
}
/**
* @deprecated Will be removed in a future release.
*/
@Deprecated
public void setStatus(int status, Bundle extras, long updateTime) {
mStatus = status;
mStatusUpdateTime = updateTime;
mExtras = extras;
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
dump(pw, "");
}
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mName);
pw.println(prefix + "mHasLocation=" + mHasLocation);
pw.println(prefix + "mLocation:");
mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
pw.println(prefix + "mExtras=" + mExtras);
}
@Override
public void setRequest(ProviderRequest request, WorkSource source) { }
@Override
public boolean sendExtraCommand(String command, Bundle extras) {
return false;
}
public void sendExtraCommand(String command, Bundle extras) {}
}

View File

@@ -17,13 +17,9 @@
package com.android.server.location;
import android.location.Criteria;
import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.WorkSource;
import android.util.Log;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -38,41 +34,20 @@ import java.io.PrintWriter;
*
* {@hide}
*/
public class PassiveProvider extends LocationProviderInterface {
private static final String TAG = "PassiveProvider";
public class PassiveProvider extends AbstractLocationProvider {
private static final ProviderProperties PROPERTIES = new ProviderProperties(
false, false, false, false, false, false, false,
Criteria.POWER_LOW, Criteria.ACCURACY_COARSE);
private final ILocationManager mLocationManager;
private boolean mReportLocation;
public PassiveProvider(ILocationManager locationManager) {
mLocationManager = locationManager;
}
public PassiveProvider(LocationProviderManager locationProviderManager) {
super(locationProviderManager, true);
@Override
public String getName() {
return LocationManager.PASSIVE_PROVIDER;
}
mReportLocation = false;
@Override
public ProviderProperties getProperties() {
return PROPERTIES;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public void enable() {
}
@Override
public void disable() {
setProperties(PROPERTIES);
}
@Override
@@ -82,22 +57,15 @@ public class PassiveProvider extends LocationProviderInterface {
public void updateLocation(Location location) {
if (mReportLocation) {
try {
// pass the location back to the location manager
mLocationManager.reportLocation(location, true);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocation");
}
reportLocation(location);
}
}
@Override
public boolean sendExtraCommand(String command, Bundle extras) {
return false;
}
public void sendExtraCommand(String command, Bundle extras) {}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("mReportLocation=" + mReportLocation);
pw.println(" report location=" + mReportLocation);
}
}